@marimo-team/islands 0.24.1-dev87 → 0.24.1-dev90
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/{chat-ui-DpE4Aa_M.js → chat-ui-BqDoKana.js} +5 -5
- package/dist/{common-Csjs6-Cq.js → common-FuL_5-mY.js} +14 -14
- package/dist/{formats-CMBaNtI6.js → formats-nPPeLOk2.js} +1 -1
- package/dist/{html-to-image-LGo891lC.js → html-to-image-BMTAw0YV.js} +3579 -3580
- package/dist/main.js +5830 -5816
- package/dist/{process-output-BMotjkzK.js → process-output-JALCTHOK.js} +1 -1
- package/dist/{reveal-component-t0AuZBu7.js → reveal-component-e4yYomxA.js} +2 -2
- package/dist/{toDate-BbnMXiIl.js → toDate-DfFzRDkN.js} +1 -1
- package/dist/{vega-component-Cid89pdp.js → vega-component-PYsP9Jod.js} +11 -11
- package/package.json +1 -1
- package/src/components/editor/output/__tests__/ansi-reduce.test.ts +36 -10
- package/src/components/editor/output/ansi-reduce.ts +2 -7
- package/src/components/editor/renderers/vertical-layout/__tests__/vertical-layout.test.ts +64 -2
- package/src/components/editor/renderers/vertical-layout/utils.ts +73 -0
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +19 -49
- package/src/components/static-html/__tests__/static-banner.test.tsx +112 -0
- package/src/components/static-html/static-banner.tsx +121 -68
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +35 -2
|
@@ -13,6 +13,9 @@ import { isStaticNotebook } from "@/core/static/static-state";
|
|
|
13
13
|
import { createShareableLink } from "@/core/wasm/share";
|
|
14
14
|
import { copyToClipboard } from "@/utils/copy";
|
|
15
15
|
import { downloadBlob } from "@/utils/download";
|
|
16
|
+
import { Paths } from "@/utils/paths";
|
|
17
|
+
import { shellQuote } from "@/utils/shell";
|
|
18
|
+
import { MarimoPlusIcon } from "../icons/marimo-icons";
|
|
16
19
|
import { Button } from "../ui/button";
|
|
17
20
|
import {
|
|
18
21
|
Dialog,
|
|
@@ -22,8 +25,8 @@ import {
|
|
|
22
25
|
DialogTitle,
|
|
23
26
|
DialogTrigger,
|
|
24
27
|
} from "../ui/dialog";
|
|
28
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
|
|
25
29
|
import { toast } from "../ui/use-toast";
|
|
26
|
-
import { MarimoPlusIcon } from "../icons/marimo-icons";
|
|
27
30
|
|
|
28
31
|
export const StaticBanner: React.FC = () => {
|
|
29
32
|
const code = useAtomValue(codeAtom);
|
|
@@ -60,21 +63,14 @@ export const StaticBanner: React.FC = () => {
|
|
|
60
63
|
};
|
|
61
64
|
|
|
62
65
|
const StaticBannerDialog = ({ code }: { code: string }) => {
|
|
63
|
-
|
|
64
|
-
// Trim the path
|
|
65
|
-
const lastSlash = filename.lastIndexOf("/");
|
|
66
|
-
if (lastSlash !== -1) {
|
|
67
|
-
filename = filename.slice(lastSlash + 1);
|
|
68
|
-
}
|
|
66
|
+
const filename = Paths.basename(useFilename() || "notebook.py");
|
|
69
67
|
|
|
70
68
|
const [resolvedConfig] = useResolvedMarimoConfig();
|
|
71
|
-
const molabEnabled = resolvedConfig.sharing?.molab
|
|
69
|
+
const molabEnabled = resolvedConfig.sharing?.molab ?? true;
|
|
72
70
|
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
baseUrl: `${Constants.molab}/new`,
|
|
77
|
-
});
|
|
71
|
+
const runTarget = getStaticNotebookRunTarget(window.location.href, filename);
|
|
72
|
+
const runsFromUrl = runTarget !== filename;
|
|
73
|
+
const quotedRunTarget = shellQuote(runTarget);
|
|
78
74
|
|
|
79
75
|
return (
|
|
80
76
|
<Dialog>
|
|
@@ -90,62 +86,46 @@ const StaticBannerDialog = ({ code }: { code: string }) => {
|
|
|
90
86
|
<DialogContent>
|
|
91
87
|
<DialogHeader>
|
|
92
88
|
<DialogTitle>{filename}</DialogTitle>
|
|
93
|
-
<DialogDescription
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
marimo
|
|
102
|
-
</a>{" "}
|
|
103
|
-
notebook. To run interactively:
|
|
104
|
-
</p>
|
|
105
|
-
|
|
106
|
-
<div className="rounded-lg p-3 border bg-(--sky-2) border-(--sky-7)">
|
|
107
|
-
<div className="font-mono text-(--sky-11) leading-relaxed">
|
|
108
|
-
pip install marimo
|
|
109
|
-
<br />
|
|
110
|
-
marimo edit {filename}
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
|
|
114
|
-
{!href.endsWith(".html") && (
|
|
115
|
-
<div className="rounded-lg p-3 border bg-(--sky-2) border-(--sky-7)">
|
|
116
|
-
<div className="text-sm text-(--sky-12) mb-1">
|
|
117
|
-
Or run directly from URL:
|
|
118
|
-
</div>
|
|
119
|
-
<div className="font-mono text-(--sky-11) break-all">
|
|
120
|
-
marimo edit {window.location.href}
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
)}
|
|
124
|
-
|
|
125
|
-
{molabEnabled && (
|
|
126
|
-
<div className="pt-3 border-t flex gap-2 items-center">
|
|
127
|
-
<Button
|
|
128
|
-
asChild={true}
|
|
129
|
-
variant="outline"
|
|
130
|
-
size="xs"
|
|
131
|
-
className="shrink-0"
|
|
89
|
+
<DialogDescription asChild={true}>
|
|
90
|
+
<div className="pt-3 text-left space-y-3">
|
|
91
|
+
<p>
|
|
92
|
+
This is a static{" "}
|
|
93
|
+
<a
|
|
94
|
+
href={Constants.githubPage}
|
|
95
|
+
target="_blank"
|
|
96
|
+
className="text-(--sky-11) hover:underline font-medium"
|
|
132
97
|
>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
98
|
+
marimo
|
|
99
|
+
</a>{" "}
|
|
100
|
+
notebook. {runsFromUrl ? "Run it" : "Download it, then run it"}{" "}
|
|
101
|
+
locally for full interactivity.
|
|
102
|
+
</p>
|
|
103
|
+
|
|
104
|
+
<Tabs defaultValue="uv">
|
|
105
|
+
<TabsList aria-label="Package manager">
|
|
106
|
+
<TabsTrigger value="uv">uv</TabsTrigger>
|
|
107
|
+
<TabsTrigger value="pip">pip</TabsTrigger>
|
|
108
|
+
<TabsTrigger value="conda">conda</TabsTrigger>
|
|
109
|
+
</TabsList>
|
|
110
|
+
<TabsContent value="uv">
|
|
111
|
+
<CommandBlock
|
|
112
|
+
command={`uvx marimo edit --sandbox ${quotedRunTarget}`}
|
|
113
|
+
/>
|
|
114
|
+
</TabsContent>
|
|
115
|
+
<TabsContent value="pip">
|
|
116
|
+
<CommandBlock
|
|
117
|
+
command={`pip install marimo\nmarimo edit ${quotedRunTarget}`}
|
|
118
|
+
/>
|
|
119
|
+
</TabsContent>
|
|
120
|
+
<TabsContent value="conda">
|
|
121
|
+
<CommandBlock
|
|
122
|
+
command={`conda install -c conda-forge marimo\nmarimo edit ${quotedRunTarget}`}
|
|
123
|
+
/>
|
|
124
|
+
</TabsContent>
|
|
125
|
+
</Tabs>
|
|
126
|
+
|
|
127
|
+
{molabEnabled && <MolabCallout code={code} />}
|
|
128
|
+
</div>
|
|
149
129
|
</DialogDescription>
|
|
150
130
|
</DialogHeader>
|
|
151
131
|
<div className="flex gap-3 pt-2">
|
|
@@ -177,3 +157,76 @@ const StaticBannerDialog = ({ code }: { code: string }) => {
|
|
|
177
157
|
</Dialog>
|
|
178
158
|
);
|
|
179
159
|
};
|
|
160
|
+
|
|
161
|
+
/** Keep this in sync with StaticNotebookReader in marimo/_cli/files/file_path.py. */
|
|
162
|
+
export function getStaticNotebookRunTarget(
|
|
163
|
+
href: string,
|
|
164
|
+
filename: string,
|
|
165
|
+
): string {
|
|
166
|
+
const url = new URL(href);
|
|
167
|
+
const isHttp = url.protocol === "http:" || url.protocol === "https:";
|
|
168
|
+
if (!isHttp) {
|
|
169
|
+
return filename;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const isHtmlFile = url.pathname.endsWith(".html") && url.search === "";
|
|
173
|
+
const matchesSupportedUrlPattern =
|
|
174
|
+
url.protocol === "https:" &&
|
|
175
|
+
(url.hostname === "marimo.app" ||
|
|
176
|
+
url.hostname === "links.marimo.app" ||
|
|
177
|
+
(url.hostname === "static.marimo.app" &&
|
|
178
|
+
url.pathname.startsWith("/static")) ||
|
|
179
|
+
url.pathname.includes("/notebooks/nb"));
|
|
180
|
+
if (!isHtmlFile && !matchesSupportedUrlPattern) {
|
|
181
|
+
return filename;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
url.hash = "";
|
|
185
|
+
return url.href;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const CommandBlock = ({ command }: { command: string }) => (
|
|
189
|
+
<div className="relative rounded-lg border bg-(--sky-2) border-(--sky-7)">
|
|
190
|
+
<pre className="p-3 pr-10 font-mono text-(--sky-11) leading-relaxed whitespace-pre-wrap break-all">
|
|
191
|
+
{command}
|
|
192
|
+
</pre>
|
|
193
|
+
<Button
|
|
194
|
+
aria-label="Copy command"
|
|
195
|
+
className="absolute right-2 top-2"
|
|
196
|
+
variant="ghost"
|
|
197
|
+
size="icon"
|
|
198
|
+
onClick={async () => {
|
|
199
|
+
await copyToClipboard(command);
|
|
200
|
+
toast({ title: "Command copied to clipboard" });
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<CopyIcon className="w-3.5 h-3.5" />
|
|
204
|
+
</Button>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const MolabCallout = ({ code }: { code: string }) => {
|
|
209
|
+
const molabLink = createShareableLink({
|
|
210
|
+
code,
|
|
211
|
+
baseUrl: `${Constants.molab}/new`,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<div className="pt-3 border-t flex gap-2 items-center">
|
|
216
|
+
<Button asChild={true} variant="outline" size="xs" className="shrink-0">
|
|
217
|
+
<a href={molabLink} target="_blank" rel="noopener noreferrer">
|
|
218
|
+
<MarimoPlusIcon
|
|
219
|
+
size={12}
|
|
220
|
+
strokeWidth={1.5}
|
|
221
|
+
className="mr-1.5 mt-px text-(--grass-11)"
|
|
222
|
+
/>
|
|
223
|
+
Open in molab
|
|
224
|
+
</a>
|
|
225
|
+
</Button>
|
|
226
|
+
<p className="text-sm text-(--sky-12)">
|
|
227
|
+
Run this notebook in <span className="font-semibold">molab</span>,
|
|
228
|
+
marimo's cloud-hosted notebook platform.
|
|
229
|
+
</p>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
};
|
|
@@ -367,6 +367,39 @@ describe("collapseConsoleOutputs", () => {
|
|
|
367
367
|
expect(consoleOutputs[0].data).toBe("Processing: |██████████| 100/100");
|
|
368
368
|
});
|
|
369
369
|
|
|
370
|
+
it("should preserve nested progress lines across flushed writes", () => {
|
|
371
|
+
let consoleOutputs: OutputMessage[] = [
|
|
372
|
+
{
|
|
373
|
+
mimetype: "text/plain",
|
|
374
|
+
channel: "stderr",
|
|
375
|
+
data: "outer: 0%",
|
|
376
|
+
timestamp: 0,
|
|
377
|
+
},
|
|
378
|
+
];
|
|
379
|
+
const append = (data: string) => {
|
|
380
|
+
consoleOutputs = collapseConsoleOutputs([
|
|
381
|
+
...consoleOutputs,
|
|
382
|
+
{
|
|
383
|
+
mimetype: "text/plain",
|
|
384
|
+
channel: "stderr",
|
|
385
|
+
data,
|
|
386
|
+
timestamp: 0,
|
|
387
|
+
},
|
|
388
|
+
]);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// tqdm flushes each of these writes independently.
|
|
392
|
+
append("\n");
|
|
393
|
+
append("\rinner: 0%");
|
|
394
|
+
append("\u001B[A");
|
|
395
|
+
expect(consoleOutputs[0].data).toBe("outer: 0%\ninner: 0%");
|
|
396
|
+
|
|
397
|
+
append("\n");
|
|
398
|
+
append("\rinner: 1%");
|
|
399
|
+
append("\u001B[A");
|
|
400
|
+
expect(consoleOutputs[0].data).toBe("outer: 0%\ninner: 1%");
|
|
401
|
+
});
|
|
402
|
+
|
|
370
403
|
it("should handle cursor up/down movements", () => {
|
|
371
404
|
// Test that cursor movements within a single message are handled
|
|
372
405
|
const consoleOutputs: OutputMessage[] = [
|
|
@@ -379,8 +412,8 @@ describe("collapseConsoleOutputs", () => {
|
|
|
379
412
|
];
|
|
380
413
|
|
|
381
414
|
const result = collapseConsoleOutputs(consoleOutputs);
|
|
382
|
-
//
|
|
383
|
-
expect(result[0].data).toBe("Line 1\nModified");
|
|
415
|
+
// Moving the cursor does not erase the lines below it.
|
|
416
|
+
expect(result[0].data).toBe("Line 1\nModified\n");
|
|
384
417
|
});
|
|
385
418
|
|
|
386
419
|
it("should handle clear screen sequence", () => {
|