@backstage/plugin-scaffolder 1.4.0 → 1.5.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 +35 -0
- package/alpha/package.json +1 -1
- package/dist/esm/{Router-e14e5f4e.esm.js → Router-fa1fcf0c.esm.js} +289 -175
- package/dist/esm/{Router-e14e5f4e.esm.js.map → Router-fa1fcf0c.esm.js.map} +1 -1
- package/dist/esm/{default-ffab2851.esm.js → default-2a48fcb0.esm.js} +2 -2
- package/dist/esm/{default-ffab2851.esm.js.map → default-2a48fcb0.esm.js.map} +1 -1
- package/dist/esm/{index-a298f509.esm.js → index-3b171258.esm.js} +388 -265
- package/dist/esm/index-3b171258.esm.js.map +1 -0
- package/dist/esm/{index-8dd91f94.esm.js → index-bdece754.esm.js} +290 -51
- package/dist/esm/index-bdece754.esm.js.map +1 -0
- package/dist/index.alpha.d.ts +3 -1
- package/dist/index.beta.d.ts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +1 -1
- package/package.json +14 -14
- package/dist/esm/index-8dd91f94.esm.js.map +0 -1
- package/dist/esm/index-a298f509.esm.js.map +0 -1
|
@@ -3,7 +3,7 @@ import { useNavigate, Navigate, useOutlet, Routes, Route, useParams as useParams
|
|
|
3
3
|
import { ItemCardHeader, MarkdownContent, Button, ContentHeader, Progress, WarningPanel, Link as Link$1, Content, ItemCardGrid, Page, Header, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage, ErrorPanel, LogViewer, StatusError, StatusOK, StatusPending, Lifecycle, EmptyState, Table as Table$1 } from '@backstage/core-components';
|
|
4
4
|
import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, alertApiRef, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
5
|
import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, catalogApiRef, humanizeEntityRef, EntityRefLink } from '@backstage/plugin-catalog-react';
|
|
6
|
-
import { s as selectedTemplateRouteRef, e as editRouteRef, a as actionsRouteRef, b as scaffolderListTaskRouteRef, r as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, c as scaffolderApiRef, d as scaffolderTaskRouteRef, f as rootRouteRef, g as TaskStatusStepper, h as TaskPageLinks, F as FIELD_EXTENSION_WRAPPER_KEY, i as FIELD_EXTENSION_KEY, l as legacySelectedTemplateRouteRef, j as SecretsContextProvider, k as TaskPage } from './index-
|
|
6
|
+
import { s as selectedTemplateRouteRef, e as editRouteRef, a as actionsRouteRef, b as scaffolderListTaskRouteRef, r as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, c as scaffolderApiRef, d as scaffolderTaskRouteRef, f as rootRouteRef, g as TaskStatusStepper, h as TaskPageLinks, F as FIELD_EXTENSION_WRAPPER_KEY, i as FIELD_EXTENSION_KEY, l as legacySelectedTemplateRouteRef, j as SecretsContextProvider, k as TaskPage } from './index-3b171258.esm.js';
|
|
7
7
|
import { RELATION_OWNED_BY, parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
8
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, Divider as Divider$1, FormControl, InputLabel, Select, MenuItem as MenuItem$1, List as List$2, ListItemIcon as ListItemIcon$1, ListItemText as ListItemText$1 } from '@material-ui/core';
|
|
9
9
|
import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
@@ -66,7 +66,7 @@ import SettingsIcon from '@material-ui/icons/Settings';
|
|
|
66
66
|
import AllIcon from '@material-ui/icons/FontDownload';
|
|
67
67
|
import { DateTime, Interval } from 'luxon';
|
|
68
68
|
import humanizeDuration from 'humanize-duration';
|
|
69
|
-
import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-
|
|
69
|
+
import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-2a48fcb0.esm.js';
|
|
70
70
|
import '@backstage/errors';
|
|
71
71
|
import 'zen-observable';
|
|
72
72
|
import '@material-ui/core/FormControl';
|
|
@@ -164,7 +164,10 @@ const TemplateCard = ({ template, deprecated }) => {
|
|
|
164
164
|
const backstageTheme = useTheme();
|
|
165
165
|
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
166
166
|
const templateProps = getTemplateCardProps(template);
|
|
167
|
-
const ownedByRelations = getEntityRelations(
|
|
167
|
+
const ownedByRelations = getEntityRelations(
|
|
168
|
+
template,
|
|
169
|
+
RELATION_OWNED_BY
|
|
170
|
+
);
|
|
168
171
|
const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type }) ? templateProps.type : "other";
|
|
169
172
|
const theme = backstageTheme.getPageTheme({ themeId });
|
|
170
173
|
const classes = useStyles$e({ backgroundImage: theme.backgroundImage });
|
|
@@ -522,17 +525,23 @@ const MultistepJsonForm = (props) => {
|
|
|
522
525
|
const filteredStep = cloneDeep(step);
|
|
523
526
|
const removedPropertyKeys = [];
|
|
524
527
|
if (filteredStep.schema.properties) {
|
|
525
|
-
filteredStep.schema.properties = Object.fromEntries(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
+
filteredStep.schema.properties = Object.fromEntries(
|
|
529
|
+
Object.entries(filteredStep.schema.properties).filter(
|
|
530
|
+
([key, value]) => {
|
|
531
|
+
if (value[featureFlagKey]) {
|
|
532
|
+
if (featureFlagApi.isActive(value[featureFlagKey])) {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
removedPropertyKeys.push(key);
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
528
538
|
return true;
|
|
529
539
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
filteredStep.schema.required = Array.isArray(filteredStep.schema.required) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter((r) => !removedPropertyKeys.includes(r)) : filteredStep.schema.required;
|
|
540
|
+
)
|
|
541
|
+
);
|
|
542
|
+
filteredStep.schema.required = Array.isArray(filteredStep.schema.required) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter(
|
|
543
|
+
(r) => !removedPropertyKeys.includes(r)
|
|
544
|
+
) : filteredStep.schema.required;
|
|
536
545
|
}
|
|
537
546
|
return filteredStep;
|
|
538
547
|
};
|
|
@@ -638,13 +647,21 @@ const createValidator = (rootSchema, validators, context) => {
|
|
|
638
647
|
if (isObject(propData)) {
|
|
639
648
|
const propSchemaProps = schemaProps[key];
|
|
640
649
|
if (isObject(propSchemaProps)) {
|
|
641
|
-
validate(
|
|
650
|
+
validate(
|
|
651
|
+
propSchemaProps,
|
|
652
|
+
propData,
|
|
653
|
+
propValidation
|
|
654
|
+
);
|
|
642
655
|
}
|
|
643
656
|
} else {
|
|
644
657
|
const propSchema = schemaProps[key];
|
|
645
658
|
const fieldName = isObject(propSchema) && propSchema["ui:field"];
|
|
646
659
|
if (fieldName && typeof validators[fieldName] === "function") {
|
|
647
|
-
validators[fieldName](
|
|
660
|
+
validators[fieldName](
|
|
661
|
+
propData,
|
|
662
|
+
propValidation,
|
|
663
|
+
context
|
|
664
|
+
);
|
|
648
665
|
}
|
|
649
666
|
}
|
|
650
667
|
}
|
|
@@ -663,7 +680,10 @@ const createValidator = (rootSchema, validators, context) => {
|
|
|
663
680
|
|
|
664
681
|
const useTemplateParameterSchema = (templateRef) => {
|
|
665
682
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
666
|
-
const { value, loading, error } = useAsync(
|
|
683
|
+
const { value, loading, error } = useAsync(
|
|
684
|
+
() => scaffolderApi.getTemplateParameterSchema(templateRef),
|
|
685
|
+
[scaffolderApi, templateRef]
|
|
686
|
+
);
|
|
667
687
|
return { schema: value, loading, error };
|
|
668
688
|
};
|
|
669
689
|
const TemplatePage = ({
|
|
@@ -695,7 +715,10 @@ const TemplatePage = ({
|
|
|
695
715
|
}
|
|
696
716
|
});
|
|
697
717
|
const handleFormReset = () => setFormState({});
|
|
698
|
-
const handleChange = useCallback(
|
|
718
|
+
const handleChange = useCallback(
|
|
719
|
+
(e) => setFormState(e.formData),
|
|
720
|
+
[setFormState]
|
|
721
|
+
);
|
|
699
722
|
const handleCreate = async () => {
|
|
700
723
|
var _a;
|
|
701
724
|
const { taskId } = await scaffolderApi.scaffold({
|
|
@@ -703,7 +726,10 @@ const TemplatePage = ({
|
|
|
703
726
|
values: formState,
|
|
704
727
|
secrets: secretsContext == null ? void 0 : secretsContext.secrets
|
|
705
728
|
});
|
|
706
|
-
const formParams = qs.stringify(
|
|
729
|
+
const formParams = qs.stringify(
|
|
730
|
+
{ formData: formState },
|
|
731
|
+
{ addQueryPrefix: true }
|
|
732
|
+
);
|
|
707
733
|
const newUrl = `${window.location.pathname}${formParams}`;
|
|
708
734
|
(_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
|
|
709
735
|
navigate(scaffolderTaskRoute({ taskId }));
|
|
@@ -720,8 +746,12 @@ const TemplatePage = ({
|
|
|
720
746
|
to: rootRoute()
|
|
721
747
|
});
|
|
722
748
|
}
|
|
723
|
-
const customFieldComponents = Object.fromEntries(
|
|
724
|
-
|
|
749
|
+
const customFieldComponents = Object.fromEntries(
|
|
750
|
+
customFieldExtensions.map(({ name, component }) => [name, component])
|
|
751
|
+
);
|
|
752
|
+
const customFieldValidators = Object.fromEntries(
|
|
753
|
+
customFieldExtensions.map(({ name, validation }) => [name, validation])
|
|
754
|
+
);
|
|
725
755
|
return /* @__PURE__ */ React.createElement(Page, {
|
|
726
756
|
themeId: "home"
|
|
727
757
|
}, /* @__PURE__ */ React.createElement(Header, {
|
|
@@ -743,7 +773,11 @@ const TemplatePage = ({
|
|
|
743
773
|
steps: schema.steps.map((step) => {
|
|
744
774
|
return {
|
|
745
775
|
...step,
|
|
746
|
-
validate: createValidator(
|
|
776
|
+
validate: createValidator(
|
|
777
|
+
step.schema,
|
|
778
|
+
customFieldValidators,
|
|
779
|
+
{ apiHolder }
|
|
780
|
+
)
|
|
747
781
|
};
|
|
748
782
|
})
|
|
749
783
|
}))));
|
|
@@ -1092,11 +1126,16 @@ class DirectoryEditorManager {
|
|
|
1092
1126
|
var _a;
|
|
1093
1127
|
const selectedPath = (_a = __privateGet(this, _selectedFile)) == null ? void 0 : _a.path;
|
|
1094
1128
|
const files = await __privateGet(this, _access2).listFiles();
|
|
1095
|
-
const fileManagers = await Promise.all(
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1129
|
+
const fileManagers = await Promise.all(
|
|
1130
|
+
files.map(async (file) => {
|
|
1131
|
+
const manager = new DirectoryEditorFileManager(
|
|
1132
|
+
file,
|
|
1133
|
+
__privateGet(this, _signalUpdate2)
|
|
1134
|
+
);
|
|
1135
|
+
await manager.reload();
|
|
1136
|
+
return manager;
|
|
1137
|
+
})
|
|
1138
|
+
);
|
|
1100
1139
|
__privateGet(this, _files).length = 0;
|
|
1101
1140
|
__privateGet(this, _files).push(...fileManagers);
|
|
1102
1141
|
this.setSelectedFile(selectedPath);
|
|
@@ -1114,7 +1153,9 @@ _listeners = new WeakMap();
|
|
|
1114
1153
|
_files = new WeakMap();
|
|
1115
1154
|
_selectedFile = new WeakMap();
|
|
1116
1155
|
_signalUpdate2 = new WeakMap();
|
|
1117
|
-
const DirectoryEditorContext = createContext(
|
|
1156
|
+
const DirectoryEditorContext = createContext(
|
|
1157
|
+
void 0
|
|
1158
|
+
);
|
|
1118
1159
|
function useDirectoryEditor() {
|
|
1119
1160
|
const value = useContext(DirectoryEditorContext);
|
|
1120
1161
|
const rerender = useRerender();
|
|
@@ -1126,15 +1167,17 @@ function useDirectoryEditor() {
|
|
|
1126
1167
|
}
|
|
1127
1168
|
function DirectoryEditorProvider(props) {
|
|
1128
1169
|
const { directory } = props;
|
|
1129
|
-
const [{ result, error }, { execute }] = useAsync$1(
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1170
|
+
const [{ result, error }, { execute }] = useAsync$1(
|
|
1171
|
+
async (dir) => {
|
|
1172
|
+
const manager = new DirectoryEditorManager(dir);
|
|
1173
|
+
await manager.reload();
|
|
1174
|
+
const firstYaml = manager.files.find((file) => file.path.match(/\.ya?ml$/));
|
|
1175
|
+
if (firstYaml) {
|
|
1176
|
+
manager.setSelectedFile(firstYaml.path);
|
|
1177
|
+
}
|
|
1178
|
+
return manager;
|
|
1135
1179
|
}
|
|
1136
|
-
|
|
1137
|
-
});
|
|
1180
|
+
);
|
|
1138
1181
|
useEffect(() => {
|
|
1139
1182
|
execute(directory);
|
|
1140
1183
|
}, [execute, directory]);
|
|
@@ -1164,7 +1207,9 @@ function base64EncodeContent(content) {
|
|
|
1164
1207
|
const buffer = decoder.encode(content);
|
|
1165
1208
|
const chunks = new Array();
|
|
1166
1209
|
for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
|
|
1167
|
-
chunks.push(
|
|
1210
|
+
chunks.push(
|
|
1211
|
+
String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE))
|
|
1212
|
+
);
|
|
1168
1213
|
}
|
|
1169
1214
|
return btoa(chunks.join(""));
|
|
1170
1215
|
}
|
|
@@ -1203,38 +1248,44 @@ function DryRunProvider(props) {
|
|
|
1203
1248
|
};
|
|
1204
1249
|
});
|
|
1205
1250
|
}, []);
|
|
1206
|
-
const execute = useCallback(
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
setState((prevState) => {
|
|
1225
|
-
var _a;
|
|
1226
|
-
return {
|
|
1227
|
-
results: [...prevState.results, result],
|
|
1228
|
-
selectedResult: (_a = prevState.selectedResult) != null ? _a : result
|
|
1251
|
+
const execute = useCallback(
|
|
1252
|
+
async (options) => {
|
|
1253
|
+
if (!scaffolderApi.dryRun) {
|
|
1254
|
+
throw new Error("Scaffolder API does not support dry-run");
|
|
1255
|
+
}
|
|
1256
|
+
const parsed = yaml.parse(options.templateContent);
|
|
1257
|
+
const response = await scaffolderApi.dryRun({
|
|
1258
|
+
template: parsed,
|
|
1259
|
+
values: options.values,
|
|
1260
|
+
secrets: {},
|
|
1261
|
+
directoryContents: options.files.map((file) => ({
|
|
1262
|
+
path: file.path,
|
|
1263
|
+
base64Content: base64EncodeContent(file.content)
|
|
1264
|
+
}))
|
|
1265
|
+
});
|
|
1266
|
+
const result = {
|
|
1267
|
+
...response,
|
|
1268
|
+
id: idRef.current++
|
|
1229
1269
|
};
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1270
|
+
setState((prevState) => {
|
|
1271
|
+
var _a;
|
|
1272
|
+
return {
|
|
1273
|
+
results: [...prevState.results, result],
|
|
1274
|
+
selectedResult: (_a = prevState.selectedResult) != null ? _a : result
|
|
1275
|
+
};
|
|
1276
|
+
});
|
|
1277
|
+
},
|
|
1278
|
+
[scaffolderApi]
|
|
1279
|
+
);
|
|
1280
|
+
const dryRun = useMemo(
|
|
1281
|
+
() => ({
|
|
1282
|
+
...state,
|
|
1283
|
+
selectResult,
|
|
1284
|
+
deleteResult,
|
|
1285
|
+
execute
|
|
1286
|
+
}),
|
|
1287
|
+
[state, selectResult, deleteResult, execute]
|
|
1288
|
+
);
|
|
1238
1289
|
return /* @__PURE__ */ React.createElement(DryRunContext.Provider, {
|
|
1239
1290
|
value: dryRun
|
|
1240
1291
|
}, props.children);
|
|
@@ -1324,7 +1375,9 @@ function parseFileEntires(paths) {
|
|
|
1324
1375
|
path: entryPath,
|
|
1325
1376
|
children: []
|
|
1326
1377
|
};
|
|
1327
|
-
const firstFileIndex = current.children.findIndex(
|
|
1378
|
+
const firstFileIndex = current.children.findIndex(
|
|
1379
|
+
(child) => child.type === "file"
|
|
1380
|
+
);
|
|
1328
1381
|
current.children.splice(firstFileIndex, 0, newEntry);
|
|
1329
1382
|
current = newEntry;
|
|
1330
1383
|
} else {
|
|
@@ -1356,7 +1409,10 @@ function FileTreeItem({ entry }) {
|
|
|
1356
1409
|
}
|
|
1357
1410
|
function FileBrowser(props) {
|
|
1358
1411
|
const classes = useStyles$9();
|
|
1359
|
-
const fileTree = useMemo(
|
|
1412
|
+
const fileTree = useMemo(
|
|
1413
|
+
() => parseFileEntires(props.filePaths),
|
|
1414
|
+
[props.filePaths]
|
|
1415
|
+
);
|
|
1360
1416
|
return /* @__PURE__ */ React.createElement(TreeView, {
|
|
1361
1417
|
selected: props.selected,
|
|
1362
1418
|
className: classes.root,
|
|
@@ -1434,7 +1490,9 @@ function FilesContent() {
|
|
|
1434
1490
|
const classes = useStyles$7();
|
|
1435
1491
|
const { selectedResult } = useDryRun();
|
|
1436
1492
|
const [selectedPath, setSelectedPath] = useState("");
|
|
1437
|
-
const selectedFile = selectedResult == null ? void 0 : selectedResult.directoryContents.find(
|
|
1493
|
+
const selectedFile = selectedResult == null ? void 0 : selectedResult.directoryContents.find(
|
|
1494
|
+
(f) => f.path === selectedPath
|
|
1495
|
+
);
|
|
1438
1496
|
useEffect(() => {
|
|
1439
1497
|
if (selectedResult) {
|
|
1440
1498
|
const [firstFile] = selectedResult.directoryContents;
|
|
@@ -1473,7 +1531,9 @@ function LogContent() {
|
|
|
1473
1531
|
}
|
|
1474
1532
|
return (_a2 = selectedResult.steps.map((step) => {
|
|
1475
1533
|
var _a3, _b2;
|
|
1476
|
-
const stepLog = selectedResult.log.filter(
|
|
1534
|
+
const stepLog = selectedResult.log.filter(
|
|
1535
|
+
(l) => l.body.stepId === step.id
|
|
1536
|
+
);
|
|
1477
1537
|
return {
|
|
1478
1538
|
id: step.id,
|
|
1479
1539
|
name: step.name,
|
|
@@ -1516,7 +1576,9 @@ function OutputContent() {
|
|
|
1516
1576
|
}
|
|
1517
1577
|
function DryRunResultsView() {
|
|
1518
1578
|
const classes = useStyles$7();
|
|
1519
|
-
const [selectedTab, setSelectedTab] = useState(
|
|
1579
|
+
const [selectedTab, setSelectedTab] = useState(
|
|
1580
|
+
"files"
|
|
1581
|
+
);
|
|
1520
1582
|
return /* @__PURE__ */ React.createElement("div", {
|
|
1521
1583
|
className: classes.root
|
|
1522
1584
|
}, /* @__PURE__ */ React.createElement(Tabs, {
|
|
@@ -1616,7 +1678,9 @@ function TemplateEditorBrowser(props) {
|
|
|
1616
1678
|
return;
|
|
1617
1679
|
}
|
|
1618
1680
|
if (changedFiles.length > 0) {
|
|
1619
|
-
const accepted = window.confirm(
|
|
1681
|
+
const accepted = window.confirm(
|
|
1682
|
+
"Are you sure? Unsaved changes will be lost"
|
|
1683
|
+
);
|
|
1620
1684
|
if (!accepted) {
|
|
1621
1685
|
return;
|
|
1622
1686
|
}
|
|
@@ -1704,49 +1768,61 @@ function TemplateEditorForm(props) {
|
|
|
1704
1768
|
const apiHolder = useApiHolder();
|
|
1705
1769
|
const [steps, setSteps] = useState();
|
|
1706
1770
|
const fields = useMemo(() => {
|
|
1707
|
-
return Object.fromEntries(
|
|
1771
|
+
return Object.fromEntries(
|
|
1772
|
+
fieldExtensions.map(({ name, component }) => [name, component])
|
|
1773
|
+
);
|
|
1708
1774
|
}, [fieldExtensions]);
|
|
1709
|
-
useDebounce(
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
return;
|
|
1714
|
-
}
|
|
1715
|
-
const parsed = yaml.parse(content);
|
|
1716
|
-
if (!isJsonObject(parsed)) {
|
|
1717
|
-
setSteps(void 0);
|
|
1718
|
-
return;
|
|
1719
|
-
}
|
|
1720
|
-
let rootObj = parsed;
|
|
1721
|
-
if (!contentIsSpec) {
|
|
1722
|
-
const isTemplate = String(parsed.kind).toLocaleLowerCase("en-US") === "template";
|
|
1723
|
-
if (!isTemplate) {
|
|
1775
|
+
useDebounce(
|
|
1776
|
+
() => {
|
|
1777
|
+
try {
|
|
1778
|
+
if (!content) {
|
|
1724
1779
|
setSteps(void 0);
|
|
1725
1780
|
return;
|
|
1726
1781
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
setErrorText("Template parameters must be an array");
|
|
1732
|
-
setSteps(void 0);
|
|
1733
|
-
return;
|
|
1734
|
-
}
|
|
1735
|
-
const fieldValidators = Object.fromEntries(fieldExtensions.map(({ name, validation }) => [name, validation]));
|
|
1736
|
-
setErrorText();
|
|
1737
|
-
setSteps(parameters.flatMap((param) => isJsonObject(param) ? [
|
|
1738
|
-
{
|
|
1739
|
-
title: String(param.title),
|
|
1740
|
-
schema: param,
|
|
1741
|
-
validate: createValidator(param, fieldValidators, {
|
|
1742
|
-
apiHolder
|
|
1743
|
-
})
|
|
1782
|
+
const parsed = yaml.parse(content);
|
|
1783
|
+
if (!isJsonObject(parsed)) {
|
|
1784
|
+
setSteps(void 0);
|
|
1785
|
+
return;
|
|
1744
1786
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1787
|
+
let rootObj = parsed;
|
|
1788
|
+
if (!contentIsSpec) {
|
|
1789
|
+
const isTemplate = String(parsed.kind).toLocaleLowerCase("en-US") === "template";
|
|
1790
|
+
if (!isTemplate) {
|
|
1791
|
+
setSteps(void 0);
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
rootObj = isJsonObject(parsed.spec) ? parsed.spec : {};
|
|
1795
|
+
}
|
|
1796
|
+
const { parameters } = rootObj;
|
|
1797
|
+
if (!Array.isArray(parameters)) {
|
|
1798
|
+
setErrorText("Template parameters must be an array");
|
|
1799
|
+
setSteps(void 0);
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
const fieldValidators = Object.fromEntries(
|
|
1803
|
+
fieldExtensions.map(({ name, validation }) => [name, validation])
|
|
1804
|
+
);
|
|
1805
|
+
setErrorText();
|
|
1806
|
+
setSteps(
|
|
1807
|
+
parameters.flatMap(
|
|
1808
|
+
(param) => isJsonObject(param) ? [
|
|
1809
|
+
{
|
|
1810
|
+
title: String(param.title),
|
|
1811
|
+
schema: param,
|
|
1812
|
+
validate: createValidator(param, fieldValidators, {
|
|
1813
|
+
apiHolder
|
|
1814
|
+
})
|
|
1815
|
+
}
|
|
1816
|
+
] : []
|
|
1817
|
+
)
|
|
1818
|
+
);
|
|
1819
|
+
} catch (e) {
|
|
1820
|
+
setErrorText(e.message);
|
|
1821
|
+
}
|
|
1822
|
+
},
|
|
1823
|
+
250,
|
|
1824
|
+
[contentIsSpec, content, apiHolder]
|
|
1825
|
+
);
|
|
1750
1826
|
if (!steps) {
|
|
1751
1827
|
return null;
|
|
1752
1828
|
}
|
|
@@ -1840,12 +1916,15 @@ function TemplateEditorTextArea(props) {
|
|
|
1840
1916
|
dom.textContent = errorText;
|
|
1841
1917
|
return showPanel.of(() => ({ dom, bottom: true }));
|
|
1842
1918
|
}, [classes, errorText]);
|
|
1843
|
-
useKeyboardEvent(
|
|
1844
|
-
e.
|
|
1845
|
-
|
|
1846
|
-
|
|
1919
|
+
useKeyboardEvent(
|
|
1920
|
+
(e) => e.key === "s" && (e.ctrlKey || e.metaKey),
|
|
1921
|
+
(e) => {
|
|
1922
|
+
e.preventDefault();
|
|
1923
|
+
if (props.onSave) {
|
|
1924
|
+
props.onSave();
|
|
1925
|
+
}
|
|
1847
1926
|
}
|
|
1848
|
-
|
|
1927
|
+
);
|
|
1849
1928
|
return /* @__PURE__ */ React.createElement("div", {
|
|
1850
1929
|
className: classes.container
|
|
1851
1930
|
}, /* @__PURE__ */ React.createElement(CodeMirror, {
|
|
@@ -2024,31 +2103,43 @@ const TemplateFormPreviewer = ({
|
|
|
2024
2103
|
const [templateOptions, setTemplateOptions] = useState([]);
|
|
2025
2104
|
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
2026
2105
|
const [formState, setFormState] = useState({});
|
|
2027
|
-
const { loading } = useAsync(
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2106
|
+
const { loading } = useAsync(
|
|
2107
|
+
() => catalogApi.getEntities({
|
|
2108
|
+
filter: { kind: "template" },
|
|
2109
|
+
fields: [
|
|
2110
|
+
"kind",
|
|
2111
|
+
"metadata.namespace",
|
|
2112
|
+
"metadata.name",
|
|
2113
|
+
"metadata.title",
|
|
2114
|
+
"spec.parameters",
|
|
2115
|
+
"spec.steps",
|
|
2116
|
+
"spec.output"
|
|
2117
|
+
]
|
|
2118
|
+
}).then(
|
|
2119
|
+
({ items }) => setTemplateOptions(
|
|
2120
|
+
items.map((template) => {
|
|
2121
|
+
var _a;
|
|
2122
|
+
return {
|
|
2123
|
+
label: (_a = template.metadata.title) != null ? _a : humanizeEntityRef(template, { defaultKind: "template" }),
|
|
2124
|
+
value: template
|
|
2125
|
+
};
|
|
2126
|
+
})
|
|
2127
|
+
)
|
|
2128
|
+
).catch(
|
|
2129
|
+
(e) => alertApi.post({
|
|
2130
|
+
message: `Error loading exisiting templates: ${e.message}`,
|
|
2131
|
+
severity: "error"
|
|
2132
|
+
})
|
|
2133
|
+
),
|
|
2134
|
+
[catalogApi]
|
|
2135
|
+
);
|
|
2136
|
+
const handleSelectChange = useCallback(
|
|
2137
|
+
(selected) => {
|
|
2138
|
+
setSelectedTemplate(selected);
|
|
2139
|
+
setTemplateYaml(yaml.stringify(selected.spec));
|
|
2140
|
+
},
|
|
2141
|
+
[setTemplateYaml]
|
|
2142
|
+
);
|
|
2052
2143
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement("main", {
|
|
2053
2144
|
className: classes.root
|
|
2054
2145
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
@@ -2123,31 +2214,34 @@ function TemplateEditorPage(props) {
|
|
|
2123
2214
|
}), content);
|
|
2124
2215
|
}
|
|
2125
2216
|
|
|
2126
|
-
const useStyles = makeStyles(
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2217
|
+
const useStyles = makeStyles(
|
|
2218
|
+
(theme) => ({
|
|
2219
|
+
root: {
|
|
2220
|
+
backgroundColor: "rgba(0, 0, 0, .11)",
|
|
2221
|
+
boxShadow: "none",
|
|
2222
|
+
margin: theme.spacing(1, 0, 1, 0)
|
|
2223
|
+
},
|
|
2224
|
+
title: {
|
|
2225
|
+
margin: theme.spacing(1, 0, 0, 1),
|
|
2226
|
+
textTransform: "uppercase",
|
|
2227
|
+
fontSize: 12,
|
|
2228
|
+
fontWeight: "bold"
|
|
2229
|
+
},
|
|
2230
|
+
listIcon: {
|
|
2231
|
+
minWidth: 30,
|
|
2232
|
+
color: theme.palette.text.primary
|
|
2233
|
+
},
|
|
2234
|
+
menuItem: {
|
|
2235
|
+
minHeight: theme.spacing(6)
|
|
2236
|
+
},
|
|
2237
|
+
groupWrapper: {
|
|
2238
|
+
margin: theme.spacing(1, 1, 2, 1)
|
|
2239
|
+
}
|
|
2240
|
+
}),
|
|
2241
|
+
{
|
|
2242
|
+
name: "ScaffolderReactOwnerListPicker"
|
|
2147
2243
|
}
|
|
2148
|
-
|
|
2149
|
-
name: "ScaffolderReactOwnerListPicker"
|
|
2150
|
-
});
|
|
2244
|
+
);
|
|
2151
2245
|
function getFilterGroups() {
|
|
2152
2246
|
return [
|
|
2153
2247
|
{
|
|
@@ -2209,7 +2303,10 @@ const CreatedAtColumn = ({ createdAt }) => {
|
|
|
2209
2303
|
const OwnerEntityColumn = ({ entityRef }) => {
|
|
2210
2304
|
var _a, _b, _c;
|
|
2211
2305
|
const catalogApi = useApi(catalogApiRef);
|
|
2212
|
-
const { value, loading, error } = useAsync(
|
|
2306
|
+
const { value, loading, error } = useAsync(
|
|
2307
|
+
() => catalogApi.getEntityByRef(entityRef || ""),
|
|
2308
|
+
[catalogApi, entityRef]
|
|
2309
|
+
);
|
|
2213
2310
|
if (!entityRef) {
|
|
2214
2311
|
return /* @__PURE__ */ React.createElement("p", null, "Unknown");
|
|
2215
2312
|
}
|
|
@@ -2236,7 +2333,10 @@ const TaskStatusColumn = ({ status }) => {
|
|
|
2236
2333
|
|
|
2237
2334
|
const TemplateTitleColumn = ({ entityRef }) => {
|
|
2238
2335
|
const scaffolder = useApi(scaffolderApiRef);
|
|
2239
|
-
const { value, loading, error } = useAsync(
|
|
2336
|
+
const { value, loading, error } = useAsync(
|
|
2337
|
+
() => scaffolder.getTemplateParameterSchema(entityRef || ""),
|
|
2338
|
+
[scaffolder, entityRef]
|
|
2339
|
+
);
|
|
2240
2340
|
if (loading || error || !entityRef) {
|
|
2241
2341
|
return null;
|
|
2242
2342
|
}
|
|
@@ -2257,7 +2357,9 @@ const ListTaskPageContent = (props) => {
|
|
|
2257
2357
|
if (scaffolderApi.listTasks) {
|
|
2258
2358
|
return (_a2 = scaffolderApi.listTasks) == null ? void 0 : _a2.call(scaffolderApi, { filterByOwnership: ownerFilter });
|
|
2259
2359
|
}
|
|
2260
|
-
console.warn(
|
|
2360
|
+
console.warn(
|
|
2361
|
+
"listTasks is not implemented in the scaffolderApi, please make sure to implement this method."
|
|
2362
|
+
);
|
|
2261
2363
|
return Promise.resolve({ tasks: [] });
|
|
2262
2364
|
}, [scaffolderApi, ownerFilter]);
|
|
2263
2365
|
if (loading) {
|
|
@@ -2342,19 +2444,31 @@ const Router = (props) => {
|
|
|
2342
2444
|
const { TemplateCardComponent, TaskPageComponent } = components;
|
|
2343
2445
|
const outlet = useOutlet();
|
|
2344
2446
|
const TaskPageElement = TaskPageComponent != null ? TaskPageComponent : TaskPage;
|
|
2345
|
-
const customFieldExtensions = useElementFilter(
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2447
|
+
const customFieldExtensions = useElementFilter(
|
|
2448
|
+
outlet,
|
|
2449
|
+
(elements) => elements.selectByComponentData({
|
|
2450
|
+
key: FIELD_EXTENSION_WRAPPER_KEY
|
|
2451
|
+
}).findComponentData({
|
|
2452
|
+
key: FIELD_EXTENSION_KEY
|
|
2453
|
+
})
|
|
2454
|
+
);
|
|
2350
2455
|
const fieldExtensions = [
|
|
2351
2456
|
...customFieldExtensions,
|
|
2352
|
-
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(
|
|
2457
|
+
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(
|
|
2458
|
+
({ name }) => !customFieldExtensions.some(
|
|
2459
|
+
(customFieldExtension) => customFieldExtension.name === name
|
|
2460
|
+
)
|
|
2461
|
+
)
|
|
2353
2462
|
];
|
|
2354
2463
|
const RedirectingComponent = () => {
|
|
2355
2464
|
const { templateName } = useParams$1();
|
|
2356
2465
|
const newLink = useRouteRef(selectedTemplateRouteRef);
|
|
2357
|
-
useEffect(
|
|
2466
|
+
useEffect(
|
|
2467
|
+
() => console.warn(
|
|
2468
|
+
"The route /template/:templateName is deprecated, please use the new /template/:namespace/:templateName route instead"
|
|
2469
|
+
),
|
|
2470
|
+
[]
|
|
2471
|
+
);
|
|
2358
2472
|
return /* @__PURE__ */ React.createElement(Navigate, {
|
|
2359
2473
|
to: newLink({ namespace: "default", templateName })
|
|
2360
2474
|
});
|
|
@@ -2396,4 +2510,4 @@ const Router = (props) => {
|
|
|
2396
2510
|
};
|
|
2397
2511
|
|
|
2398
2512
|
export { Router };
|
|
2399
|
-
//# sourceMappingURL=Router-
|
|
2513
|
+
//# sourceMappingURL=Router-fa1fcf0c.esm.js.map
|