@malloy-publisher/sdk 0.0.228 → 0.0.230
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-BlufsK4M.cjs.js +1 -0
- package/dist/{ServerProvider-BnQo3hhW.es.js → ServerProvider-Tnt9y4B6.es.js} +782 -716
- package/dist/client/api.d.ts +81 -2
- package/dist/client/index.cjs.js +1 -1
- package/dist/client/index.es.js +1 -1
- package/dist/components/Materializations/CreateEnvMaterializationDialog.d.ts +14 -0
- package/dist/components/Materializations/EnvironmentMaterializations.d.ts +7 -0
- package/dist/components/Materializations/MaterializationDetailDialog.d.ts +2 -1
- package/dist/components/Materializations/MaterializationRunsList.d.ts +5 -1
- package/dist/components/Materializations/ScheduleCard.d.ts +20 -0
- package/dist/components/Materializations/SectionLabel.d.ts +10 -0
- package/dist/components/Materializations/SetScheduleDialog.d.ts +11 -0
- package/dist/components/Materializations/TriggerChip.d.ts +10 -0
- package/dist/components/Materializations/cron.d.ts +23 -0
- package/dist/components/Materializations/index.d.ts +1 -0
- package/dist/components/Materializations/utils.d.ts +9 -0
- package/dist/components/Notebook/Notebook.d.ts +6 -1
- package/dist/components/Notebook/NotebookCell.d.ts +3 -1
- package/dist/components/RenderedResult/ResultContainer.d.ts +3 -1
- package/dist/components/RenderedResult/renderLogs.d.ts +6 -0
- package/dist/components/ResultsDialog.d.ts +3 -1
- package/dist/constants/docLinks.d.ts +6 -0
- package/dist/{core-DYlbkyc-.cjs.js → core-DPpebaY3.cjs.js} +1 -1
- package/dist/{core-CEDZMHV1.es.js → core-Dp3q5Ieu.es.js} +1 -1
- package/dist/index-ClhlT2co.cjs.js +309 -0
- package/dist/{index-DC7gIcJX.es.js → index-oNBVlY2N.es.js} +34625 -25301
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +54 -52
- package/dist/utils/queryClient.d.ts +5 -0
- package/package.json +9 -7
- package/src/components/Environment/AddPackageDialog.tsx +2 -1
- package/src/components/Environment/Environment.tsx +8 -0
- package/src/components/Home/Home.tsx +5 -4
- package/src/components/Materializations/CreateEnvMaterializationDialog.tsx +176 -0
- package/src/components/Materializations/EnvironmentMaterializations.tsx +264 -0
- package/src/components/Materializations/ManifestView.tsx +2 -3
- package/src/components/Materializations/MaterializationDetailDialog.tsx +121 -95
- package/src/components/Materializations/MaterializationRunsList.tsx +37 -0
- package/src/components/Materializations/Materializations.tsx +86 -1
- package/src/components/Materializations/ScheduleCard.tsx +228 -0
- package/src/components/Materializations/SectionLabel.tsx +27 -0
- package/src/components/Materializations/SetScheduleDialog.tsx +159 -0
- package/src/components/Materializations/TriggerChip.tsx +41 -0
- package/src/components/Materializations/cron.ts +121 -0
- package/src/components/Materializations/index.ts +1 -0
- package/src/components/Materializations/utils.ts +14 -0
- package/src/components/Model/ModelCell.tsx +4 -0
- package/src/components/Notebook/Notebook.tsx +14 -1
- package/src/components/Notebook/NotebookCell.tsx +103 -2
- package/src/components/Package/Package.tsx +14 -3
- package/src/components/QueryResult/QueryResult.tsx +7 -1
- package/src/components/RenderedResult/RenderedResult.tsx +153 -51
- package/src/components/RenderedResult/ResultContainer.tsx +40 -1
- package/src/components/RenderedResult/renderLogs.spec.ts +55 -0
- package/src/components/RenderedResult/renderLogs.ts +40 -0
- package/src/components/ResultsDialog.tsx +4 -0
- package/src/constants/docLinks.ts +17 -0
- package/src/index.ts +1 -0
- package/src/utils/queryClient.ts +14 -0
- package/dist/ServerProvider-CCKhmHeT.cjs.js +0 -1
- package/dist/index-DO6Y8XP_.cjs.js +0 -307
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { Box, Button, Snackbar, Stack, Typography } from "@mui/material";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { Materialization, MaterializationActionActionEnum } from "../../client";
|
|
5
|
+
import {
|
|
6
|
+
useMutationWithApiError,
|
|
7
|
+
useQueryWithApiError,
|
|
8
|
+
} from "../../hooks/useQueryWithApiError";
|
|
9
|
+
import { parseResourceUri } from "../../utils/formatting";
|
|
10
|
+
import { ApiErrorDisplay } from "../ApiErrorDisplay";
|
|
11
|
+
import { Loading } from "../Loading";
|
|
12
|
+
import { useServer } from "../ServerProvider";
|
|
13
|
+
import CreateEnvMaterializationDialog from "./CreateEnvMaterializationDialog";
|
|
14
|
+
import MaterializationDetailDialog from "./MaterializationDetailDialog";
|
|
15
|
+
import MaterializationRunsList from "./MaterializationRunsList";
|
|
16
|
+
import { isActiveStatus } from "./utils";
|
|
17
|
+
|
|
18
|
+
const MATERIALIZATION_POLL_MS = 3000;
|
|
19
|
+
const PAGE_SIZE = 10;
|
|
20
|
+
|
|
21
|
+
interface EnvironmentMaterializationsProps {
|
|
22
|
+
resourceUri: string;
|
|
23
|
+
onClickPackageFile?: (to: string, event?: React.MouseEvent) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function EnvironmentMaterializations({
|
|
27
|
+
resourceUri,
|
|
28
|
+
onClickPackageFile,
|
|
29
|
+
}: EnvironmentMaterializationsProps) {
|
|
30
|
+
const { apiClients, mutable } = useServer();
|
|
31
|
+
const queryClient = useQueryClient();
|
|
32
|
+
const { environmentName } = parseResourceUri(resourceUri);
|
|
33
|
+
const [notificationMessage, setNotificationMessage] = useState("");
|
|
34
|
+
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
35
|
+
// Show the most recent runs and page in more on demand — a busy environment
|
|
36
|
+
// (e.g. a frequent schedule) accumulates runs without bound, so never render
|
|
37
|
+
// the full history at once.
|
|
38
|
+
const [limit, setLimit] = useState(PAGE_SIZE);
|
|
39
|
+
|
|
40
|
+
const onClick =
|
|
41
|
+
onClickPackageFile ??
|
|
42
|
+
((to: string) => {
|
|
43
|
+
window.location.href = to;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const listQuery = useQueryWithApiError({
|
|
47
|
+
queryKey: ["env-materializations", environmentName, limit],
|
|
48
|
+
queryFn: () =>
|
|
49
|
+
apiClients.materializations.listEnvironmentMaterializations(
|
|
50
|
+
environmentName,
|
|
51
|
+
limit,
|
|
52
|
+
),
|
|
53
|
+
// "Show more" grows `limit` (part of the key), so keep the current rows on
|
|
54
|
+
// screen while the larger page loads instead of flashing back to the
|
|
55
|
+
// loading state.
|
|
56
|
+
placeholderData: (previousData) => previousData,
|
|
57
|
+
refetchInterval: (query) => {
|
|
58
|
+
const payload = query.state.data as
|
|
59
|
+
| { data?: Materialization[] }
|
|
60
|
+
| undefined;
|
|
61
|
+
const rows = payload?.data ?? [];
|
|
62
|
+
return rows.some((row) => isActiveStatus(row.status))
|
|
63
|
+
? MATERIALIZATION_POLL_MS
|
|
64
|
+
: false;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const packagesQuery = useQueryWithApiError({
|
|
69
|
+
queryKey: ["packages", environmentName],
|
|
70
|
+
queryFn: () => apiClients.packages.listPackages(environmentName),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const invalidateList = () =>
|
|
74
|
+
queryClient.invalidateQueries({
|
|
75
|
+
queryKey: ["env-materializations", environmentName],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Fire one create per selected package. Each package builds independently, so
|
|
79
|
+
// a failure on one (e.g. an already-active materialization) does not block the
|
|
80
|
+
// others — report an aggregate outcome.
|
|
81
|
+
const createMaterializations = useMutationWithApiError({
|
|
82
|
+
mutationFn: async (opts: {
|
|
83
|
+
packageNames: string[];
|
|
84
|
+
forceRefresh: boolean;
|
|
85
|
+
}) => {
|
|
86
|
+
const results = await Promise.allSettled(
|
|
87
|
+
opts.packageNames.map((pkg) =>
|
|
88
|
+
apiClients.materializations.createMaterialization(
|
|
89
|
+
environmentName,
|
|
90
|
+
pkg,
|
|
91
|
+
{ forceRefresh: opts.forceRefresh },
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
const failed = results.filter((r) => r.status === "rejected").length;
|
|
96
|
+
return { total: opts.packageNames.length, failed };
|
|
97
|
+
},
|
|
98
|
+
onSuccess(result) {
|
|
99
|
+
const started = result.total - result.failed;
|
|
100
|
+
setNotificationMessage(
|
|
101
|
+
result.failed === 0
|
|
102
|
+
? `Started ${started} materialization${started === 1 ? "" : "s"}`
|
|
103
|
+
: `Started ${started} of ${result.total} (${result.failed} could not start — a build may already be active)`,
|
|
104
|
+
);
|
|
105
|
+
invalidateList();
|
|
106
|
+
},
|
|
107
|
+
onError(error) {
|
|
108
|
+
setNotificationMessage(error.message);
|
|
109
|
+
invalidateList();
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const stopMaterialization = useMutationWithApiError({
|
|
114
|
+
mutationFn: (materialization: Materialization) =>
|
|
115
|
+
apiClients.materializations.materializationAction(
|
|
116
|
+
environmentName,
|
|
117
|
+
materialization.packageName as string,
|
|
118
|
+
materialization.id as string,
|
|
119
|
+
MaterializationActionActionEnum.Stop,
|
|
120
|
+
),
|
|
121
|
+
onSuccess() {
|
|
122
|
+
setNotificationMessage("Materialization stopped");
|
|
123
|
+
invalidateList();
|
|
124
|
+
},
|
|
125
|
+
onError(error) {
|
|
126
|
+
setNotificationMessage(error.message);
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const deleteMaterialization = useMutationWithApiError({
|
|
131
|
+
mutationFn: ({
|
|
132
|
+
materialization,
|
|
133
|
+
dropTables,
|
|
134
|
+
}: {
|
|
135
|
+
materialization: Materialization;
|
|
136
|
+
dropTables: boolean;
|
|
137
|
+
}) =>
|
|
138
|
+
apiClients.materializations.deleteMaterialization(
|
|
139
|
+
environmentName,
|
|
140
|
+
materialization.packageName as string,
|
|
141
|
+
materialization.id as string,
|
|
142
|
+
dropTables,
|
|
143
|
+
),
|
|
144
|
+
onSuccess() {
|
|
145
|
+
setNotificationMessage("Materialization deleted");
|
|
146
|
+
invalidateList();
|
|
147
|
+
},
|
|
148
|
+
onError(error) {
|
|
149
|
+
setNotificationMessage(error.message);
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const materializations = (listQuery.data?.data ?? []) as Materialization[];
|
|
154
|
+
const packages = (packagesQuery.data?.data ?? []) as { name: string }[];
|
|
155
|
+
const selected =
|
|
156
|
+
materializations.find((row) => row.id === selectedId) ?? null;
|
|
157
|
+
const isMutating =
|
|
158
|
+
createMaterializations.isPending ||
|
|
159
|
+
stopMaterialization.isPending ||
|
|
160
|
+
deleteMaterialization.isPending;
|
|
161
|
+
// A full page implies there may be older runs beyond the current window.
|
|
162
|
+
const hasMore = materializations.length >= limit;
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<Box>
|
|
166
|
+
<Box
|
|
167
|
+
sx={{
|
|
168
|
+
display: "flex",
|
|
169
|
+
alignItems: "flex-start",
|
|
170
|
+
justifyContent: "space-between",
|
|
171
|
+
mb: 3,
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
<Box>
|
|
175
|
+
<Typography
|
|
176
|
+
variant="h6"
|
|
177
|
+
sx={{ fontWeight: 600, letterSpacing: "-0.025em" }}
|
|
178
|
+
>
|
|
179
|
+
Materializations
|
|
180
|
+
</Typography>
|
|
181
|
+
<Typography variant="body2" color="text.secondary">
|
|
182
|
+
All materialization builds across the packages in this
|
|
183
|
+
environment
|
|
184
|
+
</Typography>
|
|
185
|
+
</Box>
|
|
186
|
+
{mutable && (
|
|
187
|
+
<CreateEnvMaterializationDialog
|
|
188
|
+
packages={packages}
|
|
189
|
+
onSubmit={(opts) => createMaterializations.mutateAsync(opts)}
|
|
190
|
+
isSubmitting={createMaterializations.isPending}
|
|
191
|
+
/>
|
|
192
|
+
)}
|
|
193
|
+
</Box>
|
|
194
|
+
|
|
195
|
+
{listQuery.isError && (
|
|
196
|
+
<ApiErrorDisplay
|
|
197
|
+
error={listQuery.error}
|
|
198
|
+
context={`${environmentName} > Materializations`}
|
|
199
|
+
/>
|
|
200
|
+
)}
|
|
201
|
+
{!listQuery.isSuccess && !listQuery.isError && (
|
|
202
|
+
<Loading text="Loading materializations..." />
|
|
203
|
+
)}
|
|
204
|
+
{listQuery.isSuccess && (
|
|
205
|
+
<MaterializationRunsList
|
|
206
|
+
materializations={materializations}
|
|
207
|
+
mutable={mutable}
|
|
208
|
+
isMutating={isMutating}
|
|
209
|
+
showPackage
|
|
210
|
+
onClickPackage={(packageName) =>
|
|
211
|
+
onClick(`/${environmentName}/${packageName}/materializations`)
|
|
212
|
+
}
|
|
213
|
+
onStop={(materialization) =>
|
|
214
|
+
stopMaterialization.mutate(materialization)
|
|
215
|
+
}
|
|
216
|
+
onDelete={(materialization, dropTables) =>
|
|
217
|
+
deleteMaterialization.mutate({ materialization, dropTables })
|
|
218
|
+
}
|
|
219
|
+
onViewDetails={(materialization) =>
|
|
220
|
+
setSelectedId(materialization.id ?? null)
|
|
221
|
+
}
|
|
222
|
+
/>
|
|
223
|
+
)}
|
|
224
|
+
{listQuery.isSuccess && materializations.length > 0 && (
|
|
225
|
+
<Stack
|
|
226
|
+
direction="row"
|
|
227
|
+
alignItems="center"
|
|
228
|
+
justifyContent="center"
|
|
229
|
+
spacing={2}
|
|
230
|
+
sx={{ mt: 2 }}
|
|
231
|
+
>
|
|
232
|
+
<Typography variant="caption" color="text.secondary">
|
|
233
|
+
{hasMore
|
|
234
|
+
? `Showing ${materializations.length} most recent`
|
|
235
|
+
: `${materializations.length} materialization${materializations.length === 1 ? "" : "s"}`}
|
|
236
|
+
</Typography>
|
|
237
|
+
{hasMore && (
|
|
238
|
+
<Button
|
|
239
|
+
size="small"
|
|
240
|
+
onClick={() => setLimit((l) => l + PAGE_SIZE)}
|
|
241
|
+
disabled={listQuery.isFetching}
|
|
242
|
+
>
|
|
243
|
+
Show more
|
|
244
|
+
</Button>
|
|
245
|
+
)}
|
|
246
|
+
</Stack>
|
|
247
|
+
)}
|
|
248
|
+
|
|
249
|
+
<MaterializationDetailDialog
|
|
250
|
+
materialization={selected}
|
|
251
|
+
buildPlan={null}
|
|
252
|
+
showBuildPlan={false}
|
|
253
|
+
onClose={() => setSelectedId(null)}
|
|
254
|
+
/>
|
|
255
|
+
|
|
256
|
+
<Snackbar
|
|
257
|
+
open={notificationMessage !== ""}
|
|
258
|
+
autoHideDuration={6000}
|
|
259
|
+
onClose={() => setNotificationMessage("")}
|
|
260
|
+
message={notificationMessage}
|
|
261
|
+
/>
|
|
262
|
+
</Box>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "@mui/material";
|
|
11
11
|
import { ManifestEntry } from "../../client";
|
|
12
12
|
import { MONO_FONT_FAMILY } from "../styles";
|
|
13
|
+
import SectionLabel from "./SectionLabel";
|
|
13
14
|
import { formatTimestamp } from "./utils";
|
|
14
15
|
|
|
15
16
|
type ManifestViewProps = {
|
|
@@ -31,9 +32,7 @@ export default function ManifestView({ entries, builtAt }: ManifestViewProps) {
|
|
|
31
32
|
alignItems="baseline"
|
|
32
33
|
justifyContent="space-between"
|
|
33
34
|
>
|
|
34
|
-
<
|
|
35
|
-
Build manifest
|
|
36
|
-
</Typography>
|
|
35
|
+
<SectionLabel>Build manifest</SectionLabel>
|
|
37
36
|
{builtAt && (
|
|
38
37
|
<Typography variant="caption" color="text.secondary">
|
|
39
38
|
Built {formatTimestamp(builtAt)}
|
|
@@ -17,9 +17,12 @@ import {
|
|
|
17
17
|
import { BuildPlan, Materialization } from "../../client";
|
|
18
18
|
import { MONO_FONT_FAMILY } from "../styles";
|
|
19
19
|
import ManifestView from "./ManifestView";
|
|
20
|
+
import SectionLabel from "./SectionLabel";
|
|
21
|
+
import TriggerChip from "./TriggerChip";
|
|
20
22
|
import {
|
|
21
23
|
formatDuration,
|
|
22
24
|
formatTimestamp,
|
|
25
|
+
isActiveStatus,
|
|
23
26
|
parseMetadata,
|
|
24
27
|
statusColor,
|
|
25
28
|
statusLabel,
|
|
@@ -29,13 +32,22 @@ type MaterializationDetailDialogProps = {
|
|
|
29
32
|
materialization: Materialization | null;
|
|
30
33
|
// The compiled package's current build plan (Package.buildPlan), shown for
|
|
31
34
|
// context. It is a property of the package version, not the historical run.
|
|
35
|
+
// Note it is null both in the environment-scoped view and for a package with
|
|
36
|
+
// no persist sources, so it cannot itself gate the section — see
|
|
37
|
+
// `showBuildPlan`.
|
|
32
38
|
buildPlan: BuildPlan | null;
|
|
39
|
+
// Whether to render the Build plan section. The package view shows it (with a
|
|
40
|
+
// "no persist sources" empty state when the plan is empty); the
|
|
41
|
+
// environment-scoped view, which spans packages and has no single plan, omits
|
|
42
|
+
// it entirely.
|
|
43
|
+
showBuildPlan?: boolean;
|
|
33
44
|
onClose: () => void;
|
|
34
45
|
};
|
|
35
46
|
|
|
36
47
|
export default function MaterializationDetailDialog({
|
|
37
48
|
materialization,
|
|
38
49
|
buildPlan,
|
|
50
|
+
showBuildPlan = true,
|
|
39
51
|
onClose,
|
|
40
52
|
}: MaterializationDetailDialogProps) {
|
|
41
53
|
const meta = materialization ? parseMetadata(materialization) : {};
|
|
@@ -51,20 +63,41 @@ export default function MaterializationDetailDialog({
|
|
|
51
63
|
>
|
|
52
64
|
{materialization && (
|
|
53
65
|
<>
|
|
54
|
-
<DialogTitle
|
|
55
|
-
|
|
66
|
+
<DialogTitle
|
|
67
|
+
sx={{ pr: 6, pb: 1.5 }}
|
|
68
|
+
id="materialization-detail-title"
|
|
69
|
+
>
|
|
70
|
+
<Stack
|
|
71
|
+
direction="row"
|
|
72
|
+
alignItems="center"
|
|
73
|
+
spacing={1}
|
|
74
|
+
sx={{ mb: 0.75 }}
|
|
75
|
+
>
|
|
56
76
|
<Chip
|
|
57
77
|
size="small"
|
|
58
78
|
label={statusLabel(materialization.status)}
|
|
59
79
|
color={statusColor(materialization.status)}
|
|
80
|
+
variant={
|
|
81
|
+
isActiveStatus(materialization.status)
|
|
82
|
+
? "filled"
|
|
83
|
+
: "outlined"
|
|
84
|
+
}
|
|
60
85
|
/>
|
|
61
|
-
<
|
|
62
|
-
variant="subtitle1"
|
|
63
|
-
sx={{ fontFamily: MONO_FONT_FAMILY }}
|
|
64
|
-
>
|
|
65
|
-
{materialization.id}
|
|
66
|
-
</Typography>
|
|
86
|
+
<TriggerChip meta={meta} />
|
|
67
87
|
</Stack>
|
|
88
|
+
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
|
89
|
+
{materialization.packageName ?? "Materialization"}
|
|
90
|
+
</Typography>
|
|
91
|
+
<Typography
|
|
92
|
+
variant="caption"
|
|
93
|
+
color="text.secondary"
|
|
94
|
+
sx={{
|
|
95
|
+
fontFamily: MONO_FONT_FAMILY,
|
|
96
|
+
wordBreak: "break-all",
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
{materialization.id}
|
|
100
|
+
</Typography>
|
|
68
101
|
<IconButton
|
|
69
102
|
aria-label="close"
|
|
70
103
|
onClick={onClose}
|
|
@@ -76,21 +109,16 @@ export default function MaterializationDetailDialog({
|
|
|
76
109
|
<DialogContent dividers>
|
|
77
110
|
<Box
|
|
78
111
|
sx={{
|
|
112
|
+
bgcolor: "action.hover",
|
|
113
|
+
borderRadius: 2,
|
|
114
|
+
p: 2,
|
|
115
|
+
mb: 3,
|
|
79
116
|
display: "grid",
|
|
80
117
|
gridTemplateColumns:
|
|
81
|
-
"repeat(auto-fit, minmax(
|
|
118
|
+
"repeat(auto-fit, minmax(140px, 1fr))",
|
|
82
119
|
gap: 2,
|
|
83
|
-
mb: 3,
|
|
84
120
|
}}
|
|
85
121
|
>
|
|
86
|
-
<DetailField
|
|
87
|
-
label="Package"
|
|
88
|
-
value={materialization.packageName ?? "—"}
|
|
89
|
-
/>
|
|
90
|
-
<DetailField
|
|
91
|
-
label="Force refresh"
|
|
92
|
-
value={meta.forceRefresh ? "Yes" : "No"}
|
|
93
|
-
/>
|
|
94
122
|
<DetailField
|
|
95
123
|
label="Started"
|
|
96
124
|
value={formatTimestamp(
|
|
@@ -110,32 +138,30 @@ export default function MaterializationDetailDialog({
|
|
|
110
138
|
)}
|
|
111
139
|
/>
|
|
112
140
|
<DetailField
|
|
113
|
-
label="Sources
|
|
114
|
-
value={`${meta.sourcesBuilt ?? 0}`}
|
|
115
|
-
/>
|
|
116
|
-
<DetailField
|
|
117
|
-
label="Sources reused"
|
|
118
|
-
value={`${meta.sourcesReused ?? 0}`}
|
|
119
|
-
/>
|
|
120
|
-
<DetailField
|
|
121
|
-
label="Created"
|
|
122
|
-
value={formatTimestamp(materialization.createdAt)}
|
|
141
|
+
label="Sources"
|
|
142
|
+
value={`${meta.sourcesBuilt ?? 0} built · ${meta.sourcesReused ?? 0} reused`}
|
|
123
143
|
/>
|
|
124
144
|
<DetailField
|
|
125
|
-
label="
|
|
126
|
-
value={
|
|
145
|
+
label="Force refresh"
|
|
146
|
+
value={meta.forceRefresh ? "Yes" : "No"}
|
|
127
147
|
/>
|
|
128
148
|
</Box>
|
|
129
149
|
|
|
130
150
|
{materialization.error && (
|
|
131
|
-
<Box
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
<Box
|
|
152
|
+
sx={{
|
|
153
|
+
borderRadius: 2,
|
|
154
|
+
p: 2,
|
|
155
|
+
mb: 3,
|
|
156
|
+
border: "1px solid",
|
|
157
|
+
borderColor: "error.main",
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
<SectionLabel>
|
|
161
|
+
<Box component="span" sx={{ color: "error.main" }}>
|
|
162
|
+
Error
|
|
163
|
+
</Box>
|
|
164
|
+
</SectionLabel>
|
|
139
165
|
<Typography
|
|
140
166
|
variant="body2"
|
|
141
167
|
sx={{
|
|
@@ -148,64 +174,64 @@ export default function MaterializationDetailDialog({
|
|
|
148
174
|
</Box>
|
|
149
175
|
)}
|
|
150
176
|
|
|
151
|
-
|
|
152
|
-
<
|
|
153
|
-
Build plan
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
<TableCell>Source Entity ID</TableCell>
|
|
172
|
-
</TableRow>
|
|
173
|
-
</TableHead>
|
|
174
|
-
<TableBody>
|
|
175
|
-
{planSources.map((source) => (
|
|
176
|
-
<TableRow key={source.sourceID}>
|
|
177
|
-
<TableCell
|
|
178
|
-
sx={{ fontFamily: MONO_FONT_FAMILY }}
|
|
179
|
-
>
|
|
180
|
-
{source.name}
|
|
181
|
-
</TableCell>
|
|
182
|
-
<TableCell
|
|
183
|
-
sx={{ fontFamily: MONO_FONT_FAMILY }}
|
|
184
|
-
>
|
|
185
|
-
{source.connectionName}
|
|
186
|
-
</TableCell>
|
|
187
|
-
<TableCell>
|
|
188
|
-
{source.dialect ?? "-"}
|
|
189
|
-
</TableCell>
|
|
190
|
-
<TableCell align="right">
|
|
191
|
-
{source.columns?.length ?? 0}
|
|
192
|
-
</TableCell>
|
|
193
|
-
<TableCell
|
|
194
|
-
sx={{
|
|
195
|
-
fontFamily: MONO_FONT_FAMILY,
|
|
196
|
-
fontSize: "0.75rem",
|
|
197
|
-
wordBreak: "break-all",
|
|
198
|
-
maxWidth: 220,
|
|
199
|
-
}}
|
|
200
|
-
>
|
|
201
|
-
{source.sourceEntityId}
|
|
202
|
-
</TableCell>
|
|
177
|
+
{showBuildPlan && (
|
|
178
|
+
<Box sx={{ mb: 3 }}>
|
|
179
|
+
<SectionLabel>Build plan</SectionLabel>
|
|
180
|
+
{planSources.length === 0 ? (
|
|
181
|
+
<Typography
|
|
182
|
+
variant="body2"
|
|
183
|
+
color="text.secondary"
|
|
184
|
+
sx={{ fontStyle: "italic" }}
|
|
185
|
+
>
|
|
186
|
+
This package has no persist sources.
|
|
187
|
+
</Typography>
|
|
188
|
+
) : (
|
|
189
|
+
<Table size="small">
|
|
190
|
+
<TableHead>
|
|
191
|
+
<TableRow>
|
|
192
|
+
<TableCell>Source</TableCell>
|
|
193
|
+
<TableCell>Connection</TableCell>
|
|
194
|
+
<TableCell>Dialect</TableCell>
|
|
195
|
+
<TableCell align="right">Columns</TableCell>
|
|
196
|
+
<TableCell>Source Entity ID</TableCell>
|
|
203
197
|
</TableRow>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
198
|
+
</TableHead>
|
|
199
|
+
<TableBody>
|
|
200
|
+
{planSources.map((source) => (
|
|
201
|
+
<TableRow key={source.sourceID}>
|
|
202
|
+
<TableCell
|
|
203
|
+
sx={{ fontFamily: MONO_FONT_FAMILY }}
|
|
204
|
+
>
|
|
205
|
+
{source.name}
|
|
206
|
+
</TableCell>
|
|
207
|
+
<TableCell
|
|
208
|
+
sx={{ fontFamily: MONO_FONT_FAMILY }}
|
|
209
|
+
>
|
|
210
|
+
{source.connectionName}
|
|
211
|
+
</TableCell>
|
|
212
|
+
<TableCell>
|
|
213
|
+
{source.dialect ?? "-"}
|
|
214
|
+
</TableCell>
|
|
215
|
+
<TableCell align="right">
|
|
216
|
+
{source.columns?.length ?? 0}
|
|
217
|
+
</TableCell>
|
|
218
|
+
<TableCell
|
|
219
|
+
sx={{
|
|
220
|
+
fontFamily: MONO_FONT_FAMILY,
|
|
221
|
+
fontSize: "0.75rem",
|
|
222
|
+
wordBreak: "break-all",
|
|
223
|
+
maxWidth: 220,
|
|
224
|
+
}}
|
|
225
|
+
>
|
|
226
|
+
{source.sourceEntityId}
|
|
227
|
+
</TableCell>
|
|
228
|
+
</TableRow>
|
|
229
|
+
))}
|
|
230
|
+
</TableBody>
|
|
231
|
+
</Table>
|
|
232
|
+
)}
|
|
233
|
+
</Box>
|
|
234
|
+
)}
|
|
209
235
|
|
|
210
236
|
<ManifestView
|
|
211
237
|
entries={materialization.manifest?.entries}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
Box,
|
|
6
6
|
Chip,
|
|
7
7
|
IconButton,
|
|
8
|
+
Link,
|
|
8
9
|
ListItemIcon,
|
|
9
10
|
ListItemText,
|
|
10
11
|
Menu,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
import { useState } from "react";
|
|
21
22
|
import { Materialization } from "../../client";
|
|
22
23
|
import DeleteMaterializationDialog from "./DeleteMaterializationDialog";
|
|
24
|
+
import TriggerChip from "./TriggerChip";
|
|
23
25
|
import {
|
|
24
26
|
formatDuration,
|
|
25
27
|
formatRelativeTime,
|
|
@@ -34,6 +36,10 @@ type MaterializationRunsListProps = {
|
|
|
34
36
|
materializations: Materialization[];
|
|
35
37
|
mutable: boolean;
|
|
36
38
|
isMutating: boolean;
|
|
39
|
+
/** Show a Package column — for the environment-scoped view spanning packages. */
|
|
40
|
+
showPackage?: boolean;
|
|
41
|
+
/** Navigate to a package (used by the Package column links). */
|
|
42
|
+
onClickPackage?: (packageName: string) => void;
|
|
37
43
|
onStop: (materialization: Materialization) => void;
|
|
38
44
|
onDelete: (materialization: Materialization, dropTables: boolean) => void;
|
|
39
45
|
onViewDetails: (materialization: Materialization) => void;
|
|
@@ -43,6 +49,8 @@ export default function MaterializationRunsList({
|
|
|
43
49
|
materializations,
|
|
44
50
|
mutable,
|
|
45
51
|
isMutating,
|
|
52
|
+
showPackage = false,
|
|
53
|
+
onClickPackage,
|
|
46
54
|
onStop,
|
|
47
55
|
onDelete,
|
|
48
56
|
onViewDetails,
|
|
@@ -63,7 +71,9 @@ export default function MaterializationRunsList({
|
|
|
63
71
|
<Table size="small">
|
|
64
72
|
<TableHead>
|
|
65
73
|
<TableRow>
|
|
74
|
+
{showPackage && <TableCell>Package</TableCell>}
|
|
66
75
|
<TableCell>Status</TableCell>
|
|
76
|
+
<TableCell>Trigger</TableCell>
|
|
67
77
|
<TableCell>Started</TableCell>
|
|
68
78
|
<TableCell>Duration</TableCell>
|
|
69
79
|
<TableCell>Sources</TableCell>
|
|
@@ -77,6 +87,8 @@ export default function MaterializationRunsList({
|
|
|
77
87
|
materialization={materialization}
|
|
78
88
|
mutable={mutable}
|
|
79
89
|
isMutating={isMutating}
|
|
90
|
+
showPackage={showPackage}
|
|
91
|
+
onClickPackage={onClickPackage}
|
|
80
92
|
onStop={onStop}
|
|
81
93
|
onDelete={onDelete}
|
|
82
94
|
onViewDetails={onViewDetails}
|
|
@@ -91,6 +103,8 @@ function MaterializationRow({
|
|
|
91
103
|
materialization,
|
|
92
104
|
mutable,
|
|
93
105
|
isMutating,
|
|
106
|
+
showPackage,
|
|
107
|
+
onClickPackage,
|
|
94
108
|
onStop,
|
|
95
109
|
onDelete,
|
|
96
110
|
onViewDetails,
|
|
@@ -98,6 +112,8 @@ function MaterializationRow({
|
|
|
98
112
|
materialization: Materialization;
|
|
99
113
|
mutable: boolean;
|
|
100
114
|
isMutating: boolean;
|
|
115
|
+
showPackage?: boolean;
|
|
116
|
+
onClickPackage?: (packageName: string) => void;
|
|
101
117
|
onStop: (materialization: Materialization) => void;
|
|
102
118
|
onDelete: (materialization: Materialization, dropTables: boolean) => void;
|
|
103
119
|
onViewDetails: (materialization: Materialization) => void;
|
|
@@ -138,6 +154,24 @@ function MaterializationRow({
|
|
|
138
154
|
tabIndex={0}
|
|
139
155
|
aria-label={`View materialization ${materialization.id ?? ""} details`.trim()}
|
|
140
156
|
>
|
|
157
|
+
{showPackage && (
|
|
158
|
+
<TableCell onClick={(event) => event.stopPropagation()}>
|
|
159
|
+
{onClickPackage ? (
|
|
160
|
+
<Link
|
|
161
|
+
component="button"
|
|
162
|
+
underline="hover"
|
|
163
|
+
onClick={() =>
|
|
164
|
+
onClickPackage(materialization.packageName ?? "")
|
|
165
|
+
}
|
|
166
|
+
sx={{ fontWeight: 500 }}
|
|
167
|
+
>
|
|
168
|
+
{materialization.packageName}
|
|
169
|
+
</Link>
|
|
170
|
+
) : (
|
|
171
|
+
materialization.packageName
|
|
172
|
+
)}
|
|
173
|
+
</TableCell>
|
|
174
|
+
)}
|
|
141
175
|
<TableCell>
|
|
142
176
|
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
|
|
143
177
|
<Chip
|
|
@@ -153,6 +187,9 @@ function MaterializationRow({
|
|
|
153
187
|
)}
|
|
154
188
|
</Box>
|
|
155
189
|
</TableCell>
|
|
190
|
+
<TableCell>
|
|
191
|
+
<TriggerChip meta={meta} />
|
|
192
|
+
</TableCell>
|
|
156
193
|
<TableCell>
|
|
157
194
|
{formatRelativeTime(
|
|
158
195
|
materialization.startedAt ?? materialization.createdAt,
|