@malloy-publisher/sdk 0.0.36 → 0.0.38

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.
Files changed (42) hide show
  1. package/dist/RenderedResult-D0NN1YlV.js +79 -0
  2. package/dist/RenderedResult-JN8rBUlE.cjs +1 -0
  3. package/dist/client/api.d.ts +2 -2
  4. package/dist/components/ApiErrorDisplay.d.ts +1 -1
  5. package/dist/components/Loading.d.ts +37 -0
  6. package/dist/components/Model/SourcesExplorer.d.ts +2 -2
  7. package/dist/components/MutableNotebook/EditableMalloyCell.d.ts +3 -3
  8. package/dist/components/MutableNotebook/MutableCell.d.ts +3 -4
  9. package/dist/components/MutableNotebook/MutableNotebook.d.ts +2 -1
  10. package/dist/components/index.d.ts +1 -0
  11. package/dist/{index-nKbldp0y.cjs → index-BH85bTLt.cjs} +594 -594
  12. package/dist/{index-DvGSfdDD.js → index-fYVnpzww.js} +20765 -20651
  13. package/dist/index.cjs.js +1 -1
  14. package/dist/index.es.js +17 -16
  15. package/dist/{vendor-C8UD-eyK.js → vendor-BCM56_2K.js} +16200 -19097
  16. package/dist/{vendor-BH1c2Hhy.cjs → vendor-Bg9-K32d.cjs} +140 -241
  17. package/package.json +1 -1
  18. package/src/components/ApiErrorDisplay.tsx +1 -1
  19. package/src/components/Home/Home.tsx +2 -3
  20. package/src/components/Loading.tsx +104 -0
  21. package/src/components/Model/Model.tsx +2 -6
  22. package/src/components/Model/NamedQueries.tsx +13 -13
  23. package/src/components/Model/SourcesExplorer.tsx +21 -41
  24. package/src/components/MutableNotebook/EditableMalloyCell.tsx +4 -22
  25. package/src/components/MutableNotebook/ModelPicker.tsx +31 -52
  26. package/src/components/MutableNotebook/MutableCell.tsx +229 -137
  27. package/src/components/MutableNotebook/MutableNotebook.tsx +102 -62
  28. package/src/components/Notebook/Notebook.tsx +10 -4
  29. package/src/components/Package/Databases.tsx +2 -3
  30. package/src/components/Package/Models.tsx +6 -6
  31. package/src/components/Package/Notebooks.tsx +7 -5
  32. package/src/components/Package/Package.tsx +1 -1
  33. package/src/components/Package/Schedules.tsx +2 -5
  34. package/src/components/Project/About.tsx +2 -5
  35. package/src/components/Project/ConnectionExplorer.tsx +4 -15
  36. package/src/components/Project/Packages.tsx +2 -5
  37. package/src/components/QueryResult/QueryResult.tsx +2 -6
  38. package/src/components/RenderedResult/RenderedResult.tsx +107 -18
  39. package/src/components/RenderedResult/ResultContainer.tsx +5 -2
  40. package/src/components/index.ts +1 -0
  41. package/dist/RenderedResult-BlNz8j4d.js +0 -51
  42. package/dist/RenderedResult-DphykkT6.cjs +0 -1
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.36",
4
+ "version": "0.0.38",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",
@@ -4,7 +4,7 @@ import React from "react";
4
4
  export interface ApiError extends Error {
5
5
  status?: number;
6
6
  data?: {
7
- code: string;
7
+ code: number;
8
8
  message: string;
9
9
  };
10
10
  }
@@ -1,10 +1,9 @@
1
1
  import { Grid, Typography } from "@mui/material";
2
2
  import { QueryClient, useQuery } from "@tanstack/react-query";
3
3
  import { ProjectsApi, Configuration } from "../../client";
4
- import axios from "axios";
5
4
  import { ApiErrorDisplay } from "../ApiErrorDisplay";
5
+ import { Loading } from "../Loading";
6
6
 
7
- axios.defaults.baseURL = "http://localhost:4000";
8
7
  const projectsApi = new ProjectsApi(new Configuration());
9
8
  const queryClient = new QueryClient();
10
9
 
@@ -63,6 +62,6 @@ export default function Home({ server, navigate }: HomeProps) {
63
62
  );
64
63
  }
65
64
  } else {
66
- return <Typography variant="h6">Loading projects...</Typography>;
65
+ return <Loading text="Loading projects..." />;
67
66
  }
68
67
  }
@@ -0,0 +1,104 @@
1
+ import React from "react";
2
+ import { Box, CircularProgress, Typography } from "@mui/material";
3
+
4
+ export interface LoadingProps {
5
+ /**
6
+ * The text to display below the spinner
7
+ */
8
+ text?: string;
9
+ /**
10
+ * The size of the CircularProgress component
11
+ * @default 40
12
+ */
13
+ size?: number | string;
14
+ /**
15
+ * The color of the CircularProgress component
16
+ * @default "primary"
17
+ */
18
+ color?:
19
+ | "primary"
20
+ | "secondary"
21
+ | "error"
22
+ | "info"
23
+ | "success"
24
+ | "warning"
25
+ | "inherit";
26
+ /**
27
+ * The thickness of the circular progress
28
+ * @default 3.6
29
+ */
30
+ thickness?: number;
31
+ /**
32
+ * Whether to center the component
33
+ * @default true
34
+ */
35
+ centered?: boolean;
36
+ /**
37
+ * Custom spacing between spinner and text
38
+ * @default 2
39
+ */
40
+ spacing?: number;
41
+ /**
42
+ * Typography variant for the text
43
+ * @default "body1"
44
+ */
45
+ textVariant?:
46
+ | "h1"
47
+ | "h2"
48
+ | "h3"
49
+ | "h4"
50
+ | "h5"
51
+ | "h6"
52
+ | "subtitle1"
53
+ | "subtitle2"
54
+ | "body1"
55
+ | "body2"
56
+ | "caption"
57
+ | "overline";
58
+ }
59
+
60
+ export function Loading({
61
+ text,
62
+ size = 40,
63
+ color = "primary",
64
+ thickness = 3.6,
65
+ centered = true,
66
+ spacing = 2,
67
+ textVariant = "body1",
68
+ }: LoadingProps) {
69
+ const content = (
70
+ <Box
71
+ sx={{
72
+ display: "flex",
73
+ flexDirection: "column",
74
+ alignItems: "center",
75
+ gap: spacing,
76
+ }}
77
+ >
78
+ <CircularProgress size={size} color={color} thickness={thickness} />
79
+ {text && (
80
+ <Typography variant={textVariant} color="text.secondary">
81
+ {text}
82
+ </Typography>
83
+ )}
84
+ </Box>
85
+ );
86
+
87
+ if (centered) {
88
+ return (
89
+ <Box
90
+ sx={{
91
+ display: "flex",
92
+ justifyContent: "center",
93
+ alignItems: "center",
94
+ minHeight: "200px",
95
+ width: "100%",
96
+ }}
97
+ >
98
+ {content}
99
+ </Box>
100
+ );
101
+ }
102
+
103
+ return content;
104
+ }
@@ -23,7 +23,7 @@ import { ApiErrorDisplay, ApiError } from "../ApiErrorDisplay";
23
23
  import "@malloydata/malloy-explorer/styles.css";
24
24
  import { usePackage } from "../Package/PackageProvider";
25
25
  import { SourceExplorerComponent } from "./SourcesExplorer";
26
- import NamedQueries from "./NamedQueries";
26
+ import { Loading } from "../Loading";
27
27
 
28
28
  const modelsApi = new ModelsApi(new Configuration());
29
29
 
@@ -118,11 +118,7 @@ export default function Model({
118
118
  );
119
119
 
120
120
  if (isLoading) {
121
- return (
122
- <Typography sx={{ p: "20px", m: "auto" }}>
123
- Fetching Model...
124
- </Typography>
125
- );
121
+ return <Loading text="Fetching Model..." />;
126
122
  }
127
123
 
128
124
  if (isError) {
@@ -1,17 +1,17 @@
1
1
  import {
2
- Typography,
3
2
  Accordion,
4
- AccordionSummary,
5
3
  AccordionDetails,
4
+ AccordionSummary,
5
+ Typography,
6
6
  } from "@mui/material";
7
7
  import { Box } from "@mui/system";
8
8
  import { Query, QueryresultsApi } from "../../client/api";
9
9
  import { StyledCard, StyledCardContent } from "../styles";
10
10
 
11
11
  import { QueryClient, useMutation } from "@tanstack/react-query";
12
+ import React from "react";
12
13
  import { Configuration } from "../../client";
13
14
  import { usePackage } from "../Package";
14
- import React from "react";
15
15
  import ResultContainer from "../RenderedResult/ResultContainer";
16
16
 
17
17
  const queryResultsApi = new QueryresultsApi(new Configuration());
@@ -70,17 +70,17 @@ export default function NamedQueries({
70
70
 
71
71
  const handleAccordionChange =
72
72
  (query: Query, queryKey: string) =>
73
- (event: React.SyntheticEvent, isExpanded: boolean) => {
74
- setExpandedAccordions((prev) => ({
75
- ...prev,
76
- [queryKey]: isExpanded,
77
- }));
73
+ (_event: React.SyntheticEvent, isExpanded: boolean) => {
74
+ setExpandedAccordions((prev) => ({
75
+ ...prev,
76
+ [queryKey]: isExpanded,
77
+ }));
78
78
 
79
- // Trigger mutation only if expanding and we haven't executed this query before
80
- if (isExpanded && !namedQueryResults[query.name]) {
81
- mutation.mutate({ query });
82
- }
83
- };
79
+ // Trigger mutation only if expanding and we haven't executed this query before
80
+ if (isExpanded && !namedQueryResults[query.name]) {
81
+ mutation.mutate({ query });
82
+ }
83
+ };
84
84
 
85
85
  if (!namedQueries) {
86
86
  return <div> Loading Named Queries</div>;
@@ -1,6 +1,6 @@
1
1
  import * as Malloy from "@malloydata/malloy-interfaces";
2
2
  import * as QueryBuilder from "@malloydata/malloy-query-builder";
3
- import { Button, CardActions } from "@mui/material";
3
+ import { Button } from "@mui/material";
4
4
  import { Box, Stack } from "@mui/system";
5
5
  import {
6
6
  StyledCard,
@@ -64,11 +64,7 @@ export interface SourceExplorerProps {
64
64
  sourceAndPaths: SourceAndPath[];
65
65
  existingQuery?: QueryExplorerResult;
66
66
  existingSourceName?: string;
67
- saveResult?: (
68
- modelPath: string,
69
- sourceName: string,
70
- query: QueryExplorerResult,
71
- ) => void;
67
+ onChange?: (query: QueryExplorerResult) => void;
72
68
  }
73
69
 
74
70
  /**
@@ -80,15 +76,15 @@ export interface SourceExplorerProps {
80
76
  */
81
77
  export function SourcesExplorer({
82
78
  sourceAndPaths,
83
- saveResult,
84
79
  existingQuery,
85
80
  existingSourceName,
81
+ onChange,
86
82
  }: SourceExplorerProps) {
87
83
  const [selectedTab, setSelectedTab] = React.useState(
88
84
  existingSourceName
89
85
  ? sourceAndPaths.findIndex(
90
- (entry) => entry.sourceInfo.name === existingSourceName,
91
- )
86
+ (entry) => entry.sourceInfo.name === existingSourceName,
87
+ )
92
88
  : 0,
93
89
  );
94
90
 
@@ -119,27 +115,6 @@ export function SourcesExplorer({
119
115
  ))}
120
116
  </MultiRowTabBar>
121
117
  )}
122
- {saveResult && (
123
- <CardActions
124
- sx={{
125
- padding: "0px 10px 0px 10px",
126
- mb: "auto",
127
- mt: "auto",
128
- }}
129
- >
130
- <Button
131
- onClick={() =>
132
- saveResult(
133
- sourceAndPaths[selectedTab].modelPath,
134
- sourceAndPaths[selectedTab].sourceInfo.name,
135
- query,
136
- )
137
- }
138
- >
139
- Save
140
- </Button>
141
- </CardActions>
142
- )}
143
118
  </Stack>
144
119
  </StyledCardContent>
145
120
  <StyledCardMedia>
@@ -147,7 +122,12 @@ export function SourcesExplorer({
147
122
  <SourceExplorerComponent
148
123
  sourceAndPath={sourceAndPaths[selectedTab]}
149
124
  existingQuery={query}
150
- onChange={setQuery}
125
+ onChange={(query) => {
126
+ setQuery(query);
127
+ if (onChange) {
128
+ onChange(query);
129
+ }
130
+ }}
151
131
  />
152
132
  <Box height="5px" />
153
133
  </Stack>
@@ -323,16 +303,16 @@ export function SourceExplorerComponent({
323
303
  submittedQuery={
324
304
  query?.malloyQuery
325
305
  ? {
326
- executionState: mutation.isPending
327
- ? "running"
328
- : "finished",
329
- response: {
330
- result: query.malloyResult,
331
- },
332
- query: query.malloyQuery,
333
- queryResolutionStartMillis: Date.now(),
334
- onCancel: mutation.reset,
335
- }
306
+ executionState: mutation.isPending
307
+ ? "running"
308
+ : "finished",
309
+ response: {
310
+ result: query.malloyResult,
311
+ },
312
+ query: query.malloyQuery,
313
+ queryResolutionStartMillis: Date.now(),
314
+ onCancel: mutation.reset,
315
+ }
336
316
  : undefined
337
317
  }
338
318
  options={{ showRawQuery: true }}
@@ -1,19 +1,17 @@
1
1
  import { SourceAndPath, SourcesExplorer } from "../Model";
2
+ import { QueryExplorerResult } from "../Model/SourcesExplorer";
2
3
  import { NotebookCellValue } from "../NotebookManager";
3
4
 
4
5
  interface EditableMalloyCellProps {
5
6
  cell: NotebookCellValue;
6
7
  sourceAndPaths: SourceAndPath[];
7
- onCellChange: (cell: NotebookCellValue) => void;
8
-
9
- onClose: () => void;
8
+ onChange: (query: QueryExplorerResult) => void;
10
9
  }
11
10
 
12
11
  export function EditableMalloyCell({
13
12
  cell,
14
13
  sourceAndPaths,
15
- onCellChange,
16
- onClose,
14
+ onChange,
17
15
  }: EditableMalloyCellProps) {
18
16
  const query = {
19
17
  query: cell.value,
@@ -25,23 +23,7 @@ export function EditableMalloyCell({
25
23
  sourceAndPaths={sourceAndPaths}
26
24
  existingQuery={query}
27
25
  existingSourceName={cell.sourceName}
28
- saveResult={(modelPath, sourceName, qer) => {
29
- // Convert the results of the Query Explorer into
30
- // the stringified JSON objects that are stored in the cell.
31
- onCellChange({
32
- ...cell,
33
- value: qer.query,
34
- result: qer.malloyResult
35
- ? JSON.stringify(qer.malloyResult)
36
- : undefined,
37
- queryInfo: qer.malloyQuery
38
- ? JSON.stringify(qer.malloyQuery)
39
- : undefined,
40
- sourceName,
41
- modelPath,
42
- });
43
- onClose();
44
- }}
26
+ onChange={onChange}
45
27
  />
46
28
  );
47
29
  }
@@ -1,26 +1,20 @@
1
- import AddIcon from "@mui/icons-material/Add";
2
1
  import CloseIcon from "@mui/icons-material/Close";
2
+ import FileUploadOutlinedIcon from "@mui/icons-material/FileUploadOutlined";
3
3
  import {
4
4
  Button,
5
5
  Chip,
6
- Dialog,
7
- DialogActions,
8
- DialogContent,
9
- DialogTitle,
6
+ Divider,
10
7
  FormControl,
11
- List,
12
- ListItem,
13
- ListItemButton,
14
- ListItemText,
8
+ Menu,
9
+ MenuItem,
15
10
  Stack,
16
11
  Typography,
17
12
  } from "@mui/material";
18
13
  import { QueryClient, useQuery } from "@tanstack/react-query";
19
14
  import React from "react";
20
15
  import { Configuration, ModelsApi } from "../../client";
21
- import { usePackage } from "../Package/PackageProvider";
22
- import { StyledCard } from "../styles";
23
16
  import { ApiErrorDisplay } from "../ApiErrorDisplay";
17
+ import { usePackage } from "../Package/PackageProvider";
24
18
 
25
19
  const modelsApi = new ModelsApi(new Configuration());
26
20
  const queryClient = new QueryClient();
@@ -59,7 +53,7 @@ export function ModelPicker({
59
53
  const [selectedModels, setSelectedModels] = React.useState<string[]>(
60
54
  initialSelectedModels || [],
61
55
  );
62
- const [addDialogOpen, setAddDialogOpen] = React.useState(false);
56
+ const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
63
57
 
64
58
  React.useEffect(() => {
65
59
  setSelectedModels(initialSelectedModels || []);
@@ -75,7 +69,7 @@ export function ModelPicker({
75
69
  const newModels = [...selectedModels, model];
76
70
  setSelectedModels(newModels);
77
71
  onModelChange(newModels);
78
- setAddDialogOpen(false);
72
+ setAnchorEl(null);
79
73
  };
80
74
 
81
75
  let availableModels: string[] = [];
@@ -95,22 +89,10 @@ export function ModelPicker({
95
89
  }
96
90
 
97
91
  return (
98
- <StyledCard
99
- sx={{ maxWidth: 400, marginLeft: "10px", padding: "10px 5px 5px 5px" }}
100
- >
101
- <Typography variant="h6">Imported Models</Typography>
92
+ <>
102
93
  <FormControl fullWidth>
103
94
  {isLoading && <Typography>Loading...</Typography>}
104
- <Stack
105
- direction="row"
106
- spacing={1}
107
- sx={{
108
- flexWrap: "wrap",
109
- minHeight: 30,
110
- alignItems: "center",
111
- rowGap: "8px",
112
- }}
113
- >
95
+ <Stack direction="row" spacing={1}>
114
96
  {selectedModels.map((model) => (
115
97
  <Chip
116
98
  key={model}
@@ -121,11 +103,9 @@ export function ModelPicker({
121
103
  />
122
104
  ))}
123
105
  <Button
124
- variant="outlined"
125
106
  size="small"
126
- startIcon={<AddIcon />}
127
- onClick={() => setAddDialogOpen(true)}
128
- sx={{ height: 32, marginTop: "10px" }}
107
+ startIcon={<FileUploadOutlinedIcon />}
108
+ onClick={(e) => setAnchorEl(e.currentTarget)}
129
109
  disabled={
130
110
  isLoading || isError || availableModels.length === 0
131
111
  }
@@ -134,26 +114,25 @@ export function ModelPicker({
134
114
  </Button>
135
115
  </Stack>
136
116
  </FormControl>
137
- <Dialog open={addDialogOpen} onClose={() => setAddDialogOpen(false)}>
138
- <DialogTitle>Select a Model</DialogTitle>
139
- <DialogContent>
140
- {availableModels.length === 0 && (
141
- <Typography>No models available</Typography>
142
- )}
143
- <List>
144
- {availableModels.map((model) => (
145
- <ListItem key={model} disablePadding>
146
- <ListItemButton onClick={() => handleAdd(model)}>
147
- <ListItemText primary={model} />
148
- </ListItemButton>
149
- </ListItem>
150
- ))}
151
- </List>
152
- </DialogContent>
153
- <DialogActions>
154
- <Button onClick={() => setAddDialogOpen(false)}>Cancel</Button>
155
- </DialogActions>
156
- </Dialog>
157
- </StyledCard>
117
+ <Menu
118
+ anchorEl={anchorEl}
119
+ open={Boolean(anchorEl)}
120
+ onClose={() => setAnchorEl(null)}
121
+ >
122
+ <Typography variant="subtitle2" sx={{ ml: 1 }}>
123
+ Models
124
+ </Typography>
125
+ <Divider />
126
+ {availableModels.length === 0 ? (
127
+ <MenuItem disabled>No models available</MenuItem>
128
+ ) : (
129
+ availableModels.map((model) => (
130
+ <MenuItem key={model} onClick={() => handleAdd(model)}>
131
+ <Typography variant="body2">{model}</Typography>
132
+ </MenuItem>
133
+ ))
134
+ )}
135
+ </Menu>
136
+ </>
158
137
  );
159
138
  }