@malloy-publisher/sdk 0.0.142 → 0.0.144

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@malloy-publisher/sdk",
3
3
  "description": "Malloy Publisher SDK",
4
- "version": "0.0.142",
4
+ "version": "0.0.144",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",
@@ -153,23 +153,27 @@ export default function Notebook({
153
153
  async (filtersToApply: FilterSelection[] = []) => {
154
154
  if (!isSuccess || !notebook?.notebookCells) return;
155
155
 
156
+ // Initialize or reset cells
157
+ setEnhancedCells((prev) => {
158
+ if (prev.length === 0) {
159
+ return notebook.notebookCells.map((cell) => ({ ...cell }));
160
+ }
161
+ return prev.map((cell) => ({
162
+ ...cell,
163
+ result: undefined,
164
+ }));
165
+ });
166
+
156
167
  setIsExecuting(true);
157
168
  setExecutionError(null);
158
- const cells: EnhancedNotebookCell[] = [];
159
169
 
160
170
  try {
161
171
  // Execute cells sequentially
162
172
  for (let i = 0; i < notebook.notebookCells.length; i++) {
163
173
  const rawCell = notebook.notebookCells[i];
164
174
 
165
- // Markdown cells don't need execution - use raw content directly
166
- if (rawCell.type === "markdown") {
167
- cells.push({
168
- type: rawCell.type,
169
- text: rawCell.text,
170
- });
171
- continue;
172
- }
175
+ // Markdown cells don't need execution
176
+ if (rawCell.type === "markdown") continue;
173
177
 
174
178
  // Execute code cells
175
179
  const cellText = rawCell.text || "";
@@ -179,6 +183,9 @@ export default function Notebook({
179
183
  /^\s*(run|query)\s*:/m.test(cellText);
180
184
 
181
185
  try {
186
+ let result: string | undefined;
187
+ let newSources: string[] | undefined;
188
+
182
189
  if (hasQuery && modelPath && filtersToApply.length > 0) {
183
190
  // Query cell - use models API with optional filters
184
191
  let queryToExecute = cellText;
@@ -234,12 +241,7 @@ export default function Notebook({
234
241
  versionId,
235
242
  },
236
243
  );
237
-
238
- cells.push({
239
- type: rawCell.type,
240
- text: rawCell.text,
241
- result: response.data.result,
242
- });
244
+ result = response.data.result;
243
245
  } else {
244
246
  // Non-query code cell (or no filters applied) - use notebook cell execution API
245
247
  const response =
@@ -252,24 +254,29 @@ export default function Notebook({
252
254
  );
253
255
 
254
256
  const executedCell = response.data;
255
- cells.push({
256
- type: rawCell.type,
257
- text: rawCell.text,
258
- result: executedCell.result,
259
- newSources: executedCell.newSources,
260
- });
257
+ result = executedCell.result;
258
+ newSources = rawCell.newSources || executedCell.newSources;
261
259
  }
260
+
261
+ // Update state incrementally
262
+ setEnhancedCells((prev) => {
263
+ const next = [...prev];
264
+ // Ensure we have a cell to update (in case state was reset externally, though unlikely)
265
+ if (!next[i]) {
266
+ next[i] = { ...rawCell };
267
+ }
268
+ next[i] = {
269
+ ...next[i],
270
+ result,
271
+ newSources,
272
+ };
273
+ return next;
274
+ });
262
275
  } catch (cellError) {
263
- // If a cell fails, add it without execution results
264
276
  console.error(`Error executing cell ${i}:`, cellError);
265
- cells.push({
266
- type: rawCell.type,
267
- text: rawCell.text,
268
- });
277
+ // Don't update result on error, leave as is (undefined)
269
278
  }
270
279
  }
271
-
272
- setEnhancedCells(cells);
273
280
  } catch (error) {
274
281
  console.error("Error executing notebook cells:", error);
275
282
  setExecutionError(error as Error);
@@ -412,26 +419,23 @@ export default function Notebook({
412
419
  )}
413
420
 
414
421
  {/* Loading State */}
415
- {(!isSuccess || isExecuting) && !isError && (
416
- <Loading
417
- text={
418
- isExecuting
419
- ? "Executing Notebook..."
420
- : "Fetching Notebook..."
421
- }
422
- />
422
+ {!isSuccess && !isError && (
423
+ <Loading text={"Fetching Notebook..."} />
423
424
  )}
424
425
 
425
426
  {/* Notebook Cells */}
426
427
  {isSuccess &&
427
- !isExecuting &&
428
- enhancedCells.map((cell, index) => (
428
+ (enhancedCells.length > 0
429
+ ? enhancedCells
430
+ : notebook?.notebookCells || []
431
+ ).map((cell, index) => (
429
432
  <NotebookCell
430
- cell={cell}
433
+ cell={cell as EnhancedNotebookCell}
431
434
  key={index}
432
435
  index={index}
433
436
  resourceUri={resourceUri}
434
437
  maxResultSize={maxResultSize}
438
+ isExecuting={isExecuting}
435
439
  />
436
440
  ))}
437
441
 
@@ -5,6 +5,7 @@ import LinkOutlinedIcon from "@mui/icons-material/LinkOutlined";
5
5
  import SearchIcon from "@mui/icons-material/Search";
6
6
  import {
7
7
  Box,
8
+ CircularProgress,
8
9
  Dialog,
9
10
  DialogContent,
10
11
  DialogTitle,
@@ -33,6 +34,7 @@ interface NotebookCellProps {
33
34
  resourceUri: string;
34
35
  index: number;
35
36
  maxResultSize?: number;
37
+ isExecuting?: boolean;
36
38
  }
37
39
 
38
40
  export function NotebookCell({
@@ -42,6 +44,7 @@ export function NotebookCell({
42
44
  resourceUri,
43
45
  index,
44
46
  maxResultSize,
47
+ isExecuting,
45
48
  }: NotebookCellProps) {
46
49
  const [codeDialogOpen, setCodeDialogOpen] = React.useState<boolean>(false);
47
50
  const [embeddingDialogOpen, setEmbeddingDialogOpen] =
@@ -214,45 +217,37 @@ export function NotebookCell({
214
217
  marginBottom: "16px",
215
218
  }}
216
219
  >
217
- {cell.newSources &&
218
- cell.newSources.length > 0 &&
219
- hasValidImport && (
220
- <CleanMetricCard
220
+ {cell.newSources && cell.newSources.length > 0 && (
221
+ <CleanMetricCard
222
+ sx={{
223
+ position: "relative",
224
+ padding: "0",
225
+ }}
226
+ >
227
+ <Box
221
228
  sx={{
222
- position: "relative",
223
- padding: "0",
229
+ display: "flex",
230
+ alignItems: "center",
231
+ justifyContent: "space-between",
232
+ paddingLeft: "24px",
233
+ paddingRight: "8px",
224
234
  }}
225
235
  >
226
- <Box
227
- sx={{
228
- display: "flex",
229
- alignItems: "center",
230
- justifyContent: "space-between",
231
- paddingLeft: "24px",
232
- paddingRight: "8px",
233
- }}
234
- >
235
- {/* This shouldn't be needed but there's a compiler bug */}
236
- {highlightedMalloyCode && (
237
- <span
238
- dangerouslySetInnerHTML={{
239
- __html:
240
- cell.text.length > 50 &&
241
- highlightedMalloyCode
242
- ? `${highlightedMalloyCode.substring(0, 50)}...`
243
- : highlightedMalloyCode,
244
- }}
245
- style={{
246
- fontFamily: "monospace",
247
- fontSize: "14px",
248
- flex: 1,
249
- whiteSpace: "nowrap",
250
- overflow: "hidden",
251
- textOverflow: "ellipsis",
252
- marginRight: "8px",
253
- }}
254
- />
255
- )}
236
+ {/* This shouldn't be needed but there's a compiler bug */}
237
+ {highlightedMalloyCode && (
238
+ <span
239
+ dangerouslySetInnerHTML={{
240
+ __html: highlightedMalloyCode,
241
+ }}
242
+ style={{
243
+ fontFamily: "monospace",
244
+ fontSize: "14px",
245
+ flex: 1,
246
+ marginRight: "8px",
247
+ }}
248
+ />
249
+ )}
250
+ {hasValidImport && (
256
251
  <IconButton
257
252
  sx={{
258
253
  backgroundColor: "rgba(255, 255, 255, 0.9)",
@@ -270,9 +265,10 @@ export function NotebookCell({
270
265
  sx={{ fontSize: "18px", color: "#666666" }}
271
266
  />
272
267
  </IconButton>
273
- </Box>
274
- </CleanMetricCard>
275
- )}
268
+ )}
269
+ </Box>
270
+ </CleanMetricCard>
271
+ )}
276
272
  </Stack>
277
273
  )}
278
274
 
@@ -407,6 +403,23 @@ export function NotebookCell({
407
403
  title="Results"
408
404
  />
409
405
 
406
+ {/* Loading state for executing code cells (not import cells) */}
407
+ {isExecuting &&
408
+ !cell.result &&
409
+ !hasValidImport &&
410
+ !(cell.newSources && cell.newSources.length > 0) && (
411
+ <CleanMetricCard
412
+ sx={{
413
+ display: "flex",
414
+ justifyContent: "center",
415
+ alignItems: "center",
416
+ minHeight: 200,
417
+ }}
418
+ >
419
+ <CircularProgress size={32} />
420
+ </CleanMetricCard>
421
+ )}
422
+
410
423
  {cell.result && (
411
424
  <CleanMetricCard
412
425
  sx={{
@@ -359,6 +359,8 @@ function parseIndexQueryResult(
359
359
  return cell.number_value ?? null;
360
360
  case "boolean_cell":
361
361
  return cell.boolean_value ?? null;
362
+ case "null_cell":
363
+ return null;
362
364
  default:
363
365
  console.log("Unknown cell kind: " + cell.kind);
364
366
  return null;