Răsfoiți Sursa

open PageAccessoriesModal from hooks

Yuki Takei 4 ani în urmă
părinte
comite
2a5f5d8f1e

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

@@ -51,9 +51,9 @@ import CommentContainer from '~/client/services/CommentContainer';
 import EditorContainer from '~/client/services/EditorContainer';
 import EditorContainer from '~/client/services/EditorContainer';
 import TagContainer from '~/client/services/TagContainer';
 import TagContainer from '~/client/services/TagContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
-import PageAccessoriesContainer from '~/client/services/PageAccessoriesContainer';
 
 
 import { appContainer, componentMappings } from './base';
 import { appContainer, componentMappings } from './base';
+import { toastError } from './util/apiNotification';
 
 
 const logger = loggerFactory('growi:cli:app');
 const logger = loggerFactory('growi:cli:app');
 
 
@@ -70,10 +70,9 @@ const commentContainer = new CommentContainer(appContainer);
 const editorContainer = new EditorContainer(appContainer, defaultEditorOptions, defaultPreviewOptions);
 const editorContainer = new EditorContainer(appContainer, defaultEditorOptions, defaultPreviewOptions);
 const tagContainer = new TagContainer(appContainer);
 const tagContainer = new TagContainer(appContainer);
 const personalContainer = new PersonalContainer(appContainer);
 const personalContainer = new PersonalContainer(appContainer);
-const pageAccessoriesContainer = new PageAccessoriesContainer(appContainer);
 const injectableContainers = [
 const injectableContainers = [
   appContainer, socketIoContainer, pageContainer, pageHistoryContainer, revisionComparerContainer,
   appContainer, socketIoContainer, pageContainer, pageHistoryContainer, revisionComparerContainer,
-  commentContainer, editorContainer, tagContainer, personalContainer, pageAccessoriesContainer,
+  commentContainer, editorContainer, tagContainer, personalContainer,
 ];
 ];
 
 
 logger.info('unstated containers have been initialized');
 logger.info('unstated containers have been initialized');
@@ -133,7 +132,8 @@ if (pageContainer.state.pageId != null) {
 
 
   // show the Page accessory modal when query of "compare" is requested
   // show the Page accessory modal when query of "compare" is requested
   if (revisionComparerContainer.getRevisionIDsToCompareAsParam().length > 0) {
   if (revisionComparerContainer.getRevisionIDsToCompareAsParam().length > 0) {
-    pageAccessoriesContainer.openPageAccessoriesModal('pageHistory');
+    toastError('Sorry, opening PageAccessoriesModal is not implemented yet in v5.');
+  //   pageAccessoriesContainer.openPageAccessoriesModal('pageHistory');
   }
   }
 }
 }
 if (pageContainer.state.creator != null) {
 if (pageContainer.state.creator != null) {
@@ -146,8 +146,8 @@ 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': <GrowiContextualSubNavigation />,
-    'grw-subnav-switcher-container': <GrowiSubNavigationSwitcher />,
+    'grw-subnav-container': <GrowiContextualSubNavigation isLinkSharingDisabled={appContainer.config.disableLinkSharing} />,
+    'grw-subnav-switcher-container': <GrowiSubNavigationSwitcher isLinkSharingDisabled={appContainer.config.disableLinkSharing} />,
     'display-switcher': <DisplaySwitcher />,
     'display-switcher': <DisplaySwitcher />,
   });
   });
 }
 }

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

@@ -10,6 +10,7 @@ import PageCreateModal from '../components/PageCreateModal';
 import PageDeleteModal from '../components/PageDeleteModal';
 import PageDeleteModal from '../components/PageDeleteModal';
 import PageDuplicateModal from '../components/PageDuplicateModal';
 import PageDuplicateModal from '../components/PageDuplicateModal';
 import PageRenameModal from '../components/PageRenameModal';
 import PageRenameModal from '../components/PageRenameModal';
+import PageAccessoriesModal from '../components/PageAccessoriesModal';
 
 
 import AppContainer from '~/client/services/AppContainer';
 import AppContainer from '~/client/services/AppContainer';
 import SocketIoContainer from '~/client/services/SocketIoContainer';
 import SocketIoContainer from '~/client/services/SocketIoContainer';
@@ -47,6 +48,7 @@ const componentMappings = {
   'page-delete-modal': <PageDeleteModal />,
   'page-delete-modal': <PageDeleteModal />,
   'page-duplicate-modal': <PageDuplicateModal />,
   'page-duplicate-modal': <PageDuplicateModal />,
   'page-rename-modal': <PageRenameModal />,
   'page-rename-modal': <PageRenameModal />,
+  'page-accessories-modal': <PageAccessoriesModal />,
   'descendants-page-list-modal': <DescendantsPageListModal />,
   'descendants-page-list-modal': <DescendantsPageListModal />,
 
 
   'grw-hotkeys-manager': <HotkeysManager />,
   'grw-hotkeys-manager': <HotkeysManager />,

+ 0 - 54
packages/app/src/client/services/PageAccessoriesContainer.js

@@ -1,54 +0,0 @@
-import { Container } from 'unstated';
-
-/**
- * Service container related to options for Application
- * @extends {Container} unstated Container
- */
-
-export default class PageAccessoriesContainer extends Container {
-
-  constructor(appContainer) {
-    super();
-
-    this.appContainer = appContainer;
-
-    this.state = {
-      isPageAccessoriesModalShown: false,
-      activeTab: '',
-      // Prevent unnecessary rendering
-      activeComponents: new Set(['']),
-    };
-    this.openPageAccessoriesModal = this.openPageAccessoriesModal.bind(this);
-    this.closePageAccessoriesModal = this.closePageAccessoriesModal.bind(this);
-    this.switchActiveTab = this.switchActiveTab.bind(this);
-  }
-
-  /**
-   * Workaround for the mangling in production build to break constructor.name
-   */
-  static getClassName() {
-    return 'PageAccessoriesContainer';
-  }
-
-
-  openPageAccessoriesModal(activeTab) {
-    this.setState({
-      isPageAccessoriesModalShown: true,
-    });
-    this.switchActiveTab(activeTab);
-  }
-
-  closePageAccessoriesModal() {
-    this.setState({
-      isPageAccessoriesModalShown: false,
-      activeTab: '',
-    });
-  }
-
-  switchActiveTab(activeTab) {
-    this.setState({
-      activeTab, activeComponents: this.state.activeComponents.add(activeTab),
-    });
-  }
-
-}

+ 0 - 40
packages/app/src/components/PageAccessories.jsx

@@ -1,40 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import PageAccessoriesModalControl from './PageAccessoriesModalControl';
-import PageAccessoriesModal from './PageAccessoriesModal';
-
-import { withUnstatedContainers } from './UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
-import PageAccessoriesContainer from '~/client/services/PageAccessoriesContainer';
-
-const PageAccessories = (props) => {
-  const { appContainer, pageAccessoriesContainer } = props;
-  const { isGuestUser, isSharedUser } = appContainer;
-
-  return (
-    <>
-      <PageAccessoriesModalControl
-        isGuestUser={isGuestUser}
-        isSharedUser={isSharedUser}
-      />
-      <PageAccessoriesModal
-        isGuestUser={isGuestUser}
-        isSharedUser={isSharedUser}
-        isOpen={pageAccessoriesContainer.state.isPageAccessoriesModalShown}
-        onClose={pageAccessoriesContainer.closePageAccessoriesModal}
-      />
-    </>
-  );
-};
-/**
- * Wrapper component for using unstated
- */
-const PageAccessoriesWrapper = withUnstatedContainers(PageAccessories, [AppContainer, PageAccessoriesContainer]);
-
-PageAccessories.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  pageAccessoriesContainer: PropTypes.instanceOf(PageAccessoriesContainer).isRequired,
-};
-
-export default PageAccessoriesWrapper;

+ 21 - 18
packages/app/src/components/PageAccessoriesModal.tsx

@@ -7,6 +7,7 @@ import {
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 
 
 import { useIsGuestUser, useIsSharedUser } from '~/stores/context';
 import { useIsGuestUser, useIsSharedUser } from '~/stores/context';
+import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/stores/ui';
 import AppContainer from '~/client/services/AppContainer';
 import AppContainer from '~/client/services/AppContainer';
 
 
 import HistoryIcon from './Icons/HistoryIcon';
 import HistoryIcon from './Icons/HistoryIcon';
@@ -18,7 +19,6 @@ import PageHistory from './PageHistory';
 import ShareLink from './ShareLink/ShareLink';
 import ShareLink from './ShareLink/ShareLink';
 import { CustomNavTab } from './CustomNavigation/CustomNav';
 import { CustomNavTab } from './CustomNavigation/CustomNav';
 import ExpandOrContractButton from './ExpandOrContractButton';
 import ExpandOrContractButton from './ExpandOrContractButton';
-import { usePageAccessoriesModal } from '~/stores/ui';
 
 
 
 
 type Props = {
 type Props = {
@@ -35,31 +35,31 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
 
 
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
-  const [activeTab, setActiveTab] = useState('pageHistory');
+  const [activeTab, setActiveTab] = useState(PageAccessoriesModalContents.PageHistory);
   const [isWindowExpanded, setIsWindowExpanded] = useState(false);
   const [isWindowExpanded, setIsWindowExpanded] = useState(false);
 
 
   const { data: isSharedUser } = useIsSharedUser();
   const { data: isSharedUser } = useIsSharedUser();
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isGuestUser } = useIsGuestUser();
 
 
-  const { data: status, close } = usePageAccessoriesModal();
+  const { data: status, open, close } = usePageAccessoriesModal();
 
 
   const navTabMapping = useMemo(() => {
   const navTabMapping = useMemo(() => {
     return {
     return {
-      pageHistory: {
+      [PageAccessoriesModalContents.PageHistory]: {
         Icon: HistoryIcon,
         Icon: HistoryIcon,
         i18n: t('History'),
         i18n: t('History'),
-        index: 2,
+        index: 0,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
       },
       },
-      attachment: {
+      [PageAccessoriesModalContents.Attachment]: {
         Icon: AttachmentIcon,
         Icon: AttachmentIcon,
         i18n: t('attachment_data'),
         i18n: t('attachment_data'),
-        index: 3,
+        index: 1,
       },
       },
-      shareLink: {
+      [PageAccessoriesModalContents.ShareLink]: {
         Icon: ShareLinkIcon,
         Icon: ShareLinkIcon,
         i18n: t('share_links.share_link_management'),
         i18n: t('share_links.share_link_management'),
-        index: 4,
+        index: 2,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
       },
       },
     };
     };
@@ -82,7 +82,7 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
     return <></>;
     return <></>;
   }
   }
 
 
-  const { isOpened, activeComponents } = status;
+  const { isOpened, activatedContents } = status;
 
 
   return (
   return (
     <Modal
     <Modal
@@ -96,25 +96,28 @@ const PageAccessoriesModal = (props: Props): JSX.Element => {
           activeTab={activeTab}
           activeTab={activeTab}
           navTabMapping={navTabMapping}
           navTabMapping={navTabMapping}
           breakpointToHideInactiveTabsDown="md"
           breakpointToHideInactiveTabsDown="md"
-          onNavSelected={v => setActiveTab(v)}
+          onNavSelected={(v) => {
+            setActiveTab(v);
+            open(v);
+          }}
           hideBorderBottom
           hideBorderBottom
         />
         />
       </ModalHeader>
       </ModalHeader>
       <ModalBody className="overflow-auto grw-modal-body-style">
       <ModalBody className="overflow-auto grw-modal-body-style">
         {/* Do not use CustomTabContent because of performance problem:
         {/* Do not use CustomTabContent because of performance problem:
-            the 'navTabMapping[tabId].Content' for PageAccessoriesModal depends on activeComponents */}
+            the 'navTabMapping[tabId].Content' for PageAccessoriesModal depends on activatedContents */}
         <TabContent activeTab={activeTab}>
         <TabContent activeTab={activeTab}>
           {!isGuestUser && (
           {!isGuestUser && (
-            <TabPane tabId="pageHistory">
-              {activeComponents.has('pageHistory') && <PageHistory /> }
+            <TabPane tabId={PageAccessoriesModalContents.PageHistory}>
+              {activatedContents.has(PageAccessoriesModalContents.PageHistory) && <PageHistory /> }
             </TabPane>
             </TabPane>
           )}
           )}
-          <TabPane tabId="attachment">
-            {activeComponents.has('attachment') && <PageAttachment />}
+          <TabPane tabId={PageAccessoriesModalContents.Attachment}>
+            {activatedContents.has(PageAccessoriesModalContents.Attachment) && <PageAttachment />}
           </TabPane>
           </TabPane>
           {!isGuestUser && (
           {!isGuestUser && (
-            <TabPane tabId="shareLink">
-              {activeComponents.has('shareLink') && <ShareLink />}
+            <TabPane tabId={PageAccessoriesModalContents.ShareLink}>
+              {activatedContents.has(PageAccessoriesModalContents.ShareLink) && <ShareLink />}
             </TabPane>
             </TabPane>
           )}
           )}
         </TabContent>
         </TabContent>

+ 1 - 0
packages/app/src/server/views/layout/layout.html

@@ -107,6 +107,7 @@
 <div id="page-delete-modal"></div>
 <div id="page-delete-modal"></div>
 <div id="page-duplicate-modal"></div>
 <div id="page-duplicate-modal"></div>
 <div id="page-rename-modal"></div>
 <div id="page-rename-modal"></div>
+<div id="page-accessories-modal"></div>
 <div id="descendants-page-list-modal"></div>
 <div id="descendants-page-list-modal"></div>
 
 
 {% include '../modal/shortcuts.html' %}
 {% include '../modal/shortcuts.html' %}

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

@@ -442,13 +442,20 @@ export const useDescendantsPageListModal = (
 };
 };
 
 
 
 
+export const PageAccessoriesModalContents = {
+  PageHistory: 'PageHistory',
+  Attachment: 'Attachment',
+  ShareLink: 'ShareLink',
+} as const;
+export type PageAccessoriesModalContents = typeof PageAccessoriesModalContents[keyof typeof PageAccessoriesModalContents];
+
 type PageAccessoriesModalStatus = {
 type PageAccessoriesModalStatus = {
   isOpened: boolean,
   isOpened: boolean,
-  activeComponents: Set<string>,
+  activatedContents: Set<PageAccessoriesModalContents>,
 }
 }
 
 
 type PageAccessoriesModalUtils = {
 type PageAccessoriesModalUtils = {
-  open(activatedComponent: string): Promise<PageAccessoriesModalStatus> | void
+  open(activatedContent: PageAccessoriesModalContents): Promise<PageAccessoriesModalStatus> | void
   close(): Promise<PageAccessoriesModalStatus> | void
   close(): Promise<PageAccessoriesModalStatus> | void
 }
 }
 
 
@@ -456,18 +463,18 @@ export const usePageAccessoriesModal = (
     status?: PageAccessoriesModalStatus,
     status?: PageAccessoriesModalStatus,
 ): SWRResponse<PageAccessoriesModalStatus, Error> & PageAccessoriesModalUtils => {
 ): SWRResponse<PageAccessoriesModalStatus, Error> & PageAccessoriesModalUtils => {
 
 
-  const initialData = { isOpened: false, activeComponents: new Set(['']) };
+  const initialData: PageAccessoriesModalStatus = { isOpened: false, activatedContents: new Set<PageAccessoriesModalContents>() };
   const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', status, { fallbackData: initialData });
   const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', status, { fallbackData: initialData });
 
 
   return {
   return {
     ...swrResponse,
     ...swrResponse,
-    open: (activatedComponent: string) => {
+    open: (activatedContent: PageAccessoriesModalContents) => {
       if (swrResponse.data == null) {
       if (swrResponse.data == null) {
         return;
         return;
       }
       }
       swrResponse.mutate({
       swrResponse.mutate({
         isOpened: true,
         isOpened: true,
-        activeComponents: swrResponse.data.activeComponents.add(activatedComponent),
+        activatedContents: swrResponse.data.activatedContents.add(activatedContent),
       });
       });
     },
     },
     close: () => {
     close: () => {
@@ -476,7 +483,7 @@ export const usePageAccessoriesModal = (
       }
       }
       swrResponse.mutate({
       swrResponse.mutate({
         isOpened: false,
         isOpened: false,
-        activeComponents: swrResponse.data.activeComponents,
+        activatedContents: swrResponse.data.activatedContents,
       });
       });
     },
     },
   };
   };