@malloy-publisher/sdk 0.0.81 → 0.0.83

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.
@@ -0,0 +1,342 @@
1
+ .w-md-editor-bar {
2
+ position: absolute;
3
+ cursor: s-resize;
4
+ right: 0;
5
+ bottom: 0;
6
+ margin-top: -11px;
7
+ margin-right: 0;
8
+ width: 14px;
9
+ z-index: 3;
10
+ height: 10px;
11
+ border-radius: 0 0 3px 0;
12
+ -webkit-user-select: none;
13
+ user-select: none;
14
+ }
15
+ .w-md-editor-bar svg {
16
+ display: block;
17
+ margin: 0 auto;
18
+ }
19
+ .w-md-editor-area {
20
+ overflow: auto;
21
+ border-radius: 5px;
22
+ }
23
+ .w-md-editor-text {
24
+ min-height: 100%;
25
+ position: relative;
26
+ text-align: left;
27
+ white-space: pre-wrap;
28
+ word-break: keep-all;
29
+ overflow-wrap: break-word;
30
+ box-sizing: border-box;
31
+ padding: 10px;
32
+ margin: 0;
33
+ font-size: 14px !important;
34
+ line-height: 18px !important;
35
+ font-variant-ligatures: common-ligatures;
36
+ }
37
+ .w-md-editor-text-pre,
38
+ .w-md-editor-text-input,
39
+ .w-md-editor-text > .w-md-editor-text-pre {
40
+ margin: 0;
41
+ border: 0;
42
+ background: none;
43
+ box-sizing: inherit;
44
+ display: inherit;
45
+ font-family: inherit;
46
+ font-family: var(--md-editor-font-family) !important;
47
+ font-size: inherit;
48
+ font-style: inherit;
49
+ font-variant-ligatures: inherit;
50
+ font-weight: inherit;
51
+ letter-spacing: inherit;
52
+ line-height: inherit;
53
+ tab-size: inherit;
54
+ text-indent: inherit;
55
+ text-rendering: inherit;
56
+ text-transform: inherit;
57
+ white-space: inherit;
58
+ overflow-wrap: inherit;
59
+ word-break: inherit;
60
+ word-break: normal;
61
+ padding: 0;
62
+ }
63
+ .w-md-editor-text-pre {
64
+ position: relative;
65
+ margin: 0px !important;
66
+ pointer-events: none;
67
+ background-color: transparent !important;
68
+ }
69
+ .w-md-editor-text-pre > code {
70
+ padding: 0 !important;
71
+ font-family: var(--md-editor-font-family) !important;
72
+ font-size: 14px !important;
73
+ line-height: 18px !important;
74
+ }
75
+ .w-md-editor-text-input {
76
+ position: absolute;
77
+ top: 0px;
78
+ left: 0px;
79
+ height: 100%;
80
+ width: 100%;
81
+ resize: none;
82
+ color: inherit;
83
+ overflow: hidden;
84
+ outline: 0;
85
+ padding: inherit;
86
+ -webkit-font-smoothing: antialiased;
87
+ -webkit-text-fill-color: transparent;
88
+ }
89
+ .w-md-editor-text-input:empty {
90
+ -webkit-text-fill-color: inherit !important;
91
+ }
92
+ .w-md-editor-text-pre,
93
+ .w-md-editor-text-input {
94
+ word-wrap: pre;
95
+ word-break: break-word;
96
+ white-space: pre-wrap;
97
+ }
98
+ /**
99
+ * Hack to apply on some CSS on IE10 and IE11
100
+ */
101
+ @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
102
+ /**
103
+ * IE doesn't support '-webkit-text-fill-color'
104
+ * So we use 'color: transparent' to make the text transparent on IE
105
+ * Unlike other browsers, it doesn't affect caret color in IE
106
+ */
107
+ .w-md-editor-text-input {
108
+ color: transparent !important;
109
+ }
110
+ .w-md-editor-text-input::selection {
111
+ background-color: #accef7 !important;
112
+ color: transparent !important;
113
+ }
114
+ }
115
+ .w-md-editor-text-pre .punctuation {
116
+ color: var(--color-prettylights-syntax-comment, #8b949e) !important;
117
+ }
118
+ .w-md-editor-text-pre .token.url,
119
+ .w-md-editor-text-pre .token.content {
120
+ color: var(--color-prettylights-syntax-constant, #0550ae) !important;
121
+ }
122
+ .w-md-editor-text-pre .token.title.important {
123
+ color: var(--color-prettylights-syntax-markup-bold, #24292f);
124
+ }
125
+ .w-md-editor-text-pre .token.code-block .function {
126
+ color: var(--color-prettylights-syntax-entity, #8250df);
127
+ }
128
+ .w-md-editor-text-pre .token.bold {
129
+ font-weight: unset !important;
130
+ }
131
+ .w-md-editor-text-pre .token.title {
132
+ line-height: unset !important;
133
+ font-size: unset !important;
134
+ font-weight: unset !important;
135
+ }
136
+ .w-md-editor-text-pre .token.code.keyword {
137
+ color: var(--color-prettylights-syntax-constant, #0550ae) !important;
138
+ }
139
+ .w-md-editor-text-pre .token.strike,
140
+ .w-md-editor-text-pre .token.strike .content {
141
+ color: var(--color-prettylights-syntax-markup-deleted-text, #82071e) !important;
142
+ }
143
+ .w-md-editor-toolbar-child {
144
+ position: absolute;
145
+ border-radius: 3px;
146
+ box-shadow: 0 0 0 1px var(--md-editor-box-shadow-color), 0 0 0 var(--md-editor-box-shadow-color), 0 1px 1px var(--md-editor-box-shadow-color);
147
+ background-color: var(--md-editor-background-color);
148
+ z-index: 1;
149
+ display: none;
150
+ }
151
+ .w-md-editor-toolbar-child.active {
152
+ display: block;
153
+ }
154
+ .w-md-editor-toolbar-child .w-md-editor-toolbar {
155
+ border-bottom: 0;
156
+ padding: 3px;
157
+ border-radius: 3px;
158
+ }
159
+ .w-md-editor-toolbar-child .w-md-editor-toolbar ul > li {
160
+ display: block;
161
+ }
162
+ .w-md-editor-toolbar-child .w-md-editor-toolbar ul > li button {
163
+ width: -webkit-fill-available;
164
+ height: initial;
165
+ box-sizing: border-box;
166
+ padding: 3px 4px 2px 4px;
167
+ margin: 0;
168
+ }
169
+ .w-md-editor-toolbar {
170
+ border-bottom: 1px solid var(--md-editor-box-shadow-color);
171
+ background-color: var(--md-editor-background-color);
172
+ padding: 3px;
173
+ display: flex;
174
+ justify-content: space-between;
175
+ align-items: center;
176
+ border-radius: 3px 3px 0 0;
177
+ -webkit-user-select: none;
178
+ user-select: none;
179
+ flex-wrap: wrap;
180
+ }
181
+ .w-md-editor-toolbar.bottom {
182
+ border-bottom: 0px;
183
+ border-top: 1px solid var(--md-editor-box-shadow-color);
184
+ border-radius: 0 0 3px 3px;
185
+ }
186
+ .w-md-editor-toolbar ul,
187
+ .w-md-editor-toolbar li {
188
+ margin: 0;
189
+ padding: 0;
190
+ list-style: none;
191
+ line-height: initial;
192
+ }
193
+ .w-md-editor-toolbar li {
194
+ display: inline-block;
195
+ font-size: 14px;
196
+ }
197
+ .w-md-editor-toolbar li + li {
198
+ margin: 0;
199
+ }
200
+ .w-md-editor-toolbar li > button {
201
+ border: none;
202
+ height: 20px;
203
+ line-height: 14px;
204
+ background: none;
205
+ padding: 4px;
206
+ margin: 0 1px;
207
+ border-radius: 2px;
208
+ text-transform: none;
209
+ font-weight: normal;
210
+ overflow: visible;
211
+ outline: none;
212
+ cursor: pointer;
213
+ transition: all 0.3s;
214
+ white-space: nowrap;
215
+ color: var(--color-fg-default);
216
+ }
217
+ .w-md-editor-toolbar li > button:hover,
218
+ .w-md-editor-toolbar li > button:focus {
219
+ background-color: var(--color-neutral-muted);
220
+ color: var(--color-accent-fg);
221
+ }
222
+ .w-md-editor-toolbar li > button:active {
223
+ background-color: var(--color-neutral-muted);
224
+ color: var(--color-danger-fg);
225
+ }
226
+ .w-md-editor-toolbar li > button:disabled {
227
+ color: var(--md-editor-box-shadow-color);
228
+ cursor: not-allowed;
229
+ }
230
+ .w-md-editor-toolbar li > button:disabled:hover {
231
+ background-color: transparent;
232
+ color: var(--md-editor-box-shadow-color);
233
+ }
234
+ .w-md-editor-toolbar li.active > button {
235
+ color: var(--color-accent-fg);
236
+ background-color: var(--color-neutral-muted);
237
+ }
238
+ .w-md-editor-toolbar-divider {
239
+ height: 14px;
240
+ width: 1px;
241
+ margin: -3px 3px 0 3px !important;
242
+ vertical-align: middle;
243
+ background-color: var(--md-editor-box-shadow-color);
244
+ }
245
+ .w-md-editor {
246
+ text-align: left;
247
+ border-radius: 3px;
248
+ padding-bottom: 1px;
249
+ position: relative;
250
+ color: var(--color-fg-default);
251
+ --md-editor-font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
252
+ --md-editor-background-color: var(--color-canvas-default, #ffffff);
253
+ --md-editor-box-shadow-color: var(--color-border-default, #d0d7de);
254
+ box-shadow: 0 0 0 1px var(--md-editor-box-shadow-color), 0 0 0 var(--md-editor-box-shadow-color), 0 1px 1px var(--md-editor-box-shadow-color);
255
+ background-color: var(--md-editor-background-color);
256
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
257
+ display: flex;
258
+ flex-direction: column;
259
+ }
260
+ .w-md-editor.w-md-editor-rtl {
261
+ direction: rtl !important;
262
+ text-align: right !important;
263
+ }
264
+ .w-md-editor.w-md-editor-rtl .w-md-editor-preview {
265
+ right: unset !important;
266
+ left: 0;
267
+ text-align: right !important;
268
+ box-shadow: inset -1px 0 0 0 var(--md-editor-box-shadow-color);
269
+ }
270
+ .w-md-editor.w-md-editor-rtl .w-md-editor-text {
271
+ text-align: right !important;
272
+ }
273
+ .w-md-editor-toolbar {
274
+ height: -webkit-fit-content;
275
+ height: fit-content;
276
+ }
277
+ .w-md-editor-content {
278
+ height: 100%;
279
+ overflow: auto;
280
+ position: relative;
281
+ border-radius: 0 0 3px 0;
282
+ }
283
+ .w-md-editor .copied {
284
+ display: none !important;
285
+ }
286
+ .w-md-editor-input {
287
+ width: 50%;
288
+ height: 100%;
289
+ }
290
+ .w-md-editor-text-pre > code {
291
+ word-break: break-word !important;
292
+ white-space: pre-wrap !important;
293
+ }
294
+ .w-md-editor-preview {
295
+ width: 50%;
296
+ box-sizing: border-box;
297
+ box-shadow: inset 1px 0 0 0 var(--md-editor-box-shadow-color);
298
+ position: absolute;
299
+ padding: 10px 20px;
300
+ overflow: auto;
301
+ top: 0;
302
+ right: 0;
303
+ bottom: 0;
304
+ border-radius: 0 0 5px 0;
305
+ display: flex;
306
+ flex-direction: column;
307
+ }
308
+ .w-md-editor-preview .anchor {
309
+ display: none;
310
+ }
311
+ .w-md-editor-preview .contains-task-list li.task-list-item {
312
+ list-style: none;
313
+ }
314
+ .w-md-editor-show-preview .w-md-editor-input {
315
+ width: 0%;
316
+ overflow: hidden;
317
+ background-color: var(--md-editor-background-color);
318
+ }
319
+ .w-md-editor-show-preview .w-md-editor-preview {
320
+ width: 100%;
321
+ box-shadow: inset 0 0 0 0;
322
+ }
323
+ .w-md-editor-show-edit .w-md-editor-input {
324
+ width: 100%;
325
+ }
326
+ .w-md-editor-show-edit .w-md-editor-preview {
327
+ width: 0%;
328
+ padding: 0;
329
+ }
330
+ .w-md-editor-fullscreen {
331
+ overflow: hidden;
332
+ position: fixed;
333
+ z-index: 99999;
334
+ top: 0;
335
+ left: 0;
336
+ right: 0;
337
+ bottom: 0;
338
+ height: 100% !important;
339
+ }
340
+ .w-md-editor-fullscreen .w-md-editor-content {
341
+ height: 100%;
342
+ }
@@ -0,0 +1,3 @@
1
+ /* SDK Styles */
2
+ @import "./malloy-explorer.css";
3
+ @import "./markdown-editor.css";
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.81",
4
+ "version": "0.0.83",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",
@@ -14,6 +14,12 @@
14
14
  },
15
15
  "./malloy-explorer.css": {
16
16
  "default": "./dist/malloy-explorer.css"
17
+ },
18
+ "./markdown-editor.css": {
19
+ "default": "./dist/markdown-editor.css"
20
+ },
21
+ "./styles.css": {
22
+ "default": "./dist/styles.css"
17
23
  }
18
24
  },
19
25
  "style": "./dist/malloy-explorer.css",
@@ -22,7 +28,7 @@
22
28
  },
23
29
  "scripts": {
24
30
  "build": "bun generate-api-types && bunx vite build",
25
- "postbuild": "cp ../../node_modules/@malloydata/malloy-explorer/dist/malloy-explorer.css ./dist/malloy-explorer.css",
31
+ "postbuild": "cp ../../node_modules/@malloydata/malloy-explorer/dist/malloy-explorer.css ./dist/malloy-explorer.css && cp ../../node_modules/@uiw/react-md-editor/markdown-editor.css ./dist/markdown-editor.css && echo '/* SDK Styles */\n@import \"./malloy-explorer.css\";\n@import \"./markdown-editor.css\";' > ./dist/styles.css",
26
32
  "test": "",
27
33
  "lint": "bunx eslint ./src --ext .ts,.tsx --ignore-path .gitignore --fix",
28
34
  "format": "bunx prettier --write --parser typescript '**/*.{ts,tsx}'",
@@ -1,34 +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 {
25
- QueryExplorerResult,
26
- SourceExplorerComponent,
27
- } from "./SourcesExplorer";
18
+ import { QueryExplorerResult } from "./SourcesExplorer";
28
19
  import { Loading } from "../Loading";
29
- import { useQueryWithApiError } from "../../hooks/useQueryWithApiError";
30
-
31
- const modelsApi = new ModelsApi(new Configuration());
20
+ import { ModelExplorer } from "./ModelExplorer";
21
+ import { useModelData } from "./useModelData";
32
22
 
33
23
  interface ModelProps {
34
24
  modelPath: string;
@@ -46,6 +36,7 @@ interface ModelProps {
46
36
 
47
37
  export default function Model({
48
38
  modelPath,
39
+ versionId,
49
40
  expandResults,
50
41
  hideResultIcons,
51
42
  expandEmbeddings,
@@ -56,9 +47,8 @@ export default function Model({
56
47
  React.useState<boolean>(false);
57
48
  const [highlightedEmbedCode, setHighlightedEmbedCode] =
58
49
  React.useState<string>();
59
- const [selectedTab, setSelectedTab] = React.useState(0);
60
50
 
61
- const { projectName, packageName, versionId } = usePackage();
51
+ const { isError, isLoading, error } = useModelData(modelPath, versionId);
62
52
  const modelCodeSnippet = getModelCodeSnippet(modelPath);
63
53
  useEffect(() => {
64
54
  highlight(modelCodeSnippet, "typescript").then((code) => {
@@ -66,33 +56,13 @@ export default function Model({
66
56
  });
67
57
  }, [embeddingExpanded, modelCodeSnippet]);
68
58
 
69
- const { data, isError, isLoading, error } =
70
- useQueryWithApiError<CompiledModel>({
71
- queryKey: ["package", projectName, packageName, modelPath, versionId],
72
- queryFn: async (config) => {
73
- const response = await modelsApi.getModel(
74
- projectName,
75
- packageName,
76
- modelPath,
77
- versionId,
78
- config,
79
- );
80
- return response.data;
81
- },
82
- });
83
-
84
59
  if (isLoading) {
85
60
  return <Loading text="Fetching Model..." />;
86
61
  }
87
62
 
88
63
  if (isError) {
89
64
  console.log("error", error);
90
- return (
91
- <ApiErrorDisplay
92
- error={error}
93
- context={`${packageName} > ${modelPath}`}
94
- />
95
- );
65
+ return <ApiErrorDisplay error={error} context={`Model > ${modelPath}`} />;
96
66
  }
97
67
  return (
98
68
  <StyledCard variant="outlined">
@@ -100,39 +70,9 @@ export default function Model({
100
70
  <Stack
101
71
  sx={{
102
72
  flexDirection: "row",
103
- justifyContent: "space-between",
73
+ justifyContent: "flex-end",
104
74
  }}
105
75
  >
106
- {Array.isArray(data.sourceInfos) &&
107
- data.sourceInfos.length > 0 && (
108
- <Tabs
109
- value={selectedTab}
110
- onChange={(_, newValue) => setSelectedTab(newValue)}
111
- variant="scrollable"
112
- scrollButtons="auto"
113
- sx={{
114
- borderBottom: 1,
115
- borderColor: "divider",
116
- minHeight: 36,
117
- }}
118
- >
119
- {data.sourceInfos.map((source, idx) => {
120
- let sourceInfo;
121
- try {
122
- sourceInfo = JSON.parse(source);
123
- } catch {
124
- sourceInfo = { name: String(idx) };
125
- }
126
- return (
127
- <Tab
128
- key={sourceInfo.name || idx}
129
- label={sourceInfo.name || `Source ${idx + 1}`}
130
- sx={{ minHeight: 36 }}
131
- />
132
- );
133
- })}
134
- </Tabs>
135
- )}
136
76
  {!hideEmbeddingIcons && (
137
77
  <CardActions
138
78
  sx={{
@@ -196,52 +136,15 @@ export default function Model({
196
136
  </Collapse>
197
137
  <Divider />
198
138
  </StyledCardContent>
199
- <StyledCardMedia>
200
- <Stack spacing={2} component="section">
201
- {/* Only render the selected sourceInfo */}
202
- {Array.isArray(data.sourceInfos) &&
203
- data.sourceInfos.length > 0 && (
204
- <SourceExplorerComponent
205
- sourceAndPath={{
206
- modelPath,
207
- sourceInfo: JSON.parse(
208
- data.sourceInfos[selectedTab],
209
- ),
210
- }}
211
- onChange={onChange}
212
- />
213
- )}
214
- {data.queries?.length > 0 && (
215
- <StyledCard
216
- variant="outlined"
217
- sx={{ padding: "0px 10px 0px 10px" }}
218
- >
219
- <StyledCardContent sx={{ p: "10px" }}>
220
- <Typography variant="subtitle1">
221
- Named Queries
222
- </Typography>
223
- </StyledCardContent>
224
- <Stack spacing={1} component="section">
225
- {data.queries.map((query) => (
226
- <ModelCell
227
- key={query.name}
228
- modelPath={modelPath}
229
- queryName={query.name}
230
- expandResult={expandResults}
231
- hideResultIcon={hideResultIcons}
232
- expandEmbedding={expandEmbeddings}
233
- hideEmbeddingIcon={hideEmbeddingIcons}
234
- noView={true}
235
- annotations={query.annotations}
236
- />
237
- ))}
238
- </Stack>
239
- <Box height="10px" />
240
- </StyledCard>
241
- )}
242
- <Box height="5px" />
243
- </Stack>
244
- </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
+ />
245
148
  </StyledCard>
246
149
  );
247
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
+ }