nHigashiWeseek 1 anno fa
parent
commit
d70f458435

+ 5 - 6
apps/app/src/client/components/DescendantsPageList.tsx

@@ -14,7 +14,7 @@ import type { OnDeletedFunction, OnPutBackedFunction } from '~/interfaces/ui';
 import { useIsGuestUser, useIsReadOnlyUser, useIsSharedUser } from '~/stores-universal/context';
 import {
   mutatePageTree,
-  useSWRxPageInfoForList, useSWRxPageList, useSWRINFxRecentlyUpdated,
+  useSWRxPageInfoForList, useSWRxPageList, mutateSWRINFxRecentlyUpdated,
 } from '~/stores/page-listing';
 
 import type { ForceHideMenuItems } from './Common/Dropdown/PageItemControl';
@@ -47,7 +47,6 @@ const DescendantsPageListSubstance = (props: SubstanceProps): JSX.Element => {
 
   const pageIds = pagingResult?.items?.map(page => page._id);
   const { injectTo } = useSWRxPageInfoForList(pageIds, null, true, true);
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
 
   let pageWithMetas: IDataWithMeta<IPageHasId, IPageInfoForOperation>[] = [];
 
@@ -68,22 +67,22 @@ const DescendantsPageListSubstance = (props: SubstanceProps): JSX.Element => {
     else {
       toastSuccess(t('deleted_pages_completely', { path }));
     }
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutatePageTree();
     if (onPagesDeleted != null) {
       onPagesDeleted(...args);
     }
-  }, [onPagesDeleted, mutateRecentlyUpdated, t]);
+  }, [onPagesDeleted, t]);
 
   const pagePutBackedHandler: OnPutBackedFunction = useCallback((path) => {
     toastSuccess(t('page_has_been_reverted', { path }));
 
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutatePageTree();
     if (onPagePutBacked != null) {
       onPagePutBacked(path);
     }
-  }, [onPagePutBacked, mutateRecentlyUpdated, t]);
+  }, [onPagePutBacked, t]);
 
   if (pagingResult == null) {
     return (

+ 5 - 6
apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -34,7 +34,7 @@ import {
 import {
   useSWRMUTxCurrentPage, useCurrentPageId, useSWRxPageInfo,
 } from '~/stores/page';
-import { mutatePageTree, useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+import { mutatePageTree, mutateSWRINFxRecentlyUpdated } from '~/stores/page-listing';
 import {
   useIsAbleToShowPageManagement,
   useIsAbleToChangeEditorMode,
@@ -247,7 +247,6 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
   const { open: openRenameModal } = usePageRenameModal();
   const { open: openDeleteModal } = usePageDeleteModal();
   const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId);
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
 
   const [isStickyActive, setStickyActive] = useState(false);
 
@@ -272,10 +271,10 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
       mutateCurrentPage();
       mutatePageInfo();
       mutatePageTree();
-      mutateRecentlyUpdated();
+      mutateSWRINFxRecentlyUpdated();
     };
     openRenameModal(page, { onRenamed: renamedHandler });
-  }, [mutateCurrentPage, mutatePageInfo, openRenameModal, mutateRecentlyUpdated]);
+  }, [mutateCurrentPage, mutatePageInfo, openRenameModal]);
 
   const deleteItemClickedHandler = useCallback((pageWithMeta: IPageWithMeta) => {
     const deletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively, isCompletely) => {
@@ -296,10 +295,10 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
       mutateCurrentPage();
       mutatePageInfo();
       mutatePageTree();
-      mutateRecentlyUpdated();
+      mutateSWRINFxRecentlyUpdated();
     };
     openDeleteModal([pageWithMeta], { onDeleted: deletedHandler });
-  }, [currentPathname, mutateCurrentPage, openDeleteModal, router, mutatePageInfo, mutateRecentlyUpdated]);
+  }, [currentPathname, mutateCurrentPage, openDeleteModal, router, mutatePageInfo]);
 
   const switchContentWidthHandler = useCallback(async(pageId: string, value: boolean) => {
     if (!isSharedPage) {

+ 3 - 5
apps/app/src/client/components/PageEditor/PageEditor.tsx

@@ -41,7 +41,7 @@ import {
 import {
   useCurrentPagePath, useSWRxCurrentPage, useCurrentPageId, useIsNotFound, useTemplateBodyData, useSWRxCurrentGrantData,
 } from '~/stores/page';
-import { mutatePageTree, useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+import { mutatePageTree, mutateSWRINFxRecentlyUpdated } from '~/stores/page-listing';
 import { usePreviewOptions } from '~/stores/renderer';
 import { useIsUntitledPage, useSelectedGrant } from '~/stores/ui';
 import { useEditingUsers } from '~/stores/use-editing-users';
@@ -165,8 +165,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
   const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);
   const scrollPreviewHandlerThrottle = useMemo(() => throttle(25, scrollPreviewHandler), [scrollPreviewHandler]);
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
-
 
   const save: Save = useCallback(async(revisionId, markdown, opts, onConflict) => {
     if (pageId == null || selectedGrant == null) {
@@ -193,7 +191,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
       // to sync revision id with page tree: https://github.com/weseek/growi/pull/7227
       mutatePageTree();
 
-      mutateRecentlyUpdated();
+      mutateSWRINFxRecentlyUpdated();
       // sync current grant data after update
       mutateIsGrantNormalized();
 
@@ -215,7 +213,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     finally {
       mutateWaitingSaveProcessing(false);
     }
-  }, [pageId, selectedGrant, mutateWaitingSaveProcessing, updatePage, mutateIsGrantNormalized, mutateRecentlyUpdated, t]);
+  }, [pageId, selectedGrant, mutateWaitingSaveProcessing, updatePage, mutateIsGrantNormalized, t]);
 
   const saveAndReturnToViewHandler = useCallback(async(opts: SaveOptions) => {
     const markdown = codeMirrorEditor?.getDoc();

+ 8 - 8
apps/app/src/client/components/SearchPage/SearchResultContent.tsx

@@ -21,7 +21,7 @@ import { useCurrentUser } from '~/stores-universal/context';
 import {
   usePageDuplicateModal, usePageRenameModal, usePageDeleteModal,
 } from '~/stores/modal';
-import { mutatePageList, mutatePageTree, useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+import { mutatePageList, mutatePageTree, mutateSWRINFxRecentlyUpdated } from '~/stores/page-listing';
 import { useSearchResultOptions } from '~/stores/renderer';
 import { mutateSearching } from '~/stores/search';
 
@@ -126,7 +126,7 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
   const { open: openDeleteModal } = usePageDeleteModal();
   const { data: rendererOptions } = useSearchResultOptions(pageWithMeta.data.path, highlightKeywords);
   const { data: currentUser } = useCurrentUser();
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
+
   const shouldExpandContent = useShouldExpandContent(page);
 
   const duplicateItemClickedHandler = useCallback(async(pageToDuplicate) => {
@@ -135,24 +135,24 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
       toastSuccess(t('duplicated_pages', { fromPath }));
 
       mutatePageTree();
-      mutateRecentlyUpdated();
+      mutateSWRINFxRecentlyUpdated();
       mutateSearching();
       mutatePageList();
     };
     openDuplicateModal(pageToDuplicate, { onDuplicated: duplicatedHandler });
-  }, [openDuplicateModal, mutateRecentlyUpdated, t]);
+  }, [openDuplicateModal, t]);
 
   const renameItemClickedHandler = useCallback((pageToRename: IPageToRenameWithMeta) => {
     const renamedHandler: OnRenamedFunction = (path) => {
       toastSuccess(t('renamed_pages', { path }));
 
       mutatePageTree();
-      mutateRecentlyUpdated();
+      mutateSWRINFxRecentlyUpdated();
       mutateSearching();
       mutatePageList();
     };
     openRenameModal(pageToRename, { onRenamed: renamedHandler });
-  }, [openRenameModal, mutateRecentlyUpdated, t]);
+  }, [openRenameModal, t]);
 
   const onDeletedHandler: OnDeletedFunction = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
     if (typeof pathOrPathsToDelete !== 'string') {
@@ -167,10 +167,10 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
       toastSuccess(t('deleted_pages', { path }));
     }
     mutatePageTree();
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutateSearching();
     mutatePageList();
-  }, [mutateRecentlyUpdated, t]);
+  }, [t]);
 
   const deleteItemClickedHandler = useCallback((pageToDelete: IPageToDeleteWithMeta) => {
     openDeleteModal([pageToDelete], { onDeleted: onDeletedHandler });

+ 7 - 9
apps/app/src/client/components/SearchPage/SearchResultList.tsx

@@ -12,7 +12,7 @@ import type { ISelectable, ISelectableAll } from '~/client/interfaces/selectable
 import { toastSuccess } from '~/client/util/toastr';
 import type { IPageSearchMeta, IPageWithSearchMeta } from '~/interfaces/search';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/stores-universal/context';
-import { mutatePageTree, useSWRxPageInfoForList, useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+import { mutatePageTree, useSWRxPageInfoForList, mutateSWRINFxRecentlyUpdated } from '~/stores/page-listing';
 import { mutateSearching } from '~/stores/search';
 
 import type { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
@@ -89,24 +89,22 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
     });
   }
 
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
-
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   const duplicatedHandler = useCallback((fromPath, toPath) => {
     toastSuccess(t('duplicated_pages', { fromPath }));
 
     mutatePageTree();
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutateSearching();
-  }, [t, mutateRecentlyUpdated]);
+  }, [t]);
 
   const renamedHandler = useCallback((path) => {
     toastSuccess(t('renamed_pages', { path }));
 
     mutatePageTree();
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutateSearching();
-  }, [t, mutateRecentlyUpdated]);
+  }, [t]);
 
   const deletedHandler = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
     if (typeof pathOrPathsToDelete !== 'string') {
@@ -122,9 +120,9 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
       toastSuccess(t('deleted_pages', { path }));
     }
     mutatePageTree();
-    mutateRecentlyUpdated();
+    mutateSWRINFxRecentlyUpdated();
     mutateSearching();
-  }, [t, mutateRecentlyUpdated]);
+  }, [t]);
 
   return (
     <ul data-testid="search-result-list" className="page-list-ul list-group list-group-flush">

+ 3 - 5
apps/app/src/client/components/TreeItem/NewPageInput/use-new-page-input.tsx

@@ -16,7 +16,7 @@ import { useCreatePage } from '~/client/services/create-page';
 import { toastWarning, toastError, toastSuccess } from '~/client/util/toastr';
 import type { InputValidationResult } from '~/client/util/use-input-validator';
 import { ValidationTarget, useInputValidator } from '~/client/util/use-input-validator';
-import { mutatePageTree, useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+import { mutatePageTree, mutateSWRINFxRecentlyUpdated } from '~/stores/page-listing';
 import { usePageTreeDescCountMap } from '~/stores/ui';
 
 import { shouldCreateWipPage } from '../../../../utils/should-create-wip-page';
@@ -89,8 +89,6 @@ export const useNewPageInput = (): UseNewPageInput => {
       setShowInput(false);
     }, []);
 
-    const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
-
     const create = useCallback(async(inputText) => {
       if (inputText.trim() === '') {
         return cancel();
@@ -125,7 +123,7 @@ export const useNewPageInput = (): UseNewPageInput => {
             skipTransition: true,
             onCreated: () => {
               mutatePageTree();
-              mutateRecentlyUpdated();
+              mutateSWRINFxRecentlyUpdated();
 
               if (!hasDescendants) {
                 stateHandlers?.setIsOpen(true);
@@ -142,7 +140,7 @@ export const useNewPageInput = (): UseNewPageInput => {
       finally {
         setProcessingSubmission(false);
       }
-    }, [cancel, hasDescendants, page.path, stateHandlers, t, createPage, mutateRecentlyUpdated]);
+    }, [cancel, hasDescendants, page.path, stateHandlers, t, createPage]);
 
     const inputContainerClass = newPageInputStyles['new-page-input-container'] ?? '';
     const isInvalid = validationResult != null;

+ 4 - 5
apps/app/src/components/PageView/PageAlerts/WipPageAlert.tsx

@@ -3,14 +3,12 @@ import React, { useCallback } from 'react';
 import { useTranslation } from 'react-i18next';
 
 import { useSWRMUTxCurrentPage, useSWRxCurrentPage } from '~/stores/page';
-import { useSWRINFxRecentlyUpdated } from '~/stores/page-listing';
+
 
 export const WipPageAlert = (): JSX.Element => {
   const { t } = useTranslation();
   const { data: currentPage } = useSWRxCurrentPage();
   const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
-  const { mutate: mutateRecentlyUpdated } = useSWRINFxRecentlyUpdated(20, true);
-
 
   const clickPagePublishButton = useCallback(async() => {
     const pageId = currentPage?._id;
@@ -28,7 +26,8 @@ export const WipPageAlert = (): JSX.Element => {
       const mutatePageTree = (await import('~/stores/page-listing')).mutatePageTree;
       await mutatePageTree();
 
-      await mutateRecentlyUpdated();
+      const mutateSWRINFxRecentlyUpdated = (await import('~/stores/page-listing')).mutateSWRINFxRecentlyUpdated;
+      await mutateSWRINFxRecentlyUpdated();
 
       const toastSuccess = (await import('~/client/util/toastr')).toastSuccess;
       toastSuccess(t('wip_page.success_publish_page'));
@@ -37,7 +36,7 @@ export const WipPageAlert = (): JSX.Element => {
       const toastError = (await import('~/client/util/toastr')).toastError;
       toastError(t('wip_page.fail_publish_page'));
     }
-  }, [currentPage?._id, mutateCurrentPage, t, mutateRecentlyUpdated]);
+  }, [currentPage?._id, mutateCurrentPage, t]);
 
 
   if (!currentPage?.wip) {

+ 12 - 1
apps/app/src/stores/page-listing.tsx

@@ -7,9 +7,10 @@ import type {
 import useSWR, {
   mutate, type SWRConfiguration, type SWRResponse, type Arguments,
 } from 'swr';
+import { cache } from 'swr/_internal';
 import useSWRImmutable from 'swr/immutable';
 import type { SWRInfiniteResponse } from 'swr/infinite';
-import useSWRInfinite from 'swr/infinite';
+import useSWRInfinite from 'swr/infinite'; // eslint-disable-line
 
 import type { IPagingResult } from '~/interfaces/paging-result';
 
@@ -54,6 +55,16 @@ export const useSWRINFxRecentlyUpdated = (limit: number, includeWipPage?: boolea
   );
 };
 
+export const mutateSWRINFxRecentlyUpdated = async(): Promise<void[] | undefined> => {
+  const promises: Promise<void>[] = [];
+  for (const key of cache.keys()) {
+    if (key.includes('/pages/recent')) {
+      promises.push(mutate(key));
+    }
+  }
+  return Promise.all(promises);
+};
+
 export const mutatePageList = async(): Promise<void[]> => {
   return mutate(
     key => Array.isArray(key) && key[0] === '/pages/list',