@malloy-publisher/sdk 0.0.80 → 0.0.82

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 (53) hide show
  1. package/dist/components/Model/Model.d.ts +3 -1
  2. package/dist/components/Model/ModelExplorer.d.ts +19 -0
  3. package/dist/components/Model/index.d.ts +3 -0
  4. package/dist/components/Model/useModelData.d.ts +8 -0
  5. package/dist/components/Package/index.d.ts +1 -0
  6. package/dist/components/Project/index.d.ts +1 -0
  7. package/dist/components/Workbook/BrowserWorkbookStorage.d.ts +11 -0
  8. package/dist/components/{MutableNotebook → Workbook}/EditableMalloyCell.d.ts +2 -2
  9. package/dist/components/{MutableNotebook → Workbook}/MutableCell.d.ts +3 -3
  10. package/dist/components/Workbook/Workbook.d.ts +9 -0
  11. package/dist/components/Workbook/WorkbookList.d.ts +7 -0
  12. package/dist/components/Workbook/WorkbookManager.d.ts +87 -0
  13. package/dist/components/Workbook/WorkbookStorage.d.ts +18 -0
  14. package/dist/components/Workbook/WorkbookStorageProvider.d.ts +12 -0
  15. package/dist/components/Workbook/index.d.ts +7 -0
  16. package/dist/components/index.d.ts +3 -1
  17. package/dist/index.cjs.js +67 -67
  18. package/dist/index.es.js +9481 -9329
  19. package/package.json +3 -2
  20. package/src/components/AnalyzePackageButton.tsx +121 -24
  21. package/src/components/Model/Model.tsx +19 -110
  22. package/src/components/Model/ModelExplorer.tsx +138 -0
  23. package/src/components/Model/SourcesExplorer.tsx +65 -79
  24. package/src/components/Model/index.ts +3 -0
  25. package/src/components/Model/useModelData.ts +38 -0
  26. package/src/components/Package/index.ts +1 -0
  27. package/src/components/Project/index.ts +1 -0
  28. package/src/components/Workbook/BrowserWorkbookStorage.ts +100 -0
  29. package/src/components/{MutableNotebook → Workbook}/EditableMalloyCell.tsx +2 -2
  30. package/src/components/{MutableNotebook → Workbook}/MutableCell.tsx +3 -3
  31. package/src/components/{MutableNotebook/MutableNotebook.tsx → Workbook/Workbook.tsx} +81 -57
  32. package/src/components/Workbook/WorkbookList.tsx +111 -0
  33. package/src/components/Workbook/WorkbookManager.ts +230 -0
  34. package/src/components/Workbook/WorkbookStorage.ts +54 -0
  35. package/src/components/Workbook/WorkbookStorageProvider.tsx +37 -0
  36. package/src/components/Workbook/index.ts +7 -0
  37. package/src/components/index.ts +3 -1
  38. package/src/components/styles.ts +0 -3
  39. package/dist/components/MutableNotebook/BrowserNotebookStorage.d.ts +0 -9
  40. package/dist/components/MutableNotebook/MutableNotebook.d.ts +0 -8
  41. package/dist/components/MutableNotebook/MutableNotebookList.d.ts +0 -6
  42. package/dist/components/MutableNotebook/NotebookStorage.d.ts +0 -11
  43. package/dist/components/MutableNotebook/NotebookStorageProvider.d.ts +0 -14
  44. package/dist/components/MutableNotebook/index.d.ts +0 -5
  45. package/dist/components/NotebookManager.d.ts +0 -86
  46. package/src/components/MutableNotebook/BrowserNotebookStorage.ts +0 -58
  47. package/src/components/MutableNotebook/MutableNotebookList.tsx +0 -69
  48. package/src/components/MutableNotebook/NotebookStorage.ts +0 -27
  49. package/src/components/MutableNotebook/NotebookStorageProvider.tsx +0 -43
  50. package/src/components/MutableNotebook/index.ts +0 -8
  51. package/src/components/NotebookManager.ts +0 -225
  52. /package/dist/components/{MutableNotebook → Workbook}/ModelPicker.d.ts +0 -0
  53. /package/src/components/{MutableNotebook → Workbook}/ModelPicker.tsx +0 -0
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.80",
4
+ "version": "0.0.82",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",
@@ -49,7 +49,8 @@
49
49
  "@tanstack/react-query": "^5.59.16",
50
50
  "@uiw/react-md-editor": "^4.0.6",
51
51
  "axios": "^1.7.7",
52
- "markdown-to-jsx": "^7.7.6"
52
+ "markdown-to-jsx": "^7.7.6",
53
+ "duckdb": "^1.3.1"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@openapitools/openapi-generator-cli": "^2.20.2",
@@ -1,30 +1,38 @@
1
1
  import { Add, Launch } from "@mui/icons-material";
2
2
  import {
3
+ Box,
3
4
  Button,
4
5
  Dialog,
5
6
  DialogContent,
6
7
  DialogTitle,
7
8
  FormControl,
9
+ InputLabel,
8
10
  ListItemIcon,
9
11
  ListItemText,
10
12
  Menu,
11
13
  MenuItem,
14
+ Select,
12
15
  Stack,
13
16
  TextField,
14
17
  Typography,
15
18
  } from "@mui/material";
16
19
  import React from "react";
17
20
  import { useRouterClickHandler } from "./click_helper";
18
- import {
19
- BrowserNotebookStorage,
20
- MutableNotebookList,
21
- NotebookStorageProvider,
22
- } from "./MutableNotebook";
21
+ import { WorkbookList } from "./Workbook";
22
+ import { useWorkbookStorage } from "./Workbook/WorkbookStorageProvider";
23
+ import type { WorkbookLocator, Workspace } from "./Workbook/WorkbookStorage";
23
24
  import { useParams } from "react-router-dom";
25
+ import { PackageContextProps, PackageProvider } from "./Package";
24
26
 
25
27
  export function AnalyzePackageButton() {
26
- const { projectName, packageName } = useParams();
28
+ const packageContext = useParams() as unknown as PackageContextProps;
29
+ const { packageName, projectName } = packageContext;
30
+ const { workbookStorage } = useWorkbookStorage();
27
31
  const [workbookName, setWorkbookName] = React.useState("");
32
+ const [selectedWorkspace, setSelectedWorkspace] = React.useState("");
33
+ const [availableWorkspaces, setAvailableWorkspaces] = React.useState<
34
+ Workspace[]
35
+ >([]);
28
36
  const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
29
37
  const [newDialogOpen, setNewDialogOpen] = React.useState(false);
30
38
  const [openDialogOpen, setOpenDialogOpen] = React.useState(false);
@@ -42,25 +50,52 @@ export function AnalyzePackageButton() {
42
50
  };
43
51
  const handleNewDialogClose = () => {
44
52
  setNewDialogOpen(false);
53
+ setWorkbookName("");
54
+ setSelectedWorkspace("");
45
55
  };
46
56
 
47
- const handleNotebookClick = (notebook: string, event: React.MouseEvent) => {
57
+ // Fetch available workspaces when the new dialog opens
58
+ React.useEffect(() => {
59
+ if (newDialogOpen && workbookStorage && packageContext) {
60
+ workbookStorage
61
+ .listWorkspaces(packageContext, true) // Only show writeable workspaces
62
+ .then((workspaces) => {
63
+ setAvailableWorkspaces(workspaces);
64
+ // If only one workspace, select it by default
65
+ if (workspaces.length === 1) {
66
+ setSelectedWorkspace(workspaces[0].name);
67
+ }
68
+ })
69
+ .catch((error) => {
70
+ console.error("Error fetching workspaces:", error);
71
+ setAvailableWorkspaces([]);
72
+ });
73
+ }
74
+ }, [newDialogOpen, workbookStorage, packageContext]);
75
+
76
+ const handleWorkbookClick = (
77
+ workbook: WorkbookLocator,
78
+ event: React.MouseEvent,
79
+ ) => {
48
80
  setOpenDialogOpen(false);
49
- // Navigate to the ScratchNotebookPage with anchor text for notebookPath
81
+ // Navigate to the WorkbookPage with anchor text for notebookPath
50
82
  navigate(
51
- `/${projectName}/${packageName}/scratchNotebook/${encodeURIComponent(notebook)}`,
83
+ `/${projectName}/${packageName}/workbook/${encodeURIComponent(workbook.workspace)}/${encodeURIComponent(workbook.path)}`,
52
84
  event,
53
85
  );
54
86
  };
55
87
 
56
- const createNotebookClick = (event?: React.MouseEvent) => {
88
+ const createWorkbookClick = (event?: React.MouseEvent) => {
57
89
  setNewDialogOpen(false);
58
- // Navigate to the ScratchNotebookPage with anchor text for notebookPath
90
+ // Include workspace in the workbook path if selected
91
+ const workbookPath = `${encodeURIComponent(selectedWorkspace)}/${encodeURIComponent(workbookName)}`;
92
+ // Navigate to the WorkbookPage with anchor text for notebookPath
59
93
  navigate(
60
- `/${projectName}/${packageName}/scratchNotebook/${encodeURIComponent(workbookName)}`,
94
+ `/${projectName}/${packageName}/workbook/${workbookPath}`,
61
95
  event,
62
96
  );
63
97
  setWorkbookName("");
98
+ setSelectedWorkspace("");
64
99
  };
65
100
 
66
101
  if (!projectName || !packageName) {
@@ -143,7 +178,10 @@ export function AnalyzePackageButton() {
143
178
  fullWidth
144
179
  >
145
180
  <DialogTitle sx={{ pb: 1, pt: 2, px: 2 }}>
146
- <Typography variant="h6" fontWeight={600} sx={{ mb: 0.5 }}>
181
+ <Typography
182
+ fontWeight={600}
183
+ sx={{ fontSize: "1.5rem", mb: 0.5 }}
184
+ >
147
185
  Create New Workbook
148
186
  </Typography>
149
187
  <Typography variant="body2" color="text.secondary">
@@ -152,6 +190,61 @@ export function AnalyzePackageButton() {
152
190
  </DialogTitle>
153
191
  <DialogContent sx={{ px: 2, pb: 2 }}>
154
192
  <Stack spacing={2} sx={{ mt: 1 }}>
193
+ {availableWorkspaces.length > 1 ? (
194
+ <FormControl fullWidth size="small">
195
+ <InputLabel>Workspace</InputLabel>
196
+ <Select
197
+ value={selectedWorkspace}
198
+ label="Workspace"
199
+ onChange={(e) =>
200
+ setSelectedWorkspace(e.target.value)
201
+ }
202
+ >
203
+ {availableWorkspaces.map((workspace) => (
204
+ <MenuItem
205
+ key={workspace.name}
206
+ value={workspace.name}
207
+ >
208
+ <Box>
209
+ <Typography
210
+ variant="body2"
211
+ fontWeight={500}
212
+ >
213
+ {workspace.name}
214
+ </Typography>
215
+ <Typography
216
+ variant="caption"
217
+ color="text.secondary"
218
+ >
219
+ {workspace.description}
220
+ </Typography>
221
+ </Box>
222
+ </MenuItem>
223
+ ))}
224
+ </Select>
225
+ </FormControl>
226
+ ) : availableWorkspaces.length === 1 ? (
227
+ <Box
228
+ sx={{
229
+ p: 2,
230
+ border: 1,
231
+ borderColor: "divider",
232
+ borderRadius: 1,
233
+ backgroundColor: "grey.50",
234
+ }}
235
+ >
236
+ <Typography
237
+ variant="body2"
238
+ fontWeight={500}
239
+ gutterBottom
240
+ >
241
+ Workspace: {availableWorkspaces[0].name}
242
+ </Typography>
243
+ <Typography variant="caption" color="text.secondary">
244
+ {availableWorkspaces[0].description}
245
+ </Typography>
246
+ </Box>
247
+ ) : null}
155
248
  <FormControl fullWidth>
156
249
  <TextField
157
250
  label="Workbook Name"
@@ -172,9 +265,13 @@ export function AnalyzePackageButton() {
172
265
  Cancel
173
266
  </Button>
174
267
  <Button
175
- onClick={(event) => createNotebookClick(event)}
268
+ onClick={(event) => createWorkbookClick(event)}
176
269
  variant="contained"
177
- disabled={!workbookName.trim()}
270
+ disabled={
271
+ !workbookName.trim() ||
272
+ (availableWorkspaces.length > 1 &&
273
+ !selectedWorkspace)
274
+ }
178
275
  size="small"
179
276
  >
180
277
  Create Workbook
@@ -192,7 +289,10 @@ export function AnalyzePackageButton() {
192
289
  fullWidth
193
290
  >
194
291
  <DialogTitle sx={{ pb: 1, pt: 2, px: 2 }}>
195
- <Typography variant="h6" fontWeight={600} sx={{ mb: 0.5 }}>
292
+ <Typography
293
+ fontWeight={600}
294
+ sx={{ mb: 0.5, fontSize: "1.5rem" }}
295
+ >
196
296
  Open Workbook
197
297
  </Typography>
198
298
  <Typography variant="body2" color="text.secondary">
@@ -200,15 +300,12 @@ export function AnalyzePackageButton() {
200
300
  </Typography>
201
301
  </DialogTitle>
202
302
  <DialogContent sx={{ px: 2, pb: 2 }}>
203
- <NotebookStorageProvider
204
- notebookStorage={new BrowserNotebookStorage()}
205
- userContext={{
206
- project: projectName,
207
- package: packageName,
208
- }}
303
+ <PackageProvider
304
+ projectName={projectName}
305
+ packageName={packageName}
209
306
  >
210
- <MutableNotebookList onNotebookClick={handleNotebookClick} />
211
- </NotebookStorageProvider>
307
+ <WorkbookList onWorkbookClick={handleWorkbookClick} />
308
+ </PackageProvider>
212
309
  </DialogContent>
213
310
  </Dialog>
214
311
  </>
@@ -1,31 +1,24 @@
1
1
  import ContentCopyIcon from "@mui/icons-material/ContentCopy";
2
2
  import LinkOutlinedIcon from "@mui/icons-material/LinkOutlined";
3
3
  import {
4
- Box,
5
4
  CardActions,
6
5
  Collapse,
7
6
  Divider,
8
7
  IconButton,
9
8
  Stack,
10
- Tab,
11
- Tabs,
12
9
  Tooltip,
13
10
  Typography,
14
11
  } from "@mui/material";
15
12
  import React, { useEffect } from "react";
16
- import { Configuration, ModelsApi, CompiledModel } from "../../client";
17
13
  import { highlight } from "../highlighter";
18
- import { StyledCard, StyledCardContent, StyledCardMedia } from "../styles";
19
- import { ModelCell } from "./ModelCell";
14
+ import { StyledCard, StyledCardContent } from "../styles";
20
15
  import { ApiErrorDisplay } from "../ApiErrorDisplay";
21
16
 
22
17
  import "@malloydata/malloy-explorer/styles.css";
23
- import { usePackage } from "../Package/PackageProvider";
24
- import { SourceExplorerComponent } from "./SourcesExplorer";
18
+ import { QueryExplorerResult } from "./SourcesExplorer";
25
19
  import { Loading } from "../Loading";
26
- import { useQueryWithApiError } from "../../hooks/useQueryWithApiError";
27
-
28
- const modelsApi = new ModelsApi(new Configuration());
20
+ import { ModelExplorer } from "./ModelExplorer";
21
+ import { useModelData } from "./useModelData";
29
22
 
30
23
  interface ModelProps {
31
24
  modelPath: string;
@@ -34,6 +27,7 @@ interface ModelProps {
34
27
  hideResultIcons?: boolean;
35
28
  expandEmbeddings?: boolean;
36
29
  hideEmbeddingIcons?: boolean;
30
+ onChange?: (query: QueryExplorerResult) => void;
37
31
  }
38
32
 
39
33
  // Note: For this to properly render outside of publisher,
@@ -42,18 +36,19 @@ interface ModelProps {
42
36
 
43
37
  export default function Model({
44
38
  modelPath,
39
+ versionId,
45
40
  expandResults,
46
41
  hideResultIcons,
47
42
  expandEmbeddings,
48
43
  hideEmbeddingIcons,
44
+ onChange,
49
45
  }: ModelProps) {
50
46
  const [embeddingExpanded, setEmbeddingExpanded] =
51
47
  React.useState<boolean>(false);
52
48
  const [highlightedEmbedCode, setHighlightedEmbedCode] =
53
49
  React.useState<string>();
54
- const [selectedTab, setSelectedTab] = React.useState(0);
55
50
 
56
- const { projectName, packageName, versionId } = usePackage();
51
+ const { isError, isLoading, error } = useModelData(modelPath, versionId);
57
52
  const modelCodeSnippet = getModelCodeSnippet(modelPath);
58
53
  useEffect(() => {
59
54
  highlight(modelCodeSnippet, "typescript").then((code) => {
@@ -61,33 +56,13 @@ export default function Model({
61
56
  });
62
57
  }, [embeddingExpanded, modelCodeSnippet]);
63
58
 
64
- const { data, isError, isLoading, error } =
65
- useQueryWithApiError<CompiledModel>({
66
- queryKey: ["package", projectName, packageName, modelPath, versionId],
67
- queryFn: async (config) => {
68
- const response = await modelsApi.getModel(
69
- projectName,
70
- packageName,
71
- modelPath,
72
- versionId,
73
- config,
74
- );
75
- return response.data;
76
- },
77
- });
78
-
79
59
  if (isLoading) {
80
60
  return <Loading text="Fetching Model..." />;
81
61
  }
82
62
 
83
63
  if (isError) {
84
64
  console.log("error", error);
85
- return (
86
- <ApiErrorDisplay
87
- error={error}
88
- context={`${packageName} > ${modelPath}`}
89
- />
90
- );
65
+ return <ApiErrorDisplay error={error} context={`Model > ${modelPath}`} />;
91
66
  }
92
67
  return (
93
68
  <StyledCard variant="outlined">
@@ -95,39 +70,9 @@ export default function Model({
95
70
  <Stack
96
71
  sx={{
97
72
  flexDirection: "row",
98
- justifyContent: "space-between",
73
+ justifyContent: "flex-end",
99
74
  }}
100
75
  >
101
- {Array.isArray(data.sourceInfos) &&
102
- data.sourceInfos.length > 0 && (
103
- <Tabs
104
- value={selectedTab}
105
- onChange={(_, newValue) => setSelectedTab(newValue)}
106
- variant="scrollable"
107
- scrollButtons="auto"
108
- sx={{
109
- borderBottom: 1,
110
- borderColor: "divider",
111
- minHeight: 36,
112
- }}
113
- >
114
- {data.sourceInfos.map((source, idx) => {
115
- let sourceInfo;
116
- try {
117
- sourceInfo = JSON.parse(source);
118
- } catch {
119
- sourceInfo = { name: String(idx) };
120
- }
121
- return (
122
- <Tab
123
- key={sourceInfo.name || idx}
124
- label={sourceInfo.name || `Source ${idx + 1}`}
125
- sx={{ minHeight: 36 }}
126
- />
127
- );
128
- })}
129
- </Tabs>
130
- )}
131
76
  {!hideEmbeddingIcons && (
132
77
  <CardActions
133
78
  sx={{
@@ -191,51 +136,15 @@ export default function Model({
191
136
  </Collapse>
192
137
  <Divider />
193
138
  </StyledCardContent>
194
- <StyledCardMedia>
195
- <Stack spacing={2} component="section">
196
- {/* Only render the selected sourceInfo */}
197
- {Array.isArray(data.sourceInfos) &&
198
- data.sourceInfos.length > 0 && (
199
- <SourceExplorerComponent
200
- sourceAndPath={{
201
- modelPath,
202
- sourceInfo: JSON.parse(
203
- data.sourceInfos[selectedTab],
204
- ),
205
- }}
206
- />
207
- )}
208
- {data.queries?.length > 0 && (
209
- <StyledCard
210
- variant="outlined"
211
- sx={{ padding: "0px 10px 0px 10px" }}
212
- >
213
- <StyledCardContent sx={{ p: "10px" }}>
214
- <Typography variant="subtitle1">
215
- Named Queries
216
- </Typography>
217
- </StyledCardContent>
218
- <Stack spacing={1} component="section">
219
- {data.queries.map((query) => (
220
- <ModelCell
221
- key={query.name}
222
- modelPath={modelPath}
223
- queryName={query.name}
224
- expandResult={expandResults}
225
- hideResultIcon={hideResultIcons}
226
- expandEmbedding={expandEmbeddings}
227
- hideEmbeddingIcon={hideEmbeddingIcons}
228
- noView={true}
229
- annotations={query.annotations}
230
- />
231
- ))}
232
- </Stack>
233
- <Box height="10px" />
234
- </StyledCard>
235
- )}
236
- <Box height="5px" />
237
- </Stack>
238
- </StyledCardMedia>
139
+ <ModelExplorer
140
+ modelPath={modelPath}
141
+ versionId={versionId}
142
+ expandResults={expandResults}
143
+ hideResultIcons={hideResultIcons}
144
+ expandEmbeddings={expandEmbeddings}
145
+ hideEmbeddingIcons={hideEmbeddingIcons}
146
+ onChange={onChange}
147
+ />
239
148
  </StyledCard>
240
149
  );
241
150
  }
@@ -0,0 +1,138 @@
1
+ import React from "react";
2
+ import { Box, Stack, Typography, Tabs, Tab } from "@mui/material";
3
+ import { StyledCard, StyledCardContent } from "../styles";
4
+ import { ModelCell } from "./ModelCell";
5
+ import {
6
+ QueryExplorerResult,
7
+ SourceExplorerComponent,
8
+ } from "./SourcesExplorer";
9
+ import { ApiErrorDisplay } from "../ApiErrorDisplay";
10
+ import { Loading } from "../Loading";
11
+ import { useModelData } from "./useModelData";
12
+
13
+ export interface ModelExplorerProps {
14
+ modelPath: string;
15
+ versionId?: string;
16
+ /** Display options forwarded to ModelCell */
17
+ expandResults?: boolean;
18
+ hideResultIcons?: boolean;
19
+ expandEmbeddings?: boolean;
20
+ hideEmbeddingIcons?: boolean;
21
+ /** Callback when the explorer changes (e.g. when a query is selected). */
22
+ onChange?: (query: QueryExplorerResult) => void;
23
+ }
24
+
25
+ /**
26
+ * ModelExplorer renders the main explorer UI for a Malloy model. It shows the
27
+ * selected source (via `SourceExplorerComponent`) along with the list of named
28
+ * queries for that model. This logic was originally embedded inside `Model.tsx`
29
+ * but has been extracted for easier reuse.
30
+ */
31
+ export function ModelExplorer({
32
+ modelPath,
33
+ versionId,
34
+ expandResults,
35
+ hideResultIcons,
36
+ expandEmbeddings,
37
+ hideEmbeddingIcons,
38
+ onChange,
39
+ }: ModelExplorerProps) {
40
+ const [selectedTab, setSelectedTab] = React.useState(0);
41
+
42
+ const { data, isError, isLoading, error } = useModelData(
43
+ modelPath,
44
+ versionId,
45
+ );
46
+
47
+ if (isLoading) {
48
+ return <Loading text="Fetching Model..." />;
49
+ }
50
+
51
+ if (isError) {
52
+ console.log("error", error);
53
+ return (
54
+ <ApiErrorDisplay
55
+ error={error}
56
+ context={`ModelExplorer > ${modelPath}`}
57
+ />
58
+ );
59
+ }
60
+
61
+ return (
62
+ <Stack spacing={2} component="section">
63
+ {/* Render the tabs for source selection */}
64
+ {Array.isArray(data.sourceInfos) && data.sourceInfos.length > 0 && (
65
+ <Stack sx={{ flexDirection: "row", justifyContent: "flex-start" }}>
66
+ <Tabs
67
+ value={selectedTab}
68
+ onChange={(_, newValue) => setSelectedTab(newValue)}
69
+ variant="scrollable"
70
+ scrollButtons="auto"
71
+ sx={{
72
+ borderBottom: 1,
73
+ borderColor: "divider",
74
+ minHeight: 36,
75
+ }}
76
+ >
77
+ {data.sourceInfos.map((source, idx) => {
78
+ let sourceInfo;
79
+ try {
80
+ sourceInfo = JSON.parse(source);
81
+ } catch {
82
+ sourceInfo = { name: String(idx) };
83
+ }
84
+ return (
85
+ <Tab
86
+ key={sourceInfo.name || idx}
87
+ label={sourceInfo.name || `Source ${idx + 1}`}
88
+ sx={{ minHeight: 36 }}
89
+ />
90
+ );
91
+ })}
92
+ </Tabs>
93
+ </Stack>
94
+ )}
95
+
96
+ {/* Render the selected source info */}
97
+ {Array.isArray(data.sourceInfos) && data.sourceInfos.length > 0 && (
98
+ <SourceExplorerComponent
99
+ sourceAndPath={{
100
+ modelPath,
101
+ sourceInfo: JSON.parse(data.sourceInfos[selectedTab]),
102
+ }}
103
+ onChange={onChange}
104
+ />
105
+ )}
106
+
107
+ {/* Render the named queries */}
108
+ {data.queries?.length > 0 && (
109
+ <StyledCard
110
+ variant="outlined"
111
+ sx={{ padding: "0px 10px 0px 10px" }}
112
+ >
113
+ <StyledCardContent sx={{ p: "10px" }}>
114
+ <Typography variant="subtitle1">Named Queries</Typography>
115
+ </StyledCardContent>
116
+
117
+ <Stack spacing={1} component="section">
118
+ {data.queries.map((query) => (
119
+ <ModelCell
120
+ key={query.name}
121
+ modelPath={modelPath}
122
+ queryName={query.name}
123
+ expandResult={expandResults}
124
+ hideResultIcon={hideResultIcons}
125
+ expandEmbedding={expandEmbeddings}
126
+ hideEmbeddingIcon={hideEmbeddingIcons}
127
+ noView={true}
128
+ annotations={query.annotations}
129
+ />
130
+ ))}
131
+ </Stack>
132
+ <Box height="10px" />
133
+ </StyledCard>
134
+ )}
135
+ <Box height="5px" />
136
+ </Stack>
137
+ );
138
+ }