@dxos/plugin-navtree 0.8.4-main.c85a9c8dae → 0.8.4-main.d05673bc65
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/dist/lib/browser/{CommandsDialogContent-A27AKTHH.mjs → CommandsDialogContent-2DKIOLJL.mjs} +11 -9
- package/dist/lib/browser/CommandsDialogContent-2DKIOLJL.mjs.map +7 -0
- package/dist/lib/browser/{CommandsTrigger-HBZYQCGV.mjs → CommandsTrigger-ABODVVMP.mjs} +2 -2
- package/dist/lib/browser/NavTreeContainer-TLSYS4KK.mjs +12 -0
- package/dist/lib/browser/NavTreeContainer-TLSYS4KK.mjs.map +7 -0
- package/dist/lib/browser/{NavTreeDocumentTitle-GEE3URWH.mjs → NavTreeDocumentTitle-L6NLLWLD.mjs} +2 -2
- package/dist/lib/browser/{app-graph-builder-XGA4GPGL.mjs → app-graph-builder-Z43OTNI2.mjs} +2 -2
- package/dist/lib/browser/{chunk-YKTYPINZ.mjs → chunk-A4VDCIJC.mjs} +3 -3
- package/dist/lib/browser/{chunk-YKTYPINZ.mjs.map → chunk-A4VDCIJC.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-H3OJ4WLF.mjs → chunk-AYF2TX65.mjs} +5 -5
- package/dist/lib/browser/{chunk-H3OJ4WLF.mjs.map → chunk-AYF2TX65.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-DQCYMXEU.mjs → chunk-JT37R5HS.mjs} +149 -107
- package/dist/lib/browser/chunk-JT37R5HS.mjs.map +7 -0
- package/dist/lib/browser/{chunk-X2HDG62A.mjs → chunk-KF26WA4O.mjs} +3 -3
- package/dist/lib/browser/{chunk-X2HDG62A.mjs.map → chunk-KF26WA4O.mjs.map} +1 -1
- package/dist/lib/browser/index.mjs +9 -9
- package/dist/lib/browser/{keyboard-OJZC54PK.mjs → keyboard-HYGFQO7T.mjs} +6 -3
- package/dist/lib/browser/{keyboard-OJZC54PK.mjs.map → keyboard-HYGFQO7T.mjs.map} +2 -2
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{operation-resolver-BNAMYOHF.mjs → operation-resolver-VDWVUII5.mjs} +18 -22
- package/dist/lib/browser/operation-resolver-VDWVUII5.mjs.map +7 -0
- package/dist/lib/browser/{react-surface-AYHOAJ4I.mjs → react-surface-D2RLMV4Z.mjs} +8 -8
- package/dist/lib/browser/{react-surface-AYHOAJ4I.mjs.map → react-surface-D2RLMV4Z.mjs.map} +1 -1
- package/dist/lib/browser/{state-AC3EETN7.mjs → state-CWMNNF7K.mjs} +4 -4
- package/dist/lib/browser/{state-AC3EETN7.mjs.map → state-CWMNNF7K.mjs.map} +1 -1
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -1
- package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
- package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +4 -2
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeContainer/index.d.ts +2 -2
- package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +1 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useActions.d.ts +1 -3
- package/dist/types/src/hooks/useActions.d.ts.map +1 -1
- package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -36
- package/src/capabilities/keyboard/keyboard.ts +1 -1
- package/src/capabilities/operation-resolver/operation-resolver.ts +18 -17
- package/src/capabilities/react-surface/react-surface.tsx +3 -3
- package/src/capabilities/state/state.ts +1 -1
- package/src/components/NavTree/NavTree.stories.tsx +1 -1
- package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
- package/src/components/NavTreeContext/index.ts +5 -0
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +25 -7
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +3 -1
- package/src/components/Sidebar/L0Menu.tsx +1 -1
- package/src/components/Sidebar/L1Panel.tsx +21 -4
- package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +53 -51
- package/src/containers/NavTreeContainer/NavTreeContainer.tsx +4 -3
- package/src/containers/NavTreeContainer/index.ts +2 -3
- package/src/containers/index.ts +1 -1
- package/src/hooks/useActions.ts +17 -21
- package/src/hooks/useNavTreeModel.ts +8 -2
- package/src/meta.ts +2 -2
- package/src/testing/app-graph-builder.ts +5 -5
- package/src/testing/generator.ts +1 -1
- package/src/types/capabilities.ts +1 -1
- package/dist/lib/browser/CommandsDialogContent-A27AKTHH.mjs.map +0 -7
- package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs +0 -12
- package/dist/lib/browser/NavTreeContainer-B5K4FUJS.mjs.map +0 -7
- package/dist/lib/browser/chunk-DQCYMXEU.mjs.map +0 -7
- package/dist/lib/browser/operation-resolver-BNAMYOHF.mjs.map +0 -7
- package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
- /package/dist/lib/browser/{CommandsTrigger-HBZYQCGV.mjs.map → CommandsTrigger-ABODVVMP.mjs.map} +0 -0
- /package/dist/lib/browser/{NavTreeDocumentTitle-GEE3URWH.mjs.map → NavTreeDocumentTitle-L6NLLWLD.mjs.map} +0 -0
- /package/dist/lib/browser/{app-graph-builder-XGA4GPGL.mjs.map → app-graph-builder-Z43OTNI2.mjs.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-navtree",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.d05673bc65",
|
|
4
4
|
"description": "DXOS Surface plugin for a tree view visualization of the graph.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -33,30 +33,30 @@
|
|
|
33
33
|
"@radix-ui/react-dismissable-layer": "1.1.5",
|
|
34
34
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
35
35
|
"date-fns": "^3.3.1",
|
|
36
|
-
"@dxos/app-framework": "0.8.4-main.
|
|
37
|
-
"@dxos/app-graph": "0.8.4-main.
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/log": "0.8.4-main.
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/plugin-
|
|
48
|
-
"@dxos/plugin-
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/react-
|
|
52
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/react-ui-menu": "0.8.4-main.
|
|
55
|
-
"@dxos/react-ui-mosaic": "0.8.4-main.
|
|
56
|
-
"@dxos/react-ui-
|
|
57
|
-
"@dxos/react-ui-
|
|
58
|
-
"@dxos/util": "0.8.4-main.
|
|
59
|
-
"@dxos/react-ui-
|
|
36
|
+
"@dxos/app-framework": "0.8.4-main.d05673bc65",
|
|
37
|
+
"@dxos/app-graph": "0.8.4-main.d05673bc65",
|
|
38
|
+
"@dxos/async": "0.8.4-main.d05673bc65",
|
|
39
|
+
"@dxos/echo": "0.8.4-main.d05673bc65",
|
|
40
|
+
"@dxos/debug": "0.8.4-main.d05673bc65",
|
|
41
|
+
"@dxos/app-toolkit": "0.8.4-main.d05673bc65",
|
|
42
|
+
"@dxos/invariant": "0.8.4-main.d05673bc65",
|
|
43
|
+
"@dxos/keyboard": "0.8.4-main.d05673bc65",
|
|
44
|
+
"@dxos/lit-ui": "0.8.4-main.d05673bc65",
|
|
45
|
+
"@dxos/log": "0.8.4-main.d05673bc65",
|
|
46
|
+
"@dxos/operation": "0.8.4-main.d05673bc65",
|
|
47
|
+
"@dxos/plugin-deck": "0.8.4-main.d05673bc65",
|
|
48
|
+
"@dxos/plugin-graph": "0.8.4-main.d05673bc65",
|
|
49
|
+
"@dxos/plugin-observability": "0.8.4-main.d05673bc65",
|
|
50
|
+
"@dxos/protocols": "0.8.4-main.d05673bc65",
|
|
51
|
+
"@dxos/react-client": "0.8.4-main.d05673bc65",
|
|
52
|
+
"@dxos/react-ui-attention": "0.8.4-main.d05673bc65",
|
|
53
|
+
"@dxos/react-ui-list": "0.8.4-main.d05673bc65",
|
|
54
|
+
"@dxos/react-ui-menu": "0.8.4-main.d05673bc65",
|
|
55
|
+
"@dxos/react-ui-mosaic": "0.8.4-main.d05673bc65",
|
|
56
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.d05673bc65",
|
|
57
|
+
"@dxos/react-ui-stack": "0.8.4-main.d05673bc65",
|
|
58
|
+
"@dxos/util": "0.8.4-main.d05673bc65",
|
|
59
|
+
"@dxos/react-ui-tabs": "0.8.4-main.d05673bc65"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@effect-atom/atom-react": "^0.5.0",
|
|
@@ -67,15 +67,15 @@
|
|
|
67
67
|
"react": "~19.2.3",
|
|
68
68
|
"react-dom": "~19.2.3",
|
|
69
69
|
"vite": "^7.1.11",
|
|
70
|
-
"@dxos/plugin-attention": "0.8.4-main.
|
|
71
|
-
"@dxos/plugin-client": "0.8.4-main.
|
|
72
|
-
"@dxos/plugin-
|
|
73
|
-
"@dxos/plugin-
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/ui
|
|
70
|
+
"@dxos/plugin-attention": "0.8.4-main.d05673bc65",
|
|
71
|
+
"@dxos/plugin-client": "0.8.4-main.d05673bc65",
|
|
72
|
+
"@dxos/plugin-space": "0.8.4-main.d05673bc65",
|
|
73
|
+
"@dxos/plugin-testing": "0.8.4-main.d05673bc65",
|
|
74
|
+
"@dxos/plugin-theme": "0.8.4-main.d05673bc65",
|
|
75
|
+
"@dxos/random": "0.8.4-main.d05673bc65",
|
|
76
|
+
"@dxos/storybook-utils": "0.8.4-main.d05673bc65",
|
|
77
|
+
"@dxos/ui-theme": "0.8.4-main.d05673bc65",
|
|
78
|
+
"@dxos/react-ui": "0.8.4-main.d05673bc65"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"@effect-atom/atom-react": "^0.5.0",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"effect": "3.19.16",
|
|
84
84
|
"react": "~19.2.3",
|
|
85
85
|
"react-dom": "~19.2.3",
|
|
86
|
-
"@dxos/ui
|
|
87
|
-
"@dxos/
|
|
86
|
+
"@dxos/react-ui": "0.8.4-main.d05673bc65",
|
|
87
|
+
"@dxos/ui-theme": "0.8.4-main.d05673bc65"
|
|
88
88
|
},
|
|
89
89
|
"publishConfig": {
|
|
90
90
|
"access": "public"
|
|
@@ -47,7 +47,7 @@ export default Capability.makeModule(
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
const eventHandler = debounce(() => {
|
|
50
|
-
Graph.traverse(graph, { relation: 'child', visitor });
|
|
50
|
+
Graph.traverse(graph, { relation: ['child', 'action'], visitor });
|
|
51
51
|
}, 500);
|
|
52
52
|
|
|
53
53
|
const unsubscribe = graph.onNodeChanged.on(eventHandler);
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Option from 'effect/Option';
|
|
6
7
|
|
|
7
8
|
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
8
9
|
import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
|
|
10
|
+
import { expandAttendableId } from '@dxos/react-ui-attention';
|
|
9
11
|
import { log } from '@dxos/log';
|
|
10
12
|
import { OperationResolver } from '@dxos/operation';
|
|
11
13
|
import { Graph } from '@dxos/plugin-graph';
|
|
@@ -18,25 +20,24 @@ export default Capability.makeModule(
|
|
|
18
20
|
OperationResolver.make({
|
|
19
21
|
operation: LayoutOperation.Expose,
|
|
20
22
|
handler: Effect.fnUntraced(function* ({ subject }) {
|
|
21
|
-
// TODO(wittjosiah): There's a lot of scenarios where this will fail.
|
|
22
|
-
// Probably needs to be aware of the composer ontology to more reliably ensure objects are accessible.
|
|
23
23
|
const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
|
|
24
24
|
const { getItem, setItem } = yield* Capability.get(NavTreeCapabilities.State);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
|
|
26
|
+
const prefixes = expandAttendableId(subject);
|
|
27
|
+
|
|
28
|
+
for (const qualifiedId of prefixes) {
|
|
29
|
+
Graph.expand(graph, qualifiedId, 'child');
|
|
30
|
+
|
|
31
|
+
const treePath = prefixes.slice(0, prefixes.indexOf(qualifiedId) + 1);
|
|
32
|
+
const state = getItem(treePath);
|
|
33
|
+
if (!state.open) {
|
|
34
|
+
setItem(treePath, 'open', true);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (Option.isNone(Graph.getNode(graph, subject))) {
|
|
39
|
+
log('Node not found after expansion', { subject });
|
|
40
|
+
}
|
|
40
41
|
}),
|
|
41
42
|
}),
|
|
42
43
|
]);
|
|
@@ -22,7 +22,7 @@ export default Capability.makeModule(() =>
|
|
|
22
22
|
component: ({ data, ref }) => <CommandsDialogContent {...data.props} ref={ref} />,
|
|
23
23
|
}),
|
|
24
24
|
Surface.create({
|
|
25
|
-
id: `${meta.id}
|
|
25
|
+
id: `${meta.id}.navigation`,
|
|
26
26
|
role: 'navigation',
|
|
27
27
|
filter: (data): data is { popoverAnchorId?: string; current: string } => typeof data.current === 'string',
|
|
28
28
|
component: ({ data, ref }) => {
|
|
@@ -36,14 +36,14 @@ export default Capability.makeModule(() =>
|
|
|
36
36
|
},
|
|
37
37
|
}),
|
|
38
38
|
Surface.create({
|
|
39
|
-
id: `${meta.id}
|
|
39
|
+
id: `${meta.id}.document-title`,
|
|
40
40
|
role: 'document-title',
|
|
41
41
|
component: ({ data }) => (
|
|
42
42
|
<NavTreeDocumentTitle node={Node.isGraphNode(data.subject) ? data.subject : undefined} />
|
|
43
43
|
),
|
|
44
44
|
}),
|
|
45
45
|
Surface.create({
|
|
46
|
-
id: `${meta.id}
|
|
46
|
+
id: `${meta.id}.search-input`,
|
|
47
47
|
role: 'search-input',
|
|
48
48
|
position: 'fallback',
|
|
49
49
|
component: () => <CommandsTrigger />,
|
|
@@ -13,7 +13,7 @@ import { Path } from '@dxos/react-ui-list';
|
|
|
13
13
|
import { meta } from '../../meta';
|
|
14
14
|
import { type NavTreeCapabilities as NC, NavTreeCapabilities } from '../../types';
|
|
15
15
|
|
|
16
|
-
const KEY = `${meta.id}
|
|
16
|
+
const KEY = `${meta.id}.state.v1`;
|
|
17
17
|
|
|
18
18
|
/** Default item state for new entries. */
|
|
19
19
|
const defaultItemState: NC.NavTreeItemState = { open: false, current: false, alternateTree: false };
|
|
@@ -132,7 +132,7 @@ const meta = {
|
|
|
132
132
|
NavTreePlugin(),
|
|
133
133
|
],
|
|
134
134
|
capabilities: () => {
|
|
135
|
-
const storyStateAtom = Atom.make({ tab: 'space-0' }).pipe(Atom.keepAlive);
|
|
135
|
+
const storyStateAtom = Atom.make({ tab: 'root/space-0' }).pipe(Atom.keepAlive);
|
|
136
136
|
return [
|
|
137
137
|
Capability.contributes(StoryState, storyStateAtom),
|
|
138
138
|
Capability.contributes(AppCapabilities.AppGraphBuilder, storybookGraphBuilders()),
|
|
@@ -6,7 +6,7 @@ import { createContext, useContext } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
8
|
|
|
9
|
-
import { type NavTreeContextValue } from '
|
|
9
|
+
import { type NavTreeContextValue } from '../types';
|
|
10
10
|
|
|
11
11
|
export const NavTreeContext = createContext<NavTreeContextValue | null>(null);
|
|
12
12
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React from 'react';
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
7
|
import { type Node } from '@dxos/app-graph';
|
|
8
8
|
import { useActionRunner } from '@dxos/plugin-graph';
|
|
@@ -15,6 +15,7 @@ import { type ActionProperties } from '../../types';
|
|
|
15
15
|
|
|
16
16
|
export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
17
17
|
parent: Node.Node;
|
|
18
|
+
path?: string[];
|
|
18
19
|
caller?: string;
|
|
19
20
|
monolithic?: boolean;
|
|
20
21
|
menuActions?: Node.Action[];
|
|
@@ -33,6 +34,7 @@ const coarseActionButtonProps = {
|
|
|
33
34
|
|
|
34
35
|
export const NavTreeItemActionDropdownMenu = ({
|
|
35
36
|
parent,
|
|
37
|
+
path,
|
|
36
38
|
label,
|
|
37
39
|
icon,
|
|
38
40
|
testId,
|
|
@@ -42,9 +44,13 @@ export const NavTreeItemActionDropdownMenu = ({
|
|
|
42
44
|
const { t } = useTranslation(meta.id);
|
|
43
45
|
const density = useDensityContext();
|
|
44
46
|
const runAction = useActionRunner();
|
|
47
|
+
const handleAction = useCallback(
|
|
48
|
+
(action: Node.Action, params: Node.InvokeProps = {}) => runAction(action, { ...params, path }),
|
|
49
|
+
[runAction, path],
|
|
50
|
+
);
|
|
45
51
|
|
|
46
52
|
return (
|
|
47
|
-
<Menu.Root caller={caller} onAction={
|
|
53
|
+
<Menu.Root caller={caller} onAction={handleAction}>
|
|
48
54
|
<Menu.Trigger asChild>
|
|
49
55
|
<IconButton
|
|
50
56
|
{...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
|
|
@@ -62,10 +68,16 @@ export const NavTreeItemActionDropdownMenu = ({
|
|
|
62
68
|
};
|
|
63
69
|
|
|
64
70
|
export const NavTreeItemMonolithicAction = (
|
|
65
|
-
props: Node.Action & {
|
|
71
|
+
props: Node.Action & {
|
|
72
|
+
parent: Node.Node;
|
|
73
|
+
path?: string[];
|
|
74
|
+
onAction?: (action: Node.Action) => void;
|
|
75
|
+
baseLabel: string;
|
|
76
|
+
},
|
|
66
77
|
) => {
|
|
67
78
|
const {
|
|
68
79
|
parent,
|
|
80
|
+
path,
|
|
69
81
|
properties: { disabled, caller, testId, icon, variant = 'ghost', iconOnly = true } = { label: 'never' },
|
|
70
82
|
baseLabel,
|
|
71
83
|
} = props;
|
|
@@ -91,22 +103,28 @@ export const NavTreeItemMonolithicAction = (
|
|
|
91
103
|
return;
|
|
92
104
|
}
|
|
93
105
|
|
|
94
|
-
void runAction(props, caller ? { parent, caller } : { parent });
|
|
106
|
+
void runAction(props, caller ? { parent, caller, path } : { parent, path });
|
|
95
107
|
}}
|
|
96
108
|
data-testid={testId}
|
|
97
109
|
/>
|
|
98
110
|
);
|
|
99
111
|
};
|
|
100
112
|
|
|
101
|
-
export const NavTreeItemAction = ({
|
|
113
|
+
export const NavTreeItemAction = ({
|
|
114
|
+
monolithic,
|
|
115
|
+
menuActions,
|
|
116
|
+
parent: node,
|
|
117
|
+
path,
|
|
118
|
+
...props
|
|
119
|
+
}: NavTreeItemActionMenuProps) => {
|
|
102
120
|
const { t } = useTranslation(meta.id);
|
|
103
121
|
|
|
104
122
|
const monolithicAction = menuActions?.length === 1 && menuActions[0];
|
|
105
123
|
const baseLabel = toLocalizedString(monolithicAction ? monolithicAction.properties!.label : props.label, t);
|
|
106
124
|
|
|
107
125
|
return monolithic && menuActions?.length === 1 ? (
|
|
108
|
-
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={node} {...menuActions[0]} />
|
|
126
|
+
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={node} path={path} {...menuActions[0]} />
|
|
109
127
|
) : (
|
|
110
|
-
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={node} menuActions={menuActions} />
|
|
128
|
+
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={node} path={path} menuActions={menuActions} />
|
|
111
129
|
);
|
|
112
130
|
};
|
|
@@ -56,7 +56,7 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
|
|
|
56
56
|
[primaryAction, groupedActions],
|
|
57
57
|
);
|
|
58
58
|
|
|
59
|
-
const ActionRoot = popoverAnchorId ===
|
|
59
|
+
const ActionRoot = popoverAnchorId === `${NAV_TREE_ITEM}:${item.id}` ? Popover.Anchor : Fragment;
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
62
|
<div role='none' className='contents dx-app-no-drag'>
|
|
@@ -67,6 +67,7 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
|
|
|
67
67
|
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
68
68
|
icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
|
|
69
69
|
parent={item}
|
|
70
|
+
path={path}
|
|
70
71
|
monolithic={Node.isAction(primaryAction)}
|
|
71
72
|
menuActions={primaryMenuActions}
|
|
72
73
|
menuType={primaryAction.properties?.menuType}
|
|
@@ -84,6 +85,7 @@ export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumns
|
|
|
84
85
|
label={t('tree item actions label')}
|
|
85
86
|
icon='ph--dots-three-vertical--regular'
|
|
86
87
|
parent={item}
|
|
88
|
+
path={path}
|
|
87
89
|
menuActions={actions}
|
|
88
90
|
menuType='dropdown'
|
|
89
91
|
caller={NAV_TREE_ITEM}
|
|
@@ -85,7 +85,7 @@ const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
|
|
|
85
85
|
switch (type) {
|
|
86
86
|
case 'action': {
|
|
87
87
|
const { properties: { caller } = {} } = item;
|
|
88
|
-
return void runAction(item as Node.Action, caller ? { parent, caller } : { parent });
|
|
88
|
+
return void runAction(item as Node.Action, caller ? { parent, path, caller } : { parent, path });
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
case 'tab':
|
|
@@ -7,9 +7,11 @@ import * as Option from 'effect/Option';
|
|
|
7
7
|
import React, { memo, useCallback, useMemo } from 'react';
|
|
8
8
|
|
|
9
9
|
import { Node } from '@dxos/app-graph';
|
|
10
|
+
import { isPinnedWorkspace } from '@dxos/app-toolkit';
|
|
10
11
|
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
11
12
|
import { Graph, useActionRunner, useConnections, useEdges } from '@dxos/plugin-graph';
|
|
12
13
|
import { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
14
|
+
import { useAttended } from '@dxos/react-ui-attention';
|
|
13
15
|
import { Tree } from '@dxos/react-ui-list';
|
|
14
16
|
import { Menu, type MenuItem } from '@dxos/react-ui-menu';
|
|
15
17
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
@@ -137,11 +139,25 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
|
|
|
137
139
|
const { t } = useTranslation(meta.id);
|
|
138
140
|
const { renderItemEnd: ItemEnd } = useNavTreeContext();
|
|
139
141
|
const title = toLocalizedString(item.properties.label, t);
|
|
140
|
-
const backCapableWorkspace = item.id
|
|
142
|
+
const backCapableWorkspace = isPinnedWorkspace(item.id);
|
|
141
143
|
|
|
142
144
|
const { primaryAction, groupedActions, menuActions, onAction } = useL1MenuActions({ item, path });
|
|
143
145
|
useLoadDescendents(item);
|
|
144
146
|
|
|
147
|
+
// TODO(wittjosiah): Hack to only show containsAttended when attended item is within alternate tree (e.g. settings).
|
|
148
|
+
// Since every object in the space is a descendant of the space node, we'd otherwise always show containsAttended.
|
|
149
|
+
const alternateTree = useAlternateTreeItem(item);
|
|
150
|
+
const attended = useAttended();
|
|
151
|
+
const alternateTreeOpen = useMemo(() => {
|
|
152
|
+
if (!alternateTree) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
const hasAlternateAttended = attended.some(
|
|
156
|
+
(attendedId) => attendedId === alternateTree.id || attendedId.startsWith(alternateTree.id + '/'),
|
|
157
|
+
);
|
|
158
|
+
return !hasAlternateAttended;
|
|
159
|
+
}, [alternateTree, attended]);
|
|
160
|
+
|
|
145
161
|
return (
|
|
146
162
|
<div className='flex w-full items-center border-b border-subdued-separator dx-app-drag dx-density-coarse pe-1'>
|
|
147
163
|
{backCapableWorkspace ? (
|
|
@@ -168,6 +184,7 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
|
|
|
168
184
|
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
169
185
|
icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
|
|
170
186
|
parent={item}
|
|
187
|
+
path={path}
|
|
171
188
|
monolithic={Node.isAction(primaryAction)}
|
|
172
189
|
menuActions={Node.isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction?.id ?? '']}
|
|
173
190
|
menuType={primaryAction.properties?.menuType}
|
|
@@ -204,7 +221,7 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
|
|
|
204
221
|
<Menu.Content group={item} items={menuActions as MenuItem[]} />
|
|
205
222
|
</Menu.Root>
|
|
206
223
|
)}
|
|
207
|
-
{ItemEnd && <ItemEnd node={item} open />}
|
|
224
|
+
{ItemEnd && <ItemEnd node={item} open={alternateTreeOpen} />}
|
|
208
225
|
</div>
|
|
209
226
|
</div>
|
|
210
227
|
);
|
|
@@ -269,10 +286,10 @@ const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>) =
|
|
|
269
286
|
}
|
|
270
287
|
setAlternateTree?.(alternatePath, !isAlternate);
|
|
271
288
|
} else {
|
|
272
|
-
void runAction(action, params);
|
|
289
|
+
void runAction(action, { ...params, path });
|
|
273
290
|
}
|
|
274
291
|
},
|
|
275
|
-
[settingsActionId, setAlternateTree, alternatePath, isAlternate, runAction, graph, alternateTree],
|
|
292
|
+
[settingsActionId, setAlternateTree, alternatePath, isAlternate, runAction, graph, alternateTree, path],
|
|
276
293
|
);
|
|
277
294
|
|
|
278
295
|
return { primaryAction, groupedActions, menuActions, onAction };
|
|
@@ -38,7 +38,7 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
38
38
|
const actionMap = new Set<string>();
|
|
39
39
|
const actions: Node.ActionLike[] = [];
|
|
40
40
|
Graph.traverse(graph, {
|
|
41
|
-
relation: 'child',
|
|
41
|
+
relation: ['child', 'action'],
|
|
42
42
|
visitor: (node, path) => {
|
|
43
43
|
if (
|
|
44
44
|
(Node.isAction(node) || Node.isActionGroup(node)) &&
|
|
@@ -71,62 +71,64 @@ export const CommandsDialogContent = forwardRef<HTMLDivElement, CommandsDialogCo
|
|
|
71
71
|
|
|
72
72
|
return (
|
|
73
73
|
<Dialog.Content ref={forwardedRef}>
|
|
74
|
-
<Dialog.Title>{t('commands dialog title', { ns: meta.id })}</Dialog.Title>
|
|
75
|
-
<
|
|
76
|
-
<SearchList.
|
|
77
|
-
<SearchList.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
<Dialog.Title srOnly>{t('commands dialog title', { ns: meta.id })}</Dialog.Title>
|
|
75
|
+
<Dialog.Body>
|
|
76
|
+
<SearchList.Root onSearch={handleSearch}>
|
|
77
|
+
<SearchList.Content>
|
|
78
|
+
<SearchList.Input placeholder={t('command list input placeholder')} />
|
|
79
|
+
<SearchList.Viewport>
|
|
80
|
+
{results.map((action) => {
|
|
81
|
+
const shortcut =
|
|
82
|
+
typeof action.properties.keyBinding === 'string'
|
|
83
|
+
? action.properties.keyBinding
|
|
84
|
+
: action.properties.keyBinding?.[getHostPlatform()];
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (Node.isActionGroup(action)) {
|
|
98
|
-
setSelected(action.id);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
86
|
+
return (
|
|
87
|
+
<SearchList.Item
|
|
88
|
+
value={action.id}
|
|
89
|
+
key={action.id}
|
|
90
|
+
label={toLocalizedString(action.properties.label, t)}
|
|
91
|
+
icon={action.properties.icon}
|
|
92
|
+
suffix={shortcut ? keySymbols(shortcut).join('') : undefined}
|
|
93
|
+
onSelect={() => {
|
|
94
|
+
if (action.properties.disabled) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
101
97
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
graph,
|
|
106
|
-
group?.id ?? action.id,
|
|
107
|
-
Node.childRelation('inbound'),
|
|
108
|
-
)[0];
|
|
109
|
-
if (node && Node.isAction(action)) {
|
|
110
|
-
void runAction(action, { parent: node, caller: KEY_BINDING });
|
|
98
|
+
if (Node.isActionGroup(action)) {
|
|
99
|
+
setSelected(action.id);
|
|
100
|
+
return;
|
|
111
101
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
102
|
+
|
|
103
|
+
invokeSync(LayoutOperation.UpdateDialog, { state: false });
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
const node = Graph.getConnections(
|
|
106
|
+
graph,
|
|
107
|
+
group?.id ?? action.id,
|
|
108
|
+
Node.childRelation('inbound'),
|
|
109
|
+
)[0];
|
|
110
|
+
if (node && Node.isAction(action)) {
|
|
111
|
+
void runAction(action, { parent: node, caller: KEY_BINDING });
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}}
|
|
115
|
+
classNames='flex items-center gap-2'
|
|
116
|
+
disabled={action.properties.disabled}
|
|
117
|
+
{...(action.properties?.testId && {
|
|
118
|
+
'data-testid': action.properties.testId,
|
|
119
|
+
})}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
})}
|
|
123
|
+
</SearchList.Viewport>
|
|
124
|
+
</SearchList.Content>
|
|
125
|
+
</SearchList.Root>
|
|
126
|
+
</Dialog.Body>
|
|
127
|
+
<Dialog.ActionBar>
|
|
126
128
|
<Dialog.Close asChild>
|
|
127
129
|
<Button classNames='w-full'>{t('close label', { ns: osTranslations })}</Button>
|
|
128
130
|
</Dialog.Close>
|
|
129
|
-
</
|
|
131
|
+
</Dialog.ActionBar>
|
|
130
132
|
</Dialog.Content>
|
|
131
133
|
);
|
|
132
134
|
},
|
|
@@ -131,7 +131,7 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
131
131
|
if (Node.isAction(node)) {
|
|
132
132
|
const [parent] = Graph.getConnections(graph, node.id, Node.childRelation('inbound'));
|
|
133
133
|
if (parent) {
|
|
134
|
-
void runAction(node, { parent, caller: NAV_TREE_ITEM });
|
|
134
|
+
void runAction(node, { parent, path, caller: NAV_TREE_ITEM });
|
|
135
135
|
}
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
@@ -177,8 +177,9 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
177
177
|
const targetNode = target.data.item as NavTreeItemGraphNode;
|
|
178
178
|
const sourcePath = source.data.path as string[];
|
|
179
179
|
const targetPath = target.data.path as string[];
|
|
180
|
+
const sameParent = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join();
|
|
180
181
|
const operation =
|
|
181
|
-
|
|
182
|
+
sameParent && instruction.type !== 'make-child'
|
|
182
183
|
? 'rearrange'
|
|
183
184
|
: resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
|
|
184
185
|
const sourceParent = getParent(graph, sourceNode, sourcePath);
|
|
@@ -207,7 +208,7 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
207
208
|
}
|
|
208
209
|
case 'transfer': {
|
|
209
210
|
const target = instruction.type === 'make-child' ? targetNode : targetParent;
|
|
210
|
-
if (!target?.properties.onTransferStart ||
|
|
211
|
+
if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) {
|
|
211
212
|
break;
|
|
212
213
|
}
|
|
213
214
|
void target?.properties.onTransferStart(sourceNode, migrationIndex);
|
package/src/containers/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { type ComponentType, lazy } from 'react';
|
|
6
6
|
|
|
7
|
-
export { NODE_TYPE } from './NavTreeContainer
|
|
7
|
+
export { NODE_TYPE } from './NavTreeContainer';
|
|
8
8
|
|
|
9
9
|
export const CommandsDialogContent: ComponentType<any> = lazy(() => import('./CommandsDialogContent'));
|
|
10
10
|
export const CommandsTrigger: ComponentType<any> = lazy(() => import('./CommandsTrigger'));
|
package/src/hooks/useActions.ts
CHANGED
|
@@ -9,30 +9,26 @@ import { Graph, Node, useActions as useGraphActions } from '@dxos/plugin-graph';
|
|
|
9
9
|
|
|
10
10
|
import { type FlattenedActions } from '../types';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Returns flattened actions and grouped sub-actions for a given graph node.
|
|
14
|
-
*/
|
|
12
|
+
/** Returns flattened actions and grouped sub-actions for a given graph node. */
|
|
15
13
|
export const useActions = (node: Node.Node): FlattenedActions => {
|
|
16
14
|
const { graph } = useAppGraph();
|
|
17
15
|
const actions = useGraphActions(graph, node.id);
|
|
18
16
|
|
|
19
|
-
return useMemo(
|
|
20
|
-
(
|
|
21
|
-
|
|
22
|
-
(
|
|
23
|
-
if (arg.properties.disposition === 'item') {
|
|
24
|
-
return acc;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
acc.actions.push(arg);
|
|
28
|
-
if (!Node.isAction(arg)) {
|
|
29
|
-
const actionGroup = Graph.getActions(graph, arg.id);
|
|
30
|
-
acc.groupedActions[arg.id] = actionGroup;
|
|
31
|
-
}
|
|
17
|
+
return useMemo(() => {
|
|
18
|
+
return actions.reduce(
|
|
19
|
+
(acc: FlattenedActions, arg) => {
|
|
20
|
+
if (arg.properties.disposition === 'item') {
|
|
32
21
|
return acc;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
acc.actions.push(arg);
|
|
25
|
+
if (!Node.isAction(arg)) {
|
|
26
|
+
const actionGroup = Graph.getActions(graph, arg.id);
|
|
27
|
+
acc.groupedActions[arg.id] = actionGroup;
|
|
28
|
+
}
|
|
29
|
+
return acc;
|
|
30
|
+
},
|
|
31
|
+
{ actions: [], groupedActions: {} },
|
|
32
|
+
);
|
|
33
|
+
}, [actions]);
|
|
38
34
|
};
|