Browse Source

Merge branch 'master' of https://github.com/weseek/growi into support/apply-nextjs-2

Shun Miyazawa 3 years ago
parent
commit
991d345a5c

+ 22 - 2
packages/app/src/components/Admin/AuditLog/ActivityTable.tsx

@@ -1,9 +1,11 @@
-import React, { FC } from 'react';
+import React, { FC, useState, useCallback } from 'react';
 
 import { pagePathUtils } from '@growi/core';
 import { UserPicture } from '@growi/ui';
 import { format } from 'date-fns';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
 import { useTranslation } from 'react-i18next';
+import { Tooltip } from 'reactstrap';
 
 import { IActivityHasId } from '~/interfaces/activity';
 
@@ -17,6 +19,14 @@ const formatDate = (date) => {
 
 export const ActivityTable : FC<Props> = (props: Props) => {
   const { t } = useTranslation();
+  const [tooltopOpen, setTooltipOpen] = useState(false);
+
+  const showToolTip = useCallback(() => {
+    setTooltipOpen(true);
+    setTimeout(() => {
+      setTooltipOpen(false);
+    }, 1000);
+  }, [setTooltipOpen]);
 
   return (
     <div className="table-responsive text-nowrap h-100">
@@ -45,7 +55,17 @@ export const ActivityTable : FC<Props> = (props: Props) => {
                 <td>{formatDate(activity.createdAt)}</td>
                 <td>{t(`admin:audit_log_action.${activity.action}`)}</td>
                 <td>{activity.ip}</td>
-                <td>{activity.endpoint}</td>
+                <td>
+                  {activity.endpoint}
+                  <CopyToClipboard text={activity.endpoint} onCopy={showToolTip}>
+                    <button type="button" className="btn btn-outline-secondary border-0 pull-right" id="tooltipTarget">
+                      <i className="fa fa-clipboard" aria-hidden="true"></i>
+                    </button>
+                  </CopyToClipboard>
+                  <Tooltip placement="top" isOpen={tooltopOpen} fade={false} target="tooltipTarget">
+                    copied!
+                  </Tooltip>
+                </td>
               </tr>
             );
           })}

+ 61 - 19
packages/app/src/components/Admin/AuditLogManagement.tsx

@@ -40,8 +40,9 @@ export const AuditLogManagement: FC = () => {
    * State
    */
   const [isSettingPage, setIsSettingPage] = useState<boolean>(false);
-  const [activePage, setActivePage] = useState<number>(1);
-  const offset = (activePage - 1) * PAGING_LIMIT;
+  const [activePageNumber, setActivePageNumber] = useState<number>(1);
+  const [jumpPageNumber, setJumpPageNumber] = useState<number>(1);
+  const offset = (activePageNumber - 1) * PAGING_LIMIT;
   const [startDate, setStartDate] = useState<Date | null>(null);
   const [endDate, setEndDate] = useState<Date | null>(null);
   const [selectedUsernames, setSelectedUsernames] = useState<string[]>([]);
@@ -59,6 +60,7 @@ export const AuditLogManagement: FC = () => {
   const { data: activityData, mutate: mutateActivity, error } = useSWRxActivity(PAGING_LIMIT, offset, searchFilter);
   const activityList = activityData?.docs != null ? activityData.docs : [];
   const totalActivityNum = activityData?.totalDocs != null ? activityData.totalDocs : 0;
+  const totalPagingPages = activityData?.totalPages != null ? activityData.totalPages : 0;
   const isLoading = activityData === undefined && error == null;
 
   if (error != null) {
@@ -71,34 +73,34 @@ export const AuditLogManagement: FC = () => {
    * Functions
    */
   const setActivePageHandler = useCallback((selectedPageNum: number) => {
-    setActivePage(selectedPageNum);
+    setActivePageNumber(selectedPageNum);
   }, []);
 
   const datePickerChangedHandler = useCallback((dateList: Date[] | null[]) => {
-    setActivePage(1);
+    setActivePageNumber(1);
     setStartDate(dateList[0]);
     setEndDate(dateList[1]);
   }, []);
 
   const actionCheckboxChangedHandler = useCallback((action: SupportedActionType) => {
-    setActivePage(1);
+    setActivePageNumber(1);
     actionMap.set(action, !actionMap.get(action));
     setActionMap(new Map(actionMap.entries()));
   }, [actionMap, setActionMap]);
 
   const multipleActionCheckboxChangedHandler = useCallback((actions: SupportedActionType[], isChecked) => {
-    setActivePage(1);
+    setActivePageNumber(1);
     actions.forEach(action => actionMap.set(action, isChecked));
     setActionMap(new Map(actionMap.entries()));
   }, [actionMap, setActionMap]);
 
   const setUsernamesHandler = useCallback((usernames: string[]) => {
-    setActivePage(1);
+    setActivePageNumber(1);
     setSelectedUsernames(usernames);
   }, []);
 
   const clearButtonPushedHandler = useCallback(() => {
-    setActivePage(1);
+    setActivePageNumber(1);
     setStartDate(null);
     setEndDate(null);
     setSelectedUsernames([]);
@@ -107,15 +109,39 @@ export const AuditLogManagement: FC = () => {
     if (auditLogAvailableActionsData != null) {
       setActionMap(new Map<SupportedActionType, boolean>(auditLogAvailableActionsData.map(action => [action, true])));
     }
-  }, [setActivePage, setStartDate, setEndDate, setSelectedUsernames, setActionMap, auditLogAvailableActionsData]);
+  }, [setActivePageNumber, setStartDate, setEndDate, setSelectedUsernames, setActionMap, auditLogAvailableActionsData]);
 
   const reloadButtonPushedHandler = useCallback(() => {
-    setActivePage(1);
+    setActivePageNumber(1);
     mutateActivity();
   }, [mutateActivity]);
 
+  const jumpPageInputChangeHandler = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+    const inputNumber = Number(e.target.value);
+    const isNan = Number.isNaN(inputNumber);
+
+    if (!isNan) {
+      // eslint-disable-next-line no-nested-ternary
+      const jumpPageNumber = inputNumber > totalPagingPages ? totalPagingPages : inputNumber <= 0 ? activePageNumber : inputNumber;
+      setJumpPageNumber(jumpPageNumber);
+    }
+    else {
+      setJumpPageNumber(activePageNumber);
+    }
+  }, [totalPagingPages, activePageNumber, setJumpPageNumber]);
+
+  const jumpPageInputKeyDownHandler = useCallback((e) => {
+    if (e.key === 'Enter') {
+      setActivePageNumber(jumpPageNumber);
+    }
+  }, [setActivePageNumber, jumpPageNumber]);
+
+  const jumpPageButtonPushedHandler = useCallback(() => {
+    setActivePageNumber(jumpPageNumber);
+  }, [jumpPageNumber]);
+
   // eslint-disable-next-line max-len
-  const activityCounter = `<b>${activityList.length === 0 ? 0 : offset + 1}</b> - <b>${(PAGING_LIMIT * activePage) - (PAGING_LIMIT - activityList.length)}</b> of <b>${totalActivityNum}<b/>`;
+  const activityCounter = `<b>${activityList.length === 0 ? 0 : offset + 1}</b> - <b>${(PAGING_LIMIT * activePageNumber) - (PAGING_LIMIT - activityList.length)}</b> of <b>${totalActivityNum}<b/>`;
 
   if (!auditLogEnabled) {
     return <AuditLogDisableMode />;
@@ -187,14 +213,30 @@ export const AuditLogManagement: FC = () => {
             )
           }
 
-          <PaginationWrapper
-            activePage={activePage}
-            changePage={setActivePageHandler}
-            totalItemsCount={totalActivityNum}
-            pagingLimit={PAGING_LIMIT}
-            align="center"
-            size="sm"
-          />
+          <div className="d-flex flex-row justify-content-center">
+            <PaginationWrapper
+              activePage={activePageNumber}
+              changePage={setActivePageHandler}
+              totalItemsCount={totalActivityNum}
+              pagingLimit={PAGING_LIMIT}
+              align="center"
+              size="sm"
+            />
+
+            <div className="admin-audit-log ml-3">
+              <label htmlFor="jumpPageInput" className="mr-1 text-secondary">Jump To Page</label>
+              <input
+                id="jumpPageInput"
+                type="text"
+                className="jump-page-input"
+                onChange={jumpPageInputChangeHandler}
+                onKeyDown={jumpPageInputKeyDownHandler}
+              />
+              <button className="btn btn-sm" type="button" onClick={jumpPageButtonPushedHandler}>
+                <b>Go</b>
+              </button>
+            </div>
+          </div>
         </>
       )}
     </div>

+ 3 - 0
packages/app/src/components/Layout/Admin.module.scss

@@ -230,6 +230,9 @@ $slack-work-space-name-card-border: #efc1f6;
     .date-range-picker {
       width: 188px;
     }
+    .jump-page-input {
+      width: 50px;
+    }
   }
 
   #layoutOptions {