admin/logs: persist columns configuration #817
Massimo Melina committed
Nov 24, 2024 at 15:28 UTC
15bf0b01d298a0dbb4aaf920e76735e9104cc9aa
4 files changed
+23
-4
admin/src/DataTable.ts
+13
-3
@@ -6,6 +6,7 @@ import { callable, Callback, newDialog, onlyTruthy, useGetSize } from '@hfs/shar
6
import _ from 'lodash'
7
import { Center, Flex } from './mui'
8
import { SxProps } from '@mui/system'
9
+import { state, updateStateObject } from './state'
10
11
const ACTIONS = 'Actions'
12
@@ -27,8 +28,9 @@ export interface DataTableProps<R extends GridValidRowModel=any> extends Omit<Da
28
compact?: boolean
29
footerSide?: (width: number) => ReactNode
30
fillFlex?: boolean
31
+ persist?: string
32
}
31
-export function DataTable({ columns, initialState={}, actions, actionsProps, initializing, noRows, error, compact, footerSide, fillFlex, ...rest }: DataTableProps) {
33
+export function DataTable({ columns, initialState={}, actions, actionsProps, initializing, noRows, error, compact, footerSide, fillFlex, persist, ...rest }: DataTableProps) {
34
const theme = useTheme()
35
const apiRef = useGridApiRef()
36
const [actionsLength, setActionsLength] = useState(0)
@@ -104,7 +106,7 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
106
setMerged(_.sumBy(fields, k => _.find(columns, col => !fields.includes(col.field) && col.mergeRender?.[k]) ? 1 : 0))
107
return fields
108
}, [manipulatedColumns, width])
107
- const [vis, setVis] = useState({})
109
+ const [vis, setVis] = useState(persist && state.dataTablePersistence[persist]?.columnVisibility || {})
110
111
const displayingDetails = useRef<any>({})
112
useEffect(() => {
@@ -188,7 +190,15 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
190
}
191
})
192
},
191
- onColumnVisibilityModelChange: x => setVis(x),
193
+ onColumnVisibilityModelChange: vis => {
194
+ setVis(vis)
195
+ if (!persist) return
196
+ updateStateObject(state, 'dataTablePersistence', x => {
197
+ x[persist] = {
198
+ columnVisibility: _.omitBy(vis, (v, k) => hideCols.includes(k) === (v === false))
199
+ }
200
+ })
201
+ },
202
columnVisibilityModel: {
203
...Object.fromEntries(hideCols.map(x => [x, false])),
204
...rest.columnVisibilityModel,
admin/src/LogsPage.ts
+1
@@ -157,6 +157,7 @@ export function LogFile({ file, footerSide, hidden, limit, filter, ...rest }: Lo
157
const isConsole = file === 'console'
158
const isIps = file === 'ips'
159
return hidden ? null : h(DataTable, {
160
+ persist: 'log_' + file,
161
error,
162
loading: connecting,
163
rows,
admin/src/MonitorPage.ts
+1
@@ -144,6 +144,7 @@ function Connections() {
144
h(Grid, { container: true, flex: 1, columnSpacing: 1 },
145
h(Grid, { item: true, xs: 12 - logSize },
146
h(DataTable, {
147
+ persist: 'connections',
148
error,
149
rows,
150
noRows: monitorOnlyFiles && "No downloads at the moment",
admin/src/state.ts
+8
-1
@@ -5,6 +5,7 @@ import { Dict } from './misc'
5
import { VfsNode } from './VfsPage'
6
import _ from 'lodash'
7
import { subscribeKey } from 'valtio/utils'
8
+import produce from 'immer'
9
10
const STORAGE_KEY = 'admin_state'
11
const INIT = {
@@ -19,6 +20,7 @@ const INIT = {
20
monitorWithLog: true,
21
customHtmlSection: '',
22
darkTheme: undefined as undefined | boolean,
23
+ dataTablePersistence: {} as any,
24
onlinePluginsColumns: {
25
version: false,
26
pushed_at: false,
@@ -28,7 +30,7 @@ const INIT = {
30
Object.assign(INIT, JSON.parse(localStorage[STORAGE_KEY]||null))
31
export const state = proxy(INIT)
32
31
-const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns', 'monitorOnlyFiles', 'monitorWithLog', 'customHtmlSection', 'darkTheme']
33
+const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns', 'monitorOnlyFiles', 'monitorWithLog', 'customHtmlSection', 'darkTheme', 'dataTablePersistence']
34
const storeSettings = _.debounce(() =>
35
localStorage[STORAGE_KEY] = JSON.stringify(_.pick(state, SETTINGS_TO_STORE)), 500, { maxWait: 1000 })
36
for (const k of SETTINGS_TO_STORE)
@@ -37,3 +39,8 @@ for (const k of SETTINGS_TO_STORE)
39
export function useSnapState() {
40
return useSnapshot(state)
41
}
42
+
43
+// use this to reflect a deep change in an object to its root, so that valtio is triggered
44
+export function updateStateObject(obj: any, k: string, cb: (x: any) => void) {
45
+ obj[k] = produce(obj[k], cb)
46
+}
\ No newline at end of file