@malloy-publisher/sdk 0.0.199 → 0.0.201
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/dist/ServerProvider-BSyxB6sf.cjs.js +1 -0
- package/dist/{ServerProvider-BuM1usxf.es.js → ServerProvider-DSnbMlP3.es.js} +330 -470
- package/dist/client/api.d.ts +21 -121
- package/dist/client/index.cjs.js +1 -1
- package/dist/client/index.es.js +1 -1
- package/dist/components/Connections/EditConnectionDialog.d.ts +2 -1
- package/dist/components/given/GivenInput.d.ts +16 -0
- package/dist/components/given/GivensPanel.d.ts +18 -0
- package/dist/components/given/index.d.ts +2 -0
- package/dist/{core-DfcpQGVP.es.js → core-B3IQNPBD.es.js} +1 -1
- package/dist/{core-yDgxkpo0.cjs.js → core-GkjltsUf.cjs.js} +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useGivensForm.d.ts +33 -0
- package/dist/hooks/useModelGivens.d.ts +10 -0
- package/dist/index-BpoC5QHF.cjs.js +229 -0
- package/dist/{index-Y4ooZDYA.es.js → index-uW-ZBpF2.es.js} +26102 -25626
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +28 -26
- package/package.json +1 -1
- package/src/components/Connections/DeleteConnectionDialog.tsx +10 -3
- package/src/components/Connections/EditConnectionDialog.tsx +11 -3
- package/src/components/Environment/Connections.tsx +388 -0
- package/src/components/Environment/Environment.tsx +7 -2
- package/src/components/Notebook/Notebook.tsx +81 -23
- package/src/components/Package/Package.tsx +0 -7
- package/src/components/given/GivenInput.tsx +190 -0
- package/src/components/given/GivensPanel.tsx +85 -0
- package/src/components/given/index.ts +2 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/useGivensForm.ts +110 -0
- package/src/hooks/useModelGivens.ts +26 -0
- package/dist/ServerProvider-C_Mnvmgc.cjs.js +0 -1
- package/dist/index-CMA8U4-B.cjs.js +0 -228
- package/src/components/Package/Connections.tsx +0 -373
- /package/dist/components/{Package → Environment}/Connections.d.ts +0 -0
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BpoC5QHF.cjs.js"),o=require("./ServerProvider-BSyxB6sf.cjs.js");exports.AnalyzePackageButton=e.AnalyzePackageButton;exports.BrowserWorkbookStorage=e.BrowserWorkbookStorage;exports.ConnectionExplorer=e.ConnectionExplorer;exports.DimensionFilter=e.DimensionFilter;exports.EmbeddedQueryResult=e.EmbeddedQueryResult;exports.Environment=e.Environment;exports.Home=e.Home;exports.Loading=e.Loading;exports.Model=e.Model;exports.ModelExplorer=e.ModelExplorer;exports.ModelExplorerDialog=e.ModelExplorerDialog;exports.Notebook=e.Notebook;exports.Package=e.Package;exports.Packages=e.Packages;exports.QueryResult=e.QueryResult;exports.RenderedResult=e.RenderedResult;exports.ResultContainer=e.ResultContainer;exports.SourceExplorerComponent=e.SourceExplorerComponent;exports.SourcesExplorer=e.SourcesExplorer;exports.Workbook=e.Workbook;exports.WorkbookList=e.WorkbookList;exports.WorkbookManager=e.WorkbookManager;exports.WorkbookStorageProvider=e.WorkbookStorageProvider;exports.createEmbeddedQueryResult=e.createEmbeddedQueryResult;exports.encodeResourceUri=e.encodeResourceUri;exports.extractDimensionSpecs=e.extractDimensionSpecs;exports.extractSourceFromQuery=e.extractSourceFromQuery;exports.generateFilterClause=e.generateFilterClause;exports.getDimensionKey=e.getDimensionKey;exports.getJoinedSources=e.getJoinedSources;exports.injectWhereClause=e.injectWhereClause;exports.makeDimensionKey=e.makeDimensionKey;exports.parseAllSourceInfos=e.parseAllSourceInfos;exports.parseDimensionFilterAnnotation=e.parseDimensionFilterAnnotation;exports.parseNotebookFilterAnnotation=e.parseNotebookFilterAnnotation;exports.parseResourceUri=e.parseResourceUri;exports.useDimensionFilters=e.useDimensionFilters;exports.useDimensionFiltersFromSpec=e.useDimensionFiltersFromSpec;exports.useDimensionFiltersQuery=e.useDimensionFiltersQuery;exports.useDimensionalFilterRangeData=e.useDimensionalFilterRangeData;exports.useGivensForm=e.useGivensForm;exports.useModelData=e.useModelData;exports.useModelGivens=e.useModelGivens;exports.useRawQueryData=e.useRawQueryData;exports.useRouterClickHandler=e.useRouterClickHandler;exports.ServerProvider=o.ServerProvider;exports.useServer=o.useServer;
|
package/dist/index.es.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { A as a, I as o, C as r, D as n, x as
|
|
2
|
-
import { S as
|
|
1
|
+
import { A as a, I as o, C as r, D as n, x as i, E as t, H as u, L as l, M as m, o as c, q as d, N as k, v as p, P as D, Q as g, R as S, B as F, r as R, S as x, W as y, F as b, J as E, G as v, y as C, $ as M, g as Q, i as W, j as P, V as A, k as f, l as B, X as G, p as H, m as K, n as L, _ as N, K as U, O as j, T as w, U as I, Z as J, t as h, Y as q, u as z, e as O } from "./index-uW-ZBpF2.es.js";
|
|
2
|
+
import { S as V, u as X } from "./ServerProvider-DSnbMlP3.es.js";
|
|
3
3
|
export {
|
|
4
4
|
a as AnalyzePackageButton,
|
|
5
5
|
o as BrowserWorkbookStorage,
|
|
6
6
|
r as ConnectionExplorer,
|
|
7
7
|
n as DimensionFilter,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
i as EmbeddedQueryResult,
|
|
9
|
+
t as Environment,
|
|
10
|
+
u as Home,
|
|
11
|
+
l as Loading,
|
|
12
12
|
m as Model,
|
|
13
13
|
c as ModelExplorer,
|
|
14
14
|
d as ModelExplorerDialog,
|
|
@@ -17,33 +17,35 @@ export {
|
|
|
17
17
|
D as Packages,
|
|
18
18
|
g as QueryResult,
|
|
19
19
|
S as RenderedResult,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
F as ResultContainer,
|
|
21
|
+
V as ServerProvider,
|
|
22
|
+
R as SourceExplorerComponent,
|
|
23
23
|
x as SourcesExplorer,
|
|
24
24
|
y as Workbook,
|
|
25
25
|
b as WorkbookList,
|
|
26
26
|
E as WorkbookManager,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
v as WorkbookStorageProvider,
|
|
28
|
+
C as createEmbeddedQueryResult,
|
|
29
|
+
M as encodeResourceUri,
|
|
30
|
+
Q as extractDimensionSpecs,
|
|
31
|
+
W as extractSourceFromQuery,
|
|
32
32
|
P as generateFilterClause,
|
|
33
33
|
A as getDimensionKey,
|
|
34
34
|
f as getJoinedSources,
|
|
35
35
|
B as injectWhereClause,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
G as makeDimensionKey,
|
|
37
|
+
H as parseAllSourceInfos,
|
|
38
|
+
K as parseDimensionFilterAnnotation,
|
|
39
|
+
L as parseNotebookFilterAnnotation,
|
|
40
|
+
N as parseResourceUri,
|
|
41
|
+
U as useDimensionFilters,
|
|
42
|
+
j as useDimensionFiltersFromSpec,
|
|
43
|
+
w as useDimensionFiltersQuery,
|
|
44
|
+
I as useDimensionalFilterRangeData,
|
|
45
|
+
J as useGivensForm,
|
|
45
46
|
h as useModelData,
|
|
46
|
-
q as
|
|
47
|
-
z as
|
|
48
|
-
|
|
47
|
+
q as useModelGivens,
|
|
48
|
+
z as useRawQueryData,
|
|
49
|
+
O as useRouterClickHandler,
|
|
50
|
+
X as useServer
|
|
49
51
|
};
|
package/package.json
CHANGED
|
@@ -7,6 +7,9 @@ import DialogActions from "@mui/material/DialogActions";
|
|
|
7
7
|
import DialogContent from "@mui/material/DialogContent";
|
|
8
8
|
import DialogTitle from "@mui/material/DialogTitle";
|
|
9
9
|
import IconButton from "@mui/material/IconButton";
|
|
10
|
+
import ListItemIcon from "@mui/material/ListItemIcon";
|
|
11
|
+
import ListItemText from "@mui/material/ListItemText";
|
|
12
|
+
import MenuItem from "@mui/material/MenuItem";
|
|
10
13
|
import Typography from "@mui/material/Typography";
|
|
11
14
|
import React, { useState } from "react";
|
|
12
15
|
import { Connection } from "../../client";
|
|
@@ -34,15 +37,19 @@ export default function DeleteConnectionDialog({
|
|
|
34
37
|
|
|
35
38
|
return (
|
|
36
39
|
<React.Fragment>
|
|
37
|
-
<
|
|
40
|
+
<MenuItem
|
|
38
41
|
aria-label={`Delete connection ${connection?.name ?? ""}`.trim()}
|
|
39
42
|
onClick={(event) => {
|
|
40
43
|
event.stopPropagation();
|
|
41
44
|
handleClickOpen();
|
|
42
45
|
}}
|
|
46
|
+
sx={{ color: "error.main" }}
|
|
43
47
|
>
|
|
44
|
-
<
|
|
45
|
-
|
|
48
|
+
<ListItemIcon sx={{ color: "inherit" }}>
|
|
49
|
+
<Delete fontSize="small" />
|
|
50
|
+
</ListItemIcon>
|
|
51
|
+
<ListItemText>Delete</ListItemText>
|
|
52
|
+
</MenuItem>
|
|
46
53
|
|
|
47
54
|
<Dialog
|
|
48
55
|
onClose={handleClose}
|
|
@@ -8,6 +8,8 @@ import DialogContent from "@mui/material/DialogContent";
|
|
|
8
8
|
import DialogContentText from "@mui/material/DialogContentText";
|
|
9
9
|
import DialogTitle from "@mui/material/DialogTitle";
|
|
10
10
|
import IconButton from "@mui/material/IconButton";
|
|
11
|
+
import ListItemIcon from "@mui/material/ListItemIcon";
|
|
12
|
+
import ListItemText from "@mui/material/ListItemText";
|
|
11
13
|
import TextField from "@mui/material/TextField";
|
|
12
14
|
import Typography from "@mui/material/Typography";
|
|
13
15
|
import React, { useState } from "react";
|
|
@@ -34,6 +36,7 @@ type EditConnectionDialogProps = {
|
|
|
34
36
|
connection: Connection;
|
|
35
37
|
onSubmit: (connection: Connection) => Promise<unknown>;
|
|
36
38
|
isSubmitting: boolean;
|
|
39
|
+
onCloseDialog?: () => void;
|
|
37
40
|
};
|
|
38
41
|
|
|
39
42
|
function initAttachedDatabases(connection: Connection) {
|
|
@@ -56,6 +59,7 @@ export default function EditConnectionDialog({
|
|
|
56
59
|
connection,
|
|
57
60
|
onSubmit,
|
|
58
61
|
isSubmitting,
|
|
62
|
+
onCloseDialog,
|
|
59
63
|
}: EditConnectionDialogProps) {
|
|
60
64
|
const [open, setOpen] = useState(false);
|
|
61
65
|
const [type, setType] = useState<Connection["type"]>(connection.type);
|
|
@@ -83,6 +87,7 @@ export default function EditConnectionDialog({
|
|
|
83
87
|
|
|
84
88
|
const handleClose = () => {
|
|
85
89
|
setOpen(false);
|
|
90
|
+
onCloseDialog?.();
|
|
86
91
|
};
|
|
87
92
|
|
|
88
93
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
@@ -446,7 +451,7 @@ export default function EditConnectionDialog({
|
|
|
446
451
|
|
|
447
452
|
return (
|
|
448
453
|
<React.Fragment>
|
|
449
|
-
<
|
|
454
|
+
<MenuItem
|
|
450
455
|
aria-label={`Edit connection ${connection?.name ?? ""}`.trim()}
|
|
451
456
|
onClick={(event) => {
|
|
452
457
|
event.preventDefault();
|
|
@@ -454,8 +459,11 @@ export default function EditConnectionDialog({
|
|
|
454
459
|
handleClickOpen();
|
|
455
460
|
}}
|
|
456
461
|
>
|
|
457
|
-
<
|
|
458
|
-
|
|
462
|
+
<ListItemIcon>
|
|
463
|
+
<Edit fontSize="small" />
|
|
464
|
+
</ListItemIcon>
|
|
465
|
+
<ListItemText>Edit</ListItemText>
|
|
466
|
+
</MenuItem>
|
|
459
467
|
<Dialog open={open} onClose={handleClose}>
|
|
460
468
|
<DialogTitle
|
|
461
469
|
onClick={(event) => {
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { MoreVert } from "@mui/icons-material";
|
|
2
|
+
import StorageOutlinedIcon from "@mui/icons-material/StorageOutlined";
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
Card,
|
|
6
|
+
CardContent,
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
Grid,
|
|
11
|
+
IconButton,
|
|
12
|
+
Menu,
|
|
13
|
+
Snackbar,
|
|
14
|
+
Typography,
|
|
15
|
+
} from "@mui/material";
|
|
16
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Connection as ApiConnection } from "../../client/api";
|
|
19
|
+
import {
|
|
20
|
+
useMutationWithApiError,
|
|
21
|
+
useQueryWithApiError,
|
|
22
|
+
} from "../../hooks/useQueryWithApiError";
|
|
23
|
+
import { encodeResourceUri, parseResourceUri } from "../../utils/formatting";
|
|
24
|
+
import { ApiErrorDisplay } from "../ApiErrorDisplay";
|
|
25
|
+
import AddConnectionDialog from "../Connections/AddConnectionDialog";
|
|
26
|
+
import DeleteConnectionDialog from "../Connections/DeleteConnectionDialog";
|
|
27
|
+
import EditConnectionDialog from "../Connections/EditConnectionDialog";
|
|
28
|
+
import { useServer } from "../ServerProvider";
|
|
29
|
+
import ConnectionExplorer from "./ConnectionExplorer";
|
|
30
|
+
|
|
31
|
+
const CONNECTION_TYPE_LABELS: Record<string, string> = {
|
|
32
|
+
bigquery: "BigQuery",
|
|
33
|
+
snowflake: "Snowflake",
|
|
34
|
+
postgres: "PostgreSQL",
|
|
35
|
+
mysql: "MySQL",
|
|
36
|
+
trino: "Trino",
|
|
37
|
+
databricks: "Databricks",
|
|
38
|
+
duckdb: "DuckDB",
|
|
39
|
+
ducklake: "DuckLake",
|
|
40
|
+
s3: "S3",
|
|
41
|
+
gcs: "GCS",
|
|
42
|
+
azure: "Azure",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function typeLabel(type: string | undefined): string {
|
|
46
|
+
if (!type) return "";
|
|
47
|
+
return CONNECTION_TYPE_LABELS[type] ?? type;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type ConnectionsProps = {
|
|
51
|
+
resourceUri: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default function Connections({ resourceUri }: ConnectionsProps) {
|
|
55
|
+
const { apiClients, mutable } = useServer();
|
|
56
|
+
const queryClient = useQueryClient();
|
|
57
|
+
const { environmentName } = parseResourceUri(resourceUri);
|
|
58
|
+
const [notificationMessage, setNotificationMessage] = useState("");
|
|
59
|
+
const [selectedConnection, setSelectedConnection] = useState<string | null>(
|
|
60
|
+
null,
|
|
61
|
+
);
|
|
62
|
+
const selectedConnectionResourceUri = encodeResourceUri({
|
|
63
|
+
environmentName,
|
|
64
|
+
connectionName: selectedConnection,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const { data, isSuccess, isError, error } = useQueryWithApiError({
|
|
68
|
+
queryKey: ["connections", environmentName],
|
|
69
|
+
queryFn: () => apiClients.connections.listConnections(environmentName),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const handleCloseDialog = () => {
|
|
73
|
+
setSelectedConnection(null);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const addConnection = useMutationWithApiError({
|
|
77
|
+
mutationFn: (payload: ApiConnection) => {
|
|
78
|
+
return apiClients.environments.updateEnvironment(environmentName, {
|
|
79
|
+
name: environmentName,
|
|
80
|
+
connections: [...data!.data, payload],
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
onSuccess() {
|
|
84
|
+
setNotificationMessage("Connection added successfully");
|
|
85
|
+
queryClient.invalidateQueries({
|
|
86
|
+
queryKey: ["connections", environmentName],
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
onError(error) {
|
|
90
|
+
setNotificationMessage(error.message);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const updateConnection = useMutationWithApiError({
|
|
95
|
+
mutationFn: (payload: ApiConnection) => {
|
|
96
|
+
return apiClients.environments.updateEnvironment(environmentName, {
|
|
97
|
+
name: environmentName,
|
|
98
|
+
connections: data!.data.map((conn) =>
|
|
99
|
+
conn.name === payload.name ? payload : conn,
|
|
100
|
+
),
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
onSuccess(_data, variables) {
|
|
104
|
+
setNotificationMessage(
|
|
105
|
+
`Connection ${variables.name} updated successfully`,
|
|
106
|
+
);
|
|
107
|
+
queryClient.invalidateQueries({
|
|
108
|
+
queryKey: ["connections", environmentName],
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
onError(error) {
|
|
112
|
+
setNotificationMessage(error.message);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const deleteConnection = useMutationWithApiError({
|
|
117
|
+
mutationFn: (payload: ApiConnection) => {
|
|
118
|
+
return apiClients.environments.updateEnvironment(environmentName, {
|
|
119
|
+
name: environmentName,
|
|
120
|
+
connections: data!.data.filter(
|
|
121
|
+
(conn) => conn.name !== payload.name,
|
|
122
|
+
),
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
onSuccess(_data, variables) {
|
|
126
|
+
setNotificationMessage(
|
|
127
|
+
`Connection ${variables.name} deleted successfully`,
|
|
128
|
+
);
|
|
129
|
+
queryClient.invalidateQueries({
|
|
130
|
+
queryKey: ["connections", environmentName],
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
onError(error) {
|
|
134
|
+
setNotificationMessage(error.message);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const connections = isSuccess
|
|
139
|
+
? [...data.data].sort((a, b) =>
|
|
140
|
+
(a.name ?? "").localeCompare(b.name ?? ""),
|
|
141
|
+
)
|
|
142
|
+
: [];
|
|
143
|
+
|
|
144
|
+
const isMutating =
|
|
145
|
+
addConnection.isPending ||
|
|
146
|
+
updateConnection.isPending ||
|
|
147
|
+
deleteConnection.isPending;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<Box>
|
|
151
|
+
<Box
|
|
152
|
+
sx={{
|
|
153
|
+
display: "flex",
|
|
154
|
+
alignItems: "flex-start",
|
|
155
|
+
justifyContent: "space-between",
|
|
156
|
+
mb: 3,
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<Box>
|
|
160
|
+
<Typography
|
|
161
|
+
variant="h6"
|
|
162
|
+
sx={{ fontWeight: 600, letterSpacing: "-0.025em" }}
|
|
163
|
+
>
|
|
164
|
+
Connections
|
|
165
|
+
</Typography>
|
|
166
|
+
<Typography variant="body2" color="text.secondary">
|
|
167
|
+
Database connections available to packages in this environment
|
|
168
|
+
</Typography>
|
|
169
|
+
</Box>
|
|
170
|
+
{mutable && isSuccess && (
|
|
171
|
+
<AddConnectionDialog
|
|
172
|
+
onSubmit={(payload) => addConnection.mutateAsync(payload)}
|
|
173
|
+
isSubmitting={addConnection.isPending}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
176
|
+
</Box>
|
|
177
|
+
|
|
178
|
+
{!isSuccess && !isError && (
|
|
179
|
+
<Typography variant="body2" color="text.secondary">
|
|
180
|
+
Fetching Connections...
|
|
181
|
+
</Typography>
|
|
182
|
+
)}
|
|
183
|
+
{isError && (
|
|
184
|
+
<ApiErrorDisplay
|
|
185
|
+
error={error}
|
|
186
|
+
context={`${environmentName} > Connections`}
|
|
187
|
+
/>
|
|
188
|
+
)}
|
|
189
|
+
{isSuccess && connections.length === 0 && (
|
|
190
|
+
<Typography variant="body2" color="text.secondary">
|
|
191
|
+
No connections yet.
|
|
192
|
+
</Typography>
|
|
193
|
+
)}
|
|
194
|
+
{isSuccess && connections.length > 0 && (
|
|
195
|
+
<Grid container spacing={2}>
|
|
196
|
+
{connections.map((conn) => (
|
|
197
|
+
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={conn.name}>
|
|
198
|
+
<ConnectionCard
|
|
199
|
+
connection={conn}
|
|
200
|
+
mutable={mutable}
|
|
201
|
+
isMutating={isMutating}
|
|
202
|
+
onOpenExplorer={() =>
|
|
203
|
+
setSelectedConnection(conn.name ?? null)
|
|
204
|
+
}
|
|
205
|
+
onEdit={(payload) =>
|
|
206
|
+
updateConnection.mutateAsync(payload)
|
|
207
|
+
}
|
|
208
|
+
onDelete={(payload) => {
|
|
209
|
+
if (!conn.resource) {
|
|
210
|
+
deleteConnection.mutateAsync(payload);
|
|
211
|
+
} else {
|
|
212
|
+
setNotificationMessage(
|
|
213
|
+
"Cannot delete this connection",
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
</Grid>
|
|
219
|
+
))}
|
|
220
|
+
</Grid>
|
|
221
|
+
)}
|
|
222
|
+
|
|
223
|
+
<Snackbar
|
|
224
|
+
open={notificationMessage !== ""}
|
|
225
|
+
autoHideDuration={6000}
|
|
226
|
+
onClose={() => setNotificationMessage("")}
|
|
227
|
+
message={notificationMessage}
|
|
228
|
+
/>
|
|
229
|
+
|
|
230
|
+
<Dialog
|
|
231
|
+
open={selectedConnection !== null}
|
|
232
|
+
onClose={handleCloseDialog}
|
|
233
|
+
maxWidth="lg"
|
|
234
|
+
fullWidth
|
|
235
|
+
>
|
|
236
|
+
<DialogTitle>
|
|
237
|
+
Connection Explorer: {selectedConnection}
|
|
238
|
+
<IconButton
|
|
239
|
+
aria-label="close"
|
|
240
|
+
onClick={handleCloseDialog}
|
|
241
|
+
sx={{ position: "absolute", right: 8, top: 8 }}
|
|
242
|
+
>
|
|
243
|
+
<Box
|
|
244
|
+
sx={{
|
|
245
|
+
width: 24,
|
|
246
|
+
height: 24,
|
|
247
|
+
display: "flex",
|
|
248
|
+
alignItems: "center",
|
|
249
|
+
justifyContent: "center",
|
|
250
|
+
}}
|
|
251
|
+
>
|
|
252
|
+
X
|
|
253
|
+
</Box>
|
|
254
|
+
</IconButton>
|
|
255
|
+
</DialogTitle>
|
|
256
|
+
<DialogContent>
|
|
257
|
+
{selectedConnection && (
|
|
258
|
+
<ConnectionExplorer
|
|
259
|
+
resourceUri={selectedConnectionResourceUri}
|
|
260
|
+
connectionName={selectedConnection}
|
|
261
|
+
connection={data?.data?.find(
|
|
262
|
+
(c) => c.name === selectedConnection,
|
|
263
|
+
)}
|
|
264
|
+
/>
|
|
265
|
+
)}
|
|
266
|
+
</DialogContent>
|
|
267
|
+
</Dialog>
|
|
268
|
+
</Box>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
type ConnectionCardProps = {
|
|
273
|
+
connection: ApiConnection;
|
|
274
|
+
mutable: boolean;
|
|
275
|
+
isMutating: boolean;
|
|
276
|
+
onOpenExplorer: () => void;
|
|
277
|
+
onEdit: (connection: ApiConnection) => Promise<unknown>;
|
|
278
|
+
onDelete: (connection: ApiConnection) => Promise<unknown> | void;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
function ConnectionCard({
|
|
282
|
+
connection,
|
|
283
|
+
mutable,
|
|
284
|
+
isMutating,
|
|
285
|
+
onOpenExplorer,
|
|
286
|
+
onEdit,
|
|
287
|
+
onDelete,
|
|
288
|
+
}: ConnectionCardProps) {
|
|
289
|
+
const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
|
|
290
|
+
const menuOpen = Boolean(menuAnchorEl);
|
|
291
|
+
|
|
292
|
+
const handleMenuClick = (event: React.MouseEvent<HTMLElement>) => {
|
|
293
|
+
event.stopPropagation();
|
|
294
|
+
setMenuAnchorEl(event.currentTarget);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const handleMenuClose = () => {
|
|
298
|
+
setMenuAnchorEl(null);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<Card
|
|
303
|
+
variant="outlined"
|
|
304
|
+
onClick={onOpenExplorer}
|
|
305
|
+
sx={{
|
|
306
|
+
height: "100%",
|
|
307
|
+
cursor: "pointer",
|
|
308
|
+
borderRadius: 3,
|
|
309
|
+
borderColor: "divider",
|
|
310
|
+
boxShadow: "none",
|
|
311
|
+
transition: "all 0.2s ease-in-out",
|
|
312
|
+
"&:hover": { boxShadow: 2, borderColor: "primary.main" },
|
|
313
|
+
}}
|
|
314
|
+
>
|
|
315
|
+
<CardContent sx={{ p: 2.5, "&:last-child": { pb: 2.5 } }}>
|
|
316
|
+
<Box sx={{ display: "flex", alignItems: "flex-start", gap: 1.5 }}>
|
|
317
|
+
<Box
|
|
318
|
+
sx={{
|
|
319
|
+
width: 36,
|
|
320
|
+
height: 36,
|
|
321
|
+
borderRadius: 1.5,
|
|
322
|
+
bgcolor: "warning.light",
|
|
323
|
+
display: "flex",
|
|
324
|
+
alignItems: "center",
|
|
325
|
+
justifyContent: "center",
|
|
326
|
+
flexShrink: 0,
|
|
327
|
+
color: "warning.main",
|
|
328
|
+
}}
|
|
329
|
+
>
|
|
330
|
+
<StorageOutlinedIcon sx={{ fontSize: 20 }} />
|
|
331
|
+
</Box>
|
|
332
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
333
|
+
<Typography
|
|
334
|
+
variant="subtitle1"
|
|
335
|
+
component="h6"
|
|
336
|
+
noWrap
|
|
337
|
+
sx={{ fontWeight: 600, mb: 0.5 }}
|
|
338
|
+
>
|
|
339
|
+
{connection.name}
|
|
340
|
+
</Typography>
|
|
341
|
+
<Typography variant="body2" color="text.secondary" noWrap>
|
|
342
|
+
{typeLabel(connection.type)}
|
|
343
|
+
</Typography>
|
|
344
|
+
</Box>
|
|
345
|
+
{mutable && (
|
|
346
|
+
<>
|
|
347
|
+
<IconButton
|
|
348
|
+
size="small"
|
|
349
|
+
onClick={handleMenuClick}
|
|
350
|
+
aria-label={`Connection actions for ${connection.name ?? ""}`.trim()}
|
|
351
|
+
sx={{ flexShrink: 0, mt: -0.5, mr: -0.5 }}
|
|
352
|
+
>
|
|
353
|
+
<MoreVert fontSize="small" />
|
|
354
|
+
</IconButton>
|
|
355
|
+
<Menu
|
|
356
|
+
anchorEl={menuAnchorEl}
|
|
357
|
+
open={menuOpen}
|
|
358
|
+
onClose={handleMenuClose}
|
|
359
|
+
onClick={(e) => e.stopPropagation()}
|
|
360
|
+
anchorOrigin={{
|
|
361
|
+
vertical: "bottom",
|
|
362
|
+
horizontal: "right",
|
|
363
|
+
}}
|
|
364
|
+
transformOrigin={{
|
|
365
|
+
vertical: "top",
|
|
366
|
+
horizontal: "right",
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<EditConnectionDialog
|
|
370
|
+
connection={connection}
|
|
371
|
+
onSubmit={onEdit}
|
|
372
|
+
isSubmitting={isMutating}
|
|
373
|
+
onCloseDialog={handleMenuClose}
|
|
374
|
+
/>
|
|
375
|
+
<DeleteConnectionDialog
|
|
376
|
+
connection={connection}
|
|
377
|
+
onCloseDialog={handleMenuClose}
|
|
378
|
+
isMutating={isMutating}
|
|
379
|
+
onDelete={() => onDelete(connection)}
|
|
380
|
+
/>
|
|
381
|
+
</Menu>
|
|
382
|
+
</>
|
|
383
|
+
)}
|
|
384
|
+
</Box>
|
|
385
|
+
</CardContent>
|
|
386
|
+
</Card>
|
|
387
|
+
);
|
|
388
|
+
}
|
|
@@ -4,6 +4,7 @@ import { parseResourceUri } from "../../utils/formatting";
|
|
|
4
4
|
import { useServer } from "../ServerProvider";
|
|
5
5
|
import About from "./About";
|
|
6
6
|
import AddPackageDialog from "./AddPackageDialog";
|
|
7
|
+
import Connections from "./Connections";
|
|
7
8
|
import Packages from "./Packages";
|
|
8
9
|
|
|
9
10
|
interface EnvironmentProps {
|
|
@@ -36,8 +37,8 @@ export default function Environment({
|
|
|
36
37
|
{environmentName}
|
|
37
38
|
</Typography>
|
|
38
39
|
<Typography variant="body2" color="text.secondary">
|
|
39
|
-
Manage packages in this environment.
|
|
40
|
-
its models
|
|
40
|
+
Manage packages and database connections in this environment.
|
|
41
|
+
Open a package to explore its models and notebooks.
|
|
41
42
|
</Typography>
|
|
42
43
|
</Box>
|
|
43
44
|
|
|
@@ -67,6 +68,10 @@ export default function Environment({
|
|
|
67
68
|
/>
|
|
68
69
|
</Box>
|
|
69
70
|
|
|
71
|
+
<Box sx={{ mb: 5 }}>
|
|
72
|
+
<Connections resourceUri={resourceUri} />
|
|
73
|
+
</Box>
|
|
74
|
+
|
|
70
75
|
<About resourceUri={resourceUri} />
|
|
71
76
|
</Container>
|
|
72
77
|
);
|