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

refactor GrowiContextualSubNavigation

Yuki Takei 4 лет назад
Родитель
Сommit
0c95c005a6

+ 2 - 2
packages/app/src/client/app.jsx

@@ -39,7 +39,7 @@ import MyDraftList from '../components/MyDraftList/MyDraftList';
 import BookmarkList from '../components/PageList/BookmarkList';
 import BookmarkList from '../components/PageList/BookmarkList';
 import Fab from '../components/Fab';
 import Fab from '../components/Fab';
 import PersonalSettings from '../components/Me/PersonalSettings';
 import PersonalSettings from '../components/Me/PersonalSettings';
-import GrowiSubNavigation from '../components/Navbar/GrowiSubNavigation';
+import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
 import GrowiSubNavigationSwitcher from '../components/Navbar/GrowiSubNavigationSwitcher';
 import GrowiSubNavigationSwitcher from '../components/Navbar/GrowiSubNavigationSwitcher';
 import IdenticalPathPage from '~/components/IdenticalPathPage';
 import IdenticalPathPage from '~/components/IdenticalPathPage';
 
 
@@ -146,7 +146,7 @@ if (pageContainer.state.path != null) {
   Object.assign(componentMappings, {
   Object.assign(componentMappings, {
     // eslint-disable-next-line quote-props
     // eslint-disable-next-line quote-props
     'page': <Page />,
     'page': <Page />,
-    'grw-subnav-container': <GrowiSubNavigation />,
+    'grw-subnav-container': <GrowiContextualSubNavigation />,
     'grw-subnav-switcher-container': <GrowiSubNavigationSwitcher />,
     'grw-subnav-switcher-container': <GrowiSubNavigationSwitcher />,
     'display-switcher': <DisplaySwitcher />,
     'display-switcher': <DisplaySwitcher />,
   });
   });

+ 1 - 1
packages/app/src/components/Navbar/AuthorInfo.jsx

@@ -34,7 +34,7 @@ const AuthorInfo = (props) => {
       if (err instanceof RangeError) {
       if (err instanceof RangeError) {
         return <p>{nullinfoLabelForFooter} <UserPicture user={user} size="sm" /> {userLabel}</p>;
         return <p>{nullinfoLabelForFooter} <UserPicture user={user} size="sm" /> {userLabel}</p>;
       }
       }
-      return;
+      return <></>;
     }
     }
   }
   }
 
 

+ 30 - 21
packages/app/src/components/Navbar/GrowiSubNavigation.jsx → packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -9,7 +9,7 @@ import {
 } from '~/stores/ui';
 } from '~/stores/ui';
 import {
 import {
   useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath, useIsDeletable,
   useCurrentCreatedAt, useCurrentUpdatedAt, useCurrentPageId, useRevisionId, useCurrentPagePath, useIsDeletable,
-  useIsAbleToDeleteCompletely, useCreator, useRevisionAuthor, useIsPageExist, useIsGuestUser,
+  useIsAbleToDeleteCompletely, useCreator, useRevisionAuthor, useIsGuestUser,
 } from '~/stores/context';
 } from '~/stores/context';
 import { useSWRTagsInfo } from '~/stores/page';
 import { useSWRTagsInfo } from '~/stores/page';
 
 
@@ -25,7 +25,7 @@ import PagePathNav from '../PagePathNav';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiPost } from '~/client/util/apiv1-client';
 
 
-const GrowiSubNavigation = (props) => {
+const GrowiContextualSubNavigation = (props) => {
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
   const { data: isDrawerMode } = useDrawerMode();
   const { data: isDrawerMode } = useDrawerMode();
   const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
   const { data: editorMode, mutate: mutateEditorMode } = useEditorMode();
@@ -53,19 +53,20 @@ const GrowiSubNavigation = (props) => {
 
 
   const isViewMode = editorMode === EditorMode.View;
   const isViewMode = editorMode === EditorMode.View;
   const isEditorMode = !isViewMode;
   const isEditorMode = !isViewMode;
+  const isPageExist = pageId != null;
 
 
   function onPageEditorModeButtonClicked(viewType) {
   function onPageEditorModeButtonClicked(viewType) {
     mutateEditorMode(viewType);
     mutateEditorMode(viewType);
   }
   }
 
 
-  const tagsUpdatedHandler = useCallback(async(newTags) => {
+  const tagsUpdatedHandler = useCallback(async(newTags: string[]) => {
     // It will not be reflected in the DB until the page is refreshed
     // It will not be reflected in the DB until the page is refreshed
-    if (editorMode === 'edit') {
+    if (editorMode === EditorMode.Editor) {
       return editorContainer.setState({ tags: newTags });
       return editorContainer.setState({ tags: newTags });
     }
     }
 
 
     try {
     try {
-      const { tags } = await apiPost('/tags.update', { pageId, revisionId, tags: newTags });
+      const { tags } = await apiPost('/tags.update', { pageId, revisionId, tags: newTags }) as { tags };
 
 
       // revalidate SWRTagsInfo
       // revalidate SWRTagsInfo
       mutateSWRTagsInfo();
       mutateSWRTagsInfo();
@@ -80,6 +81,10 @@ const GrowiSubNavigation = (props) => {
   // eslint-disable-next-line react-hooks/exhaustive-deps
   // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [pageId]);
   }, [pageId]);
 
 
+  if (path == null) {
+    return <></>;
+  }
+
   return (
   return (
     <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
     <div className={`grw-subnav container-fluid d-flex align-items-center justify-content-between ${isCompactMode ? 'grw-subnav-compact d-print-none' : ''}`}>
 
 
@@ -94,7 +99,7 @@ const GrowiSubNavigation = (props) => {
         <div className="grw-path-nav-container">
         <div className="grw-path-nav-container">
           { isAbleToShowTagLabel && !isCompactMode && (
           { isAbleToShowTagLabel && !isCompactMode && (
             <div className="grw-taglabels-container">
             <div className="grw-taglabels-container">
-              <TagLabels tags={TagsInfoData?.tags || []} tagsUpdateInvoked={tagsUpdatedHandler} />
+              <TagLabels tags={TagsInfoData?.tags || []} isGuestUser={isGuestUser ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
             </div>
             </div>
           ) }
           ) }
           <PagePathNav pageId={pageId} pagePath={path} isSingleLineMode={isEditorMode} isCompactMode={isCompactMode} />
           <PagePathNav pageId={pageId} pagePath={path} isSingleLineMode={isEditorMode} isCompactMode={isCompactMode} />
@@ -104,18 +109,22 @@ const GrowiSubNavigation = (props) => {
       {/* Right side */}
       {/* Right side */}
       <div className="d-flex">
       <div className="d-flex">
 
 
-        <div className="d-flex flex-column align-items-end">
-          <SubNavButtons
-            isCompactMode={isCompactMode}
-            pageId={pageId}
-            revisionId={revisionId}
-            path={path}
-            isDeletable={isDeletable}
-            isAbleToDeleteCompletely={isAbleToDeleteCompletely}
-            isViewMode={isViewMode}
-            isAbleToShowPageManagement={isAbleToShowPageManagement}
-          />
-          <div className="mt-2">
+        <div>
+          <div className="h-50 d-flex flex-column align-items-end justify-content-center">
+            { isPageExist && (
+              <SubNavButtons
+                isCompactMode={isCompactMode}
+                pageId={pageId}
+                revisionId={revisionId}
+                path={path}
+                isDeletable={isDeletable}
+                isAbleToDeleteCompletely={isAbleToDeleteCompletely}
+                isViewMode={isViewMode}
+                isAbleToShowPageManagement={isAbleToShowPageManagement}
+              />
+            ) }
+          </div>
+          <div className="h-50 d-flex flex-column align-items-end justify-content-center">
             {isAbleToShowPageEditorModeManager && (
             {isAbleToShowPageEditorModeManager && (
               <PageEditorModeManager
               <PageEditorModeManager
                 onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
                 onPageEditorModeButtonClicked={onPageEditorModeButtonClicked}
@@ -146,13 +155,13 @@ const GrowiSubNavigation = (props) => {
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
-const GrowiSubNavigationWrapper = withUnstatedContainers(GrowiSubNavigation, [EditorContainer]);
+const GrowiContextualSubNavigationWrapper = withUnstatedContainers(GrowiContextualSubNavigation, [EditorContainer]);
 
 
 
 
-GrowiSubNavigation.propTypes = {
+GrowiContextualSubNavigation.propTypes = {
   editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
   editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
 
 
   isCompactMode: PropTypes.bool,
   isCompactMode: PropTypes.bool,
 };
 };
 
 
-export default GrowiSubNavigationWrapper;
+export default GrowiContextualSubNavigationWrapper;

+ 2 - 2
packages/app/src/components/Navbar/GrowiSubNavigationSwitcher.jsx

@@ -8,7 +8,7 @@ import { debounce } from 'throttle-debounce';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 import { useSidebarCollapsed } from '~/stores/ui';
 import { useSidebarCollapsed } from '~/stores/ui';
 
 
-import GrowiSubNavigation from './GrowiSubNavigation';
+import GrowiContextualSubNavigation from './GrowiContextualSubNavigation';
 
 
 const logger = loggerFactory('growi:cli:GrowiSubNavigationSticky');
 const logger = loggerFactory('growi:cli:GrowiSubNavigationSticky');
 
 
@@ -110,7 +110,7 @@ const GrowiSubNavigationSwitcher = (props) => {
   return (
   return (
     <div className={`grw-subnav-switcher ${isVisible ? '' : 'grw-subnav-switcher-hidden'}`}>
     <div className={`grw-subnav-switcher ${isVisible ? '' : 'grw-subnav-switcher-hidden'}`}>
       <div id="grw-subnav-fixed-container" className="grw-subnav-fixed-container position-fixed" ref={fixedContainerRef} style={{ width }}>
       <div id="grw-subnav-fixed-container" className="grw-subnav-fixed-container position-fixed" ref={fixedContainerRef} style={{ width }}>
-        <GrowiSubNavigation isCompactMode />
+        <GrowiContextualSubNavigation isCompactMode />
       </div>
       </div>
     </div>
     </div>
   );
   );

+ 4 - 4
packages/app/src/components/Navbar/SubNavButtons.tsx

@@ -17,10 +17,10 @@ type SubNavButtonsProps= {
   pageId: string,
   pageId: string,
   revisionId: string,
   revisionId: string,
   path: string,
   path: string,
-  isViewMode: boolean
-  isAbleToShowPageManagement: boolean,
-  isDeletable: boolean,
-  isAbleToDeleteCompletely: boolean,
+  isViewMode?: boolean
+  isAbleToShowPageManagement?: boolean,
+  isDeletable?: boolean,
+  isAbleToDeleteCompletely?: boolean,
 }
 }
 const SubNavButtons: FC<SubNavButtonsProps> = (props: SubNavButtonsProps) => {
 const SubNavButtons: FC<SubNavButtonsProps> = (props: SubNavButtonsProps) => {
   const {
   const {

+ 7 - 15
packages/app/src/components/Page/TagLabels.tsx

@@ -1,20 +1,17 @@
 import React, { FC, Suspense, useState } from 'react';
 import React, { FC, Suspense, useState } from 'react';
 
 
-import { withUnstatedContainers } from '../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
-
 import RenderTagLabels from './RenderTagLabels';
 import RenderTagLabels from './RenderTagLabels';
 import TagEditModal from './TagEditModal';
 import TagEditModal from './TagEditModal';
 
 
-type TagLabels = {
+type Props = {
   tags: string[],
   tags: string[],
-  appContainer: AppContainer,
-  tagsUpdateInvoked?: () => Promise<void>,
+  isGuestUser: boolean,
+  tagsUpdateInvoked?: (tags: string[]) => Promise<void>,
 }
 }
 
 
 
 
-const TagLabels:FC<TagLabels> = (props:TagLabels) => {
-  const { tags, appContainer, tagsUpdateInvoked } = props;
+const TagLabels:FC<Props> = (props: Props) => {
+  const { tags, isGuestUser, tagsUpdateInvoked } = props;
 
 
   const [isTagEditModalShown, setIsTagEditModalShown] = useState(false);
   const [isTagEditModalShown, setIsTagEditModalShown] = useState(false);
 
 
@@ -34,7 +31,7 @@ const TagLabels:FC<TagLabels> = (props:TagLabels) => {
           <RenderTagLabels
           <RenderTagLabels
             tags={tags}
             tags={tags}
             openEditorModal={openEditorModal}
             openEditorModal={openEditorModal}
-            isGuestUser={appContainer.isGuestUser}
+            isGuestUser={isGuestUser}
           />
           />
         </Suspense>
         </Suspense>
       </form>
       </form>
@@ -50,9 +47,4 @@ const TagLabels:FC<TagLabels> = (props:TagLabels) => {
   );
   );
 };
 };
 
 
-/**
- * Wrapper component for using unstated
- */
-const TagLabelsUnstatedWrapper = withUnstatedContainers(TagLabels, [AppContainer]);
-
-export default TagLabelsUnstatedWrapper;
+export default TagLabels;

+ 9 - 7
packages/app/src/components/PagePathNav.tsx

@@ -7,8 +7,8 @@ import LinkedPagePath from '../models/linked-page-path';
 
 
 
 
 type Props = {
 type Props = {
-  pageId :string,
-  pagePath:string,
+  pagePath: string,
+  pageId?: string | null,
   isSingleLineMode?:boolean,
   isSingleLineMode?:boolean,
   isCompactMode?:boolean,
   isCompactMode?:boolean,
 }
 }
@@ -43,11 +43,13 @@ const PagePathNav: FC<Props> = (props: Props) => {
       {formerLink}
       {formerLink}
       <span className="d-flex align-items-center">
       <span className="d-flex align-items-center">
         <h1 className="m-0">{latterLink}</h1>
         <h1 className="m-0">{latterLink}</h1>
-        <div className="mx-2">
-          <CopyDropdown pageId={pageId} pagePath={pagePath} dropdownToggleId={copyDropdownId} dropdownToggleClassName={copyDropdownToggleClassName}>
-            <i className="ti-clipboard"></i>
-          </CopyDropdown>
-        </div>
+        { pageId != null && (
+          <div className="mx-2">
+            <CopyDropdown pageId={pageId} pagePath={pagePath} dropdownToggleId={copyDropdownId} dropdownToggleClassName={copyDropdownToggleClassName}>
+              <i className="ti-clipboard"></i>
+            </CopyDropdown>
+          </div>
+        ) }
       </span>
       </span>
     </div>
     </div>
   );
   );

+ 4 - 2
packages/app/src/stores/page.tsx

@@ -61,8 +61,10 @@ export const useSWRPageInfo = (pageId: string | null): SWRResponse<IPageInfo, Er
   }));
   }));
 };
 };
 
 
-export const useSWRTagsInfo = (pageId: string): SWRResponse<IPageTagsInfo, Error> => {
-  return useSWR(`/pages.getPageTag?pageId=${pageId}`, endpoint => apiGet(endpoint).then((response: IPageTagsInfo) => {
+export const useSWRTagsInfo = (pageId: string | null | undefined): SWRResponse<IPageTagsInfo, Error> => {
+  const key = pageId == null ? null : `/pages.getPageTag?pageId=${pageId}`;
+
+  return useSWR(key, endpoint => apiGet(endpoint).then((response: IPageTagsInfo) => {
     return {
     return {
       tags: response.tags,
       tags: response.tags,
     };
     };