|
@@ -1,46 +1,25 @@
|
|
|
-import { Suspense, useCallback, useMemo, useState } from 'react';
|
|
|
|
|
|
|
+import { useCallback } from 'react';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { ModalBody } from 'reactstrap';
|
|
import { ModalBody } from 'reactstrap';
|
|
|
-import SimpleBar from 'simplebar-react';
|
|
|
|
|
|
|
|
|
|
-import ItemsTreeContentSkeleton from '~/client/components/ItemsTree/ItemsTreeContentSkeleton';
|
|
|
|
|
-import { SimplifiedItemsTree } from '~/features/page-tree/components';
|
|
|
|
|
-import type { IPageForTreeItem } from '~/interfaces/page';
|
|
|
|
|
import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
|
|
import { useIsGuestUser, useIsReadOnlyUser } from '~/states/context';
|
|
|
|
|
|
|
|
-import {
|
|
|
|
|
- isSelectablePage,
|
|
|
|
|
- type SelectablePage,
|
|
|
|
|
-} from '../../../../interfaces/selectable-page';
|
|
|
|
|
-import { useSelectedPages } from '../../../services/use-selected-pages';
|
|
|
|
|
|
|
+import type { SelectablePage } from '../../../../interfaces/selectable-page';
|
|
|
import {
|
|
import {
|
|
|
AiAssistantManagementModalPageMode,
|
|
AiAssistantManagementModalPageMode,
|
|
|
useAiAssistantManagementModalActions,
|
|
useAiAssistantManagementModalActions,
|
|
|
useAiAssistantManagementModalStatus,
|
|
useAiAssistantManagementModalStatus,
|
|
|
} from '../../../states/modal/ai-assistant-management';
|
|
} from '../../../states/modal/ai-assistant-management';
|
|
|
import { AiAssistantManagementHeader } from './AiAssistantManagementHeader';
|
|
import { AiAssistantManagementHeader } from './AiAssistantManagementHeader';
|
|
|
-import { SelectablePageList } from './SelectablePageList';
|
|
|
|
|
-import {
|
|
|
|
|
- SimplifiedTreeItemWithCheckbox,
|
|
|
|
|
- simplifiedTreeItemWithCheckboxSize,
|
|
|
|
|
-} from './SimplifiedTreeItemWithCheckbox';
|
|
|
|
|
|
|
+import { usePageTreeSelection } from './hooks/use-page-tree-selection';
|
|
|
|
|
+import { PageTreeSelectionTree } from './PageTreeSelectionTree';
|
|
|
|
|
+import { SelectedPagesPanel } from './SelectedPagesPanel';
|
|
|
|
|
|
|
|
import styles from './AiAssistantManagementPageTreeSelection.module.scss';
|
|
import styles from './AiAssistantManagementPageTreeSelection.module.scss';
|
|
|
|
|
|
|
|
const moduleClass =
|
|
const moduleClass =
|
|
|
styles['grw-ai-assistant-management-page-tree-selection'] ?? '';
|
|
styles['grw-ai-assistant-management-page-tree-selection'] ?? '';
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * Convert a page path to a glob pattern for selecting descendants.
|
|
|
|
|
- * Handles the root page case where '//*' should become '/*'.
|
|
|
|
|
- */
|
|
|
|
|
-const toPagePathGlob = (path: string): string => {
|
|
|
|
|
- if (path === '/') {
|
|
|
|
|
- return '/*';
|
|
|
|
|
- }
|
|
|
|
|
- return `${path}/*`;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
type Props = {
|
|
type Props = {
|
|
|
baseSelectedPages: SelectablePage[];
|
|
baseSelectedPages: SelectablePage[];
|
|
|
updateBaseSelectedPages: (pages: SelectablePage[]) => void;
|
|
updateBaseSelectedPages: (pages: SelectablePage[]) => void;
|
|
@@ -59,54 +38,13 @@ export const AiAssistantManagementPageTreeSelection = (
|
|
|
const isNewAiAssistant =
|
|
const isNewAiAssistant =
|
|
|
aiAssistantManagementModalData?.aiAssistantData == null;
|
|
aiAssistantManagementModalData?.aiAssistantData == null;
|
|
|
|
|
|
|
|
- // Scroll container for virtualization
|
|
|
|
|
- const [scrollerElem, setScrollerElem] = useState<HTMLElement | null>(null);
|
|
|
|
|
-
|
|
|
|
|
- const { selectedPages, selectedPagesArray, addPage, removePage } =
|
|
|
|
|
- useSelectedPages(baseSelectedPages);
|
|
|
|
|
-
|
|
|
|
|
- // Calculate initial checked items from baseSelectedPages
|
|
|
|
|
- // Remove the /* suffix to match with page IDs
|
|
|
|
|
- const initialCheckedItems = useMemo(() => {
|
|
|
|
|
- return baseSelectedPages
|
|
|
|
|
- .filter((page) => page._id != null)
|
|
|
|
|
- .map((page) => page._id as string);
|
|
|
|
|
- }, [baseSelectedPages]);
|
|
|
|
|
-
|
|
|
|
|
- // Handle checked items change from tree
|
|
|
|
|
- const handleCheckedItemsChange = useCallback(
|
|
|
|
|
- (checkedPages: IPageForTreeItem[]) => {
|
|
|
|
|
- // Get current checked page IDs (with /* suffix paths)
|
|
|
|
|
- const currentCheckedPaths = new Set(
|
|
|
|
|
- checkedPages
|
|
|
|
|
- .filter((page) => isSelectablePage(page) && page.path != null)
|
|
|
|
|
- .map((page) => toPagePathGlob(page.path as string)),
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // Get currently selected page paths
|
|
|
|
|
- const currentSelectedPaths = new Set(selectedPages.keys());
|
|
|
|
|
-
|
|
|
|
|
- // Add newly checked pages
|
|
|
|
|
- checkedPages.forEach((page) => {
|
|
|
|
|
- if (!isSelectablePage(page) || page.path == null) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- const pagePathWithGlob = toPagePathGlob(page.path);
|
|
|
|
|
- if (!currentSelectedPaths.has(pagePathWithGlob)) {
|
|
|
|
|
- const clonedPage = { ...page, path: pagePathWithGlob };
|
|
|
|
|
- addPage(clonedPage as SelectablePage);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // Remove unchecked pages
|
|
|
|
|
- selectedPagesArray.forEach((page) => {
|
|
|
|
|
- if (page.path != null && !currentCheckedPaths.has(page.path)) {
|
|
|
|
|
- removePage(page);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- },
|
|
|
|
|
- [selectedPages, selectedPagesArray, addPage, removePage],
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ const {
|
|
|
|
|
+ selectedPages,
|
|
|
|
|
+ selectedPagesArray,
|
|
|
|
|
+ initialCheckedItems,
|
|
|
|
|
+ handleCheckedItemsChange,
|
|
|
|
|
+ removePage,
|
|
|
|
|
+ } = usePageTreeSelection(baseSelectedPages);
|
|
|
|
|
|
|
|
const nextButtonClickHandler = useCallback(() => {
|
|
const nextButtonClickHandler = useCallback(() => {
|
|
|
updateBaseSelectedPages(Array.from(selectedPages.values()));
|
|
updateBaseSelectedPages(Array.from(selectedPages.values()));
|
|
@@ -122,11 +60,6 @@ export const AiAssistantManagementPageTreeSelection = (
|
|
|
updateBaseSelectedPages,
|
|
updateBaseSelectedPages,
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
- const estimateTreeItemSize = useCallback(
|
|
|
|
|
- () => simplifiedTreeItemWithCheckboxSize,
|
|
|
|
|
- [],
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
return (
|
|
return (
|
|
|
<div className={moduleClass}>
|
|
<div className={moduleClass}>
|
|
|
<AiAssistantManagementHeader
|
|
<AiAssistantManagementHeader
|
|
@@ -149,45 +82,18 @@ export const AiAssistantManagementPageTreeSelection = (
|
|
|
</h4>
|
|
</h4>
|
|
|
|
|
|
|
|
<div className="px-4">
|
|
<div className="px-4">
|
|
|
- <div className="page-tree-container" ref={setScrollerElem}>
|
|
|
|
|
- {scrollerElem != null && (
|
|
|
|
|
- <Suspense fallback={<ItemsTreeContentSkeleton />}>
|
|
|
|
|
- <SimplifiedItemsTree
|
|
|
|
|
- targetPath="/"
|
|
|
|
|
- isEnableActions={!isGuestUser}
|
|
|
|
|
- isReadOnlyUser={!!isReadOnlyUser}
|
|
|
|
|
- CustomTreeItem={SimplifiedTreeItemWithCheckbox}
|
|
|
|
|
- estimateTreeItemSize={estimateTreeItemSize}
|
|
|
|
|
- scrollerElem={scrollerElem}
|
|
|
|
|
- enableCheckboxes
|
|
|
|
|
- initialCheckedItems={initialCheckedItems}
|
|
|
|
|
- onCheckedItemsChange={handleCheckedItemsChange}
|
|
|
|
|
- />
|
|
|
|
|
- </Suspense>
|
|
|
|
|
- )}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <PageTreeSelectionTree
|
|
|
|
|
+ isEnableActions={!isGuestUser}
|
|
|
|
|
+ isReadOnlyUser={!!isReadOnlyUser}
|
|
|
|
|
+ initialCheckedItems={initialCheckedItems}
|
|
|
|
|
+ onCheckedItemsChange={handleCheckedItemsChange}
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <h4 className="text-center fw-bold mb-3 mt-4">
|
|
|
|
|
- {t('modal_ai_assistant.reference_pages')}
|
|
|
|
|
- </h4>
|
|
|
|
|
-
|
|
|
|
|
- <div className="px-4">
|
|
|
|
|
- <SimpleBar
|
|
|
|
|
- className="page-list-container"
|
|
|
|
|
- style={{ maxHeight: '300px' }}
|
|
|
|
|
- >
|
|
|
|
|
- <SelectablePageList
|
|
|
|
|
- method="remove"
|
|
|
|
|
- methodButtonPosition="right"
|
|
|
|
|
- pages={selectedPagesArray}
|
|
|
|
|
- onClickMethodButton={removePage}
|
|
|
|
|
- />
|
|
|
|
|
- </SimpleBar>
|
|
|
|
|
- <span className="form-text text-muted mt-2">
|
|
|
|
|
- {t('modal_ai_assistant.can_add_later')}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <SelectedPagesPanel
|
|
|
|
|
+ pages={selectedPagesArray}
|
|
|
|
|
+ onRemovePage={removePage}
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
<div className="d-flex justify-content-center mt-4">
|
|
<div className="d-flex justify-content-center mt-4">
|
|
|
<button
|
|
<button
|