|
@@ -9,23 +9,23 @@ import { useTranslation } from 'react-i18next';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
|
|
import {
|
|
import {
|
|
|
- IPageInfo, IPageInfoCommon, isExistPageInfo,
|
|
|
|
|
|
|
+ IPageInfoAll, isIPageInfoForOperation,
|
|
|
} from '~/interfaces/page';
|
|
} from '~/interfaces/page';
|
|
|
import { useSWRxPageInfo } from '~/stores/page';
|
|
import { useSWRxPageInfo } from '~/stores/page';
|
|
|
|
|
|
|
|
const logger = loggerFactory('growi:cli:PageItemControl');
|
|
const logger = loggerFactory('growi:cli:PageItemControl');
|
|
|
|
|
|
|
|
|
|
|
|
|
-export type AdditionalMenuItemsRendererProps = { pageInfo: IPageInfoCommon | IPageInfo };
|
|
|
|
|
|
|
+export type AdditionalMenuItemsRendererProps = { pageInfo: IPageInfoAll };
|
|
|
|
|
|
|
|
type CommonProps = {
|
|
type CommonProps = {
|
|
|
- pageInfo?: IPageInfoCommon | IPageInfo,
|
|
|
|
|
|
|
+ pageInfo?: IPageInfoAll,
|
|
|
isEnableActions?: boolean,
|
|
isEnableActions?: boolean,
|
|
|
- hideBookmarkMenuItem?: boolean,
|
|
|
|
|
- onClickBookmarkMenuItem?: (pageId: string, newValue?: boolean) => Promise<void> | void,
|
|
|
|
|
|
|
+ showBookmarkMenuItem?: boolean,
|
|
|
|
|
+ onClickBookmarkMenuItem?: (pageId: string, newValue?: boolean) => Promise<void>,
|
|
|
onClickDuplicateMenuItem?: () => Promise<void> | void,
|
|
onClickDuplicateMenuItem?: () => Promise<void> | void,
|
|
|
- onClickRenameMenuItem?: (pageId: string) => Promise<void> | void,
|
|
|
|
|
- onClickDeleteMenuItem?: (pageId: string) => Promise<void> | void,
|
|
|
|
|
|
|
+ onClickRenameMenuItem?: (pageId: string) => void,
|
|
|
|
|
+ onClickDeleteMenuItem?: (pageId: string) => void,
|
|
|
|
|
|
|
|
additionalMenuItemRenderer?: React.FunctionComponent<AdditionalMenuItemsRendererProps>,
|
|
additionalMenuItemRenderer?: React.FunctionComponent<AdditionalMenuItemsRendererProps>,
|
|
|
}
|
|
}
|
|
@@ -33,13 +33,15 @@ type CommonProps = {
|
|
|
|
|
|
|
|
type DropdownMenuProps = CommonProps & {
|
|
type DropdownMenuProps = CommonProps & {
|
|
|
pageId: string,
|
|
pageId: string,
|
|
|
|
|
+ isLoading?: boolean,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.Element => {
|
|
const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.Element => {
|
|
|
const { t } = useTranslation('');
|
|
const { t } = useTranslation('');
|
|
|
|
|
|
|
|
const {
|
|
const {
|
|
|
- pageId, pageInfo, isEnableActions, hideBookmarkMenuItem,
|
|
|
|
|
|
|
+ pageId, isLoading,
|
|
|
|
|
+ pageInfo, isEnableActions, showBookmarkMenuItem,
|
|
|
onClickBookmarkMenuItem, onClickDuplicateMenuItem, onClickRenameMenuItem, onClickDeleteMenuItem,
|
|
onClickBookmarkMenuItem, onClickDuplicateMenuItem, onClickRenameMenuItem, onClickDeleteMenuItem,
|
|
|
additionalMenuItemRenderer: AdditionalMenuItems,
|
|
additionalMenuItemRenderer: AdditionalMenuItems,
|
|
|
} = props;
|
|
} = props;
|
|
@@ -47,7 +49,7 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
|
|
|
|
|
|
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
|
const bookmarkItemClickedHandler = useCallback(async() => {
|
|
const bookmarkItemClickedHandler = useCallback(async() => {
|
|
|
- if (!isExistPageInfo(pageInfo) || onClickBookmarkMenuItem == null) {
|
|
|
|
|
|
|
+ if (!isIPageInfoForOperation(pageInfo) || onClickBookmarkMenuItem == null) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
await onClickBookmarkMenuItem(pageId, !pageInfo.isBookmarked);
|
|
await onClickBookmarkMenuItem(pageId, !pageInfo.isBookmarked);
|
|
@@ -71,7 +73,7 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
|
|
|
|
|
|
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
|
const deleteItemClickedHandler = useCallback(async() => {
|
|
const deleteItemClickedHandler = useCallback(async() => {
|
|
|
- if (!isExistPageInfo(pageInfo) || onClickDeleteMenuItem == null) {
|
|
|
|
|
|
|
+ if (pageInfo == null || onClickDeleteMenuItem == null) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
if (!pageInfo.isDeletable) {
|
|
if (!pageInfo.isDeletable) {
|
|
@@ -81,62 +83,74 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
|
|
|
await onClickDeleteMenuItem(pageId);
|
|
await onClickDeleteMenuItem(pageId);
|
|
|
}, [onClickDeleteMenuItem, pageId, pageInfo]);
|
|
}, [onClickDeleteMenuItem, pageId, pageInfo]);
|
|
|
|
|
|
|
|
- if (pageId == null || pageInfo == null) {
|
|
|
|
|
- return <></>;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <DropdownMenu positionFixed modifiers={{ preventOverflow: { boundariesElement: undefined } }}>
|
|
|
|
|
-
|
|
|
|
|
- { !isEnableActions && (
|
|
|
|
|
- <DropdownItem>
|
|
|
|
|
- <p>
|
|
|
|
|
- {t('search_result.currently_not_implemented')}
|
|
|
|
|
- </p>
|
|
|
|
|
- </DropdownItem>
|
|
|
|
|
- ) }
|
|
|
|
|
|
|
+ let contents = <></>;
|
|
|
|
|
|
|
|
- {/* Bookmark */}
|
|
|
|
|
- { !hideBookmarkMenuItem && isExistPageInfo(pageInfo) && isEnableActions && (
|
|
|
|
|
- <DropdownItem onClick={bookmarkItemClickedHandler}>
|
|
|
|
|
- <i className="fa fa-fw fa-bookmark-o"></i>
|
|
|
|
|
- { pageInfo.isBookmarked ? t('remove_bookmark') : t('add_bookmark') }
|
|
|
|
|
- </DropdownItem>
|
|
|
|
|
- ) }
|
|
|
|
|
|
|
+ if (isLoading) {
|
|
|
|
|
+ contents = (
|
|
|
|
|
+ <div className="text-muted text-center my-2">
|
|
|
|
|
+ <i className="fa fa-spinner fa-pulse"></i>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (pageId != null && pageInfo != null) {
|
|
|
|
|
+ contents = (
|
|
|
|
|
+ <>
|
|
|
|
|
+ { !isEnableActions && (
|
|
|
|
|
+ <DropdownItem>
|
|
|
|
|
+ <p>
|
|
|
|
|
+ {t('search_result.currently_not_implemented')}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </DropdownItem>
|
|
|
|
|
+ ) }
|
|
|
|
|
|
|
|
- {/* Duplicate */}
|
|
|
|
|
- { isExistPageInfo(pageInfo) && isEnableActions && (
|
|
|
|
|
- <DropdownItem onClick={duplicateItemClickedHandler}>
|
|
|
|
|
- <i className="icon-fw icon-docs"></i>
|
|
|
|
|
- {t('Duplicate')}
|
|
|
|
|
- </DropdownItem>
|
|
|
|
|
- ) }
|
|
|
|
|
|
|
+ {/* Bookmark */}
|
|
|
|
|
+ { showBookmarkMenuItem && isEnableActions && !pageInfo.isEmpty && isIPageInfoForOperation(pageInfo) && (
|
|
|
|
|
+ <DropdownItem onClick={bookmarkItemClickedHandler}>
|
|
|
|
|
+ <i className="fa fa-fw fa-bookmark-o"></i>
|
|
|
|
|
+ { pageInfo.isBookmarked ? t('remove_bookmark') : t('add_bookmark') }
|
|
|
|
|
+ </DropdownItem>
|
|
|
|
|
+ ) }
|
|
|
|
|
|
|
|
- {/* Move/Rename */}
|
|
|
|
|
- { isEnableActions && pageInfo.isMovable && (
|
|
|
|
|
- <DropdownItem onClick={renameItemClickedHandler}>
|
|
|
|
|
- <i className="icon-fw icon-action-redo"></i>
|
|
|
|
|
- {t('Move/Rename')}
|
|
|
|
|
- </DropdownItem>
|
|
|
|
|
- ) }
|
|
|
|
|
|
|
+ {/* Duplicate */}
|
|
|
|
|
+ { isEnableActions && !pageInfo.isEmpty && (
|
|
|
|
|
+ <DropdownItem onClick={duplicateItemClickedHandler}>
|
|
|
|
|
+ <i className="icon-fw icon-docs"></i>
|
|
|
|
|
+ {t('Duplicate')}
|
|
|
|
|
+ </DropdownItem>
|
|
|
|
|
+ ) }
|
|
|
|
|
|
|
|
- { AdditionalMenuItems && <AdditionalMenuItems pageInfo={pageInfo} /> }
|
|
|
|
|
-
|
|
|
|
|
- {/* divider */}
|
|
|
|
|
- {/* Delete */}
|
|
|
|
|
- { isExistPageInfo(pageInfo) && isEnableActions && pageInfo.isMovable && (
|
|
|
|
|
- <>
|
|
|
|
|
- <DropdownItem divider />
|
|
|
|
|
- <DropdownItem
|
|
|
|
|
- className={`pt-2 ${pageInfo.isDeletable ? 'text-danger' : ''}`}
|
|
|
|
|
- disabled={!pageInfo.isDeletable}
|
|
|
|
|
- onClick={deleteItemClickedHandler}
|
|
|
|
|
- >
|
|
|
|
|
- <i className="icon-fw icon-trash"></i>
|
|
|
|
|
- {t('Delete')}
|
|
|
|
|
|
|
+ {/* Move/Rename */}
|
|
|
|
|
+ { isEnableActions && pageInfo.isMovable && (
|
|
|
|
|
+ <DropdownItem onClick={renameItemClickedHandler}>
|
|
|
|
|
+ <i className="icon-fw icon-action-redo"></i>
|
|
|
|
|
+ {t('Move/Rename')}
|
|
|
</DropdownItem>
|
|
</DropdownItem>
|
|
|
- </>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ ) }
|
|
|
|
|
+
|
|
|
|
|
+ { AdditionalMenuItems && <AdditionalMenuItems pageInfo={pageInfo} /> }
|
|
|
|
|
+
|
|
|
|
|
+ {/* divider */}
|
|
|
|
|
+ {/* Delete */}
|
|
|
|
|
+ { isEnableActions && pageInfo.isMovable && !pageInfo.isEmpty && (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <DropdownItem divider />
|
|
|
|
|
+ <DropdownItem
|
|
|
|
|
+ className={`pt-2 ${pageInfo.isDeletable ? 'text-danger' : ''}`}
|
|
|
|
|
+ disabled={!pageInfo.isDeletable}
|
|
|
|
|
+ onClick={deleteItemClickedHandler}
|
|
|
|
|
+ >
|
|
|
|
|
+ <i className="icon-fw icon-trash"></i>
|
|
|
|
|
+ {t('Delete')}
|
|
|
|
|
+ </DropdownItem>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <DropdownMenu positionFixed modifiers={{ preventOverflow: { boundariesElement: undefined } }}>
|
|
|
|
|
+ {contents}
|
|
|
</DropdownMenu>
|
|
</DropdownMenu>
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
@@ -144,19 +158,23 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
|
|
|
|
|
|
|
|
type PageItemControlSubstanceProps = CommonProps & {
|
|
type PageItemControlSubstanceProps = CommonProps & {
|
|
|
pageId: string,
|
|
pageId: string,
|
|
|
- fetchOnOpen?: boolean,
|
|
|
|
|
|
|
+ fetchOnInit?: boolean,
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const PageItemControlSubstance = (props: PageItemControlSubstanceProps): JSX.Element => {
|
|
export const PageItemControlSubstance = (props: PageItemControlSubstanceProps): JSX.Element => {
|
|
|
|
|
|
|
|
const {
|
|
const {
|
|
|
- pageId, pageInfo: presetPageInfo, fetchOnOpen,
|
|
|
|
|
|
|
+ pageId, pageInfo: presetPageInfo, fetchOnInit,
|
|
|
|
|
+ children,
|
|
|
onClickBookmarkMenuItem, onClickDuplicateMenuItem,
|
|
onClickBookmarkMenuItem, onClickDuplicateMenuItem,
|
|
|
} = props;
|
|
} = props;
|
|
|
|
|
|
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
|
|
|
|
- const shouldFetch = presetPageInfo == null && (!fetchOnOpen || isOpen);
|
|
|
|
|
|
|
+ const shouldFetch = fetchOnInit === true || (!isIPageInfoForOperation(presetPageInfo) && isOpen);
|
|
|
|
|
+ const shouldMutate = fetchOnInit === true || !isIPageInfoForOperation(presetPageInfo);
|
|
|
|
|
+
|
|
|
const { data: fetchedPageInfo, mutate: mutatePageInfo } = useSWRxPageInfo(shouldFetch ? pageId : null);
|
|
const { data: fetchedPageInfo, mutate: mutatePageInfo } = useSWRxPageInfo(shouldFetch ? pageId : null);
|
|
|
|
|
|
|
|
// mutate after handle event
|
|
// mutate after handle event
|
|
@@ -165,10 +183,12 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
|
|
|
await onClickBookmarkMenuItem(_pageId, _newValue);
|
|
await onClickBookmarkMenuItem(_pageId, _newValue);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (shouldFetch) {
|
|
|
|
|
|
|
+ if (shouldMutate) {
|
|
|
mutatePageInfo();
|
|
mutatePageInfo();
|
|
|
}
|
|
}
|
|
|
- }, [mutatePageInfo, onClickBookmarkMenuItem, shouldFetch]);
|
|
|
|
|
|
|
+ }, [mutatePageInfo, onClickBookmarkMenuItem, shouldMutate]);
|
|
|
|
|
+
|
|
|
|
|
+ const isLoading = shouldFetch && fetchedPageInfo == null;
|
|
|
|
|
|
|
|
const duplicateMenuItemClickHandler = useCallback(async() => {
|
|
const duplicateMenuItemClickHandler = useCallback(async() => {
|
|
|
if (onClickDuplicateMenuItem == null) {
|
|
if (onClickDuplicateMenuItem == null) {
|
|
@@ -179,13 +199,17 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<Dropdown isOpen={isOpen} toggle={() => setIsOpen(!isOpen)}>
|
|
<Dropdown isOpen={isOpen} toggle={() => setIsOpen(!isOpen)}>
|
|
|
- <DropdownToggle color="transparent" className="border-0 rounded grw-btn-page-management p-0">
|
|
|
|
|
- <i className="icon-options fa fa-rotate-90 text-muted p-1"></i>
|
|
|
|
|
- </DropdownToggle>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ { children ?? (
|
|
|
|
|
+ <DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control">
|
|
|
|
|
+ <i className="icon-options text-muted"></i>
|
|
|
|
|
+ </DropdownToggle>
|
|
|
|
|
+ ) }
|
|
|
|
|
|
|
|
<PageItemControlDropdownMenu
|
|
<PageItemControlDropdownMenu
|
|
|
{...props}
|
|
{...props}
|
|
|
- pageInfo={presetPageInfo ?? fetchedPageInfo}
|
|
|
|
|
|
|
+ isLoading={isLoading}
|
|
|
|
|
+ pageInfo={fetchedPageInfo ?? presetPageInfo}
|
|
|
onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
|
|
onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
|
|
|
onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
|
|
onClickDuplicateMenuItem={duplicateMenuItemClickHandler}
|
|
|
/>
|
|
/>
|
|
@@ -197,13 +221,13 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
|
|
|
|
|
|
|
|
type PageItemControlProps = CommonProps & {
|
|
type PageItemControlProps = CommonProps & {
|
|
|
pageId?: string,
|
|
pageId?: string,
|
|
|
- path?: string,
|
|
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const PageItemControl = (props: PageItemControlProps): JSX.Element => {
|
|
export const PageItemControl = (props: PageItemControlProps): JSX.Element => {
|
|
|
- const { pageId, path } = props;
|
|
|
|
|
|
|
+ const { pageId } = props;
|
|
|
|
|
|
|
|
- if (pageId == null || path == null) {
|
|
|
|
|
|
|
+ if (pageId == null) {
|
|
|
return <></>;
|
|
return <></>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -211,8 +235,9 @@ export const PageItemControl = (props: PageItemControlProps): JSX.Element => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
-type AsyncPageItemControlProps = CommonProps & {
|
|
|
|
|
|
|
+type AsyncPageItemControlProps = Omit<CommonProps, 'pageInfo'> & {
|
|
|
pageId?: string,
|
|
pageId?: string,
|
|
|
|
|
+ children?: React.ReactNode,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const AsyncPageItemControl = (props: AsyncPageItemControlProps): JSX.Element => {
|
|
export const AsyncPageItemControl = (props: AsyncPageItemControlProps): JSX.Element => {
|
|
@@ -222,5 +247,5 @@ export const AsyncPageItemControl = (props: AsyncPageItemControlProps): JSX.Elem
|
|
|
return <></>;
|
|
return <></>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return <PageItemControlSubstance pageId={pageId} fetchOnOpen {...props} />;
|
|
|
|
|
|
|
+ return <PageItemControlSubstance pageId={pageId} fetchOnInit {...props} />;
|
|
|
};
|
|
};
|