Skip to content

Commit 316f2b4

Browse files
committed
Filter component
1 parent cfab5bc commit 316f2b4

File tree

4 files changed

+92
-113
lines changed

4 files changed

+92
-113
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {ActionIcon, Checkbox, Popover, ScrollArea, Stack} from "@mantine/core"
2+
import {IconFilter} from "@tabler/icons-react"
3+
import {useState} from "react"
4+
import type {DropdownConfig} from "../types"
5+
6+
interface FilterSelectorArgs {
7+
initialItems: DropdownConfig[]
8+
onChange: (items: DropdownConfig[]) => void
9+
}
10+
11+
export default function DropdownSelector({
12+
initialItems,
13+
onChange
14+
}: FilterSelectorArgs) {
15+
const [opened, setOpened] = useState(false)
16+
const [items, setItems] = useState<DropdownConfig[]>(initialItems)
17+
18+
const onLocalChange = (key: DropdownConfig["key"], checked: boolean) => {
19+
const newItems = items.map(i =>
20+
i.key === key ? {...i, visible: checked} : i
21+
)
22+
23+
setItems(newItems)
24+
onChange(newItems)
25+
}
26+
27+
return (
28+
<Popover
29+
width={180}
30+
position="bottom-end"
31+
withArrow
32+
shadow="md"
33+
opened={opened}
34+
onChange={setOpened}
35+
>
36+
<Popover.Target>
37+
<ActionIcon variant="light" onClick={() => setOpened(o => !o)}>
38+
<IconFilter size={16} />
39+
</ActionIcon>
40+
</Popover.Target>
41+
42+
<Popover.Dropdown>
43+
<ScrollArea.Autosize mah={300}>
44+
<Stack gap="xs">
45+
{items.map(filter => (
46+
<Checkbox
47+
key={String(filter.key)}
48+
label={filter.label}
49+
checked={filter.visible !== false}
50+
onChange={e =>
51+
onLocalChange(filter.key, e.currentTarget.checked)
52+
}
53+
size="sm"
54+
/>
55+
))}
56+
</Stack>
57+
</ScrollArea.Autosize>
58+
</Popover.Dropdown>
59+
</Popover>
60+
)
61+
}

frontend/apps/ui/src/features/audit/components/List.tsx

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import {Container, Group, Stack} from "@mantine/core"
22
import type {SortState} from "kommon"
3-
import {useCallback, useEffect} from "react"
4-
import type {AuditLogItem, SortBy} from "../types"
3+
import {useCallback} from "react"
4+
import type {AuditLogItem, DropdownConfig, SortBy} from "../types"
55
import auditLogColumns from "./auditLogColumns"
6+
import FilterSelector from "./DropdownSelector"
67
import useAuditLogTable from "./useAuditLogTable"
78

8-
import {
9-
ColumnSelector,
10-
DataTable,
11-
TableFilters,
12-
TablePagination,
13-
useTableData
14-
} from "kommon"
9+
import {ColumnSelector, DataTable, TablePagination, useTableData} from "kommon"
10+
11+
let filtersConfig = [
12+
{key: "timestamp", label: "Timestamp", visible: false},
13+
{key: "user", label: "User", visible: false}
14+
]
1515

1616
export default function AuditLogsList() {
1717
const auditLogTable = useAuditLogTable()
@@ -38,20 +38,9 @@ export default function AuditLogsList() {
3838
[auditLogTable]
3939
)
4040

41-
// Debug logging
42-
useEffect(() => {
43-
console.log("=== AUDIT LOGS DEBUG ===")
44-
console.log("auditLogTable.currentFilters:", auditLogTable.currentFilters)
45-
console.log("state.columns:", state.columns)
46-
console.log(
47-
"filterable columns:",
48-
state.columns.filter(col => col.filterable)
49-
)
50-
console.log(
51-
"visible filterable columns:",
52-
state.columns.filter(col => col.filterable && col.visible !== false)
53-
)
54-
}, [auditLogTable.currentFilters, state.columns])
41+
const onFilterVisibilityChange = (items: DropdownConfig[]) => {
42+
console.log(items)
43+
}
5544

5645
if (auditLogTable.isError) {
5746
return (
@@ -67,14 +56,11 @@ export default function AuditLogsList() {
6756
return (
6857
<Container size="xl" py="md">
6958
<Stack gap="lg">
70-
<Group justify="space-between" align="flex-start">
71-
<div style={{flex: 1}}>
72-
<TableFilters
73-
columns={state.columns}
74-
filters={auditLogTable.currentFilters}
75-
onFiltersChange={auditLogTable.setTableFilters}
76-
/>
77-
</div>
59+
<Group justify="end" align="flex-start">
60+
<FilterSelector
61+
onChange={onFilterVisibilityChange}
62+
initialItems={filtersConfig}
63+
/>
7864

7965
<ColumnSelector
8066
columns={state.columns}

frontend/apps/ui/src/features/audit/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ export type SortBy =
2828
| "record_id"
2929
| "user_id"
3030
| "id"
31+
32+
export interface DropdownConfig {
33+
key: string
34+
label: string
35+
visible?: boolean
36+
}

frontend/packages/kommon/src/components/Table/ColumnSelector.tsx

Lines changed: 8 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
// components/ColumnSelector/ColumnSelector.tsx
2-
import {
3-
Button,
4-
Checkbox,
5-
Divider,
6-
Group,
7-
Popover,
8-
ScrollArea,
9-
Stack,
10-
Text
11-
} from "@mantine/core"
12-
import {IconColumns, IconEye, IconEyeOff} from "@tabler/icons-react"
2+
import {ActionIcon, Checkbox, Popover, ScrollArea, Stack} from "@mantine/core"
3+
import {IconColumns} from "@tabler/icons-react"
134
import {useState} from "react"
145
import {ColumnConfig} from "./types"
156

16-
interface ColumnSelectorProps<T> {
7+
interface ColumnSelectorArgs<T> {
178
columns: ColumnConfig<T>[]
189
onColumnsChange: (columns: ColumnConfig<T>[]) => void
1910
onToggleColumn?: (columnKey: keyof T) => void
@@ -23,12 +14,9 @@ export default function ColumnSelector<T>({
2314
columns,
2415
onColumnsChange,
2516
onToggleColumn
26-
}: ColumnSelectorProps<T>) {
17+
}: ColumnSelectorArgs<T>) {
2718
const [opened, setOpened] = useState(false)
2819

29-
const visibleCount = columns.filter(col => col.visible !== false).length
30-
const totalCount = columns.length
31-
3220
const handleToggle = (columnKey: keyof T) => {
3321
if (onToggleColumn) {
3422
onToggleColumn(columnKey)
@@ -40,70 +28,22 @@ export default function ColumnSelector<T>({
4028
}
4129
}
4230

43-
const showAll = () => {
44-
const newColumns = columns.map(col => ({...col, visible: true}))
45-
onColumnsChange(newColumns)
46-
}
47-
48-
const hideAll = () => {
49-
const newColumns = columns.map(col => ({...col, visible: false}))
50-
onColumnsChange(newColumns)
51-
}
52-
53-
const resetToDefault = () => {
54-
const newColumns = columns.map(col => ({
55-
...col,
56-
visible: col.visible !== false // Reset to initial state
57-
}))
58-
onColumnsChange(newColumns)
59-
}
60-
6131
return (
6232
<Popover
63-
width={280}
33+
width={180}
6434
position="bottom-end"
6535
withArrow
6636
shadow="md"
6737
opened={opened}
6838
onChange={setOpened}
6939
>
7040
<Popover.Target>
71-
<Button
72-
variant="light"
73-
leftSection={<IconColumns size={16} />}
74-
onClick={() => setOpened(o => !o)}
75-
>
76-
Columns ({visibleCount}/{totalCount})
77-
</Button>
41+
<ActionIcon variant="light" onClick={() => setOpened(o => !o)}>
42+
<IconColumns size={16} />
43+
</ActionIcon>
7844
</Popover.Target>
7945

8046
<Popover.Dropdown>
81-
<Group justify="space-between" mb="sm">
82-
<Text size="sm" fw={500}>
83-
Column Visibility
84-
</Text>
85-
<Group gap="xs">
86-
<Button
87-
size="xs"
88-
variant="subtle"
89-
leftSection={<IconEye size={14} />}
90-
onClick={showAll}
91-
>
92-
Show All
93-
</Button>
94-
<Button
95-
size="xs"
96-
variant="subtle"
97-
leftSection={<IconEyeOff size={14} />}
98-
onClick={hideAll}
99-
>
100-
Hide All
101-
</Button>
102-
</Group>
103-
</Group>
104-
105-
<Divider mb="sm" />
106-
10747
<ScrollArea.Autosize mah={300}>
10848
<Stack gap="xs">
10949
{columns.map(column => (
@@ -117,20 +57,6 @@ export default function ColumnSelector<T>({
11757
))}
11858
</Stack>
11959
</ScrollArea.Autosize>
120-
121-
{columns.length > 5 && (
122-
<>
123-
<Divider mt="sm" mb="sm" />
124-
<Button
125-
size="xs"
126-
variant="subtle"
127-
fullWidth
128-
onClick={resetToDefault}
129-
>
130-
Reset to Default
131-
</Button>
132-
</>
133-
)}
13460
</Popover.Dropdown>
13561
</Popover>
13662
)

0 commit comments

Comments
 (0)