Minor fixes

This commit is contained in:
Tom Butcher 2025-07-07 00:35:10 +01:00
parent 3c2d3ec858
commit 157d115c82
2 changed files with 12 additions and 280 deletions

View File

@ -1,255 +1,16 @@
import React, { useRef } from 'react' import React, { useRef } from 'react'
import { import { Button, Flex, Space, Dropdown } from 'antd'
Button,
Flex,
Space,
Typography,
Popover,
Checkbox,
Dropdown,
Descriptions,
Input,
Badge
} from 'antd'
import IdDisplay from '../common/IdDisplay'
import ReloadIcon from '../../Icons/ReloadIcon' import ReloadIcon from '../../Icons/ReloadIcon'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import TimeDisplay from '../common/TimeDisplay'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ColumnViewButton from '../common/ColumnViewButton'
import AuditLogIcon from '../../Icons/AuditLogIcon'
import XMarkIcon from '../../Icons/XMarkIcon'
import CheckIcon from '../../Icons/CheckIcon'
import BoolDisplay from '../common/BoolDisplay'
import StateTag from '../common/StateTag'
const { Text } = Typography
const formatPropertyName = (name) => {
return name
.replace(/([A-Z])/g, ' $1')
.replace(/^./, (str) => str.toUpperCase())
}
const isObjectId = (value) => {
return typeof value === 'string' && /^[0-9a-fA-F]{24}$/.test(value)
}
const formatValue = (value, propertyName) => {
if (value === null || value === undefined || value === '') {
return <Text type='secondary'>n/a</Text>
}
// Handle colors specifically
if (propertyName === 'color' && value) {
return <Badge color={value} text={value} />
}
if (propertyName === 'state' && typeof value === 'object' && value.type) {
return <StateTag state={value.type} />
}
// Check if the value is a timestamp (ISO date string)
if (
typeof value === 'string' &&
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)
) {
return <TimeDisplay dateTime={value} />
}
if (typeof value === 'boolean') {
return <BoolDisplay value={value} yesNo={true} />
}
if (isObjectId(value)) {
return (
<IdDisplay
id={value}
type={propertyName.toLowerCase().replaceAll('current', '')}
longId={false}
showHyperlink={true}
/>
)
}
if (typeof value === 'object') {
return <Text>{JSON.stringify(value)}</Text>
}
return <Text>{value}</Text>
}
const AuditLogs = () => { const AuditLogs = () => {
const tableRef = useRef() const tableRef = useRef()
// Column definitions const [columnVisibility, updateColumnVisibility] =
const columns = [ useColumnVisibility('auditLogs')
{
title: '',
dataIndex: '',
key: '',
width: 40,
fixed: 'left',
render: () => <AuditLogIcon />
},
{
title: 'ID',
dataIndex: '_id',
key: 'id',
fixed: 'left',
width: 180,
render: (text) => (
<IdDisplay id={text} type={'auditlog'} longId={false} />
),
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters
}) =>
getFilterDropdown({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
propertyName: 'ID'
}),
onFilter: (value, record) =>
record._id.toLowerCase().includes(value.toLowerCase()),
sorter: true
},
{
title: 'Owner Name',
dataIndex: ['owner', 'name'],
key: 'name',
width: 200,
fixed: 'left',
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters
}) =>
getFilterDropdown({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
propertyName: 'name'
}),
onFilter: (value, record) =>
record.owner?.name?.toLowerCase().includes(value.toLowerCase()),
sorter: true
},
{
title: 'Owner',
key: 'owner',
width: 180,
render: (record) => (
<IdDisplay
id={record.owner._id}
type={record.ownerModel.toLowerCase()}
longId={false}
showHyperlink={true}
/>
)
},
{
title: 'Target',
key: 'target',
width: 180,
render: (record) => (
<IdDisplay
id={record.target}
type={record.targetModel.toLowerCase()}
longId={false}
showHyperlink={true}
/>
)
},
{
title: 'Properties',
dataIndex: 'type',
key: 'type',
width: 550,
render: (_, record) => {
const oldValue = record.oldValue || {}
const newValue = record.newValue || {}
return (
<Descriptions size='small' column={1}>
{Object.keys(newValue).map((key) => (
<Descriptions.Item key={key} label={formatPropertyName(key)}>
<Space>
{formatValue(oldValue[key], key)}
<Text type='secondary'></Text>
{formatValue(newValue[key], key)}
</Space>
</Descriptions.Item>
))}
</Descriptions>
)
}
},
{
title: 'Timestamp',
dataIndex: 'createdAt',
key: 'createdAt',
width: 180,
fixed: 'right',
render: (createdAt) => {
if (createdAt) {
return <TimeDisplay dateTime={createdAt} />
} else {
return 'n/a'
}
},
sorter: true,
defaultSortOrder: 'descend'
}
]
const getFilterDropdown = ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
propertyName
}) => {
return (
<div style={{ padding: 8 }}>
<Space.Compact>
<Input
placeholder={'Search ' + propertyName}
value={selectedKeys[0]}
onChange={(e) =>
setSelectedKeys(e.target.value ? [e.target.value] : [])
}
onPressEnter={() => confirm()}
style={{ width: 200, display: 'block' }}
/>
<Button
onClick={() => {
clearFilters()
confirm()
}}
icon={<XMarkIcon />}
/>
<Button
type='primary'
onClick={() => confirm()}
icon={<CheckIcon />}
/>
</Space.Compact>
</div>
)
}
const [columnVisibility, updateColumnVisibility] = useColumnVisibility(
'AuditLogs',
columns
)
const actionItems = { const actionItems = {
items: [ items: [
@ -266,30 +27,6 @@ const AuditLogs = () => {
} }
} }
const getViewDropdownItems = () => {
const columnItems = columns
.filter((col) => col.key && col.title !== '')
.map((col) => (
<Checkbox
checked={columnVisibility[col.key]}
key={col.key}
onChange={(e) => {
updateColumnVisibility(col.key, e.target.checked)
}}
>
{col.title}
</Checkbox>
))
return (
<Flex vertical>
<Flex vertical gap='middle' style={{ margin: '4px 8px' }}>
{columnItems}
</Flex>
</Flex>
)
}
return ( return (
<> <>
<Flex vertical={'true'} gap='large'> <Flex vertical={'true'} gap='large'>
@ -298,13 +35,12 @@ const AuditLogs = () => {
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
</Dropdown> </Dropdown>
<Popover <ColumnViewButton
content={getViewDropdownItems()} type='auditLog'
placement='bottomLeft' loading={false}
arrow={false} visibleState={columnVisibility}
> updateVisibleState={updateColumnVisibility}
<Button>View</Button> />
</Popover>
</Space> </Space>
</Flex> </Flex>

View File

@ -1,9 +1,8 @@
// src/filaments.js // src/filaments.js
import React, { useContext, useRef, useState } from 'react' import React, { useRef, useState } from 'react'
import { Button, Flex, Space, Modal, message, Dropdown } from 'antd' import { Button, Flex, Space, Modal, message, Dropdown } from 'antd'
import { AuthContext } from '../context/AuthContext'
import NewFilament from './Filaments/NewFilament' import NewFilament from './Filaments/NewFilament'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
@ -26,8 +25,6 @@ const Filaments = () => {
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filament') useColumnVisibility('filament')
const { authenticated } = useContext(AuthContext)
const actionItems = { const actionItems = {
items: [ items: [
{ {
@ -79,8 +76,7 @@ const Filaments = () => {
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'filament'} type='filament'
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
/> />