@dxos/plugin-debug 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLUGIN.mdl +12 -325
- package/README.md +4 -14
- package/dist/lib/DebugPlugin.mjs +29 -0
- package/dist/lib/DebugPlugin.mjs.map +1 -0
- package/dist/lib/DebugPlugin.node.mjs +10 -0
- package/dist/lib/DebugPlugin.node.mjs.map +1 -0
- package/dist/lib/DebugPlugin.workerd.mjs +8 -0
- package/dist/lib/DebugPlugin.workerd.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +11 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-DebugObjectPanel.mjs +58 -0
- package/dist/lib/chunk-DebugObjectPanel.mjs.map +1 -0
- package/dist/lib/chunk-DebugSettings.mjs +237 -0
- package/dist/lib/chunk-DebugSettings.mjs.map +1 -0
- package/dist/lib/chunk-DebugSpaceObjectsPanel.mjs +39 -0
- package/dist/lib/chunk-DebugSpaceObjectsPanel.mjs.map +1 -0
- package/dist/lib/chunk-DebugStatus.mjs +117 -0
- package/dist/lib/chunk-DebugStatus.mjs.map +1 -0
- package/dist/lib/chunk-LogStatus.mjs +44 -0
- package/dist/lib/chunk-LogStatus.mjs.map +1 -0
- package/dist/lib/chunk-SpaceGenerator.mjs +208 -0
- package/dist/lib/chunk-SpaceGenerator.mjs.map +1 -0
- package/dist/lib/chunk-StatsPanel.mjs +58 -0
- package/dist/lib/chunk-StatsPanel.mjs.map +1 -0
- package/dist/lib/chunk-Wireframe.mjs +60 -0
- package/dist/lib/chunk-Wireframe.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +76 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-log-recording.mjs +17 -0
- package/dist/lib/chunk-log-recording.mjs.map +1 -0
- package/dist/lib/chunk-meta.mjs +36 -0
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +193 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-settings.mjs +23 -0
- package/dist/lib/chunk-settings.mjs.map +1 -0
- package/dist/lib/chunk-stats-panel.mjs +56 -0
- package/dist/lib/chunk-stats-panel.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +60 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/components.mjs +763 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +14 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/index.mjs +3 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/plugin.mjs +8 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/translations.mjs +38 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/DebugPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/DebugSurfaces.d.ts +25 -0
- package/dist/types/src/capabilities/DebugSurfaces.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts +4 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/log-recording.d.ts +10 -0
- package/dist/types/src/capabilities/log-recording.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -1
- package/dist/types/src/capabilities/stats-panel.d.ts +16 -0
- package/dist/types/src/capabilities/stats-panel.d.ts.map +1 -0
- package/dist/types/src/components/SchemaTable/SchemaTable.d.ts +4 -3
- package/dist/types/src/components/SchemaTable/SchemaTable.d.ts.map +1 -1
- package/dist/types/src/components/SpaceGenerator/ObjectGenerator.d.ts.map +1 -1
- package/dist/types/src/containers/DebugObjectPanel/DebugObjectPanel.d.ts +4 -1
- package/dist/types/src/containers/DebugObjectPanel/DebugObjectPanel.d.ts.map +1 -1
- package/dist/types/src/containers/DebugSettings/DebugSettings.d.ts +4 -1
- package/dist/types/src/containers/DebugSettings/DebugSettings.d.ts.map +1 -1
- package/dist/types/src/containers/DebugSettings/DebugSettings.stories.d.ts +30 -58
- package/dist/types/src/containers/DebugSettings/DebugSettings.stories.d.ts.map +1 -1
- package/dist/types/src/containers/DebugSpaceObjectsPanel/DebugSpaceObjectsPanel.d.ts +4 -1
- package/dist/types/src/containers/DebugSpaceObjectsPanel/DebugSpaceObjectsPanel.d.ts.map +1 -1
- package/dist/types/src/containers/DebugStatus/DebugStatus.d.ts +4 -1
- package/dist/types/src/containers/DebugStatus/DebugStatus.d.ts.map +1 -1
- package/dist/types/src/containers/LogStatus/LogStatus.d.ts +6 -0
- package/dist/types/src/containers/LogStatus/LogStatus.d.ts.map +1 -0
- package/dist/types/src/containers/LogStatus/index.d.ts +2 -0
- package/dist/types/src/containers/LogStatus/index.d.ts.map +1 -0
- package/dist/types/src/containers/SpaceGenerator/SpaceGenerator.d.ts +1 -1
- package/dist/types/src/containers/SpaceGenerator/SpaceGenerator.d.ts.map +1 -1
- package/dist/types/src/containers/StatsPanel/StatsPanel.d.ts +6 -0
- package/dist/types/src/containers/StatsPanel/StatsPanel.d.ts.map +1 -0
- package/dist/types/src/containers/StatsPanel/index.d.ts +2 -0
- package/dist/types/src/containers/StatsPanel/index.d.ts.map +1 -0
- package/dist/types/src/containers/Wireframe/Wireframe.d.ts +4 -1
- package/dist/types/src/containers/Wireframe/Wireframe.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +4 -6
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +26 -57
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/DebugNodes.d.ts +7 -0
- package/dist/types/src/types/DebugNodes.d.ts.map +1 -0
- package/dist/types/src/types/DebugSurface.d.ts +8 -0
- package/dist/types/src/types/DebugSurface.d.ts.map +1 -0
- package/dist/types/src/types/debug.d.ts +3 -1
- package/dist/types/src/types/debug.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +2 -2
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +8 -13
- package/package.json +61 -63
- package/src/DebugPlugin.node.ts +1 -1
- package/src/DebugPlugin.tsx +10 -27
- package/src/DebugPlugin.workerd.ts +1 -1
- package/src/capabilities/DebugSurfaces.tsx +146 -0
- package/src/capabilities/app-graph-builder.ts +39 -373
- package/src/capabilities/index.ts +3 -2
- package/src/capabilities/log-recording.ts +20 -0
- package/src/capabilities/react-surface.ts +123 -0
- package/src/capabilities/stats-panel.ts +74 -0
- package/src/components/SchemaTable/SchemaTable.tsx +6 -5
- package/src/components/SpaceGenerator/ObjectGenerator.tsx +9 -3
- package/src/components/SpaceGenerator/presets.ts +2 -2
- package/src/components/index.ts +1 -1
- package/src/containers/DebugObjectPanel/DebugObjectPanel.tsx +20 -20
- package/src/containers/DebugSettings/DebugSettings.tsx +4 -3
- package/src/containers/DebugSpaceObjectsPanel/DebugSpaceObjectsPanel.tsx +4 -2
- package/src/containers/DebugStatus/DebugStatus.tsx +2 -0
- package/src/containers/LogStatus/LogStatus.tsx +51 -0
- package/src/containers/LogStatus/index.ts +5 -0
- package/src/containers/SpaceGenerator/SpaceGenerator.tsx +108 -10
- package/src/containers/StatsPanel/StatsPanel.tsx +74 -0
- package/src/containers/StatsPanel/index.ts +5 -0
- package/src/containers/Wireframe/Wireframe.tsx +2 -0
- package/src/containers/index.ts +9 -7
- package/src/index.ts +1 -1
- package/src/meta.ts +1 -1
- package/src/plugin.ts +1 -1
- package/src/translations.ts +8 -52
- package/src/types/DebugNodes.ts +18 -0
- package/src/types/DebugSurface.ts +16 -0
- package/src/types/debug.ts +3 -1
- package/src/types/index.ts +3 -3
- package/dist/lib/neutral/DebugGraph-G4FWS57E.mjs +0 -15
- package/dist/lib/neutral/DebugGraph-G4FWS57E.mjs.map +0 -7
- package/dist/lib/neutral/DebugObjectPanel-QSGQJ3LM.mjs +0 -61
- package/dist/lib/neutral/DebugObjectPanel-QSGQJ3LM.mjs.map +0 -7
- package/dist/lib/neutral/DebugPlugin.mjs +0 -59
- package/dist/lib/neutral/DebugPlugin.mjs.map +0 -7
- package/dist/lib/neutral/DebugPlugin.node.mjs +0 -18
- package/dist/lib/neutral/DebugPlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/DebugPlugin.workerd.mjs +0 -12
- package/dist/lib/neutral/DebugPlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/DebugSettings-Q3WUL6YQ.mjs +0 -229
- package/dist/lib/neutral/DebugSettings-Q3WUL6YQ.mjs.map +0 -7
- package/dist/lib/neutral/DebugSpaceObjectsPanel-AXFZWEIM.mjs +0 -36
- package/dist/lib/neutral/DebugSpaceObjectsPanel-AXFZWEIM.mjs.map +0 -7
- package/dist/lib/neutral/DebugStatus-H2BAHN26.mjs +0 -122
- package/dist/lib/neutral/DebugStatus-H2BAHN26.mjs.map +0 -7
- package/dist/lib/neutral/DevtoolsOverviewContainer-DWQHTK7D.mjs +0 -24
- package/dist/lib/neutral/DevtoolsOverviewContainer-DWQHTK7D.mjs.map +0 -7
- package/dist/lib/neutral/GithubPanel-4CSJRVKE.mjs +0 -177
- package/dist/lib/neutral/GithubPanel-4CSJRVKE.mjs.map +0 -7
- package/dist/lib/neutral/RegistryPanel-64GIYJHN.mjs +0 -161
- package/dist/lib/neutral/RegistryPanel-64GIYJHN.mjs.map +0 -7
- package/dist/lib/neutral/SpaceGenerator-Y35G6DRV.mjs +0 -146
- package/dist/lib/neutral/SpaceGenerator-Y35G6DRV.mjs.map +0 -7
- package/dist/lib/neutral/Wireframe-WD7S2AUU.mjs +0 -52
- package/dist/lib/neutral/Wireframe-WD7S2AUU.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-UKG4WVYK.mjs +0 -619
- package/dist/lib/neutral/app-graph-builder-UKG4WVYK.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -15
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-72QXLYMI.mjs +0 -118
- package/dist/lib/neutral/chunk-72QXLYMI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-R5C4CKOF.mjs +0 -54
- package/dist/lib/neutral/chunk-R5C4CKOF.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -961
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -27
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -20
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -12
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/react-context-UJURDOO6.mjs +0 -17
- package/dist/lib/neutral/react-context-UJURDOO6.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-URESE7J4.mjs +0 -484
- package/dist/lib/neutral/react-surface-URESE7J4.mjs.map +0 -7
- package/dist/lib/neutral/settings-5I2674B6.mjs +0 -28
- package/dist/lib/neutral/settings-5I2674B6.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -91
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -16
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/types/src/DebugPlugin.test.d.ts +0 -2
- package/dist/types/src/DebugPlugin.test.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-context.d.ts +0 -5
- package/dist/types/src/capabilities/react-context.d.ts.map +0 -1
- package/dist/types/src/containers/DebugGraph/DebugGraph.d.ts +0 -8
- package/dist/types/src/containers/DebugGraph/DebugGraph.d.ts.map +0 -1
- package/dist/types/src/containers/DebugGraph/index.d.ts +0 -2
- package/dist/types/src/containers/DebugGraph/index.d.ts.map +0 -1
- package/dist/types/src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.d.ts +0 -3
- package/dist/types/src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.d.ts.map +0 -1
- package/dist/types/src/containers/DevtoolsOverviewContainer/index.d.ts +0 -2
- package/dist/types/src/containers/DevtoolsOverviewContainer/index.d.ts.map +0 -1
- package/dist/types/src/containers/GithubPanel/GithubComponent.d.ts +0 -15
- package/dist/types/src/containers/GithubPanel/GithubComponent.d.ts.map +0 -1
- package/dist/types/src/containers/GithubPanel/GithubComponent.stories.d.ts +0 -106
- package/dist/types/src/containers/GithubPanel/GithubComponent.stories.d.ts.map +0 -1
- package/dist/types/src/containers/GithubPanel/GithubPanel.d.ts +0 -3
- package/dist/types/src/containers/GithubPanel/GithubPanel.d.ts.map +0 -1
- package/dist/types/src/containers/GithubPanel/index.d.ts +0 -2
- package/dist/types/src/containers/GithubPanel/index.d.ts.map +0 -1
- package/dist/types/src/containers/RegistryPanel/RegistryPanel.d.ts +0 -3
- package/dist/types/src/containers/RegistryPanel/RegistryPanel.d.ts.map +0 -1
- package/dist/types/src/containers/RegistryPanel/index.d.ts +0 -2
- package/dist/types/src/containers/RegistryPanel/index.d.ts.map +0 -1
- package/dist/types/src/types/Devtools.d.ts +0 -57
- package/dist/types/src/types/Devtools.d.ts.map +0 -1
- package/dist/types/src/types/surface.d.ts +0 -4
- package/dist/types/src/types/surface.d.ts.map +0 -1
- package/src/DebugPlugin.test.ts +0 -29
- package/src/capabilities/react-context.tsx +0 -25
- package/src/capabilities/react-surface.tsx +0 -504
- package/src/containers/DebugGraph/DebugGraph.tsx +0 -14
- package/src/containers/DebugGraph/index.ts +0 -5
- package/src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.tsx +0 -27
- package/src/containers/DevtoolsOverviewContainer/index.ts +0 -5
- package/src/containers/GithubPanel/GithubComponent.stories.tsx +0 -38
- package/src/containers/GithubPanel/GithubComponent.tsx +0 -192
- package/src/containers/GithubPanel/GithubPanel.tsx +0 -17
- package/src/containers/GithubPanel/index.ts +0 -5
- package/src/containers/RegistryPanel/RegistryPanel.tsx +0 -150
- package/src/containers/RegistryPanel/index.ts +0 -5
- package/src/types/Devtools.ts +0 -73
- package/src/types/surface.ts +0 -10
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Atom } from '@effect-atom/atom';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
|
|
8
|
+
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
|
+
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
10
|
+
|
|
11
|
+
import { meta } from '#meta';
|
|
12
|
+
|
|
13
|
+
type StatsPanelOptions = {
|
|
14
|
+
/** Persist the store to localStorage (hydrate on load, save on write). */
|
|
15
|
+
persist?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const STORAGE_KEY = `${meta.profile.key}.statsPanel`;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Contributes the {@link AppCapabilities.StatsPanel} store: a single reactive atom holding one
|
|
22
|
+
* compartment per plugin, keyed by plugin key. Read access spans the whole store; writes are scoped
|
|
23
|
+
* to a compartment via `compartment(pluginKey)`. Kept alive with `Atom.keepAlive` so a background
|
|
24
|
+
* writer (e.g. a sync operation) can populate it before any surface subscribes. When `persist` is set
|
|
25
|
+
* the store hydrates from and saves to localStorage so stats survive a reload.
|
|
26
|
+
*/
|
|
27
|
+
export default Capability.makeModule(
|
|
28
|
+
Effect.fnUntraced(function* ({ persist = true }: StatsPanelOptions = {}) {
|
|
29
|
+
const registry = yield* Capability.get(Capabilities.AtomRegistry);
|
|
30
|
+
const canPersist = persist && typeof localStorage !== 'undefined';
|
|
31
|
+
|
|
32
|
+
const hydrate = (): Record<string, unknown> => {
|
|
33
|
+
if (!canPersist) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const raw = localStorage.getItem(STORAGE_KEY);
|
|
38
|
+
return raw ? JSON.parse(raw) : {};
|
|
39
|
+
} catch {
|
|
40
|
+
// Best-effort: a malformed/unavailable value just starts empty.
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const statsAtom = Atom.make<Record<string, unknown>>(hydrate()).pipe(Atom.keepAlive);
|
|
46
|
+
|
|
47
|
+
const save = () => {
|
|
48
|
+
if (!canPersist) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(registry.get(statsAtom)));
|
|
53
|
+
} catch {
|
|
54
|
+
// Best-effort: localStorage may be disabled or over quota; the in-memory atom is authoritative.
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return Capability.contributes(AppCapabilities.StatsPanel, {
|
|
59
|
+
statsAtom,
|
|
60
|
+
get: (pluginKey) => registry.get(statsAtom)[pluginKey],
|
|
61
|
+
compartment: (pluginKey) => ({
|
|
62
|
+
set: (stats) => {
|
|
63
|
+
registry.set(statsAtom, { ...registry.get(statsAtom), [pluginKey]: stats });
|
|
64
|
+
save();
|
|
65
|
+
},
|
|
66
|
+
clear: () => {
|
|
67
|
+
const { [pluginKey]: _removed, ...rest } = registry.get(statsAtom);
|
|
68
|
+
registry.set(statsAtom, rest);
|
|
69
|
+
save();
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { IconButton } from '@dxos/react-ui';
|
|
7
|
+
import { IconButton, ThemedClassName } from '@dxos/react-ui';
|
|
8
|
+
import { mx } from '@dxos/ui-theme';
|
|
8
9
|
|
|
9
|
-
export type SchemaTableProps = {
|
|
10
|
+
export type SchemaTableProps = ThemedClassName<{
|
|
10
11
|
types: any[];
|
|
11
12
|
objects?: Record<string, number | undefined>;
|
|
12
13
|
label: string;
|
|
13
14
|
onClick: (typename: string) => void;
|
|
14
|
-
}
|
|
15
|
+
}>;
|
|
15
16
|
|
|
16
|
-
export const SchemaTable = ({ types, objects = {}, label, onClick }: SchemaTableProps) => {
|
|
17
|
+
export const SchemaTable = ({ classNames, types, objects = {}, label, onClick }: SchemaTableProps) => {
|
|
17
18
|
return (
|
|
18
|
-
<div className='grid grid-cols-[1fr_80px_40px] gap-1 overflow-none'>
|
|
19
|
+
<div className={mx('grid grid-cols-[1fr_80px_40px] gap-1 overflow-none', classNames)}>
|
|
19
20
|
<h2 className='p-2'>{label}</h2>
|
|
20
21
|
{types.map((type) => (
|
|
21
22
|
<div key={type.typename} className='grid grid-cols-subgrid col-span-3 items-center'>
|
|
@@ -6,10 +6,11 @@ import { addressToA1Notation } from '@dxos/compute-hyperformula';
|
|
|
6
6
|
import { ComputeGraph, ComputeGraphModel, DEFAULT_OUTPUT, NODE_INPUT, NODE_OUTPUT } from '@dxos/conductor';
|
|
7
7
|
import { EID, Filter, Key, Type, View } from '@dxos/echo';
|
|
8
8
|
import { OperationInvoker } from '@dxos/operation';
|
|
9
|
+
import { Drawing } from '@dxos/plugin-illustrator';
|
|
9
10
|
import { Markdown } from '@dxos/plugin-markdown';
|
|
10
11
|
import { Sheet } from '@dxos/plugin-sheet';
|
|
11
|
-
import { Sketch } from '@dxos/plugin-sketch';
|
|
12
12
|
import { SpaceOperation } from '@dxos/plugin-space';
|
|
13
|
+
import { Tldraw } from '@dxos/plugin-tldraw';
|
|
13
14
|
import { random } from '@dxos/random';
|
|
14
15
|
import { type Client } from '@dxos/react-client';
|
|
15
16
|
import { type Space } from '@dxos/react-client/echo';
|
|
@@ -70,10 +71,15 @@ export const staticGenerators = new Map<string, ObjectGenerator<any>>([
|
|
|
70
71
|
},
|
|
71
72
|
],
|
|
72
73
|
[
|
|
73
|
-
Type.getTypename(
|
|
74
|
+
Type.getTypename(Drawing.Drawing),
|
|
74
75
|
async (space, n, cb) => {
|
|
75
76
|
const objects = range(n).map(() => {
|
|
76
|
-
const obj = space.db.add(
|
|
77
|
+
const obj = space.db.add(
|
|
78
|
+
Drawing.make({
|
|
79
|
+
name: random.commerce.productName(),
|
|
80
|
+
canvas: Drawing.makeCanvas({ schema: Tldraw.TLDRAW_SCHEMA }),
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
77
83
|
return obj;
|
|
78
84
|
});
|
|
79
85
|
|
|
@@ -121,8 +121,8 @@ export const generator = () => ({
|
|
|
121
121
|
invariant(mailbox, 'Mailbox not found');
|
|
122
122
|
const mailboxFeed = await mailbox.feed?.tryLoad();
|
|
123
123
|
invariant(mailboxFeed, 'Mailbox missing feed reference');
|
|
124
|
-
const
|
|
125
|
-
invariant(
|
|
124
|
+
const feedUri = Feed.getFeedUri(mailboxFeed);
|
|
125
|
+
invariant(feedUri, 'Mailbox feed missing feed URI');
|
|
126
126
|
const tag = await space.db.query(Filter.type(Tag.Tag, { label: 'Investor' })).first();
|
|
127
127
|
const tagUri = Obj.getURI(tag);
|
|
128
128
|
|
package/src/components/index.ts
CHANGED
|
@@ -7,9 +7,9 @@ import React, { useMemo, useState } from 'react';
|
|
|
7
7
|
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
8
8
|
import { ObjectsTree } from '@dxos/devtools';
|
|
9
9
|
import { type Entity, Filter, Json, Obj, Query } from '@dxos/echo';
|
|
10
|
+
import { useQuery } from '@dxos/echo-react';
|
|
10
11
|
import type { EntityId } from '@dxos/keys';
|
|
11
|
-
import {
|
|
12
|
-
import { Clipboard, Input, Panel, ScrollArea, Toolbar } from '@dxos/react-ui';
|
|
12
|
+
import { Clipboard, Panel, ScrollArea, Toolbar } from '@dxos/react-ui';
|
|
13
13
|
import { Syntax } from '@dxos/react-ui-syntax-highlighter';
|
|
14
14
|
import { mx } from '@dxos/ui-theme';
|
|
15
15
|
|
|
@@ -24,12 +24,17 @@ export type DebugObjectPanelProps = Pick<
|
|
|
24
24
|
export const DebugObjectPanel = ({ role, companionTo, onOpen, canOpen }: DebugObjectPanelProps) => {
|
|
25
25
|
const db = Obj.getDatabase(companionTo);
|
|
26
26
|
const [selectedId, setSelectedId] = useState<EntityId | null>(null);
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
// Include feeds so that feed-backed objects (e.g. synced games) resolve in the selection query.
|
|
28
|
+
const selectionQuery = useMemo(
|
|
29
|
+
() =>
|
|
30
|
+
db
|
|
31
|
+
? Query.select(Filter.id(selectedId ?? companionTo.id))
|
|
32
|
+
.options({ deleted: 'include' })
|
|
33
|
+
.from(db, { includeFeeds: true })
|
|
34
|
+
: Query.select(Filter.nothing()),
|
|
35
|
+
[db, selectedId, companionTo.id],
|
|
31
36
|
);
|
|
32
|
-
const
|
|
37
|
+
const [selectedObject] = useQuery(db, selectionQuery);
|
|
33
38
|
|
|
34
39
|
return (
|
|
35
40
|
<Clipboard.Provider>
|
|
@@ -38,7 +43,7 @@ export const DebugObjectPanel = ({ role, companionTo, onOpen, canOpen }: DebugOb
|
|
|
38
43
|
<Toolbar.Root />
|
|
39
44
|
</Panel.Toolbar>
|
|
40
45
|
<Panel.Content asChild>
|
|
41
|
-
<div className={mx('grid divide-y divide-separator', db && 'grid-rows-[1fr_2fr]')}>
|
|
46
|
+
<div className={mx('grid divide-y divide-subdued-separator', db && 'grid-rows-[1fr_2fr]')}>
|
|
42
47
|
{db && (
|
|
43
48
|
<ScrollArea.Root>
|
|
44
49
|
<ScrollArea.Viewport>
|
|
@@ -52,22 +57,15 @@ export const DebugObjectPanel = ({ role, companionTo, onOpen, canOpen }: DebugOb
|
|
|
52
57
|
</ScrollArea.Viewport>
|
|
53
58
|
</ScrollArea.Root>
|
|
54
59
|
)}
|
|
55
|
-
<Syntax.Root
|
|
60
|
+
<Syntax.Root
|
|
61
|
+
data={selectedObject}
|
|
62
|
+
getReplacer={(depth) => (db ? Json.createRefReplacer({ db, depth }) : undefined)}
|
|
63
|
+
>
|
|
56
64
|
<Panel.Root>
|
|
57
65
|
<Panel.Toolbar asChild>
|
|
58
66
|
<Toolbar.Root classNames='grid grid-cols-[1fr_3rem]'>
|
|
59
67
|
<Syntax.Filter />
|
|
60
|
-
<
|
|
61
|
-
<Input.TextInput
|
|
62
|
-
variant='subdued'
|
|
63
|
-
type='number'
|
|
64
|
-
min={0}
|
|
65
|
-
step={1}
|
|
66
|
-
aria-label='Ref depth'
|
|
67
|
-
value={depth}
|
|
68
|
-
onChange={(event) => setDepth(Math.max(0, Number(event.target.value) || 0))}
|
|
69
|
-
/>
|
|
70
|
-
</Input.Root>
|
|
68
|
+
<Syntax.Depth />
|
|
71
69
|
</Toolbar.Root>
|
|
72
70
|
</Panel.Toolbar>
|
|
73
71
|
<Panel.Content asChild>
|
|
@@ -83,3 +81,5 @@ export const DebugObjectPanel = ({ role, companionTo, onOpen, canOpen }: DebugOb
|
|
|
83
81
|
</Clipboard.Provider>
|
|
84
82
|
);
|
|
85
83
|
};
|
|
84
|
+
|
|
85
|
+
DebugObjectPanel.displayName = 'DebugObjectPanel';
|
|
@@ -8,7 +8,7 @@ import { AppCapabilities, AppSpace } from '@dxos/app-toolkit';
|
|
|
8
8
|
import { type AppSurface } from '@dxos/app-toolkit/ui';
|
|
9
9
|
import { type ConfigProto, SaveConfig, Storage, defs } from '@dxos/config';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
|
-
import { type IdbLogStore } from '@dxos/log-store-idb';
|
|
11
|
+
import { type IdbLogStore, MANUAL_LOG_EXPORT_MAX_BYTES } from '@dxos/log-store-idb';
|
|
12
12
|
import { useClient } from '@dxos/react-client';
|
|
13
13
|
import { IconButton, Input, Select, Toast, useFileDownload, useTranslation } from '@dxos/react-ui';
|
|
14
14
|
import { Form } from '@dxos/react-ui-form';
|
|
@@ -92,8 +92,7 @@ export const DebugSettings = ({ settings, onSettingsChange, logStore, onUpload }
|
|
|
92
92
|
}, [client, download, handleToast, onUpload, t]);
|
|
93
93
|
|
|
94
94
|
const handleDownloadLogs = useCallback(async () => {
|
|
95
|
-
const
|
|
96
|
-
const file = new Blob([ndjson], { type: 'application/x-ndjson' });
|
|
95
|
+
const file = await logStore.exportBlob({ maxSize: MANUAL_LOG_EXPORT_MAX_BYTES });
|
|
97
96
|
const fileName = `composer-logs-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.ndjson`;
|
|
98
97
|
download(file, fileName);
|
|
99
98
|
}, [download, logStore]);
|
|
@@ -259,3 +258,5 @@ const updateConfig = (config: ConfigProto, setConfig: (newConfig: ConfigProto) =
|
|
|
259
258
|
await SaveConfig(storageConfigCopy);
|
|
260
259
|
});
|
|
261
260
|
};
|
|
261
|
+
|
|
262
|
+
DebugSettings.displayName = 'DebugSettings';
|
|
@@ -7,8 +7,8 @@ import React, { useState } from 'react';
|
|
|
7
7
|
import { type AppSurface } from '@dxos/app-toolkit/ui';
|
|
8
8
|
import { ObjectsTree } from '@dxos/devtools';
|
|
9
9
|
import { type Entity, Filter, Obj, Query } from '@dxos/echo';
|
|
10
|
+
import { useQuery } from '@dxos/echo-react';
|
|
10
11
|
import { type EntityId } from '@dxos/keys';
|
|
11
|
-
import { useQuery } from '@dxos/react-client/echo';
|
|
12
12
|
import { Clipboard, Grid, Input, Panel, ScrollArea, Toolbar } from '@dxos/react-ui';
|
|
13
13
|
import { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
14
14
|
|
|
@@ -35,7 +35,7 @@ export const DebugSpaceObjectsPanel = ({ space, onOpen, canOpen }: DebugSpaceObj
|
|
|
35
35
|
</Toolbar.Root>
|
|
36
36
|
</Panel.Toolbar>
|
|
37
37
|
<Panel.Content asChild>
|
|
38
|
-
<Grid rows={2} classNames='divide-y divide-separator'>
|
|
38
|
+
<Grid rows={2} classNames='divide-y divide-subdued-separator'>
|
|
39
39
|
<ScrollArea.Root>
|
|
40
40
|
<ScrollArea.Viewport>
|
|
41
41
|
<ObjectsTree
|
|
@@ -53,3 +53,5 @@ export const DebugSpaceObjectsPanel = ({ space, onOpen, canOpen }: DebugSpaceObj
|
|
|
53
53
|
</Clipboard.Provider>
|
|
54
54
|
);
|
|
55
55
|
};
|
|
56
|
+
|
|
57
|
+
DebugSpaceObjectsPanel.displayName = 'DebugSpaceObjectsPanel';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { StatusBar } from '@dxos/plugin-status-bar/components';
|
|
8
|
+
import { IconButton, Panel, Popover, useTranslation } from '@dxos/react-ui';
|
|
9
|
+
import { Logger } from '@dxos/react-ui-debug';
|
|
10
|
+
|
|
11
|
+
import { meta } from '#meta';
|
|
12
|
+
|
|
13
|
+
/** Status-bar button that opens the log panel in a popover for a quick glance. */
|
|
14
|
+
export const LogStatus = () => {
|
|
15
|
+
const { t } = useTranslation(meta.profile.key);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Popover.Root>
|
|
19
|
+
{/* IconButton is the direct trigger child so the trigger ref/handlers/ARIA attach to the button, not the container. */}
|
|
20
|
+
<StatusBar.Item>
|
|
21
|
+
<Popover.Trigger asChild>
|
|
22
|
+
<IconButton variant='ghost' icon='ph--list-magnifying-glass--regular' iconOnly label={t('open-logs.label')} />
|
|
23
|
+
</Popover.Trigger>
|
|
24
|
+
</StatusBar.Item>
|
|
25
|
+
<Popover.Portal>
|
|
26
|
+
<Popover.Content side='top'>
|
|
27
|
+
<Popover.Viewport classNames='w-[40rem] h-[24rem]'>
|
|
28
|
+
<Logger.Root>
|
|
29
|
+
<Panel.Root>
|
|
30
|
+
<Panel.Toolbar asChild>
|
|
31
|
+
<Logger.Toolbar />
|
|
32
|
+
</Panel.Toolbar>
|
|
33
|
+
<Panel.Content asChild>
|
|
34
|
+
<Logger.Content>
|
|
35
|
+
<Logger.List />
|
|
36
|
+
</Logger.Content>
|
|
37
|
+
</Panel.Content>
|
|
38
|
+
<Panel.Statusbar asChild>
|
|
39
|
+
<Logger.Filter />
|
|
40
|
+
</Panel.Statusbar>
|
|
41
|
+
</Panel.Root>
|
|
42
|
+
</Logger.Root>
|
|
43
|
+
</Popover.Viewport>
|
|
44
|
+
<Popover.Arrow />
|
|
45
|
+
</Popover.Content>
|
|
46
|
+
</Popover.Portal>
|
|
47
|
+
</Popover.Root>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
LogStatus.displayName = 'LogStatus';
|
|
@@ -2,25 +2,29 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { useCallback, useMemo, useState } from 'react';
|
|
5
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { useOperationInvoker } from '@dxos/app-framework/ui';
|
|
7
|
+
import { useOperationInvoker, useOptionalCapability } from '@dxos/app-framework/ui';
|
|
8
|
+
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
9
|
+
import { useProgress } from '@dxos/app-toolkit/ui';
|
|
8
10
|
import { ComputeGraph } from '@dxos/conductor';
|
|
9
11
|
import { Filter, Obj, Type } from '@dxos/echo';
|
|
12
|
+
import { Drawing } from '@dxos/plugin-illustrator';
|
|
10
13
|
import { Markdown } from '@dxos/plugin-markdown';
|
|
11
14
|
import { Sheet } from '@dxos/plugin-sheet';
|
|
12
|
-
import { Sketch } from '@dxos/plugin-sketch';
|
|
13
15
|
import { useClient } from '@dxos/react-client';
|
|
14
16
|
import { type Space } from '@dxos/react-client/echo';
|
|
15
|
-
import { IconButton, Input, Panel, ScrollArea, Toolbar, useAsyncEffect } from '@dxos/react-ui';
|
|
17
|
+
import { IconButton, Input, Panel, ScrollArea, ThemedClassName, Toolbar, useAsyncEffect } from '@dxos/react-ui';
|
|
16
18
|
import { composable, composableProps } from '@dxos/react-ui';
|
|
17
19
|
import { Organization, Person, Task } from '@dxos/types';
|
|
20
|
+
import { mx } from '@dxos/ui-theme';
|
|
18
21
|
import { sortKeys } from '@dxos/util';
|
|
19
22
|
|
|
20
23
|
import { type ObjectGenerator, SchemaTable, createGenerator, generator, staticGenerators } from '#components';
|
|
24
|
+
import { meta } from '#meta';
|
|
21
25
|
|
|
22
26
|
// TODO(burdon): Make extensible.
|
|
23
|
-
const staticTypes = [Markdown.Document,
|
|
27
|
+
const staticTypes = [Markdown.Document, Drawing.Drawing, Sheet.Sheet, ComputeGraph];
|
|
24
28
|
const recordTypes: Type.AnyObj[] = [Organization.Organization, Person.Person, Task.Task];
|
|
25
29
|
|
|
26
30
|
export type SpaceGeneratorProps = {
|
|
@@ -94,8 +98,8 @@ export const SpaceGenerator = composable<HTMLDivElement, SpaceGeneratorProps>(
|
|
|
94
98
|
|
|
95
99
|
return (
|
|
96
100
|
<Panel.Root {...composableProps(props)} ref={forwardedRef}>
|
|
97
|
-
<Panel.Toolbar
|
|
98
|
-
<Toolbar.Root>
|
|
101
|
+
<Panel.Toolbar>
|
|
102
|
+
<Toolbar.Root classNames='dx-document'>
|
|
99
103
|
<IconButton icon='ph--arrow-clockwise--regular' iconOnly label='Refresh' onClick={updateInfo} />
|
|
100
104
|
<Toolbar.Separator />
|
|
101
105
|
<Input.Root>
|
|
@@ -115,9 +119,28 @@ export const SpaceGenerator = composable<HTMLDivElement, SpaceGeneratorProps>(
|
|
|
115
119
|
<Panel.Content asChild>
|
|
116
120
|
<ScrollArea.Root thin orientation='vertical'>
|
|
117
121
|
<ScrollArea.Viewport classNames='dx-document gap-4 divide-y divide-subdued-separator'>
|
|
118
|
-
<SchemaTable
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
<SchemaTable
|
|
123
|
+
classNames='py-1'
|
|
124
|
+
types={staticTypes}
|
|
125
|
+
objects={info.objects}
|
|
126
|
+
label='Static Types'
|
|
127
|
+
onClick={handleCreateData}
|
|
128
|
+
/>
|
|
129
|
+
<SchemaTable
|
|
130
|
+
classNames='py-1'
|
|
131
|
+
types={recordTypes}
|
|
132
|
+
objects={info.objects}
|
|
133
|
+
label='Record Types'
|
|
134
|
+
onClick={handleCreateData}
|
|
135
|
+
/>
|
|
136
|
+
<SchemaTable
|
|
137
|
+
classNames='py-1'
|
|
138
|
+
types={presets.types}
|
|
139
|
+
objects={info.objects}
|
|
140
|
+
label='Presets'
|
|
141
|
+
onClick={handleCreateData}
|
|
142
|
+
/>
|
|
143
|
+
<ProgressGenerator classNames='py-1' />
|
|
121
144
|
</ScrollArea.Viewport>
|
|
122
145
|
</ScrollArea.Root>
|
|
123
146
|
</Panel.Content>
|
|
@@ -125,3 +148,78 @@ export const SpaceGenerator = composable<HTMLDivElement, SpaceGeneratorProps>(
|
|
|
125
148
|
);
|
|
126
149
|
},
|
|
127
150
|
);
|
|
151
|
+
|
|
152
|
+
SpaceGenerator.displayName = 'SpaceGenerator';
|
|
153
|
+
|
|
154
|
+
// Stable key for the test progress monitor within the shared registry.
|
|
155
|
+
const TEST_PROGRESS_NAME = `${meta.profile.key}.test-progress`;
|
|
156
|
+
|
|
157
|
+
type ProgressGeneratorProps = ThemedClassName;
|
|
158
|
+
|
|
159
|
+
// Drives a synthetic progress monitor (10s over 10 steps) so the R0 rail meter can be exercised.
|
|
160
|
+
const ProgressGenerator = ({ classNames }: ProgressGeneratorProps) => {
|
|
161
|
+
const registry = useOptionalCapability(AppCapabilities.ProgressRegistry);
|
|
162
|
+
const monitor = useProgress(TEST_PROGRESS_NAME);
|
|
163
|
+
const running = monitor?.status === 'running';
|
|
164
|
+
const intervalRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);
|
|
165
|
+
|
|
166
|
+
const clearTimer = useCallback(() => {
|
|
167
|
+
if (intervalRef.current) {
|
|
168
|
+
clearInterval(intervalRef.current);
|
|
169
|
+
intervalRef.current = undefined;
|
|
170
|
+
}
|
|
171
|
+
}, []);
|
|
172
|
+
|
|
173
|
+
const handleStart = useCallback(() => {
|
|
174
|
+
// Guard on the timer ref too: `running` (derived from the registry) can lag a fast second click.
|
|
175
|
+
if (!registry || running || intervalRef.current) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const steps = 10;
|
|
180
|
+
let current = 0;
|
|
181
|
+
const handle = registry.register(TEST_PROGRESS_NAME, {
|
|
182
|
+
label: 'Test Progress',
|
|
183
|
+
total: steps,
|
|
184
|
+
// Invoked by the meter's cancel control (R0 rail) or the local button.
|
|
185
|
+
onCancel: () => {
|
|
186
|
+
clearTimer();
|
|
187
|
+
handle.remove();
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
intervalRef.current = setInterval(() => {
|
|
192
|
+
current += 1;
|
|
193
|
+
handle.set(current);
|
|
194
|
+
if (current >= steps) {
|
|
195
|
+
clearTimer();
|
|
196
|
+
handle.done();
|
|
197
|
+
handle.remove();
|
|
198
|
+
}
|
|
199
|
+
}, 1_000);
|
|
200
|
+
}, [registry, running, clearTimer]);
|
|
201
|
+
|
|
202
|
+
// Tear down the timer and the registry entry if unmounted mid-run.
|
|
203
|
+
useEffect(
|
|
204
|
+
() => () => {
|
|
205
|
+
clearTimer();
|
|
206
|
+
registry?.cancel(TEST_PROGRESS_NAME);
|
|
207
|
+
},
|
|
208
|
+
[clearTimer, registry],
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<div className={mx('flex items-center gap-2 py-1', classNames)}>
|
|
213
|
+
<span className='grow'>Progress Monitor</span>
|
|
214
|
+
{running ? (
|
|
215
|
+
<IconButton
|
|
216
|
+
icon='ph--x--regular'
|
|
217
|
+
label='Cancel test progress'
|
|
218
|
+
onClick={() => registry?.cancel(TEST_PROGRESS_NAME)}
|
|
219
|
+
/>
|
|
220
|
+
) : (
|
|
221
|
+
<IconButton icon='ph--play--regular' label='Start test progress' disabled={!registry} onClick={handleStart} />
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
);
|
|
225
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Atom, useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import React, { Fragment } from 'react';
|
|
7
|
+
|
|
8
|
+
import { useOptionalCapability } from '@dxos/app-framework/ui';
|
|
9
|
+
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
10
|
+
import { ScrollArea } from '@dxos/react-ui';
|
|
11
|
+
|
|
12
|
+
// Fallback so the atom hook is called unconditionally when no store is contributed (host plugin not
|
|
13
|
+
// loaded); the panel then renders its empty state.
|
|
14
|
+
const EMPTY = Atom.make<Record<string, unknown>>({});
|
|
15
|
+
|
|
16
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
17
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
18
|
+
|
|
19
|
+
/** Renders a leaf value; numbers are monospace so columns of counts align. */
|
|
20
|
+
const formatValue = (value: unknown): string => (typeof value === 'number' ? value.toLocaleString() : String(value));
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Flattens a compartment into `key → value` rows, one level deep: nested objects (e.g. `coverage`)
|
|
24
|
+
* become dotted keys (`coverage.plain`) so everything renders in a single flat table.
|
|
25
|
+
*/
|
|
26
|
+
const flatten = (stats: unknown): [string, unknown][] => {
|
|
27
|
+
if (!isRecord(stats)) {
|
|
28
|
+
return [['value', stats]];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Object.entries(stats).flatMap(([key, value]) =>
|
|
32
|
+
isRecord(value)
|
|
33
|
+
? Object.entries(value).map(([subKey, subValue]): [string, unknown] => [`${key}.${subKey}`, subValue])
|
|
34
|
+
: [[key, value] as [string, unknown]],
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Presentational panel for the {@link AppCapabilities.StatsPanel} store: renders every plugin
|
|
40
|
+
* compartment as a flat key × value table, live (re-renders on each write). Purely generic — it
|
|
41
|
+
* displays whatever each plugin stores, so it works for sync telemetry or any other stats.
|
|
42
|
+
*/
|
|
43
|
+
export const StatsPanel = () => {
|
|
44
|
+
const store = useOptionalCapability(AppCapabilities.StatsPanel);
|
|
45
|
+
const stats = useAtomValue(store?.statsAtom ?? EMPTY);
|
|
46
|
+
const compartments = Object.entries(stats);
|
|
47
|
+
if (compartments.length === 0) {
|
|
48
|
+
return <div className='p-2 text-sm text-description'>No stats yet.</div>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<ScrollArea.Root thin centered padding>
|
|
53
|
+
<ScrollArea.Viewport>
|
|
54
|
+
{compartments.map(([pluginKey, value]) => (
|
|
55
|
+
<section key={pluginKey} className='w-full'>
|
|
56
|
+
<h3 className='text-start font-mono text-xs text-description pbe-1'>{pluginKey}</h3>
|
|
57
|
+
<dl className='grid grid-cols-[auto_minmax(0,1fr)] w-full'>
|
|
58
|
+
{flatten(value).map(([key, cell]) => (
|
|
59
|
+
<Fragment key={key}>
|
|
60
|
+
<dt className='border-be border-separator pbe-1 pbs-1 pie-2 text-description self-start'>{key}</dt>
|
|
61
|
+
<dd className='border-be border-separator pbe-1 pbs-1 truncate font-mono text-end'>
|
|
62
|
+
{formatValue(cell)}
|
|
63
|
+
</dd>
|
|
64
|
+
</Fragment>
|
|
65
|
+
))}
|
|
66
|
+
</dl>
|
|
67
|
+
</section>
|
|
68
|
+
))}
|
|
69
|
+
</ScrollArea.Viewport>
|
|
70
|
+
</ScrollArea.Root>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
StatsPanel.displayName = 'StatsPanel';
|
package/src/containers/index.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type ComponentType, lazy } from 'react';
|
|
6
6
|
|
|
7
|
-
export const DebugGraph: ComponentType<any> = lazy(() => import('./DebugGraph'));
|
|
8
|
-
export const DebugSettings: ComponentType<any> = lazy(() => import('./DebugSettings'));
|
|
9
7
|
export const DebugObjectPanel: ComponentType<any> = lazy(() => import('./DebugObjectPanel'));
|
|
8
|
+
export const DebugSettings: ComponentType<any> = lazy(() => import('./DebugSettings'));
|
|
9
|
+
export const DebugSpaceObjectsPanel: ComponentType<any> = lazy(() => import('./DebugSpaceObjectsPanel'));
|
|
10
10
|
export const DebugStatus: ComponentType<any> = lazy(() => import('./DebugStatus'));
|
|
11
|
-
export const
|
|
11
|
+
export const LogStatus: ComponentType<any> = lazy(() =>
|
|
12
|
+
import('./LogStatus').then((module) => ({ default: module.LogStatus })),
|
|
13
|
+
);
|
|
12
14
|
export const SpaceGenerator: ComponentType<any> = lazy(() => import('./SpaceGenerator'));
|
|
13
15
|
export const Wireframe: ComponentType<any> = lazy(() => import('./Wireframe'));
|
|
14
|
-
export const
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
export const StatsPanel: ComponentType<any> = lazy(() =>
|
|
17
|
+
import('./StatsPanel').then((module) => ({ default: module.StatsPanel })),
|
|
18
|
+
);
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
package/src/plugin.ts
CHANGED