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

Merge branch 'master' into imprv/avoid-cypress-errors

jam411 3 лет назад
Родитель
Сommit
f4fe94313b

+ 14 - 1
CHANGELOG.md

@@ -1,9 +1,22 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v5.1.5...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v5.1.7...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v5.1.7](https://github.com/weseek/growi/compare/v5.1.6...v5.1.7) - 2022-10-26
+
+### 🐛 Bug Fixes
+
+- fix: Page move event notification message (#6823) @hakumizuki
+
+## [v5.1.6](https://github.com/weseek/growi/compare/v5.1.5...v5.1.6) - 2022-10-19
+
+### 🐛 Bug Fixes
+
+- fix: image not showing and exceed crop modal area (#6712) @mudana-grune
+- fix: Conflict Diff Modal Error getCurrentOptionsToSave is not a function (#6745) @kaoritokashiki
+
 ## [v5.1.5](https://github.com/weseek/growi/compare/v5.1.4...v5.1.5) - 2022-10-04
 
 ### 💎 Features

+ 2 - 10
packages/app/_obsolete/src/client/services/PageContainer.js

@@ -14,8 +14,6 @@ import {
 import {
   DrawioInterceptor,
 } from '../../services/renderer/interceptor/drawio-interceptor';
-import { toastError } from '../util/apiNotification';
-import { apiPost } from '../util/apiv1-client';
 
 const { isTrashPage } = pagePathUtils;
 
@@ -338,23 +336,17 @@ export default class PageContainer extends Container {
   retrieveMyBookmarkList() {
   }
 
-  async resolveConflict(markdown, editorMode) {
+  async resolveConflict(markdown, editorMode, optionsToSave) {
 
     const { pageId, remoteRevisionId, path } = this.state;
     const editorContainer = this.appContainer.getContainer('EditorContainer');
-    const options = editorContainer.getCurrentOptionsToSave();
-    const optionsToSave = Object.assign({}, options);
 
     const res = await this.updatePage(pageId, remoteRevisionId, markdown, optionsToSave);
 
     editorContainer.clearDraft(path);
     this.updateStateAfterSave(res.page, res.tags, res.revision, editorMode);
 
-    // Update PageEditor component
-    if (editorMode !== EditorMode.Editor) {
-      // eslint-disable-next-line no-undef
-      globalEmitter.emit('updateEditorValue', markdown);
-    }
+    window.globalEmitter.emit('updateEditorValue', markdown);
 
     editorContainer.setState({ tags: res.tags });
 

+ 2 - 2
packages/app/docker/README.md

@@ -11,8 +11,8 @@ Supported tags and respective Dockerfile links
 ------------------------------------------------
 
 * [`6.0.0`, `6.0`, `6`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v6.0.0/packages/app/docker/Dockerfile)
-* [`5.1.5`, `5.1`, `5`](https://github.com/weseek/growi/blob/v5.1.5/packages/app/docker/Dockerfile)
-* [`5.1.5-nocdn`, `5.1-nocdn`, `5-nocdn`](https://github.com/weseek/growi/blob/v5.1.5/packages/app/docker/Dockerfile)
+* [`5.1.7`, `5.1`, `5`](https://github.com/weseek/growi/blob/v5.1.7/packages/app/docker/Dockerfile)
+* [`5.1.7-nocdn`, `5.1-nocdn`, `5-nocdn`](https://github.com/weseek/growi/blob/v5.1.7/packages/app/docker/Dockerfile)
 * [`4.5.23`, `4.5`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.23/packages/app/docker/Dockerfile)
 * [`4.5.23-nocdn`, `4.5-nocdn`, `4-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.23/packages/app/docker/Dockerfile)
 

+ 1 - 1
packages/app/src/client/util/editor.ts

@@ -1,4 +1,4 @@
-import { OptionsToSave } from '~/interfaces/editor-settings';
+import type { OptionsToSave } from '~/interfaces/editor-settings';
 
 export const getOptionsToSave = (
     isSlackEnabled: boolean,

+ 29 - 25
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -3,6 +3,7 @@ import React, { useState, useEffect, useCallback } from 'react';
 import { isPopulated, IUser } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
+import { useRouter } from 'next/router';
 import { DropdownItem } from 'reactstrap';
 
 import { exportAsMarkdown } from '~/client/services/page-operation';
@@ -184,6 +185,8 @@ type GrowiContextualSubNavigationProps = {
 
 const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps): JSX.Element => {
 
+  const router = useRouter();
+
   const { data: currentPage, mutate: mutateCurrentPage } = useSWRxCurrentPage();
 
   const revision = currentPage?.revision;
@@ -270,43 +273,44 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
     return;
   }, [mutatePageTagsForEditors]);
 
+  const reload = useCallback(() => {
+    if (currentPathname != null) {
+      router.push(currentPathname);
+    }
+  }, [currentPathname, router]);
+
   const duplicateItemClickedHandler = useCallback(async(page: IPageForPageDuplicateModal) => {
     const duplicatedHandler: OnDuplicatedFunction = (fromPath, toPath) => {
-      window.location.href = toPath;
+      router.push(toPath);
     };
     openDuplicateModal(page, { onDuplicated: duplicatedHandler });
-  }, [openDuplicateModal]);
+  }, [openDuplicateModal, router]);
 
   const renameItemClickedHandler = useCallback(async(page: IPageToRenameWithMeta<IPageInfoForEntity>) => {
     const renamedHandler: OnRenamedFunction = () => {
-      if (page.data._id !== null) {
-        window.location.href = `/${page.data._id}`;
-        return;
-      }
-      window.location.reload();
+      reload();
     };
     openRenameModal(page, { onRenamed: renamedHandler });
-  }, [openRenameModal]);
+  }, [openRenameModal, reload]);
 
-  const onDeletedHandler: OnDeletedFunction = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
-    if (typeof pathOrPathsToDelete !== 'string') {
-      return;
-    }
-
-    const path = pathOrPathsToDelete;
+  const deleteItemClickedHandler = useCallback((pageWithMeta: IPageWithMeta) => {
+    const deletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively, isCompletely) => {
+      if (typeof pathOrPathsToDelete !== 'string') {
+        return;
+      }
 
-    if (isCompletely) {
-      // redirect to NotFound Page
-      window.location.href = path;
-    }
-    else {
-      window.location.reload();
-    }
-  }, []);
+      const path = pathOrPathsToDelete;
 
-  const deleteItemClickedHandler = useCallback((pageWithMeta: IPageWithMeta) => {
-    openDeleteModal([pageWithMeta], { onDeleted: onDeletedHandler });
-  }, [onDeletedHandler, openDeleteModal]);
+      if (isCompletely) {
+        // redirect to NotFound Page
+        router.push(path);
+      }
+      else {
+        reload();
+      }
+    };
+    openDeleteModal([pageWithMeta], { onDeleted: deletedHandler });
+  }, [openDeleteModal, reload, router]);
 
   const templateMenuItemClickHandler = useCallback(() => {
     setIsPageTempleteModalShown(true);

+ 5 - 6
packages/app/src/components/PageAlert/TrashPageAlert.tsx

@@ -2,11 +2,10 @@ import React from 'react';
 
 import { UserPicture } from '@growi/ui';
 import { format } from 'date-fns';
+import { useRouter } from 'next/router';
 import { useTranslation } from 'react-i18next';
 
-import {
-  useIsTrashPage, useShareLinkId,
-} from '~/stores/context';
+import { useIsTrashPage } from '~/stores/context';
 import { usePageDeleteModal, usePutBackPageModal } from '~/stores/modal';
 import { useSWRxPageInfo, useSWRxCurrentPage } from '~/stores/page';
 import { useIsAbleToShowTrashPageManagementButtons } from '~/stores/ui';
@@ -21,14 +20,14 @@ const onDeletedHandler = (pathOrPathsToDelete) => {
 
 export const TrashPageAlert = (): JSX.Element => {
   const { t } = useTranslation();
+  const router = useRouter();
 
   const { data: isAbleToShowTrashPageManagementButtons } = useIsAbleToShowTrashPageManagementButtons();
-  const { data: shareLinkId } = useShareLinkId();
   const { data: pageData } = useSWRxCurrentPage();
   const { data: isTrashPage } = useIsTrashPage();
   const pageId = pageData?._id;
   const pagePath = pageData?.path;
-  const { data: pageInfo } = useSWRxPageInfo(pageId ?? null, shareLinkId);
+  const { data: pageInfo } = useSWRxPageInfo(pageId ?? null);
 
 
   const { open: openDeleteModal } = usePageDeleteModal();
@@ -49,7 +48,7 @@ export const TrashPageAlert = (): JSX.Element => {
       return;
     }
     const putBackedHandler = () => {
-      window.location.reload();
+      router.push(`/${pageId}`);
     };
     openPutBackPageModal({ pageId, path: pagePath }, { onPutBacked: putBackedHandler });
   }

+ 15 - 0
packages/app/src/components/PageEditor.tsx

@@ -84,6 +84,20 @@ const PageEditor = React.memo((): JSX.Element => {
   const editorRef = useRef<IEditorMethods>(null);
   const previewRef = useRef<HTMLDivElement>(null);
 
+
+  // const optionsToSave = useMemo(() => {
+  //   if (grantData == null) {
+  //     return;
+  //   }
+  //   const slackChannels = slackChannelsData ? slackChannelsData.toString() : '';
+  //   const optionsToSave = getOptionsToSave(
+  //     isSlackEnabled ?? false, slackChannels,
+  //     grantData.grant, grantData.grantedGroup?.id, grantData.grantedGroup?.name,
+  //     pageTags || [],
+  //   );
+  //   return optionsToSave;
+  // }, [grantData, isSlackEnabled, pageTags, slackChannelsData]);
+
   const setMarkdownWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string, isClean: boolean) => {
     markdownToSave.current = value;
     setMarkdownToPreview(value);
@@ -427,6 +441,7 @@ const PageEditor = React.memo((): JSX.Element => {
         onClose={() => pageContainer.setState({ isConflictDiffModalOpen: false })}
         pageContainer={pageContainer}
         markdownOnEdit={markdown}
+        optionsToSave={optionsToSave}
       /> */}
     </div>
   );

+ 5 - 3
packages/app/src/components/PageEditor/ConflictDiffModal.tsx

@@ -2,6 +2,7 @@ import React, {
   useState, useEffect, useRef, useMemo, useCallback,
 } from 'react';
 
+import type { IUser } from '@growi/core';
 import { UserPicture } from '@growi/ui';
 import CodeMirror from 'codemirror/lib/codemirror';
 import { format } from 'date-fns';
@@ -10,7 +11,7 @@ import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
-import { IUser } from '~/interfaces/user';
+import type { OptionsToSave } from '~/interfaces/editor-settings';
 import { useCurrentUser } from '~/stores/context';
 import { useEditorMode } from '~/stores/ui';
 
@@ -30,6 +31,7 @@ type ConflictDiffModalProps = {
   onClose?: (() => void);
   // pageContainer: PageContainer;
   markdownOnEdit: string;
+  optionsToSave: OptionsToSave | undefined;
 };
 
 type IRevisionOnConflictWithStringDate = Omit<IRevisionOnConflict, 'createdAt'> & {
@@ -109,7 +111,7 @@ const ConflictDiffModalCore = (props: ConflictDiffModalProps & { currentUser: IU
     const codeMirrorVal = uncontrolledRef.current?.editor.doc.getValue();
 
     try {
-      // await pageContainer.resolveConflict(codeMirrorVal, editorMode);
+      // await pageContainer.resolveConflict(codeMirrorVal, editorMode, props.optionsToSave);
       // close();
       // pageContainer.showSuccessToastr();
     }
@@ -117,7 +119,7 @@ const ConflictDiffModalCore = (props: ConflictDiffModalProps & { currentUser: IU
       // pageContainer.showErrorToastr(error);
     }
 
-  }, [editorMode, close]);
+  }, []);
 
   const resizeAndCloseButtons = useMemo(() => (
     <div className="d-flex flex-nowrap">

+ 1 - 0
packages/app/src/components/PutbackPageModal.jsx

@@ -63,6 +63,7 @@ const PutBackPageModal = () => {
       </>
     );
   };
+
   const BodyContent = () => {
     if (!isOpened) {
       return <></>;

+ 7 - 2
packages/app/src/components/TableOfContents.tsx

@@ -1,8 +1,9 @@
 import React, { useCallback } from 'react';
 
+import { pagePathUtils } from '@growi/core';
 import ReactMarkdown from 'react-markdown';
 
-import { useIsUserPage } from '~/stores/context';
+import { useCurrentPagePath } from '~/stores/context';
 import { useTocOptions } from '~/stores/renderer';
 import loggerFactory from '~/utils/logger';
 
@@ -10,12 +11,16 @@ import { StickyStretchableScroller } from './StickyStretchableScroller';
 
 import styles from './TableOfContents.module.scss';
 
+const { isUserPage: _isUserPage } = pagePathUtils;
+
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:TableOfContents');
 
 const TableOfContents = (): JSX.Element => {
 
-  const { data: isUserPage } = useIsUserPage();
+  const { data: currentPagePath } = useCurrentPagePath();
+
+  const isUserPage = currentPagePath != null && _isUserPage(currentPagePath);
 
   // const [tocHtml, setTocHtml] = useState('');
 

+ 2 - 4
packages/app/src/pages/[[...path]].page.tsx

@@ -58,11 +58,11 @@ import DisplaySwitcher from '../components/Page/DisplaySwitcher';
 import {
   useCurrentUser, useCurrentPagePath,
   useIsLatestRevision,
-  useIsForbidden, useIsNotFound, useIsTrashPage, useIsSharedUser,
+  useIsForbidden, useIsNotFound, useIsSharedUser,
   useIsEnabledStaleNotification, useIsIdenticalPath,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useDisableLinkSharing,
   useDrawioUri, useHackmdUri, useDefaultIndentSize, useIsIndentSizeForced,
-  useIsAclEnabled, useIsUserPage, useIsSearchPage,
+  useIsAclEnabled, useIsSearchPage,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
   useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
   useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage, useLayoutSetting, useCustomizedLogoSrc,
@@ -239,11 +239,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   const pagePath = pageWithMeta?.data.path ?? (!_isPermalink(props.currentPathname) ? props.currentPathname : undefined);
 
   useCurrentPageId(pageId ?? null);
-  useIsUserPage(pagePath != null && isUserPage(pagePath));
   // useIsNotCreatable(props.isForbidden || !isCreatablePage(pagePath)); // TODO: need to include props.isIdentical
   useCurrentPagePath(pagePath);
   useCurrentPathname(props.currentPathname);
-  useIsTrashPage(pagePath != null && _isTrashPage(pagePath));
 
   useSWRxCurrentPage(undefined, pageWithMeta?.data ?? null); // store initial data
   useEditingMarkdown(pageWithMeta?.data.revision?.body ?? '');

+ 13 - 13
packages/app/src/stores/context.tsx

@@ -1,4 +1,4 @@
-import { IUser } from '@growi/core';
+import { IUser, pagePathUtils } from '@growi/core';
 import { HtmlElementNode } from 'rehype-toc';
 import { Key, SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
@@ -80,14 +80,6 @@ export const useIsIdenticalPath = (initialData?: boolean): SWRResponse<boolean,
   return useStaticSWR<boolean, Error>('isIdenticalPath', initialData, { fallbackData: false });
 };
 
-export const useIsUserPage = (initialData?: boolean): SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isUserPage', initialData, { fallbackData: false });
-};
-
-export const useIsTrashPage = (initialData?: boolean): SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isTrashPage', initialData, { fallbackData: false });
-};
-
 // export const useIsNotCreatable = (initialData?: boolean): SWRResponse<boolean, Error> => {
 //   return useStaticSWR<boolean, Error>('isNotCreatable', initialData, { fallbackData: false });
 // };
@@ -293,12 +285,11 @@ export const useIsEditable = (): SWRResponse<boolean, Error> => {
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isForbidden } = useIsForbidden();
   const { data: isIdenticalPath } = useIsIdenticalPath();
-  const { data: isTrashPage } = useIsTrashPage();
 
   return useSWRImmutable(
-    ['isEditable', isGuestUser, isForbidden, isIdenticalPath, isTrashPage],
-    (key: Key, isGuestUser: boolean, isForbidden: boolean, isIdenticalPath: boolean, isTrashPage: boolean) => {
-      return (!isTrashPage && !isForbidden && !isIdenticalPath && !isGuestUser);
+    ['isEditable', isGuestUser, isForbidden, isIdenticalPath],
+    (key: Key, isGuestUser: boolean, isForbidden: boolean, isIdenticalPath: boolean) => {
+      return (!isForbidden && !isIdenticalPath && !isGuestUser);
     },
   );
 };
@@ -308,3 +299,12 @@ export const useCurrentPageTocNode = (): SWRResponse<HtmlElementNode, any> => {
 
   return useStaticSWR(['currentPageTocNode', currentPagePath]);
 };
+
+export const useIsTrashPage = (): SWRResponse<boolean, Error> => {
+  const { data: pagePath } = useCurrentPagePath();
+
+  return useSWRImmutable(
+    pagePath == null ? null : ['isTrashPage', pagePath],
+    (key: Key, pagePath: string) => pagePathUtils.isTrashPage(pagePath),
+  );
+};

+ 10 - 7
packages/app/src/stores/ui.tsx

@@ -405,18 +405,21 @@ export const useIsAbleToShowTrashPageManagementButtons = (): SWRResponse<boolean
 export const useIsAbleToShowPageManagement = (): SWRResponse<boolean, Error> => {
   const key = 'isAbleToShowPageManagement';
   const { data: currentPageId } = useCurrentPageId();
-  const { data: isTrashPage } = useIsTrashPage();
-  const { data: isSharedUser } = useIsSharedUser();
+  const { data: _isTrashPage } = useIsTrashPage();
+  const { data: _isSharedUser } = useIsSharedUser();
   const { data: isNotFound } = useIsNotFound();
 
   const pageId = currentPageId;
-  const includesUndefined = [pageId, isTrashPage, isSharedUser, isNotFound].some(v => v === undefined);
-  const isPageExist = (pageId != null) && !isNotFound;
-  const isEmptyPage = (pageId != null) && isNotFound;
+  const includesUndefined = [pageId, _isTrashPage, _isSharedUser, isNotFound].some(v => v === undefined);
+  const isPageExist = (pageId != null) && isNotFound === false;
+  const isEmptyPage = (pageId != null) && isNotFound === true;
+  const isTrashPage = isPageExist && _isTrashPage === true;
+  const isSharedUser = isPageExist && _isSharedUser === true;
 
   return useSWRImmutable(
-    includesUndefined ? null : [key, pageId],
-    () => (isPageExist && !isTrashPage && !isSharedUser) || (isEmptyPage != null && isEmptyPage),
+    includesUndefined ? null : [key, pageId, isPageExist, isEmptyPage, isTrashPage, isSharedUser],
+    // eslint-disable-next-line max-len
+    (key: string, pageId: string, isPageExist: boolean, isTrashPage: boolean, isSharedUser: boolean) => (isPageExist && !isTrashPage && !isSharedUser) || isEmptyPage,
   );
 };