Просмотр исходного кода

Merge pull request #6199 from weseek/imprv/99374-next-GrowiContextualSubNav

Imprv/99374 next growi contextual sub nav
Yuki Takei 3 лет назад
Родитель
Сommit
65389ea7e9

+ 1 - 14
packages/app/src/components/LikeButtons.tsx

@@ -3,11 +3,8 @@ import React, { FC, useState, useCallback } from 'react';
 import { useTranslation } from 'next-i18next';
 import { UncontrolledTooltip, Popover, PopoverBody } from 'reactstrap';
 
-import AppContainer from '~/client/services/AppContainer';
-
 import { IUser } from '../interfaces/user';
 
-import { withUnstatedContainers } from './UnstatedUtils';
 import UserPictureList from './User/UserPictureList';
 
 type LikeButtonsProps = {
@@ -80,14 +77,4 @@ const LikeButtons: FC<LikeButtonsProps> = (props: LikeButtonsProps) => {
 
 };
 
-/**
- * Wrapper component for using unstated
- */
-const LikeButtonsUnstatedWrapper = withUnstatedContainers(LikeButtons, [AppContainer]);
-
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-const LikeButtonsWrapper = (props) => {
-  return <LikeButtonsUnstatedWrapper {...props}></LikeButtonsUnstatedWrapper>;
-};
-
-export default LikeButtonsWrapper;
+export default LikeButtons;

+ 28 - 62
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -1,32 +1,25 @@
 import React, { useState, useEffect, useCallback } from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
 import { DropdownItem } from 'reactstrap';
 
-import EditorContainer from '~/client/services/EditorContainer';
-import PageContainer from '~/client/services/PageContainer';
 import { exportAsMarkdown } from '~/client/services/page-operation';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiPost } from '~/client/util/apiv1-client';
-import { getIdForRef } from '~/interfaces/common';
+import { isPopulated } from '~/interfaces/common';
 import {
-  IPageHasId, IPageToRenameWithMeta, IPageWithMeta, IPageInfoForEntity,
+  IPageToRenameWithMeta, IPageWithMeta, IPageInfoForEntity,
 } from '~/interfaces/page';
-import { IResTagsUpdateApiv1 } from '~/interfaces/tag';
 import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
-import {
-  useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath,
-  useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId, useEmptyPageId,
-} from '~/stores/context';
+import { useCurrentUser, useIsGuestUser, useIsSharedUser } from '~/stores/context';
 import { usePageTagsForEditors } from '~/stores/editor';
 import {
   usePageAccessoriesModal, PageAccessoriesModalContents, IPageForPageDuplicateModal,
   usePageDuplicateModal, usePageRenameModal, usePageDeleteModal, usePagePresentationModal,
 } from '~/stores/modal';
-import { useSWRxTagsInfo } from '~/stores/page';
+import { useSWRxCurrentPage, useSWRxTagsInfo } from '~/stores/page';
 import {
-  EditorMode, useDrawerMode, useEditorMode, useIsDeviceSmallerThanMd, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
+  EditorMode, useDrawerMode, useEditorMode, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
   useIsAbleToShowPageEditorModeManager, useIsAbleToShowPageAuthors,
 } from '~/stores/ui';
 
@@ -36,7 +29,6 @@ import AttachmentIcon from '../Icons/AttachmentIcon';
 import HistoryIcon from '../Icons/HistoryIcon';
 import PresentationIcon from '../Icons/PresentationIcon';
 import ShareLinkIcon from '../Icons/ShareLinkIcon';
-import { withUnstatedContainers } from '../UnstatedUtils';
 
 
 import { GrowiSubNavigation } from './GrowiSubNavigation';
@@ -149,23 +141,25 @@ const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
   );
 };
 
+type GrowiContextualSubNavigationProps = {
+  isCompactMode: boolean,
+  isLinkSharingDisabled: boolean,
+};
+
+const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps): JSX.Element => {
+
+  const { data: pageData, mutate: mutateCurrentPage } = useSWRxCurrentPage();
+  const pageId = pageData?._id;
+  const path = pageData?.path;
+
+  const revision = pageData?.revision;
+  const revisionId = (revision != null && isPopulated(revision)) ? revision._id : undefined;
 
-const GrowiContextualSubNavigation = (props) => {
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: isDrawerMode } = useDrawerMode();
   const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
-  const { data: createdAt } = useCurrentCreatedAt();
-  const { data: updatedAt } = useCurrentUpdatedAt();
-  const { data: pageId } = useCurrentPageId();
-  const { data: emptyPageId } = useEmptyPageId();
-  const { data: revisionId } = useRevisionId();
-  const { data: path } = useCurrentPagePath();
-  const { data: creator } = useCreator();
-  const { data: revisionAuthor } = useRevisionAuthor();
   const { data: currentUser } = useCurrentUser();
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isSharedUser } = useIsSharedUser();
-  const { data: shareLinkId } = useShareLinkId();
 
   const { data: isAbleToShowPageManagement } = useIsAbleToShowPageManagement();
   const { data: isAbleToShowTagLabel } = useIsAbleToShowTagLabel();
@@ -187,18 +181,15 @@ const GrowiContextualSubNavigation = (props) => {
 
   const [isPageTemplateModalShown, setIsPageTempleteModalShown] = useState(false);
 
-  const {
-    isCompactMode, isLinkSharingDisabled, pageContainer,
-  } = props;
+  const { isCompactMode, isLinkSharingDisabled } = props;
 
   const isViewMode = editorMode === EditorMode.View;
 
 
   const tagsUpdatedHandlerForViewMode = useCallback(async(newTags: string[]) => {
     try {
-      const res: IResTagsUpdateApiv1 = await apiPost('/tags.update', { pageId, revisionId, tags: newTags });
-      const updatedRevisionId = getIdForRef(res.savedPage.revision);
-      await pageContainer.setState({ revisionId: updatedRevisionId });
+      await apiPost('/tags.update', { pageId, revisionId, tags: newTags });
+      mutateCurrentPage();
 
       // revalidate SWRTagsInfo
       mutateSWRTagsInfo();
@@ -210,7 +201,7 @@ const GrowiContextualSubNavigation = (props) => {
       toastError(err, 'fail to update tags');
     }
 
-  }, [pageId, revisionId, mutateSWRTagsInfo, mutatePageTagsForEditors, pageContainer]);
+  }, [mutateSWRTagsInfo, mutatePageTagsForEditors, mutateCurrentPage, pageId, revisionId]);
 
   const tagsUpdatedHandlerForEditMode = useCallback((newTags: string[]): void => {
     // It will not be reflected in the DB until the page is refreshed
@@ -262,7 +253,7 @@ const GrowiContextualSubNavigation = (props) => {
 
 
   const ControlComponents = useCallback(() => {
-    const pageIdForSubNavButtons = pageId ?? emptyPageId; // for SubNavButtons
+    const pageIdForSubNavButtons = pageId; // for SubNavButtons
 
     function onPageEditorModeButtonClicked(viewType) {
       mutateEditorMode(viewType);
@@ -288,7 +279,6 @@ const GrowiContextualSubNavigation = (props) => {
               <SubNavButtons
                 isCompactMode={isCompactMode}
                 pageId={pageIdForSubNavButtons}
-                shareLinkId={shareLinkId}
                 revisionId={revisionId}
                 path={path}
                 disableSeenUserInfoPopover={isSharedUser}
@@ -305,7 +295,6 @@ const GrowiContextualSubNavigation = (props) => {
               onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
               isBtnDisabled={isGuestUser}
               editorMode={editorMode}
-              isDeviceSmallerThanMd={isDeviceSmallerThanMd}
             />
           )}
         </div>
@@ -319,30 +308,20 @@ const GrowiContextualSubNavigation = (props) => {
       </>
     );
   }, [
-    pageId, emptyPageId, revisionId, shareLinkId, editorMode, mutateEditorMode, isCompactMode,
-    isLinkSharingDisabled, isDeviceSmallerThanMd, isGuestUser, isSharedUser, currentUser,
+    pageId, revisionId, editorMode, mutateEditorMode, isCompactMode,
+    isLinkSharingDisabled, isGuestUser, isSharedUser, currentUser,
     isViewMode, isAbleToShowPageEditorModeManager, isAbleToShowPageManagement,
     duplicateItemClickedHandler, renameItemClickedHandler, deleteItemClickedHandler,
     path, templateMenuItemClickHandler, isPageTemplateModalShown,
   ]);
 
-  if (path == null) {
+  if (pageData == null) {
     return <></>;
   }
 
-  const currentPage: Partial<IPageHasId> = {
-    _id: pageId ?? undefined,
-    path,
-    revision: revisionId ?? undefined,
-    creator: creator ?? undefined,
-    lastUpdateUser: revisionAuthor,
-    createdAt: createdAt ?? undefined,
-    updatedAt: updatedAt ?? undefined,
-  };
-
   return (
     <GrowiSubNavigation
-      page={currentPage}
+      page={pageData}
       showDrawerToggler={isDrawerMode}
       showTagLabel={isAbleToShowTagLabel}
       showPageAuthors={isAbleToShowPageAuthors}
@@ -357,18 +336,5 @@ const GrowiContextualSubNavigation = (props) => {
   );
 };
 
-/**
- * Wrapper component for using unstated
- */
-const GrowiContextualSubNavigationWrapper = withUnstatedContainers(GrowiContextualSubNavigation, [EditorContainer, PageContainer]);
-
-
-GrowiContextualSubNavigation.propTypes = {
-  editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
-  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
-
-  isCompactMode: PropTypes.bool,
-  isLinkSharingDisabled: PropTypes.bool,
-};
 
-export default GrowiContextualSubNavigationWrapper;
+export default GrowiContextualSubNavigation;

+ 5 - 15
packages/app/src/components/Navbar/PageEditorModeManager.jsx

@@ -4,12 +4,9 @@ import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import { UncontrolledTooltip } from 'reactstrap';
 
-import AppContainer from '~/client/services/AppContainer';
-import { useCurrentUser } from '~/stores/context';
+import { useCurrentUser, useHackmdUri } from '~/stores/context';
 import { EditorMode, useIsDeviceSmallerThanMd } from '~/stores/ui';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
-
 /* eslint-disable react/prop-types */
 const PageEditorModeButtonWrapper = React.memo(({
   editorMode, isBtnDisabled, onClick, targetMode, icon, label, id,
@@ -42,16 +39,16 @@ PageEditorModeButtonWrapper.displayName = 'PageEditorModeButtonWrapper';
 
 function PageEditorModeManager(props) {
   const {
-    appContainer,
     editorMode, onPageEditorModeButtonClicked, isBtnDisabled,
   } = props;
 
   const { t } = useTranslation();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: currentUser } = useCurrentUser();
+  const { data: hackmdUri } = useHackmdUri();
 
-  const isAdmin = currentUser?.isAdmin;
-  const isHackmdEnabled = appContainer.config.env.HACKMD_URI != null;
+  const isAdmin = currentUser?.admin;
+  const isHackmdEnabled = hackmdUri != null;
   const showHackmdBtn = isHackmdEnabled || isAdmin;
 
   const pageEditorModeButtonClickedHandler = useCallback((viewType) => {
@@ -121,8 +118,6 @@ function PageEditorModeManager(props) {
 }
 
 PageEditorModeManager.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-
   onPageEditorModeButtonClicked: PropTypes.func,
   isBtnDisabled: PropTypes.bool,
   editorMode: PropTypes.string,
@@ -132,9 +127,4 @@ PageEditorModeManager.defaultProps = {
   isBtnDisabled: false,
 };
 
-/**
- * Wrapper component for using unstated
- */
-const PageEditorModeManagerWrapper = withUnstatedContainers(PageEditorModeManager, [AppContainer]);
-
-export default PageEditorModeManagerWrapper;
+export default PageEditorModeManager;

+ 0 - 6
packages/app/src/interfaces/page-listing-results.ts

@@ -22,12 +22,6 @@ export interface TargetAndAncestors {
   rootPage: Partial<IPageForItem>,
 }
 
-
-export interface IsNotFoundPermalink {
-  isNotFoundPermalink: boolean
-}
-
-
 export interface V5MigrationStatus {
   isV5Compatible : boolean,
   migratablePagesCount: number

+ 21 - 12
packages/app/src/pages/[[...path]].page.tsx

@@ -26,8 +26,9 @@ import loggerFactory from '~/utils/logger';
 
 // import GrowiSubNavigation from '../client/js/components/Navbar/GrowiSubNavigation';
 // import GrowiSubNavigationSwitcher from '../client/js/components/Navbar/GrowiSubNavigationSwitcher';
-// import DisplaySwitcher from '../client/js/components/Page/DisplaySwitcher';
 import { BasicLayout } from '../components/BasicLayout';
+import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
+// import DisplaySwitcher from '../client/js/components/Page/DisplaySwitcher';
 
 // import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
 // import PageStatusAlert from '../client/js/components/PageStatusAlert';
@@ -35,10 +36,10 @@ import { BasicLayout } from '../components/BasicLayout';
 
 import {
   useCurrentUser, useCurrentPagePath,
-  useOwnerOfCurrentPage,
-  useIsForbidden, useIsNotFound, useIsTrashPage, useShared, useShareLinkId, useIsSharedUser, useIsAbleToDeleteCompletely,
-  useAppTitle, useSiteUrl, useConfidential, useIsEnabledStaleNotification,
-  useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsMailerSetup,
+  useOwnerOfCurrentPage, useIsUserPage, useCurrentPageId,
+  useIsForbidden, useIsNotFoundPermalink, useIsTrashPage, useShareLinkId, useIsSharedUser, useIsAbleToDeleteCompletely,
+  useAppTitle, useSiteUrl, useConfidential, useIsEnabledStaleNotification, useIsGuestUser, useIsNotCreatable,
+  useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsMailerSetup, useIsIdenticalPath,
   useAclEnabled, useHasSlackConfig, useDrawioUri, useHackmdUri, useMathJax, useNoCdn, useEditorConfig, useCsrfToken, useIsSearchScopeChildrenAsDefault,
 } from '../stores/context';
 
@@ -47,7 +48,9 @@ import { CommonProps, getServerSideCommonProps, useCustomTitle } from './commons
 
 
 const logger = loggerFactory('growi:pages:all');
-const { isUsersHomePage, isTrashPage: _isTrashPage } = pagePathUtils;
+const {
+  isUsersHomePage, isTrashPage: _isTrashPage, isUserPage, isCreatablePage,
+} = pagePathUtils;
 
 type Props = CommonProps & {
   currentUser: string,
@@ -69,7 +72,7 @@ type Props = CommonProps & {
   // isAclEnabled: boolean,
   // hasSlackConfig: boolean,
   // drawioUri: string,
-  // hackmdUri: string,
+  hackmdUri: string,
   // mathJax: string,
   // noCdn: string,
   // highlightJsStyle: string,
@@ -99,11 +102,12 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   // page
   useCurrentPagePath(props.currentPathname);
   // useOwnerOfCurrentPage(props.pageUser != null ? JSON.parse(props.pageUser) : null);
-  // useIsForbidden(props.isForbidden);
+  useIsForbidden(props.isForbidden);
   // useNotFound(props.isNotFound);
-  // useIsTrashPage(_isTrashPage(props.currentPagePath));
-  // useShared(isSharedPage(props.currentPagePath));
   // useShareLinkId(props.shareLinkId);
+  useIsSharedUser(props.currentUser == null); // '/shared' is not routed this page
+  useIsNotFoundPermalink(props.isNotFound ?? false);
+  useIsIdenticalPath(false); // TODO: need to initialize from props
   // useIsAbleToDeleteCompletely(props.isAbleToDeleteCompletely);
   // useIsSharedUser(props.currentUser == null && isSharedPage(props.currentPagePath));
   // useIsEnabledStaleNotification(props.isEnabledStaleNotification);
@@ -115,7 +119,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   // useAclEnabled(props.isAclEnabled);
   // useHasSlackConfig(props.hasSlackConfig);
   // useDrawioUri(props.drawioUri);
-  // useHackmdUri(props.hackmdUri);
+  useHackmdUri(props.hackmdUri);
   // useMathJax(props.mathJax);
   // useNoCdn(props.noCdn);
   // useIndentSize(props.adminPreferredIndentSize);
@@ -133,8 +137,12 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   if (props.pageWithMetaStr != null) {
     pageWithMeta = JSON.parse(props.pageWithMetaStr) as IPageWithMeta;
   }
+  useCurrentPageId(pageWithMeta?.data._id);
   useSWRxCurrentPage(undefined, pageWithMeta?.data); // store initial data
   useSWRxPageInfo(pageWithMeta?.data._id, undefined, pageWithMeta?.meta); // store initial data
+  useIsTrashPage(_isTrashPage(pageWithMeta?.data.path ?? ''));
+  useIsUserPage(isUserPage(pageWithMeta?.data.path ?? ''));
+  useIsNotCreatable(props.isForbidden || !isCreatablePage(pageWithMeta?.data.path ?? '')); // TODO: need to include props.isIdentical
 
   const classNames: string[] = [];
   // switch (editorMode) {
@@ -176,6 +184,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
         <header className="py-0">
           {/* <GrowiSubNavigation /> */}
           GrowiSubNavigation
+          <GrowiContextualSubNavigation />
         </header>
         <div className="d-edit-none">
           {/* <GrowiSubNavigationSwitcher /> */}
@@ -292,7 +301,7 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
   // props.isAclEnabled = aclService.isAclEnabled();
   // props.hasSlackConfig = slackNotificationService.hasSlackConfig();
   // props.drawioUri = configManager.getConfig('crowi', 'app:drawioUri');
-  // props.hackmdUri = configManager.getConfig('crowi', 'app:hackmdUri');
+  props.hackmdUri = configManager.getConfig('crowi', 'app:hackmdUri');
   // props.mathJax = configManager.getConfig('crowi', 'app:mathJax');
   // props.noCdn = configManager.getConfig('crowi', 'app:noCdn');
   // props.highlightJsStyle = configManager.getConfig('crowi', 'customize:highlightJsStyle');

+ 11 - 16
packages/app/src/stores/context.tsx

@@ -3,7 +3,7 @@ import { Key, SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
 
-import { TargetAndAncestors, IsNotFoundPermalink } from '../interfaces/page-listing-results';
+import { TargetAndAncestors } from '../interfaces/page-listing-results';
 import { IUser } from '../interfaces/user';
 
 import { useStaticSWR } from './use-static-swr';
@@ -96,6 +96,10 @@ export const useTemplateTagData = (initialData?: Nullable<any>): SWRResponse<Nul
   return useStaticSWR<Nullable<any>, Error>('templateTagData', initialData);
 };
 
+export const useIsSharedUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
+  return useStaticSWR<boolean, Error>('isSharedUser', initialData);
+};
+
 export const useShareLinksNumber = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {
   return useStaticSWR<Nullable<any>, Error>('shareLinksNumber', initialData);
 };
@@ -108,6 +112,10 @@ export const useRevisionIdHackmdSynced = (initialData?: Nullable<any>): SWRRespo
   return useStaticSWR<Nullable<any>, Error>('revisionIdHackmdSynced', initialData);
 };
 
+export const useHackmdUri = (initialData?: Nullable<string>): SWRResponse<Nullable<string>, Error> => {
+  return useStaticSWR<Nullable<string>, Error>('hackmdUri', initialData);
+};
+
 export const useLastUpdateUsername = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {
   return useStaticSWR<Nullable<any>, Error>('lastUpdateUsername', initialData);
 };
@@ -144,8 +152,8 @@ export const useNotFoundTargetPathOrId = (initialData?: string): SWRResponse<str
   return useStaticSWR<string, Error>('notFoundTargetPathOrId', initialData);
 };
 
-export const useIsNotFoundPermalink = (initialData?: Nullable<IsNotFoundPermalink>): SWRResponse<Nullable<IsNotFoundPermalink>, Error> => {
-  return useStaticSWR<Nullable<IsNotFoundPermalink>, Error>('isNotFoundPermalink', initialData);
+export const useIsNotFoundPermalink = (initialData?: Nullable<boolean>): SWRResponse<Nullable<boolean>, Error> => {
+  return useStaticSWR<Nullable<boolean>, Error>('isNotFoundPermalink', initialData);
 };
 
 export const useIsAclEnabled = (initialData?: boolean) : SWRResponse<boolean, Error> => {
@@ -213,16 +221,3 @@ export const useIsEditable = (): SWRResponse<boolean, Error> => {
     },
   );
 };
-
-export const useIsSharedUser = (): SWRResponse<boolean, Error> => {
-  const { data: isGuestUser } = useIsGuestUser();
-
-  const pathname = window.location.pathname;
-
-  return useSWRImmutable(
-    ['isSharedUser', isGuestUser, pathname],
-    (key: Key, isGuestUser: boolean, pathname: string) => {
-      return isGuestUser && pagePathUtils.isSharedPage(pathname);
-    },
-  );
-};

+ 8 - 8
packages/app/src/stores/ui.tsx

@@ -1,5 +1,7 @@
 import { RefObject } from 'react';
 
+import { constants } from 'zlib';
+
 import { isClient, pagePathUtils } from '@growi/core';
 import { Breakpoint, addBreakpointListener } from '@growi/ui';
 import SimpleBar from 'simplebar-react';
@@ -23,7 +25,6 @@ import {
 } from './context';
 import { localStorageMiddleware } from './middlewares/sync-to-storage';
 import { useStaticSWR } from './use-static-swr';
-import { constants } from 'zlib';
 
 const { isSharedPage } = pagePathUtils;
 
@@ -112,6 +113,7 @@ const updateHashByEditorMode = (newEditorMode: EditorMode) => {
 };
 
 export const determineEditorModeByHash = (): EditorMode => {
+  if (!isClient()) { return EditorMode.View }
   const { hash } = window.location;
 
   switch (hash) {
@@ -404,11 +406,10 @@ export const useIsAbleToShowTrashPageManagementButtons = (): SWRResponse<boolean
 export const useIsAbleToShowPageManagement = (): SWRResponse<boolean, Error> => {
   const key = 'isAbleToShowPageManagement';
   const { data: currentPageId } = useCurrentPageId();
-  const { data: emptyPageId } = useEmptyPageId();
   const { data: isTrashPage } = useIsTrashPage();
   const { data: isSharedUser } = useIsSharedUser();
 
-  const pageId = currentPageId ?? emptyPageId;
+  const pageId = currentPageId;
   const includesUndefined = [pageId, isTrashPage, isSharedUser].some(v => v === undefined);
   const isPageExist = pageId != null;
 
@@ -422,19 +423,18 @@ export const useIsAbleToShowTagLabel = (): SWRResponse<boolean, Error> => {
   const key = 'isAbleToShowTagLabel';
   const { data: isUserPage } = useIsUserPage();
   const { data: currentPagePath } = useCurrentPagePath();
-  const { data: isIdenticalPath } = useIsIdenticalPath();
-  const { data: notFoundTargetPathOrId } = useNotFoundTargetPathOrId();
+  const { data: isIdenticalPath } = useIsIdenticalPath(); // TODO: need to initialize at [[...page]].page.tsx
+  const { data: isNotFound } = useIsNotFoundPermalink();
   const { data: editorMode } = useEditorMode();
 
-  const includesUndefined = [isUserPage, currentPagePath, isIdenticalPath, notFoundTargetPathOrId, editorMode].some(v => v === undefined);
+  const includesUndefined = [isUserPage, currentPagePath, isIdenticalPath, isNotFound, editorMode].some(v => v === undefined);
 
   const isViewMode = editorMode === EditorMode.View;
-  const isNotFoundPage = notFoundTargetPathOrId != null;
 
   return useSWRImmutable(
     includesUndefined ? null : [key, editorMode],
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    () => !isUserPage && !isSharedPage(currentPagePath!) && !isIdenticalPath && !(isViewMode && isNotFoundPage),
+    () => !isUserPage && !isSharedPage(currentPagePath!) && !isIdenticalPath && !(isViewMode && isNotFound),
   );
 };