Explorar el Código

Merge branch 'master' into feat/123475-126853-template-name-truncation

Yuki Takei hace 2 años
padre
commit
4134ee8058
Se han modificado 39 ficheros con 225 adiciones y 188 borrados
  1. 4 4
      .mergify.yml
  2. 23 1
      CHANGELOG.md
  3. 1 1
      apps/app/package.json
  4. 0 34
      apps/app/src/client/services/ShowPageAccessoriesModal.tsx
  5. 1 1
      apps/app/src/components/Admin/Security/ShareLinkSetting.tsx
  6. 1 1
      apps/app/src/components/Layout/BasicLayout.tsx
  7. 0 0
      apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.module.scss
  8. 25 57
      apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.tsx
  9. 2 2
      apps/app/src/components/PageAccessoriesModal/PageAttachment.tsx
  10. 8 12
      apps/app/src/components/PageAccessoriesModal/PageHistory.tsx
  11. 1 3
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLink.tsx
  12. 0 0
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx
  13. 1 1
      apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkList.tsx
  14. 1 0
      apps/app/src/components/PageAccessoriesModal/ShareLink/index.ts
  15. 79 0
      apps/app/src/components/PageAccessoriesModal/hooks.tsx
  16. 1 0
      apps/app/src/components/PageAccessoriesModal/index.ts
  17. 1 2
      apps/app/src/components/SearchPage/SearchPageBase.tsx
  18. 7 7
      apps/app/src/components/ShareLinkPageView.tsx
  19. 1 1
      apps/app/src/pages/share/[[...path]].page.tsx
  20. 13 4
      apps/app/src/stores/modal.tsx
  21. 22 7
      apps/app/test/cypress/e2e/20-basic-features/20-basic-features--access-to-page.cy.ts
  22. 1 2
      apps/app/test/cypress/e2e/22-sharelink/22-sharelink--access-to-sharelink.cy.ts
  23. 1 7
      apps/app/test/cypress/e2e/50-sidebar/50-sidebar--access-to-side-bar.cy.ts
  24. 0 13
      apps/app/test/cypress/e2e/50-sidebar/50-sidebar--switching-sidebar-mode.cy.ts
  25. 7 4
      apps/app/test/cypress/support/commands.ts
  26. 1 1
      apps/slackbot-proxy/package.json
  27. 1 1
      package.json
  28. 1 1
      packages/core/package.json
  29. 1 1
      packages/hackmd/package.json
  30. 1 1
      packages/presentation/package.json
  31. 1 1
      packages/preset-templates/package.json
  32. 1 1
      packages/preset-themes/package.json
  33. 1 1
      packages/remark-attachment-refs/package.json
  34. 1 1
      packages/remark-drawio/package.json
  35. 1 1
      packages/remark-growi-directive/package.json
  36. 1 1
      packages/remark-lsx/package.json
  37. 1 1
      packages/slack/package.json
  38. 1 1
      packages/ui/package.json
  39. 11 11
      yarn.lock

+ 4 - 4
.mergify.yml

@@ -3,11 +3,11 @@ pull_request_rules:
     conditions:
       - author = dependabot[bot]
       - '#approved-reviews-by >= 1'
-      - check-success = "lint (16.x)"
-      - check-success = "test (16.x)"
-      - check-success = "launch-dev (16.x)"
-      - check-success = "test-prod-node14 / launch-prod"
+      - check-success = "lint (18.x)"
+      - check-success = "test (18.x)"
+      - check-success = "launch-dev (18.x)"
       - check-success = "test-prod-node16 / launch-prod"
+      - check-success = "test-prod-node18 / launch-prod"
     actions:
       merge:
         method: merge

+ 23 - 1
CHANGELOG.md

@@ -1,9 +1,31 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v6.1.6...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v6.1.7...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v6.1.7](https://github.com/weseek/growi/compare/v6.1.6...v6.1.7) - 2023-07-19
+
+### 💎 Features
+
+- feat: Authentication settings cannot be disabled if there will be no administrator user available to log in (#7761) @mudana-grune
+
+### 🚀 Improvement
+
+- imprv: Show spinner while installing and logging-in (#7823) @soumaeda
+- imprv: Routing with next link (#7880) @yuki-takei
+
+### 🐛 Bug Fixes
+
+- fix: Auto popup PageAccessoriesModal and show page history (#7888) @yuki-takei
+- fix: Auto-scroll does not work when accessing the page when the header string is CJK (#7882) @yuki-takei
+- fix: Avoid unnecessary next routing (#7863) @miya
+- fix: Work put back page on bookmark sidebar (#7698) @mudana-grune
+
+### 🧰 Maintenance
+
+- support: Render SearchPageBase in CSR (#7889) @yuki-takei
+
 ## [v6.1.6](https://github.com/weseek/growi/compare/v6.1.5...v6.1.6) - 2023-07-12
 
 ### 🐛 Bug Fixes

+ 1 - 1
apps/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "license": "MIT",
   "scripts": {
     "//// for production": "",

+ 0 - 34
apps/app/src/client/services/ShowPageAccessoriesModal.tsx

@@ -1,34 +0,0 @@
-import React, { useEffect, useState } from 'react';
-
-import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/stores/modal';
-
-function getURLQueryParamValue(key: string) {
-// window.location.href is page URL;
-  const queryStr: URLSearchParams = new URL(window.location.href).searchParams;
-  return queryStr.get(key);
-}
-
-const queryCompareFormat = new RegExp(/([a-z0-9]){24}...([a-z0-9]){24}/);
-
-const ShowPageAccessoriesModal = (): JSX.Element => {
-  const { data: status, open: openPageAccessories } = usePageAccessoriesModal();
-  const [isArleadyMounted, setIsArleadyMounted] = useState(false);
-  useEffect(() => {
-    const pageIdParams = getURLQueryParamValue('compare');
-    if (status == null || status.isOpened === true) {
-      return;
-    }
-    if (isArleadyMounted === true) {
-      return;
-    }
-    if (pageIdParams != null) {
-      if (queryCompareFormat.test(pageIdParams)) {
-        openPageAccessories(PageAccessoriesModalContents.PageHistory);
-      }
-    }
-    setIsArleadyMounted(true);
-  }, [openPageAccessories, status, isArleadyMounted]);
-  return <></>;
-};
-
-export default ShowPageAccessoriesModal;

+ 1 - 1
apps/app/src/components/Admin/Security/ShareLinkSetting.tsx

@@ -8,8 +8,8 @@ import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurit
 import { apiv3Delete } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 
+import ShareLinkList from '../../PageAccessoriesModal/ShareLink/ShareLinkList';
 import PaginationWrapper from '../../PaginationWrapper';
-import ShareLinkList from '../../ShareLink/ShareLinkList';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 
 import DeleteAllShareLinksModal from './DeleteAllShareLinksModal';

+ 1 - 1
apps/app/src/components/Layout/BasicLayout.tsx

@@ -23,7 +23,7 @@ const PageDuplicateModal = dynamic(() => import('../PageDuplicateModal'), { ssr:
 const PageDeleteModal = dynamic(() => import('../PageDeleteModal'), { ssr: false });
 const PageRenameModal = dynamic(() => import('../PageRenameModal'), { ssr: false });
 const PagePresentationModal = dynamic(() => import('../PagePresentationModal'), { ssr: false });
-const PageAccessoriesModal = dynamic(() => import('../PageAccessoriesModal'), { ssr: false });
+const PageAccessoriesModal = dynamic(() => import('../PageAccessoriesModal').then(mod => mod.PageAccessoriesModal), { ssr: false });
 const DeleteBookmarkFolderModal = dynamic(() => import('../DeleteBookmarkFolderModal').then(mod => mod.DeleteBookmarkFolderModal), { ssr: false });
 // Fab
 const Fab = dynamic(() => import('../Fab').then(mod => mod.Fab), { ssr: false });

+ 0 - 0
apps/app/src/components/PageAccessoriesModal.module.scss → apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.module.scss


+ 25 - 57
apps/app/src/components/PageAccessoriesModal.tsx → apps/app/src/components/PageAccessoriesModal/PageAccessoriesModal.tsx

@@ -1,6 +1,7 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import React, { useMemo, useState } from 'react';
 
 import { useTranslation } from 'next-i18next';
+import dynamic from 'next/dynamic';
 import {
   Modal, ModalBody, ModalHeader,
 } from 'reactstrap';
@@ -10,25 +11,26 @@ import {
 } from '~/stores/context';
 import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/stores/modal';
 
-import { CustomNavTab } from './CustomNavigation/CustomNav';
-import CustomTabContent from './CustomNavigation/CustomTabContent';
-import ExpandOrContractButton from './ExpandOrContractButton';
-import AttachmentIcon from './Icons/AttachmentIcon';
-import HistoryIcon from './Icons/HistoryIcon';
-import ShareLinkIcon from './Icons/ShareLinkIcon';
-import PageAttachment from './PageAttachment';
-import { PageHistory, getQueryParam } from './PageHistory';
-import ShareLink from './ShareLink/ShareLink';
+import { CustomNavTab } from '../CustomNavigation/CustomNav';
+import CustomTabContent from '../CustomNavigation/CustomTabContent';
+import ExpandOrContractButton from '../ExpandOrContractButton';
+import AttachmentIcon from '../Icons/AttachmentIcon';
+import HistoryIcon from '../Icons/HistoryIcon';
+import ShareLinkIcon from '../Icons/ShareLinkIcon';
+
+import { useAutoOpenModalByQueryParam } from './hooks';
 
 import styles from './PageAccessoriesModal.module.scss';
 
-const PageAccessoriesModal = (): JSX.Element => {
 
-  const { t } = useTranslation();
+const PageAttachment = dynamic(() => import('./PageAttachment'), { ssr: false });
+const PageHistory = dynamic(() => import('./PageHistory').then(mod => mod.PageHistory), { ssr: false });
+const ShareLink = dynamic(() => import('./ShareLink').then(mod => mod.ShareLink), { ssr: false });
+
 
-  const [activeTab, setActiveTab] = useState<PageAccessoriesModalContents>();
-  const [sourceRevisionId, setSourceRevisionId] = useState<string>();
-  const [targetRevisionId, setTargetRevisionId] = useState<string>();
+export const PageAccessoriesModal = (): JSX.Element => {
+
+  const { t } = useTranslation();
 
   const [isWindowExpanded, setIsWindowExpanded] = useState(false);
 
@@ -37,46 +39,16 @@ const PageAccessoriesModal = (): JSX.Element => {
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
   const { data: isLinkSharingDisabled } = useDisableLinkSharing();
 
-  const { data: status, mutate, close } = usePageAccessoriesModal();
-
-  // activate tab when open
-  useEffect(() => {
-    if (status == null) return;
+  const { data: status, close, selectContents } = usePageAccessoriesModal();
 
-    const { isOpened, activatedContents } = status;
-    if (isOpened && activatedContents != null) {
-      setActiveTab(activatedContents);
-    }
-  }, [status]);
-
-  // Set sourceRevisionId and targetRevisionId as state with valid object id string
-  useEffect(() => {
-    const queryParams = getQueryParam();
-    // https://regex101.com/r/YHTDsr/1
-    const regex = /^([0-9a-f]{24})...([0-9a-f]{24})$/i;
-
-    if (queryParams == null || !regex.test(queryParams)) {
-      return;
-    }
-
-    const matches = queryParams.match(regex);
-
-    if (matches == null) {
-      return;
-    }
-
-    const [, sourceRevisionId, targetRevisionId] = matches;
-    setSourceRevisionId(sourceRevisionId);
-    setTargetRevisionId(targetRevisionId);
-    mutate({ isOpened: true });
-  }, [mutate]);
+  useAutoOpenModalByQueryParam();
 
   const navTabMapping = useMemo(() => {
     return {
       [PageAccessoriesModalContents.PageHistory]: {
         Icon: HistoryIcon,
         Content: () => {
-          return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
+          return <PageHistory onClose={close} />;
         },
         i18n: t('History'),
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
@@ -97,7 +69,7 @@ const PageAccessoriesModal = (): JSX.Element => {
         isLinkEnabled: () => !isGuestUser && !isReadOnlyUser && !isSharedUser && !isLinkSharingDisabled,
       },
     };
-  }, [t, close, sourceRevisionId, targetRevisionId, isGuestUser, isReadOnlyUser, isSharedUser, isLinkSharingDisabled]);
+  }, [t, close, isGuestUser, isReadOnlyUser, isSharedUser, isLinkSharingDisabled]);
 
   const buttons = useMemo(() => (
     <div className="d-flex flex-nowrap">
@@ -112,7 +84,7 @@ const PageAccessoriesModal = (): JSX.Element => {
     </div>
   ), [close, isWindowExpanded]);
 
-  if (status == null || activeTab == null) {
+  if (status == null || status.activatedContents == null) {
     return <></>;
   }
 
@@ -128,20 +100,16 @@ const PageAccessoriesModal = (): JSX.Element => {
     >
       <ModalHeader className="p-0" toggle={close} close={buttons}>
         <CustomNavTab
-          activeTab={activeTab}
+          activeTab={status.activatedContents}
           navTabMapping={navTabMapping}
           breakpointToHideInactiveTabsDown="md"
-          onNavSelected={(v: PageAccessoriesModalContents) => {
-            setActiveTab(v);
-          }}
+          onNavSelected={selectContents}
           hideBorderBottom
         />
       </ModalHeader>
       <ModalBody className="overflow-auto grw-modal-body-style">
-        <CustomTabContent activeTab={activeTab} navTabMapping={navTabMapping} />
+        <CustomTabContent activeTab={status.activatedContents} navTabMapping={navTabMapping} />
       </ModalBody>
     </Modal>
   );
 };
-
-export default PageAccessoriesModal;

+ 2 - 2
apps/app/src/components/PageAttachment.tsx → apps/app/src/components/PageAccessoriesModal/PageAttachment.tsx

@@ -9,8 +9,8 @@ import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context';
 import { useDeleteAttachmentModal } from '~/stores/modal';
 import { useSWRxCurrentPage, useCurrentPageId } from '~/stores/page';
 
-import { PageAttachmentList } from './PageAttachment/PageAttachmentList';
-import PaginationWrapper from './PaginationWrapper';
+import { PageAttachmentList } from '../PageAttachment/PageAttachmentList';
+import PaginationWrapper from '../PaginationWrapper';
 
 // Utility
 const checkIfFileInUse = (markdown: string, attachment): boolean => {

+ 8 - 12
apps/app/src/components/PageHistory.tsx → apps/app/src/components/PageAccessoriesModal/PageHistory.tsx

@@ -3,34 +3,30 @@ import React from 'react';
 import { useCurrentPagePath, useCurrentPageId } from '~/stores/page';
 import loggerFactory from '~/utils/logger';
 
-import { PageRevisionTable } from './PageHistory/PageRevisionTable';
+import { PageRevisionTable } from '../PageHistory/PageRevisionTable';
+
+import { useAutoComparingRevisionsByQueryParam } from './hooks';
 
 const logger = loggerFactory('growi:PageHistory');
 
 type PageHistoryProps = {
-  sourceRevisionId?: string,
-  targetRevisionId?: string
   onClose: () => void
 }
 
-// Get string from 'compare' query params
-export const getQueryParam = (): string | null => {
-  const query: URLSearchParams = new URL(window.location.href).searchParams;
-  return query.get('compare');
-};
-
 export const PageHistory: React.FC<PageHistoryProps> = (props: PageHistoryProps) => {
-  const { sourceRevisionId, targetRevisionId, onClose } = props;
+  const { onClose } = props;
 
   const { data: currentPageId } = useCurrentPageId();
   const { data: currentPagePath } = useCurrentPagePath();
 
+  const comparingRevisions = useAutoComparingRevisionsByQueryParam();
+
   return (
     <div className="revision-history" data-testid="page-history">
       {currentPageId != null && currentPagePath != null && (
         <PageRevisionTable
-          sourceRevisionId={sourceRevisionId}
-          targetRevisionId={targetRevisionId}
+          sourceRevisionId={comparingRevisions?.sourceRevisionId}
+          targetRevisionId={comparingRevisions?.targetRevisionId}
           currentPageId={currentPageId}
           currentPagePath={currentPagePath}
           onClose={onClose}

+ 1 - 3
apps/app/src/components/ShareLink/ShareLink.tsx → apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLink.tsx

@@ -12,7 +12,7 @@ import { useSWRxSharelink } from '~/stores/share-link';
 import { ShareLinkForm } from './ShareLinkForm';
 import ShareLinkList from './ShareLinkList';
 
-const ShareLink = (): JSX.Element => {
+export const ShareLink = (): JSX.Element => {
   const { t } = useTranslation();
   const [isOpenShareLinkForm, setIsOpenShareLinkForm] = useState<boolean>(false);
 
@@ -73,5 +73,3 @@ const ShareLink = (): JSX.Element => {
     </div>
   );
 };
-
-export default ShareLink;

+ 0 - 0
apps/app/src/components/ShareLink/ShareLinkForm.tsx → apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkForm.tsx


+ 1 - 1
apps/app/src/components/ShareLink/ShareLinkList.tsx → apps/app/src/components/PageAccessoriesModal/ShareLink/ShareLinkList.tsx

@@ -3,7 +3,7 @@ import React from 'react';
 import dateFnsFormat from 'date-fns/format';
 import { useTranslation } from 'next-i18next';
 
-import CopyDropdown from '../Page/CopyDropdown';
+import CopyDropdown from '../../Page/CopyDropdown';
 
 
 type ShareLinkTrProps = {

+ 1 - 0
apps/app/src/components/PageAccessoriesModal/ShareLink/index.ts

@@ -0,0 +1 @@
+export * from './ShareLink';

+ 79 - 0
apps/app/src/components/PageAccessoriesModal/hooks.tsx

@@ -0,0 +1,79 @@
+import { useEffect, useState } from 'react';
+
+import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/stores/modal';
+
+function getURLQueryParamValue(key: string) {
+// window.location.href is page URL;
+  const queryStr: URLSearchParams = new URL(window.location.href).searchParams;
+  return queryStr.get(key);
+}
+
+// https://regex101.com/r/YHTDsr/1
+const queryCompareFormat = /^([0-9a-f]{24})...([0-9a-f]{24})$/i;
+
+
+export const useAutoOpenModalByQueryParam = (): void => {
+  const [isArleadyMounted, setIsArleadyMounted] = useState(false);
+
+  const { data: status, open: openPageAccessories } = usePageAccessoriesModal();
+
+  useEffect(() => {
+    if (isArleadyMounted) {
+      return;
+    }
+
+    if (status == null || status.isOpened === true) {
+      return;
+    }
+
+    const pageIdParams = getURLQueryParamValue('compare');
+    if (pageIdParams != null) {
+      const matches = pageIdParams.match(queryCompareFormat);
+
+      if (matches == null) {
+        return;
+      }
+
+      // open History
+      openPageAccessories(PageAccessoriesModalContents.PageHistory);
+    }
+
+    setIsArleadyMounted(true);
+  }, [openPageAccessories, status, isArleadyMounted]);
+
+};
+
+type ComparingRevisionIds = {
+  sourceRevisionId: string,
+  targetRevisionId: string,
+}
+
+export const useAutoComparingRevisionsByQueryParam = (): ComparingRevisionIds | null => {
+  const [isArleadyMounted, setIsArleadyMounted] = useState(false);
+
+  const [sourceRevisionId, setSourceRevisionId] = useState<string>();
+  const [targetRevisionId, setTargetRevisionId] = useState<string>();
+
+  useEffect(() => {
+    if (isArleadyMounted) {
+      return;
+    }
+
+    const pageIdParams = getURLQueryParamValue('compare');
+    if (pageIdParams != null) {
+      const matches = pageIdParams.match(queryCompareFormat);
+
+      if (matches != null) {
+        const [, source, target] = matches;
+        setSourceRevisionId(source);
+        setTargetRevisionId(target);
+      }
+    }
+
+    setIsArleadyMounted(true);
+  }, [isArleadyMounted]);
+
+  return sourceRevisionId != null && targetRevisionId != null
+    ? { sourceRevisionId, targetRevisionId }
+    : null;
+};

+ 1 - 0
apps/app/src/components/PageAccessoriesModal/index.ts

@@ -0,0 +1 @@
+export * from './PageAccessoriesModal';

+ 1 - 2
apps/app/src/components/SearchPage/SearchPageBase.tsx

@@ -17,8 +17,6 @@ import { mutatePageTree } from '~/stores/page-listing';
 
 import { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
 
-import { SearchResultList } from './SearchResultList';
-
 import styles from './SearchPageBase.module.scss';
 
 // https://regex101.com/r/brrkBu/1
@@ -44,6 +42,7 @@ type Props = {
 }
 
 
+const SearchResultList = dynamic(() => import('./SearchResultList').then(mod => mod.SearchResultList), { ssr: false });
 const SearchResultContent = dynamic(() => import('./SearchResultContent').then(mod => mod.SearchResultContent), {
   ssr: false,
   loading: () => <></>,

+ 7 - 7
apps/app/src/components/ShareLink/ShareLinkPageView.tsx → apps/app/src/components/ShareLinkPageView.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from 'react';
+import React, { useMemo } from 'react';
 
 import type { IPagePopulatedToShowRevision } from '@growi/core';
 import dynamic from 'next/dynamic';
@@ -10,17 +10,17 @@ import { useIsNotFound } from '~/stores/page';
 import { useViewOptions } from '~/stores/renderer';
 import loggerFactory from '~/utils/logger';
 
-import { MainPane } from '../Layout/MainPane';
-import RevisionRenderer from '../Page/RevisionRenderer';
-import ShareLinkAlert from '../Page/ShareLinkAlert';
-import type { PageSideContentsProps } from '../PageSideContents';
+import { MainPane } from './Layout/MainPane';
+import RevisionRenderer from './Page/RevisionRenderer';
+import ShareLinkAlert from './Page/ShareLinkAlert';
+import type { PageSideContentsProps } from './PageSideContents';
 
 
 const logger = loggerFactory('growi:Page');
 
 
-const PageSideContents = dynamic<PageSideContentsProps>(() => import('../PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
-const ForbiddenPage = dynamic(() => import('../ForbiddenPage'), { ssr: false });
+const PageSideContents = dynamic<PageSideContentsProps>(() => import('./PageSideContents').then(mod => mod.PageSideContents), { ssr: false });
+const ForbiddenPage = dynamic(() => import('./ForbiddenPage'), { ssr: false });
 
 
 type Props = {

+ 1 - 1
apps/app/src/pages/share/[[...path]].page.tsx

@@ -12,7 +12,7 @@ import { useCurrentGrowiLayoutFluidClassName } from '~/client/services/layout';
 import { ShareLinkLayout } from '~/components/Layout/ShareLinkLayout';
 import GrowiContextualSubNavigationSubstance from '~/components/Navbar/GrowiContextualSubNavigation';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
-import { ShareLinkPageView } from '~/components/ShareLink/ShareLinkPageView';
+import { ShareLinkPageView } from '~/components/ShareLinkPageView';
 import { SupportedAction, SupportedActionType } from '~/interfaces/activity';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';

+ 13 - 4
apps/app/src/stores/modal.tsx

@@ -357,6 +357,7 @@ type PageAccessoriesModalStatus = {
 type PageAccessoriesModalUtils = {
   open(activatedContents: PageAccessoriesModalContents): void
   close(): void
+  selectContents(activatedContents: PageAccessoriesModalContents): void
 }
 
 export const usePageAccessoriesModal = (): SWRResponse<PageAccessoriesModalStatus, Error> & PageAccessoriesModalUtils => {
@@ -364,9 +365,8 @@ export const usePageAccessoriesModal = (): SWRResponse<PageAccessoriesModalStatu
   const initialStatus = { isOpened: false };
   const swrResponse = useStaticSWR<PageAccessoriesModalStatus, Error>('pageAccessoriesModalStatus', undefined, { fallbackData: initialStatus });
 
-  return {
-    ...swrResponse,
-    open: (activatedContents: PageAccessoriesModalContents) => {
+  return Object.assign(swrResponse, {
+    open: (activatedContents) => {
       if (swrResponse.data == null) {
         return;
       }
@@ -381,7 +381,16 @@ export const usePageAccessoriesModal = (): SWRResponse<PageAccessoriesModalStatu
       }
       swrResponse.mutate({ isOpened: false });
     },
-  };
+    selectContents: (activatedContents) => {
+      if (swrResponse.data == null) {
+        return;
+      }
+      swrResponse.mutate({
+        isOpened: swrResponse.data.isOpened,
+        activatedContents,
+      });
+    },
+  });
 };
 
 /*

+ 22 - 7
apps/app/test/cypress/e2e/20-basic-features/20-basic-features--access-to-page.cy.ts

@@ -7,10 +7,25 @@ function openEditor() {
     });
     // until
     return cy.get('.layout-root').then($elem => $elem.hasClass('editing'));
-  })
+  });
   cy.get('.CodeMirror').should('be.visible');
 }
 
+function appendTextToEditorUntilContains(inputText: string) {
+  const lines: string[] = [];
+  cy.waitUntil(() => {
+    // do
+    cy.get('.CodeMirror textarea').type(inputText, { force: true });
+    // until
+    return cy.get('.CodeMirror-line')
+      .each(($item) => {
+        lines.push($item.text());
+      }).then(() => {
+        return lines.join('\n').endsWith(inputText);
+      });
+  });
+}
+
 context('Access to page', () => {
   const ssPrefix = 'access-to-page-';
 
@@ -86,22 +101,22 @@ context('Access to page', () => {
 
   const body1 = 'hello';
   const body2 = ' world!';
-  it('View and Edit contents are successfully loaded', () => {
+  it('Edit and save with save-page-btn', () => {
     cy.visit('/Sandbox/testForUseEditingMarkdown');
 
     openEditor();
 
     // check edited contents after save
-    cy.get('.CodeMirror textarea').type(body1, { force: true });
-    cy.get('.CodeMirror-code').should('contain.text', body1);
+    appendTextToEditorUntilContains(body1);
     cy.get('.page-editor-preview-body').should('contain.text', body1);
     cy.getByTestid('page-editor').should('be.visible');
     cy.getByTestid('save-page-btn').click();
     cy.get('.wiki').should('be.visible');
     cy.get('.wiki').children().first().should('have.text', body1);
+    cy.screenshot(`${ssPrefix}-edit-and-save-with-save-page-btn`);
   })
 
-  it('Editing contents are successfully loaded with shortcut key', () => {
+  it('Edit and save with shortcut key', () => {
     const savePageShortcutKey = '{ctrl+s}';
 
     cy.visit('/Sandbox/testForUseEditingMarkdown');
@@ -109,12 +124,12 @@ context('Access to page', () => {
     openEditor();
 
     // check editing contents with shortcut key
-    cy.get('.CodeMirror textarea').type(body2, { force: true });
-    cy.get('.CodeMirror-code').should('contain.text', body1+body2);
+    appendTextToEditorUntilContains(body2);
     cy.get('.page-editor-preview-body').should('contain.text', body1+body2);
     cy.get('.CodeMirror').click().type(savePageShortcutKey);
     cy.get('.CodeMirror-code').should('contain.text', body1+body2);
     cy.get('.page-editor-preview-body').should('contain.text', body1+body2);
+    cy.screenshot(`${ssPrefix}-edit-and-save-with-shortcut-key`);
   })
 
   it('/user/admin is successfully loaded', () => {

+ 1 - 2
apps/app/test/cypress/e2e/22-sharelink/22-sharelink--access-to-sharelink.cy.ts

@@ -10,13 +10,12 @@ context('Access to sharelink by guest', () => {
     });
 
     cy.visit('/Sandbox/Bootstrap4');
-    cy.waitUntilSkeletonDisappear();
 
     // open dropdown
     cy.waitUntil(() => {
       // do
       cy.get('#grw-subnav-container').within(() => {
-        cy.getByTestid('open-page-item-control-btn').find('button').click({force: true});
+        cy.getByTestid('open-page-item-control-btn', { timeout: 14000 }).find('button').click({force: true});
       });
       // wait until
       return cy.getByTestid('page-item-control-menu').then($elem => $elem.is(':visible'))

+ 1 - 7
apps/app/test/cypress/e2e/50-sidebar/50-sidebar--access-to-side-bar.cy.ts

@@ -21,11 +21,6 @@ describe('Access to sidebar', () => {
       beforeEach(() => {
         cy.visit('/');
 
-        // Workaround for waitinig initial open/close interaction
-        // TODO: remove this cy.wait() after SSR without the initial interaction is implemented
-        // eslint-disable-next-line cypress/no-unnecessary-waiting
-        cy.wait(2000);
-
         // Since this is a sidebar test, call collapseSidebar in beforeEach.
         cy.collapseSidebar(false);
       });
@@ -212,7 +207,7 @@ describe('Access to sidebar', () => {
         it('Successfully redirect to editor', () => {
           const content = '# HELLO \n ## Hello\n ### Hello';
 
-          cy.get('.grw-sidebar-content-header > h3').find('a').click();
+          cy.get('.grw-sidebar-content-header > h3 > a').should('be.visible').click();
 
           cy.get('.layout-root').should('have.class', 'editing');
           cy.get('.CodeMirror textarea').type(content, {force: true});
@@ -220,7 +215,6 @@ describe('Access to sidebar', () => {
           cy.screenshot(`${ssPrefix}custom-sidebar-2-redirect-to-editor`, { blackout: blackoutOverride });
 
           cy.getByTestid('save-page-btn').click();
-          cy.get('.layout-root').should('not.have.class', 'editing');
         });
 
         it('Successfully create custom sidebar content', () => {

+ 0 - 13
apps/app/test/cypress/e2e/50-sidebar/50-sidebar--switching-sidebar-mode.cy.ts

@@ -9,28 +9,15 @@ const blackoutOverride = [
 context('Switch sidebar mode', () => {
   const ssPrefix = 'switch-sidebar-mode-';
 
-  let connectSid: string | undefined;
-
   before(() => {
     // login
     cy.fixture("user-admin.json").then(user => {
       cy.login(user.username, user.password);
     });
-    cy.getCookie('connect.sid').then(cookie => {
-      connectSid = cookie?.value;
-    });
-  });
-
-  beforeEach(() => {
-    if (connectSid != null) {
-      cy.setCookie('connect.sid', connectSid);
-    }
   });
 
   it('Switching sidebar mode', () => {
     cy.visit('/');
-    // This test uses collapseSidebar here, because this test for the sidebar.
-    cy.collapseSidebar(true)
     cy.get('.grw-apperance-mode-dropdown').first().click();
 
     cy.get('[for="swSidebarMode"]').click({force: true});

+ 7 - 4
apps/app/test/cypress/support/commands.ts

@@ -70,15 +70,17 @@ Cypress.Commands.add('waitUntilSpinnerDisappear', () => {
 });
 
 Cypress.Commands.add('collapseSidebar', (isCollapsed: boolean, waitUntilSaving = false) => {
-  cy.getByTestid('grw-sidebar').should('be.visible');
-
-  cy.getByTestid('grw-sidebar').within(($elem) => {
+  cy.getByTestid('grw-sidebar').within(($sidebar) => {
 
     // skip if .grw-sidebar-dock does not exist
-    if ($elem.hasClass('grw-sidebar-dock')) {
+    if (!$sidebar.hasClass('grw-sidebar-dock')) {
       return;
     }
 
+  });
+
+  cy.getByTestid('grw-sidebar').should('be.visible').within(() => {
+
     const isSidebarContextualNavigationHidden = isHiddenByTestId('grw-contextual-navigation-sub');
     if (isSidebarContextualNavigationHidden === isCollapsed) {
       return;
@@ -97,4 +99,5 @@ Cypress.Commands.add('collapseSidebar', (isCollapsed: boolean, waitUntilSaving =
       return cy.getByTestid('grw-contextual-navigation-sub').then($contents => isHidden($contents) === isCollapsed);
     });
   });
+
 });

+ 1 - 1
apps/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "6.1.7-slackbot-proxy.0",
+  "version": "6.1.8-slackbot-proxy.0",
   "license": "MIT",
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/core",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI Core Libraries",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/hackmd/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/hackmd",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI js and css files to use hackmd",
   "license": "MIT",
   "type": "module",

+ 1 - 1
packages/presentation/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/presentation",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI plugin for presentation",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/preset-templates/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/preset-templates",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "scripts": {
     "test": "vitest run",
     "version": "yarn version --no-git-tag-version --preid=RC"

+ 1 - 1
packages/preset-themes/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@growi/preset-themes",
   "description": "GROWI preset themes",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "license": "MIT",
   "main": "dist/libs/preset-themes.umd.js",
   "module": "dist/libs/preset-themes.mjs",

+ 1 - 1
packages/remark-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/remark-attachment-refs",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/remark-drawio/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/remark-drawio",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "remark plugin to draw diagrams with draw.io (diagrams.net)",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/remark-growi-directive/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/remark-growi-directive",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "remark plugin to support GROWI plugin (forked from remark-directive@2.0.1)",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/remark-lsx/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/remark-lsx",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI plugin to list pages",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slack",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "module": "dist/index.mjs",

+ 1 - 1
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/ui",
-  "version": "6.1.7-RC.0",
+  "version": "6.1.8-RC.0",
   "description": "GROWI UI Libraries",
   "license": "MIT",
   "keywords": [

+ 11 - 11
yarn.lock

@@ -2312,13 +2312,13 @@
     xdg-basedir "^4.0.0"
 
 "@growi/core@link:packages/core":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     bson-objectid "^2.0.4"
     escape-string-regexp "^4.0.0"
 
 "@growi/hackmd@link:packages/hackmd":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
 
 "@growi/pluginkit@link:packages/pluginkit":
   version "0.1.0"
@@ -2327,18 +2327,18 @@
     extensible-custom-error "^0.0.7"
 
 "@growi/presentation@link:packages/presentation":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@growi/core" "link:packages/core"
 
 "@growi/preset-templates@link:packages/preset-templates":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
 
 "@growi/preset-themes@link:packages/preset-themes":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
 
 "@growi/remark-attachment-refs@link:packages/remark-attachment-refs":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@growi/core" "link:packages/core"
     "@growi/remark-growi-directive" "link:packages/remark-growi-directive"
@@ -2347,12 +2347,12 @@
     universal-bunyan "^0.9.2"
 
 "@growi/remark-drawio@link:packages/remark-drawio":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     pako "^2.1.0"
 
 "@growi/remark-growi-directive@link:packages/remark-growi-directive":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@types/mdast" "^3.0.0"
     "@types/unist" "^2.0.0"
@@ -2369,7 +2369,7 @@
     uvu "^0.5.0"
 
 "@growi/remark-lsx@link:packages/remark-lsx":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@growi/core" "link:packages/core"
     "@growi/remark-growi-directive" "link:packages/remark-growi-directive"
@@ -2380,7 +2380,7 @@
     swr "^2.0.3"
 
 "@growi/slack@link:packages/slack":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@slack/oauth" "^2.0.1"
     axios "^0.24.0"
@@ -2393,7 +2393,7 @@
     url-join "^4.0.0"
 
 "@growi/ui@link:packages/ui":
-  version "6.1.7-RC.0"
+  version "6.1.8-RC.0"
   dependencies:
     "@growi/core" "link:packages/core"