@marimo-team/islands 0.18.5-dev184 → 0.18.5-dev187
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/main.js +33 -23
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/dependency-graph/dependency-graph.tsx +5 -22
- package/src/components/{editor/chrome/wrapper/minimap.tsx → dependency-graph/minimap-content.tsx} +49 -76
- package/src/components/dependency-graph/panels.tsx +4 -15
- package/src/components/dependency-graph/types.ts +0 -1
- package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +12 -5
- package/src/components/editor/chrome/state.ts +62 -24
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +36 -11
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer.tsx +9 -4
- package/src/components/editor/chrome/wrapper/minimap-state.ts +0 -2
- package/src/components/editor/chrome/wrapper/sidebar.tsx +2 -3
- package/src/components/editor/chrome/wrapper/useDependencyPanelTab.ts +16 -0
- package/src/components/editor/output/MarimoErrorOutput.tsx +2 -2
- package/src/components/terminal/hooks.ts +2 -2
- package/src/components/dependency-graph/dependency-graph-minimap.tsx +0 -197
- package/src/components/editor/chrome/wrapper/footer-items/minimap-status.tsx +0 -21
package/package.json
CHANGED
|
@@ -7,10 +7,9 @@ import { ReactFlowProvider } from "reactflow";
|
|
|
7
7
|
import type { CellId } from "@/core/cells/ids";
|
|
8
8
|
import type { CellData } from "@/core/cells/types";
|
|
9
9
|
import type { Variables } from "@/core/variables/types";
|
|
10
|
-
import { DependencyGraphMinimap } from "./dependency-graph-minimap";
|
|
11
10
|
import { DependencyGraphTree } from "./dependency-graph-tree";
|
|
12
11
|
import { GraphToolbar } from "./panels";
|
|
13
|
-
import type {
|
|
12
|
+
import type { GraphSettings, LayoutDirection } from "./types";
|
|
14
13
|
|
|
15
14
|
import "reactflow/dist/style.css";
|
|
16
15
|
import "./dependency-graph.css";
|
|
@@ -22,7 +21,7 @@ interface Props {
|
|
|
22
21
|
children?: React.ReactNode;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
const graphViewAtom = atom<
|
|
24
|
+
const graphViewAtom = atom<LayoutDirection>("TB");
|
|
26
25
|
const graphViewSettings = atom<GraphSettings>({
|
|
27
26
|
hidePureMarkdown: true,
|
|
28
27
|
});
|
|
@@ -31,20 +30,8 @@ export const DependencyGraph: React.FC<Props> = (props) => {
|
|
|
31
30
|
const [layoutDirection, setLayoutDirection] = useAtom(graphViewAtom);
|
|
32
31
|
const [settings, setSettings] = useAtom(graphViewSettings);
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<DependencyGraphMinimap {...props}>
|
|
38
|
-
<GraphToolbar
|
|
39
|
-
settings={settings}
|
|
40
|
-
onSettingsChange={setSettings}
|
|
41
|
-
view={layoutDirection}
|
|
42
|
-
onChange={setLayoutDirection}
|
|
43
|
-
/>
|
|
44
|
-
</DependencyGraphMinimap>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
return (
|
|
33
|
+
return (
|
|
34
|
+
<ReactFlowProvider key={layoutDirection}>
|
|
48
35
|
<DependencyGraphTree
|
|
49
36
|
{...props}
|
|
50
37
|
settings={settings}
|
|
@@ -57,10 +44,6 @@ export const DependencyGraph: React.FC<Props> = (props) => {
|
|
|
57
44
|
onChange={setLayoutDirection}
|
|
58
45
|
/>
|
|
59
46
|
</DependencyGraphTree>
|
|
60
|
-
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<ReactFlowProvider key={layoutDirection}>{renderGraph()}</ReactFlowProvider>
|
|
47
|
+
</ReactFlowProvider>
|
|
65
48
|
);
|
|
66
49
|
};
|
package/src/components/{editor/chrome/wrapper/minimap.tsx → dependency-graph/minimap-content.tsx}
RENAMED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { XIcon } from "lucide-react";
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
5
4
|
import * as React from "react";
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
type CellGraph,
|
|
7
|
+
cellGraphsAtom,
|
|
8
|
+
isVariableAffectedBySelectedCell,
|
|
9
|
+
} from "@/components/editor/chrome/wrapper/minimap-state";
|
|
7
10
|
import {
|
|
8
11
|
useCellActions,
|
|
9
12
|
useCellData,
|
|
@@ -13,14 +16,7 @@ import {
|
|
|
13
16
|
import { cellFocusAtom, useCellFocusActions } from "@/core/cells/focus";
|
|
14
17
|
import type { CellId } from "@/core/cells/ids";
|
|
15
18
|
import { useVariables } from "@/core/variables/state";
|
|
16
|
-
import { useHotkey } from "@/hooks/useHotkey";
|
|
17
19
|
import { cn } from "@/utils/cn";
|
|
18
|
-
import {
|
|
19
|
-
type CellGraph,
|
|
20
|
-
cellGraphsAtom,
|
|
21
|
-
isVariableAffectedBySelectedCell,
|
|
22
|
-
minimapOpenAtom,
|
|
23
|
-
} from "./minimap-state";
|
|
24
20
|
|
|
25
21
|
interface MinimapCellProps {
|
|
26
22
|
cellId: CellId;
|
|
@@ -127,72 +123,6 @@ const MinimapCell: React.FC<MinimapCellProps> = (props) => {
|
|
|
127
123
|
);
|
|
128
124
|
};
|
|
129
125
|
|
|
130
|
-
const MinimapInternal: React.FC<{
|
|
131
|
-
open: boolean;
|
|
132
|
-
setOpen: (update: boolean) => void;
|
|
133
|
-
}> = ({ open, setOpen }) => {
|
|
134
|
-
const cellIds = useCellIds();
|
|
135
|
-
const cellPositions: Record<CellId, number> = Object.fromEntries(
|
|
136
|
-
cellIds.inOrderIds.map((id, idx) => [id, idx]),
|
|
137
|
-
);
|
|
138
|
-
const columnBoundaries: number[] = [];
|
|
139
|
-
let cellCount = 0;
|
|
140
|
-
for (const [idx, column] of cellIds.getColumns().entries()) {
|
|
141
|
-
if (idx > 0) {
|
|
142
|
-
columnBoundaries.push(cellCount);
|
|
143
|
-
}
|
|
144
|
-
cellCount += column.inOrderIds.length;
|
|
145
|
-
}
|
|
146
|
-
return (
|
|
147
|
-
<div
|
|
148
|
-
className={cn(
|
|
149
|
-
"fixed top-14 right-5 z-50 bg-background/95 backdrop-blur-sm supports-backdrop-filter:bg-background/60 rounded-lg border shadow-lg w-64 flex flex-col max-h-[58vh]",
|
|
150
|
-
"motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-in-out",
|
|
151
|
-
open ? "translate-x-0" : "translate-x-[calc(100%+20px)]",
|
|
152
|
-
)}
|
|
153
|
-
>
|
|
154
|
-
<div className="flex items-center justify-between p-4 border-b">
|
|
155
|
-
<span className="text-sm font-semibold">Minimap</span>
|
|
156
|
-
<Button
|
|
157
|
-
variant="ghost"
|
|
158
|
-
size="icon"
|
|
159
|
-
className="h-6 w-6"
|
|
160
|
-
onClick={() => setOpen(false)}
|
|
161
|
-
>
|
|
162
|
-
<XIcon className="h-4 w-4" />
|
|
163
|
-
</Button>
|
|
164
|
-
</div>
|
|
165
|
-
<div className="overflow-y-auto overflow-x-hidden flex-1 scrollbar-none">
|
|
166
|
-
<div className="py-3 pl-3 pr-4 relative min-h-full">
|
|
167
|
-
{cellIds.inOrderIds.map((cellId, idx) => {
|
|
168
|
-
const isColumnBoundary = columnBoundaries.includes(idx);
|
|
169
|
-
return (
|
|
170
|
-
<React.Fragment key={cellId}>
|
|
171
|
-
{/* Subtle visual divider between nodes */}
|
|
172
|
-
{isColumnBoundary && (
|
|
173
|
-
<div
|
|
174
|
-
className="absolute left-5 w-[36px] h-px bg-(--gray-4) pointer-events-none"
|
|
175
|
-
aria-hidden="true"
|
|
176
|
-
/>
|
|
177
|
-
)}
|
|
178
|
-
<MinimapCell cellId={cellId} cellPositions={cellPositions} />
|
|
179
|
-
</React.Fragment>
|
|
180
|
-
);
|
|
181
|
-
})}
|
|
182
|
-
</div>
|
|
183
|
-
{/* Invisible element to prevent SVG overflow from affecting scroll */}
|
|
184
|
-
<div className="h-0 overflow-hidden" aria-hidden="true" />
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
);
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
export const Minimap: React.FC = () => {
|
|
191
|
-
const [open, setOpen] = useAtom(minimapOpenAtom);
|
|
192
|
-
useHotkey("global.toggleMinimap", () => setOpen((prev) => !prev));
|
|
193
|
-
return <MinimapInternal open={open} setOpen={setOpen} />;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
126
|
function codePreview(code: string): string | undefined {
|
|
197
127
|
return code.split("\n")[0].trim() || undefined;
|
|
198
128
|
}
|
|
@@ -443,3 +373,46 @@ function isNonReferenceableCell(graph: CellGraph): boolean {
|
|
|
443
373
|
graph.descendants.size === 0
|
|
444
374
|
);
|
|
445
375
|
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Minimap content component for display in the dependencies panel.
|
|
379
|
+
* Shows a scrollable list of cells with dependency visualization.
|
|
380
|
+
*/
|
|
381
|
+
export const MinimapContent: React.FC = () => {
|
|
382
|
+
const cellIds = useCellIds();
|
|
383
|
+
const cellPositions: Record<CellId, number> = Object.fromEntries(
|
|
384
|
+
cellIds.inOrderIds.map((id, idx) => [id, idx]),
|
|
385
|
+
);
|
|
386
|
+
const columnBoundaries: number[] = [];
|
|
387
|
+
let cellCount = 0;
|
|
388
|
+
for (const [idx, column] of cellIds.getColumns().entries()) {
|
|
389
|
+
if (idx > 0) {
|
|
390
|
+
columnBoundaries.push(cellCount);
|
|
391
|
+
}
|
|
392
|
+
cellCount += column.inOrderIds.length;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return (
|
|
396
|
+
<div className="overflow-y-auto overflow-x-hidden flex-1 scrollbar-none h-full max-w-80">
|
|
397
|
+
<div className="py-3 pl-3 pr-4 relative min-h-full">
|
|
398
|
+
{cellIds.inOrderIds.map((cellId, idx) => {
|
|
399
|
+
const isColumnBoundary = columnBoundaries.includes(idx);
|
|
400
|
+
return (
|
|
401
|
+
<React.Fragment key={cellId}>
|
|
402
|
+
{/* Subtle visual divider between nodes */}
|
|
403
|
+
{isColumnBoundary && (
|
|
404
|
+
<div
|
|
405
|
+
className="absolute left-5 w-[36px] h-px bg-(--gray-4) pointer-events-none"
|
|
406
|
+
aria-hidden="true"
|
|
407
|
+
/>
|
|
408
|
+
)}
|
|
409
|
+
<MinimapCell cellId={cellId} cellPositions={cellPositions} />
|
|
410
|
+
</React.Fragment>
|
|
411
|
+
);
|
|
412
|
+
})}
|
|
413
|
+
</div>
|
|
414
|
+
{/* Invisible element to prevent SVG overflow from affecting scroll */}
|
|
415
|
+
<div className="h-0 overflow-hidden" aria-hidden="true" />
|
|
416
|
+
</div>
|
|
417
|
+
);
|
|
418
|
+
};
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
ArrowRightToLineIcon,
|
|
7
7
|
MoreVerticalIcon,
|
|
8
8
|
NetworkIcon,
|
|
9
|
-
Rows3Icon,
|
|
10
9
|
SettingsIcon,
|
|
11
10
|
SquareFunction,
|
|
12
11
|
WorkflowIcon,
|
|
@@ -26,11 +25,11 @@ import { Checkbox } from "../ui/checkbox";
|
|
|
26
25
|
import { Label } from "../ui/label";
|
|
27
26
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
28
27
|
import { VariableName } from "../variables/common";
|
|
29
|
-
import type {
|
|
28
|
+
import type { GraphSelection, GraphSettings, LayoutDirection } from "./types";
|
|
30
29
|
|
|
31
30
|
interface Props {
|
|
32
|
-
view:
|
|
33
|
-
onChange: (view:
|
|
31
|
+
view: LayoutDirection;
|
|
32
|
+
onChange: (view: LayoutDirection) => void;
|
|
34
33
|
settings: GraphSettings;
|
|
35
34
|
onSettingsChange: (settings: GraphSettings) => void;
|
|
36
35
|
}
|
|
@@ -73,16 +72,6 @@ export const GraphToolbar: React.FC<Props> = memo(
|
|
|
73
72
|
return (
|
|
74
73
|
<Panel position="top-right" className="flex flex-col items-end gap-2">
|
|
75
74
|
<div className="flex gap-2">
|
|
76
|
-
<Button
|
|
77
|
-
variant="outline"
|
|
78
|
-
className="bg-background"
|
|
79
|
-
aria-selected={view === "_minimap_"}
|
|
80
|
-
size="xs"
|
|
81
|
-
onClick={() => onChange("_minimap_")}
|
|
82
|
-
>
|
|
83
|
-
<Rows3Icon className="w-4 h-4 mr-1" />
|
|
84
|
-
Mini Map
|
|
85
|
-
</Button>
|
|
86
75
|
<Button
|
|
87
76
|
variant="outline"
|
|
88
77
|
className="bg-background"
|
|
@@ -104,7 +93,7 @@ export const GraphToolbar: React.FC<Props> = memo(
|
|
|
104
93
|
Horizontal Tree
|
|
105
94
|
</Button>
|
|
106
95
|
</div>
|
|
107
|
-
{
|
|
96
|
+
{settingsButton}
|
|
108
97
|
</Panel>
|
|
109
98
|
);
|
|
110
99
|
},
|
|
@@ -5,19 +5,26 @@ import { useCellDataAtoms, useCellIds } from "@/core/cells/cells";
|
|
|
5
5
|
import { useVariables } from "@/core/variables/state";
|
|
6
6
|
import { cn } from "@/utils/cn";
|
|
7
7
|
import { DependencyGraph } from "../../../dependency-graph/dependency-graph";
|
|
8
|
+
import { MinimapContent } from "../../../dependency-graph/minimap-content";
|
|
9
|
+
import { useDependencyPanelTab } from "../wrapper/useDependencyPanelTab";
|
|
8
10
|
|
|
9
11
|
const DependencyGraphPanel: React.FC = () => {
|
|
12
|
+
const { dependencyPanelTab } = useDependencyPanelTab();
|
|
10
13
|
const variables = useVariables();
|
|
11
14
|
const cellIds = useCellIds();
|
|
12
15
|
const [cells] = useCellDataAtoms();
|
|
13
16
|
|
|
14
17
|
return (
|
|
15
18
|
<div className={cn("w-full h-full flex-1 mx-auto -mb-4 relative")}>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
{dependencyPanelTab === "minimap" ? (
|
|
20
|
+
<MinimapContent />
|
|
21
|
+
) : (
|
|
22
|
+
<DependencyGraph
|
|
23
|
+
cellAtoms={cells}
|
|
24
|
+
variables={variables}
|
|
25
|
+
cellIds={cellIds.inOrderIds}
|
|
26
|
+
/>
|
|
27
|
+
)}
|
|
21
28
|
</div>
|
|
22
29
|
);
|
|
23
30
|
};
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
4
|
import { atomWithStorage } from "jotai/utils";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { store } from "@/core/state/jotai";
|
|
6
7
|
import { createReducerAndAtoms } from "@/utils/createReducer";
|
|
7
8
|
import { jotaiJsonStorage } from "@/utils/storage/jotai";
|
|
8
9
|
import { ZodLocalStorage } from "@/utils/storage/typed";
|
|
9
|
-
import type { PanelType } from "./types";
|
|
10
|
+
import type { PanelSection, PanelType } from "./types";
|
|
10
11
|
import { isPanelHidden, PANELS } from "./types";
|
|
11
12
|
|
|
12
13
|
export interface ChromeState {
|
|
@@ -41,6 +42,20 @@ export const panelLayoutAtom = atomWithStorage<PanelLayout>(
|
|
|
41
42
|
{ getOnInit: true },
|
|
42
43
|
);
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Resolve which section a panel belongs to based on current layout.
|
|
47
|
+
*/
|
|
48
|
+
function resolvePanelLocation(panelType: PanelType): PanelSection | null {
|
|
49
|
+
const layout = store.get(panelLayoutAtom);
|
|
50
|
+
if (layout.sidebar.includes(panelType)) {
|
|
51
|
+
return "sidebar";
|
|
52
|
+
}
|
|
53
|
+
if (layout.developerPanel.includes(panelType)) {
|
|
54
|
+
return "developer-panel";
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
const KEY = "marimo:sidebar";
|
|
45
60
|
const storage = new ZodLocalStorage<ChromeState>(
|
|
46
61
|
z.object({
|
|
@@ -76,20 +91,52 @@ const {
|
|
|
76
91
|
} = createReducerAndAtoms(
|
|
77
92
|
() => storage.get(KEY),
|
|
78
93
|
{
|
|
79
|
-
openApplication: (state, selectedPanel: PanelType) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
openApplication: (state, selectedPanel: PanelType) => {
|
|
95
|
+
const location = resolvePanelLocation(selectedPanel);
|
|
96
|
+
if (location === "sidebar") {
|
|
97
|
+
return {
|
|
98
|
+
...state,
|
|
99
|
+
selectedPanel,
|
|
100
|
+
isSidebarOpen: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (location === "developer-panel") {
|
|
104
|
+
return {
|
|
105
|
+
...state,
|
|
106
|
+
selectedDeveloperPanelTab: selectedPanel,
|
|
107
|
+
isDeveloperPanelOpen: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Panel not found in layout, no-op
|
|
111
|
+
return state;
|
|
112
|
+
},
|
|
113
|
+
toggleApplication: (state, selectedPanel: PanelType) => {
|
|
114
|
+
const location = resolvePanelLocation(selectedPanel);
|
|
115
|
+
if (location === "sidebar") {
|
|
116
|
+
return {
|
|
117
|
+
...state,
|
|
118
|
+
selectedPanel,
|
|
119
|
+
// If it was closed, open it
|
|
120
|
+
// If it was open, keep it open unless it was the same application
|
|
121
|
+
isSidebarOpen: state.isSidebarOpen
|
|
122
|
+
? state.selectedPanel !== selectedPanel
|
|
123
|
+
: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (location === "developer-panel") {
|
|
127
|
+
return {
|
|
128
|
+
...state,
|
|
129
|
+
selectedDeveloperPanelTab: selectedPanel,
|
|
130
|
+
// If it was closed, open it
|
|
131
|
+
// If it was open, keep it open unless it was the same tab
|
|
132
|
+
isDeveloperPanelOpen: state.isDeveloperPanelOpen
|
|
133
|
+
? state.selectedDeveloperPanelTab !== selectedPanel
|
|
134
|
+
: true,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Panel not found in layout, no-op
|
|
138
|
+
return state;
|
|
139
|
+
},
|
|
93
140
|
toggleSidebarPanel: (state) => ({
|
|
94
141
|
...state,
|
|
95
142
|
isSidebarOpen: !state.isSidebarOpen,
|
|
@@ -106,15 +153,6 @@ const {
|
|
|
106
153
|
...state,
|
|
107
154
|
isDeveloperPanelOpen: isOpen,
|
|
108
155
|
}),
|
|
109
|
-
setSelectedDeveloperPanelTab: (state, tab: PanelType) => ({
|
|
110
|
-
...state,
|
|
111
|
-
selectedDeveloperPanelTab: tab,
|
|
112
|
-
}),
|
|
113
|
-
openDeveloperPanelTab: (state, tab: PanelType) => ({
|
|
114
|
-
...state,
|
|
115
|
-
isDeveloperPanelOpen: true,
|
|
116
|
-
selectedDeveloperPanelTab: tab,
|
|
117
|
-
}),
|
|
118
156
|
},
|
|
119
157
|
[(_prevState, newState) => storage.set(KEY, newState)],
|
|
120
158
|
);
|
|
@@ -35,10 +35,10 @@ import {
|
|
|
35
35
|
type PanelDescriptor,
|
|
36
36
|
} from "../types";
|
|
37
37
|
import { BackendConnectionStatus } from "./footer-items/backend-status";
|
|
38
|
-
import { Minimap } from "./minimap";
|
|
39
38
|
import { PanelsWrapper } from "./panels";
|
|
40
39
|
import { PendingAICells } from "./pending-ai-cells";
|
|
41
40
|
import { useAiPanelTab } from "./useAiPanel";
|
|
41
|
+
import { useDependencyPanelTab } from "./useDependencyPanelTab";
|
|
42
42
|
import { handleDragging } from "./utils";
|
|
43
43
|
|
|
44
44
|
const LazyTerminal = React.lazy(() => import("@/components/terminal/terminal"));
|
|
@@ -75,15 +75,12 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
75
75
|
selectedPanel,
|
|
76
76
|
selectedDeveloperPanelTab,
|
|
77
77
|
} = useChromeState();
|
|
78
|
-
const {
|
|
79
|
-
|
|
80
|
-
setIsDeveloperPanelOpen,
|
|
81
|
-
setSelectedDeveloperPanelTab,
|
|
82
|
-
openApplication,
|
|
83
|
-
} = useChromeActions();
|
|
78
|
+
const { setIsSidebarOpen, setIsDeveloperPanelOpen, openApplication } =
|
|
79
|
+
useChromeActions();
|
|
84
80
|
const sidebarRef = React.useRef<ImperativePanelHandle>(null);
|
|
85
81
|
const developerPanelRef = React.useRef<ImperativePanelHandle>(null);
|
|
86
82
|
const { aiPanelTab, setAiPanelTab } = useAiPanelTab();
|
|
83
|
+
const { dependencyPanelTab, setDependencyPanelTab } = useDependencyPanelTab();
|
|
87
84
|
const errorCount = useAtomValue(cellErrorCount);
|
|
88
85
|
const [panelLayout, setPanelLayout] = useAtom(panelLayoutAtom);
|
|
89
86
|
|
|
@@ -122,7 +119,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
122
119
|
}
|
|
123
120
|
|
|
124
121
|
// Select the dropped item in developer panel
|
|
125
|
-
|
|
122
|
+
openApplication(item.type);
|
|
126
123
|
};
|
|
127
124
|
|
|
128
125
|
// Get panels available for developer panel context menu
|
|
@@ -231,7 +228,36 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
231
228
|
<PanelSectionProvider value="sidebar">
|
|
232
229
|
<div className="flex flex-col h-full flex-1 overflow-hidden mr-[-4px]">
|
|
233
230
|
<div className="p-3 border-b flex justify-between items-center">
|
|
234
|
-
{selectedPanel === "
|
|
231
|
+
{selectedPanel === "dependencies" ? (
|
|
232
|
+
<div className="flex items-center justify-between flex-1">
|
|
233
|
+
<span className="text-sm text-(--slate-11) uppercase tracking-wide font-semibold">
|
|
234
|
+
Dependencies
|
|
235
|
+
</span>
|
|
236
|
+
<Tabs
|
|
237
|
+
value={dependencyPanelTab}
|
|
238
|
+
onValueChange={(value) => {
|
|
239
|
+
if (value === "minimap" || value === "graph") {
|
|
240
|
+
setDependencyPanelTab(value);
|
|
241
|
+
}
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
<TabsList>
|
|
245
|
+
<TabsTrigger
|
|
246
|
+
value="minimap"
|
|
247
|
+
className="py-0.5 text-xs uppercase tracking-wide font-bold"
|
|
248
|
+
>
|
|
249
|
+
Minimap
|
|
250
|
+
</TabsTrigger>
|
|
251
|
+
<TabsTrigger
|
|
252
|
+
value="graph"
|
|
253
|
+
className="py-0.5 text-xs uppercase tracking-wide font-bold"
|
|
254
|
+
>
|
|
255
|
+
Graph
|
|
256
|
+
</TabsTrigger>
|
|
257
|
+
</TabsList>
|
|
258
|
+
</Tabs>
|
|
259
|
+
</div>
|
|
260
|
+
) : selectedPanel === "ai" && agentsEnabled ? (
|
|
235
261
|
<Tabs
|
|
236
262
|
value={aiPanelTab}
|
|
237
263
|
onValueChange={(value) => {
|
|
@@ -382,7 +408,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
382
408
|
ariaLabel="Developer panel tabs"
|
|
383
409
|
className="flex flex-row gap-1"
|
|
384
410
|
minItems={0}
|
|
385
|
-
onAction={(panel) =>
|
|
411
|
+
onAction={(panel) => openApplication(panel.type)}
|
|
386
412
|
renderItem={(panel) => (
|
|
387
413
|
<div
|
|
388
414
|
className={cn(
|
|
@@ -481,7 +507,6 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
481
507
|
</Panel>
|
|
482
508
|
<ContextAwarePanel />
|
|
483
509
|
</PanelGroup>
|
|
484
|
-
<Minimap />
|
|
485
510
|
<PendingAICells />
|
|
486
511
|
<ErrorBoundary>
|
|
487
512
|
<TooltipProvider>
|
|
@@ -18,13 +18,14 @@ import {
|
|
|
18
18
|
} from "./footer-items/backend-status";
|
|
19
19
|
import { CopilotStatusIcon } from "./footer-items/copilot-status";
|
|
20
20
|
import { MachineStats } from "./footer-items/machine-stats";
|
|
21
|
-
import { MinimapStatusIcon } from "./footer-items/minimap-status";
|
|
22
21
|
import { RTCStatus } from "./footer-items/rtc-status";
|
|
23
22
|
import { RuntimeSettings } from "./footer-items/runtime-settings";
|
|
23
|
+
import { useSetDependencyPanelTab } from "./useDependencyPanelTab";
|
|
24
24
|
|
|
25
25
|
export const Footer: React.FC = () => {
|
|
26
26
|
const { isDeveloperPanelOpen } = useChromeState();
|
|
27
|
-
const { toggleDeveloperPanel } = useChromeActions();
|
|
27
|
+
const { toggleDeveloperPanel, toggleApplication } = useChromeActions();
|
|
28
|
+
const setDependencyPanelTab = useSetDependencyPanelTab();
|
|
28
29
|
|
|
29
30
|
const errorCount = useAtomValue(cellErrorCount);
|
|
30
31
|
const connectionStatus = useAtomValue(connectionStatusAtom);
|
|
@@ -39,13 +40,18 @@ export const Footer: React.FC = () => {
|
|
|
39
40
|
const warningCount = 0;
|
|
40
41
|
|
|
41
42
|
useHotkey("global.toggleTerminal", () => {
|
|
42
|
-
|
|
43
|
+
toggleApplication("terminal");
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
useHotkey("global.togglePanel", () => {
|
|
46
47
|
toggleDeveloperPanel();
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
useHotkey("global.toggleMinimap", () => {
|
|
51
|
+
toggleApplication("dependencies");
|
|
52
|
+
setDependencyPanelTab("minimap");
|
|
53
|
+
});
|
|
54
|
+
|
|
49
55
|
return (
|
|
50
56
|
<footer className="h-10 py-1 gap-1 bg-background flex items-center text-muted-foreground text-md pl-2 pr-1 border-t border-border select-none no-print text-sm z-50 print:hidden hide-on-fullscreen overflow-x-auto overflow-y-hidden scrollbar-thin">
|
|
51
57
|
<FooterItem
|
|
@@ -92,7 +98,6 @@ export const Footer: React.FC = () => {
|
|
|
92
98
|
|
|
93
99
|
<div className="flex items-center shrink-0 min-w-0">
|
|
94
100
|
<MachineStats />
|
|
95
|
-
<MinimapStatusIcon />
|
|
96
101
|
<AIStatusIcon />
|
|
97
102
|
<CopilotStatusIcon />
|
|
98
103
|
<RTCStatus />
|
|
@@ -6,8 +6,6 @@ import type { CellId } from "@/core/cells/ids";
|
|
|
6
6
|
import { variablesAtom } from "@/core/variables/state";
|
|
7
7
|
import type { Variable, VariableName, Variables } from "@/core/variables/types";
|
|
8
8
|
|
|
9
|
-
export const minimapOpenAtom = atom(false);
|
|
10
|
-
|
|
11
9
|
export interface CellGraph {
|
|
12
10
|
variables: readonly VariableName[];
|
|
13
11
|
|
|
@@ -20,8 +20,7 @@ import {
|
|
|
20
20
|
|
|
21
21
|
export const Sidebar: React.FC = () => {
|
|
22
22
|
const { selectedPanel, selectedDeveloperPanelTab } = useChromeState();
|
|
23
|
-
const { toggleApplication,
|
|
24
|
-
useChromeActions();
|
|
23
|
+
const { toggleApplication, openApplication } = useChromeActions();
|
|
25
24
|
const [panelLayout, setPanelLayout] = useAtom(panelLayoutAtom);
|
|
26
25
|
|
|
27
26
|
const renderIcon = ({ Icon }: PanelDescriptor, className?: string) => {
|
|
@@ -73,7 +72,7 @@ export const Sidebar: React.FC = () => {
|
|
|
73
72
|
(id) => id !== item.type,
|
|
74
73
|
);
|
|
75
74
|
if (remainingDevPanels.length > 0) {
|
|
76
|
-
|
|
75
|
+
openApplication(remainingDevPanels[0]);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
78
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { atom, useAtom, useSetAtom } from "jotai";
|
|
4
|
+
|
|
5
|
+
export const dependencyPanelTabAtom = atom<"minimap" | "graph">("minimap");
|
|
6
|
+
|
|
7
|
+
export function useDependencyPanelTab() {
|
|
8
|
+
const [dependencyPanelTab, setDependencyPanelTab] = useAtom(
|
|
9
|
+
dependencyPanelTabAtom,
|
|
10
|
+
);
|
|
11
|
+
return { dependencyPanelTab, setDependencyPanelTab };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useSetDependencyPanelTab() {
|
|
15
|
+
return useSetAtom(dependencyPanelTabAtom);
|
|
16
|
+
}
|
|
@@ -142,7 +142,7 @@ export const MarimoErrorOutput = ({
|
|
|
142
142
|
);
|
|
143
143
|
|
|
144
144
|
const openScratchpad = () => {
|
|
145
|
-
chromeActions.
|
|
145
|
+
chromeActions.openApplication("scratchpad");
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
const renderMessages = () => {
|
|
@@ -186,7 +186,7 @@ export const MarimoErrorOutput = ({
|
|
|
186
186
|
size="xs"
|
|
187
187
|
variant="outline"
|
|
188
188
|
className="mt-2 font-normal"
|
|
189
|
-
onClick={() => chromeActions.
|
|
189
|
+
onClick={() => chromeActions.openApplication("terminal")}
|
|
190
190
|
>
|
|
191
191
|
<TerminalIcon className="h-3.5 w-3.5 mr-1.5" />
|
|
192
192
|
<span>Open terminal</span>
|
|
@@ -25,11 +25,11 @@ import { useTerminalActions } from "./state";
|
|
|
25
25
|
*/
|
|
26
26
|
export function useTerminalCommands() {
|
|
27
27
|
const { addCommand } = useTerminalActions();
|
|
28
|
-
const {
|
|
28
|
+
const { openApplication } = useChromeActions();
|
|
29
29
|
|
|
30
30
|
const sendCommand = (text: string) => {
|
|
31
31
|
// First, ensure the terminal is open
|
|
32
|
-
|
|
32
|
+
openApplication("terminal");
|
|
33
33
|
|
|
34
34
|
// Add the command to the queue
|
|
35
35
|
addCommand(text);
|