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

Merge pull request #6327 from weseek/feat/100608-reset-search-criteria-button

feat: Reset search criteria button
Yuki Takei 3 лет назад
Родитель
Сommit
060969e158

+ 2 - 0
packages/app/public/static/locales/en_US/admin/admin.json

@@ -536,6 +536,8 @@
     "url": "URL",
     "url": "URL",
     "settings": "Settings",
     "settings": "Settings",
     "return": "Return",
     "return": "Return",
+    "clear": "Clear search criteria",
+    "reload": "Reload",
     "activity_expiration_date": "Audit Log expiration date",
     "activity_expiration_date": "Audit Log expiration date",
     "activity_expiration_date_explain": "Created Audit Log are automatically deleted after the number of seconds set in the environment variable from the creation time",
     "activity_expiration_date_explain": "Created Audit Log are automatically deleted after the number of seconds set in the environment variable from the creation time",
     "fixed_by_env_var": "This is fixed by the env var <code>{{key}}={{value}}</code>.",
     "fixed_by_env_var": "This is fixed by the env var <code>{{key}}={{value}}</code>.",

+ 2 - 0
packages/app/public/static/locales/ja_JP/admin/admin.json

@@ -535,6 +535,8 @@
     "url": "URL",
     "url": "URL",
     "settings": "設定",
     "settings": "設定",
     "return": "戻る",
     "return": "戻る",
+    "clear": "検索条件のクリア",
+    "reload": "再読み込み",
     "activity_expiration_date": "監査ログの有効期限",
     "activity_expiration_date": "監査ログの有効期限",
     "activity_expiration_date_explain": "作成された監査ログは、作成時間から環境変数に設定した秒数後に自動的に削除されます",
     "activity_expiration_date_explain": "作成された監査ログは、作成時間から環境変数に設定した秒数後に自動的に削除されます",
     "fixed_by_env_var": "環境変数により固定されています <code>{{key}}={{value}}</code>.",
     "fixed_by_env_var": "環境変数により固定されています <code>{{key}}={{value}}</code>.",

+ 2 - 0
packages/app/public/static/locales/zh_CN/admin/admin.json

@@ -545,6 +545,8 @@
     "url": "URL",
     "url": "URL",
     "settings": "设置",
     "settings": "设置",
     "return": "返回",
     "return": "返回",
+    "clear": "清除搜索标准",
+    "reload": "重新加载",
     "activity_expiration_date": "审计日志的到期日",
     "activity_expiration_date": "审计日志的到期日",
     "activity_expiration_date_explain": "创建的审计日志会在环境变量中设置的从创建时间算起的秒数后自动删除",
     "activity_expiration_date_explain": "创建的审计日志会在环境变量中设置的从创建时间算起的秒数后自动删除",
     "fixed_by_env_var": "这是由env var 修复的 <code>{{key}}={{value}}</code>.",
     "fixed_by_env_var": "这是由env var 修复的 <code>{{key}}={{value}}</code>.",

+ 3 - 0
packages/app/src/client/interfaces/clearable.ts

@@ -0,0 +1,3 @@
+export interface IClearable {
+  clear: () => void,
+}

+ 18 - 3
packages/app/src/components/Admin/AuditLog/SearchUsernameTypeahead.tsx

@@ -1,10 +1,11 @@
 import React, {
 import React, {
-  FC, Fragment, useState, useCallback,
+  Fragment, useState, useCallback, useRef, ForwardRefRenderFunction, forwardRef, useImperativeHandle,
 } from 'react';
 } from 'react';
 
 
 import { AsyncTypeahead, Menu, MenuItem } from 'react-bootstrap-typeahead';
 import { AsyncTypeahead, Menu, MenuItem } from 'react-bootstrap-typeahead';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 
 
+import { IClearable } from '~/client/interfaces/clearable';
 import { useSWRxUsernames } from '~/stores/user';
 import { useSWRxUsernames } from '~/stores/user';
 
 
 
 
@@ -25,10 +26,12 @@ type Props = {
   onChange: (text: string[]) => void
   onChange: (text: string[]) => void
 }
 }
 
 
-export const SearchUsernameTypeahead: FC<Props> = (props: Props) => {
+const SearchUsernameTypeaheadSubstance: ForwardRefRenderFunction<IClearable, Props> = ((props: Props, ref) => {
   const { onChange } = props;
   const { onChange } = props;
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
+  const typeaheadRef = useRef<IClearable>(null);
+
   /*
   /*
    * State
    * State
    */
    */
@@ -96,6 +99,15 @@ export const SearchUsernameTypeahead: FC<Props> = (props: Props) => {
     );
     );
   }, []);
   }, []);
 
 
+  useImperativeHandle(ref, () => ({
+    clear() {
+      const instance = typeaheadRef?.current;
+      if (instance != null) {
+        instance.clear();
+      }
+    },
+  }));
+
   return (
   return (
     <div className="input-group mr-2">
     <div className="input-group mr-2">
       <div className="input-group-prepend">
       <div className="input-group-prepend">
@@ -104,6 +116,7 @@ export const SearchUsernameTypeahead: FC<Props> = (props: Props) => {
         </span>
         </span>
       </div>
       </div>
       <AsyncTypeahead
       <AsyncTypeahead
+        ref={typeaheadRef}
         id="search-username-typeahead-asynctypeahead"
         id="search-username-typeahead-asynctypeahead"
         multiple
         multiple
         delay={400}
         delay={400}
@@ -119,4 +132,6 @@ export const SearchUsernameTypeahead: FC<Props> = (props: Props) => {
       />
       />
     </div>
     </div>
   );
   );
-};
+});
+
+export const SearchUsernameTypeahead = forwardRef(SearchUsernameTypeaheadSubstance);

+ 32 - 8
packages/app/src/components/Admin/AuditLogManagement.tsx

@@ -1,8 +1,11 @@
-import React, { FC, useState, useCallback } from 'react';
+import React, {
+  FC, useState, useCallback, useRef,
+} from 'react';
 
 
 import { format } from 'date-fns';
 import { format } from 'date-fns';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 
 
+import { IClearable } from '~/client/interfaces/clearable';
 import { toastError } from '~/client/util/apiNotification';
 import { toastError } from '~/client/util/apiNotification';
 import { SupportedActionType } from '~/interfaces/activity';
 import { SupportedActionType } from '~/interfaces/activity';
 import { useSWRxActivity } from '~/stores/activity';
 import { useSWRxActivity } from '~/stores/activity';
@@ -17,7 +20,6 @@ import { DateRangePicker } from './AuditLog/DateRangePicker';
 import { SearchUsernameTypeahead } from './AuditLog/SearchUsernameTypeahead';
 import { SearchUsernameTypeahead } from './AuditLog/SearchUsernameTypeahead';
 import { SelectActionDropdown } from './AuditLog/SelectActionDropdown';
 import { SelectActionDropdown } from './AuditLog/SelectActionDropdown';
 
 
-
 const formatDate = (date: Date | null) => {
 const formatDate = (date: Date | null) => {
   if (date == null) {
   if (date == null) {
     return '';
     return '';
@@ -30,8 +32,9 @@ const PAGING_LIMIT = 10;
 export const AuditLogManagement: FC = () => {
 export const AuditLogManagement: FC = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
+  const typeaheadRef = useRef<IClearable>(null);
+
   const { data: auditLogAvailableActionsData } = useAuditLogAvailableActions();
   const { data: auditLogAvailableActionsData } = useAuditLogAvailableActions();
-  const auditLogAvailableActions = auditLogAvailableActionsData != null ? auditLogAvailableActionsData : [];
 
 
   /*
   /*
    * State
    * State
@@ -43,7 +46,7 @@ export const AuditLogManagement: FC = () => {
   const [endDate, setEndDate] = useState<Date | null>(null);
   const [endDate, setEndDate] = useState<Date | null>(null);
   const [selectedUsernames, setSelectedUsernames] = useState<string[]>([]);
   const [selectedUsernames, setSelectedUsernames] = useState<string[]>([]);
   const [actionMap, setActionMap] = useState(
   const [actionMap, setActionMap] = useState(
-    new Map<SupportedActionType, boolean>(auditLogAvailableActions.map(action => [action, true])),
+    new Map<SupportedActionType, boolean>(auditLogAvailableActionsData != null ? auditLogAvailableActionsData.map(action => [action, true]) : []),
   );
   );
 
 
   /*
   /*
@@ -94,6 +97,18 @@ export const AuditLogManagement: FC = () => {
     setSelectedUsernames(usernames);
     setSelectedUsernames(usernames);
   }, []);
   }, []);
 
 
+  const clearButtonPushedHandler = useCallback(() => {
+    setActivePage(1);
+    setStartDate(null);
+    setEndDate(null);
+    setSelectedUsernames([]);
+    typeaheadRef.current?.clear();
+
+    if (auditLogAvailableActionsData != null) {
+      setActionMap(new Map<SupportedActionType, boolean>(auditLogAvailableActionsData.map(action => [action, true])));
+    }
+  }, [setActivePage, setStartDate, setEndDate, setSelectedUsernames, setActionMap, auditLogAvailableActionsData]);
+
   const reloadButtonPushedHandler = useCallback(() => {
   const reloadButtonPushedHandler = useCallback(() => {
     setActivePage(1);
     setActivePage(1);
     mutateActivity();
     mutateActivity();
@@ -128,6 +143,7 @@ export const AuditLogManagement: FC = () => {
         <>
         <>
           <div className="form-inline mb-3">
           <div className="form-inline mb-3">
             <SearchUsernameTypeahead
             <SearchUsernameTypeahead
+              ref={typeaheadRef}
               onChange={setUsernamesHandler}
               onChange={setUsernamesHandler}
             />
             />
 
 
@@ -139,14 +155,22 @@ export const AuditLogManagement: FC = () => {
 
 
             <SelectActionDropdown
             <SelectActionDropdown
               actionMap={actionMap}
               actionMap={actionMap}
-              availableActions={auditLogAvailableActions}
+              availableActions={auditLogAvailableActionsData || []}
               onChangeAction={actionCheckboxChangedHandler}
               onChangeAction={actionCheckboxChangedHandler}
               onChangeMultipleAction={multipleActionCheckboxChangedHandler}
               onChangeMultipleAction={multipleActionCheckboxChangedHandler}
             />
             />
 
 
-            <button type="button" className="btn ml-auto grw-btn-reload" onClick={reloadButtonPushedHandler}>
-              <i className="icon icon-reload" />
-            </button>
+            <div className="ml-auto">
+              <button type="button" className="btn btn-outline-secondary btn-sm mr-2" onClick={clearButtonPushedHandler}>
+                <span className="icon-refresh mr-1" />
+                {t('admin:audit_log_management.clear')}
+              </button>
+
+              <button type="button" className="btn btn-outline-secondary btn-sm" onClick={reloadButtonPushedHandler}>
+                <i className="icon icon-reload mr-1" />
+                {t('admin:audit_log_management.reload')}
+              </button>
+            </div>
           </div>
           </div>
 
 
           <p
           <p