@backstage/plugin-scaffolder 1.17.1 → 1.18.0-next.0
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/CHANGELOG.md +34 -0
- package/alpha/package.json +1 -1
- package/dist/alpha.d.ts +20 -5
- package/dist/alpha.esm.js +55 -97
- package/dist/alpha.esm.js.map +1 -1
- package/dist/esm/{OngoingTask-87c6761c.esm.js → OngoingTask-caf1a6e8.esm.js} +197 -445
- package/dist/esm/OngoingTask-caf1a6e8.esm.js.map +1 -0
- package/dist/esm/{DryRunResults-c0cd5eb5.esm.js → index-445b4718.esm.js} +1314 -634
- package/dist/esm/index-445b4718.esm.js.map +1 -0
- package/dist/esm/routes-1428737e.esm.js +275 -0
- package/dist/esm/routes-1428737e.esm.js.map +1 -0
- package/dist/index.d.ts +187 -18
- package/dist/index.esm.js +171 -17
- package/dist/index.esm.js.map +1 -1
- package/package.json +15 -13
- package/dist/esm/DryRunResults-c0cd5eb5.esm.js.map +0 -1
- package/dist/esm/OngoingTask-87c6761c.esm.js.map +0 -1
- package/dist/esm/Router-5d4d36fb.esm.js +0 -1563
- package/dist/esm/Router-5d4d36fb.esm.js.map +0 -1
- package/dist/esm/index-38156f16.esm.js +0 -876
- package/dist/esm/index-38156f16.esm.js.map +0 -1
- package/dist/types/plugin.d-c637df46.d.ts +0 -214
|
@@ -1,363 +1,183 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState, Fragment, useCallback, createContext, useRef, useMemo, useContext, useEffect, Component, Children, memo } from 'react';
|
|
2
|
+
import { Link as Link$1, useNavigate, Navigate, useOutlet, Routes, Route } from 'react-router-dom';
|
|
3
|
+
import { useTemplateSecrets, scaffolderApiRef, useCustomFieldExtensions, useCustomLayouts, SecretsContextProvider } from '@backstage/plugin-scaffolder-react';
|
|
4
|
+
import { E as EntityPicker, a as EntityPickerSchema, b as EntityNamePicker, e as entityNamePickerValidation, c as EntityNamePickerSchema, l as EntityTagsPicker, m as EntityTagsPickerSchema, R as RepoUrlPicker, r as repoPickerValidation, f as RepoUrlPickerSchema, O as OwnerPicker, g as OwnerPickerSchema, j as OwnedEntityPicker, k as OwnedEntityPickerSchema, h as MyGroupsPicker, i as MyGroupsPickerSchema, M as MultiEntityPicker, d as MultiEntityPickerSchema, v as validateMultiEntityPickerValidation, n as OngoingTask } from './OngoingTask-caf1a6e8.esm.js';
|
|
5
|
+
import { ScaffolderField, ScaffolderPageContextMenu, TemplateCategoryPicker, TemplateGroups, Workflow, createAsyncValidators, Stepper, Form } from '@backstage/plugin-scaffolder-react/alpha';
|
|
6
|
+
import { InputLabel, Input, makeStyles, Box, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody, Collapse, Card, List, MenuItem, ListItemIcon, ListItemText, FormControl, Select, IconButton as IconButton$1, CardHeader, CardContent, Button as Button$1, Tooltip, Divider, createStyles, StepButton, CircularProgress, LinearProgress } from '@material-ui/core';
|
|
7
|
+
import { r as rootRouteRef, d as registerComponentRouteRef, e as editRouteRef, b as actionsRouteRef, c as scaffolderListTaskRouteRef, v as viewTechDocRouteRef, s as selectedTemplateRouteRef, a as scaffolderTaskRouteRef } from './routes-1428737e.esm.js';
|
|
8
|
+
import { Progress, ErrorPage, MarkdownContent, Page, Header, Content, CodeSnippet, StatusError, StatusOK, StatusPending, ErrorPanel, EmptyState, Table as Table$1, Link, DocsIcon, ContentHeader, SupportButton, LogViewer } from '@backstage/core-components';
|
|
2
9
|
import useAsync from 'react-use/lib/useAsync';
|
|
3
|
-
import { scaffolderApiRef, useTaskEventStream, useTemplateSecrets } from '@backstage/plugin-scaffolder-react';
|
|
4
|
-
import { Box, makeStyles, Grid, Typography, StepButton, CircularProgress, Paper, Button, Accordion, AccordionSummary, AccordionDetails, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Collapse, InputLabel, Input, Card, List, MenuItem, ListItemIcon, ListItemText, Tooltip as Tooltip$1, IconButton, Divider } from '@material-ui/core';
|
|
5
10
|
import classNames from 'classnames';
|
|
6
11
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
7
12
|
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
|
|
8
|
-
import {
|
|
9
|
-
import { DismissableBanner, Link, Page, Header, Content, ErrorPage, Progress, LogViewer, MarkdownContent, CodeSnippet, StatusError, StatusOK, StatusPending, Lifecycle, ErrorPanel, EmptyState, Table as Table$1 } from '@backstage/core-components';
|
|
13
|
+
import { useApi, useRouteRef, useApp, useRouteRefParams, AnalyticsContext, useApiHolder, alertApiRef } from '@backstage/core-plugin-api';
|
|
10
14
|
import Chip from '@material-ui/core/Chip';
|
|
11
|
-
import {
|
|
12
|
-
import { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';
|
|
13
|
-
import { entityRouteRef, catalogApiRef, EntityRefLink, CatalogFilterLayout } from '@backstage/plugin-catalog-react';
|
|
15
|
+
import { catalogApiRef, EntityRefLink, CatalogFilterLayout, EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, entityRouteRef, humanizeEntityRef } from '@backstage/plugin-catalog-react';
|
|
14
16
|
import SettingsIcon from '@material-ui/icons/Settings';
|
|
15
17
|
import AllIcon from '@material-ui/icons/FontDownload';
|
|
16
18
|
import { DateTime, Interval } from 'luxon';
|
|
17
19
|
import humanizeDuration from 'humanize-duration';
|
|
18
20
|
import Typography$1 from '@material-ui/core/Typography';
|
|
19
|
-
import { parseEntityRef } from '@backstage/catalog-model';
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
21
|
+
import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
22
|
+
import Button from '@material-ui/core/Button';
|
|
23
|
+
import IconButton from '@material-ui/core/IconButton';
|
|
24
|
+
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
|
25
|
+
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
|
|
26
|
+
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
|
|
27
|
+
import { usePermission } from '@backstage/plugin-permission-react';
|
|
28
|
+
import { StreamLanguage } from '@codemirror/language';
|
|
29
|
+
import { yaml as yaml$1 } from '@codemirror/legacy-modes/mode/yaml';
|
|
26
30
|
import CloseIcon from '@material-ui/icons/Close';
|
|
31
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
32
|
+
import yaml from 'yaml';
|
|
33
|
+
import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
|
|
34
|
+
import useDebounce from 'react-use/lib/useDebounce';
|
|
35
|
+
import { useAsync as useAsync$1, useRerender, useKeyboardEvent, usePrevious } from '@react-hookz/web';
|
|
36
|
+
import validator from '@rjsf/validator-ajv8';
|
|
27
37
|
import RefreshIcon from '@material-ui/icons/Refresh';
|
|
28
38
|
import SaveIcon from '@material-ui/icons/Save';
|
|
29
|
-
import
|
|
30
|
-
import
|
|
39
|
+
import TreeView from '@material-ui/lab/TreeView';
|
|
40
|
+
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
|
|
41
|
+
import TreeItem from '@material-ui/lab/TreeItem';
|
|
31
42
|
import { showPanel } from '@codemirror/view';
|
|
32
|
-
import { useAsync as useAsync$1, useRerender, useKeyboardEvent, usePrevious } from '@react-hookz/web';
|
|
33
|
-
import CodeMirror from '@uiw/react-codemirror';
|
|
34
43
|
import Accordion$1 from '@material-ui/core/Accordion';
|
|
35
44
|
import AccordionDetails$1 from '@material-ui/core/AccordionDetails';
|
|
36
45
|
import AccordionSummary$1 from '@material-ui/core/AccordionSummary';
|
|
37
46
|
import Divider$1 from '@material-ui/core/Divider';
|
|
38
|
-
import yaml from 'yaml';
|
|
39
|
-
import IconButton$1 from '@material-ui/core/IconButton';
|
|
40
47
|
import List$1 from '@material-ui/core/List';
|
|
41
48
|
import ListItem from '@material-ui/core/ListItem';
|
|
42
49
|
import ListItemIcon$1 from '@material-ui/core/ListItemIcon';
|
|
43
50
|
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
|
44
51
|
import ListItemText$1 from '@material-ui/core/ListItemText';
|
|
45
52
|
import Cancel from '@material-ui/icons/Cancel';
|
|
46
|
-
import
|
|
53
|
+
import CheckIcon from '@material-ui/icons/Check';
|
|
47
54
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
48
55
|
import DownloadIcon from '@material-ui/icons/GetApp';
|
|
49
56
|
import Box$1 from '@material-ui/core/Box';
|
|
50
57
|
import Tab from '@material-ui/core/Tab';
|
|
51
58
|
import Tabs from '@material-ui/core/Tabs';
|
|
52
|
-
import TreeView from '@material-ui/lab/TreeView';
|
|
53
|
-
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
|
|
54
|
-
import TreeItem from '@material-ui/lab/TreeItem';
|
|
55
59
|
import LanguageIcon from '@material-ui/icons/Language';
|
|
56
|
-
import Grid$1 from '@material-ui/core/Grid';
|
|
57
60
|
import Step from '@material-ui/core/Step';
|
|
58
61
|
import StepLabel from '@material-ui/core/StepLabel';
|
|
59
|
-
import Stepper from '@material-ui/core/Stepper';
|
|
62
|
+
import Stepper$1 from '@material-ui/core/Stepper';
|
|
60
63
|
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
|
61
|
-
import qs from 'qs';
|
|
62
|
-
import { useNavigate } from 'react-router-dom';
|
|
63
64
|
import useInterval from 'react-use/lib/useInterval';
|
|
65
|
+
import Card$1 from '@material-ui/core/Card';
|
|
66
|
+
import CardActionArea from '@material-ui/core/CardActionArea';
|
|
67
|
+
import CardContent$1 from '@material-ui/core/CardContent';
|
|
68
|
+
import Tooltip$1 from '@material-ui/core/Tooltip';
|
|
69
|
+
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
|
|
70
|
+
import 'zod';
|
|
71
|
+
import '@backstage/catalog-client';
|
|
72
|
+
import '@material-ui/core/FormControl';
|
|
73
|
+
import '@material-ui/lab/Autocomplete';
|
|
74
|
+
import '@backstage/integration-react';
|
|
75
|
+
import '@material-ui/core/FormHelperText';
|
|
76
|
+
import '@material-ui/core/Input';
|
|
77
|
+
import '@material-ui/core/InputLabel';
|
|
78
|
+
import 'react-use/lib/useEffectOnce';
|
|
79
|
+
import '@material-ui/lab';
|
|
80
|
+
import 'zod-to-json-schema';
|
|
81
|
+
import '@backstage/errors';
|
|
82
|
+
import 'qs';
|
|
83
|
+
import '@material-ui/icons/Repeat';
|
|
84
|
+
import '@material-ui/icons/Toc';
|
|
85
|
+
import '@material-ui/icons/ControlPoint';
|
|
86
|
+
import '@material-ui/icons/MoreVert';
|
|
87
|
+
import 'zen-observable';
|
|
88
|
+
import 'event-source-polyfill';
|
|
64
89
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)) : null;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const useStyles$b = makeStyles({
|
|
81
|
-
svgIcon: {
|
|
82
|
-
display: "inline-block",
|
|
83
|
-
"& svg": {
|
|
84
|
-
display: "inline-block",
|
|
85
|
-
fontSize: "inherit",
|
|
86
|
-
verticalAlign: "baseline"
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
const IconLink = (props) => {
|
|
91
|
-
const { href, text, Icon, ...linkProps } = props;
|
|
92
|
-
const classes = useStyles$b();
|
|
93
|
-
return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row", spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { component: "div", className: classes.svgIcon }, Icon ? /* @__PURE__ */ React.createElement(Icon, null) : /* @__PURE__ */ React.createElement(LanguageIcon, null))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Link, { to: href, ...linkProps }, text || href)));
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const TaskPageLinks = ({ output }) => {
|
|
97
|
-
const { links = [] } = output;
|
|
98
|
-
const app = useApp();
|
|
99
|
-
const entityRoute = useRouteRef(entityRouteRef);
|
|
100
|
-
const iconResolver = (key) => {
|
|
101
|
-
var _a;
|
|
102
|
-
return key ? (_a = app.getSystemIcon(key)) != null ? _a : LanguageIcon : LanguageIcon;
|
|
103
|
-
};
|
|
104
|
-
return /* @__PURE__ */ React.createElement(Box, { px: 3, pb: 3 }, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
|
|
105
|
-
if (entityRef) {
|
|
106
|
-
const entityName = parseEntityRef(entityRef, {
|
|
107
|
-
defaultKind: "<unknown>",
|
|
108
|
-
defaultNamespace: "<unknown>"
|
|
109
|
-
});
|
|
110
|
-
const target = entityRoute(entityName);
|
|
111
|
-
return { title, icon, url: target };
|
|
112
|
-
}
|
|
113
|
-
return { title, icon, url };
|
|
114
|
-
}).map(({ url, title, icon }, i) => /* @__PURE__ */ React.createElement(
|
|
115
|
-
IconLink,
|
|
116
|
-
{
|
|
117
|
-
key: `output-link-${i}`,
|
|
118
|
-
href: url,
|
|
119
|
-
text: title != null ? title : url,
|
|
120
|
-
Icon: iconResolver(icon),
|
|
121
|
-
target: "_blank"
|
|
122
|
-
}
|
|
123
|
-
)));
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const useStyles$a = makeStyles$1(
|
|
127
|
-
(theme) => createStyles({
|
|
128
|
-
root: {
|
|
129
|
-
width: "100%"
|
|
130
|
-
},
|
|
131
|
-
button: {
|
|
132
|
-
marginBottom: theme.spacing(2),
|
|
133
|
-
marginLeft: theme.spacing(2)
|
|
134
|
-
},
|
|
135
|
-
actionsContainer: {
|
|
136
|
-
marginBottom: theme.spacing(2)
|
|
137
|
-
},
|
|
138
|
-
resetContainer: {
|
|
139
|
-
padding: theme.spacing(3)
|
|
140
|
-
},
|
|
141
|
-
labelWrapper: {
|
|
142
|
-
display: "flex",
|
|
143
|
-
flex: 1,
|
|
144
|
-
flexDirection: "row",
|
|
145
|
-
justifyContent: "space-between"
|
|
146
|
-
},
|
|
147
|
-
stepWrapper: {
|
|
148
|
-
width: "100%"
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
);
|
|
152
|
-
const StepTimeTicker = ({ step }) => {
|
|
153
|
-
const [time, setTime] = useState("");
|
|
154
|
-
useInterval(() => {
|
|
155
|
-
if (!step.startedAt) {
|
|
156
|
-
setTime("");
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
const end = step.endedAt ? DateTime.fromISO(step.endedAt) : DateTime.local();
|
|
160
|
-
const startedAt = DateTime.fromISO(step.startedAt);
|
|
161
|
-
const formatted = Interval.fromDateTimes(startedAt, end).toDuration().valueOf();
|
|
162
|
-
setTime(humanizeDuration(formatted, { round: true }));
|
|
163
|
-
}, 1e3);
|
|
164
|
-
return /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, time);
|
|
165
|
-
};
|
|
166
|
-
const useStepIconStyles = makeStyles$1(
|
|
167
|
-
(theme) => createStyles({
|
|
168
|
-
root: {
|
|
169
|
-
color: theme.palette.text.disabled,
|
|
170
|
-
display: "flex",
|
|
171
|
-
height: 22,
|
|
172
|
-
alignItems: "center"
|
|
173
|
-
},
|
|
174
|
-
completed: {
|
|
175
|
-
color: theme.palette.status.ok
|
|
176
|
-
},
|
|
177
|
-
error: {
|
|
178
|
-
color: theme.palette.status.error
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
);
|
|
182
|
-
function TaskStepIconComponent(props) {
|
|
183
|
-
const classes = useStepIconStyles();
|
|
184
|
-
const { active, completed, error } = props;
|
|
185
|
-
const getMiddle = () => {
|
|
186
|
-
if (active) {
|
|
187
|
-
return /* @__PURE__ */ React.createElement(CircularProgress, { size: "24px" });
|
|
188
|
-
}
|
|
189
|
-
if (completed) {
|
|
190
|
-
return /* @__PURE__ */ React.createElement(Check, null);
|
|
191
|
-
}
|
|
192
|
-
if (error) {
|
|
193
|
-
return /* @__PURE__ */ React.createElement(Cancel, null);
|
|
194
|
-
}
|
|
195
|
-
return /* @__PURE__ */ React.createElement(FiberManualRecordIcon, null);
|
|
196
|
-
};
|
|
90
|
+
const SecretInput = (props) => {
|
|
91
|
+
var _a;
|
|
92
|
+
const { setSecrets, secrets } = useTemplateSecrets();
|
|
93
|
+
const {
|
|
94
|
+
name,
|
|
95
|
+
onChange,
|
|
96
|
+
schema: { title, description },
|
|
97
|
+
rawErrors,
|
|
98
|
+
disabled,
|
|
99
|
+
errors,
|
|
100
|
+
required
|
|
101
|
+
} = props;
|
|
197
102
|
return /* @__PURE__ */ React.createElement(
|
|
198
|
-
|
|
103
|
+
ScaffolderField,
|
|
199
104
|
{
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
105
|
+
rawErrors,
|
|
106
|
+
rawDescription: description,
|
|
107
|
+
disabled,
|
|
108
|
+
errors,
|
|
109
|
+
required
|
|
204
110
|
},
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const TaskStatusStepper = memo(
|
|
209
|
-
(props) => {
|
|
210
|
-
const { steps, currentStepId, onUserStepChange } = props;
|
|
211
|
-
const classes = useStyles$a(props);
|
|
212
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(
|
|
213
|
-
Stepper,
|
|
111
|
+
/* @__PURE__ */ React.createElement(InputLabel, { htmlFor: title }, title),
|
|
112
|
+
/* @__PURE__ */ React.createElement(
|
|
113
|
+
Input,
|
|
214
114
|
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
StepIconProps: {
|
|
229
|
-
completed: isCompleted,
|
|
230
|
-
error: isFailed || isCancelled,
|
|
231
|
-
active: isActive
|
|
232
|
-
},
|
|
233
|
-
StepIconComponent: TaskStepIconComponent,
|
|
234
|
-
className: classes.stepWrapper
|
|
235
|
-
},
|
|
236
|
-
/* @__PURE__ */ React.createElement("div", { className: classes.labelWrapper }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "subtitle2" }, step.name), isSkipped ? /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, "Skipped") : /* @__PURE__ */ React.createElement(StepTimeTicker, { step }))
|
|
237
|
-
)));
|
|
238
|
-
})
|
|
239
|
-
));
|
|
240
|
-
}
|
|
241
|
-
);
|
|
242
|
-
const hasLinks = ({ links = [] }) => links.length > 0;
|
|
243
|
-
const TaskPage = (props) => {
|
|
244
|
-
const { loadingText } = props;
|
|
245
|
-
const classes = useStyles$a();
|
|
246
|
-
const navigate = useNavigate();
|
|
247
|
-
const rootPath = useRouteRef(rootRouteRef);
|
|
248
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
249
|
-
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
250
|
-
const [userSelectedStepId, setUserSelectedStepId] = useState(void 0);
|
|
251
|
-
const [clickedToCancel, setClickedToCancel] = useState(false);
|
|
252
|
-
const [lastActiveStepId, setLastActiveStepId] = useState(
|
|
253
|
-
void 0
|
|
254
|
-
);
|
|
255
|
-
const { taskId } = useRouteRefParams(scaffolderTaskRouteRef);
|
|
256
|
-
const taskStream = useTaskEventStream(taskId);
|
|
257
|
-
const completed = taskStream.completed;
|
|
258
|
-
const taskCancelled = taskStream.cancelled;
|
|
259
|
-
const steps = useMemo(
|
|
260
|
-
() => {
|
|
261
|
-
var _a, _b;
|
|
262
|
-
return (_b = (_a = taskStream.task) == null ? void 0 : _a.spec.steps.map((step) => {
|
|
263
|
-
var _a2;
|
|
264
|
-
return {
|
|
265
|
-
...step,
|
|
266
|
-
...(_a2 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a2[step.id]
|
|
267
|
-
};
|
|
268
|
-
})) != null ? _b : [];
|
|
269
|
-
},
|
|
270
|
-
[taskStream]
|
|
115
|
+
id: title,
|
|
116
|
+
"aria-describedby": title,
|
|
117
|
+
onChange: (e) => {
|
|
118
|
+
var _a2, _b;
|
|
119
|
+
onChange(Array((_a2 = e.target) == null ? void 0 : _a2.value.length).fill("*").join(""));
|
|
120
|
+
setSecrets({ [name]: (_b = e.target) == null ? void 0 : _b.value });
|
|
121
|
+
},
|
|
122
|
+
value: (_a = secrets[name]) != null ? _a : "",
|
|
123
|
+
type: "password",
|
|
124
|
+
autoComplete: "off"
|
|
125
|
+
}
|
|
126
|
+
)
|
|
271
127
|
);
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
var _a;
|
|
274
|
-
const mostRecentFailedOrActiveStep = steps.find(
|
|
275
|
-
(step) => ["failed", "processing"].includes(step.status)
|
|
276
|
-
);
|
|
277
|
-
if (completed && !mostRecentFailedOrActiveStep) {
|
|
278
|
-
setLastActiveStepId((_a = steps[steps.length - 1]) == null ? void 0 : _a.id);
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
setLastActiveStepId(mostRecentFailedOrActiveStep == null ? void 0 : mostRecentFailedOrActiveStep.id);
|
|
282
|
-
}, [steps, completed]);
|
|
283
|
-
const currentStepId = userSelectedStepId != null ? userSelectedStepId : lastActiveStepId;
|
|
284
|
-
const logAsString = useMemo(() => {
|
|
285
|
-
if (!currentStepId) {
|
|
286
|
-
return loadingText ? loadingText : "Loading...";
|
|
287
|
-
}
|
|
288
|
-
const log = taskStream.stepLogs[currentStepId];
|
|
289
|
-
if (!(log == null ? void 0 : log.length)) {
|
|
290
|
-
return "Waiting for logs...";
|
|
291
|
-
}
|
|
292
|
-
return log.join("\n");
|
|
293
|
-
}, [taskStream.stepLogs, currentStepId, loadingText]);
|
|
294
|
-
const taskNotFound = taskStream.completed && !taskStream.loading && !taskStream.task;
|
|
295
|
-
const { output } = taskStream;
|
|
296
|
-
const handleStartOver = () => {
|
|
297
|
-
var _a, _b, _c;
|
|
298
|
-
if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.templateInfo) == null ? void 0 : _b.entityRef)) {
|
|
299
|
-
navigate(rootPath());
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const formData = taskStream.task.spec.parameters;
|
|
303
|
-
const { name, namespace } = parseEntityRef(
|
|
304
|
-
(_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef
|
|
305
|
-
);
|
|
306
|
-
navigate(
|
|
307
|
-
`${templateRoute({ templateName: name, namespace })}?${qs.stringify({
|
|
308
|
-
formData: JSON.stringify(formData)
|
|
309
|
-
})}`
|
|
310
|
-
);
|
|
311
|
-
};
|
|
312
|
-
const handleCancel = async () => {
|
|
313
|
-
setClickedToCancel(true);
|
|
314
|
-
await scaffolderApi.cancelTask(taskId);
|
|
315
|
-
};
|
|
316
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
317
|
-
Header,
|
|
318
|
-
{
|
|
319
|
-
pageTitleOverride: `Task ${taskId}`,
|
|
320
|
-
title: "Task Activity",
|
|
321
|
-
subtitle: `Activity for task: ${taskId}`
|
|
322
|
-
}
|
|
323
|
-
), /* @__PURE__ */ React.createElement(Content, null, taskNotFound ? /* @__PURE__ */ React.createElement(
|
|
324
|
-
ErrorPage,
|
|
325
|
-
{
|
|
326
|
-
status: "404",
|
|
327
|
-
statusMessage: "Task not found",
|
|
328
|
-
additionalInfo: "No task found with this ID"
|
|
329
|
-
}
|
|
330
|
-
) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Grid$1, { container: true }, /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 3 }, /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(
|
|
331
|
-
TaskStatusStepper,
|
|
332
|
-
{
|
|
333
|
-
steps,
|
|
334
|
-
currentStepId,
|
|
335
|
-
onUserStepChange: setUserSelectedStepId
|
|
336
|
-
}
|
|
337
|
-
), output && hasLinks(output) && /* @__PURE__ */ React.createElement(TaskPageLinks, { output }), /* @__PURE__ */ React.createElement(
|
|
338
|
-
Button,
|
|
339
|
-
{
|
|
340
|
-
className: classes.button,
|
|
341
|
-
onClick: handleStartOver,
|
|
342
|
-
disabled: !completed,
|
|
343
|
-
variant: "contained",
|
|
344
|
-
color: "primary"
|
|
345
|
-
},
|
|
346
|
-
"Start Over"
|
|
347
|
-
), /* @__PURE__ */ React.createElement(
|
|
348
|
-
Button,
|
|
349
|
-
{
|
|
350
|
-
className: classes.button,
|
|
351
|
-
onClick: handleCancel,
|
|
352
|
-
disabled: completed || taskCancelled || clickedToCancel,
|
|
353
|
-
variant: "outlined",
|
|
354
|
-
color: "secondary"
|
|
355
|
-
},
|
|
356
|
-
(taskCancelled || clickedToCancel) && !completed ? "Cancelling..." : "Cancel"
|
|
357
|
-
))), /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 9 }, !currentStepId && /* @__PURE__ */ React.createElement(Progress, null), /* @__PURE__ */ React.createElement("div", { style: { height: "80vh" } }, /* @__PURE__ */ React.createElement(TaskErrors, { error: taskStream.error }), /* @__PURE__ */ React.createElement(LogViewer, { text: logAsString })))))));
|
|
358
128
|
};
|
|
359
129
|
|
|
360
|
-
const
|
|
130
|
+
const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [
|
|
131
|
+
{
|
|
132
|
+
component: EntityPicker,
|
|
133
|
+
name: "EntityPicker",
|
|
134
|
+
schema: EntityPickerSchema
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
component: EntityNamePicker,
|
|
138
|
+
name: "EntityNamePicker",
|
|
139
|
+
validation: entityNamePickerValidation,
|
|
140
|
+
schema: EntityNamePickerSchema
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
component: EntityTagsPicker,
|
|
144
|
+
name: "EntityTagsPicker",
|
|
145
|
+
schema: EntityTagsPickerSchema
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
component: RepoUrlPicker,
|
|
149
|
+
name: "RepoUrlPicker",
|
|
150
|
+
validation: repoPickerValidation,
|
|
151
|
+
schema: RepoUrlPickerSchema
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
component: OwnerPicker,
|
|
155
|
+
name: "OwnerPicker",
|
|
156
|
+
schema: OwnerPickerSchema
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
component: OwnedEntityPicker,
|
|
160
|
+
name: "OwnedEntityPicker",
|
|
161
|
+
schema: OwnedEntityPickerSchema
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
component: MyGroupsPicker,
|
|
165
|
+
name: "MyGroupsPicker",
|
|
166
|
+
schema: MyGroupsPickerSchema
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
component: SecretInput,
|
|
170
|
+
name: "Secret"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
component: MultiEntityPicker,
|
|
174
|
+
name: "MultiEntityPicker",
|
|
175
|
+
schema: MultiEntityPickerSchema,
|
|
176
|
+
validation: validateMultiEntityPickerValidation
|
|
177
|
+
}
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
const useStyles$f = makeStyles((theme) => ({
|
|
361
181
|
code: {
|
|
362
182
|
fontFamily: "Menlo, monospace",
|
|
363
183
|
padding: theme.spacing(1),
|
|
@@ -393,7 +213,7 @@ const ExamplesTable = (props) => {
|
|
|
393
213
|
};
|
|
394
214
|
const ActionsPage = () => {
|
|
395
215
|
const api = useApi(scaffolderApiRef);
|
|
396
|
-
const classes = useStyles$
|
|
216
|
+
const classes = useStyles$f();
|
|
397
217
|
const { loading, value, error } = useAsync(async () => {
|
|
398
218
|
return api.listActions();
|
|
399
219
|
});
|
|
@@ -501,91 +321,7 @@ const ActionsPage = () => {
|
|
|
501
321
|
), /* @__PURE__ */ React.createElement(Content, null, items));
|
|
502
322
|
};
|
|
503
323
|
|
|
504
|
-
const
|
|
505
|
-
var _a;
|
|
506
|
-
const { setSecrets, secrets } = useTemplateSecrets();
|
|
507
|
-
const {
|
|
508
|
-
name,
|
|
509
|
-
onChange,
|
|
510
|
-
schema: { title, description },
|
|
511
|
-
rawErrors,
|
|
512
|
-
disabled,
|
|
513
|
-
errors,
|
|
514
|
-
required
|
|
515
|
-
} = props;
|
|
516
|
-
return /* @__PURE__ */ React.createElement(
|
|
517
|
-
ScaffolderField,
|
|
518
|
-
{
|
|
519
|
-
rawErrors,
|
|
520
|
-
rawDescription: description,
|
|
521
|
-
disabled,
|
|
522
|
-
errors,
|
|
523
|
-
required
|
|
524
|
-
},
|
|
525
|
-
/* @__PURE__ */ React.createElement(InputLabel, { htmlFor: title }, title),
|
|
526
|
-
/* @__PURE__ */ React.createElement(
|
|
527
|
-
Input,
|
|
528
|
-
{
|
|
529
|
-
id: title,
|
|
530
|
-
"aria-describedby": title,
|
|
531
|
-
onChange: (e) => {
|
|
532
|
-
var _a2, _b;
|
|
533
|
-
onChange(Array((_a2 = e.target) == null ? void 0 : _a2.value.length).fill("*").join(""));
|
|
534
|
-
setSecrets({ [name]: (_b = e.target) == null ? void 0 : _b.value });
|
|
535
|
-
},
|
|
536
|
-
value: (_a = secrets[name]) != null ? _a : "",
|
|
537
|
-
type: "password",
|
|
538
|
-
autoComplete: "off"
|
|
539
|
-
}
|
|
540
|
-
)
|
|
541
|
-
);
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [
|
|
545
|
-
{
|
|
546
|
-
component: EntityPicker,
|
|
547
|
-
name: "EntityPicker",
|
|
548
|
-
schema: EntityPickerSchema
|
|
549
|
-
},
|
|
550
|
-
{
|
|
551
|
-
component: EntityNamePicker,
|
|
552
|
-
name: "EntityNamePicker",
|
|
553
|
-
validation: entityNamePickerValidation,
|
|
554
|
-
schema: EntityNamePickerSchema
|
|
555
|
-
},
|
|
556
|
-
{
|
|
557
|
-
component: EntityTagsPicker,
|
|
558
|
-
name: "EntityTagsPicker",
|
|
559
|
-
schema: EntityTagsPickerSchema
|
|
560
|
-
},
|
|
561
|
-
{
|
|
562
|
-
component: RepoUrlPicker,
|
|
563
|
-
name: "RepoUrlPicker",
|
|
564
|
-
validation: repoPickerValidation,
|
|
565
|
-
schema: RepoUrlPickerSchema
|
|
566
|
-
},
|
|
567
|
-
{
|
|
568
|
-
component: OwnerPicker,
|
|
569
|
-
name: "OwnerPicker",
|
|
570
|
-
schema: OwnerPickerSchema
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
component: OwnedEntityPicker,
|
|
574
|
-
name: "OwnedEntityPicker",
|
|
575
|
-
schema: OwnedEntityPickerSchema
|
|
576
|
-
},
|
|
577
|
-
{
|
|
578
|
-
component: MyGroupsPicker,
|
|
579
|
-
name: "MyGroupsPicker",
|
|
580
|
-
schema: MyGroupsPickerSchema
|
|
581
|
-
},
|
|
582
|
-
{
|
|
583
|
-
component: SecretInput,
|
|
584
|
-
name: "Secret"
|
|
585
|
-
}
|
|
586
|
-
];
|
|
587
|
-
|
|
588
|
-
const useStyles$8 = makeStyles(
|
|
324
|
+
const useStyles$e = makeStyles(
|
|
589
325
|
(theme) => ({
|
|
590
326
|
root: {
|
|
591
327
|
backgroundColor: "rgba(0, 0, 0, .11)",
|
|
@@ -634,7 +370,7 @@ function getFilterGroups() {
|
|
|
634
370
|
}
|
|
635
371
|
const OwnerListPicker = (props) => {
|
|
636
372
|
const { filter, onSelectOwner } = props;
|
|
637
|
-
const classes = useStyles$
|
|
373
|
+
const classes = useStyles$e();
|
|
638
374
|
const filterGroups = getFilterGroups();
|
|
639
375
|
return /* @__PURE__ */ React.createElement(Card, { className: classes.root }, filterGroups.map((group) => /* @__PURE__ */ React.createElement(Fragment, { key: group.name }, /* @__PURE__ */ React.createElement(
|
|
640
376
|
Typography,
|
|
@@ -796,11 +532,170 @@ const ListTasksPage = (props) => {
|
|
|
796
532
|
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
797
533
|
Header,
|
|
798
534
|
{
|
|
799
|
-
pageTitleOverride: "Templates Tasks",
|
|
800
|
-
title:
|
|
801
|
-
subtitle: "All tasks that have been started"
|
|
535
|
+
pageTitleOverride: "Templates Tasks",
|
|
536
|
+
title: "List template tasks",
|
|
537
|
+
subtitle: "All tasks that have been started"
|
|
538
|
+
}
|
|
539
|
+
), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ListTaskPageContent, { ...props })));
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const RegisterExistingButton = (props) => {
|
|
543
|
+
const { title, to } = props;
|
|
544
|
+
const { allowed } = usePermission({
|
|
545
|
+
permission: catalogEntityCreatePermission
|
|
546
|
+
});
|
|
547
|
+
const isXSScreen = useMediaQuery(
|
|
548
|
+
(theme) => theme.breakpoints.down("xs")
|
|
549
|
+
);
|
|
550
|
+
if (!to || !allowed) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
return isXSScreen ? /* @__PURE__ */ React.createElement(
|
|
554
|
+
IconButton,
|
|
555
|
+
{
|
|
556
|
+
component: Link$1,
|
|
557
|
+
color: "primary",
|
|
558
|
+
title,
|
|
559
|
+
size: "small",
|
|
560
|
+
to
|
|
561
|
+
},
|
|
562
|
+
/* @__PURE__ */ React.createElement(CreateComponentIcon, null)
|
|
563
|
+
) : /* @__PURE__ */ React.createElement(Button, { component: Link$1, variant: "contained", color: "primary", to }, title);
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const defaultGroup = {
|
|
567
|
+
title: "Templates",
|
|
568
|
+
filter: () => true
|
|
569
|
+
};
|
|
570
|
+
const createGroupsWithOther = (groups) => [
|
|
571
|
+
...groups,
|
|
572
|
+
{
|
|
573
|
+
title: "Other Templates",
|
|
574
|
+
filter: (e) => ![...groups].some(({ filter }) => filter(e))
|
|
575
|
+
}
|
|
576
|
+
];
|
|
577
|
+
const TemplateListPage = (props) => {
|
|
578
|
+
var _a, _b, _c;
|
|
579
|
+
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
580
|
+
const {
|
|
581
|
+
TemplateCardComponent,
|
|
582
|
+
groups: givenGroups = [],
|
|
583
|
+
templateFilter,
|
|
584
|
+
headerOptions
|
|
585
|
+
} = props;
|
|
586
|
+
const navigate = useNavigate();
|
|
587
|
+
const editorLink = useRouteRef(editRouteRef);
|
|
588
|
+
const actionsLink = useRouteRef(actionsRouteRef);
|
|
589
|
+
const tasksLink = useRouteRef(scaffolderListTaskRouteRef);
|
|
590
|
+
const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);
|
|
591
|
+
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
592
|
+
const app = useApp();
|
|
593
|
+
const groups = givenGroups.length ? createGroupsWithOther(givenGroups) : [defaultGroup];
|
|
594
|
+
const scaffolderPageContextMenuProps = {
|
|
595
|
+
onEditorClicked: ((_a = props == null ? void 0 : props.contextMenu) == null ? void 0 : _a.editor) !== false ? () => navigate(editorLink()) : void 0,
|
|
596
|
+
onActionsClicked: ((_b = props == null ? void 0 : props.contextMenu) == null ? void 0 : _b.actions) !== false ? () => navigate(actionsLink()) : void 0,
|
|
597
|
+
onTasksClicked: ((_c = props == null ? void 0 : props.contextMenu) == null ? void 0 : _c.tasks) !== false ? () => navigate(tasksLink()) : void 0
|
|
598
|
+
};
|
|
599
|
+
const additionalLinksForEntity = useCallback(
|
|
600
|
+
(template) => {
|
|
601
|
+
var _a2, _b2;
|
|
602
|
+
const { kind, namespace, name } = parseEntityRef(
|
|
603
|
+
stringifyEntityRef(template)
|
|
604
|
+
);
|
|
605
|
+
return ((_a2 = template.metadata.annotations) == null ? void 0 : _a2["backstage.io/techdocs-ref"]) && viewTechDocsLink ? [
|
|
606
|
+
{
|
|
607
|
+
icon: (_b2 = app.getSystemIcon("docs")) != null ? _b2 : DocsIcon,
|
|
608
|
+
text: "View TechDocs",
|
|
609
|
+
url: viewTechDocsLink({ kind, namespace, name })
|
|
610
|
+
}
|
|
611
|
+
] : [];
|
|
612
|
+
},
|
|
613
|
+
[app, viewTechDocsLink]
|
|
614
|
+
);
|
|
615
|
+
const onTemplateSelected = useCallback(
|
|
616
|
+
(template) => {
|
|
617
|
+
const { namespace, name } = parseEntityRef(stringifyEntityRef(template));
|
|
618
|
+
navigate(templateRoute({ namespace, templateName: name }));
|
|
619
|
+
},
|
|
620
|
+
[navigate, templateRoute]
|
|
621
|
+
);
|
|
622
|
+
return /* @__PURE__ */ React.createElement(EntityListProvider, null, /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
623
|
+
Header,
|
|
624
|
+
{
|
|
625
|
+
pageTitleOverride: "Create a new component",
|
|
626
|
+
title: "Create a new component",
|
|
627
|
+
subtitle: "Create new software components using standard templates in your organization",
|
|
628
|
+
...headerOptions
|
|
629
|
+
},
|
|
630
|
+
/* @__PURE__ */ React.createElement(ScaffolderPageContextMenu, { ...scaffolderPageContextMenuProps })
|
|
631
|
+
), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ContentHeader, { title: "Available Templates" }, /* @__PURE__ */ React.createElement(
|
|
632
|
+
RegisterExistingButton,
|
|
633
|
+
{
|
|
634
|
+
title: "Register Existing Component",
|
|
635
|
+
to: registerComponentLink && registerComponentLink()
|
|
636
|
+
}
|
|
637
|
+
), /* @__PURE__ */ React.createElement(SupportButton, null, "Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).")), /* @__PURE__ */ React.createElement(CatalogFilterLayout, null, /* @__PURE__ */ React.createElement(CatalogFilterLayout.Filters, null, /* @__PURE__ */ React.createElement(EntitySearchBar, null), /* @__PURE__ */ React.createElement(EntityKindPicker, { initialFilter: "template", hidden: true }), /* @__PURE__ */ React.createElement(
|
|
638
|
+
UserListPicker,
|
|
639
|
+
{
|
|
640
|
+
initialFilter: "all",
|
|
641
|
+
availableFilters: ["all", "starred"]
|
|
642
|
+
}
|
|
643
|
+
), /* @__PURE__ */ React.createElement(TemplateCategoryPicker, null), /* @__PURE__ */ React.createElement(EntityTagPicker, null)), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, /* @__PURE__ */ React.createElement(
|
|
644
|
+
TemplateGroups,
|
|
645
|
+
{
|
|
646
|
+
groups,
|
|
647
|
+
templateFilter,
|
|
648
|
+
TemplateCardComponent,
|
|
649
|
+
onTemplateSelected,
|
|
650
|
+
additionalLinksForEntity
|
|
651
|
+
}
|
|
652
|
+
))))));
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
const TemplateWizardPage = (props) => {
|
|
656
|
+
const rootRef = useRouteRef(rootRouteRef);
|
|
657
|
+
const taskRoute = useRouteRef(scaffolderTaskRouteRef);
|
|
658
|
+
const { secrets } = useTemplateSecrets();
|
|
659
|
+
const scaffolderApi = useApi(scaffolderApiRef);
|
|
660
|
+
const navigate = useNavigate();
|
|
661
|
+
const { templateName, namespace } = useRouteRefParams(
|
|
662
|
+
selectedTemplateRouteRef
|
|
663
|
+
);
|
|
664
|
+
const templateRef = stringifyEntityRef({
|
|
665
|
+
kind: "Template",
|
|
666
|
+
namespace,
|
|
667
|
+
name: templateName
|
|
668
|
+
});
|
|
669
|
+
const onCreate = async (values) => {
|
|
670
|
+
const { taskId } = await scaffolderApi.scaffold({
|
|
671
|
+
templateRef,
|
|
672
|
+
values,
|
|
673
|
+
secrets
|
|
674
|
+
});
|
|
675
|
+
navigate(taskRoute({ taskId }));
|
|
676
|
+
};
|
|
677
|
+
const onError = () => /* @__PURE__ */ React.createElement(Navigate, { to: rootRef() });
|
|
678
|
+
return /* @__PURE__ */ React.createElement(AnalyticsContext, { attributes: { entityRef: templateRef } }, /* @__PURE__ */ React.createElement(Page, { themeId: "website" }, /* @__PURE__ */ React.createElement(
|
|
679
|
+
Header,
|
|
680
|
+
{
|
|
681
|
+
pageTitleOverride: "Create a new component",
|
|
682
|
+
title: "Create a new component",
|
|
683
|
+
subtitle: "Create new software components using standard templates in your organization",
|
|
684
|
+
...props.headerOptions
|
|
802
685
|
}
|
|
803
|
-
), /* @__PURE__ */ React.createElement(
|
|
686
|
+
), /* @__PURE__ */ React.createElement(
|
|
687
|
+
Workflow,
|
|
688
|
+
{
|
|
689
|
+
namespace,
|
|
690
|
+
templateName,
|
|
691
|
+
onCreate,
|
|
692
|
+
components: props.components,
|
|
693
|
+
onError,
|
|
694
|
+
extensions: props.customFieldExtensions,
|
|
695
|
+
formProps: props.formProps,
|
|
696
|
+
layouts: props.layouts
|
|
697
|
+
}
|
|
698
|
+
)));
|
|
804
699
|
};
|
|
805
700
|
|
|
806
701
|
const showDirectoryPicker = window.showDirectoryPicker;
|
|
@@ -857,91 +752,113 @@ class WebFileSystemAccess {
|
|
|
857
752
|
}
|
|
858
753
|
}
|
|
859
754
|
|
|
860
|
-
const
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
position: "relative",
|
|
867
|
-
maxWidth: 340,
|
|
868
|
-
marginTop: theme.spacing(4),
|
|
869
|
-
margin: theme.spacing(0, 2)
|
|
870
|
-
},
|
|
871
|
-
infoIcon: {
|
|
872
|
-
position: "absolute",
|
|
873
|
-
top: theme.spacing(1),
|
|
874
|
-
right: theme.spacing(1)
|
|
755
|
+
const MAX_CONTENT_SIZE = 64 * 1024;
|
|
756
|
+
const CHUNK_SIZE = 32 * 1024;
|
|
757
|
+
const DryRunContext = createContext(void 0);
|
|
758
|
+
function base64EncodeContent(content) {
|
|
759
|
+
if (content.length > MAX_CONTENT_SIZE) {
|
|
760
|
+
return window.btoa("<file too large>");
|
|
875
761
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
{
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
762
|
+
try {
|
|
763
|
+
return window.btoa(content);
|
|
764
|
+
} catch {
|
|
765
|
+
const decoder = new TextEncoder();
|
|
766
|
+
const buffer = decoder.encode(content);
|
|
767
|
+
const chunks = new Array();
|
|
768
|
+
for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
|
|
769
|
+
chunks.push(
|
|
770
|
+
String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE))
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
return window.btoa(chunks.join(""));
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
function DryRunProvider(props) {
|
|
777
|
+
const scaffolderApi = useApi(scaffolderApiRef);
|
|
778
|
+
const [state, setState] = useState({
|
|
779
|
+
results: [],
|
|
780
|
+
selectedResult: void 0
|
|
781
|
+
});
|
|
782
|
+
const idRef = useRef(1);
|
|
783
|
+
const selectResult = useCallback((id) => {
|
|
784
|
+
setState((prevState) => {
|
|
785
|
+
const result = prevState.results.find((r) => r.id === id);
|
|
786
|
+
if (result === prevState.selectedResult) {
|
|
787
|
+
return prevState;
|
|
887
788
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
/* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
|
|
914
|
-
)));
|
|
915
|
-
const cardFormEditor = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
916
|
-
var _a;
|
|
917
|
-
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
|
|
918
|
-
} }, /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h3", gutterBottom: true }, "Edit Template Form"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "Preview and edit a template form, either using a sample template or by loading a template from the catalog."))));
|
|
919
|
-
const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
920
|
-
var _a;
|
|
921
|
-
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
|
|
922
|
-
} }, /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h3", gutterBottom: true }, "Custom Field Explorer"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "View and play around with available installed custom field extensions."))));
|
|
923
|
-
return /* @__PURE__ */ React.createElement("div", { style: props.style }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h2", className: classes.introText }, "Get started by choosing one of the options below"), /* @__PURE__ */ React.createElement(
|
|
924
|
-
"div",
|
|
925
|
-
{
|
|
926
|
-
style: {
|
|
927
|
-
display: "flex",
|
|
928
|
-
flexFlow: "row wrap",
|
|
929
|
-
alignItems: "flex-start",
|
|
930
|
-
justifyContent: "center",
|
|
931
|
-
alignContent: "flex-start"
|
|
789
|
+
return {
|
|
790
|
+
results: prevState.results,
|
|
791
|
+
selectedResult: result
|
|
792
|
+
};
|
|
793
|
+
});
|
|
794
|
+
}, []);
|
|
795
|
+
const deleteResult = useCallback((id) => {
|
|
796
|
+
setState((prevState) => {
|
|
797
|
+
var _a;
|
|
798
|
+
const index = prevState.results.findIndex((r) => r.id === id);
|
|
799
|
+
if (index === -1) {
|
|
800
|
+
return prevState;
|
|
801
|
+
}
|
|
802
|
+
const newResults = prevState.results.slice();
|
|
803
|
+
const [deleted] = newResults.splice(index, 1);
|
|
804
|
+
return {
|
|
805
|
+
results: newResults,
|
|
806
|
+
selectedResult: ((_a = prevState.selectedResult) == null ? void 0 : _a.id) === deleted.id ? newResults[0] : prevState.selectedResult
|
|
807
|
+
};
|
|
808
|
+
});
|
|
809
|
+
}, []);
|
|
810
|
+
const execute = useCallback(
|
|
811
|
+
async (options) => {
|
|
812
|
+
if (!scaffolderApi.dryRun) {
|
|
813
|
+
throw new Error("Scaffolder API does not support dry-run");
|
|
932
814
|
}
|
|
815
|
+
const parsed = yaml.parse(options.templateContent);
|
|
816
|
+
const response = await scaffolderApi.dryRun({
|
|
817
|
+
template: parsed,
|
|
818
|
+
values: options.values,
|
|
819
|
+
secrets: {},
|
|
820
|
+
directoryContents: options.files.map((file) => ({
|
|
821
|
+
path: file.path,
|
|
822
|
+
base64Content: base64EncodeContent(file.content)
|
|
823
|
+
}))
|
|
824
|
+
});
|
|
825
|
+
const result = {
|
|
826
|
+
...response,
|
|
827
|
+
id: idRef.current++
|
|
828
|
+
};
|
|
829
|
+
setState((prevState) => {
|
|
830
|
+
var _a;
|
|
831
|
+
return {
|
|
832
|
+
results: [...prevState.results, result],
|
|
833
|
+
selectedResult: (_a = prevState.selectedResult) != null ? _a : result
|
|
834
|
+
};
|
|
835
|
+
});
|
|
933
836
|
},
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
837
|
+
[scaffolderApi]
|
|
838
|
+
);
|
|
839
|
+
const dryRun = useMemo(
|
|
840
|
+
() => ({
|
|
841
|
+
...state,
|
|
842
|
+
selectResult,
|
|
843
|
+
deleteResult,
|
|
844
|
+
execute
|
|
845
|
+
}),
|
|
846
|
+
[state, selectResult, deleteResult, execute]
|
|
847
|
+
);
|
|
848
|
+
return /* @__PURE__ */ React.createElement(DryRunContext.Provider, { value: dryRun }, props.children);
|
|
849
|
+
}
|
|
850
|
+
function useDryRun() {
|
|
851
|
+
const value = useContext(DryRunContext);
|
|
852
|
+
if (!value) {
|
|
853
|
+
throw new Error("must be used within a DryRunProvider");
|
|
854
|
+
}
|
|
855
|
+
return value;
|
|
939
856
|
}
|
|
940
857
|
|
|
941
|
-
var __defProp = Object.defineProperty;
|
|
942
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
943
|
-
var __publicField = (obj, key, value) => {
|
|
944
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
858
|
+
var __defProp$1 = Object.defineProperty;
|
|
859
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
860
|
+
var __publicField$1 = (obj, key, value) => {
|
|
861
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
945
862
|
return value;
|
|
946
863
|
};
|
|
947
864
|
var __accessCheck = (obj, member, msg) => {
|
|
@@ -1026,7 +943,7 @@ class DirectoryEditorManager {
|
|
|
1026
943
|
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
1027
944
|
__privateAdd(this, _files, []);
|
|
1028
945
|
__privateAdd(this, _selectedFile, void 0);
|
|
1029
|
-
__publicField(this, "setSelectedFile", (path) => {
|
|
946
|
+
__publicField$1(this, "setSelectedFile", (path) => {
|
|
1030
947
|
const prev = __privateGet(this, _selectedFile);
|
|
1031
948
|
const next = __privateGet(this, _files).find((file) => file.path === path);
|
|
1032
949
|
if (prev !== next) {
|
|
@@ -1118,110 +1035,299 @@ function DirectoryEditorProvider(props) {
|
|
|
1118
1035
|
return /* @__PURE__ */ React.createElement(DirectoryEditorContext.Provider, { value: result }, props.children);
|
|
1119
1036
|
}
|
|
1120
1037
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1038
|
+
var __defProp = Object.defineProperty;
|
|
1039
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1040
|
+
var __publicField = (obj, key, value) => {
|
|
1041
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1042
|
+
return value;
|
|
1043
|
+
};
|
|
1044
|
+
const useStyles$d = makeStyles$1({
|
|
1045
|
+
containerWrapper: {
|
|
1046
|
+
position: "relative",
|
|
1047
|
+
width: "100%",
|
|
1048
|
+
height: "100%"
|
|
1049
|
+
},
|
|
1050
|
+
container: {
|
|
1051
|
+
position: "absolute",
|
|
1052
|
+
top: 0,
|
|
1053
|
+
bottom: 0,
|
|
1054
|
+
left: 0,
|
|
1055
|
+
right: 0,
|
|
1056
|
+
overflow: "auto"
|
|
1140
1057
|
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
});
|
|
1148
|
-
const idRef = useRef(1);
|
|
1149
|
-
const selectResult = useCallback((id) => {
|
|
1150
|
-
setState((prevState) => {
|
|
1151
|
-
const result = prevState.results.find((r) => r.id === id);
|
|
1152
|
-
if (result === prevState.selectedResult) {
|
|
1153
|
-
return prevState;
|
|
1154
|
-
}
|
|
1155
|
-
return {
|
|
1156
|
-
results: prevState.results,
|
|
1157
|
-
selectedResult: result
|
|
1158
|
-
};
|
|
1159
|
-
});
|
|
1160
|
-
}, []);
|
|
1161
|
-
const deleteResult = useCallback((id) => {
|
|
1162
|
-
setState((prevState) => {
|
|
1163
|
-
var _a;
|
|
1164
|
-
const index = prevState.results.findIndex((r) => r.id === id);
|
|
1165
|
-
if (index === -1) {
|
|
1166
|
-
return prevState;
|
|
1167
|
-
}
|
|
1168
|
-
const newResults = prevState.results.slice();
|
|
1169
|
-
const [deleted] = newResults.splice(index, 1);
|
|
1170
|
-
return {
|
|
1171
|
-
results: newResults,
|
|
1172
|
-
selectedResult: ((_a = prevState.selectedResult) == null ? void 0 : _a.id) === deleted.id ? newResults[0] : prevState.selectedResult
|
|
1173
|
-
};
|
|
1058
|
+
});
|
|
1059
|
+
class ErrorBoundary extends Component {
|
|
1060
|
+
constructor() {
|
|
1061
|
+
super(...arguments);
|
|
1062
|
+
__publicField(this, "state", {
|
|
1063
|
+
shouldRender: true
|
|
1174
1064
|
});
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1065
|
+
}
|
|
1066
|
+
componentDidUpdate(prevProps) {
|
|
1067
|
+
if (prevProps.invalidator !== this.props.invalidator) {
|
|
1068
|
+
this.setState({ shouldRender: true });
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
componentDidCatch(error) {
|
|
1072
|
+
this.props.setErrorText(error.message);
|
|
1073
|
+
this.setState({ shouldRender: false });
|
|
1074
|
+
}
|
|
1075
|
+
render() {
|
|
1076
|
+
return this.state.shouldRender ? this.props.children : null;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function isJsonObject(value) {
|
|
1080
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1081
|
+
}
|
|
1082
|
+
function TemplateEditorForm(props) {
|
|
1083
|
+
const {
|
|
1084
|
+
content,
|
|
1085
|
+
contentIsSpec,
|
|
1086
|
+
onDryRun,
|
|
1087
|
+
setErrorText,
|
|
1088
|
+
fieldExtensions = [],
|
|
1089
|
+
layouts = []
|
|
1090
|
+
} = props;
|
|
1091
|
+
const classes = useStyles$d();
|
|
1092
|
+
const apiHolder = useApiHolder();
|
|
1093
|
+
const [steps, setSteps] = useState();
|
|
1094
|
+
const fields = useMemo(() => {
|
|
1095
|
+
return Object.fromEntries(
|
|
1096
|
+
fieldExtensions.map(({ name, component }) => [name, component])
|
|
1097
|
+
);
|
|
1098
|
+
}, [fieldExtensions]);
|
|
1099
|
+
useDebounce(
|
|
1100
|
+
() => {
|
|
1101
|
+
try {
|
|
1102
|
+
if (!content) {
|
|
1103
|
+
setSteps(void 0);
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
const parsed = yaml.parseAllDocuments(content).filter((c) => c).map((c) => c.toJSON())[0];
|
|
1107
|
+
if (!isJsonObject(parsed)) {
|
|
1108
|
+
setSteps(void 0);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
let rootObj = parsed;
|
|
1112
|
+
if (!contentIsSpec) {
|
|
1113
|
+
const isTemplate = String(parsed.kind).toLocaleLowerCase("en-US") === "template";
|
|
1114
|
+
if (!isTemplate) {
|
|
1115
|
+
setSteps(void 0);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
rootObj = isJsonObject(parsed.spec) ? parsed.spec : {};
|
|
1119
|
+
}
|
|
1120
|
+
const { parameters } = rootObj;
|
|
1121
|
+
if (!Array.isArray(parameters)) {
|
|
1122
|
+
setErrorText("Template parameters must be an array");
|
|
1123
|
+
setSteps(void 0);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
const fieldValidators = Object.fromEntries(
|
|
1127
|
+
fieldExtensions.map(({ name, validation }) => [name, validation])
|
|
1128
|
+
);
|
|
1129
|
+
setErrorText();
|
|
1130
|
+
setSteps(
|
|
1131
|
+
parameters.flatMap(
|
|
1132
|
+
(param) => isJsonObject(param) ? [
|
|
1133
|
+
{
|
|
1134
|
+
title: String(param.title),
|
|
1135
|
+
schema: param,
|
|
1136
|
+
validate: createAsyncValidators(param, fieldValidators, {
|
|
1137
|
+
apiHolder
|
|
1138
|
+
})
|
|
1139
|
+
}
|
|
1140
|
+
] : []
|
|
1141
|
+
)
|
|
1142
|
+
);
|
|
1143
|
+
} catch (e) {
|
|
1144
|
+
setErrorText(e.message);
|
|
1180
1145
|
}
|
|
1181
|
-
const parsed = yaml.parse(options.templateContent);
|
|
1182
|
-
const response = await scaffolderApi.dryRun({
|
|
1183
|
-
template: parsed,
|
|
1184
|
-
values: options.values,
|
|
1185
|
-
secrets: {},
|
|
1186
|
-
directoryContents: options.files.map((file) => ({
|
|
1187
|
-
path: file.path,
|
|
1188
|
-
base64Content: base64EncodeContent(file.content)
|
|
1189
|
-
}))
|
|
1190
|
-
});
|
|
1191
|
-
const result = {
|
|
1192
|
-
...response,
|
|
1193
|
-
id: idRef.current++
|
|
1194
|
-
};
|
|
1195
|
-
setState((prevState) => {
|
|
1196
|
-
var _a;
|
|
1197
|
-
return {
|
|
1198
|
-
results: [...prevState.results, result],
|
|
1199
|
-
selectedResult: (_a = prevState.selectedResult) != null ? _a : result
|
|
1200
|
-
};
|
|
1201
|
-
});
|
|
1202
1146
|
},
|
|
1203
|
-
|
|
1147
|
+
250,
|
|
1148
|
+
[contentIsSpec, content, apiHolder]
|
|
1204
1149
|
);
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1150
|
+
if (!steps) {
|
|
1151
|
+
return null;
|
|
1152
|
+
}
|
|
1153
|
+
return /* @__PURE__ */ React.createElement("div", { className: classes.containerWrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(ErrorBoundary, { invalidator: steps, setErrorText }, /* @__PURE__ */ React.createElement(
|
|
1154
|
+
Stepper,
|
|
1155
|
+
{
|
|
1156
|
+
manifest: { steps, title: "Template Editor" },
|
|
1157
|
+
extensions: fieldExtensions,
|
|
1158
|
+
components: fields,
|
|
1159
|
+
onCreate: async (options) => {
|
|
1160
|
+
await (onDryRun == null ? void 0 : onDryRun(options));
|
|
1161
|
+
},
|
|
1162
|
+
layouts
|
|
1163
|
+
}
|
|
1164
|
+
))));
|
|
1165
|
+
}
|
|
1166
|
+
function TemplateEditorFormDirectoryEditorDryRun(props) {
|
|
1167
|
+
const { setErrorText, fieldExtensions = [], layouts } = props;
|
|
1168
|
+
const dryRun = useDryRun();
|
|
1169
|
+
const directoryEditor = useDirectoryEditor();
|
|
1170
|
+
const { selectedFile } = directoryEditor;
|
|
1171
|
+
const handleDryRun = async (data) => {
|
|
1172
|
+
if (!selectedFile) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
try {
|
|
1176
|
+
await dryRun.execute({
|
|
1177
|
+
templateContent: selectedFile.content,
|
|
1178
|
+
values: data,
|
|
1179
|
+
files: directoryEditor.files
|
|
1180
|
+
});
|
|
1181
|
+
setErrorText();
|
|
1182
|
+
} catch (e) {
|
|
1183
|
+
setErrorText(String(e.cause || e));
|
|
1184
|
+
throw e;
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
const content = selectedFile && selectedFile.path.match(/\.ya?ml$/) ? selectedFile.content : void 0;
|
|
1188
|
+
return /* @__PURE__ */ React.createElement(
|
|
1189
|
+
TemplateEditorForm,
|
|
1190
|
+
{
|
|
1191
|
+
onDryRun: handleDryRun,
|
|
1192
|
+
fieldExtensions,
|
|
1193
|
+
setErrorText,
|
|
1194
|
+
content,
|
|
1195
|
+
layouts
|
|
1196
|
+
}
|
|
1213
1197
|
);
|
|
1214
|
-
return /* @__PURE__ */ React.createElement(DryRunContext.Provider, { value: dryRun }, props.children);
|
|
1215
1198
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1199
|
+
TemplateEditorForm.DirectoryEditorDryRun = TemplateEditorFormDirectoryEditorDryRun;
|
|
1200
|
+
|
|
1201
|
+
const useStyles$c = makeStyles((theme) => ({
|
|
1202
|
+
root: {
|
|
1203
|
+
gridArea: "pageContent",
|
|
1204
|
+
display: "grid",
|
|
1205
|
+
gridTemplateAreas: `
|
|
1206
|
+
"controls controls"
|
|
1207
|
+
"fieldForm preview"
|
|
1208
|
+
`,
|
|
1209
|
+
gridTemplateRows: "auto 1fr",
|
|
1210
|
+
gridTemplateColumns: "1fr 1fr"
|
|
1211
|
+
},
|
|
1212
|
+
controls: {
|
|
1213
|
+
gridArea: "controls",
|
|
1214
|
+
display: "flex",
|
|
1215
|
+
flexFlow: "row nowrap",
|
|
1216
|
+
alignItems: "center",
|
|
1217
|
+
margin: theme.spacing(1)
|
|
1218
|
+
},
|
|
1219
|
+
fieldForm: {
|
|
1220
|
+
gridArea: "fieldForm"
|
|
1221
|
+
},
|
|
1222
|
+
preview: {
|
|
1223
|
+
gridArea: "preview"
|
|
1220
1224
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1225
|
+
}));
|
|
1226
|
+
const CustomFieldExplorer = ({
|
|
1227
|
+
customFieldExtensions = [],
|
|
1228
|
+
onClose
|
|
1229
|
+
}) => {
|
|
1230
|
+
var _a, _b;
|
|
1231
|
+
const classes = useStyles$c();
|
|
1232
|
+
const fieldOptions = customFieldExtensions.filter((field) => !!field.schema);
|
|
1233
|
+
const [selectedField, setSelectedField] = useState(fieldOptions[0]);
|
|
1234
|
+
const [fieldFormState, setFieldFormState] = useState({});
|
|
1235
|
+
const [refreshKey, setRefreshKey] = useState(Date.now());
|
|
1236
|
+
const sampleFieldTemplate = useMemo(
|
|
1237
|
+
() => {
|
|
1238
|
+
var _a2, _b2;
|
|
1239
|
+
return yaml.stringify({
|
|
1240
|
+
parameters: [
|
|
1241
|
+
{
|
|
1242
|
+
title: `${selectedField.name} Example`,
|
|
1243
|
+
properties: {
|
|
1244
|
+
[selectedField.name]: {
|
|
1245
|
+
type: (_b2 = (_a2 = selectedField.schema) == null ? void 0 : _a2.returnValue) == null ? void 0 : _b2.type,
|
|
1246
|
+
"ui:field": selectedField.name,
|
|
1247
|
+
"ui:options": fieldFormState
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
]
|
|
1252
|
+
});
|
|
1253
|
+
},
|
|
1254
|
+
[fieldFormState, selectedField]
|
|
1255
|
+
);
|
|
1256
|
+
const fieldComponents = useMemo(() => {
|
|
1257
|
+
return Object.fromEntries(
|
|
1258
|
+
customFieldExtensions.map(({ name, component }) => [name, component])
|
|
1259
|
+
);
|
|
1260
|
+
}, [customFieldExtensions]);
|
|
1261
|
+
const handleSelectionChange = useCallback(
|
|
1262
|
+
(selection) => {
|
|
1263
|
+
setSelectedField(selection);
|
|
1264
|
+
setFieldFormState({});
|
|
1265
|
+
},
|
|
1266
|
+
[setFieldFormState, setSelectedField]
|
|
1267
|
+
);
|
|
1268
|
+
const handleFieldConfigChange = useCallback(
|
|
1269
|
+
(state) => {
|
|
1270
|
+
setFieldFormState(state);
|
|
1271
|
+
setRefreshKey(Date.now());
|
|
1272
|
+
},
|
|
1273
|
+
[setFieldFormState, setRefreshKey]
|
|
1274
|
+
);
|
|
1275
|
+
return /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classes.controls }, /* @__PURE__ */ React.createElement(FormControl, { variant: "outlined", size: "small", fullWidth: true }, /* @__PURE__ */ React.createElement(InputLabel, { id: "select-field-label" }, "Choose Custom Field Extension"), /* @__PURE__ */ React.createElement(
|
|
1276
|
+
Select,
|
|
1277
|
+
{
|
|
1278
|
+
value: selectedField,
|
|
1279
|
+
label: "Choose Custom Field Extension",
|
|
1280
|
+
labelId: "select-field-label",
|
|
1281
|
+
onChange: (e) => handleSelectionChange(e.target.value)
|
|
1282
|
+
},
|
|
1283
|
+
fieldOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, { key: idx, value: option }, option.name))
|
|
1284
|
+
)), /* @__PURE__ */ React.createElement(IconButton$1, { size: "medium", onClick: onClose, "aria-label": "Close" }, /* @__PURE__ */ React.createElement(CloseIcon, null))), /* @__PURE__ */ React.createElement("div", { className: classes.fieldForm }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { title: "Field Options" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
|
|
1285
|
+
Form,
|
|
1286
|
+
{
|
|
1287
|
+
showErrorList: false,
|
|
1288
|
+
fields: { ...fieldComponents },
|
|
1289
|
+
noHtml5Validate: true,
|
|
1290
|
+
formData: fieldFormState,
|
|
1291
|
+
formContext: { fieldFormState },
|
|
1292
|
+
onSubmit: (e) => handleFieldConfigChange(e.formData),
|
|
1293
|
+
validator,
|
|
1294
|
+
schema: ((_a = selectedField.schema) == null ? void 0 : _a.uiOptions) || {},
|
|
1295
|
+
experimental_defaultFormStateBehavior: {
|
|
1296
|
+
allOf: "populateDefaults"
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
/* @__PURE__ */ React.createElement(
|
|
1300
|
+
Button$1,
|
|
1301
|
+
{
|
|
1302
|
+
variant: "contained",
|
|
1303
|
+
color: "primary",
|
|
1304
|
+
type: "submit",
|
|
1305
|
+
disabled: !((_b = selectedField.schema) == null ? void 0 : _b.uiOptions)
|
|
1306
|
+
},
|
|
1307
|
+
"Apply"
|
|
1308
|
+
)
|
|
1309
|
+
)))), /* @__PURE__ */ React.createElement("div", { className: classes.preview }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { title: "Example Template Spec" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
|
|
1310
|
+
CodeMirror,
|
|
1311
|
+
{
|
|
1312
|
+
readOnly: true,
|
|
1313
|
+
theme: "dark",
|
|
1314
|
+
height: "100%",
|
|
1315
|
+
extensions: [StreamLanguage.define(yaml$1)],
|
|
1316
|
+
value: sampleFieldTemplate
|
|
1317
|
+
}
|
|
1318
|
+
))), /* @__PURE__ */ React.createElement(
|
|
1319
|
+
TemplateEditorForm,
|
|
1320
|
+
{
|
|
1321
|
+
key: refreshKey,
|
|
1322
|
+
content: sampleFieldTemplate,
|
|
1323
|
+
contentIsSpec: true,
|
|
1324
|
+
fieldExtensions: customFieldExtensions,
|
|
1325
|
+
setErrorText: () => null
|
|
1326
|
+
}
|
|
1327
|
+
)));
|
|
1328
|
+
};
|
|
1223
1329
|
|
|
1224
|
-
const useStyles$
|
|
1330
|
+
const useStyles$b = makeStyles$1({
|
|
1225
1331
|
root: {
|
|
1226
1332
|
whiteSpace: "nowrap",
|
|
1227
1333
|
overflowY: "auto"
|
|
@@ -1280,7 +1386,7 @@ function FileTreeItem({ entry }) {
|
|
|
1280
1386
|
return /* @__PURE__ */ React.createElement(TreeItem, { nodeId: entry.path, label: entry.name }, entry.children.map((child) => /* @__PURE__ */ React.createElement(FileTreeItem, { key: child.path, entry: child })));
|
|
1281
1387
|
}
|
|
1282
1388
|
function FileBrowser(props) {
|
|
1283
|
-
const classes = useStyles$
|
|
1389
|
+
const classes = useStyles$b();
|
|
1284
1390
|
const fileTree = useMemo(
|
|
1285
1391
|
() => parseFileEntires(props.filePaths),
|
|
1286
1392
|
[props.filePaths]
|
|
@@ -1302,7 +1408,7 @@ function FileBrowser(props) {
|
|
|
1302
1408
|
);
|
|
1303
1409
|
}
|
|
1304
1410
|
|
|
1305
|
-
const useStyles$
|
|
1411
|
+
const useStyles$a = makeStyles((theme) => ({
|
|
1306
1412
|
button: {
|
|
1307
1413
|
padding: theme.spacing(1)
|
|
1308
1414
|
},
|
|
@@ -1321,7 +1427,7 @@ const useStyles$5 = makeStyles((theme) => ({
|
|
|
1321
1427
|
}));
|
|
1322
1428
|
function TemplateEditorBrowser(props) {
|
|
1323
1429
|
var _a, _b;
|
|
1324
|
-
const classes = useStyles$
|
|
1430
|
+
const classes = useStyles$a();
|
|
1325
1431
|
const directoryEditor = useDirectoryEditor();
|
|
1326
1432
|
const changedFiles = directoryEditor.files.filter((file) => file.dirty);
|
|
1327
1433
|
const handleClose = () => {
|
|
@@ -1338,22 +1444,22 @@ function TemplateEditorBrowser(props) {
|
|
|
1338
1444
|
}
|
|
1339
1445
|
props.onClose();
|
|
1340
1446
|
};
|
|
1341
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: classes.buttons }, /* @__PURE__ */ React.createElement(Tooltip
|
|
1342
|
-
IconButton,
|
|
1447
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: classes.buttons }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Save all files" }, /* @__PURE__ */ React.createElement(
|
|
1448
|
+
IconButton$1,
|
|
1343
1449
|
{
|
|
1344
1450
|
className: classes.button,
|
|
1345
1451
|
disabled: directoryEditor.files.every((file) => !file.dirty),
|
|
1346
1452
|
onClick: () => directoryEditor.save()
|
|
1347
1453
|
},
|
|
1348
1454
|
/* @__PURE__ */ React.createElement(SaveIcon, null)
|
|
1349
|
-
)), /* @__PURE__ */ React.createElement(Tooltip
|
|
1350
|
-
IconButton,
|
|
1455
|
+
)), /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload directory" }, /* @__PURE__ */ React.createElement(
|
|
1456
|
+
IconButton$1,
|
|
1351
1457
|
{
|
|
1352
1458
|
className: classes.button,
|
|
1353
1459
|
onClick: () => directoryEditor.reload()
|
|
1354
1460
|
},
|
|
1355
1461
|
/* @__PURE__ */ React.createElement(RefreshIcon, null)
|
|
1356
|
-
)), /* @__PURE__ */ React.createElement("div", { className: classes.buttonsGap }), /* @__PURE__ */ React.createElement(Tooltip
|
|
1462
|
+
)), /* @__PURE__ */ React.createElement("div", { className: classes.buttonsGap }), /* @__PURE__ */ React.createElement(Tooltip, { title: "Close directory" }, /* @__PURE__ */ React.createElement(IconButton$1, { className: classes.button, onClick: handleClose }, /* @__PURE__ */ React.createElement(CloseIcon, null)))), /* @__PURE__ */ React.createElement(Divider, { className: classes.buttonsDivider }), /* @__PURE__ */ React.createElement(
|
|
1357
1463
|
FileBrowser,
|
|
1358
1464
|
{
|
|
1359
1465
|
selected: (_b = (_a = directoryEditor.selectedFile) == null ? void 0 : _a.path) != null ? _b : "",
|
|
@@ -1363,7 +1469,7 @@ function TemplateEditorBrowser(props) {
|
|
|
1363
1469
|
));
|
|
1364
1470
|
}
|
|
1365
1471
|
|
|
1366
|
-
const useStyles$
|
|
1472
|
+
const useStyles$9 = makeStyles((theme) => ({
|
|
1367
1473
|
container: {
|
|
1368
1474
|
position: "relative",
|
|
1369
1475
|
width: "100%",
|
|
@@ -1392,7 +1498,7 @@ const useStyles$4 = makeStyles((theme) => ({
|
|
|
1392
1498
|
}));
|
|
1393
1499
|
function TemplateEditorTextArea(props) {
|
|
1394
1500
|
const { errorText } = props;
|
|
1395
|
-
const classes = useStyles$
|
|
1501
|
+
const classes = useStyles$9();
|
|
1396
1502
|
const panelExtension = useMemo(() => {
|
|
1397
1503
|
if (!errorText) {
|
|
1398
1504
|
return showPanel.of(null);
|
|
@@ -1421,8 +1527,8 @@ function TemplateEditorTextArea(props) {
|
|
|
1421
1527
|
value: props.content,
|
|
1422
1528
|
onChange: props.onUpdate
|
|
1423
1529
|
}
|
|
1424
|
-
), (props.onSave || props.onReload) && /* @__PURE__ */ React.createElement("div", { className: classes.floatingButtons }, /* @__PURE__ */ React.createElement(Paper, null, props.onSave && /* @__PURE__ */ React.createElement(Tooltip
|
|
1425
|
-
IconButton,
|
|
1530
|
+
), (props.onSave || props.onReload) && /* @__PURE__ */ React.createElement("div", { className: classes.floatingButtons }, /* @__PURE__ */ React.createElement(Paper, null, props.onSave && /* @__PURE__ */ React.createElement(Tooltip, { title: "Save file" }, /* @__PURE__ */ React.createElement(
|
|
1531
|
+
IconButton$1,
|
|
1426
1532
|
{
|
|
1427
1533
|
className: classes.floatingButton,
|
|
1428
1534
|
onClick: () => {
|
|
@@ -1431,8 +1537,8 @@ function TemplateEditorTextArea(props) {
|
|
|
1431
1537
|
}
|
|
1432
1538
|
},
|
|
1433
1539
|
/* @__PURE__ */ React.createElement(SaveIcon, null)
|
|
1434
|
-
)), props.onReload && /* @__PURE__ */ React.createElement(Tooltip
|
|
1435
|
-
IconButton,
|
|
1540
|
+
)), props.onReload && /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload file" }, /* @__PURE__ */ React.createElement(
|
|
1541
|
+
IconButton$1,
|
|
1436
1542
|
{
|
|
1437
1543
|
className: classes.floatingButton,
|
|
1438
1544
|
onClick: () => {
|
|
@@ -1476,7 +1582,7 @@ function downloadBlob(blob, name) {
|
|
|
1476
1582
|
a.remove();
|
|
1477
1583
|
}
|
|
1478
1584
|
|
|
1479
|
-
const useStyles$
|
|
1585
|
+
const useStyles$8 = makeStyles$1((theme) => ({
|
|
1480
1586
|
root: {
|
|
1481
1587
|
overflowY: "auto",
|
|
1482
1588
|
background: theme.palette.background.default
|
|
@@ -1493,7 +1599,7 @@ const useStyles$3 = makeStyles$1((theme) => ({
|
|
|
1493
1599
|
}
|
|
1494
1600
|
}));
|
|
1495
1601
|
function DryRunResultsList() {
|
|
1496
|
-
const classes = useStyles$
|
|
1602
|
+
const classes = useStyles$8();
|
|
1497
1603
|
const dryRun = useDryRun();
|
|
1498
1604
|
return /* @__PURE__ */ React.createElement(List$1, { className: classes.root, dense: true }, dryRun.results.map((result) => {
|
|
1499
1605
|
var _a;
|
|
@@ -1520,11 +1626,11 @@ function DryRunResultsList() {
|
|
|
1520
1626
|
{
|
|
1521
1627
|
className: failed ? classes.iconFailure : classes.iconSuccess
|
|
1522
1628
|
},
|
|
1523
|
-
failed ? /* @__PURE__ */ React.createElement(Cancel, null) : /* @__PURE__ */ React.createElement(
|
|
1629
|
+
failed ? /* @__PURE__ */ React.createElement(Cancel, null) : /* @__PURE__ */ React.createElement(CheckIcon, null)
|
|
1524
1630
|
),
|
|
1525
1631
|
/* @__PURE__ */ React.createElement(ListItemText$1, { primary: `Result ${result.id}` }),
|
|
1526
1632
|
/* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(
|
|
1527
|
-
IconButton
|
|
1633
|
+
IconButton,
|
|
1528
1634
|
{
|
|
1529
1635
|
edge: "end",
|
|
1530
1636
|
"aria-label": "download",
|
|
@@ -1534,7 +1640,7 @@ function DryRunResultsList() {
|
|
|
1534
1640
|
},
|
|
1535
1641
|
/* @__PURE__ */ React.createElement(DownloadIcon, null)
|
|
1536
1642
|
), /* @__PURE__ */ React.createElement(
|
|
1537
|
-
IconButton
|
|
1643
|
+
IconButton,
|
|
1538
1644
|
{
|
|
1539
1645
|
edge: "end",
|
|
1540
1646
|
"aria-label": "delete",
|
|
@@ -1556,32 +1662,195 @@ async function downloadDirectoryContents(directoryContents, name) {
|
|
|
1556
1662
|
const blob = await zip.generateAsync({ type: "blob" });
|
|
1557
1663
|
downloadBlob(blob, name);
|
|
1558
1664
|
}
|
|
1559
|
-
|
|
1560
|
-
const useStyles$
|
|
1561
|
-
root: {
|
|
1562
|
-
display: "grid",
|
|
1563
|
-
gridTemplateColumns: "280px auto 3fr",
|
|
1564
|
-
gridTemplateRows: "1fr"
|
|
1565
|
-
},
|
|
1566
|
-
child: {
|
|
1567
|
-
overflowY: "auto",
|
|
1568
|
-
height: "100%",
|
|
1569
|
-
minHeight: 0
|
|
1570
|
-
},
|
|
1571
|
-
firstChild: {
|
|
1572
|
-
background: theme.palette.background.paper
|
|
1573
|
-
}
|
|
1574
|
-
}));
|
|
1575
|
-
function DryRunResultsSplitView(props) {
|
|
1576
|
-
const classes = useStyles$
|
|
1577
|
-
const childArray = Children.toArray(props.children);
|
|
1578
|
-
if (childArray.length !== 2) {
|
|
1579
|
-
throw new Error("must have exactly 2 children");
|
|
1665
|
+
|
|
1666
|
+
const useStyles$7 = makeStyles$1((theme) => ({
|
|
1667
|
+
root: {
|
|
1668
|
+
display: "grid",
|
|
1669
|
+
gridTemplateColumns: "280px auto 3fr",
|
|
1670
|
+
gridTemplateRows: "1fr"
|
|
1671
|
+
},
|
|
1672
|
+
child: {
|
|
1673
|
+
overflowY: "auto",
|
|
1674
|
+
height: "100%",
|
|
1675
|
+
minHeight: 0
|
|
1676
|
+
},
|
|
1677
|
+
firstChild: {
|
|
1678
|
+
background: theme.palette.background.paper
|
|
1679
|
+
}
|
|
1680
|
+
}));
|
|
1681
|
+
function DryRunResultsSplitView(props) {
|
|
1682
|
+
const classes = useStyles$7();
|
|
1683
|
+
const childArray = Children.toArray(props.children);
|
|
1684
|
+
if (childArray.length !== 2) {
|
|
1685
|
+
throw new Error("must have exactly 2 children");
|
|
1686
|
+
}
|
|
1687
|
+
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classNames(classes.child, classes.firstChild) }, childArray[0]), /* @__PURE__ */ React.createElement(Divider$1, { orientation: "horizontal" }), /* @__PURE__ */ React.createElement("div", { className: classes.child }, childArray[1]));
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
const useStyles$6 = makeStyles({
|
|
1691
|
+
svgIcon: {
|
|
1692
|
+
display: "inline-block",
|
|
1693
|
+
"& svg": {
|
|
1694
|
+
display: "inline-block",
|
|
1695
|
+
fontSize: "inherit",
|
|
1696
|
+
verticalAlign: "baseline"
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
const IconLink = (props) => {
|
|
1701
|
+
const { href, text, Icon, ...linkProps } = props;
|
|
1702
|
+
const classes = useStyles$6();
|
|
1703
|
+
return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row", spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { component: "div", className: classes.svgIcon }, Icon ? /* @__PURE__ */ React.createElement(Icon, null) : /* @__PURE__ */ React.createElement(LanguageIcon, null))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Link, { to: href, ...linkProps }, text || href)));
|
|
1704
|
+
};
|
|
1705
|
+
|
|
1706
|
+
const TaskPageLinks = ({ output }) => {
|
|
1707
|
+
const { links = [] } = output;
|
|
1708
|
+
const app = useApp();
|
|
1709
|
+
const entityRoute = useRouteRef(entityRouteRef);
|
|
1710
|
+
const iconResolver = (key) => {
|
|
1711
|
+
var _a;
|
|
1712
|
+
return key ? (_a = app.getSystemIcon(key)) != null ? _a : LanguageIcon : LanguageIcon;
|
|
1713
|
+
};
|
|
1714
|
+
return /* @__PURE__ */ React.createElement(Box, { px: 3, pb: 3 }, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
|
|
1715
|
+
if (entityRef) {
|
|
1716
|
+
const entityName = parseEntityRef(entityRef, {
|
|
1717
|
+
defaultKind: "<unknown>",
|
|
1718
|
+
defaultNamespace: "<unknown>"
|
|
1719
|
+
});
|
|
1720
|
+
const target = entityRoute(entityName);
|
|
1721
|
+
return { title, icon, url: target };
|
|
1722
|
+
}
|
|
1723
|
+
return { title, icon, url };
|
|
1724
|
+
}).map(({ url, title, icon }, i) => /* @__PURE__ */ React.createElement(
|
|
1725
|
+
IconLink,
|
|
1726
|
+
{
|
|
1727
|
+
key: `output-link-${i}`,
|
|
1728
|
+
href: url,
|
|
1729
|
+
text: title != null ? title : url,
|
|
1730
|
+
Icon: iconResolver(icon),
|
|
1731
|
+
target: "_blank"
|
|
1732
|
+
}
|
|
1733
|
+
)));
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
const useStyles$5 = makeStyles(
|
|
1737
|
+
(theme) => createStyles({
|
|
1738
|
+
root: {
|
|
1739
|
+
width: "100%"
|
|
1740
|
+
},
|
|
1741
|
+
button: {
|
|
1742
|
+
marginBottom: theme.spacing(2),
|
|
1743
|
+
marginLeft: theme.spacing(2)
|
|
1744
|
+
},
|
|
1745
|
+
actionsContainer: {
|
|
1746
|
+
marginBottom: theme.spacing(2)
|
|
1747
|
+
},
|
|
1748
|
+
resetContainer: {
|
|
1749
|
+
padding: theme.spacing(3)
|
|
1750
|
+
},
|
|
1751
|
+
labelWrapper: {
|
|
1752
|
+
display: "flex",
|
|
1753
|
+
flex: 1,
|
|
1754
|
+
flexDirection: "row",
|
|
1755
|
+
justifyContent: "space-between"
|
|
1756
|
+
},
|
|
1757
|
+
stepWrapper: {
|
|
1758
|
+
width: "100%"
|
|
1759
|
+
}
|
|
1760
|
+
})
|
|
1761
|
+
);
|
|
1762
|
+
const useStepIconStyles = makeStyles(
|
|
1763
|
+
(theme) => createStyles({
|
|
1764
|
+
root: {
|
|
1765
|
+
color: theme.palette.text.disabled,
|
|
1766
|
+
display: "flex",
|
|
1767
|
+
height: 22,
|
|
1768
|
+
alignItems: "center"
|
|
1769
|
+
},
|
|
1770
|
+
completed: {
|
|
1771
|
+
color: theme.palette.status.ok
|
|
1772
|
+
},
|
|
1773
|
+
error: {
|
|
1774
|
+
color: theme.palette.status.error
|
|
1775
|
+
}
|
|
1776
|
+
})
|
|
1777
|
+
);
|
|
1778
|
+
const StepTimeTicker = ({ step }) => {
|
|
1779
|
+
const [time, setTime] = useState("");
|
|
1780
|
+
useInterval(() => {
|
|
1781
|
+
if (!step.startedAt) {
|
|
1782
|
+
setTime("");
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
const end = step.endedAt ? DateTime.fromISO(step.endedAt) : DateTime.local();
|
|
1786
|
+
const startedAt = DateTime.fromISO(step.startedAt);
|
|
1787
|
+
const formatted = Interval.fromDateTimes(startedAt, end).toDuration().valueOf();
|
|
1788
|
+
setTime(humanizeDuration(formatted, { round: true }));
|
|
1789
|
+
}, 1e3);
|
|
1790
|
+
return /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, time);
|
|
1791
|
+
};
|
|
1792
|
+
function TaskStepIconComponent(props) {
|
|
1793
|
+
const classes = useStepIconStyles();
|
|
1794
|
+
const { active, completed, error } = props;
|
|
1795
|
+
const getMiddle = () => {
|
|
1796
|
+
if (active) {
|
|
1797
|
+
return /* @__PURE__ */ React.createElement(CircularProgress, { size: "24px" });
|
|
1798
|
+
}
|
|
1799
|
+
if (completed) {
|
|
1800
|
+
return /* @__PURE__ */ React.createElement(CheckIcon, null);
|
|
1801
|
+
}
|
|
1802
|
+
if (error) {
|
|
1803
|
+
return /* @__PURE__ */ React.createElement(Cancel, null);
|
|
1804
|
+
}
|
|
1805
|
+
return /* @__PURE__ */ React.createElement(FiberManualRecordIcon, null);
|
|
1806
|
+
};
|
|
1807
|
+
return /* @__PURE__ */ React.createElement(
|
|
1808
|
+
"div",
|
|
1809
|
+
{
|
|
1810
|
+
className: classNames(classes.root, {
|
|
1811
|
+
[classes.completed]: completed,
|
|
1812
|
+
[classes.error]: error
|
|
1813
|
+
})
|
|
1814
|
+
},
|
|
1815
|
+
getMiddle()
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
const TaskStatusStepper = memo(
|
|
1819
|
+
(props) => {
|
|
1820
|
+
const { steps, currentStepId, onUserStepChange } = props;
|
|
1821
|
+
const classes = useStyles$5(props);
|
|
1822
|
+
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(
|
|
1823
|
+
Stepper$1,
|
|
1824
|
+
{
|
|
1825
|
+
activeStep: steps.findIndex((s) => s.id === currentStepId),
|
|
1826
|
+
orientation: "vertical",
|
|
1827
|
+
nonLinear: true
|
|
1828
|
+
},
|
|
1829
|
+
steps.map((step, index) => {
|
|
1830
|
+
const isCancelled = step.status === "cancelled";
|
|
1831
|
+
const isActive = step.status === "processing";
|
|
1832
|
+
const isCompleted = step.status === "completed";
|
|
1833
|
+
const isFailed = step.status === "failed";
|
|
1834
|
+
const isSkipped = step.status === "skipped";
|
|
1835
|
+
return /* @__PURE__ */ React.createElement(Step, { key: String(index), expanded: true }, /* @__PURE__ */ React.createElement(StepButton, { onClick: () => onUserStepChange(step.id) }, /* @__PURE__ */ React.createElement(
|
|
1836
|
+
StepLabel,
|
|
1837
|
+
{
|
|
1838
|
+
StepIconProps: {
|
|
1839
|
+
completed: isCompleted,
|
|
1840
|
+
error: isFailed || isCancelled,
|
|
1841
|
+
active: isActive
|
|
1842
|
+
},
|
|
1843
|
+
StepIconComponent: TaskStepIconComponent,
|
|
1844
|
+
className: classes.stepWrapper
|
|
1845
|
+
},
|
|
1846
|
+
/* @__PURE__ */ React.createElement("div", { className: classes.labelWrapper }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "subtitle2" }, step.name), isSkipped ? /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, "Skipped") : /* @__PURE__ */ React.createElement(StepTimeTicker, { step }))
|
|
1847
|
+
)));
|
|
1848
|
+
})
|
|
1849
|
+
));
|
|
1580
1850
|
}
|
|
1581
|
-
|
|
1582
|
-
}
|
|
1851
|
+
);
|
|
1583
1852
|
|
|
1584
|
-
const useStyles$
|
|
1853
|
+
const useStyles$4 = makeStyles$1({
|
|
1585
1854
|
root: {
|
|
1586
1855
|
display: "flex",
|
|
1587
1856
|
flexFlow: "column nowrap"
|
|
@@ -1607,7 +1876,7 @@ const useStyles$1 = makeStyles$1({
|
|
|
1607
1876
|
}
|
|
1608
1877
|
});
|
|
1609
1878
|
function FilesContent() {
|
|
1610
|
-
const classes = useStyles$
|
|
1879
|
+
const classes = useStyles$4();
|
|
1611
1880
|
const { selectedResult } = useDryRun();
|
|
1612
1881
|
const [selectedPath, setSelectedPath] = useState("");
|
|
1613
1882
|
const selectedFile = selectedResult == null ? void 0 : selectedResult.directoryContents.find(
|
|
@@ -1683,7 +1952,7 @@ function LogContent() {
|
|
|
1683
1952
|
}
|
|
1684
1953
|
function OutputContent() {
|
|
1685
1954
|
var _a, _b;
|
|
1686
|
-
const classes = useStyles$
|
|
1955
|
+
const classes = useStyles$4();
|
|
1687
1956
|
const { selectedResult } = useDryRun();
|
|
1688
1957
|
if (!selectedResult) {
|
|
1689
1958
|
return null;
|
|
@@ -1701,14 +1970,14 @@ function OutputContent() {
|
|
|
1701
1970
|
));
|
|
1702
1971
|
}
|
|
1703
1972
|
function DryRunResultsView() {
|
|
1704
|
-
const classes = useStyles$
|
|
1973
|
+
const classes = useStyles$4();
|
|
1705
1974
|
const [selectedTab, setSelectedTab] = useState(
|
|
1706
1975
|
"files"
|
|
1707
1976
|
);
|
|
1708
1977
|
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Tabs, { value: selectedTab, onChange: (_, v) => setSelectedTab(v) }, /* @__PURE__ */ React.createElement(Tab, { value: "files", label: "Files" }), /* @__PURE__ */ React.createElement(Tab, { value: "log", label: "Log" }), /* @__PURE__ */ React.createElement(Tab, { value: "output", label: "Output" })), /* @__PURE__ */ React.createElement(Divider$1, null), /* @__PURE__ */ React.createElement("div", { className: classes.contentWrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.content }, selectedTab === "files" && /* @__PURE__ */ React.createElement(FilesContent, null), selectedTab === "log" && /* @__PURE__ */ React.createElement(LogContent, null), selectedTab === "output" && /* @__PURE__ */ React.createElement(OutputContent, null))));
|
|
1709
1978
|
}
|
|
1710
1979
|
|
|
1711
|
-
const useStyles = makeStyles$1((theme) => ({
|
|
1980
|
+
const useStyles$3 = makeStyles$1((theme) => ({
|
|
1712
1981
|
header: {
|
|
1713
1982
|
height: 48,
|
|
1714
1983
|
minHeight: 0,
|
|
@@ -1727,7 +1996,7 @@ const useStyles = makeStyles$1((theme) => ({
|
|
|
1727
1996
|
}
|
|
1728
1997
|
}));
|
|
1729
1998
|
function DryRunResults() {
|
|
1730
|
-
const classes = useStyles();
|
|
1999
|
+
const classes = useStyles$3();
|
|
1731
2000
|
const dryRun = useDryRun();
|
|
1732
2001
|
const [expanded, setExpanded] = useState(false);
|
|
1733
2002
|
const [hidden, setHidden] = useState(true);
|
|
@@ -1763,5 +2032,416 @@ function DryRunResults() {
|
|
|
1763
2032
|
));
|
|
1764
2033
|
}
|
|
1765
2034
|
|
|
1766
|
-
|
|
1767
|
-
|
|
2035
|
+
const useStyles$2 = makeStyles({
|
|
2036
|
+
// Reset and fix sizing to make sure scrolling behaves correctly
|
|
2037
|
+
root: {
|
|
2038
|
+
gridArea: "pageContent",
|
|
2039
|
+
display: "grid",
|
|
2040
|
+
gridTemplateAreas: `
|
|
2041
|
+
"browser editor preview"
|
|
2042
|
+
"results results results"
|
|
2043
|
+
`,
|
|
2044
|
+
gridTemplateColumns: "1fr 3fr 2fr",
|
|
2045
|
+
gridTemplateRows: "1fr auto"
|
|
2046
|
+
},
|
|
2047
|
+
browser: {
|
|
2048
|
+
gridArea: "browser",
|
|
2049
|
+
overflow: "auto"
|
|
2050
|
+
},
|
|
2051
|
+
editor: {
|
|
2052
|
+
gridArea: "editor",
|
|
2053
|
+
overflow: "auto"
|
|
2054
|
+
},
|
|
2055
|
+
preview: {
|
|
2056
|
+
gridArea: "preview",
|
|
2057
|
+
overflow: "auto"
|
|
2058
|
+
},
|
|
2059
|
+
results: {
|
|
2060
|
+
gridArea: "results"
|
|
2061
|
+
}
|
|
2062
|
+
});
|
|
2063
|
+
const TemplateEditor = (props) => {
|
|
2064
|
+
const classes = useStyles$2();
|
|
2065
|
+
const [errorText, setErrorText] = useState();
|
|
2066
|
+
return /* @__PURE__ */ React.createElement(DirectoryEditorProvider, { directory: props.directory }, /* @__PURE__ */ React.createElement(DryRunProvider, null, /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("section", { className: classes.browser }, /* @__PURE__ */ React.createElement(TemplateEditorBrowser, { onClose: props.onClose })), /* @__PURE__ */ React.createElement("section", { className: classes.editor }, /* @__PURE__ */ React.createElement(TemplateEditorTextArea.DirectoryEditor, { errorText })), /* @__PURE__ */ React.createElement("section", { className: classes.preview }, /* @__PURE__ */ React.createElement(
|
|
2067
|
+
TemplateEditorForm.DirectoryEditorDryRun,
|
|
2068
|
+
{
|
|
2069
|
+
setErrorText,
|
|
2070
|
+
fieldExtensions: props.fieldExtensions,
|
|
2071
|
+
layouts: props.layouts
|
|
2072
|
+
}
|
|
2073
|
+
)), /* @__PURE__ */ React.createElement("section", { className: classes.results }, /* @__PURE__ */ React.createElement(DryRunResults, null)))));
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI
|
|
2077
|
+
parameters:
|
|
2078
|
+
- title: Fill in some steps
|
|
2079
|
+
required:
|
|
2080
|
+
- name
|
|
2081
|
+
properties:
|
|
2082
|
+
name:
|
|
2083
|
+
title: Name
|
|
2084
|
+
type: string
|
|
2085
|
+
description: Unique name of the component
|
|
2086
|
+
owner:
|
|
2087
|
+
title: Owner
|
|
2088
|
+
type: string
|
|
2089
|
+
description: Owner of the component
|
|
2090
|
+
ui:field: OwnerPicker
|
|
2091
|
+
ui:options:
|
|
2092
|
+
catalogFilter:
|
|
2093
|
+
kind: Group
|
|
2094
|
+
- title: Choose a location
|
|
2095
|
+
required:
|
|
2096
|
+
- repoUrl
|
|
2097
|
+
properties:
|
|
2098
|
+
repoUrl:
|
|
2099
|
+
title: Repository Location
|
|
2100
|
+
type: string
|
|
2101
|
+
ui:field: RepoUrlPicker
|
|
2102
|
+
ui:options:
|
|
2103
|
+
allowedHosts:
|
|
2104
|
+
- github.com
|
|
2105
|
+
steps:
|
|
2106
|
+
- id: fetch-base
|
|
2107
|
+
name: Fetch Base
|
|
2108
|
+
action: fetch:template
|
|
2109
|
+
input:
|
|
2110
|
+
url: ./template
|
|
2111
|
+
values:
|
|
2112
|
+
name: \${{parameters.name}}
|
|
2113
|
+
`;
|
|
2114
|
+
const useStyles$1 = makeStyles((theme) => ({
|
|
2115
|
+
root: {
|
|
2116
|
+
gridArea: "pageContent",
|
|
2117
|
+
display: "grid",
|
|
2118
|
+
gridTemplateAreas: `
|
|
2119
|
+
"controls controls"
|
|
2120
|
+
"textArea preview"
|
|
2121
|
+
`,
|
|
2122
|
+
gridTemplateRows: "auto 1fr",
|
|
2123
|
+
gridTemplateColumns: "1fr 1fr"
|
|
2124
|
+
},
|
|
2125
|
+
controls: {
|
|
2126
|
+
gridArea: "controls",
|
|
2127
|
+
display: "flex",
|
|
2128
|
+
flexFlow: "row nowrap",
|
|
2129
|
+
alignItems: "center",
|
|
2130
|
+
margin: theme.spacing(1)
|
|
2131
|
+
},
|
|
2132
|
+
textArea: {
|
|
2133
|
+
gridArea: "textArea"
|
|
2134
|
+
},
|
|
2135
|
+
preview: {
|
|
2136
|
+
gridArea: "preview"
|
|
2137
|
+
}
|
|
2138
|
+
}));
|
|
2139
|
+
const TemplateFormPreviewer = ({
|
|
2140
|
+
defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,
|
|
2141
|
+
customFieldExtensions = [],
|
|
2142
|
+
onClose,
|
|
2143
|
+
layouts = []
|
|
2144
|
+
}) => {
|
|
2145
|
+
const classes = useStyles$1();
|
|
2146
|
+
const alertApi = useApi(alertApiRef);
|
|
2147
|
+
const catalogApi = useApi(catalogApiRef);
|
|
2148
|
+
const [selectedTemplate, setSelectedTemplate] = useState("");
|
|
2149
|
+
const [errorText, setErrorText] = useState();
|
|
2150
|
+
const [templateOptions, setTemplateOptions] = useState([]);
|
|
2151
|
+
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
2152
|
+
const { loading } = useAsync(
|
|
2153
|
+
() => catalogApi.getEntities({
|
|
2154
|
+
filter: { kind: "template" },
|
|
2155
|
+
fields: [
|
|
2156
|
+
"kind",
|
|
2157
|
+
"metadata.namespace",
|
|
2158
|
+
"metadata.name",
|
|
2159
|
+
"metadata.title",
|
|
2160
|
+
"spec.parameters",
|
|
2161
|
+
"spec.steps",
|
|
2162
|
+
"spec.output"
|
|
2163
|
+
]
|
|
2164
|
+
}).then(
|
|
2165
|
+
({ items }) => setTemplateOptions(
|
|
2166
|
+
items.map((template) => {
|
|
2167
|
+
var _a;
|
|
2168
|
+
return {
|
|
2169
|
+
label: (_a = template.metadata.title) != null ? _a : humanizeEntityRef(template, { defaultKind: "template" }),
|
|
2170
|
+
value: template
|
|
2171
|
+
};
|
|
2172
|
+
})
|
|
2173
|
+
)
|
|
2174
|
+
).catch(
|
|
2175
|
+
(e) => alertApi.post({
|
|
2176
|
+
message: `Error loading exisiting templates: ${e.message}`,
|
|
2177
|
+
severity: "error"
|
|
2178
|
+
})
|
|
2179
|
+
),
|
|
2180
|
+
[catalogApi]
|
|
2181
|
+
);
|
|
2182
|
+
const handleSelectChange = useCallback(
|
|
2183
|
+
// TODO(Rugvip): Afaik this should be Entity, but didn't want to make runtime changes while fixing types
|
|
2184
|
+
(selected) => {
|
|
2185
|
+
setSelectedTemplate(selected);
|
|
2186
|
+
setTemplateYaml(yaml.stringify(selected.spec));
|
|
2187
|
+
},
|
|
2188
|
+
[setTemplateYaml]
|
|
2189
|
+
);
|
|
2190
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classes.controls }, /* @__PURE__ */ React.createElement(FormControl, { variant: "outlined", size: "small", fullWidth: true }, /* @__PURE__ */ React.createElement(InputLabel, { id: "select-template-label" }, "Load Existing Template"), /* @__PURE__ */ React.createElement(
|
|
2191
|
+
Select,
|
|
2192
|
+
{
|
|
2193
|
+
value: selectedTemplate,
|
|
2194
|
+
label: "Load Existing Template",
|
|
2195
|
+
labelId: "select-template-label",
|
|
2196
|
+
onChange: (e) => handleSelectChange(e.target.value)
|
|
2197
|
+
},
|
|
2198
|
+
templateOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, { key: idx, value: option.value }, option.label))
|
|
2199
|
+
)), /* @__PURE__ */ React.createElement(IconButton$1, { size: "medium", onClick: onClose }, /* @__PURE__ */ React.createElement(CloseIcon, null))), /* @__PURE__ */ React.createElement("div", { className: classes.textArea }, /* @__PURE__ */ React.createElement(
|
|
2200
|
+
TemplateEditorTextArea,
|
|
2201
|
+
{
|
|
2202
|
+
content: templateYaml,
|
|
2203
|
+
onUpdate: setTemplateYaml,
|
|
2204
|
+
errorText
|
|
2205
|
+
}
|
|
2206
|
+
)), /* @__PURE__ */ React.createElement("div", { className: classes.preview }, /* @__PURE__ */ React.createElement(
|
|
2207
|
+
TemplateEditorForm,
|
|
2208
|
+
{
|
|
2209
|
+
content: templateYaml,
|
|
2210
|
+
contentIsSpec: true,
|
|
2211
|
+
fieldExtensions: customFieldExtensions,
|
|
2212
|
+
setErrorText,
|
|
2213
|
+
layouts
|
|
2214
|
+
}
|
|
2215
|
+
))));
|
|
2216
|
+
};
|
|
2217
|
+
|
|
2218
|
+
const useStyles = makeStyles$1((theme) => ({
|
|
2219
|
+
introText: {
|
|
2220
|
+
textAlign: "center",
|
|
2221
|
+
marginTop: theme.spacing(2)
|
|
2222
|
+
},
|
|
2223
|
+
card: {
|
|
2224
|
+
position: "relative",
|
|
2225
|
+
maxWidth: 340,
|
|
2226
|
+
marginTop: theme.spacing(4),
|
|
2227
|
+
margin: theme.spacing(0, 2)
|
|
2228
|
+
},
|
|
2229
|
+
infoIcon: {
|
|
2230
|
+
position: "absolute",
|
|
2231
|
+
top: theme.spacing(1),
|
|
2232
|
+
right: theme.spacing(1)
|
|
2233
|
+
}
|
|
2234
|
+
}));
|
|
2235
|
+
function TemplateEditorIntro(props) {
|
|
2236
|
+
const classes = useStyles();
|
|
2237
|
+
const supportsLoad = WebFileSystemAccess.isSupported();
|
|
2238
|
+
const cardLoadLocal = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(
|
|
2239
|
+
CardActionArea,
|
|
2240
|
+
{
|
|
2241
|
+
disabled: !supportsLoad,
|
|
2242
|
+
onClick: () => {
|
|
2243
|
+
var _a;
|
|
2244
|
+
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "local");
|
|
2245
|
+
}
|
|
2246
|
+
},
|
|
2247
|
+
/* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(
|
|
2248
|
+
Typography$1,
|
|
2249
|
+
{
|
|
2250
|
+
variant: "h4",
|
|
2251
|
+
component: "h3",
|
|
2252
|
+
gutterBottom: true,
|
|
2253
|
+
color: supportsLoad ? void 0 : "textSecondary",
|
|
2254
|
+
style: { display: "flex", flexFlow: "row nowrap" }
|
|
2255
|
+
},
|
|
2256
|
+
"Load Template Directory"
|
|
2257
|
+
), /* @__PURE__ */ React.createElement(
|
|
2258
|
+
Typography$1,
|
|
2259
|
+
{
|
|
2260
|
+
variant: "body1",
|
|
2261
|
+
color: supportsLoad ? void 0 : "textSecondary"
|
|
2262
|
+
},
|
|
2263
|
+
"Load a local template directory, allowing you to both edit and try executing your own template."
|
|
2264
|
+
))
|
|
2265
|
+
), !supportsLoad && /* @__PURE__ */ React.createElement("div", { className: classes.infoIcon }, /* @__PURE__ */ React.createElement(
|
|
2266
|
+
Tooltip$1,
|
|
2267
|
+
{
|
|
2268
|
+
placement: "top",
|
|
2269
|
+
title: "Only supported in some Chromium-based browsers"
|
|
2270
|
+
},
|
|
2271
|
+
/* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
|
|
2272
|
+
)));
|
|
2273
|
+
const cardFormEditor = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
2274
|
+
var _a;
|
|
2275
|
+
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
|
|
2276
|
+
} }, /* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h3", gutterBottom: true }, "Edit Template Form"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "Preview and edit a template form, either using a sample template or by loading a template from the catalog."))));
|
|
2277
|
+
const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
2278
|
+
var _a;
|
|
2279
|
+
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
|
|
2280
|
+
} }, /* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h3", gutterBottom: true }, "Custom Field Explorer"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "View and play around with available installed custom field extensions."))));
|
|
2281
|
+
return /* @__PURE__ */ React.createElement("div", { style: props.style }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h4", component: "h2", className: classes.introText }, "Get started by choosing one of the options below"), /* @__PURE__ */ React.createElement(
|
|
2282
|
+
"div",
|
|
2283
|
+
{
|
|
2284
|
+
style: {
|
|
2285
|
+
display: "flex",
|
|
2286
|
+
flexFlow: "row wrap",
|
|
2287
|
+
alignItems: "flex-start",
|
|
2288
|
+
justifyContent: "center",
|
|
2289
|
+
alignContent: "flex-start"
|
|
2290
|
+
}
|
|
2291
|
+
},
|
|
2292
|
+
supportsLoad && cardLoadLocal,
|
|
2293
|
+
cardFormEditor,
|
|
2294
|
+
!supportsLoad && cardLoadLocal,
|
|
2295
|
+
cardFieldExplorer
|
|
2296
|
+
));
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
function TemplateEditorPage(props) {
|
|
2300
|
+
const [selection, setSelection] = useState();
|
|
2301
|
+
let content = null;
|
|
2302
|
+
if ((selection == null ? void 0 : selection.type) === "local") {
|
|
2303
|
+
content = /* @__PURE__ */ React.createElement(
|
|
2304
|
+
TemplateEditor,
|
|
2305
|
+
{
|
|
2306
|
+
directory: selection.directory,
|
|
2307
|
+
fieldExtensions: props.customFieldExtensions,
|
|
2308
|
+
onClose: () => setSelection(void 0),
|
|
2309
|
+
layouts: props.layouts
|
|
2310
|
+
}
|
|
2311
|
+
);
|
|
2312
|
+
} else if ((selection == null ? void 0 : selection.type) === "form") {
|
|
2313
|
+
content = /* @__PURE__ */ React.createElement(
|
|
2314
|
+
TemplateFormPreviewer,
|
|
2315
|
+
{
|
|
2316
|
+
defaultPreviewTemplate: props.defaultPreviewTemplate,
|
|
2317
|
+
customFieldExtensions: props.customFieldExtensions,
|
|
2318
|
+
onClose: () => setSelection(void 0),
|
|
2319
|
+
layouts: props.layouts
|
|
2320
|
+
}
|
|
2321
|
+
);
|
|
2322
|
+
} else if ((selection == null ? void 0 : selection.type) === "field-explorer") {
|
|
2323
|
+
content = /* @__PURE__ */ React.createElement(
|
|
2324
|
+
CustomFieldExplorer,
|
|
2325
|
+
{
|
|
2326
|
+
customFieldExtensions: props.customFieldExtensions,
|
|
2327
|
+
onClose: () => setSelection(void 0)
|
|
2328
|
+
}
|
|
2329
|
+
);
|
|
2330
|
+
} else {
|
|
2331
|
+
content = /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(
|
|
2332
|
+
TemplateEditorIntro,
|
|
2333
|
+
{
|
|
2334
|
+
onSelect: (option) => {
|
|
2335
|
+
if (option === "local") {
|
|
2336
|
+
WebFileSystemAccess.requestDirectoryAccess().then((directory) => setSelection({ type: "local", directory })).catch(() => {
|
|
2337
|
+
});
|
|
2338
|
+
} else if (option === "form") {
|
|
2339
|
+
setSelection({ type: "form" });
|
|
2340
|
+
} else if (option === "field-explorer") {
|
|
2341
|
+
setSelection({ type: "field-explorer" });
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
));
|
|
2346
|
+
}
|
|
2347
|
+
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
2348
|
+
Header,
|
|
2349
|
+
{
|
|
2350
|
+
title: "Template Editor",
|
|
2351
|
+
subtitle: "Edit, preview, and try out templates and template forms"
|
|
2352
|
+
}
|
|
2353
|
+
), content);
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
const Router = (props) => {
|
|
2357
|
+
const {
|
|
2358
|
+
components: {
|
|
2359
|
+
TemplateCardComponent,
|
|
2360
|
+
TaskPageComponent = OngoingTask,
|
|
2361
|
+
ReviewStepComponent,
|
|
2362
|
+
EXPERIMENTAL_TemplateOutputsComponent: TemplateOutputsComponent,
|
|
2363
|
+
EXPERIMENTAL_TemplateListPageComponent: TemplateListPageComponent = TemplateListPage,
|
|
2364
|
+
EXPERIMENTAL_TemplateWizardPageComponent: TemplateWizardPageComponent = TemplateWizardPage
|
|
2365
|
+
} = {}
|
|
2366
|
+
} = props;
|
|
2367
|
+
const outlet = useOutlet() || props.children;
|
|
2368
|
+
const customFieldExtensions = useCustomFieldExtensions(outlet);
|
|
2369
|
+
const fieldExtensions = [
|
|
2370
|
+
...customFieldExtensions,
|
|
2371
|
+
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(
|
|
2372
|
+
({ name }) => !customFieldExtensions.some(
|
|
2373
|
+
(customFieldExtension) => customFieldExtension.name === name
|
|
2374
|
+
)
|
|
2375
|
+
)
|
|
2376
|
+
];
|
|
2377
|
+
const customLayouts = useCustomLayouts(outlet);
|
|
2378
|
+
return /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(
|
|
2379
|
+
Route,
|
|
2380
|
+
{
|
|
2381
|
+
path: "/",
|
|
2382
|
+
element: /* @__PURE__ */ React.createElement(
|
|
2383
|
+
TemplateListPageComponent,
|
|
2384
|
+
{
|
|
2385
|
+
TemplateCardComponent,
|
|
2386
|
+
contextMenu: props.contextMenu,
|
|
2387
|
+
groups: props.groups,
|
|
2388
|
+
templateFilter: props.templateFilter,
|
|
2389
|
+
headerOptions: props.headerOptions
|
|
2390
|
+
}
|
|
2391
|
+
)
|
|
2392
|
+
}
|
|
2393
|
+
), /* @__PURE__ */ React.createElement(
|
|
2394
|
+
Route,
|
|
2395
|
+
{
|
|
2396
|
+
path: selectedTemplateRouteRef.path,
|
|
2397
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(
|
|
2398
|
+
TemplateWizardPageComponent,
|
|
2399
|
+
{
|
|
2400
|
+
headerOptions: props.headerOptions,
|
|
2401
|
+
customFieldExtensions: fieldExtensions,
|
|
2402
|
+
layouts: customLayouts,
|
|
2403
|
+
components: { ReviewStepComponent },
|
|
2404
|
+
formProps: props.formProps
|
|
2405
|
+
}
|
|
2406
|
+
))
|
|
2407
|
+
}
|
|
2408
|
+
), /* @__PURE__ */ React.createElement(
|
|
2409
|
+
Route,
|
|
2410
|
+
{
|
|
2411
|
+
path: scaffolderTaskRouteRef.path,
|
|
2412
|
+
element: /* @__PURE__ */ React.createElement(
|
|
2413
|
+
TaskPageComponent,
|
|
2414
|
+
{
|
|
2415
|
+
TemplateOutputsComponent
|
|
2416
|
+
}
|
|
2417
|
+
)
|
|
2418
|
+
}
|
|
2419
|
+
), /* @__PURE__ */ React.createElement(
|
|
2420
|
+
Route,
|
|
2421
|
+
{
|
|
2422
|
+
path: editRouteRef.path,
|
|
2423
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(
|
|
2424
|
+
TemplateEditorPage,
|
|
2425
|
+
{
|
|
2426
|
+
customFieldExtensions: fieldExtensions,
|
|
2427
|
+
layouts: customLayouts
|
|
2428
|
+
}
|
|
2429
|
+
))
|
|
2430
|
+
}
|
|
2431
|
+
), /* @__PURE__ */ React.createElement(Route, { path: actionsRouteRef.path, element: /* @__PURE__ */ React.createElement(ActionsPage, null) }), /* @__PURE__ */ React.createElement(
|
|
2432
|
+
Route,
|
|
2433
|
+
{
|
|
2434
|
+
path: scaffolderListTaskRouteRef.path,
|
|
2435
|
+
element: /* @__PURE__ */ React.createElement(ListTasksPage, null)
|
|
2436
|
+
}
|
|
2437
|
+
), /* @__PURE__ */ React.createElement(
|
|
2438
|
+
Route,
|
|
2439
|
+
{
|
|
2440
|
+
path: "*",
|
|
2441
|
+
element: /* @__PURE__ */ React.createElement(ErrorPage, { status: "404", statusMessage: "Page not found" })
|
|
2442
|
+
}
|
|
2443
|
+
));
|
|
2444
|
+
};
|
|
2445
|
+
|
|
2446
|
+
export { Router };
|
|
2447
|
+
//# sourceMappingURL=index-445b4718.esm.js.map
|