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

Merge pull request #10593 from growilabs/fix/page-info-api-and-page-item-control

fix: /page/info API and PageItemControl condition
Yuki Takei 3 месяцев назад
Родитель
Сommit
73f475f5dd

+ 16 - 4
apps/app/src/client/components/Common/Dropdown/PageItemControl.tsx

@@ -58,6 +58,7 @@ type CommonProps = {
 type DropdownMenuProps = CommonProps & {
 type DropdownMenuProps = CommonProps & {
   pageId: string,
   pageId: string,
   isLoading?: boolean,
   isLoading?: boolean,
+  isDataUnavailable?: boolean,
   operationProcessData?: IPageOperationProcessData,
   operationProcessData?: IPageOperationProcessData,
 }
 }
 
 
@@ -65,7 +66,7 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
   const { t } = useTranslation('');
   const { t } = useTranslation('');
 
 
   const {
   const {
-    pageId, isLoading, pageInfo, isEnableActions, isReadOnlyUser, forceHideMenuItems, operationProcessData,
+    pageId, isLoading, isDataUnavailable, pageInfo, isEnableActions, isReadOnlyUser, forceHideMenuItems, operationProcessData,
     onClickBookmarkMenuItem, onClickRenameMenuItem, onClickDuplicateMenuItem, onClickDeleteMenuItem,
     onClickBookmarkMenuItem, onClickRenameMenuItem, onClickDuplicateMenuItem, onClickDeleteMenuItem,
     onClickRevertMenuItem, onClickPathRecoveryMenuItem,
     onClickRevertMenuItem, onClickPathRecoveryMenuItem,
     additionalMenuItemOnTopRenderer: AdditionalMenuItemsOnTop,
     additionalMenuItemOnTopRenderer: AdditionalMenuItemsOnTop,
@@ -130,7 +131,15 @@ const PageItemControlDropdownMenu = React.memo((props: DropdownMenuProps): JSX.E
 
 
   let contents = <></>;
   let contents = <></>;
 
 
-  if (isLoading) {
+  if (isDataUnavailable) {
+    // Show message when data is not available (e.g., fetch error)
+    contents = (
+      <div className="text-warning text-center px-3">
+        <span className="material-symbols-outlined">error_outline</span> No data available
+      </div>
+    );
+  }
+  else if (isLoading) {
     contents = (
     contents = (
       <div className="text-muted text-center my-2">
       <div className="text-muted text-center my-2">
         <LoadingSpinner />
         <LoadingSpinner />
@@ -284,7 +293,7 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
   const [isOpen, setIsOpen] = useState(false);
   const [isOpen, setIsOpen] = useState(false);
   const [shouldFetch, setShouldFetch] = useState(false);
   const [shouldFetch, setShouldFetch] = useState(false);
 
 
-  const { data: fetchedPageInfo, mutate: mutatePageInfo } = useSWRxPageInfo(shouldFetch ? pageId : null);
+  const { data: fetchedPageInfo, error: fetchError, mutate: mutatePageInfo } = useSWRxPageInfo(shouldFetch ? pageId : null);
 
 
   // update shouldFetch (and will never be false)
   // update shouldFetch (and will never be false)
   useEffect(() => {
   useEffect(() => {
@@ -307,7 +316,9 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
     }
     }
   }, [mutatePageInfo, onClickBookmarkMenuItem, shouldFetch]);
   }, [mutatePageInfo, onClickBookmarkMenuItem, shouldFetch]);
 
 
-  const isLoading = shouldFetch && fetchedPageInfo == null;
+  // isLoading should be true only when fetching is in progress (data and error are both undefined)
+  const isLoading = shouldFetch && fetchedPageInfo == null && fetchError == null;
+  const isDataUnavailable = !isLoading && fetchedPageInfo == null && presetPageInfo == null;
 
 
   const renameMenuItemClickHandler = useCallback(async() => {
   const renameMenuItemClickHandler = useCallback(async() => {
     if (onClickRenameMenuItem == null) {
     if (onClickRenameMenuItem == null) {
@@ -350,6 +361,7 @@ export const PageItemControlSubstance = (props: PageItemControlSubstanceProps):
           <PageItemControlDropdownMenu
           <PageItemControlDropdownMenu
             {...props}
             {...props}
             isLoading={isLoading}
             isLoading={isLoading}
+            isDataUnavailable={isDataUnavailable}
             pageInfo={fetchedPageInfo ?? presetPageInfo}
             pageInfo={fetchedPageInfo ?? presetPageInfo}
             onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
             onClickBookmarkMenuItem={bookmarkMenuItemClickHandler}
             onClickRenameMenuItem={renameMenuItemClickHandler}
             onClickRenameMenuItem={renameMenuItemClickHandler}

+ 14 - 1
apps/app/src/server/routes/apiv3/page/index.ts

@@ -591,7 +591,20 @@ module.exports = (crowi: Crowi) => {
         );
         );
 
 
         if (isIPageNotFoundInfo(meta)) {
         if (isIPageNotFoundInfo(meta)) {
-          return res.apiv3Err(`Page '${pageId}' is not found or forbidden`);
+          // Return error only when the page is forbidden
+          // Empty pages (isEmpty: true) should return page info for UI operations
+          if (meta.isForbidden) {
+            return res.apiv3Err(
+              new ErrorV3(
+                'Page is forbidden',
+                'page-is-forbidden',
+                undefined,
+                meta,
+              ),
+              403,
+            );
+          }
+          // For not found but not forbidden pages (isEmpty: true), return the meta info
         }
         }
 
 
         return res.apiv3(meta);
         return res.apiv3(meta);