Minor fixes
This commit is contained in:
parent
3c2d3ec858
commit
157d115c82
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user