Taichi Masuyama 4 лет назад
Родитель
Сommit
d65f8818fb

+ 7 - 6
packages/app/src/components/PageDeleteModal.tsx

@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
 
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiv3Post } from '~/client/util/apiv3-client';
-import { usePageDeleteModalStatus, usePageDeleteModalOpened } from '~/stores/ui';
+import { usePageDeleteModal, usePageDeleteModalOpened } from '~/stores/ui';
 
 import { IPageApiv1Result, IDeleteManyPageApiv3Result } from '~/interfaces/page';
 
@@ -38,7 +38,7 @@ const PageDeleteModal: FC<Props> = (props: Props) => {
     isDeleteCompletelyModal, isAbleToDeleteCompletely,
   } = props;
 
-  const { data: deleteModalStatus, close: closeDeleteModal } = usePageDeleteModalStatus();
+  const { data: deleteModalStatus, close: closeDeleteModal } = usePageDeleteModal();
   const { data: pageDeleteModalOpened } = usePageDeleteModalOpened();
 
   const isOpened = pageDeleteModalOpened?.isOpend != null ? pageDeleteModalOpened.isOpend : false;
@@ -84,7 +84,7 @@ const PageDeleteModal: FC<Props> = (props: Props) => {
         });
 
         if (pageDeleteModalOpened != null && pageDeleteModalOpened.onDeleted != null) {
-          pageDeleteModalOpened.onDeleted(data.paths, data.isRecursively);
+          pageDeleteModalOpened.onDeleted(data.paths, data.isRecursively, data.isCompletely);
         }
       }
       catch (err) {
@@ -101,7 +101,7 @@ const PageDeleteModal: FC<Props> = (props: Props) => {
 
         const page = deleteModalStatus.pages[0];
 
-        const { path, isRecursively } = await apiPost('/pages.remove', {
+        const { path, isRecursively, isCompletely } = await apiPost('/pages.remove', {
           page_id: page.pageId,
           revision_id: page.revisionId,
           recursively,
@@ -109,7 +109,7 @@ const PageDeleteModal: FC<Props> = (props: Props) => {
         }) as IPageApiv1Result;
 
         if (pageDeleteModalOpened != null && pageDeleteModalOpened.onDeleted != null) {
-          pageDeleteModalOpened.onDeleted(path, isRecursively);
+          pageDeleteModalOpened.onDeleted(path, isRecursively, isCompletely);
         }
       }
       catch (err) {
@@ -119,7 +119,8 @@ const PageDeleteModal: FC<Props> = (props: Props) => {
   }
 
   async function deleteButtonHandler() {
-    deletePage();
+    await closeDeleteModal();
+    await deletePage();
   }
 
   function renderDeleteRecursivelyForm() {

+ 1 - 1
packages/app/src/components/SearchPage.jsx

@@ -352,7 +352,7 @@ class SearchPage extends React.Component {
           activePage={this.state.activePage}
         >
         </SearchPageLayout>
-        {/* TODO: show PageDeleteModal with usePageDeleteModalStatus by 87569  */}
+        {/* TODO: show PageDeleteModal with usePageDeleteModal by 87569  */}
         <PageDeleteModal
           isOpen={this.state.isDeleteConfirmModalShown}
           onClose={this.closeDeleteConfirmModalHandler}

+ 18 - 5
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -8,7 +8,7 @@ import { useSWRxPageAncestorsChildren, useSWRxRootPage } from '../../../stores/p
 import { TargetAndAncestors } from '~/interfaces/page-listing-results';
 import { toastError, toastSuccess } from '~/client/util/apiNotification';
 import {
-  IPageForPageDeleteModal, usePageDuplicateModalStatus, usePageRenameModalStatus, usePageDeleteModalStatus,
+  IPageForPageDeleteModal, usePageDuplicateModalStatus, usePageRenameModalStatus, usePageDeleteModal,
   OnDeletedFunction,
 } from '~/stores/ui';
 import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
@@ -99,7 +99,7 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
   const { data: rootPageData, error: error2 } = useSWRxRootPage();
   const { open: openDuplicateModal } = usePageDuplicateModalStatus();
   const { open: openRenameModal } = usePageRenameModalStatus();
-  const { open: openDeleteModal } = usePageDeleteModalStatus();
+  const { open: openDeleteModal } = usePageDeleteModal();
 
   useEffect(() => {
     const startFrom = document.getElementById('grw-sidebar-contents-scroll-target');
@@ -118,13 +118,26 @@ const ItemsTree: FC<ItemsTreeProps> = (props: ItemsTreeProps) => {
     openRenameModal(pageId, revisionId, path);
   };
 
-  const onDeletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively) => {
+  const onDeletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively, isCompletely) => {
     if (typeof pathOrPathsToDelete === 'string') {
+      const path = pathOrPathsToDelete;
+      console.log(pathOrPathsToDelete, isRecursively, isCompletely);
       if (isRecursively) {
-        toastSuccess(t('deleted_single_page_recursively', { path: pathOrPathsToDelete }));
+        if (isCompletely) {
+          toastSuccess(t('deleted_single_page_recursively_completely', { path }));
+        }
+        else {
+          toastSuccess(t('deleted_single_page_recursively', { path }));
+        }
       }
       else {
-        toastSuccess(t('deleted_single_page', { path: pathOrPathsToDelete }));
+        // eslint-disable-next-line no-lonely-if
+        if (isCompletely) {
+          toastSuccess(t('deleted_single_page_completely', { path }));
+        }
+        else {
+          toastSuccess(t('deleted_single_page', { path }));
+        }
       }
     }
   };

+ 2 - 0
packages/app/src/interfaces/common.ts

@@ -7,3 +7,5 @@ import { HasObjectId } from './has-object-id';
 
 // Foreign key field
 export type Ref<T> = string | T & HasObjectId;
+
+export type Nullable<T> = T | null | undefined;

+ 5 - 3
packages/app/src/interfaces/page.ts

@@ -1,4 +1,4 @@
-import { Ref } from './common';
+import { Ref, Nullable } from './common';
 import { IUser } from './user';
 import { IRevision, HasRevisionShortbody } from './revision';
 import { ITag } from './tag';
@@ -101,10 +101,12 @@ export type IPageWithMeta<M = IPageInfoAll> = {
 export type IPageApiv1Result = {
   ok: boolean
   path: string,
-  isRecursively: true | null | undefined,
+  isRecursively: Nullable<true>,
+  isCompletely: Nullable<true>,
 };
 
 export type IDeleteManyPageApiv3Result = {
   paths: string[],
-  isRecursively: true | null | undefined,
+  isRecursively: Nullable<true>,
+  isCompletely: Nullable<true>,
 };

+ 2 - 1
packages/app/src/server/routes/apiv3/pages.js

@@ -183,6 +183,7 @@ module.exports = (crowi) => {
     ],
     deletePages: [
       body('pageIdToRevisionIdMap')
+        .exists()
         .withMessage('The body property "pageIdToRevisionIdMap" must be an json map with pageId as key and revisionId as value.'),
       body('isCompletely')
         .custom(v => v === 'true' || v === true || v == null)
@@ -761,7 +762,7 @@ module.exports = (crowi) => {
     // run delete
     crowi.pageService.deleteMultiplePages(pagesCanBeDeleted, req.user, isCompletely, isRecursively);
 
-    return res.apiv3({ paths: pagesCanBeDeleted.map(p => p.path), isRecursively });
+    return res.apiv3({ paths: pagesCanBeDeleted.map(p => p.path), isRecursively, isCompletely });
   });
 
   router.post('/v5-schema-migration', accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {

+ 3 - 5
packages/app/src/server/routes/page.js

@@ -1180,10 +1180,7 @@ module.exports = function(crowi, app) {
     const pageId = req.body.page_id;
     const previousRevision = req.body.revision_id || null;
 
-    // get completely flag
-    const isCompletely = req.body.completely;
-    // get recursively flag
-    const isRecursively = req.body.recursively;
+    const { recursively: isRecursively, completely: isCompletely } = req.body;
 
     const options = {};
 
@@ -1223,8 +1220,9 @@ module.exports = function(crowi, app) {
 
     debug('Page deleted', page.path);
     const result = {};
-    result.path = page.path; // TODO consider to use serializePageSecurely method -- 2018.08.06 Yuki Takei
+    result.path = page.path;
     result.isRecursively = isRecursively;
+    result.isCompletely = isCompletely;
 
     res.json(ApiResponse.success(result));
 

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

@@ -4,6 +4,7 @@ import useSWR, {
 import useSWRImmutable from 'swr/immutable';
 
 import { Breakpoint, addBreakpointListener } from '@growi/ui';
+import { pagePathUtils } from '@growi/core';
 
 import { RefObject } from 'react';
 import { SidebarContentsType } from '~/interfaces/ui';
@@ -15,14 +16,14 @@ import {
   useIsNotCreatable, useIsSharedUser, useNotFoundTargetPathOrId, useIsForbidden, useIsIdenticalPath,
 } from './context';
 import { IFocusable } from '~/client/interfaces/focusable';
-import { isSharedPage } from '^/../core/src/utils/page-path-utils';
+import { Nullable } from '~/interfaces/common';
+
+const { isSharedPage } = pagePathUtils;
 
 const logger = loggerFactory('growi:stores:ui');
 
 const isServer = typeof window === 'undefined';
 
-type Nullable<T> = T | null;
-
 
 /** **********************************************************
  *                          Unions
@@ -299,11 +300,11 @@ export const useCreateModalPath = (): SWRResponse<string | null | undefined, Err
 // PageDeleteModal
 export type IPageForPageDeleteModal = {
   pageId: string,
-  revisionId: string,
+  revisionId?: string,
   path: string
 }
 
-export type OnDeletedFunction = (pathOrPaths: string | string[], isRecursively: true | null | undefined) => void;
+export type OnDeletedFunction = (pathOrPaths: string | string[], isRecursively: Nullable<true>, isCompletely: Nullable<true>) => void;
 
 type DeleteModalStatus = {
   isOpened: boolean,
@@ -324,7 +325,7 @@ type DeleteModalStatusUtils = {
   close(): Promise<DeleteModalStatus | undefined>,
 }
 
-export const usePageDeleteModalStatus = (status?: DeleteModalStatus): SWRResponse<DeleteModalStatus, Error> & DeleteModalStatusUtils => {
+export const usePageDeleteModal = (status?: DeleteModalStatus): SWRResponse<DeleteModalStatus, Error> & DeleteModalStatusUtils => {
   const initialData: DeleteModalStatus = { isOpened: false };
   const swrResponse = useStaticSWR<DeleteModalStatus, Error>('deleteModalStatus', status, { fallbackData: initialData });
 
@@ -336,7 +337,7 @@ export const usePageDeleteModalStatus = (status?: DeleteModalStatus): SWRRespons
 };
 
 export const usePageDeleteModalOpened = (): SWRResponse<(DeleteModalOpened | null), Error> => {
-  const { data } = usePageDeleteModalStatus();
+  const { data } = usePageDeleteModal();
   return useSWRImmutable(
     data != null ? ['isDeleteModalOpened', data] : null,
     () => {