main
ts 84 lines 2.79 KB
Raw
1 // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3 import { proxy, useSnapshot } from 'valtio'
4 import { Dict } from './misc'
5 import { reindexVfs, VfsNodeAdmin } 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 = {
12 title: '',
13 config: {} as Dict,
14 selectedFiles: [] as VfsNodeAdmin[],
15 vfsShowDiskContentFor: '',
16 accountsAsTree: false,
17 movingFile: '',
18 vfs: undefined as VfsNodeAdmin | undefined,
19 vfsUndo: undefined as VfsNodeAdmin | undefined,
20 vfsModified: false,
21 expanded: [] as string[],
22 loginRequired: false as boolean | number,
23 username: '',
24 monitorOnlyFiles: true,
25 monitorWithLog: true,
26 customHtmlSection: '',
27 darkTheme: undefined as undefined | boolean,
28 dataTablePersistence: {} as any,
29 hideRandomPlugin: false,
30 onlinePluginsColumns: {
31 version: false,
32 pushed_at: false,
33 license: false,
34 } as Dict<boolean>
35 }
36 Object.assign(INIT, JSON.parse(localStorage[STORAGE_KEY]||null))
37 export const state = proxy(INIT)
38 Object.assign(window, { state })
39
40 const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns', 'monitorOnlyFiles', 'monitorWithLog',
41 'customHtmlSection', 'darkTheme', 'dataTablePersistence', 'accountsAsTree', 'hideRandomPlugin']
42 const storeSettings = _.debounce(() =>
43 localStorage[STORAGE_KEY] = JSON.stringify(_.pick(state, SETTINGS_TO_STORE)), 500, { maxWait: 1000 })
44 for (const k of SETTINGS_TO_STORE)
45 subscribeKey(state, k, storeSettings)
46
47 export function useSnapState() {
48 return useSnapshot(state)
49 }
50
51 export function markVfsModified() {
52 state.vfs = { ...state.vfs! }
53 state.vfsModified = true
54 reindexVfs()
55 }
56
57 export function prepareVfsUndo() {
58 if (!state.vfs) return
59 state.vfsUndo = cloneVfs(state.vfs)
60 }
61
62 export function undoVfs() {
63 if (!state.vfs || !state.vfsUndo) return
64 // Swap current/snapshot so pressing undo again restores the state we just replaced (single-level redo behavior).
65 const current = cloneVfs(state.vfs)
66 state.vfs = state.vfsUndo
67 state.vfsUndo = current
68 state.vfsModified = true
69 reindexVfs()
70 }
71
72 // use this to reflect a deep change in an object to its root, so that valtio is triggered
73 export function updateStateObject(obj: any, k: string, cb: (x: any) => void) {
74 obj[k] = produce(obj[k], cb)
75 }
76
77 function cloneVfs(node: VfsNodeAdmin): VfsNodeAdmin {
78 const { parent, children, ...rest } = node
79 // Parent links create cycles in the live tree; omit them so snapshots can be cloned and restored safely.
80 const copy = _.cloneDeep(rest) as VfsNodeAdmin
81 if (children)
82 copy.children = children.map(cloneVfs)
83 return copy
84 }