Ver código fonte

Merge pull request #6105 from weseek/feat/fix-swr-hook-for-is-empty-page

feat: Modify swr hook for isEmptyPage & separate pageId and emptyPageId
Haku Mizuki 3 anos atrás
pai
commit
df0f9c9b35

+ 4 - 2
packages/app/src/client/services/ContextExtractor.tsx

@@ -18,7 +18,7 @@ import {
   useShareLinkId, useShareLinksNumber, useTemplateTagData, useCurrentUpdatedAt, useCreator, useRevisionAuthor, useCurrentUser, useTargetAndAncestors,
   useNotFoundTargetPathOrId, useIsSearchPage, useIsForbidden, useIsIdenticalPath, useHasParent,
   useIsAclEnabled, useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsEnabledAttachTitleHeader, useIsNotFoundPermalink,
-  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useIsEmptyPage,
+  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useIsEmptyPage, useEmptyPageId,
 } from '../../stores/context';
 
 const { isTrashPage: _isTrashPage } = pagePathUtils;
@@ -58,7 +58,8 @@ const ContextExtractorOnce: FC = () => {
   const revisionId = mainContent?.getAttribute('data-page-revision-id');
   const path = decodeURI(mainContent?.getAttribute('data-path') || '');
   // assign `null` to avoid returning empty string
-  const pageId = (mainContent?.getAttribute('data-page-id') || notFoundContext?.getAttribute('data-page-id')) || null;
+  const pageId = mainContent?.getAttribute('data-page-id') || null;
+  const emptyPageId = notFoundContext?.getAttribute('data-page-id') || null;
 
   const revisionCreatedAt = +(mainContent?.getAttribute('data-page-revision-created') || '');
 
@@ -138,6 +139,7 @@ const ContextExtractorOnce: FC = () => {
   useIsUserPage(isUserPage);
   useLastUpdateUsername(lastUpdateUsername);
   useCurrentPageId(pageId);
+  useEmptyPageId(emptyPageId);
   usePageIdOnHackmd(pageIdOnHackmd);
   usePageUser(pageUser);
   useCurrentPagePath(path);

+ 7 - 4
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -14,7 +14,7 @@ import {
 import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import {
   useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath,
-  useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId,
+  useCreator, useRevisionAuthor, useCurrentUser, useIsGuestUser, useIsSharedUser, useShareLinkId, useEmptyPageId,
 } from '~/stores/context';
 import {
   usePageAccessoriesModal, PageAccessoriesModalContents, IPageForPageDuplicateModal,
@@ -153,6 +153,7 @@ const GrowiContextualSubNavigation = (props) => {
   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();
@@ -247,6 +248,8 @@ const GrowiContextualSubNavigation = (props) => {
 
 
   const ControlComponents = useCallback(() => {
+    const pageIdForSubNavButtons = pageId ?? emptyPageId; // for SubNavButtons
+
     function onPageEditorModeButtonClicked(viewType) {
       mutateEditorMode(viewType);
     }
@@ -266,11 +269,11 @@ const GrowiContextualSubNavigation = (props) => {
     return (
       <>
         <div className="d-flex flex-column align-items-end justify-content-center py-md-2" style={{ gap: `${isCompactMode ? '5px' : '7px'}` }}>
-          { pageId != null && isViewMode && (
+          { pageIdForSubNavButtons != null && isViewMode && (
             <div className="h-50">
               <SubNavButtons
                 isCompactMode={isCompactMode}
-                pageId={pageId}
+                pageId={pageIdForSubNavButtons}
                 shareLinkId={shareLinkId}
                 revisionId={revisionId}
                 path={path}
@@ -302,7 +305,7 @@ const GrowiContextualSubNavigation = (props) => {
       </>
     );
   }, [
-    pageId, revisionId, shareLinkId, editorMode, mutateEditorMode, isCompactMode,
+    pageId, emptyPageId, revisionId, shareLinkId, editorMode, mutateEditorMode, isCompactMode,
     isLinkSharingDisabled, isDeviceSmallerThanMd, isGuestUser, isSharedUser, currentUser,
     isViewMode, isAbleToShowPageEditorModeManager, isAbleToShowPageManagement,
     duplicateItemClickedHandler, renameItemClickedHandler, deleteItemClickedHandler,

+ 4 - 8
packages/app/src/components/NotFoundPage.tsx

@@ -3,7 +3,7 @@ import React, { useMemo, useEffect } from 'react';
 import { useTranslation } from 'react-i18next';
 import urljoin from 'url-join';
 
-import { useCurrentPageId, useCurrentPagePath, useNotFoundTargetPathOrId } from '~/stores/context';
+import { useCurrentPagePath, useIsEmptyPage, useNotFoundTargetPathOrId } from '~/stores/context';
 
 import CustomNavAndContents from './CustomNavigation/CustomNavAndContents';
 import { DescendantsPageListForCurrentPath } from './DescendantsPageList';
@@ -21,7 +21,7 @@ const replaceURLHistory = (path: string) => {
 
 const NotFoundPage = (): JSX.Element => {
   const { t } = useTranslation();
-  const { data: pageId } = useCurrentPageId();
+  const { data: isEmptyPage } = useIsEmptyPage();
   const { data: path } = useCurrentPagePath();
   const { data: notFoundTargetPathOrId } = useNotFoundTargetPathOrId();
 
@@ -30,15 +30,11 @@ const NotFoundPage = (): JSX.Element => {
     if (path == null) {
       return;
     }
-
-    const isEmptyPage = pageId != null; // Todo: should be improved. https://redmine.weseek.co.jp/issues/98152
     const isPermalink = !notFoundTargetPathOrId?.includes('/');
     if (isEmptyPage && isPermalink) {
-      // The (as string) below is a workaround for the case. See the link. (Fixed in typescript version 4.4)
-      // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html#control-flow-analysis-of-aliased-conditions-and-discriminants
-      replaceURLHistory(path as string);
+      replaceURLHistory(path);
     }
-  }, [pageId, path, notFoundTargetPathOrId]);
+  }, [path, isEmptyPage, notFoundTargetPathOrId]);
 
   const navTabMapping = useMemo(() => {
     return {

+ 1 - 3
packages/app/src/components/Page/FixPageGrantAlert.tsx

@@ -9,9 +9,7 @@ import { toastError, toastSuccess } from '~/client/util/apiNotification';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { PageGrant, IPageGrantData } from '~/interfaces/page';
 import { IRecordApplicableGrant, IResIsGrantNormalizedGrantData } from '~/interfaces/page-grant';
-import {
-  useCurrentPageId, useCurrentUser, useHasParent,
-} from '~/stores/context';
+import { useCurrentPageId, useCurrentUser, useHasParent } from '~/stores/context';
 import { useSWRxApplicableGrant, useSWRxIsGrantNormalized } from '~/stores/page';
 
 type ModalProps = {

+ 5 - 1
packages/app/src/stores/context.tsx

@@ -36,6 +36,10 @@ export const useCurrentPageId = (initialData?: Nullable<string>): SWRResponse<Nu
   return useStaticSWR<Nullable<string>, Error>('currentPageId', initialData);
 };
 
+export const useEmptyPageId = (initialData?: Nullable<string>): SWRResponse<Nullable<string>, Error> => {
+  return useStaticSWR<Nullable<string>, Error>('emptyPageId', initialData);
+};
+
 export const useRevisionCreatedAt = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {
   return useStaticSWR<Nullable<any>, Error>('revisionCreatedAt', initialData);
 };
@@ -157,7 +161,7 @@ export const useIsEnabledAttachTitleHeader = (initialData?: boolean) : SWRRespon
 };
 
 export const useIsEmptyPage = (initialData?: boolean) : SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isEmptyPageInNotFoundContext', initialData);
+  return useStaticSWR<boolean, Error>('isEmptyPage', initialData);
 };
 export const useHasParent = (initialData?: boolean) : SWRResponse<boolean, Error> => {
   return useStaticSWR<boolean, Error>('hasParent', initialData);

+ 6 - 5
packages/app/src/stores/ui.tsx

@@ -16,7 +16,7 @@ import { UpdateDescCountData } from '~/interfaces/websocket';
 import loggerFactory from '~/utils/logger';
 
 import {
-  useCurrentPageId, useCurrentPagePath, useIsEditable, useIsTrashPage, useIsUserPage, useIsGuestUser, useIsEmptyPage,
+  useCurrentPageId, useCurrentPagePath, useIsEditable, useIsTrashPage, useIsUserPage, useIsGuestUser, useEmptyPageId,
   useIsNotCreatable, useIsSharedUser, useNotFoundTargetPathOrId, useIsForbidden, useIsIdenticalPath, useIsNotFoundPermalink, useCurrentUser, useIsDeleted,
 } from './context';
 import { localStorageMiddleware } from './middlewares/sync-to-storage';
@@ -336,11 +336,13 @@ 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 includesUndefined = [currentPageId, isTrashPage, isSharedUser].some(v => v === undefined);
-  const isPageExist = currentPageId != null;
+  const pageId = currentPageId ?? emptyPageId;
+  const includesUndefined = [pageId, isTrashPage, isSharedUser].some(v => v === undefined);
+  const isPageExist = pageId != null;
 
   return useSWRImmutable(
     includesUndefined ? null : key,
@@ -388,13 +390,12 @@ export const useIsAbleToShowPageAuthors = (): SWRResponse<boolean, Error> => {
   const key = 'isAbleToShowPageAuthors';
   const { data: currentPageId } = useCurrentPageId();
   const { data: isUserPage } = useIsUserPage();
-  const { data: isEmptyPageInNotFoundContext } = useIsEmptyPage();
 
   const includesUndefined = [currentPageId, isUserPage].some(v => v === undefined);
   const isPageExist = currentPageId != null;
 
   return useSWRImmutable(
-    (includesUndefined || isEmptyPageInNotFoundContext) ? null : key,
+    includesUndefined ? null : key,
     () => isPageExist && !isUserPage,
   );
 };