Kaynağa Gözat

Merge branch 'master' into fix/normalize-parent

Haku Mizuki 4 yıl önce
ebeveyn
işleme
beeb1c75c2

+ 5 - 4
packages/app/src/components/PageList/PageListItemL.tsx

@@ -23,7 +23,7 @@ import {
   IPageInfoAll, IPageInfoForEntity, IPageInfoForListing, IPageWithMeta, isIPageInfoForListing,
   IPageInfoAll, IPageInfoForEntity, IPageInfoForListing, IPageWithMeta, isIPageInfoForListing,
 } from '~/interfaces/page';
 } from '~/interfaces/page';
 import { IPageSearchMeta, isIPageSearchMeta } from '~/interfaces/search';
 import { IPageSearchMeta, isIPageSearchMeta } from '~/interfaces/search';
-import { OnDuplicatedFunction, OnDeletedFunction } from '~/interfaces/ui';
+import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import LinkedPagePath from '~/models/linked-page-path';
 import LinkedPagePath from '~/models/linked-page-path';
 
 
 import { ForceHideMenuItems, PageItemControl } from '../Common/Dropdown/PageItemControl';
 import { ForceHideMenuItems, PageItemControl } from '../Common/Dropdown/PageItemControl';
@@ -38,6 +38,7 @@ type Props = {
   onCheckboxChanged?: (isChecked: boolean, pageId: string) => void,
   onCheckboxChanged?: (isChecked: boolean, pageId: string) => void,
   onClickItem?: (pageId: string) => void,
   onClickItem?: (pageId: string) => void,
   onPageDuplicated?: OnDuplicatedFunction,
   onPageDuplicated?: OnDuplicatedFunction,
+  onPageRenamed?: OnRenamedFunction,
   onPageDeleted?: OnDeletedFunction,
   onPageDeleted?: OnDeletedFunction,
 }
 }
 
 
@@ -47,7 +48,7 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
     page: { data: pageData, meta: pageMeta }, isSelected, isEnableActions,
     page: { data: pageData, meta: pageMeta }, isSelected, isEnableActions,
     forceHideMenuItems,
     forceHideMenuItems,
     showPageUpdatedTime,
     showPageUpdatedTime,
-    onClickItem, onCheckboxChanged, onPageDuplicated, onPageDeleted,
+    onClickItem, onCheckboxChanged, onPageDuplicated, onPageRenamed, onPageDeleted,
   } = props;
   } = props;
 
 
   const inputRef = useRef<HTMLInputElement>(null);
   const inputRef = useRef<HTMLInputElement>(null);
@@ -115,8 +116,8 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
       revisionId: pageData.revision as string,
       revisionId: pageData.revision as string,
       path: pageData.path,
       path: pageData.path,
     };
     };
-    openRenameModal(page);
-  }, [openRenameModal, pageData]);
+    openRenameModal(page, { onRenamed: onPageRenamed });
+  }, [onPageRenamed, openRenameModal, pageData._id, pageData.path, pageData.revision]);
 
 
 
 
   const deleteMenuItemClickHandler = useCallback((_id: string, pageInfo: IPageInfoAll | undefined) => {
   const deleteMenuItemClickHandler = useCallback((_id: string, pageInfo: IPageInfoAll | undefined) => {

+ 10 - 3
packages/app/src/components/SearchPage/SearchResultContent.tsx

@@ -7,7 +7,7 @@ import { DropdownItem } from 'reactstrap';
 
 
 import { IPageToDeleteWithMeta, IPageWithMeta } from '~/interfaces/page';
 import { IPageToDeleteWithMeta, IPageWithMeta } from '~/interfaces/page';
 import { IPageSearchMeta } from '~/interfaces/search';
 import { IPageSearchMeta } from '~/interfaces/search';
-import { OnDuplicatedFunction, OnDeletedFunction } from '~/interfaces/ui';
+import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import { usePageTreeTermManager } from '~/stores/page-listing';
 import { usePageTreeTermManager } from '~/stores/page-listing';
 import { useFullTextSearchTermManager } from '~/stores/search';
 import { useFullTextSearchTermManager } from '~/stores/search';
 import { useDescendantsPageListForCurrentPathTermManager } from '~/stores/page';
 import { useDescendantsPageListForCurrentPathTermManager } from '~/stores/page';
@@ -132,8 +132,15 @@ export const SearchResultContent: FC<Props> = (props: Props) => {
   }, [advanceDpl, advanceFts, advancePt, openDuplicateModal, t]);
   }, [advanceDpl, advanceFts, advancePt, openDuplicateModal, t]);
 
 
   const renameItemClickedHandler = useCallback(async(pageToRename) => {
   const renameItemClickedHandler = useCallback(async(pageToRename) => {
-    openRenameModal(pageToRename);
-  }, [openRenameModal]);
+    const renamedHandler: OnRenamedFunction = (path) => {
+      toastSuccess(t('renamed_pages', { path }));
+
+      advancePt();
+      advanceFts();
+      advanceDpl();
+    };
+    openRenameModal(pageToRename, { onRenamed: renamedHandler });
+  }, [advanceDpl, advanceFts, advancePt, openRenameModal, t]);
 
 
   const onDeletedHandler: OnDeletedFunction = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
   const onDeletedHandler: OnDeletedFunction = useCallback((pathOrPathsToDelete, isRecursively, isCompletely) => {
     if (typeof pathOrPathsToDelete !== 'string') {
     if (typeof pathOrPathsToDelete !== 'string') {

+ 40 - 2
packages/app/src/components/SearchPage/SearchResultList.tsx

@@ -2,11 +2,14 @@ import React, {
   forwardRef,
   forwardRef,
   ForwardRefRenderFunction, useCallback, useImperativeHandle, useRef,
   ForwardRefRenderFunction, useCallback, useImperativeHandle, useRef,
 } from 'react';
 } from 'react';
+import { useTranslation } from 'react-i18next';
 import { ISelectable, ISelectableAll } from '~/client/interfaces/selectable-all';
 import { ISelectable, ISelectableAll } from '~/client/interfaces/selectable-all';
+import { toastSuccess } from '~/client/util/apiNotification';
 import {
 import {
   IPageInfoForListing, IPageWithMeta, isIPageInfoForListing,
   IPageInfoForListing, IPageWithMeta, isIPageInfoForListing,
 } from '~/interfaces/page';
 } from '~/interfaces/page';
 import { IPageSearchMeta } from '~/interfaces/search';
 import { IPageSearchMeta } from '~/interfaces/search';
+import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import { useIsGuestUser } from '~/stores/context';
 import { useIsGuestUser } from '~/stores/context';
 import { useSWRxPageInfoForList } from '~/stores/page';
 import { useSWRxPageInfoForList } from '~/stores/page';
 import { usePageTreeTermManager } from '~/stores/page-listing';
 import { usePageTreeTermManager } from '~/stores/page-listing';
@@ -31,6 +34,8 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
     onPageSelected,
     onPageSelected,
   } = props;
   } = props;
 
 
+  const { t } = useTranslation();
+
   const pageIdsWithNoSnippet = pages
   const pageIdsWithNoSnippet = pages
     .filter(page => (page.meta?.elasticSearchResult?.snippet.length ?? 0) === 0)
     .filter(page => (page.meta?.elasticSearchResult?.snippet.length ?? 0) === 0)
     .map(page => page.data._id);
     .map(page => page.data._id);
@@ -88,6 +93,38 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
     });
     });
   }
   }
 
 
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  const duplicatedHandler : OnDuplicatedFunction = (fromPath, toPath) => {
+    toastSuccess(t('duplicated_pages', { fromPath }));
+
+    advancePt();
+    advanceFts();
+  };
+
+  const renamedHandler: OnRenamedFunction = (path) => {
+    toastSuccess(t('renamed_pages', { path }));
+
+    advancePt();
+    advanceFts();
+  };
+  const deletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively, isCompletely) => {
+    if (typeof pathOrPathsToDelete !== 'string') {
+      return;
+    }
+
+    const path = pathOrPathsToDelete;
+
+    if (isCompletely) {
+      toastSuccess(t('deleted_pages_completely', { path }));
+    }
+    else {
+      toastSuccess(t('deleted_pages', { path }));
+    }
+    advancePt();
+    advanceFts();
+  };
+
+
   return (
   return (
     <ul data-testid="search-result-list" className="page-list-ul list-group list-group-flush">
     <ul data-testid="search-result-list" className="page-list-ul list-group list-group-flush">
       { (injectedPages ?? pages).map((page, i) => {
       { (injectedPages ?? pages).map((page, i) => {
@@ -102,8 +139,9 @@ const SearchResultListSubstance: ForwardRefRenderFunction<ISelectableAll, Props>
             forceHideMenuItems={forceHideMenuItems}
             forceHideMenuItems={forceHideMenuItems}
             onClickItem={clickItemHandler}
             onClickItem={clickItemHandler}
             onCheckboxChanged={props.onCheckboxChanged}
             onCheckboxChanged={props.onCheckboxChanged}
-            onPageDeleted={() => { advancePt(); advanceFts() }}
-            onPageDuplicated={() => { advancePt(); advanceFts() }}
+            onPageDuplicated={duplicatedHandler}
+            onPageRenamed={renamedHandler}
+            onPageDeleted={deletedHandler}
           />
           />
         );
         );
       })}
       })}

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

@@ -1230,7 +1230,8 @@ module.exports = function(crowi, app) {
 
 
   validator.revertRemove = [
   validator.revertRemove = [
     body('recursively')
     body('recursively')
-      .custom(v => v === 'true' || v === true || null)
+      .optional()
+      .custom(v => v === 'true' || v === true || v == null)
       .withMessage('The body property "recursively" must be "true" or true. (Omit param for false)'),
       .withMessage('The body property "recursively" must be "true" or true. (Omit param for false)'),
   ];
   ];