@malloy-publisher/sdk 0.0.141 → 0.0.143

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.141",
4
+ "version": "0.0.143",
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,7 +183,10 @@ export default function Notebook({
179
183
  /^\s*(run|query)\s*:/m.test(cellText);
180
184
 
181
185
  try {
182
- if (hasQuery && modelPath) {
186
+ let result: string | undefined;
187
+ let newSources: string[] | undefined;
188
+
189
+ if (hasQuery && modelPath && filtersToApply.length > 0) {
183
190
  // Query cell - use models API with optional filters
184
191
  let queryToExecute = cellText;
185
192
 
@@ -234,14 +241,9 @@ 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
- // Non-query code cell - use notebook cell execution API
246
+ // Non-query code cell (or no filters applied) - use notebook cell execution API
245
247
  const response =
246
248
  await apiClients.notebooks.executeNotebookCell(
247
249
  projectName,
@@ -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 = executedCell.newSources || rawCell.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] =
@@ -236,19 +239,12 @@ export function NotebookCell({
236
239
  {highlightedMalloyCode && (
237
240
  <span
238
241
  dangerouslySetInnerHTML={{
239
- __html:
240
- cell.text.length > 50 &&
241
- highlightedMalloyCode
242
- ? `${highlightedMalloyCode.substring(0, 50)}...`
243
- : highlightedMalloyCode,
242
+ __html: highlightedMalloyCode,
244
243
  }}
245
244
  style={{
246
245
  fontFamily: "monospace",
247
246
  fontSize: "14px",
248
247
  flex: 1,
249
- whiteSpace: "nowrap",
250
- overflow: "hidden",
251
- textOverflow: "ellipsis",
252
248
  marginRight: "8px",
253
249
  }}
254
250
  />
@@ -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={{
@@ -160,7 +160,7 @@ export default function ResultContainer({
160
160
  ref={contentRef}
161
161
  sx={{
162
162
  flex: 1,
163
- overflow: "scroll",
163
+ overflow: "hidden",
164
164
  p: 0,
165
165
  // Adjust bottom padding when toggle is shown to prevent content overlap
166
166
  pb: shouldShowToggle ? "40px" : 1,
@@ -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;