From 0e6eaaeddc53b9e15badea37dc54bdefc0712dcf Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 04:45:14 +0100 Subject: [PATCH 01/13] Add more generic get method to model context --- src/contexts/api/model/ModelContext.tsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/contexts/api/model/ModelContext.tsx b/src/contexts/api/model/ModelContext.tsx index 5fff57bc..ecec8a67 100644 --- a/src/contexts/api/model/ModelContext.tsx +++ b/src/contexts/api/model/ModelContext.tsx @@ -34,6 +34,9 @@ export interface ModelContextValue { /** The user models, active users etc. */ readonly users: Users; + /** Fetches an arbitrary path. */ + get(path: string[]): Promise>; + /** Fetches lamp server metrics. */ getLaserMetrics(): Promise>; } @@ -43,6 +46,7 @@ export const ModelContext = createContext({ models: Map(), active: Set(), }, + get: async () => errorResult('No model context for fetching path'), getLaserMetrics: async () => errorResult('No model context for fetching laser metrics'), }); @@ -148,17 +152,25 @@ export function ModelContextProvider({ children }: ModelContextProviderProps) { const value: ModelContextValue = useMemo( () => ({ users, - async getLaserMetrics() { + async get(path) { try { - const message = await client?.get(['metrics', 'laser']); - if (!message || message.RNUM >= 400) { - return errorResult('Model server provided no laser metrics'); + const message = await client?.get(path); + if (!message) { + return errorResult('Model server provided no results'); + } + if (message.RNUM >= 400) { + return errorResult( + `Model server errored while fetching ${JSON.stringify(path)}: ${message.RNUM} ${message.RESPONSE ?? ''}` + ); } - return okResult(message.PAYL as LaserMetrics); + return okResult(message.PAYL); } catch (error) { return errorResult(error); } }, + async getLaserMetrics() { + return (await this.get(['metrics', 'laser'])) as Result; + }, }), [client, users] ); From e97880f0cd7adf4766ada08f5b7ac4d23ae2a428 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 04:46:40 +0100 Subject: [PATCH 02/13] Stub out ResourcesTreeView --- src/screens/home/admin/ResourcesTreeView.tsx | 20 ++++++++++++++++++++ src/screens/home/admin/ResourcesView.tsx | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/screens/home/admin/ResourcesTreeView.tsx diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx new file mode 100644 index 00000000..9cc00d16 --- /dev/null +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -0,0 +1,20 @@ +import { UnderConstruction } from '@luna/components/UnderConstruction'; +import { ModelContext } from '@luna/contexts/api/model/ModelContext'; +import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; +import { useContext } from 'react'; + +export interface ResourcesTreeViewProps { + layout: ResourcesLayout; + path: string[]; +} + +export function ResourcesTreeView({ path, layout }: ResourcesTreeViewProps) { + const model = useContext(ModelContext); + + switch (layout) { + case 'column': + return <>; + case 'list': + return ; // TODO + } +} diff --git a/src/screens/home/admin/ResourcesView.tsx b/src/screens/home/admin/ResourcesView.tsx index a905942b..323b058f 100644 --- a/src/screens/home/admin/ResourcesView.tsx +++ b/src/screens/home/admin/ResourcesView.tsx @@ -1,8 +1,8 @@ -import { UnderConstruction } from '@luna/components/UnderConstruction'; import { LocalStorageKey } from '@luna/constants/LocalStorageKey'; import { useLocalStorage } from '@luna/hooks/useLocalStorage'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; import { ResourcesToolbar } from '@luna/screens/home/admin/ResourcesToolbar'; +import { ResourcesTreeView } from '@luna/screens/home/admin/ResourcesTreeView'; import { HomeContent } from '@luna/screens/home/HomeContent'; export function ResourcesView() { @@ -16,7 +16,7 @@ export function ResourcesView() { title="Resources" toolbar={} > - + ); } From 476d834d62d27aa8168e0677d19822e7d5ea62d7 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 04:59:11 +0100 Subject: [PATCH 03/13] Add mapResult --- src/utils/result.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/utils/result.ts b/src/utils/result.ts index 2ab5eb3a..b08c599e 100644 --- a/src/utils/result.ts +++ b/src/utils/result.ts @@ -10,6 +10,17 @@ export function errorResult(error: E): Result { return { ok: false, error }; } +export function mapResult( + result: Result, + transform: (value: T) => U +): Result { + if (result.ok) { + return { ok: true, value: transform(result.value) }; + } else { + return result; + } +} + export function getOrThrow(result: Result): T { if (result.ok) { return result.value; From ba7a19f0a2b11419d5aa4035a0876770ad28d31a Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:04:46 +0100 Subject: [PATCH 04/13] Bump nighthouse to 3.0.4 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a01e732b..44440993 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@testing-library/user-event": "^14.5.2", "framer-motion": "^11", "immutable": "^4.3.6", - "nighthouse": "3.0.3", + "nighthouse": "3.0.4", "react": "^18.3.1", "react-card-flip": "^1.2.3", "react-dom": "^18.3.1", @@ -20092,9 +20092,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nighthouse": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/nighthouse/-/nighthouse-3.0.3.tgz", - "integrity": "sha512-Xdf05MpHYUvKRy2Fc8iuX1UasMir7SyzZkwuqVMI0cYmZoCu943BbZkYb6EOiGF+KU5VNNpkyU+6NdPcjsV3+g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/nighthouse/-/nighthouse-3.0.4.tgz", + "integrity": "sha512-CUMq62io/fCxn2QFDTcPQT2LaJ14d5Jdj/0WicrKvKMf7YJJa6tj+8CqFiKqJ7t5tFF3z1SWCkbnHANFEfX0Ng==", "dependencies": { "@msgpack/msgpack": "^3.0.0-beta2" }, diff --git a/package.json b/package.json index 2f051b2f..b3bb50d4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "@testing-library/user-event": "^14.5.2", "framer-motion": "^11", "immutable": "^4.3.6", - "nighthouse": "3.0.3", + "nighthouse": "3.0.4", "react": "^18.3.1", "react-card-flip": "^1.2.3", "react-dom": "^18.3.1", From d0f8cfb4838ffb3019b13364b28e33a4a36d42d1 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:09:34 +0100 Subject: [PATCH 05/13] Pass tree directly to ResourcesTreeView --- src/contexts/api/model/ModelContext.tsx | 42 +++++++++++++------- src/screens/home/admin/ResourcesTreeView.tsx | 9 ++--- src/screens/home/admin/ResourcesView.tsx | 19 ++++++++- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/contexts/api/model/ModelContext.tsx b/src/contexts/api/model/ModelContext.tsx index ecec8a67..0f23887c 100644 --- a/src/contexts/api/model/ModelContext.tsx +++ b/src/contexts/api/model/ModelContext.tsx @@ -7,10 +7,12 @@ import { Map, Set } from 'immutable'; import { connect, ConsoleLogHandler, + DirectoryTree, LeveledLogHandler, Lighthouse, LIGHTHOUSE_FRAME_BYTES, LogLevel, + ServerMessage, } from 'nighthouse/browser'; import { createContext, @@ -34,6 +36,9 @@ export interface ModelContextValue { /** The user models, active users etc. */ readonly users: Users; + /** Lists an arbitrary path. */ + list(path: string[]): Promise>; + /** Fetches an arbitrary path. */ get(path: string[]): Promise>; @@ -46,6 +51,7 @@ export const ModelContext = createContext({ models: Map(), active: Set(), }, + list: async () => errorResult('No model context for listing path'), get: async () => errorResult('No model context for fetching path'), getLaserMetrics: async () => errorResult('No model context for fetching laser metrics'), @@ -55,6 +61,22 @@ interface ModelContextProviderProps { children: ReactNode; } +function messageToResult(message: ServerMessage | undefined): Result { + try { + if (!message) { + return errorResult('Model server provided no results'); + } + if (message.RNUM >= 400) { + return errorResult( + `Model server errored: ${message.RNUM} ${message.RESPONSE ?? ''}` + ); + } + return okResult(message.PAYL); + } catch (error) { + return errorResult(error); + } +} + export function ModelContextProvider({ children }: ModelContextProviderProps) { const auth = useContext(AuthContext); @@ -152,21 +174,13 @@ export function ModelContextProvider({ children }: ModelContextProviderProps) { const value: ModelContextValue = useMemo( () => ({ users, + async list(path) { + const message = await client?.list(path); + return messageToResult(message); + }, async get(path) { - try { - const message = await client?.get(path); - if (!message) { - return errorResult('Model server provided no results'); - } - if (message.RNUM >= 400) { - return errorResult( - `Model server errored while fetching ${JSON.stringify(path)}: ${message.RNUM} ${message.RESPONSE ?? ''}` - ); - } - return okResult(message.PAYL); - } catch (error) { - return errorResult(error); - } + const message = await client?.get(path); + return messageToResult(message); }, async getLaserMetrics() { return (await this.get(['metrics', 'laser'])) as Result; diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx index 9cc00d16..a1ffe7f0 100644 --- a/src/screens/home/admin/ResourcesTreeView.tsx +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -1,16 +1,13 @@ import { UnderConstruction } from '@luna/components/UnderConstruction'; -import { ModelContext } from '@luna/contexts/api/model/ModelContext'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; -import { useContext } from 'react'; +import { DirectoryTree } from 'nighthouse/browser'; export interface ResourcesTreeViewProps { layout: ResourcesLayout; - path: string[]; + tree: DirectoryTree; } -export function ResourcesTreeView({ path, layout }: ResourcesTreeViewProps) { - const model = useContext(ModelContext); - +export function ResourcesTreeView({ layout }: ResourcesTreeViewProps) { switch (layout) { case 'column': return <>; diff --git a/src/screens/home/admin/ResourcesView.tsx b/src/screens/home/admin/ResourcesView.tsx index 323b058f..4b7c88e5 100644 --- a/src/screens/home/admin/ResourcesView.tsx +++ b/src/screens/home/admin/ResourcesView.tsx @@ -1,9 +1,12 @@ import { LocalStorageKey } from '@luna/constants/LocalStorageKey'; +import { ModelContext } from '@luna/contexts/api/model/ModelContext'; import { useLocalStorage } from '@luna/hooks/useLocalStorage'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; import { ResourcesToolbar } from '@luna/screens/home/admin/ResourcesToolbar'; import { ResourcesTreeView } from '@luna/screens/home/admin/ResourcesTreeView'; import { HomeContent } from '@luna/screens/home/HomeContent'; +import { DirectoryTree } from 'nighthouse/browser'; +import { useContext, useEffect, useState } from 'react'; export function ResourcesView() { const [layout, setLayout] = useLocalStorage( @@ -11,12 +14,26 @@ export function ResourcesView() { () => 'column' ); + const model = useContext(ModelContext); + const [tree, setTree] = useState(); + + useEffect(() => { + (async () => { + const result = await model.list([]); + if (result.ok) { + setTree(result.value); + } else { + console.log(result.error); + } + })(); + }, [model]); + return ( } > - + {tree ? : undefined} ); } From 85188f49aa3db2b2df0c092d90d652832ec54029 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:34:16 +0100 Subject: [PATCH 06/13] Implement basic column browser --- src/screens/home/admin/ResourcesTreeView.tsx | 70 +++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx index a1ffe7f0..78ed6ef5 100644 --- a/src/screens/home/admin/ResourcesTreeView.tsx +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -1,17 +1,81 @@ +import { Button } from '@heroui/react'; import { UnderConstruction } from '@luna/components/UnderConstruction'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; +import { IconFile, IconFolder } from '@tabler/icons-react'; import { DirectoryTree } from 'nighthouse/browser'; +import { useCallback, useMemo, useState } from 'react'; export interface ResourcesTreeViewProps { + tree: DirectoryTree | undefined | null; layout: ResourcesLayout; - tree: DirectoryTree; } -export function ResourcesTreeView({ layout }: ResourcesTreeViewProps) { +export function ResourcesTreeView({ tree, layout }: ResourcesTreeViewProps) { + const [expanded, setExpanded] = useState(); + + const sortedEntries = useMemo( + () => + tree + ? Object.entries(tree).sort(([name1, _1], [name2, _2]) => + name1.localeCompare(name2) + ) + : undefined, + [tree] + ); + switch (layout) { case 'column': - return <>; + return ( +
+
+ {sortedEntries + ? sortedEntries.map(([name, subTree]) => ( + + )) + : undefined} +
+ {expanded !== undefined && tree?.[expanded] !== null ? ( + + ) : undefined} +
+ ); case 'list': return ; // TODO } } + +function ResourcesTreeButton({ + name, + subTree, + expanded, + setExpanded, +}: { + name: string; + subTree: DirectoryTree | null; + expanded: string | undefined; + setExpanded: (name: string) => void; +}) { + const color = useMemo( + () => (expanded === name ? 'primary' : 'default'), + [expanded, name] + ); + + const onPress = useCallback(() => { + setExpanded(name); + }, [name, setExpanded]); + + return ( + + ); +} From a138a0ff6a9fa600c70bf74742f8f56d40fce3ca Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:39:10 +0100 Subject: [PATCH 07/13] Add dividers and improve keying --- src/screens/home/admin/ResourcesTreeView.tsx | 23 ++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx index 78ed6ef5..00c89cfc 100644 --- a/src/screens/home/admin/ResourcesTreeView.tsx +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -1,4 +1,4 @@ -import { Button } from '@heroui/react'; +import { Button, Divider } from '@heroui/react'; import { UnderConstruction } from '@luna/components/UnderConstruction'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; import { IconFile, IconFolder } from '@tabler/icons-react'; @@ -6,11 +6,16 @@ import { DirectoryTree } from 'nighthouse/browser'; import { useCallback, useMemo, useState } from 'react'; export interface ResourcesTreeViewProps { + parentPath?: string[]; tree: DirectoryTree | undefined | null; layout: ResourcesLayout; } -export function ResourcesTreeView({ tree, layout }: ResourcesTreeViewProps) { +export function ResourcesTreeView({ + parentPath: path = [], + tree, + layout, +}: ResourcesTreeViewProps) { const [expanded, setExpanded] = useState(); const sortedEntries = useMemo( @@ -31,7 +36,7 @@ export function ResourcesTreeView({ tree, layout }: ResourcesTreeViewProps) { {sortedEntries ? sortedEntries.map(([name, subTree]) => ( {expanded !== undefined && tree?.[expanded] !== null ? ( - + <> +
+ +
+ + ) : undefined} ); From 0775f388c57e4ce031e7e32802b6e9f5a4b1b167 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:47:09 +0100 Subject: [PATCH 08/13] Implement basic view for showing resource contents --- .../home/admin/ResourcesContentsView.tsx | 37 +++++++++++++++++++ src/screens/home/admin/ResourcesTreeView.tsx | 21 +++++++---- 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/screens/home/admin/ResourcesContentsView.tsx diff --git a/src/screens/home/admin/ResourcesContentsView.tsx b/src/screens/home/admin/ResourcesContentsView.tsx new file mode 100644 index 00000000..39dc9bea --- /dev/null +++ b/src/screens/home/admin/ResourcesContentsView.tsx @@ -0,0 +1,37 @@ +import { Spinner } from '@heroui/react'; +import { ModelContext } from '@luna/contexts/api/model/ModelContext'; +import { useContext, useEffect, useState } from 'react'; + +export interface ResourcesContentsViewProps { + path: string[]; +} + +export function ResourcesContentsView({ path }: ResourcesContentsViewProps) { + const model = useContext(ModelContext); + const [value, setValue] = useState(); + const [error, setError] = useState(); + + useEffect(() => { + (async () => { + const result = await model.get(path); + console.log(result); + if (result.ok) { + setValue(result.value); + } else { + setError(`${result.error}`); + } + })(); + }, [model, path]); + + return ( + <> + {value !== undefined ? ( + JSON.stringify(value) + ) : error ? ( + error + ) : ( + + )} + + ); +} diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx index 00c89cfc..f146ac9a 100644 --- a/src/screens/home/admin/ResourcesTreeView.tsx +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -1,5 +1,6 @@ import { Button, Divider } from '@heroui/react'; import { UnderConstruction } from '@luna/components/UnderConstruction'; +import { ResourcesContentsView } from '@luna/screens/home/admin/ResourcesContentsView'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; import { IconFile, IconFolder } from '@tabler/icons-react'; import { DirectoryTree } from 'nighthouse/browser'; @@ -45,17 +46,23 @@ export function ResourcesTreeView({ )) : undefined} - {expanded !== undefined && tree?.[expanded] !== null ? ( + {expanded !== undefined ? ( <>
- + {tree?.[expanded] !== null ? ( + <> + + + ) : ( + + )} ) : undefined} From f3f9cb8014e6d25fe3cf6e29bdd0c2e64335ca56 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:48:35 +0100 Subject: [PATCH 09/13] Pretty-print JSON in resource view --- src/screens/home/admin/ResourcesContentsView.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/screens/home/admin/ResourcesContentsView.tsx b/src/screens/home/admin/ResourcesContentsView.tsx index 39dc9bea..4c7d0717 100644 --- a/src/screens/home/admin/ResourcesContentsView.tsx +++ b/src/screens/home/admin/ResourcesContentsView.tsx @@ -14,7 +14,6 @@ export function ResourcesContentsView({ path }: ResourcesContentsViewProps) { useEffect(() => { (async () => { const result = await model.get(path); - console.log(result); if (result.ok) { setValue(result.value); } else { @@ -26,7 +25,7 @@ export function ResourcesContentsView({ path }: ResourcesContentsViewProps) { return ( <> {value !== undefined ? ( - JSON.stringify(value) +
{JSON.stringify(value, null, 2)}
) : error ? ( error ) : ( From 48b0acc68fdbc05051b88df4b5020f3bcb8bab13 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:54:54 +0100 Subject: [PATCH 10/13] Add button for refreshing the listing --- src/screens/home/admin/ResourcesToolbar.tsx | 27 ++++++++++++------- src/screens/home/admin/ResourcesView.tsx | 30 +++++++++++++-------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/screens/home/admin/ResourcesToolbar.tsx b/src/screens/home/admin/ResourcesToolbar.tsx index e7eb4e75..952b09ec 100644 --- a/src/screens/home/admin/ResourcesToolbar.tsx +++ b/src/screens/home/admin/ResourcesToolbar.tsx @@ -3,26 +3,35 @@ import { resourcesLayouts, } from '@luna/screens/home/admin/ResourcesLayout'; import { ResourcesLayoutIcon } from '@luna/screens/home/admin/ResourcesLayoutIcon'; -import { Tab, Tabs } from '@heroui/react'; +import { Button, Tab, Tabs } from '@heroui/react'; import { Key } from 'react'; +import { IconRefresh } from '@tabler/icons-react'; export interface ResourcesToolbarProps { layout: ResourcesLayout; onLayoutChange: (layout: ResourcesLayout) => void; + refreshListing: () => void; } export function ResourcesToolbar({ layout, onLayoutChange, + refreshListing, }: ResourcesToolbarProps) { return ( - void} - > - {resourcesLayouts.map(layout => ( - } /> - ))} - +
+ + void} + > + {resourcesLayouts.map(layout => ( + } /> + ))} + +
); } diff --git a/src/screens/home/admin/ResourcesView.tsx b/src/screens/home/admin/ResourcesView.tsx index 4b7c88e5..591027f9 100644 --- a/src/screens/home/admin/ResourcesView.tsx +++ b/src/screens/home/admin/ResourcesView.tsx @@ -6,7 +6,7 @@ import { ResourcesToolbar } from '@luna/screens/home/admin/ResourcesToolbar'; import { ResourcesTreeView } from '@luna/screens/home/admin/ResourcesTreeView'; import { HomeContent } from '@luna/screens/home/HomeContent'; import { DirectoryTree } from 'nighthouse/browser'; -import { useContext, useEffect, useState } from 'react'; +import { useCallback, useContext, useEffect, useState } from 'react'; export function ResourcesView() { const [layout, setLayout] = useLocalStorage( @@ -17,21 +17,29 @@ export function ResourcesView() { const model = useContext(ModelContext); const [tree, setTree] = useState(); - useEffect(() => { - (async () => { - const result = await model.list([]); - if (result.ok) { - setTree(result.value); - } else { - console.log(result.error); - } - })(); + const refreshListing = useCallback(async () => { + const result = await model.list([]); + if (result.ok) { + setTree(result.value); + } else { + console.log(result.error); + } }, [model]); + useEffect(() => { + refreshListing(); + }, [refreshListing]); + return ( } + toolbar={ + + } > {tree ? : undefined} From 571822e59077f410282bfcab51845a636ce94e90 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 05:55:23 +0100 Subject: [PATCH 11/13] Update monitoring button for consistency --- src/screens/home/admin/MonitorView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/screens/home/admin/MonitorView.tsx b/src/screens/home/admin/MonitorView.tsx index f0cb5b52..f60eb13e 100644 --- a/src/screens/home/admin/MonitorView.tsx +++ b/src/screens/home/admin/MonitorView.tsx @@ -252,9 +252,9 @@ export function MonitorView() { title="Monitoring" toolbar={ /* TODO: auto-refresh (polling) or streaming metrics */ - } > From c3c2507d7ba680b085b5d1647dd1ea73f649c1cb Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 27 Feb 2025 06:08:14 +0100 Subject: [PATCH 12/13] Implement list view in resources view --- src/screens/home/admin/ResourcesTreeView.tsx | 63 +++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/screens/home/admin/ResourcesTreeView.tsx b/src/screens/home/admin/ResourcesTreeView.tsx index f146ac9a..24ade7a1 100644 --- a/src/screens/home/admin/ResourcesTreeView.tsx +++ b/src/screens/home/admin/ResourcesTreeView.tsx @@ -1,8 +1,12 @@ import { Button, Divider } from '@heroui/react'; -import { UnderConstruction } from '@luna/components/UnderConstruction'; import { ResourcesContentsView } from '@luna/screens/home/admin/ResourcesContentsView'; import { ResourcesLayout } from '@luna/screens/home/admin/ResourcesLayout'; -import { IconFile, IconFolder } from '@tabler/icons-react'; +import { + IconChevronDown, + IconChevronRight, + IconFile, + IconFolder, +} from '@tabler/icons-react'; import { DirectoryTree } from 'nighthouse/browser'; import { useCallback, useMemo, useState } from 'react'; @@ -39,6 +43,7 @@ export function ResourcesTreeView({ ); case 'list': - return ; // TODO + return ( +
+ {sortedEntries + ? sortedEntries.map(([name, subTree]) => ( + <> + + {expanded === name ? ( +
+ {subTree === null ? ( + + ) : ( + + )} +
+ ) : undefined} + + )) + : undefined} +
+ ); } } function ResourcesTreeButton({ name, subTree, + layout, expanded, setExpanded, }: { name: string; subTree: DirectoryTree | null; + layout: ResourcesLayout; expanded: string | undefined; - setExpanded: (name: string) => void; + setExpanded: (name?: string) => void; }) { + const isExpanded = useMemo(() => expanded === name, [expanded, name]); + const color = useMemo( - () => (expanded === name ? 'primary' : 'default'), - [expanded, name] + () => (isExpanded && layout === 'column' ? 'primary' : 'default'), + [isExpanded, layout] ); const onPress = useCallback(() => { - setExpanded(name); - }, [name, setExpanded]); + setExpanded(isExpanded ? undefined : name); + }, [name, isExpanded, setExpanded]); return (