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

Merge pull request #6189 from weseek/imprv/99422-select-action-dropdown

imprv: Select Action Dropdown
Yuki Takei 3 лет назад
Родитель
Сommit
1a9071a893

+ 33 - 8
packages/app/src/components/Admin/AuditLog/SelectActionDropdown.tsx

@@ -1,12 +1,14 @@
-import React, { FC, useCallback } from 'react';
+import React, { FC, useMemo, useCallback } from 'react';
 
 import { useTranslation } from 'react-i18next';
 
-import { SupportedActionType } from '~/interfaces/activity';
+import {
+  SupportedActionType, SupportedActionCategoryType, SupportedActionCategory, PageActions, CommentActions, UserActions, AdminActions,
+} from '~/interfaces/activity';
 
 type Props = {
-  dropdownItems: Array<{actionCategory: string, actionNames: SupportedActionType[]}>
   actionMap: Map<SupportedActionType, boolean>
+  availableActions: SupportedActionType[]
   onChangeAction: (action: SupportedActionType) => void
   onChangeMultipleAction: (actions: SupportedActionType[], isChecked: boolean) => void
 }
@@ -14,9 +16,32 @@ type Props = {
 export const SelectActionDropdown: FC<Props> = (props: Props) => {
   const { t } = useTranslation();
   const {
-    dropdownItems, actionMap, onChangeAction, onChangeMultipleAction,
+    actionMap, availableActions, onChangeAction, onChangeMultipleAction,
   } = props;
 
+  const dropdownItems = useMemo<Array<{actionCategory: SupportedActionCategoryType, actions: SupportedActionType[]}>>(() => {
+    return (
+      [
+        {
+          actionCategory: SupportedActionCategory.PAGE,
+          actions: PageActions.filter(action => availableActions.includes(action)),
+        },
+        {
+          actionCategory: SupportedActionCategory.COMMENT,
+          actions: CommentActions.filter(action => availableActions.includes(action)),
+        },
+        {
+          actionCategory: SupportedActionCategory.USER,
+          actions: UserActions.filter(action => availableActions.includes(action)),
+        },
+        {
+          actionCategory: SupportedActionCategory.ADMIN,
+          actions: AdminActions.filter(action => availableActions.includes(action)),
+        },
+      ]
+    );
+  }, [availableActions]).filter(item => item.actions.length !== 0);
+
   const actionCheckboxChangedHandler = useCallback((action) => {
     if (onChangeAction != null) {
       onChangeAction(action);
@@ -30,11 +55,11 @@ export const SelectActionDropdown: FC<Props> = (props: Props) => {
   }, [onChangeMultipleAction]);
 
   return (
-    <div className="btn-group mr-2">
+    <div className="btn-group mr-2 admin-audit-log">
       <button className="btn btn-outline-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown">
         <i className="fa fa-fw fa-bolt" />{t('admin:audit_log_management.action')}
       </button>
-      <ul className="dropdown-menu" aria-labelledby="dropdownMenuButton">
+      <ul className="dropdown-menu select-action-dropdown" aria-labelledby="dropdownMenuButton">
         {dropdownItems.map(item => (
           <div key={item.actionCategory}>
             <div className="dropdown-item">
@@ -43,13 +68,13 @@ export const SelectActionDropdown: FC<Props> = (props: Props) => {
                   type="checkbox"
                   className="form-check-input"
                   defaultChecked
-                  onChange={(e) => { multipleActionCheckboxChangedHandler(item.actionNames, e.target.checked) }}
+                  onChange={(e) => { multipleActionCheckboxChangedHandler(item.actions, e.target.checked) }}
                 />
                 <label className="form-check-label">{item.actionCategory}</label>
               </div>
             </div>
             {
-              item.actionNames.map(action => (
+              item.actions.map(action => (
                 <div className="dropdown-item" key={action}>
                   <div className="form-group px-4 m-0">
                     <input

+ 7 - 9
packages/app/src/components/Admin/AuditLogManagement.tsx

@@ -3,11 +3,9 @@ import React, { FC, useState, useCallback } from 'react';
 import { format } from 'date-fns';
 import { useTranslation } from 'react-i18next';
 
-import {
-  SupportedActionType, AllSupportedActions, PageActions, CommentActions,
-} from '~/interfaces/activity';
+import { SupportedActionType } from '~/interfaces/activity';
 import { useSWRxActivity } from '~/stores/activity';
-import { useAuditLogEnabled } from '~/stores/context';
+import { useAuditLogEnabled, useAuditLogAvailableActions } from '~/stores/context';
 
 import PaginationWrapper from '../PaginationWrapper';
 
@@ -31,6 +29,9 @@ const PAGING_LIMIT = 10;
 export const AuditLogManagement: FC = () => {
   const { t } = useTranslation();
 
+  const { data: auditLogAvailableActionsData } = useAuditLogAvailableActions();
+  const auditLogAvailableActions = auditLogAvailableActionsData != null ? auditLogAvailableActionsData : [];
+
   /*
    * State
    */
@@ -41,7 +42,7 @@ export const AuditLogManagement: FC = () => {
   const [endDate, setEndDate] = useState<Date | null>(null);
   const [selectedUsernames, setSelectedUsernames] = useState<string[]>([]);
   const [actionMap, setActionMap] = useState(
-    new Map<SupportedActionType, boolean>(AllSupportedActions.map(action => [action, true])),
+    new Map<SupportedActionType, boolean>(auditLogAvailableActions.map(action => [action, true])),
   );
 
   /*
@@ -132,11 +133,8 @@ export const AuditLogManagement: FC = () => {
             />
 
             <SelectActionDropdown
-              dropdownItems={[
-                { actionCategory: 'Page', actionNames: PageActions },
-                { actionCategory: 'Comment', actionNames: CommentActions },
-              ]}
               actionMap={actionMap}
+              availableActions={auditLogAvailableActions}
               onChangeAction={actionCheckboxChangedHandler}
               onChangeMultipleAction={multipleActionCheckboxChangedHandler}
             />

+ 32 - 31
packages/app/src/interfaces/activity.ts

@@ -8,10 +8,10 @@ const MODEL_COMMENT = 'Comment';
 
 // Action
 const ACTION_UNSETTLED = 'UNSETTLED';
-const ACTION_REGISTRATION_SUCCESS = 'REGISTRATION_SUCCESS';
-const ACTION_LOGIN_SUCCESS = 'LOGIN_SUCCESS';
-const ACTION_LOGIN_FAILURE = 'LOGIN_FAILURE';
-const ACTION_LOGOUT = 'LOGOUT';
+const ACTION_USER_REGISTRATION_SUCCESS = 'USER_REGISTRATION_SUCCESS';
+const ACTION_USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS';
+const ACTION_USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE';
+const ACTION_USER_LOGOUT = 'USER_LOGOUT';
 const ACTION_USER_PERSONAL_SETTINGS_UPDATE = 'USER_PERSONAL_SETTINGS_UPDATE';
 const ACTION_USER_IMAGE_TYPE_UPDATE = 'USER_IMAGE_TYPE_UPDATE';
 const ACTION_USER_LDAP_ACCOUNT_ASSOCIATE = 'USER_LDAP_ACCOUNT_ASSOCIATE';
@@ -78,7 +78,7 @@ const ACTION_ADMIN_ARCHIVE_DATA_UPLOAD = 'ADMIN_ARCHIVE_DATA_UPLOAD';
 const ACTION_ADMIN_ARCHIVE_DATA_CREATE = 'ADMIN_ARCHIVE_DATA_CREATE';
 const ACTION_ADMIN_USER_NOTIFICATION_SETTINGS_ADD = 'ADMIN_USER_NOTIFICATION_SETTINGS_ADD';
 const ACTION_ADMIN_SLACK_WORKSPACE_CREATE = 'ADMIN_SLACK_WORKSPACE_CREATE';
-const ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE = 'ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE';
+const ACTION_ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE = 'ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE';
 const ACTION_ADMIN_USERS_INVITE = 'ADMIN_USERS_INVITE';
 const ACTION_ADMIN_USER_GROUP_CREATE = 'ADMIN_USER_GROUP_CREATE';
 const ACTION_ADMIN_USER_GROUP_UPDATE = 'ADMIN_USER_GROUP_UPDATE';
@@ -96,12 +96,19 @@ export const SupportedEventModel = {
   MODEL_COMMENT,
 } as const;
 
+export const SupportedActionCategory = {
+  PAGE: 'Page',
+  COMMENT: 'Comment',
+  USER: 'User',
+  ADMIN: 'Admin',
+} as const;
+
 export const SupportedAction = {
   ACTION_UNSETTLED,
-  ACTION_REGISTRATION_SUCCESS,
-  ACTION_LOGIN_SUCCESS,
-  ACTION_LOGIN_FAILURE,
-  ACTION_LOGOUT,
+  ACTION_USER_REGISTRATION_SUCCESS,
+  ACTION_USER_LOGIN_SUCCESS,
+  ACTION_USER_LOGIN_FAILURE,
+  ACTION_USER_LOGOUT,
   ACTION_USER_PERSONAL_SETTINGS_UPDATE,
   ACTION_USER_IMAGE_TYPE_UPDATE,
   ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
@@ -198,9 +205,9 @@ export const ActionGroupSize = {
 } as const;
 
 export const SmallActionGroup = {
-  ACTION_LOGIN_SUCCESS,
-  ACTION_LOGIN_FAILURE,
-  ACTION_LOGOUT,
+  ACTION_USER_LOGIN_SUCCESS,
+  ACTION_USER_LOGIN_FAILURE,
+  ACTION_USER_LOGOUT,
   ACTION_PAGE_CREATE,
   ACTION_PAGE_DELETE,
 } as const;
@@ -208,6 +215,7 @@ export const SmallActionGroup = {
 // SmallActionGroup + Action by all General Users - PAGE_VIEW
 export const MediumActionGroup = {
   ...SmallActionGroup,
+  ACTION_USER_REGISTRATION_SUCCESS,
   ACTION_USER_PERSONAL_SETTINGS_UPDATE,
   ACTION_USER_IMAGE_TYPE_UPDATE,
   ACTION_USER_LDAP_ACCOUNT_ASSOCIATE,
@@ -288,25 +296,6 @@ export const LargeActionGroup = {
   ACTION_ADMIN_SEARCH_INDICES_REBUILD,
 } as const;
 
-/*
- * For AuditLogManagement.tsx
- */
-export const PageActions = Object.values({
-  ACTION_PAGE_LIKE,
-  ACTION_PAGE_BOOKMARK,
-  ACTION_PAGE_CREATE,
-  ACTION_PAGE_UPDATE,
-  ACTION_PAGE_RENAME,
-  ACTION_PAGE_DUPLICATE,
-  ACTION_PAGE_DELETE,
-  ACTION_PAGE_DELETE_COMPLETELY,
-  ACTION_PAGE_REVERT,
-} as const);
-
-export const CommentActions = Object.values({
-  ACTION_COMMENT_CREATE,
-  ACTION_COMMENT_UPDATE,
-} as const);
 
 /*
  * Array
@@ -319,12 +308,24 @@ export const AllSmallGroupActions = Object.values(SmallActionGroup);
 export const AllMediumGroupActions = Object.values(MediumActionGroup);
 export const AllLargeGroupActions = Object.values(LargeActionGroup);
 
+// Action categories(for SelectActionDropdown.tsx)
+const pageRegExp = new RegExp(`^${SupportedActionCategory.PAGE.toUpperCase()}_`);
+const commentRegExp = new RegExp(`^${SupportedActionCategory.COMMENT.toUpperCase()}_`);
+const userRegExp = new RegExp(`^${SupportedActionCategory.USER.toUpperCase()}_`);
+const adminRegExp = new RegExp(`^${SupportedActionCategory.ADMIN.toUpperCase()}_`);
+
+export const PageActions = AllSupportedActions.filter(action => action.match(pageRegExp));
+export const CommentActions = AllSupportedActions.filter(action => action.match(commentRegExp));
+export const UserActions = AllSupportedActions.filter(action => action.match(userRegExp));
+export const AdminActions = AllSupportedActions.filter(action => action.match(adminRegExp));
+
 /*
  * Type
  */
 export type SupportedTargetModelType = typeof SupportedTargetModel[keyof typeof SupportedTargetModel];
 export type SupportedEventModelType = typeof SupportedEventModel[keyof typeof SupportedEventModel];
 export type SupportedActionType = typeof SupportedAction[keyof typeof SupportedAction];
+export type SupportedActionCategoryType = typeof SupportedActionCategory[keyof typeof SupportedActionCategory]
 
 export type ISnapshot = Partial<Pick<IUser, 'username'>>
 

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

@@ -17,7 +17,7 @@ module.exports = (crowi) => {
     req.session.destroy();
 
     const activityId = res.locals.activity._id;
-    const parameters = { action: SupportedAction.ACTION_LOGOUT };
+    const parameters = { action: SupportedAction.ACTION_USER_LOGOUT };
     activityEvent.emit('update', activityId, parameters);
 
     return res.send();

+ 1 - 1
packages/app/src/server/routes/installer.js

@@ -59,7 +59,7 @@ module.exports = function(crowi) {
 
       req.flash('successMessage', req.t('message.complete_to_install2'));
 
-      const parameters = { action: SupportedAction.ACTION_REGISTRATION_SUCCESS };
+      const parameters = { action: SupportedAction.ACTION_USER_REGISTRATION_SUCCESS };
       activityEvent.emit('update', res.locals.activity._id, parameters);
 
       return res.redirect('/');

+ 2 - 2
packages/app/src/server/routes/login-passport.js

@@ -33,7 +33,7 @@ module.exports = function(crowi, app) {
     // remove session.redirectTo
     delete req.session.redirectTo;
 
-    const parameters = { action: SupportedAction.ACTION_LOGIN_SUCCESS };
+    const parameters = { action: SupportedAction.ACTION_USER_LOGIN_SUCCESS };
     activityEvent.emit('update', res.locals.activity._id, parameters);
 
     return res.safeRedirect(redirectTo);
@@ -47,7 +47,7 @@ module.exports = function(crowi, app) {
   const loginFailureHandler = async(req, res, message) => {
     req.flash('errorMessage', message || req.t('message.sign_in_failure'));
 
-    const parameters = { action: SupportedAction.ACTION_LOGIN_FAILURE };
+    const parameters = { action: SupportedAction.ACTION_USER_LOGIN_FAILURE };
     activityEvent.emit('update', res.locals.activity._id, parameters);
 
     return res.redirect('/login');

+ 1 - 1
packages/app/src/server/routes/login.js

@@ -40,7 +40,7 @@ module.exports = function(crowi, app) {
       // remove session.redirectTo
       delete req.session.redirectTo;
 
-      const parameters = { action: SupportedAction.ACTION_REGISTRATION_SUCCESS };
+      const parameters = { action: SupportedAction.ACTION_USER_REGISTRATION_SUCCESS };
       activityEvent.emit('update', res.locals.activity._id, parameters);
 
       return res.safeRedirect(redirectTo);

+ 7 - 0
packages/app/src/styles/_admin.scss

@@ -228,6 +228,13 @@ $slack-work-space-name-card-border: #efc1f6;
   //   }
   // }
 
+  .admin-audit-log {
+    .select-action-dropdown {
+      max-height: 500px;
+      overflow-y: auto;
+    }
+  }
+
   #layoutOptions {
     .customize-layout-card {
       border: 4px solid $border-color;