Skip to content

Commit 7b66b77

Browse files
committed
OKish UI
1 parent 316f2b4 commit 7b66b77

File tree

7 files changed

+271
-44
lines changed

7 files changed

+271
-44
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default function FilterList() {}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import {Stack} from "@mantine/core"
2+
import {IconChevronDown} from "@tabler/icons-react"
3+
import React, {useState} from "react"
4+
import {DropdownConfig} from "../types"
5+
import OperationFilter from "./OperationFilter"
6+
import TableNameFilter from "./TableNameFilter"
7+
import TimestampFilter from "./TimestampFilter"
8+
import UserFilter from "./UserFilter"
9+
10+
interface Args {
11+
filters: DropdownConfig[]
12+
className?: string
13+
}
14+
15+
export default function FiltersCollapse({filters, className}: Args) {
16+
const [expanded, setExpanded] = useState(true)
17+
18+
const toggleExpanded = () => {
19+
setExpanded(!expanded)
20+
}
21+
22+
let filterComponents: React.ReactElement[] = []
23+
24+
if (filters.length == 0) {
25+
return <></>
26+
}
27+
28+
filters.forEach(f => {
29+
if (f.visible) {
30+
switch (f.key) {
31+
case "timestamp":
32+
filterComponents.push(<TimestampFilter key={f.key} />)
33+
break
34+
case "operation":
35+
filterComponents.push(<OperationFilter key={f.key} />)
36+
break
37+
case "table_name":
38+
filterComponents.push(<TableNameFilter key={f.key} />)
39+
break
40+
case "user":
41+
filterComponents.push(<UserFilter key={f.key} />)
42+
break
43+
}
44+
}
45+
})
46+
47+
return (
48+
<div className={`filters-collapse ${className}`} style={styles.container}>
49+
<div style={styles.header} onClick={toggleExpanded}>
50+
<IconChevronDown
51+
size={20}
52+
style={{
53+
...styles.icon,
54+
transform: expanded ? "rotate(0deg)" : "rotate(90deg)"
55+
}}
56+
/>
57+
</div>
58+
59+
{expanded && <Stack>{filterComponents}</Stack>}
60+
</div>
61+
)
62+
}
63+
64+
const styles: {[key: string]: React.CSSProperties} = {
65+
container: {
66+
width: "100%",
67+
border: "1px solid #e0e0e0",
68+
backgroundColor: "#ffffff",
69+
overflow: "hidden"
70+
},
71+
header: {
72+
display: "flex",
73+
alignItems: "center",
74+
justifyContent: "space-between",
75+
padding: "4px 4px",
76+
backgroundColor: "rgba(0, 0, 0, 0.03)",
77+
cursor: "pointer",
78+
borderBottom: "1px solid #e0e0e0",
79+
transition: "background-color 0.2s ease"
80+
},
81+
icon: {
82+
transition: "transform 0.2s ease-in-out",
83+
color: "#666666"
84+
},
85+
content: {
86+
overflow: "hidden",
87+
transition:
88+
"max-height 0.3s ease-in-out, opacity 0.3s ease-in-out, padding 0.3s ease-in-out",
89+
backgroundColor: "#ffffff"
90+
}
91+
}
Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import {Container, Group, Stack} from "@mantine/core"
22
import type {SortState} from "kommon"
3-
import {useCallback} from "react"
3+
import {useCallback, useState} from "react"
44
import type {AuditLogItem, DropdownConfig, SortBy} from "../types"
55
import auditLogColumns from "./auditLogColumns"
66
import FilterSelector from "./DropdownSelector"
77
import useAuditLogTable from "./useAuditLogTable"
88

99
import {ColumnSelector, DataTable, TablePagination, useTableData} from "kommon"
10+
import Filters from "./FiltersCollapse"
1011

11-
let filtersConfig = [
12+
let initialFilters = [
1213
{key: "timestamp", label: "Timestamp", visible: false},
14+
{key: "operation", label: "Operation", visible: false},
15+
{key: "table_name", label: "Table", visible: false},
1316
{key: "user", label: "User", visible: false}
1417
]
1518

1619
export default function AuditLogsList() {
1720
const auditLogTable = useAuditLogTable()
21+
const [filtersList, setFiltersList] = useState<DropdownConfig[]>([])
1822

1923
// Table state management
2024
const {state, actions, visibleColumns} = useTableData<AuditLogItem>({
@@ -39,7 +43,8 @@ export default function AuditLogsList() {
3943
)
4044

4145
const onFilterVisibilityChange = (items: DropdownConfig[]) => {
42-
console.log(items)
46+
const visibleItems = items.filter(i => i.visible)
47+
setFiltersList(visibleItems)
4348
}
4449

4550
if (auditLogTable.isError) {
@@ -54,49 +59,48 @@ export default function AuditLogsList() {
5459
}
5560

5661
return (
57-
<Container size="xl" py="md">
58-
<Stack gap="lg">
59-
<Group justify="end" align="flex-start">
60-
<FilterSelector
61-
onChange={onFilterVisibilityChange}
62-
initialItems={filtersConfig}
63-
/>
64-
65-
<ColumnSelector
66-
columns={state.columns}
67-
onColumnsChange={actions.setColumns}
68-
onToggleColumn={actions.toggleColumnVisibility}
69-
/>
70-
</Group>
71-
72-
<DataTable
73-
data={auditLogTable.data?.items || []}
74-
columns={visibleColumns}
75-
sorting={{
76-
column: auditLogTable.queryParams.sort_by || null,
77-
direction: auditLogTable.queryParams.sort_direction || null
78-
}}
79-
onSortChange={handleSortChange}
80-
columnWidths={state.columnWidths}
81-
onColumnResize={actions.setColumnWidth}
82-
loading={auditLogTable.isLoading || auditLogTable.isFetching}
83-
emptyMessage="No audit logs found"
62+
<Stack gap="xs">
63+
<Filters filters={filtersList} />
64+
<Group justify="end" align="flex-start">
65+
<FilterSelector
66+
onChange={onFilterVisibilityChange}
67+
initialItems={initialFilters}
8468
/>
8569

86-
<TablePagination
87-
currentPage={auditLogTable.queryParams.page_number || 1}
88-
totalPages={auditLogTable.data?.num_pages || 0}
89-
pageSize={auditLogTable.queryParams.page_size || 15}
90-
onPageChange={auditLogTable.setPage}
91-
onPageSizeChange={auditLogTable.setPageSize}
92-
totalItems={
93-
auditLogTable.data
94-
? auditLogTable.data.num_pages * auditLogTable.data.page_size
95-
: 0
96-
}
97-
showPageSizeSelector
70+
<ColumnSelector
71+
columns={state.columns}
72+
onColumnsChange={actions.setColumns}
73+
onToggleColumn={actions.toggleColumnVisibility}
9874
/>
99-
</Stack>
100-
</Container>
75+
</Group>
76+
77+
<DataTable
78+
data={auditLogTable.data?.items || []}
79+
columns={visibleColumns}
80+
sorting={{
81+
column: auditLogTable.queryParams.sort_by || null,
82+
direction: auditLogTable.queryParams.sort_direction || null
83+
}}
84+
onSortChange={handleSortChange}
85+
columnWidths={state.columnWidths}
86+
onColumnResize={actions.setColumnWidth}
87+
loading={auditLogTable.isLoading || auditLogTable.isFetching}
88+
emptyMessage="No audit logs found"
89+
/>
90+
91+
<TablePagination
92+
currentPage={auditLogTable.queryParams.page_number || 1}
93+
totalPages={auditLogTable.data?.num_pages || 0}
94+
pageSize={auditLogTable.queryParams.page_size || 15}
95+
onPageChange={auditLogTable.setPage}
96+
onPageSizeChange={auditLogTable.setPageSize}
97+
totalItems={
98+
auditLogTable.data
99+
? auditLogTable.data.num_pages * auditLogTable.data.page_size
100+
: 0
101+
}
102+
showPageSizeSelector
103+
/>
104+
</Stack>
101105
)
102106
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {MultiSelect, Paper} from "@mantine/core"
2+
3+
export default function OperationFilter() {
4+
return (
5+
<Paper p="xs">
6+
<MultiSelect
7+
label="Operation"
8+
placeholder="Pick value"
9+
clearable
10+
data={["INSERT", "DELETE", "UPDATE", "TRUNCATE"]}
11+
/>
12+
</Paper>
13+
)
14+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {MultiSelect, Paper} from "@mantine/core"
2+
3+
export default function TableNameFilter() {
4+
return (
5+
<Paper p="xs">
6+
<MultiSelect
7+
searchable
8+
label="Table"
9+
placeholder="Pick value"
10+
clearable
11+
data={[
12+
"users_groups",
13+
"roles_permissions",
14+
"documents",
15+
"document_types_custom_fields",
16+
"nodes",
17+
"users"
18+
]}
19+
/>
20+
</Paper>
21+
)
22+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import {Button, Group, Paper, Stack} from "@mantine/core"
2+
import {DateTimePicker} from "@mantine/dates"
3+
import React, {useState} from "react"
4+
5+
type TimestampMode = "range" | "older" | "newer"
6+
7+
interface TimestampRange {
8+
from?: Date | null
9+
to?: Date | null
10+
}
11+
12+
interface TimestampPickerProps {
13+
value?: {
14+
mode: TimestampMode
15+
range: TimestampRange
16+
}
17+
onChange?: (value: {mode: TimestampMode; range: TimestampRange}) => void
18+
}
19+
20+
const TimestampPicker: React.FC<TimestampPickerProps> = ({value, onChange}) => {
21+
const [range, setRange] = useState<TimestampRange>(
22+
value?.range || {from: null, to: null}
23+
)
24+
25+
const handleQuickSelect = (type: "today" | "1hour" | "3hours") => {
26+
const now = new Date()
27+
let newRange: TimestampRange = {from: null, to: null}
28+
29+
switch (type) {
30+
case "today":
31+
const startOfDay = new Date(now)
32+
startOfDay.setHours(0, 0, 0, 0)
33+
const endOfDay = new Date(now)
34+
endOfDay.setHours(23, 59, 59, 999)
35+
newRange = {from: startOfDay, to: endOfDay}
36+
break
37+
case "1hour":
38+
const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000)
39+
newRange = {from: oneHourAgo, to: now}
40+
break
41+
case "3hours":
42+
const threeHoursAgo = new Date(now.getTime() - 3 * 60 * 60 * 1000)
43+
newRange = {from: threeHoursAgo, to: now}
44+
break
45+
}
46+
47+
setRange(newRange)
48+
onChange?.({mode: "range", range: newRange})
49+
}
50+
51+
return (
52+
<Paper p="xs">
53+
<Stack>
54+
<Group justify={"start"}>
55+
<DateTimePicker
56+
label="From"
57+
value={range.from}
58+
clearable
59+
withSeconds
60+
/>
61+
<DateTimePicker label="To" value={range.to} clearable withSeconds />
62+
</Group>
63+
64+
<Group>
65+
<Button
66+
size="xs"
67+
variant="light"
68+
onClick={() => handleQuickSelect("today")}
69+
>
70+
Today
71+
</Button>
72+
<Button
73+
size="xs"
74+
variant="light"
75+
onClick={() => handleQuickSelect("1hour")}
76+
>
77+
Last 1 Hour
78+
</Button>
79+
<Button
80+
size="xs"
81+
variant="light"
82+
onClick={() => handleQuickSelect("3hours")}
83+
>
84+
Last 3 Hours
85+
</Button>
86+
</Group>
87+
</Stack>
88+
</Paper>
89+
)
90+
}
91+
92+
export default TimestampPicker
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function UserFilter() {
2+
return <></>
3+
}

0 commit comments

Comments
 (0)