@backstage/plugin-scaffolder 1.2.0 → 1.3.0-next.2
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 +66 -0
- package/alpha/package.json +1 -1
- package/dist/esm/Router-09b6a7c3.esm.js +2380 -0
- package/dist/esm/Router-09b6a7c3.esm.js.map +1 -0
- package/dist/esm/{default-67a72a06.esm.js → default-554cb9ad.esm.js} +2 -2
- package/dist/esm/{default-67a72a06.esm.js.map → default-554cb9ad.esm.js.map} +1 -1
- package/dist/esm/{index-6a9fc0c0.esm.js → index-b64713a1.esm.js} +95 -14
- package/dist/esm/index-b64713a1.esm.js.map +1 -0
- package/dist/esm/{index-d5c1fdb0.esm.js → index-f46ffb89.esm.js} +3 -3
- package/dist/esm/{index-d5c1fdb0.esm.js.map → index-f46ffb89.esm.js.map} +1 -1
- package/dist/index.alpha.d.ts +40 -0
- package/dist/index.beta.d.ts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.esm.js +1 -1
- package/package.json +20 -18
- package/dist/esm/Router-b7921312.esm.js +0 -1013
- package/dist/esm/Router-b7921312.esm.js.map +0 -1
- package/dist/esm/index-6a9fc0c0.esm.js.map +0 -1
|
@@ -1,1013 +0,0 @@
|
|
|
1
|
-
import React, { useState, useContext, useCallback } from 'react';
|
|
2
|
-
import { useNavigate, Navigate, useOutlet, Routes, Route } from 'react-router';
|
|
3
|
-
import { ItemCardHeader, MarkdownContent, Button, ContentHeader, Progress, WarningPanel, Link as Link$1, Content, ItemCardGrid, Page, Header, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage } from '@backstage/core-components';
|
|
4
|
-
import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, alertApiRef, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
|
-
import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, catalogApiRef, humanizeEntityRef } from '@backstage/plugin-catalog-react';
|
|
6
|
-
import { s as selectedTemplateRouteRef, r as rootRouteRef, a as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, b as scaffolderApiRef, c as scaffolderTaskRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, d as FIELD_EXTENSION_KEY, e as SecretsContextProvider, f as actionsRouteRef, g as editRouteRef, h as TaskPage } from './index-6a9fc0c0.esm.js';
|
|
7
|
-
import { RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
|
|
8
|
-
import { makeStyles, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, IconButton, Tooltip, Link, Stepper, Step, StepLabel, StepContent, Button as Button$1, Paper, LinearProgress, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Grid, FormControl, InputLabel, Select, MenuItem as MenuItem$1 } from '@material-ui/core';
|
|
9
|
-
import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
10
|
-
import WarningIcon from '@material-ui/icons/Warning';
|
|
11
|
-
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
|
|
12
|
-
import { usePermission } from '@backstage/plugin-permission-react';
|
|
13
|
-
import IconButton$1 from '@material-ui/core/IconButton';
|
|
14
|
-
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|
15
|
-
import ListItemText from '@material-ui/core/ListItemText';
|
|
16
|
-
import MenuItem from '@material-ui/core/MenuItem';
|
|
17
|
-
import MenuList from '@material-ui/core/MenuList';
|
|
18
|
-
import Popover from '@material-ui/core/Popover';
|
|
19
|
-
import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
|
|
20
|
-
import Description from '@material-ui/icons/Description';
|
|
21
|
-
import Edit from '@material-ui/icons/Edit';
|
|
22
|
-
import MoreVert from '@material-ui/icons/MoreVert';
|
|
23
|
-
import qs from 'qs';
|
|
24
|
-
import { useParams } from 'react-router-dom';
|
|
25
|
-
import useAsync from 'react-use/lib/useAsync';
|
|
26
|
-
import { withTheme } from '@rjsf/core';
|
|
27
|
-
import { Theme } from '@rjsf/material-ui';
|
|
28
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
29
|
-
import classNames from 'classnames';
|
|
30
|
-
import useDebounce from 'react-use/lib/useDebounce';
|
|
31
|
-
import { yaml as yaml$1 } from '@codemirror/legacy-modes/mode/yaml';
|
|
32
|
-
import { showPanel } from '@codemirror/view';
|
|
33
|
-
import { StreamLanguage } from '@codemirror/language';
|
|
34
|
-
import CodeMirror from '@uiw/react-codemirror';
|
|
35
|
-
import yaml from 'yaml';
|
|
36
|
-
import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-67a72a06.esm.js';
|
|
37
|
-
import '@backstage/errors';
|
|
38
|
-
import 'zen-observable';
|
|
39
|
-
import '@material-ui/core/FormControl';
|
|
40
|
-
import '@material-ui/lab/Autocomplete';
|
|
41
|
-
import 'react-use/lib/useEffectOnce';
|
|
42
|
-
import '@material-ui/lab';
|
|
43
|
-
import '@material-ui/core/FormHelperText';
|
|
44
|
-
import '@material-ui/core/Input';
|
|
45
|
-
import '@material-ui/core/InputLabel';
|
|
46
|
-
import 'lodash/capitalize';
|
|
47
|
-
import '@material-ui/icons/CheckBox';
|
|
48
|
-
import '@material-ui/icons/CheckBoxOutlineBlank';
|
|
49
|
-
import '@material-ui/icons/ExpandMore';
|
|
50
|
-
import '@material-ui/core/Grid';
|
|
51
|
-
import '@material-ui/core/Step';
|
|
52
|
-
import '@material-ui/core/StepLabel';
|
|
53
|
-
import '@material-ui/core/Stepper';
|
|
54
|
-
import '@material-ui/core/Typography';
|
|
55
|
-
import '@material-ui/icons/Cancel';
|
|
56
|
-
import '@material-ui/icons/Check';
|
|
57
|
-
import '@material-ui/icons/FiberManualRecord';
|
|
58
|
-
import 'luxon';
|
|
59
|
-
import 'react-use/lib/useInterval';
|
|
60
|
-
import 'use-immer';
|
|
61
|
-
import '@material-ui/icons/Language';
|
|
62
|
-
|
|
63
|
-
const useStyles$3 = makeStyles((theme) => ({
|
|
64
|
-
cardHeader: {
|
|
65
|
-
position: "relative"
|
|
66
|
-
},
|
|
67
|
-
title: {
|
|
68
|
-
backgroundImage: ({ backgroundImage }) => backgroundImage
|
|
69
|
-
},
|
|
70
|
-
box: {
|
|
71
|
-
overflow: "hidden",
|
|
72
|
-
textOverflow: "ellipsis",
|
|
73
|
-
display: "-webkit-box",
|
|
74
|
-
"-webkit-line-clamp": 10,
|
|
75
|
-
"-webkit-box-orient": "vertical",
|
|
76
|
-
paddingBottom: "0.8em"
|
|
77
|
-
},
|
|
78
|
-
label: {
|
|
79
|
-
color: theme.palette.text.secondary,
|
|
80
|
-
textTransform: "uppercase",
|
|
81
|
-
fontSize: "0.65rem",
|
|
82
|
-
fontWeight: "bold",
|
|
83
|
-
letterSpacing: 0.5,
|
|
84
|
-
lineHeight: 1,
|
|
85
|
-
paddingBottom: "0.2rem"
|
|
86
|
-
},
|
|
87
|
-
leftButton: {
|
|
88
|
-
marginRight: "auto"
|
|
89
|
-
},
|
|
90
|
-
starButton: {
|
|
91
|
-
position: "absolute",
|
|
92
|
-
top: theme.spacing(0.5),
|
|
93
|
-
right: theme.spacing(0.5),
|
|
94
|
-
padding: "0.25rem",
|
|
95
|
-
color: "#fff"
|
|
96
|
-
}
|
|
97
|
-
}));
|
|
98
|
-
const useDeprecationStyles = makeStyles((theme) => ({
|
|
99
|
-
deprecationIcon: {
|
|
100
|
-
position: "absolute",
|
|
101
|
-
top: theme.spacing(0.5),
|
|
102
|
-
right: theme.spacing(3.5),
|
|
103
|
-
padding: "0.25rem"
|
|
104
|
-
},
|
|
105
|
-
link: {
|
|
106
|
-
color: theme.palette.warning.light
|
|
107
|
-
}
|
|
108
|
-
}));
|
|
109
|
-
const getTemplateCardProps = (template) => {
|
|
110
|
-
var _a, _b, _c, _d, _e;
|
|
111
|
-
return {
|
|
112
|
-
key: template.metadata.uid,
|
|
113
|
-
name: template.metadata.name,
|
|
114
|
-
title: `${(_a = template.metadata.title || template.metadata.name) != null ? _a : ""}`,
|
|
115
|
-
type: (_b = template.spec.type) != null ? _b : "",
|
|
116
|
-
description: (_c = template.metadata.description) != null ? _c : "-",
|
|
117
|
-
tags: (_e = (_d = template.metadata) == null ? void 0 : _d.tags) != null ? _e : []
|
|
118
|
-
};
|
|
119
|
-
};
|
|
120
|
-
const DeprecationWarning = () => {
|
|
121
|
-
const styles = useDeprecationStyles();
|
|
122
|
-
const Title = /* @__PURE__ */ React.createElement(Typography, {
|
|
123
|
-
style: { padding: 10, maxWidth: 300 }
|
|
124
|
-
}, "This template uses a syntax that has been deprecated, and should be migrated to a newer syntax. Click for more info.");
|
|
125
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
126
|
-
className: styles.deprecationIcon
|
|
127
|
-
}, /* @__PURE__ */ React.createElement(Tooltip, {
|
|
128
|
-
title: Title
|
|
129
|
-
}, /* @__PURE__ */ React.createElement(Link, {
|
|
130
|
-
href: "https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3",
|
|
131
|
-
className: styles.link
|
|
132
|
-
}, /* @__PURE__ */ React.createElement(WarningIcon, null))));
|
|
133
|
-
};
|
|
134
|
-
const TemplateCard = ({ template, deprecated }) => {
|
|
135
|
-
var _a;
|
|
136
|
-
const backstageTheme = useTheme();
|
|
137
|
-
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
138
|
-
const templateProps = getTemplateCardProps(template);
|
|
139
|
-
const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
|
|
140
|
-
const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type }) ? templateProps.type : "other";
|
|
141
|
-
const theme = backstageTheme.getPageTheme({ themeId });
|
|
142
|
-
const classes = useStyles$3({ backgroundImage: theme.backgroundImage });
|
|
143
|
-
const href = templateRoute({ templateName: templateProps.name });
|
|
144
|
-
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
|
145
|
-
const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);
|
|
146
|
-
return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardMedia, {
|
|
147
|
-
className: classes.cardHeader
|
|
148
|
-
}, /* @__PURE__ */ React.createElement(FavoriteEntity, {
|
|
149
|
-
className: classes.starButton,
|
|
150
|
-
entity: template
|
|
151
|
-
}), deprecated && /* @__PURE__ */ React.createElement(DeprecationWarning, null), /* @__PURE__ */ React.createElement(ItemCardHeader, {
|
|
152
|
-
title: templateProps.title,
|
|
153
|
-
subtitle: templateProps.type,
|
|
154
|
-
classes: { root: classes.title }
|
|
155
|
-
})), /* @__PURE__ */ React.createElement(CardContent, {
|
|
156
|
-
style: { display: "grid" }
|
|
157
|
-
}, /* @__PURE__ */ React.createElement(Box, {
|
|
158
|
-
className: classes.box
|
|
159
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
160
|
-
variant: "body2",
|
|
161
|
-
className: classes.label
|
|
162
|
-
}, "Description"), /* @__PURE__ */ React.createElement(MarkdownContent, {
|
|
163
|
-
content: templateProps.description
|
|
164
|
-
})), /* @__PURE__ */ React.createElement(Box, {
|
|
165
|
-
className: classes.box
|
|
166
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
167
|
-
variant: "body2",
|
|
168
|
-
className: classes.label
|
|
169
|
-
}, "Owner"), /* @__PURE__ */ React.createElement(EntityRefLinks, {
|
|
170
|
-
entityRefs: ownedByRelations,
|
|
171
|
-
defaultKind: "Group"
|
|
172
|
-
})), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, {
|
|
173
|
-
variant: "body2",
|
|
174
|
-
className: classes.label
|
|
175
|
-
}, "Tags"), (_a = templateProps.tags) == null ? void 0 : _a.map((tag) => /* @__PURE__ */ React.createElement(Chip, {
|
|
176
|
-
size: "small",
|
|
177
|
-
label: tag,
|
|
178
|
-
key: tag
|
|
179
|
-
})))), /* @__PURE__ */ React.createElement(CardActions, null, sourceLocation && /* @__PURE__ */ React.createElement(IconButton, {
|
|
180
|
-
className: classes.leftButton,
|
|
181
|
-
href: sourceLocation.locationTargetUrl
|
|
182
|
-
}, /* @__PURE__ */ React.createElement(ScmIntegrationIcon, {
|
|
183
|
-
type: sourceLocation.integrationType
|
|
184
|
-
})), /* @__PURE__ */ React.createElement(Button, {
|
|
185
|
-
color: "primary",
|
|
186
|
-
to: href,
|
|
187
|
-
"aria-label": `Choose ${templateProps.title}`
|
|
188
|
-
}, "Choose")));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const TemplateList = ({
|
|
192
|
-
TemplateCardComponent,
|
|
193
|
-
group
|
|
194
|
-
}) => {
|
|
195
|
-
const { loading, error, entities } = useEntityList();
|
|
196
|
-
const Card = TemplateCardComponent || TemplateCard;
|
|
197
|
-
const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
|
|
198
|
-
const titleComponent = (() => {
|
|
199
|
-
if (group && group.title) {
|
|
200
|
-
if (typeof group.title === "string") {
|
|
201
|
-
return /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
202
|
-
title: group.title
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
return group.title;
|
|
206
|
-
}
|
|
207
|
-
return /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
208
|
-
title: "Other Templates"
|
|
209
|
-
});
|
|
210
|
-
})();
|
|
211
|
-
if (group && maybeFilteredEntities.length === 0) {
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(Progress, null), error && /* @__PURE__ */ React.createElement(WarningPanel, {
|
|
215
|
-
title: "Oops! Something went wrong loading the templates"
|
|
216
|
-
}, error.message), !error && !loading && !entities.length && /* @__PURE__ */ React.createElement(Typography, {
|
|
217
|
-
variant: "body2"
|
|
218
|
-
}, "No templates found that match your filter. Learn more about", " ", /* @__PURE__ */ React.createElement(Link$1, {
|
|
219
|
-
to: "https://backstage.io/docs/features/software-templates/adding-templates"
|
|
220
|
-
}, "adding templates"), "."), /* @__PURE__ */ React.createElement(Content, null, titleComponent, /* @__PURE__ */ React.createElement(ItemCardGrid, null, maybeFilteredEntities && (maybeFilteredEntities == null ? void 0 : maybeFilteredEntities.length) > 0 && maybeFilteredEntities.map((template) => /* @__PURE__ */ React.createElement(Card, {
|
|
221
|
-
key: stringifyEntityRef(template),
|
|
222
|
-
template,
|
|
223
|
-
deprecated: template.apiVersion === "backstage.io/v1beta2"
|
|
224
|
-
})))));
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const useStyles$2 = makeStyles$1({
|
|
228
|
-
button: {
|
|
229
|
-
color: "white"
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
function ScaffolderPageContextMenu(props) {
|
|
233
|
-
const classes = useStyles$2();
|
|
234
|
-
const [anchorEl, setAnchorEl] = useState();
|
|
235
|
-
const pageLink = useRouteRef(rootRouteRef);
|
|
236
|
-
const navigate = useNavigate();
|
|
237
|
-
const showEditor = props.editor !== false;
|
|
238
|
-
const showActions = props.actions !== false;
|
|
239
|
-
if (!showEditor && !showActions) {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
const onOpen = (event) => {
|
|
243
|
-
setAnchorEl(event.currentTarget);
|
|
244
|
-
};
|
|
245
|
-
const onClose = () => {
|
|
246
|
-
setAnchorEl(void 0);
|
|
247
|
-
};
|
|
248
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(IconButton$1, {
|
|
249
|
-
"aria-label": "more",
|
|
250
|
-
"aria-controls": "long-menu",
|
|
251
|
-
"aria-haspopup": "true",
|
|
252
|
-
onClick: onOpen,
|
|
253
|
-
"data-testid": "menu-button",
|
|
254
|
-
color: "inherit",
|
|
255
|
-
className: classes.button
|
|
256
|
-
}, /* @__PURE__ */ React.createElement(MoreVert, null)), /* @__PURE__ */ React.createElement(Popover, {
|
|
257
|
-
open: Boolean(anchorEl),
|
|
258
|
-
onClose,
|
|
259
|
-
anchorEl,
|
|
260
|
-
anchorOrigin: { vertical: "bottom", horizontal: "right" },
|
|
261
|
-
transformOrigin: { vertical: "top", horizontal: "right" }
|
|
262
|
-
}, /* @__PURE__ */ React.createElement(MenuList, null, showEditor && /* @__PURE__ */ React.createElement(MenuItem, {
|
|
263
|
-
onClick: () => navigate(`${pageLink()}/edit`)
|
|
264
|
-
}, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Edit, {
|
|
265
|
-
fontSize: "small"
|
|
266
|
-
})), /* @__PURE__ */ React.createElement(ListItemText, {
|
|
267
|
-
primary: "Template Editor"
|
|
268
|
-
})), showActions && /* @__PURE__ */ React.createElement(MenuItem, {
|
|
269
|
-
onClick: () => navigate(`${pageLink()}/actions`)
|
|
270
|
-
}, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Description, {
|
|
271
|
-
fontSize: "small"
|
|
272
|
-
})), /* @__PURE__ */ React.createElement(ListItemText, {
|
|
273
|
-
primary: "Installed Actions"
|
|
274
|
-
})))));
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const ScaffolderPageContents = ({
|
|
278
|
-
TemplateCardComponent,
|
|
279
|
-
groups,
|
|
280
|
-
contextMenu
|
|
281
|
-
}) => {
|
|
282
|
-
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
283
|
-
const otherTemplatesGroup = {
|
|
284
|
-
title: groups ? "Other Templates" : "Templates",
|
|
285
|
-
filter: (entity) => {
|
|
286
|
-
const filtered = (groups != null ? groups : []).map((group) => group.filter(entity));
|
|
287
|
-
return !filtered.some((result) => result === true);
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
const { allowed } = usePermission({
|
|
291
|
-
permission: catalogEntityCreatePermission
|
|
292
|
-
});
|
|
293
|
-
return /* @__PURE__ */ React.createElement(Page, {
|
|
294
|
-
themeId: "home"
|
|
295
|
-
}, /* @__PURE__ */ React.createElement(Header, {
|
|
296
|
-
pageTitleOverride: "Create a New Component",
|
|
297
|
-
title: "Create a New Component",
|
|
298
|
-
subtitle: "Create new software components using standard templates"
|
|
299
|
-
}, /* @__PURE__ */ React.createElement(ScaffolderPageContextMenu, {
|
|
300
|
-
...contextMenu
|
|
301
|
-
})), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
302
|
-
title: "Available Templates"
|
|
303
|
-
}, allowed && /* @__PURE__ */ React.createElement(CreateButton, {
|
|
304
|
-
title: "Register Existing Component",
|
|
305
|
-
to: registerComponentLink && registerComponentLink()
|
|
306
|
-
}), /* @__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, {
|
|
307
|
-
initialFilter: "template",
|
|
308
|
-
hidden: true
|
|
309
|
-
}), /* @__PURE__ */ React.createElement(UserListPicker, {
|
|
310
|
-
initialFilter: "all",
|
|
311
|
-
availableFilters: ["all", "starred"]
|
|
312
|
-
}), /* @__PURE__ */ React.createElement(TemplateTypePicker, null), /* @__PURE__ */ React.createElement(EntityTagPicker, null)), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, groups && groups.map((group, index) => /* @__PURE__ */ React.createElement(TemplateList, {
|
|
313
|
-
key: index,
|
|
314
|
-
TemplateCardComponent,
|
|
315
|
-
group
|
|
316
|
-
})), /* @__PURE__ */ React.createElement(TemplateList, {
|
|
317
|
-
key: "other",
|
|
318
|
-
TemplateCardComponent,
|
|
319
|
-
group: otherTemplatesGroup
|
|
320
|
-
})))));
|
|
321
|
-
};
|
|
322
|
-
const ScaffolderPage = ({
|
|
323
|
-
TemplateCardComponent,
|
|
324
|
-
groups
|
|
325
|
-
}) => /* @__PURE__ */ React.createElement(EntityListProvider, null, /* @__PURE__ */ React.createElement(ScaffolderPageContents, {
|
|
326
|
-
TemplateCardComponent,
|
|
327
|
-
groups
|
|
328
|
-
}));
|
|
329
|
-
|
|
330
|
-
function isObject$1(value) {
|
|
331
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
332
|
-
}
|
|
333
|
-
function extractUiSchema(schema, uiSchema) {
|
|
334
|
-
if (!isObject$1(schema)) {
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
const { properties, items, anyOf, oneOf, allOf, dependencies } = schema;
|
|
338
|
-
for (const propName in schema) {
|
|
339
|
-
if (!schema.hasOwnProperty(propName)) {
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
if (propName.startsWith("ui:")) {
|
|
343
|
-
uiSchema[propName] = schema[propName];
|
|
344
|
-
delete schema[propName];
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (isObject$1(properties)) {
|
|
348
|
-
for (const propName in properties) {
|
|
349
|
-
if (!properties.hasOwnProperty(propName)) {
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
const schemaNode = properties[propName];
|
|
353
|
-
if (!isObject$1(schemaNode)) {
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
const innerUiSchema = {};
|
|
357
|
-
uiSchema[propName] = innerUiSchema;
|
|
358
|
-
extractUiSchema(schemaNode, innerUiSchema);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (isObject$1(items)) {
|
|
362
|
-
const innerUiSchema = {};
|
|
363
|
-
uiSchema.items = innerUiSchema;
|
|
364
|
-
extractUiSchema(items, innerUiSchema);
|
|
365
|
-
}
|
|
366
|
-
if (Array.isArray(anyOf)) {
|
|
367
|
-
for (const schemaNode of anyOf) {
|
|
368
|
-
if (!isObject$1(schemaNode)) {
|
|
369
|
-
continue;
|
|
370
|
-
}
|
|
371
|
-
extractUiSchema(schemaNode, uiSchema);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (Array.isArray(oneOf)) {
|
|
375
|
-
for (const schemaNode of oneOf) {
|
|
376
|
-
if (!isObject$1(schemaNode)) {
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
extractUiSchema(schemaNode, uiSchema);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
if (Array.isArray(allOf)) {
|
|
383
|
-
for (const schemaNode of allOf) {
|
|
384
|
-
if (!isObject$1(schemaNode)) {
|
|
385
|
-
continue;
|
|
386
|
-
}
|
|
387
|
-
extractUiSchema(schemaNode, uiSchema);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
if (isObject$1(dependencies)) {
|
|
391
|
-
for (const depName of Object.keys(dependencies)) {
|
|
392
|
-
const schemaNode = dependencies[depName];
|
|
393
|
-
if (!isObject$1(schemaNode)) {
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
extractUiSchema(schemaNode, uiSchema);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function transformSchemaToProps(inputSchema) {
|
|
401
|
-
inputSchema.type = inputSchema.type || "object";
|
|
402
|
-
const schema = JSON.parse(JSON.stringify(inputSchema));
|
|
403
|
-
delete schema.title;
|
|
404
|
-
const uiSchema = {};
|
|
405
|
-
extractUiSchema(schema, uiSchema);
|
|
406
|
-
return { schema, uiSchema };
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const DescriptionField = ({ description }) => description && /* @__PURE__ */ React.createElement(MarkdownContent, {
|
|
410
|
-
content: description,
|
|
411
|
-
linkTarget: "_blank"
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
var fieldOverrides = /*#__PURE__*/Object.freeze({
|
|
415
|
-
__proto__: null,
|
|
416
|
-
DescriptionField: DescriptionField
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
const Form = withTheme(Theme);
|
|
420
|
-
function getUiSchemasFromSteps(steps) {
|
|
421
|
-
const uiSchemas = [];
|
|
422
|
-
steps.forEach((step) => {
|
|
423
|
-
const schemaProps = step.schema.properties;
|
|
424
|
-
for (const key in schemaProps) {
|
|
425
|
-
if (schemaProps.hasOwnProperty(key)) {
|
|
426
|
-
const uiSchema = schemaProps[key];
|
|
427
|
-
uiSchema.name = key;
|
|
428
|
-
uiSchemas.push(uiSchema);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
return uiSchemas;
|
|
433
|
-
}
|
|
434
|
-
function getReviewData(formData, steps) {
|
|
435
|
-
const uiSchemas = getUiSchemasFromSteps(steps);
|
|
436
|
-
const reviewData = {};
|
|
437
|
-
for (const key in formData) {
|
|
438
|
-
if (formData.hasOwnProperty(key)) {
|
|
439
|
-
const uiSchema = uiSchemas.find((us) => us.name === key);
|
|
440
|
-
if (!uiSchema) {
|
|
441
|
-
reviewData[key] = formData[key];
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
if (uiSchema["ui:widget"] === "password") {
|
|
445
|
-
reviewData[key] = "******";
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
if (!uiSchema["ui:backstage"] || !uiSchema["ui:backstage"].review) {
|
|
449
|
-
reviewData[key] = formData[key];
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
const review = uiSchema["ui:backstage"].review;
|
|
453
|
-
if (!review.show) {
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
if (review.mask) {
|
|
457
|
-
reviewData[key] = review.mask;
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
reviewData[key] = formData[key];
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
return reviewData;
|
|
464
|
-
}
|
|
465
|
-
const MultistepJsonForm = (props) => {
|
|
466
|
-
const { formData, onChange, onReset, onFinish, fields, widgets } = props;
|
|
467
|
-
const [activeStep, setActiveStep] = useState(0);
|
|
468
|
-
const [disableButtons, setDisableButtons] = useState(false);
|
|
469
|
-
const errorApi = useApi(errorApiRef);
|
|
470
|
-
const featureFlagApi = useApi(featureFlagsApiRef);
|
|
471
|
-
const featureFlagKey = "backstage:featureFlag";
|
|
472
|
-
const filterOutProperties = (step) => {
|
|
473
|
-
var _a;
|
|
474
|
-
const filteredStep = cloneDeep(step);
|
|
475
|
-
const removedPropertyKeys = [];
|
|
476
|
-
if (filteredStep.schema.properties) {
|
|
477
|
-
filteredStep.schema.properties = Object.fromEntries(Object.entries(filteredStep.schema.properties).filter(([key, value]) => {
|
|
478
|
-
if (value[featureFlagKey]) {
|
|
479
|
-
if (featureFlagApi.isActive(value[featureFlagKey])) {
|
|
480
|
-
return true;
|
|
481
|
-
}
|
|
482
|
-
removedPropertyKeys.push(key);
|
|
483
|
-
return false;
|
|
484
|
-
}
|
|
485
|
-
return true;
|
|
486
|
-
}));
|
|
487
|
-
filteredStep.schema.required = Array.isArray(filteredStep.schema.required) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter((r) => !removedPropertyKeys.includes(r)) : filteredStep.schema.required;
|
|
488
|
-
}
|
|
489
|
-
return filteredStep;
|
|
490
|
-
};
|
|
491
|
-
const steps = props.steps.filter((step) => {
|
|
492
|
-
const featureFlag = step.schema[featureFlagKey];
|
|
493
|
-
return typeof featureFlag !== "string" || featureFlagApi.isActive(featureFlag);
|
|
494
|
-
}).map(filterOutProperties);
|
|
495
|
-
const handleReset = () => {
|
|
496
|
-
setActiveStep(0);
|
|
497
|
-
onReset();
|
|
498
|
-
};
|
|
499
|
-
const handleNext = () => {
|
|
500
|
-
setActiveStep(Math.min(activeStep + 1, steps.length));
|
|
501
|
-
};
|
|
502
|
-
const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0));
|
|
503
|
-
const handleCreate = async () => {
|
|
504
|
-
if (!onFinish) {
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
setDisableButtons(true);
|
|
508
|
-
try {
|
|
509
|
-
await onFinish();
|
|
510
|
-
} catch (err) {
|
|
511
|
-
setDisableButtons(false);
|
|
512
|
-
errorApi.post(err);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Stepper, {
|
|
516
|
-
activeStep,
|
|
517
|
-
orientation: "vertical"
|
|
518
|
-
}, steps.map(({ title, schema, ...formProps }, index) => {
|
|
519
|
-
return /* @__PURE__ */ React.createElement(Step, {
|
|
520
|
-
key: title
|
|
521
|
-
}, /* @__PURE__ */ React.createElement(StepLabel, {
|
|
522
|
-
"aria-label": `Step ${index + 1} ${title}`,
|
|
523
|
-
"aria-disabled": "false",
|
|
524
|
-
tabIndex: 0
|
|
525
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
526
|
-
variant: "h6",
|
|
527
|
-
component: "h3"
|
|
528
|
-
}, title)), /* @__PURE__ */ React.createElement(StepContent, {
|
|
529
|
-
key: title
|
|
530
|
-
}, /* @__PURE__ */ React.createElement(Form, {
|
|
531
|
-
showErrorList: false,
|
|
532
|
-
fields: { ...fieldOverrides, ...fields },
|
|
533
|
-
widgets,
|
|
534
|
-
noHtml5Validate: true,
|
|
535
|
-
formData,
|
|
536
|
-
onChange,
|
|
537
|
-
onSubmit: (e) => {
|
|
538
|
-
if (e.errors.length === 0)
|
|
539
|
-
handleNext();
|
|
540
|
-
},
|
|
541
|
-
...formProps,
|
|
542
|
-
...transformSchemaToProps(schema)
|
|
543
|
-
}, /* @__PURE__ */ React.createElement(Button$1, {
|
|
544
|
-
disabled: activeStep === 0,
|
|
545
|
-
onClick: handleBack
|
|
546
|
-
}, "Back"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
547
|
-
variant: "contained",
|
|
548
|
-
color: "primary",
|
|
549
|
-
type: "submit"
|
|
550
|
-
}, "Next step"))));
|
|
551
|
-
})), activeStep === steps.length && /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(Paper, {
|
|
552
|
-
square: true,
|
|
553
|
-
elevation: 0
|
|
554
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
555
|
-
variant: "h6"
|
|
556
|
-
}, "Review and create"), /* @__PURE__ */ React.createElement(StructuredMetadataTable, {
|
|
557
|
-
dense: true,
|
|
558
|
-
metadata: getReviewData(formData, steps)
|
|
559
|
-
}), /* @__PURE__ */ React.createElement(Box, {
|
|
560
|
-
mb: 4
|
|
561
|
-
}), /* @__PURE__ */ React.createElement(Button$1, {
|
|
562
|
-
onClick: handleBack,
|
|
563
|
-
disabled: disableButtons
|
|
564
|
-
}, "Back"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
565
|
-
onClick: handleReset,
|
|
566
|
-
disabled: disableButtons
|
|
567
|
-
}, "Reset"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
568
|
-
variant: "contained",
|
|
569
|
-
color: "primary",
|
|
570
|
-
onClick: handleCreate,
|
|
571
|
-
disabled: !onFinish || disableButtons
|
|
572
|
-
}, "Create"))));
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
function isObject(obj) {
|
|
576
|
-
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
|
577
|
-
}
|
|
578
|
-
const createValidator = (rootSchema, validators, context) => {
|
|
579
|
-
function validate(schema, formData, errors) {
|
|
580
|
-
const schemaProps = schema.properties;
|
|
581
|
-
const customObject = schema.type === "object" && schemaProps === void 0;
|
|
582
|
-
if (!isObject(schemaProps) && !customObject) {
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
if (schemaProps) {
|
|
586
|
-
for (const [key, propData] of Object.entries(formData)) {
|
|
587
|
-
const propValidation = errors[key];
|
|
588
|
-
if (isObject(propData)) {
|
|
589
|
-
const propSchemaProps = schemaProps[key];
|
|
590
|
-
if (isObject(propSchemaProps)) {
|
|
591
|
-
validate(propSchemaProps, propData, propValidation);
|
|
592
|
-
}
|
|
593
|
-
} else {
|
|
594
|
-
const propSchema = schemaProps[key];
|
|
595
|
-
const fieldName = isObject(propSchema) && propSchema["ui:field"];
|
|
596
|
-
if (fieldName && typeof validators[fieldName] === "function") {
|
|
597
|
-
validators[fieldName](propData, propValidation, context);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
} else if (customObject) {
|
|
602
|
-
const fieldName = schema["ui:field"];
|
|
603
|
-
if (fieldName && typeof validators[fieldName] === "function") {
|
|
604
|
-
validators[fieldName](formData, errors, context);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
return (formData, errors) => {
|
|
609
|
-
validate(rootSchema, formData, errors);
|
|
610
|
-
return errors;
|
|
611
|
-
};
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
const useTemplateParameterSchema = (templateRef) => {
|
|
615
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
616
|
-
const { value, loading, error } = useAsync(() => scaffolderApi.getTemplateParameterSchema(templateRef), [scaffolderApi, templateRef]);
|
|
617
|
-
return { schema: value, loading, error };
|
|
618
|
-
};
|
|
619
|
-
const TemplatePage = ({
|
|
620
|
-
customFieldExtensions = []
|
|
621
|
-
}) => {
|
|
622
|
-
const apiHolder = useApiHolder();
|
|
623
|
-
const secretsContext = useContext(SecretsContext);
|
|
624
|
-
const errorApi = useApi(errorApiRef);
|
|
625
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
626
|
-
const { templateName } = useParams();
|
|
627
|
-
const navigate = useNavigate();
|
|
628
|
-
const scaffolderTaskRoute = useRouteRef(scaffolderTaskRouteRef);
|
|
629
|
-
const rootRoute = useRouteRef(rootRouteRef);
|
|
630
|
-
const { schema, loading, error } = useTemplateParameterSchema(templateName);
|
|
631
|
-
const [formState, setFormState] = useState(() => {
|
|
632
|
-
var _a;
|
|
633
|
-
const query = qs.parse(window.location.search, {
|
|
634
|
-
ignoreQueryPrefix: true
|
|
635
|
-
});
|
|
636
|
-
try {
|
|
637
|
-
return JSON.parse(query.formData);
|
|
638
|
-
} catch (e) {
|
|
639
|
-
return (_a = query.formData) != null ? _a : {};
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
const handleFormReset = () => setFormState({});
|
|
643
|
-
const handleChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
644
|
-
const handleCreate = async () => {
|
|
645
|
-
var _a;
|
|
646
|
-
const { taskId } = await scaffolderApi.scaffold({
|
|
647
|
-
templateRef: stringifyEntityRef({
|
|
648
|
-
name: templateName,
|
|
649
|
-
kind: "template",
|
|
650
|
-
namespace: "default"
|
|
651
|
-
}),
|
|
652
|
-
values: formState,
|
|
653
|
-
secrets: secretsContext == null ? void 0 : secretsContext.secrets
|
|
654
|
-
});
|
|
655
|
-
const formParams = qs.stringify({ formData: formState }, { addQueryPrefix: true });
|
|
656
|
-
const newUrl = `${window.location.pathname}${formParams}`;
|
|
657
|
-
(_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
|
|
658
|
-
navigate(scaffolderTaskRoute({ taskId }));
|
|
659
|
-
};
|
|
660
|
-
if (error) {
|
|
661
|
-
errorApi.post(new Error(`Failed to load template, ${error}`));
|
|
662
|
-
return /* @__PURE__ */ React.createElement(Navigate, {
|
|
663
|
-
to: rootRoute()
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
if (!loading && !schema) {
|
|
667
|
-
errorApi.post(new Error("Template was not found."));
|
|
668
|
-
return /* @__PURE__ */ React.createElement(Navigate, {
|
|
669
|
-
to: rootRoute()
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
const customFieldComponents = Object.fromEntries(customFieldExtensions.map(({ name, component }) => [name, component]));
|
|
673
|
-
const customFieldValidators = Object.fromEntries(customFieldExtensions.map(({ name, validation }) => [name, validation]));
|
|
674
|
-
return /* @__PURE__ */ React.createElement(Page, {
|
|
675
|
-
themeId: "home"
|
|
676
|
-
}, /* @__PURE__ */ React.createElement(Header, {
|
|
677
|
-
pageTitleOverride: "Create a New Component",
|
|
678
|
-
title: "Create a New Component",
|
|
679
|
-
subtitle: "Create new software components using standard templates"
|
|
680
|
-
}), /* @__PURE__ */ React.createElement(Content, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, {
|
|
681
|
-
"data-testid": "loading-progress"
|
|
682
|
-
}), schema && /* @__PURE__ */ React.createElement(InfoCard, {
|
|
683
|
-
title: schema.title,
|
|
684
|
-
noPadding: true,
|
|
685
|
-
titleTypographyProps: { component: "h2" }
|
|
686
|
-
}, /* @__PURE__ */ React.createElement(MultistepJsonForm, {
|
|
687
|
-
formData: formState,
|
|
688
|
-
fields: customFieldComponents,
|
|
689
|
-
onChange: handleChange,
|
|
690
|
-
onReset: handleFormReset,
|
|
691
|
-
onFinish: handleCreate,
|
|
692
|
-
steps: schema.steps.map((step) => {
|
|
693
|
-
return {
|
|
694
|
-
...step,
|
|
695
|
-
validate: createValidator(step.schema, customFieldValidators, { apiHolder })
|
|
696
|
-
};
|
|
697
|
-
})
|
|
698
|
-
}))));
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
const useStyles$1 = makeStyles((theme) => ({
|
|
702
|
-
code: {
|
|
703
|
-
fontFamily: "Menlo, monospace",
|
|
704
|
-
padding: theme.spacing(1),
|
|
705
|
-
backgroundColor: theme.palette.type === "dark" ? theme.palette.grey[700] : theme.palette.grey[300],
|
|
706
|
-
display: "inline-block",
|
|
707
|
-
borderRadius: 5,
|
|
708
|
-
border: `1px solid ${theme.palette.grey[500]}`,
|
|
709
|
-
position: "relative"
|
|
710
|
-
},
|
|
711
|
-
codeRequired: {
|
|
712
|
-
"&::after": {
|
|
713
|
-
position: "absolute",
|
|
714
|
-
content: '"*"',
|
|
715
|
-
top: 0,
|
|
716
|
-
right: theme.spacing(0.5),
|
|
717
|
-
fontWeight: "bolder",
|
|
718
|
-
color: theme.palette.error.light
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}));
|
|
722
|
-
const ActionsPage = () => {
|
|
723
|
-
const api = useApi(scaffolderApiRef);
|
|
724
|
-
const classes = useStyles$1();
|
|
725
|
-
const { loading, value, error } = useAsync(async () => {
|
|
726
|
-
return api.listActions();
|
|
727
|
-
});
|
|
728
|
-
if (loading) {
|
|
729
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
730
|
-
}
|
|
731
|
-
if (error) {
|
|
732
|
-
return /* @__PURE__ */ React.createElement(ErrorPage, {
|
|
733
|
-
statusMessage: "Failed to load installed actions",
|
|
734
|
-
status: "500"
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
const formatRows = (input) => {
|
|
738
|
-
const properties = input.properties;
|
|
739
|
-
if (!properties) {
|
|
740
|
-
return void 0;
|
|
741
|
-
}
|
|
742
|
-
return Object.entries(properties).map((entry) => {
|
|
743
|
-
var _a;
|
|
744
|
-
const [key] = entry;
|
|
745
|
-
const props = entry[1];
|
|
746
|
-
const codeClassname = classNames(classes.code, {
|
|
747
|
-
[classes.codeRequired]: (_a = input.required) == null ? void 0 : _a.includes(key)
|
|
748
|
-
});
|
|
749
|
-
return /* @__PURE__ */ React.createElement(TableRow, {
|
|
750
|
-
key
|
|
751
|
-
}, /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement("div", {
|
|
752
|
-
className: codeClassname
|
|
753
|
-
}, key)), /* @__PURE__ */ React.createElement(TableCell, null, props.title), /* @__PURE__ */ React.createElement(TableCell, null, props.description), /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement("span", {
|
|
754
|
-
className: classes.code
|
|
755
|
-
}, props.type)));
|
|
756
|
-
});
|
|
757
|
-
};
|
|
758
|
-
const renderTable = (input) => {
|
|
759
|
-
if (!input.properties) {
|
|
760
|
-
return void 0;
|
|
761
|
-
}
|
|
762
|
-
return /* @__PURE__ */ React.createElement(TableContainer, {
|
|
763
|
-
component: Paper
|
|
764
|
-
}, /* @__PURE__ */ React.createElement(Table, {
|
|
765
|
-
size: "small"
|
|
766
|
-
}, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, null, "Name"), /* @__PURE__ */ React.createElement(TableCell, null, "Title"), /* @__PURE__ */ React.createElement(TableCell, null, "Description"), /* @__PURE__ */ React.createElement(TableCell, null, "Type"))), /* @__PURE__ */ React.createElement(TableBody, null, formatRows(input))));
|
|
767
|
-
};
|
|
768
|
-
const renderTables = (name, input) => {
|
|
769
|
-
if (!input) {
|
|
770
|
-
return void 0;
|
|
771
|
-
}
|
|
772
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, {
|
|
773
|
-
variant: "h6"
|
|
774
|
-
}, name), input.map((i, index) => /* @__PURE__ */ React.createElement("div", {
|
|
775
|
-
key: index
|
|
776
|
-
}, renderTable(i))));
|
|
777
|
-
};
|
|
778
|
-
const items = value == null ? void 0 : value.map((action) => {
|
|
779
|
-
var _a, _b, _c, _d;
|
|
780
|
-
if (action.id.startsWith("legacy:")) {
|
|
781
|
-
return void 0;
|
|
782
|
-
}
|
|
783
|
-
const oneOf = renderTables("oneOf", (_b = (_a = action.schema) == null ? void 0 : _a.input) == null ? void 0 : _b.oneOf);
|
|
784
|
-
return /* @__PURE__ */ React.createElement(Box, {
|
|
785
|
-
pb: 4,
|
|
786
|
-
key: action.id
|
|
787
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
788
|
-
variant: "h4",
|
|
789
|
-
className: classes.code
|
|
790
|
-
}, action.id), /* @__PURE__ */ React.createElement(Typography, null, action.description), ((_c = action.schema) == null ? void 0 : _c.input) && /* @__PURE__ */ React.createElement(Box, {
|
|
791
|
-
pb: 2
|
|
792
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
793
|
-
variant: "h5"
|
|
794
|
-
}, "Input"), renderTable(action.schema.input), oneOf), ((_d = action.schema) == null ? void 0 : _d.output) && /* @__PURE__ */ React.createElement(Box, {
|
|
795
|
-
pb: 2
|
|
796
|
-
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
797
|
-
variant: "h5"
|
|
798
|
-
}, "Output"), renderTable(action.schema.output)));
|
|
799
|
-
});
|
|
800
|
-
return /* @__PURE__ */ React.createElement(Page, {
|
|
801
|
-
themeId: "home"
|
|
802
|
-
}, /* @__PURE__ */ React.createElement(Header, {
|
|
803
|
-
pageTitleOverride: "Create a New Component",
|
|
804
|
-
title: "Installed actions",
|
|
805
|
-
subtitle: "This is the collection of all installed actions"
|
|
806
|
-
}), /* @__PURE__ */ React.createElement(Content, null, items));
|
|
807
|
-
};
|
|
808
|
-
|
|
809
|
-
const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI
|
|
810
|
-
parameters:
|
|
811
|
-
- title: Fill in some steps
|
|
812
|
-
required:
|
|
813
|
-
- name
|
|
814
|
-
properties:
|
|
815
|
-
name:
|
|
816
|
-
title: Name
|
|
817
|
-
type: string
|
|
818
|
-
description: Unique name of the component
|
|
819
|
-
owner:
|
|
820
|
-
title: Owner
|
|
821
|
-
type: string
|
|
822
|
-
description: Owner of the component
|
|
823
|
-
ui:field: OwnerPicker
|
|
824
|
-
ui:options:
|
|
825
|
-
allowedKinds:
|
|
826
|
-
- Group
|
|
827
|
-
- title: Choose a location
|
|
828
|
-
required:
|
|
829
|
-
- repoUrl
|
|
830
|
-
properties:
|
|
831
|
-
repoUrl:
|
|
832
|
-
title: Repository Location
|
|
833
|
-
type: string
|
|
834
|
-
ui:field: RepoUrlPicker
|
|
835
|
-
ui:options:
|
|
836
|
-
allowedHosts:
|
|
837
|
-
- github.com
|
|
838
|
-
`;
|
|
839
|
-
const useStyles = makeStyles({
|
|
840
|
-
templateSelect: {
|
|
841
|
-
marginBottom: "10px"
|
|
842
|
-
},
|
|
843
|
-
grid: {
|
|
844
|
-
height: "100%"
|
|
845
|
-
},
|
|
846
|
-
codeMirror: {
|
|
847
|
-
height: "95%"
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
const TemplateEditorPage = ({
|
|
851
|
-
defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,
|
|
852
|
-
customFieldExtensions = []
|
|
853
|
-
}) => {
|
|
854
|
-
const classes = useStyles();
|
|
855
|
-
const alertApi = useApi(alertApiRef);
|
|
856
|
-
const catalogApi = useApi(catalogApiRef);
|
|
857
|
-
const apiHolder = useApiHolder();
|
|
858
|
-
const [selectedTemplate, setSelectedTemplate] = useState("");
|
|
859
|
-
const [schema, setSchema] = useState({
|
|
860
|
-
title: "",
|
|
861
|
-
steps: []
|
|
862
|
-
});
|
|
863
|
-
const [templateOptions, setTemplateOptions] = useState([]);
|
|
864
|
-
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
865
|
-
const [formState, setFormState] = useState({});
|
|
866
|
-
const { loading } = useAsync(() => catalogApi.getEntities({
|
|
867
|
-
filter: { kind: "template" },
|
|
868
|
-
fields: [
|
|
869
|
-
"kind",
|
|
870
|
-
"metadata.namespace",
|
|
871
|
-
"metadata.name",
|
|
872
|
-
"metadata.title",
|
|
873
|
-
"spec.parameters"
|
|
874
|
-
]
|
|
875
|
-
}).then(({ items }) => setTemplateOptions(items.map((template) => {
|
|
876
|
-
var _a;
|
|
877
|
-
return {
|
|
878
|
-
label: (_a = template.metadata.title) != null ? _a : humanizeEntityRef(template, { defaultKind: "template" }),
|
|
879
|
-
value: template
|
|
880
|
-
};
|
|
881
|
-
}))).catch((e) => alertApi.post({
|
|
882
|
-
message: `Error loading exisiting templates: ${e.message}`,
|
|
883
|
-
severity: "error"
|
|
884
|
-
})), [catalogApi]);
|
|
885
|
-
const errorPanel = document.createElement("div");
|
|
886
|
-
errorPanel.style.color = "red";
|
|
887
|
-
useDebounce(() => {
|
|
888
|
-
try {
|
|
889
|
-
const parsedTemplate = yaml.parse(templateYaml);
|
|
890
|
-
setSchema({
|
|
891
|
-
title: "Preview",
|
|
892
|
-
steps: parsedTemplate.parameters.map((param) => ({
|
|
893
|
-
title: param.title,
|
|
894
|
-
schema: param
|
|
895
|
-
}))
|
|
896
|
-
});
|
|
897
|
-
setFormState({});
|
|
898
|
-
} catch (e) {
|
|
899
|
-
errorPanel.textContent = e.message;
|
|
900
|
-
}
|
|
901
|
-
}, 250, [setFormState, setSchema, templateYaml]);
|
|
902
|
-
const handleSelectChange = useCallback((selected) => {
|
|
903
|
-
setSelectedTemplate(selected);
|
|
904
|
-
setTemplateYaml(yaml.stringify(selected.spec));
|
|
905
|
-
}, [setTemplateYaml]);
|
|
906
|
-
const handleFormReset = () => setFormState({});
|
|
907
|
-
const handleFormChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
908
|
-
const handleCodeChange = useCallback((code) => {
|
|
909
|
-
setTemplateYaml(code);
|
|
910
|
-
}, [setTemplateYaml]);
|
|
911
|
-
const customFieldComponents = Object.fromEntries(customFieldExtensions.map(({ name, component }) => [name, component]));
|
|
912
|
-
const customFieldValidators = Object.fromEntries(customFieldExtensions.map(({ name, validation }) => [name, validation]));
|
|
913
|
-
return /* @__PURE__ */ React.createElement(Page, {
|
|
914
|
-
themeId: "home"
|
|
915
|
-
}, /* @__PURE__ */ React.createElement(Header, {
|
|
916
|
-
title: "Template Editor",
|
|
917
|
-
subtitle: "Preview your template parameter UI"
|
|
918
|
-
}), /* @__PURE__ */ React.createElement(Content, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement(Grid, {
|
|
919
|
-
container: true,
|
|
920
|
-
className: classes.grid
|
|
921
|
-
}, /* @__PURE__ */ React.createElement(Grid, {
|
|
922
|
-
item: true,
|
|
923
|
-
xs: 6
|
|
924
|
-
}, /* @__PURE__ */ React.createElement(FormControl, {
|
|
925
|
-
className: classes.templateSelect,
|
|
926
|
-
variant: "outlined",
|
|
927
|
-
fullWidth: true
|
|
928
|
-
}, /* @__PURE__ */ React.createElement(InputLabel, {
|
|
929
|
-
id: "select-template-label"
|
|
930
|
-
}, "Load Existing Template"), /* @__PURE__ */ React.createElement(Select, {
|
|
931
|
-
value: selectedTemplate,
|
|
932
|
-
label: "Load Existing Template",
|
|
933
|
-
labelId: "select-template-label",
|
|
934
|
-
onChange: (e) => handleSelectChange(e.target.value)
|
|
935
|
-
}, templateOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem$1, {
|
|
936
|
-
key: idx,
|
|
937
|
-
value: option.value
|
|
938
|
-
}, option.label)))), /* @__PURE__ */ React.createElement(CodeMirror, {
|
|
939
|
-
className: classes.codeMirror,
|
|
940
|
-
value: templateYaml,
|
|
941
|
-
theme: "dark",
|
|
942
|
-
height: "100%",
|
|
943
|
-
extensions: [
|
|
944
|
-
StreamLanguage.define(yaml$1),
|
|
945
|
-
showPanel.of(() => ({ dom: errorPanel, top: true }))
|
|
946
|
-
],
|
|
947
|
-
onChange: handleCodeChange
|
|
948
|
-
})), /* @__PURE__ */ React.createElement(Grid, {
|
|
949
|
-
item: true,
|
|
950
|
-
xs: 6
|
|
951
|
-
}, schema && /* @__PURE__ */ React.createElement(InfoCard, {
|
|
952
|
-
key: JSON.stringify(schema)
|
|
953
|
-
}, /* @__PURE__ */ React.createElement(MultistepJsonForm, {
|
|
954
|
-
formData: formState,
|
|
955
|
-
fields: customFieldComponents,
|
|
956
|
-
onChange: handleFormChange,
|
|
957
|
-
onReset: handleFormReset,
|
|
958
|
-
steps: schema.steps.map((step) => {
|
|
959
|
-
return {
|
|
960
|
-
...step,
|
|
961
|
-
validate: createValidator(step.schema, customFieldValidators, { apiHolder })
|
|
962
|
-
};
|
|
963
|
-
})
|
|
964
|
-
}))))));
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
const Router = (props) => {
|
|
968
|
-
const { groups, components = {}, defaultPreviewTemplate } = props;
|
|
969
|
-
const { TemplateCardComponent, TaskPageComponent } = components;
|
|
970
|
-
const outlet = useOutlet();
|
|
971
|
-
const TaskPageElement = TaskPageComponent != null ? TaskPageComponent : TaskPage;
|
|
972
|
-
const customFieldExtensions = useElementFilter(outlet, (elements) => elements.selectByComponentData({
|
|
973
|
-
key: FIELD_EXTENSION_WRAPPER_KEY
|
|
974
|
-
}).findComponentData({
|
|
975
|
-
key: FIELD_EXTENSION_KEY
|
|
976
|
-
}));
|
|
977
|
-
const fieldExtensions = [
|
|
978
|
-
...customFieldExtensions,
|
|
979
|
-
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(({ name }) => !customFieldExtensions.some((customFieldExtension) => customFieldExtension.name === name))
|
|
980
|
-
];
|
|
981
|
-
return /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
|
|
982
|
-
element: /* @__PURE__ */ React.createElement(ScaffolderPage, {
|
|
983
|
-
groups,
|
|
984
|
-
TemplateCardComponent,
|
|
985
|
-
contextMenu: props.contextMenu
|
|
986
|
-
})
|
|
987
|
-
}), /* @__PURE__ */ React.createElement(Route, {
|
|
988
|
-
path: selectedTemplateRouteRef.path,
|
|
989
|
-
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplatePage, {
|
|
990
|
-
customFieldExtensions: fieldExtensions
|
|
991
|
-
}))
|
|
992
|
-
}), /* @__PURE__ */ React.createElement(Route, {
|
|
993
|
-
path: scaffolderTaskRouteRef.path,
|
|
994
|
-
element: /* @__PURE__ */ React.createElement(TaskPageElement, null)
|
|
995
|
-
}), /* @__PURE__ */ React.createElement(Route, {
|
|
996
|
-
path: actionsRouteRef.path,
|
|
997
|
-
element: /* @__PURE__ */ React.createElement(ActionsPage, null)
|
|
998
|
-
}), /* @__PURE__ */ React.createElement(Route, {
|
|
999
|
-
path: editRouteRef.path,
|
|
1000
|
-
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplateEditorPage, {
|
|
1001
|
-
defaultPreviewTemplate,
|
|
1002
|
-
customFieldExtensions: fieldExtensions
|
|
1003
|
-
}))
|
|
1004
|
-
}), /* @__PURE__ */ React.createElement(Route, {
|
|
1005
|
-
path: "preview",
|
|
1006
|
-
element: /* @__PURE__ */ React.createElement(Navigate, {
|
|
1007
|
-
to: "../edit"
|
|
1008
|
-
})
|
|
1009
|
-
}));
|
|
1010
|
-
};
|
|
1011
|
-
|
|
1012
|
-
export { Router };
|
|
1013
|
-
//# sourceMappingURL=Router-b7921312.esm.js.map
|