LogDetailsPanel.tsx130 lines · main
1import dayjs from 'dayjs'
2import { Input, SidePanel, TextArea } from 'ui'
3import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
4
5import {
6 FormSection,
7 FormSectionContent,
8 FormSectionLabel,
9} from '@/components/ui/Forms/FormSection'
10import {
11 TIMESTAMP_MICROS_PER_MS,
12 type AuditLog,
13} from '@/data/organizations/organization-audit-logs-query'
14
15interface LogDetailsPanelProps {
16 selectedLog?: AuditLog
17 onClose: () => void
18}
19
20export const LogDetailsPanel = ({ selectedLog, onClose }: LogDetailsPanelProps) => {
21 const timestamp = selectedLog
22 ? dayjs(selectedLog.timestamp / TIMESTAMP_MICROS_PER_MS).format('DD MMM YYYY, HH:mm:ss')
23 : ''
24 const timestampWithTz = selectedLog
25 ? dayjs(selectedLog.timestamp / TIMESTAMP_MICROS_PER_MS).format('DD MMM YYYY, HH:mm:ss (ZZ)')
26 : ''
27
28 return (
29 <SidePanel
30 size="large"
31 header={selectedLog ? `"${selectedLog.action.name}" on ${timestamp}` : ''}
32 visible={selectedLog !== undefined}
33 onCancel={onClose}
34 cancelText="Close"
35 >
36 <FormSection header={<FormSectionLabel>General</FormSectionLabel>}>
37 <FormSectionContent loading={false}>
38 <FormItemLayout label="Occurred at" description={timestampWithTz} isReactForm={false}>
39 <Input
40 readOnly
41 size="small"
42 value={
43 selectedLog
44 ? dayjs(selectedLog.timestamp / TIMESTAMP_MICROS_PER_MS).toISOString()
45 : ''
46 }
47 />
48 </FormItemLayout>
49 <FormItemLayout label="Request ID" isReactForm={false}>
50 <Input readOnly size="small" value={selectedLog?.request_id ?? ''} />
51 </FormItemLayout>
52 {selectedLog?.organization_slug && (
53 <FormItemLayout label="Organization" isReactForm={false}>
54 <Input readOnly size="small" value={selectedLog.organization_slug} />
55 </FormItemLayout>
56 )}
57 {selectedLog?.project_ref && (
58 <FormItemLayout label="Project ref" isReactForm={false}>
59 <Input readOnly size="small" value={selectedLog.project_ref} />
60 </FormItemLayout>
61 )}
62 </FormSectionContent>
63 </FormSection>
64
65 <SidePanel.Separator />
66
67 <FormSection header={<FormSectionLabel>Actor</FormSectionLabel>}>
68 <FormSectionContent loading={false}>
69 <FormItemLayout label="Token type" isReactForm={false}>
70 <Input readOnly size="small" value={selectedLog?.actor.token_type ?? ''} />
71 </FormItemLayout>
72 {selectedLog?.actor.email && (
73 <FormItemLayout label="Email" isReactForm={false}>
74 <Input readOnly size="small" value={selectedLog?.actor.email ?? ''} />
75 </FormItemLayout>
76 )}
77 {selectedLog?.actor.user_id && (
78 <FormItemLayout label="User ID" isReactForm={false}>
79 <Input readOnly size="small" value={selectedLog?.actor.user_id ?? ''} />
80 </FormItemLayout>
81 )}
82 {selectedLog?.actor.ip && (
83 <FormItemLayout label="IP address" isReactForm={false}>
84 <Input readOnly size="small" value={selectedLog?.actor.ip ?? ''} />
85 </FormItemLayout>
86 )}
87 {selectedLog?.actor.oauth_app_name && (
88 <FormItemLayout label="OAuth app" isReactForm={false}>
89 <Input readOnly size="small" value={selectedLog?.actor.oauth_app_name ?? ''} />
90 </FormItemLayout>
91 )}
92 {selectedLog?.actor.app_name && (
93 <FormItemLayout label="App" isReactForm={false}>
94 <Input readOnly size="small" value={selectedLog?.actor.app_name ?? ''} />
95 </FormItemLayout>
96 )}
97 </FormSectionContent>
98 </FormSection>
99
100 <SidePanel.Separator />
101
102 <FormSection header={<FormSectionLabel>Action</FormSectionLabel>}>
103 <FormSectionContent loading={false}>
104 <FormItemLayout label="Name" isReactForm={false}>
105 <Input readOnly size="small" value={selectedLog?.action.name ?? ''} />
106 </FormItemLayout>
107 <FormItemLayout label="Method" isReactForm={false}>
108 <Input readOnly size="small" value={selectedLog?.action.method ?? ''} />
109 </FormItemLayout>
110 <FormItemLayout label="Route" isReactForm={false}>
111 <Input readOnly size="small" value={selectedLog?.action.route ?? ''} />
112 </FormItemLayout>
113 <FormItemLayout label="Status" isReactForm={false}>
114 <Input readOnly size="small" value={String(selectedLog?.action.status ?? '')} />
115 </FormItemLayout>
116 {selectedLog?.action.metadata && (
117 <FormItemLayout label="Metadata" isReactForm={false}>
118 <TextArea
119 readOnly
120 rows={5}
121 className="font-mono input-xs"
122 value={JSON.stringify(selectedLog.action.metadata, null, 2)}
123 />
124 </FormItemLayout>
125 )}
126 </FormSectionContent>
127 </FormSection>
128 </SidePanel>
129 )
130}