Jelajahi Sumber

Merge pull request #4380 from weseek/feat/77515-77640-create-searchbox-component

feat: change search functionality
yuto-o 4 tahun lalu
induk
melakukan
ee8439f4ee

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

@@ -63,6 +63,7 @@
   "Include Attachment File": "Include Attachment File",
   "Include Comment": "Include Comment",
   "Include Subordinated Page": "Include Subordinated Page",
+  "Include Subordinated Target Page": "include {{target}}",
   "All Subordinated Page": "All Subordinated Page",
   "Specify Hierarchy": "Specify Hierarchy",
   "Submitted the request to create the archive": "Submitted the request to create the archive",

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

@@ -64,6 +64,7 @@
   "Include Attachment File": "添付ファイルも含める",
   "Include Comment": "コメントも含める",
   "Include Subordinated Page": "配下ページも含める",
+  "Include Subordinated Target Page": "{{target}}下を含む",
   "All Subordinated Page": "全ての配下ページ",
   "Specify Hierarchy": "階層の深さを指定",
   "Submitted the request to create the archive": "アーカイブ作成のリクエストを正常に送信しました",

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

@@ -65,6 +65,7 @@
   "Include Attachment File": "包含附件",
   "Include Comment": "包含评论",
   "Include Subordinated Page": "包括子页面",
+  "Include Subordinated Target Page": "包括 {{target}}",
   "All Subordinated Page": "所有子页面",
   "Specify Hierarchy": "指定层级",
   "Submitted the request to create the archive": "提交创建归档请求",

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

@@ -13,6 +13,11 @@ import SearchResultContent from './SearchPage/SearchResultContent';
 import SearchResultList from './SearchPage/SearchResultList';
 import SearchControl from './SearchPage/SearchControl';
 
+export const specificPathNames = {
+  user: '/user',
+  trash: '/trash',
+};
+
 class SearchPage extends React.Component {
 
   constructor(props) {
@@ -27,12 +32,16 @@ class SearchPage extends React.Component {
       searchResultMeta: {},
       selectedPage: {},
       selectedPages: new Set(),
+      excludeUsersHome: true,
+      excludeTrash: true,
     };
 
     this.changeURL = this.changeURL.bind(this);
     this.search = this.search.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);
   }
 
   componentDidMount() {
@@ -54,6 +63,14 @@ class SearchPage extends React.Component {
     return query;
   }
 
+  onExcludeUsersHome() {
+    this.setState({ excludeUsersHome: !this.state.excludeUsersHome });
+  }
+
+  onExcludeTrash() {
+    this.setState({ excludeTrash: !this.state.excludeTrash });
+  }
+
   changeURL(keyword, refreshHash) {
     let hash = window.location.hash || '';
     // TODO 整理する
@@ -65,6 +82,19 @@ class SearchPage extends React.Component {
     }
   }
 
+  createSearchQuery(keyword) {
+    let query = keyword;
+
+    // pages included in specific path are not retrived when prefix is added
+    if (this.state.excludeTrash) {
+      query = `${query} -prefix:${specificPathNames.trash}`;
+    }
+    if (this.state.excludeUsersHome) {
+      query = `${query} -prefix:${specificPathNames.user}`;
+    }
+
+    return query;
+  }
 
   search(data) {
     const keyword = data.keyword;
@@ -81,7 +111,7 @@ class SearchPage extends React.Component {
     this.setState({
       searchingKeyword: keyword,
     });
-    this.props.appContainer.apiGet('/search', { q: keyword })
+    this.props.appContainer.apiGet('/search', { q: this.createSearchQuery(keyword) })
       .then((res) => {
         this.changeURL(keyword);
         if (res.data.length > 0) {
@@ -97,6 +127,14 @@ class SearchPage extends React.Component {
             selectedPage: res.data[0],
           });
         }
+        else {
+          this.setState({
+            searchedKeyword: keyword,
+            searchedPages: [],
+            searchResultMeta: {},
+            selectedPage: {},
+          });
+        }
       })
       .catch((err) => {
         toastError(err);
@@ -152,6 +190,8 @@ class SearchPage extends React.Component {
         searchingKeyword={this.state.searchingKeyword}
         appContainer={this.props.appContainer}
         onSearchInvoked={this.search}
+        onExcludeUsersHome={this.onExcludeUsersHome}
+        onExcludeTrash={this.onExcludeTrash}
       >
       </SearchControl>
     );

+ 44 - 2
packages/app/src/components/SearchPage/SearchControl.tsx

@@ -1,18 +1,34 @@
 import React, { FC } from 'react';
+import { useTranslation } from 'react-i18next';
 import SearchPageForm from './SearchPageForm';
 import AppContainer from '../../client/services/AppContainer';
 
-
 type Props = {
   searchingKeyword: string,
   appContainer: AppContainer,
   onSearchInvoked: (data : any[]) => boolean,
+  onExcludeUsersHome?: () => void,
+  onExcludeTrash?: () => void,
 }
 
 const SearchControl: FC <Props> = (props: Props) => {
   // 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 onExcludeTrash = () => {
+    if (props.onExcludeTrash != null) {
+      props.onExcludeTrash();
+    }
+  };
+
   return (
     <div className="">
       <div className="search-page-input sps sps--abv">
@@ -22,7 +38,33 @@ const SearchControl: FC <Props> = (props: Props) => {
           onSearchFormChanged={props.onSearchInvoked}
         />
       </div>
-      {/* TODO: place deleteAll button , relevance button , include specificPath button */}
+      {/* TODO: replace the following elements deleteAll button , relevance button and include specificPath button component */}
+      <div className="d-flex my-4">
+        <div className="form-check border-gray">
+          <input
+            className="form-check-input"
+            type="checkbox"
+            value=""
+            id="flexCheckDefault"
+            onClick={() => onExcludeUsersHome()}
+          />
+          <label className="form-check-label" htmlFor="flexCheckDefault">
+            {t('Include Subordinated Target Page', { target: '/user' })}
+          </label>
+        </div>
+        <div className="form-check">
+          <input
+            className="form-check-input"
+            type="checkbox"
+            value=""
+            id="flexCheckChecked"
+            onClick={() => onExcludeTrash()}
+          />
+          <label className="form-check-label" htmlFor="flexCheckChecked">
+            {t('Include Subordinated Target Page', { target: '/trash' })}
+          </label>
+        </div>
+      </div>
     </div>
   );
 };

+ 3 - 2
packages/app/src/components/SearchPage/SearchPageForm.jsx

@@ -40,8 +40,9 @@ class SearchPageForm extends React.Component {
 
   render() {
     return (
-      <div className="input-group mb-3 d-flex">
-        <div className="flex-fill">
+      // TODO: modify design after other component is created
+      <div className="grw-search-form-in-search-result-page d-flex">
+        <div className="input-group flex-nowrap">
           <SearchForm
             onSubmit={this.search}
             keyword={this.state.searchedKeyword}