@marimo-team/frontend 0.25.3-dev79 → 0.25.3-dev81
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/assets/{CellStatus-cD3S0wEA.js → CellStatus-DXroYLOP.js} +1 -1
- package/dist/assets/{ErrorBoundary-DJhsFCsX.js → ErrorBoundary-DaQ9THH_.js} +2 -2
- package/dist/assets/{JsonOutput-Pm6OCP3J.js → JsonOutput-VxzHyItt.js} +1 -1
- package/dist/assets/{MarimoErrorOutput-DlEjLCZ-.js → MarimoErrorOutput-D-hLaDA-.js} +1 -1
- package/dist/assets/{RenderHTML-CfQ6i3QV.js → RenderHTML-DjOEZL25.js} +1 -1
- package/dist/assets/{RunButton-DvuvkgrG.js → RunButton-CuhNTo5_.js} +1 -1
- package/dist/assets/{add-cell-with-ai-By51zSlC.js → add-cell-with-ai-BbVntTh7.js} +1 -1
- package/dist/assets/{add-connection-dialog-D7EYSraq.js → add-connection-dialog-Qf63aKV6.js} +1 -1
- package/dist/assets/{agent-panel-aCWa3Yai.js → agent-panel-DMOfF3qF.js} +1 -1
- package/dist/assets/{ai-model-dropdown-bwTRyFn4.js → ai-model-dropdown-B15l0R62.js} +2 -2
- package/dist/assets/{app-config-button-DGhsM0xw.js → app-config-button-BIMB8qjD.js} +1 -1
- package/dist/assets/{blob-e6VlOmQP.js → blob-De9GR2s6.js} +1 -1
- package/dist/assets/{cell-editor-M8dEnDzk.js → cell-editor-DFNLDjfX.js} +3 -3
- package/dist/assets/{cell-link-DFqfW-Ym.js → cell-link-DR3W2HC7.js} +1 -1
- package/dist/assets/{cells-T9_Y4Jlv.js → cells-styV7IX8.js} +6 -6
- package/dist/assets/{chat-display-DXn2Yrjr.js → chat-display-BzdYdN39.js} +1 -1
- package/dist/assets/{chat-panel-D3iUyZId.js → chat-panel-De3YzkSF.js} +1 -1
- package/dist/assets/{chat-ui-YuJtv3UJ.js → chat-ui-NTNapdtP.js} +1 -1
- package/dist/assets/{code-visibility-CV3S4xuf.js → code-visibility-csc3tgA0.js} +1 -1
- package/dist/assets/{column-preview-C6uXRJry.js → column-preview-DkH-oD8f.js} +1 -1
- package/dist/assets/{command-palette-B5H-9JMB.js → command-palette-OOQHBTnr.js} +1 -1
- package/dist/assets/{common-DeeLgjWQ.js → common-D7VAS6rd.js} +1 -1
- package/dist/assets/components-CJRBUI2s.js +1 -0
- package/dist/assets/{components-DyAF3_Nf.js → components-CNmvC781.js} +1 -1
- package/dist/assets/config-BQT0uYUo.js +1 -0
- package/dist/assets/{config-CjQ4WJnJ.js → config-BbRbT9Ww.js} +1 -1
- package/dist/assets/{datasource-gqFgG9Qd.js → datasource-C3yfeDa2.js} +1 -1
- package/dist/assets/{dependency-graph-panel-BFFxLgR6.js → dependency-graph-panel-CjoA6L0w.js} +1 -1
- package/dist/assets/{documentation-panel-BBpGbT-f.js → documentation-panel-DHWFOiG1.js} +1 -1
- package/dist/assets/{download-C8Gw-D0Y.js → download-BrCpRZKN.js} +1 -1
- package/dist/assets/{edit-page-D5LKeAwW.js → edit-page-DafDcIAI.js} +6 -6
- package/dist/assets/{error-entries-uyqOG5tg.js → error-entries-BkEAmmnD.js} +1 -1
- package/dist/assets/{error-panel-Cli5zPWi.js → error-panel-BhTfPA_i.js} +1 -1
- package/dist/assets/feedback-button-BAcClv7c.js +1 -0
- package/dist/assets/{feedback-button-CvrwBGr7.js → feedback-button-D9InK87G.js} +1 -1
- package/dist/assets/{file-explorer-panel-BSU5ultY.js → file-explorer-panel-BSd_ZbUC.js} +1 -1
- package/dist/assets/{file-name-input-CDrRlIiX.js → file-name-input-RHURglL_.js} +1 -1
- package/dist/assets/{floating-outline-GQD9km0W.js → floating-outline-Cm49rYYe.js} +1 -1
- package/dist/assets/{gallery-page-CxmV1JLF.js → gallery-page-DdMdOtdv.js} +1 -1
- package/dist/assets/{glide-data-editor-B1kpoetH.js → glide-data-editor-eiSlEUyR.js} +1 -1
- package/dist/assets/home-page-DwWvBB0R.js +1 -0
- package/dist/assets/{hooks-BrFYiTJS.js → hooks-C4GjmtQ-.js} +1 -1
- package/dist/assets/index-BdsOMJac.css +2 -0
- package/dist/assets/{index-BU1n9Awq.js → index-jR_KRDMC.js} +8 -8
- package/dist/assets/{layout-CGC8ajpe.js → layout-Bq7wRzdR.js} +3 -3
- package/dist/assets/{logs-panel-CdUc5vtA.js → logs-panel-CAAk72Gb.js} +1 -1
- package/dist/assets/{markdown-renderer-pKc_bFac.js → markdown-renderer-CAyCgogC.js} +1 -1
- package/dist/assets/{name-cell-input-csH3Cy54.js → name-cell-input-DA8hU9XT.js} +1 -1
- package/dist/assets/{outline-panel-DhsHYTuo.js → outline-panel-Cc5oQ4LL.js} +1 -1
- package/dist/assets/{packages-panel-BtkXVz3L.js → packages-panel-DTfKez6I.js} +1 -1
- package/dist/assets/{panel-accordion-state-Bco6nsUI.js → panel-accordion-state-BZHex38W.js} +1 -1
- package/dist/assets/panels-Cnu2Flfw.js +105 -0
- package/dist/assets/{process-output-B2-bT4cq.js → process-output-CrDc_O1D.js} +1 -1
- package/dist/assets/{readonly-code-display-Dsp6vWPh.js → readonly-code-display-BR-_jUj8.js} +1 -1
- package/dist/assets/{readonly-python-code-B81AjzXM.js → readonly-python-code-D7jcy9ds.js} +1 -1
- package/dist/assets/{reveal-component-Cxo3hLGA.js → reveal-component-BWu6kkxZ.js} +1 -1
- package/dist/assets/{run-page-CLP1s8uX.js → run-page-BJq9MULx.js} +1 -1
- package/dist/assets/{runtime-details-state-CznIe40L.js → runtime-details-state-hb7A1jgR.js} +1 -1
- package/dist/assets/{scratchpad-panel-yHIW63VQ.js → scratchpad-panel-OHQ7Z0RY.js} +1 -1
- package/dist/assets/{session-panel-C7-wmZhc.js → session-panel-DmDjaPsN.js} +1 -1
- package/dist/assets/{snippets-panel-BARpOPyS.js → snippets-panel-o9KL5jMi.js} +1 -1
- package/dist/assets/state-BkAqJoW7.js +3 -0
- package/dist/assets/{state-Bye6rCo4.js → state-Os7LSUUZ.js} +1 -1
- package/dist/assets/{terminal-Bhcn_y1N.js → terminal-BI85khrS.js} +1 -1
- package/dist/assets/tracing-AsNGuDsh.js +1 -0
- package/dist/assets/{tracing-panel-UKdh_YXC.js → tracing-panel-CBcmea6L.js} +2 -2
- package/dist/assets/{tree-actions-Cb-nUK1F.js → tree-actions-Cx5EDpA6.js} +1 -1
- package/dist/assets/{useAddCell-Bielffe0.js → useAddCell-uJJYtgwa.js} +1 -1
- package/dist/assets/{useBoolean-CMgj9hnq.js → useBoolean-8wlrTeus.js} +1 -1
- package/dist/assets/useCellActionButton-CmQ-OcPa.js +1 -0
- package/dist/assets/{useDeleteCell-BV4VemCv.js → useDeleteCell-CXgOCDqY.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-BEGqRiWi.js → useDependencyPanelTab-Ch6gm7uM.js} +1 -1
- package/dist/assets/{useInstallPackage-C7neMPwh.js → useInstallPackage-CYQoMdMQ.js} +1 -1
- package/dist/assets/useNotebookActions-CqXa3U6u.js +1 -0
- package/dist/assets/{useRunCells-BFeZMi7f.js → useRunCells-DAfDmOMC.js} +1 -1
- package/dist/assets/{useSplitCell-DllkNFke.js → useSplitCell-NLULgcq7.js} +1 -1
- package/dist/assets/{vega-component-D7JFthDD.js → vega-component-BKJU3uaB.js} +1 -1
- package/dist/index.html +25 -25
- package/package.json +1 -1
- package/src/components/home/components.tsx +17 -31
- package/src/components/pages/home-page.tsx +141 -89
- package/src/core/host/__tests__/notebook-client.test.ts +368 -350
- package/src/core/host/notebook-client.ts +129 -186
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +133 -59
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +152 -250
- package/src/core/websocket/transports/__tests__/notebook.test.ts +502 -0
- package/src/core/websocket/transports/notebook.ts +213 -0
- package/src/core/websocket/useNotebookClient.ts +28 -17
- package/src/css/globals.css +3 -0
- package/dist/assets/circle-play-CYIb0qT6.js +0 -1
- package/dist/assets/components-lDm0qi2t.js +0 -1
- package/dist/assets/config-DzdxZb17.js +0 -1
- package/dist/assets/feedback-button-DknbRCN_.js +0 -1
- package/dist/assets/home-page-CZ3hkD3m.js +0 -4
- package/dist/assets/index-evFWHKmM.css +0 -2
- package/dist/assets/link-NuFVR7G9.js +0 -1
- package/dist/assets/panels-D1i80TGn.js +0 -107
- package/dist/assets/state-BRYi026f.js +0 -3
- package/dist/assets/tracing-BW2ZVnXs.js +0 -1
- package/dist/assets/useCellActionButton-Cu34Zs6x.js +0 -1
- package/dist/assets/useNotebookActions-CmqOx-WZ.js +0 -1
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
GraduationCapIcon,
|
|
13
13
|
GridIcon,
|
|
14
14
|
LayoutIcon,
|
|
15
|
-
LinkIcon,
|
|
16
15
|
MessagesSquareIcon,
|
|
17
16
|
OrbitIcon,
|
|
18
17
|
PackageIcon,
|
|
@@ -82,7 +81,12 @@ export const OpenTutorialDropDown: React.FC = () => {
|
|
|
82
81
|
return (
|
|
83
82
|
<DropdownMenu>
|
|
84
83
|
<DropdownMenuTrigger asChild={true}>
|
|
85
|
-
<Button
|
|
84
|
+
<Button
|
|
85
|
+
data-testid="open-tutorial-button"
|
|
86
|
+
size="sm"
|
|
87
|
+
variant="outline"
|
|
88
|
+
className="border-border text-(--gray-11) shadow-none hover:border-(--gray-7) hover:bg-(--gray-3)"
|
|
89
|
+
>
|
|
86
90
|
<GraduationCapIcon className="w-4 h-4 mr-2" />
|
|
87
91
|
Tutorials
|
|
88
92
|
<CaretDownIcon className="w-3 h-3 ml-1" />
|
|
@@ -135,7 +139,7 @@ const RESOURCES = [
|
|
|
135
139
|
url: Constants.githubPage,
|
|
136
140
|
},
|
|
137
141
|
{
|
|
138
|
-
title: "
|
|
142
|
+
title: "Discussion",
|
|
139
143
|
description: "Join the marimo Discord community",
|
|
140
144
|
icon: MessagesSquareIcon,
|
|
141
145
|
url: Constants.discordLink,
|
|
@@ -162,9 +166,11 @@ const RESOURCES = [
|
|
|
162
166
|
|
|
163
167
|
export const ResourceLinks: React.FC = () => {
|
|
164
168
|
return (
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
169
|
+
<nav
|
|
170
|
+
aria-label="Resources"
|
|
171
|
+
className="mt-12 border-t border-border/60 pt-6"
|
|
172
|
+
>
|
|
173
|
+
<div className="flex flex-wrap items-center gap-x-6 gap-y-4">
|
|
168
174
|
{RESOURCES.map((resource) => (
|
|
169
175
|
<a
|
|
170
176
|
key={resource.title}
|
|
@@ -172,19 +178,15 @@ export const ResourceLinks: React.FC = () => {
|
|
|
172
178
|
target="_blank"
|
|
173
179
|
rel="noreferrer"
|
|
174
180
|
aria-label={`${resource.title}: ${resource.description}`}
|
|
175
|
-
|
|
181
|
+
title={resource.description}
|
|
182
|
+
className="flex items-center gap-2 rounded-sm text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
|
|
176
183
|
>
|
|
177
|
-
<resource.icon className="
|
|
178
|
-
<
|
|
179
|
-
<h3 className="font-medium">{resource.title}</h3>
|
|
180
|
-
<p className="text-sm text-muted-foreground">
|
|
181
|
-
{resource.description}
|
|
182
|
-
</p>
|
|
183
|
-
</div>
|
|
184
|
+
<resource.icon className="h-4 w-4" />
|
|
185
|
+
<span>{resource.title}</span>
|
|
184
186
|
</a>
|
|
185
187
|
))}
|
|
186
188
|
</div>
|
|
187
|
-
</
|
|
189
|
+
</nav>
|
|
188
190
|
);
|
|
189
191
|
};
|
|
190
192
|
|
|
@@ -203,19 +205,3 @@ export const TruncatedWorkspaceBanner: React.FC<{
|
|
|
203
205
|
</Banner>
|
|
204
206
|
);
|
|
205
207
|
};
|
|
206
|
-
|
|
207
|
-
export const Header: React.FC<{
|
|
208
|
-
Icon: React.FC<React.SVGProps<SVGSVGElement>>;
|
|
209
|
-
control?: React.ReactNode;
|
|
210
|
-
children: React.ReactNode;
|
|
211
|
-
}> = ({ Icon, control, children }) => {
|
|
212
|
-
return (
|
|
213
|
-
<div className="flex items-center justify-between gap-2">
|
|
214
|
-
<h2 className="flex items-center gap-2 text-xl font-semibold text-muted-foreground select-none">
|
|
215
|
-
<Icon className="h-5 w-5" />
|
|
216
|
-
{children}
|
|
217
|
-
</h2>
|
|
218
|
-
{control}
|
|
219
|
-
</div>
|
|
220
|
-
);
|
|
221
|
-
};
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { useAtom, useSetAtom } from "jotai";
|
|
4
4
|
import {
|
|
5
|
-
BookTextIcon,
|
|
6
5
|
ChevronDownIcon,
|
|
7
6
|
ChevronRightIcon,
|
|
8
7
|
ChevronsDownUpIcon,
|
|
9
|
-
ClockIcon,
|
|
10
8
|
ExternalLinkIcon,
|
|
11
|
-
|
|
9
|
+
PlusIcon,
|
|
12
10
|
PowerOffIcon,
|
|
13
11
|
RefreshCcwIcon,
|
|
14
12
|
SearchIcon,
|
|
@@ -44,6 +42,7 @@ import { Button } from "@/components/ui/button";
|
|
|
44
42
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
45
43
|
import { DropdownMenuSeparator } from "@/components/ui/dropdown-menu";
|
|
46
44
|
import { Label } from "@/components/ui/label";
|
|
45
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
47
46
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
48
47
|
import { toast } from "@/components/ui/use-toast";
|
|
49
48
|
import { getSessionId, isSessionId } from "@/core/kernel/session";
|
|
@@ -64,7 +63,6 @@ import { ConfigButton } from "../app-config/app-config-button";
|
|
|
64
63
|
import { ErrorBoundary } from "../editor/boundary/ErrorBoundary";
|
|
65
64
|
import { ShutdownButton } from "../editor/controls/shutdown-button";
|
|
66
65
|
import {
|
|
67
|
-
Header,
|
|
68
66
|
OpenTutorialDropDown,
|
|
69
67
|
ResourceLinks,
|
|
70
68
|
TruncatedWorkspaceBanner,
|
|
@@ -83,6 +81,9 @@ function tabTarget(path: string) {
|
|
|
83
81
|
return `${getSessionId()}-${encodeURIComponent(path)}`;
|
|
84
82
|
}
|
|
85
83
|
|
|
84
|
+
const NOTEBOOK_TAB_CLASS =
|
|
85
|
+
"-mb-px rounded-none border-b-2 border-transparent px-1 py-3 text-(--gray-11) transition-colors hover:text-foreground focus-visible:ring-inset focus-visible:ring-offset-0 data-[state=active]:border-(--green-11) data-[state=active]:bg-transparent data-[state=active]:text-(--green-11) data-[state=active]:shadow-none";
|
|
86
|
+
|
|
86
87
|
const HomePage: React.FC = () => {
|
|
87
88
|
const [nonce, setNonce] = useState(0);
|
|
88
89
|
const { getRecentFiles, getRunningNotebooks } = useRequestClient();
|
|
@@ -123,28 +124,75 @@ const HomePage: React.FC = () => {
|
|
|
123
124
|
setRunningNotebooks: runningResponse.setData,
|
|
124
125
|
}}
|
|
125
126
|
>
|
|
126
|
-
<div className="
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
127
|
+
<div className="min-h-screen bg-background">
|
|
128
|
+
<header className="border-b border-border/60">
|
|
129
|
+
<div className="mx-auto flex max-w-7xl items-center justify-between gap-4 px-5 py-5 sm:px-10">
|
|
130
|
+
<img src="logo.png" alt="marimo" className="w-28" />
|
|
131
|
+
<div className="flex items-center gap-3">
|
|
132
|
+
<ConfigButton showAppConfig={false} />
|
|
133
|
+
<ShutdownButton
|
|
134
|
+
description={`This will shutdown the notebook server and terminate all running notebooks (${running.size}). You'll lose all data that's in memory.`}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</header>
|
|
139
|
+
<main className="mx-auto max-w-7xl px-5 py-8 sm:px-10 sm:py-10">
|
|
140
|
+
<div className="mb-8">
|
|
141
|
+
<h1 className="text-2xl font-semibold tracking-tight">
|
|
142
|
+
Your notebooks
|
|
143
|
+
</h1>
|
|
144
|
+
<p className="mt-2 text-sm text-muted-foreground">
|
|
145
|
+
Pick up where you left off, or start something new.
|
|
146
|
+
</p>
|
|
147
|
+
<div className="mt-5 flex items-center gap-3">
|
|
148
|
+
<CreateNewNotebook />
|
|
149
|
+
<OpenTutorialDropDown />
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<Tabs defaultValue="workspace">
|
|
153
|
+
<TabsList
|
|
154
|
+
aria-label="Notebooks"
|
|
155
|
+
className="mb-5 flex h-auto w-full justify-start gap-6 rounded-none border-b border-border/70 bg-transparent p-0"
|
|
156
|
+
>
|
|
157
|
+
<TabsTrigger value="workspace" className={NOTEBOOK_TAB_CLASS}>
|
|
158
|
+
Workspace
|
|
159
|
+
</TabsTrigger>
|
|
160
|
+
<TabsTrigger value="recent" className={NOTEBOOK_TAB_CLASS}>
|
|
161
|
+
Recent
|
|
162
|
+
</TabsTrigger>
|
|
163
|
+
<TabsTrigger value="running" className={NOTEBOOK_TAB_CLASS}>
|
|
164
|
+
Running
|
|
165
|
+
<span className="ml-1.5 text-xs font-normal tabular-nums text-(--gray-11)">
|
|
166
|
+
{running.size}
|
|
167
|
+
</span>
|
|
168
|
+
</TabsTrigger>
|
|
169
|
+
</TabsList>
|
|
170
|
+
<TabsContent
|
|
171
|
+
value="workspace"
|
|
172
|
+
forceMount={true}
|
|
173
|
+
className="mt-0 data-[state=inactive]:hidden"
|
|
174
|
+
>
|
|
175
|
+
<ErrorBoundary>
|
|
176
|
+
<WorkspaceNotebooks
|
|
177
|
+
onRefreshRecents={recentsResponse.refetch}
|
|
178
|
+
/>
|
|
179
|
+
</ErrorBoundary>
|
|
180
|
+
</TabsContent>
|
|
181
|
+
<TabsContent value="recent" className="mt-0">
|
|
182
|
+
<NotebookList
|
|
183
|
+
files={recents.files}
|
|
184
|
+
emptyMessage="Notebooks you open will appear here."
|
|
185
|
+
/>
|
|
186
|
+
</TabsContent>
|
|
187
|
+
<TabsContent value="running" className="mt-0">
|
|
188
|
+
<NotebookList
|
|
189
|
+
files={[...running.values()]}
|
|
190
|
+
emptyMessage="No notebooks are running."
|
|
191
|
+
/>
|
|
192
|
+
</TabsContent>
|
|
193
|
+
</Tabs>
|
|
194
|
+
<ResourceLinks />
|
|
195
|
+
</main>
|
|
148
196
|
</div>
|
|
149
197
|
</RunningNotebooksContext>
|
|
150
198
|
</Suspense>
|
|
@@ -195,23 +243,37 @@ const WorkspaceNotebooks: React.FC<{ onRefreshRecents: () => void }> = ({
|
|
|
195
243
|
|
|
196
244
|
return (
|
|
197
245
|
<WorkspaceContext value={workspaceContextValue}>
|
|
198
|
-
<div className="flex flex-col gap-
|
|
246
|
+
<div className="flex min-w-0 flex-col gap-4">
|
|
199
247
|
{workspace.hasMore && (
|
|
200
248
|
<TruncatedWorkspaceBanner fileCount={workspace.fileCount} />
|
|
201
249
|
)}
|
|
202
|
-
<
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<div className="flex items-center gap-2">
|
|
250
|
+
<div className="overflow-hidden rounded-lg border border-border/70 bg-background">
|
|
251
|
+
<div className="flex flex-wrap items-center gap-3 border-b border-border/60 bg-muted/20 p-3">
|
|
252
|
+
<div className="min-w-40 flex-1">
|
|
206
253
|
<Input
|
|
207
254
|
id="search"
|
|
255
|
+
aria-label="Search workspace"
|
|
208
256
|
value={searchText}
|
|
209
|
-
icon={<SearchIcon size={
|
|
257
|
+
icon={<SearchIcon size={15} />}
|
|
210
258
|
onChange={(e) => setSearchText(e.target.value)}
|
|
211
|
-
placeholder="
|
|
212
|
-
className="mb-0 border-border"
|
|
259
|
+
placeholder="Find a notebook…"
|
|
260
|
+
className="mb-0 h-9 rounded-md border-border/60 bg-background font-sans shadow-none hover:shadow-none focus-visible:shadow-none"
|
|
213
261
|
/>
|
|
214
|
-
|
|
262
|
+
</div>
|
|
263
|
+
<Button
|
|
264
|
+
variant="ghost"
|
|
265
|
+
size="icon"
|
|
266
|
+
onClick={() => refetch()}
|
|
267
|
+
aria-label="Refresh workspace"
|
|
268
|
+
>
|
|
269
|
+
{isFetching ? (
|
|
270
|
+
<Spinner size="small" />
|
|
271
|
+
) : (
|
|
272
|
+
<RefreshCcwIcon className="w-4 h-4" />
|
|
273
|
+
)}
|
|
274
|
+
</Button>
|
|
275
|
+
<CollapseAllButton />
|
|
276
|
+
<div className="flex items-center gap-2">
|
|
215
277
|
<Checkbox
|
|
216
278
|
data-testid="include-markdown-checkbox"
|
|
217
279
|
id="include-markdown"
|
|
@@ -220,23 +282,14 @@ const WorkspaceNotebooks: React.FC<{ onRefreshRecents: () => void }> = ({
|
|
|
220
282
|
setIncludeMarkdown(Boolean(checked))
|
|
221
283
|
}
|
|
222
284
|
/>
|
|
223
|
-
<Label
|
|
285
|
+
<Label
|
|
286
|
+
htmlFor="include-markdown"
|
|
287
|
+
className="text-xs text-muted-foreground"
|
|
288
|
+
>
|
|
289
|
+
Include markdown
|
|
290
|
+
</Label>
|
|
224
291
|
</div>
|
|
225
|
-
|
|
226
|
-
>
|
|
227
|
-
Workspace
|
|
228
|
-
<Button
|
|
229
|
-
variant="text"
|
|
230
|
-
size="icon"
|
|
231
|
-
className="w-4 h-4 ml-1 p-0 opacity-70 hover:opacity-100"
|
|
232
|
-
onClick={() => refetch()}
|
|
233
|
-
aria-label="Refresh workspace"
|
|
234
|
-
>
|
|
235
|
-
<RefreshCcwIcon className="w-4 h-4" />
|
|
236
|
-
</Button>
|
|
237
|
-
{isFetching && <Spinner size="small" />}
|
|
238
|
-
</Header>
|
|
239
|
-
<div className="flex flex-col divide-y divide-(--slate-3) border rounded overflow-hidden max-h-192 overflow-y-auto shadow-sm bg-background">
|
|
292
|
+
</div>
|
|
240
293
|
<NotebookFileTree searchText={searchText} files={workspace.files} />
|
|
241
294
|
</div>
|
|
242
295
|
</div>
|
|
@@ -322,7 +375,7 @@ const NotebookFileTree: React.FC<{
|
|
|
322
375
|
await handleRename(id, name);
|
|
323
376
|
}}
|
|
324
377
|
padding={5}
|
|
325
|
-
rowHeight={
|
|
378
|
+
rowHeight={44}
|
|
326
379
|
indent={15}
|
|
327
380
|
overscanCount={1000}
|
|
328
381
|
// Hide the drop cursor
|
|
@@ -343,13 +396,15 @@ const Node = ({ node, style }: NodeRendererProps<FileInfo>) => {
|
|
|
343
396
|
: guessFileType(node.data.name);
|
|
344
397
|
|
|
345
398
|
const Icon = FILE_TYPE_ICONS[fileType];
|
|
346
|
-
const iconEl =
|
|
399
|
+
const iconEl = (
|
|
400
|
+
<Icon className="w-4 h-4 shrink-0 text-(--gray-11)" strokeWidth={1.5} />
|
|
401
|
+
);
|
|
347
402
|
const { root } = use(WorkspaceContext);
|
|
348
403
|
const { runningNotebooks } = use(RunningNotebooksContext);
|
|
349
404
|
|
|
350
405
|
const renderItem = () => {
|
|
351
406
|
const itemClassName =
|
|
352
|
-
"flex items-center pl-1 cursor-pointer hover:bg-
|
|
407
|
+
"flex items-center pl-1 cursor-pointer hover:bg-(--sage-3) hover:text-foreground rounded-l flex-1 overflow-hidden h-full pr-3 gap-2";
|
|
353
408
|
|
|
354
409
|
// Inline rename input; react-arborist flips `node.isEditing` when
|
|
355
410
|
// `node.edit()` is called from the FileActions menu.
|
|
@@ -413,7 +468,7 @@ const Node = ({ node, style }: NodeRendererProps<FileInfo>) => {
|
|
|
413
468
|
<div
|
|
414
469
|
style={style}
|
|
415
470
|
className={cn(
|
|
416
|
-
"flex items-center cursor-pointer ml-1 text-
|
|
471
|
+
"flex items-center cursor-pointer ml-1 text-sm text-foreground whitespace-nowrap group h-full",
|
|
417
472
|
)}
|
|
418
473
|
onClick={(evt) => {
|
|
419
474
|
evt.stopPropagation();
|
|
@@ -479,21 +534,19 @@ const FolderArrow = ({ node }: { node: NodeApi<FileInfo> }) => {
|
|
|
479
534
|
};
|
|
480
535
|
|
|
481
536
|
const NotebookList: React.FC<{
|
|
482
|
-
header: React.ReactNode;
|
|
483
537
|
files: MarimoFile[];
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
return null;
|
|
487
|
-
}
|
|
488
|
-
|
|
538
|
+
emptyMessage: string;
|
|
539
|
+
}> = ({ files, emptyMessage }) => {
|
|
489
540
|
return (
|
|
490
|
-
<div className="flex flex-col
|
|
491
|
-
{
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
541
|
+
<div className="flex max-h-[500px] min-h-40 min-w-0 flex-col divide-y divide-border/50 overflow-y-auto rounded-lg border border-border/60">
|
|
542
|
+
{files.length === 0 && (
|
|
543
|
+
<p className="px-4 py-6 text-sm text-muted-foreground">
|
|
544
|
+
{emptyMessage}
|
|
545
|
+
</p>
|
|
546
|
+
)}
|
|
547
|
+
{files.map((file) => {
|
|
548
|
+
return <MarimoFileComponent key={file.path} file={file} />;
|
|
549
|
+
})}
|
|
497
550
|
</div>
|
|
498
551
|
);
|
|
499
552
|
};
|
|
@@ -511,17 +564,19 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
|
|
|
511
564
|
: asURL(`?file=${encodeURIComponent(file.path)}`);
|
|
512
565
|
|
|
513
566
|
const isMarkdown = file.path.endsWith(".md");
|
|
567
|
+
const Icon = FILE_TYPE_ICONS[guessFileType(file.name)];
|
|
514
568
|
|
|
515
569
|
return (
|
|
516
570
|
<a
|
|
517
|
-
className="py-
|
|
571
|
+
className="py-3 px-4 hover:bg-(--sage-3) transition-colors cursor-pointer group relative flex gap-3 items-center focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
518
572
|
key={file.path}
|
|
519
573
|
href={href.toString()}
|
|
520
574
|
target={tabTarget(file.initializationId || file.path)}
|
|
521
575
|
>
|
|
522
|
-
<
|
|
523
|
-
|
|
524
|
-
|
|
576
|
+
<Icon className="h-4 w-4 shrink-0 text-(--gray-11)" strokeWidth={1.5} />
|
|
577
|
+
<div className="flex min-w-0 flex-col gap-1 flex-1">
|
|
578
|
+
<span className="flex items-center gap-2 text-sm font-medium">
|
|
579
|
+
<span className="truncate">{file.name}</span>
|
|
525
580
|
{isMarkdown && (
|
|
526
581
|
<span className="opacity-80">
|
|
527
582
|
<MarkdownIcon />
|
|
@@ -530,7 +585,7 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
|
|
|
530
585
|
</span>
|
|
531
586
|
<p
|
|
532
587
|
title={file.path}
|
|
533
|
-
className="text-
|
|
588
|
+
className="text-xs text-muted-foreground overflow-hidden whitespace-nowrap text-ellipsis"
|
|
534
589
|
>
|
|
535
590
|
{file.path}
|
|
536
591
|
</p>
|
|
@@ -541,8 +596,8 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
|
|
|
541
596
|
<SessionShutdownButton filePath={file.path} />
|
|
542
597
|
</div>
|
|
543
598
|
<ExternalLinkIcon
|
|
544
|
-
size={
|
|
545
|
-
className="group-hover:opacity-100
|
|
599
|
+
size={14}
|
|
600
|
+
className="opacity-40 group-hover:opacity-100"
|
|
546
601
|
/>
|
|
547
602
|
</div>
|
|
548
603
|
{!!file.lastModified && (
|
|
@@ -571,7 +626,8 @@ const SessionShutdownButton: React.FC<{ filePath: string }> = ({
|
|
|
571
626
|
<Button
|
|
572
627
|
size={"icon"}
|
|
573
628
|
variant="outline"
|
|
574
|
-
|
|
629
|
+
aria-label="Shutdown notebook"
|
|
630
|
+
className="border-transparent text-muted-foreground shadow-none hover:border-destructive hover:bg-(--red-1) hover:text-destructive"
|
|
575
631
|
onClick={(e) => {
|
|
576
632
|
e.stopPropagation();
|
|
577
633
|
e.preventDefault();
|
|
@@ -614,20 +670,16 @@ const SessionShutdownButton: React.FC<{ filePath: string }> = ({
|
|
|
614
670
|
const CreateNewNotebook: React.FC = () => {
|
|
615
671
|
const url = newNotebookURL();
|
|
616
672
|
return (
|
|
617
|
-
<
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
"
|
|
622
|
-
href={url}
|
|
623
|
-
target="_blank"
|
|
624
|
-
rel="noreferrer"
|
|
673
|
+
<Button
|
|
674
|
+
asChild={true}
|
|
675
|
+
size="sm"
|
|
676
|
+
className="gap-2 rounded-md border-(--brand) bg-(--brand) text-(--brand-foreground) shadow-none hover:bg-(--brand-hover)"
|
|
625
677
|
>
|
|
626
|
-
<
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
</
|
|
630
|
-
</
|
|
678
|
+
<a href={url} target="_blank" rel="noreferrer">
|
|
679
|
+
<PlusIcon className="h-4 w-4" />
|
|
680
|
+
New notebook
|
|
681
|
+
</a>
|
|
682
|
+
</Button>
|
|
631
683
|
);
|
|
632
684
|
};
|
|
633
685
|
|