ActivityTable.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import type { FC } from 'react';
  2. import React, { useCallback, useState } from 'react';
  3. import { isPopulated } from '@growi/core';
  4. import { pagePathUtils } from '@growi/core/dist/utils';
  5. import { UserPicture } from '@growi/ui/dist/components';
  6. import { format } from 'date-fns/format';
  7. import { CopyToClipboard } from 'react-copy-to-clipboard';
  8. import { useTranslation } from 'react-i18next';
  9. import { Tooltip } from 'reactstrap';
  10. import type { IActivityHasId } from '~/interfaces/activity';
  11. type Props = {
  12. activityList: IActivityHasId[];
  13. };
  14. const formatDate = (date: Date): string => {
  15. return format(new Date(date), 'yyyy/MM/dd HH:mm:ss');
  16. };
  17. export const ActivityTable: FC<Props> = (props: Props) => {
  18. const { t } = useTranslation();
  19. const [activeTooltipId, setActiveTooltipId] = useState<string | null>(null);
  20. const showToolTip = useCallback((id: string) => {
  21. setActiveTooltipId(id);
  22. setTimeout(() => {
  23. setActiveTooltipId(null);
  24. }, 1000);
  25. }, []);
  26. return (
  27. <div className="table-responsive admin-audit-log">
  28. <table className="table table-default table-bordered table-user-list">
  29. <thead>
  30. <tr>
  31. <th scope="col">{t('admin:audit_log_management.user')}</th>
  32. <th scope="col">{t('admin:audit_log_management.date')}</th>
  33. <th scope="col">{t('admin:audit_log_management.action')}</th>
  34. <th scope="col">{t('admin:audit_log_management.ip')}</th>
  35. <th scope="col">{t('admin:audit_log_management.url')}</th>
  36. </tr>
  37. </thead>
  38. <tbody>
  39. {props.activityList.map((activity) => {
  40. return (
  41. <tr data-testid="activity-table" key={activity._id}>
  42. <td>
  43. {activity.user != null && (
  44. <>
  45. <UserPicture user={activity.user} />
  46. <a
  47. className="ms-2"
  48. href={
  49. isPopulated(activity.user)
  50. ? pagePathUtils.userHomepagePath(activity.user)
  51. : undefined
  52. }
  53. >
  54. {activity.snapshot?.username}
  55. </a>
  56. </>
  57. )}
  58. </td>
  59. <td>{formatDate(activity.createdAt)}</td>
  60. <td>{t(`admin:audit_log_action.${activity.action}`)}</td>
  61. <td>{activity.ip}</td>
  62. <td className="audit-log-url-cell">
  63. <div className="d-flex align-items-center">
  64. <span className="flex-grow-1 text-truncate">
  65. {activity.endpoint}
  66. </span>
  67. <CopyToClipboard
  68. text={activity.endpoint}
  69. onCopy={() => showToolTip(activity._id)}
  70. >
  71. <button
  72. type="button"
  73. className="btn btn-outline-secondary border-0 ms-2"
  74. id={`tooltipTarget-${activity._id}`}
  75. >
  76. <span
  77. className="material-symbols-outlined"
  78. aria-hidden="true"
  79. >
  80. content_paste
  81. </span>
  82. </button>
  83. </CopyToClipboard>
  84. <Tooltip
  85. placement="top"
  86. isOpen={activeTooltipId === activity._id}
  87. fade={false}
  88. target={`tooltipTarget-${activity._id}`}
  89. >
  90. copied!
  91. </Tooltip>
  92. </div>
  93. </td>
  94. </tr>
  95. );
  96. })}
  97. </tbody>
  98. </table>
  99. </div>
  100. );
  101. };