Przeglądaj źródła

Merge branch 'feat/search-implement' into feat/77524-search-result-conent-page

Yohei-Shiina 4 lat temu
rodzic
commit
dce6d8cb66

+ 1 - 0
packages/app/resource/locales/en_US/translation.json

@@ -577,6 +577,7 @@
     "delete_completely": "Delete completely",
     "include_certain_path" : "Include {{pathToInclude}} path ",
     "delete_all_selected_page" : "Delete All",
+    "search_again" : "Search again",
     "number_of_list_to_display" : "Display",
     "page_number_unit" : "pages"
 

+ 2 - 1
packages/app/resource/locales/ja_JP/translation.json

@@ -64,7 +64,7 @@
   "Include Attachment File": "添付ファイルも含める",
   "Include Comment": "コメントも含める",
   "Include Subordinated Page": "配下ページも含める",
-  "Include Subordinated Target Page": "{{target}} 下含む",
+  "Include Subordinated Target Page": "{{target}} 下含む",
   "All Subordinated Page": "全ての配下ページ",
   "Specify Hierarchy": "階層の深さを指定",
   "Submitted the request to create the archive": "アーカイブ作成のリクエストを正常に送信しました",
@@ -577,6 +577,7 @@
     "delete_completely": "完全に削除する",
     "include_certain_path": "{{pathToInclude}}下を含む ",
     "delete_all_selected_page" : "一括削除",
+    "search_again" : "再検索",
     "number_of_list_to_display" : "表示件数",
     "page_number_unit" : "件"
   },

+ 1 - 0
packages/app/resource/locales/zh_CN/translation.json

@@ -850,6 +850,7 @@
 		"delete_completely": "完全删除",
     "include_certain_path": "包含 {{pathToInclude}} 路径 ",
     "delete_all_selected_page": "删除所有",
+    "search_again" : "再次搜索",
     "number_of_list_to_display" : "显示器的数量",
     "page_number_unit" : "例"
 	},

+ 16 - 12
packages/app/src/components/SearchPage.jsx

@@ -34,8 +34,8 @@ class SearchPage extends React.Component {
       searchResultCount: 0,
       activePage: 1,
       pagingLimit: this.props.appContainer.config.pageLimitationL,
-      excludeUsersHome: true,
-      excludeTrash: true,
+      excludeUserPages: true,
+      excludeTrashPages: true,
     };
 
     this.changeURL = this.changeURL.bind(this);
@@ -43,8 +43,8 @@ class SearchPage extends React.Component {
     this.onSearchInvoked = this.onSearchInvoked.bind(this);
     this.selectPage = this.selectPage.bind(this);
     this.toggleCheckBox = this.toggleCheckBox.bind(this);
-    this.onExcludeUsersHome = this.onExcludeUsersHome.bind(this);
-    this.onExcludeTrash = this.onExcludeTrash.bind(this);
+    this.switchExcludeUserPagesHandler = this.switchExcludeUserPagesHandler.bind(this);
+    this.switchExcludeTrashPagesHandler = this.switchExcludeTrashPagesHandler.bind(this);
     this.onPagingNumberChanged = this.onPagingNumberChanged.bind(this);
     this.onPagingLimitChanged = this.onPagingLimitChanged.bind(this);
   }
@@ -68,12 +68,12 @@ class SearchPage extends React.Component {
     return query;
   }
 
-  onExcludeUsersHome() {
-    this.setState({ excludeUsersHome: !this.state.excludeUsersHome });
+  switchExcludeUserPagesHandler() {
+    this.setState({ excludeUserPages: !this.state.excludeUserPages });
   }
 
-  onExcludeTrash() {
-    this.setState({ excludeTrash: !this.state.excludeTrash });
+  switchExcludeTrashPagesHandler() {
+    this.setState({ excludeTrashPages: !this.state.excludeTrashPages });
   }
 
   changeURL(keyword, refreshHash) {
@@ -91,10 +91,10 @@ class SearchPage extends React.Component {
     let query = keyword;
 
     // pages included in specific path are not retrived when prefix is added
-    if (this.state.excludeTrash) {
+    if (this.state.excludeTrashPages) {
       query = `${query} -prefix:${specificPathNames.trash}`;
     }
-    if (this.state.excludeUsersHome) {
+    if (this.state.excludeUserPages) {
       query = `${query} -prefix:${specificPathNames.user}`;
     }
 
@@ -122,6 +122,8 @@ class SearchPage extends React.Component {
     this.setState({ pagingLimit: limit }, () => this.search({ keyword: this.state.searchedKeyword }));
   }
 
+  // todo: refactoring
+  // refs: https://redmine.weseek.co.jp/issues/82139
   async search(data) {
     const keyword = data.keyword;
     if (keyword === '') {
@@ -227,8 +229,10 @@ class SearchPage extends React.Component {
         searchingKeyword={this.state.searchingKeyword}
         appContainer={this.props.appContainer}
         onSearchInvoked={this.onSearchInvoked}
-        onExcludeUsersHome={this.onExcludeUsersHome}
-        onExcludeTrash={this.onExcludeTrash}
+        onExcludeUserPagesSwitched={this.switchExcludeUserPagesHandler}
+        onExcludeTrashPagesSwitched={this.switchExcludeTrashPagesHandler}
+        excludeUserPages={this.state.excludeUserPages}
+        excludeTrashPages={this.state.excludeTrashPages}
       >
       </SearchControl>
     );

+ 57 - 13
packages/app/src/components/SearchPage/SearchControl.tsx

@@ -1,33 +1,38 @@
-import React, { FC } from 'react';
+import React, { FC, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 import SearchPageForm from './SearchPageForm';
 import AppContainer from '../../client/services/AppContainer';
 import DeleteSelectedPageGroup from './DeleteSelectedPageGroup';
+import SearchOptionModal from './SearchOptionModal';
 import { CheckboxType } from '../../interfaces/search';
 
 type Props = {
   searchingKeyword: string,
   appContainer: AppContainer,
-  onSearchInvoked: (data : any[]) => boolean,
-  onExcludeUsersHome?: () => void,
-  onExcludeTrash?: () => void,
+  excludeUserPages: boolean,
+  excludeTrashPages: boolean,
+  onSearchInvoked: (data: {keyword: string}) => boolean,
+  onExcludeUserPagesSwitched?: () => void,
+  onExcludeTrashPagesSwitched?: () => void,
 }
 
 const SearchControl: FC <Props> = (props: Props) => {
+
+  const [isFileterOptionModalShown, setIsFileterOptionModalShown] = useState(false);
   // Temporaly workaround for lint error
   // later needs to be fixed: SearchControl to typescript componet
   const SearchPageFormTypeAny : any = SearchPageForm;
   const { t } = useTranslation('');
 
-  const onExcludeUsersHome = () => {
-    if (props.onExcludeUsersHome != null) {
-      props.onExcludeUsersHome();
+  const switchExcludeUserPagesHandler = () => {
+    if (props.onExcludeUserPagesSwitched != null) {
+      props.onExcludeUserPagesSwitched();
     }
   };
 
-  const onExcludeTrash = () => {
-    if (props.onExcludeTrash != null) {
-      props.onExcludeTrash();
+  const switchExcludeTrashPagesHandler = () => {
+    if (props.onExcludeTrashPagesSwitched != null) {
+      props.onExcludeTrashPagesSwitched();
     }
   };
 
@@ -46,6 +51,34 @@ const SearchControl: FC <Props> = (props: Props) => {
     // ref: https://getbootstrap.com/docs/4.5/components/forms/#checkboxes
   };
 
+  const openSearchOptionModalHandler = () => {
+    setIsFileterOptionModalShown(true);
+  };
+
+  const closeSearchOptionModalHandler = () => {
+    setIsFileterOptionModalShown(false);
+  };
+
+  const onRetrySearchInvoked = () => {
+    if (props.onSearchInvoked != null) {
+      props.onSearchInvoked({ keyword: props.searchingKeyword });
+    }
+  };
+
+  const rednerSearchOptionModal = () => {
+    return (
+      <SearchOptionModal
+        isOpen={isFileterOptionModalShown || false}
+        onClickFilteringSearchResult={onRetrySearchInvoked}
+        onClose={closeSearchOptionModalHandler}
+        onExcludeUserPagesSwitched={switchExcludeUserPagesHandler}
+        onExcludeTrashPagesSwitched={switchExcludeTrashPagesHandler}
+        excludeUserPages={props.excludeUserPages}
+        excludeTrashPages={props.excludeTrashPages}
+      />
+    );
+  };
+
   return (
     <>
       <div className="search-page-nav d-flex py-3 align-items-center">
@@ -71,14 +104,24 @@ const SearchControl: FC <Props> = (props: Props) => {
             onCheckInvoked={onCheckAllPagesInvoked}
           />
         </div>
-        <div className="d-flex align-items-center mr-3">
+        {/** filter option */}
+        <div className="d-lg-none mr-4">
+          <button
+            type="button"
+            className="btn"
+            onClick={openSearchOptionModalHandler}
+          >
+            <i className="icon-equalizer"></i>
+          </button>
+        </div>
+        <div className="d-none d-lg-flex align-items-center mr-3">
           <div className="border border-gray mr-3">
             <label className="px-3 py-2 mb-0 d-flex align-items-center" htmlFor="flexCheckDefault">
               <input
                 className="mr-2"
                 type="checkbox"
                 id="flexCheckDefault"
-                onClick={() => onExcludeUsersHome()}
+                onClick={switchExcludeUserPagesHandler}
               />
               {t('Include Subordinated Target Page', { target: '/user' })}
             </label>
@@ -89,13 +132,14 @@ const SearchControl: FC <Props> = (props: Props) => {
                 className="mr-2"
                 type="checkbox"
                 id="flexCheckChecked"
-                onClick={() => onExcludeTrash()}
+                onClick={switchExcludeTrashPagesHandler}
               />
               {t('Include Subordinated Target Page', { target: '/trash' })}
             </label>
           </div>
         </div>
       </div>
+      {rednerSearchOptionModal()}
     </>
   );
 };

+ 83 - 0
packages/app/src/components/SearchPage/SearchOptionModal.tsx

@@ -0,0 +1,83 @@
+import React, { FC } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import {
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
+
+
+type Props = {
+  isOpen: boolean,
+  excludeUserPages: boolean,
+  excludeTrashPages: boolean,
+  onClose?: () => void,
+  onExcludeUserPagesSwitched?: () => void,
+  onExcludeTrashPagesSwitched?: () => void,
+  onClickFilteringSearchResult?: () => void,
+}
+
+const SearchOptionModal: FC<Props> = (props: Props) => {
+
+  const { t } = useTranslation('');
+
+  const {
+    isOpen, onClose, excludeUserPages, excludeTrashPages,
+  } = props;
+
+  const onCloseModal = () => {
+    if (onClose != null) {
+      onClose();
+    }
+  };
+
+  const onClickFilteringSearchResult = () => {
+    if (props.onClickFilteringSearchResult != null) {
+      props.onClickFilteringSearchResult();
+      onCloseModal();
+    }
+  };
+
+  return (
+    <Modal size="lg" isOpen={isOpen} toggle={onCloseModal} autoFocus={false}>
+      <ModalHeader tag="h4" toggle={onCloseModal} className="bg-primary text-light">
+        Search Option
+      </ModalHeader>
+      <ModalBody>
+        <div className="d-flex p-3">
+          <div className="border border-gray mr-3">
+            <label className="px-3 py-2 mb-0 d-flex align-items-center">
+              <input
+                className="mr-2"
+                type="checkbox"
+                onClick={props.onExcludeUserPagesSwitched}
+                checked={!excludeUserPages}
+              />
+              {t('Include Subordinated Target Page', { target: '/user' })}
+            </label>
+          </div>
+          <div className="border border-gray">
+            <label className="px-3 py-2 mb-0 d-flex align-items-center">
+              <input
+                className="mr-2"
+                type="checkbox"
+                onClick={props.onExcludeTrashPagesSwitched}
+                checked={!excludeTrashPages}
+              />
+              {t('Include Subordinated Target Page', { target: '/trash' })}
+            </label>
+          </div>
+        </div>
+      </ModalBody>
+      <ModalFooter>
+        <button
+          type="button"
+          className="btn btn-secondary"
+          onClick={onClickFilteringSearchResult}
+        >{t('search_result.search_again')}
+        </button>
+      </ModalFooter>
+    </Modal>
+  );
+};
+
+export default SearchOptionModal;