diff --git a/studio/components/interfaces/Account/AuditLogs.tsx b/studio/components/interfaces/Account/AuditLogs.tsx index 1e054d24c86..2fba78c31de 100644 --- a/studio/components/interfaces/Account/AuditLogs.tsx +++ b/studio/components/interfaces/Account/AuditLogs.tsx @@ -1,8 +1,9 @@ import * as Tooltip from '@radix-ui/react-tooltip' import dayjs from 'dayjs' import { useEffect, useState } from 'react' +import { Alert, Button, IconArrowDown, IconArrowUp, IconRefreshCw } from 'ui' -import { ScaffoldContainerLegacy } from 'components/layouts/Scaffold' +import { FilterPopover, LogDetailsPanel } from 'components/interfaces/AuditLogs' import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' import { DatePicker } from 'components/ui/DatePicker' @@ -11,9 +12,6 @@ import { AuditLog } from 'data/organizations/organization-audit-logs-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProfileAuditLogsQuery } from 'data/profile/profile-audit-logs-query' import { useProjectsQuery } from 'data/projects/projects-query' -import { Alert, Button, IconArrowDown, IconArrowUp, IconRefreshCw } from 'ui' -import FilterPopover from '../Organization/AuditLogs/FilterPopover' -import LogDetailsPanel from '../Organization/AuditLogs/LogDetailsPanel' const AuditLogs = () => { const currentTime = dayjs().utc().set('millisecond', 0) @@ -71,219 +69,215 @@ const AuditLogs = () => { return ( <> - -
-
-
-

Filter by

- setFilters({ ...filters, projects: values })} - /> - { - if (value.from !== null && value.to !== null) { - const current = dayjs().utc() - const from = dayjs(value.from) - .utc() - .hour(current.hour()) - .minute(current.minute()) - .second(current.second()) - .toISOString() - const to = dayjs(value.to) - .utc() - .hour(current.hour()) - .minute(current.minute()) - .second(current.second()) - .toISOString() - setDateRange({ from, to }) - } - }} - renderFooter={() => { - return ( - - You have a log retention period of{' '} - - {retentionPeriod} day - {retentionPeriod > 1 ? 's' : ''} - - . You may only view logs from{' '} - {dayjs().subtract(retentionPeriod, 'days').format('DD MMM YYYY')} as the - earliest date. - - ) - }} - /> - {isSuccess && ( - <> -
-

Viewing {sortedLogs.length} logs in total

- - )} -
- +
+
+
+

Filter by

+ setFilters({ ...filters, projects: values })} + /> + { + if (value.from !== null && value.to !== null) { + const current = dayjs().utc() + const from = dayjs(value.from) + .utc() + .hour(current.hour()) + .minute(current.minute()) + .second(current.second()) + .toISOString() + const to = dayjs(value.to) + .utc() + .hour(current.hour()) + .minute(current.minute()) + .second(current.second()) + .toISOString() + setDateRange({ from, to }) + } + }} + renderFooter={() => { + return ( + + You have a log retention period of{' '} + + {retentionPeriod} day + {retentionPeriod > 1 ? 's' : ''} + + . You may only view logs from{' '} + {dayjs().subtract(retentionPeriod, 'days').format('DD MMM YYYY')} as the + earliest date. + + ) + }} + /> + {isSuccess && ( + <> +
+

Viewing {sortedLogs.length} logs in total

+ + )}
- - {isLoading && ( -
- - - -
- )} - - {isError && } - - {isSuccess && ( - <> - {logs.length === 0 ? ( -
-

You do not have any audit logs available yet

-
- ) : logs.length > 0 && sortedLogs.length === 0 ? ( -
-

No audit logs found based on the filters applied

-
- ) : ( - - Action - , - - Target - , - -
-

Date

- - - -
-
, - , - ]} - body={ - sortedLogs?.map((log) => { - const project = projects?.find( - (project) => project.ref === log.target.metadata.project_ref - ) - const organization = organizations?.find( - (org) => org.slug === log.target.metadata.org_slug - ) - - const hasStatusCode = log.action.metadata[0]?.status !== undefined - - return ( - setSelectedLog(log)} - className="cursor-pointer hover:!bg-scale-100 transition duration-100" - > - -
- {hasStatusCode && ( -

- {log.action.metadata[0].status} -

- )} -

- {log.action.name} -

-
-
- -

- {project?.name - ? 'Project: ' - : organization?.name - ? 'Organization: ' - : null} - {project?.name ?? organization?.name ?? 'Unknown'} -

-

- {log.target.metadata.project_ref - ? 'Ref: ' - : log.target.metadata.org_slug - ? 'Slug: ' - : null} - {log.target.metadata.project_ref ?? log.target.metadata.org_slug} -

-
- - {dayjs(log.occurred_at).format('DD MMM YYYY, HH:mm:ss')} - - - - -
- ) - }) ?? [] - } - /> - )} - - )} + - + + {isLoading && ( +
+ + + +
+ )} + + {isError && } + + {isSuccess && ( + <> + {logs.length === 0 ? ( +
+

You do not have any audit logs available yet

+
+ ) : logs.length > 0 && sortedLogs.length === 0 ? ( +
+

No audit logs found based on the filters applied

+
+ ) : ( +
+ Action + , + + Target + , + +
+

Date

+ + + +
+
, + , + ]} + body={ + sortedLogs?.map((log) => { + const project = projects?.find( + (project) => project.ref === log.target.metadata.project_ref + ) + const organization = organizations?.find( + (org) => org.slug === log.target.metadata.org_slug + ) + + const hasStatusCode = log.action.metadata[0]?.status !== undefined + + return ( + setSelectedLog(log)} + className="cursor-pointer hover:!bg-scale-100 transition duration-100" + > + +
+ {hasStatusCode && ( +

+ {log.action.metadata[0].status} +

+ )} +

+ {log.action.name} +

+
+
+ +

+ {project?.name + ? 'Project: ' + : organization?.name + ? 'Organization: ' + : null} + {project?.name ?? organization?.name ?? 'Unknown'} +

+

+ {log.target.metadata.project_ref + ? 'Ref: ' + : log.target.metadata.org_slug + ? 'Slug: ' + : null} + {log.target.metadata.project_ref ?? log.target.metadata.org_slug} +

+
+ + {dayjs(log.occurred_at).format('DD MMM YYYY, HH:mm:ss')} + + + + +
+ ) + }) ?? [] + } + /> + )} + + )} + setSelectedLog(undefined)} /> diff --git a/studio/components/interfaces/Organization/AuditLogs/FilterPopover.tsx b/studio/components/interfaces/AuditLogs/FilterPopover.tsx similarity index 100% rename from studio/components/interfaces/Organization/AuditLogs/FilterPopover.tsx rename to studio/components/interfaces/AuditLogs/FilterPopover.tsx diff --git a/studio/components/interfaces/Organization/AuditLogs/LogDetailsPanel.tsx b/studio/components/interfaces/AuditLogs/LogDetailsPanel.tsx similarity index 100% rename from studio/components/interfaces/Organization/AuditLogs/LogDetailsPanel.tsx rename to studio/components/interfaces/AuditLogs/LogDetailsPanel.tsx diff --git a/studio/components/interfaces/AuditLogs/index.ts b/studio/components/interfaces/AuditLogs/index.ts new file mode 100644 index 00000000000..d54f1b5d120 --- /dev/null +++ b/studio/components/interfaces/AuditLogs/index.ts @@ -0,0 +1,4 @@ +import FilterPopover from './FilterPopover' +import LogDetailsPanel from './LogDetailsPanel' + +export { FilterPopover, LogDetailsPanel } diff --git a/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx b/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx index fc10ea0873d..5d93d958d68 100644 --- a/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx +++ b/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx @@ -2,8 +2,10 @@ import * as Tooltip from '@radix-ui/react-tooltip' import dayjs from 'dayjs' import Image from 'next/image' import { useState } from 'react' +import { Alert, Button, IconArrowDown, IconArrowUp, IconRefreshCw, IconUser } from 'ui' import { useParams } from 'common' +import { FilterPopover, LogDetailsPanel } from 'components/interfaces/AuditLogs' import { ScaffoldContainerLegacy } from 'components/layouts/Scaffold' import Table from 'components/to-be-cleaned/Table' import AlertError from 'components/ui/AlertError' @@ -17,9 +19,6 @@ import { useOrganizationDetailQuery } from 'data/organizations/organization-deta import { useOrganizationRolesQuery } from 'data/organizations/organization-roles-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectsQuery } from 'data/projects/projects-query' -import { Alert, Button, IconArrowDown, IconArrowUp, IconRefreshCw, IconUser } from 'ui' -import FilterPopover from './FilterPopover' -import LogDetailsPanel from './LogDetailsPanel' // [Joshen considerations] // - Maybe fix the height of the table to the remaining height of the viewport, so that the search input is always visible @@ -283,14 +282,14 @@ const AuditLogs = () => { - +
{hasStatusCode && (

{log.action.metadata[0].status}

)} -

+

{log.action.name}

diff --git a/studio/components/ui/DatePicker/DatePicker.tsx b/studio/components/ui/DatePicker/DatePicker.tsx index ec327d36b8f..9d1deb498f1 100644 --- a/studio/components/ui/DatePicker/DatePicker.tsx +++ b/studio/components/ui/DatePicker/DatePicker.tsx @@ -274,7 +274,7 @@ function _DatePicker({ {children !== undefined ? ( children ) : ( - + <> {/* Custom */} {selectsRange && appliedStartDate && @@ -289,7 +289,7 @@ function _DatePicker({ ) : ( 'Custom' )} - + )} diff --git a/studio/pages/account/audit.tsx b/studio/pages/account/audit.tsx index 7dddb8705a3..1e6398b63d4 100644 --- a/studio/pages/account/audit.tsx +++ b/studio/pages/account/audit.tsx @@ -1,12 +1,20 @@ import { AuditLogs } from 'components/interfaces/Account' import { AccountLayout } from 'components/layouts' +import { ScaffoldContainerLegacy } from 'components/layouts/Scaffold' +import { FormHeader } from 'components/ui/Forms' import { NextPageWithLayout } from 'types' const User: NextPageWithLayout = () => { return ( -
+ +
+ +
-
+ ) }