import React, { type JSX, useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'next-i18next'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; import { apiPost } from '~/client/util/apiv1-client'; import { toastError, toastSuccess } from '~/client/util/toastr'; const GROUPS_PAGE = [ 'pages', 'revisions', 'tags', 'pagetagrelations', 'pageredirects', 'comments', 'sharelinks', ]; const GROUPS_USER = [ 'users', 'externalaccounts', 'usergroups', 'usergrouprelations', 'externalusergroups', 'externalusergrouprelations', 'useruisettings', 'editorsettings', 'bookmarks', 'bookmarkfolders', 'subscriptions', 'inappnotificationsettings', ]; const GROUPS_CONFIG = [ 'configs', 'migrations', 'updateposts', 'globalnotificationsettings', 'slackappintegrations', 'growiplugins', ]; const ALL_GROUPED_COLLECTIONS = GROUPS_PAGE.concat(GROUPS_USER).concat(GROUPS_CONFIG); type Props = { isOpen: boolean; onExportingRequested: () => void; onClose: () => void; collections: string[]; isAllChecked?: boolean; }; const SelectCollectionsModal = (props: Props): JSX.Element => { const { t } = useTranslation(); const { isOpen, onExportingRequested, onClose, collections, isAllChecked } = props; const [selectedCollections, setSelectedCollections] = useState>( new Set(), ); const toggleCheckbox = useCallback((e) => { const { target } = e; const { name, checked } = target; setSelectedCollections((prevState) => { const selectedCollections = new Set(prevState); if (checked) { selectedCollections.add(name); } else { selectedCollections.delete(name); } return selectedCollections; }); }, []); const checkAll = useCallback(() => { setSelectedCollections(new Set(collections)); }, [collections]); const uncheckAll = useCallback(() => { setSelectedCollections(new Set()); }, []); const doExport = useCallback( async (e) => { e.preventDefault(); try { // TODO: use apiv3Post const result = await apiPost('/v3/export', { collections: Array.from(selectedCollections), }); if (!result.ok) { throw new Error('Error occured.'); } toastSuccess('Export process has requested.'); onExportingRequested(); onClose(); uncheckAll(); } catch (err) { toastError(err); } }, [onClose, onExportingRequested, selectedCollections, uncheckAll], ); const validateForm = useCallback(() => { return selectedCollections.size > 0; }, [selectedCollections.size]); const renderWarnForUser = useCallback(() => { // whether selectedCollections includes one of GROUPS_USER const isUserRelatedDataSelected = GROUPS_USER.some((collectionName) => { return selectedCollections.has(collectionName); }); if (!isUserRelatedDataSelected) { return <>; } const html = t('admin:export_management.desc_password_seed'); return (
{/** biome-ignore lint/security/noDangerouslySetInnerHtml: ignore */}

); }, [selectedCollections, t]); const renderCheckboxes = useCallback( (collectionNames, color?) => { const checkboxColor = color ? `form-check-${color}` : 'form-check-info'; return (
{collectionNames.map((collectionName) => { return (
); })}
); }, [selectedCollections, toggleCheckbox], ); const renderGroups = useCallback( (groupList, color?) => { const collectionNames = groupList.filter((collectionName) => { return collections.includes(collectionName); }); return renderCheckboxes(collectionNames, color); }, [collections, renderCheckboxes], ); const renderOthers = useCallback(() => { const collectionNames = collections.filter((collectionName) => { return !ALL_GROUPED_COLLECTIONS.includes(collectionName); }); return renderCheckboxes(collectionNames); }, [collections, renderCheckboxes]); useEffect(() => { if (isAllChecked) checkAll(); }, [isAllChecked, checkAll]); return ( {t('admin:export_management.export_collections')}

MongoDB Page Collections

{renderGroups(GROUPS_PAGE)}

MongoDB User Collections

{renderGroups(GROUPS_USER, 'danger')} {renderWarnForUser()}

MongoDB Config Collections

{renderGroups(GROUPS_CONFIG)}

MongoDB Other Collections

{renderOthers()}
); }; export default SelectCollectionsModal;