@backstage/plugin-scaffolder 0.12.2-next.0 → 0.13.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.
@@ -1,14 +1,14 @@
1
+ import { parseEntityRef, KubernetesValidatorFunctions, makeValidator, RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
1
2
  import { createApiRef, useApi, attachComponentData, createExternalRouteRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, useRouteRef, alertApiRef, useApp } from '@backstage/core-plugin-api';
2
3
  import { ResponseError } from '@backstage/errors';
3
4
  import qs from 'qs';
4
5
  import ObservableImpl from 'zen-observable';
5
- import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks, useEntityListProvider, useEntityTypeFilter, entityRouteRef } from '@backstage/plugin-catalog-react';
6
+ import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks, useEntityList, useEntityTypeFilter, entityRouteRef } from '@backstage/plugin-catalog-react';
6
7
  import { TextField, FormControl as FormControl$1, withStyles, makeStyles, IconButton, Tooltip, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, Link, FormControlLabel, Checkbox, Grid, StepButton, Paper, Button as Button$1, CircularProgress } from '@material-ui/core';
7
8
  import FormControl from '@material-ui/core/FormControl';
8
9
  import Autocomplete from '@material-ui/lab/Autocomplete';
9
10
  import React, { useCallback, useEffect, useState, createContext, useContext, useMemo, memo } from 'react';
10
11
  import useAsync from 'react-use/lib/useAsync';
11
- import { KubernetesValidatorFunctions, makeValidator, RELATION_OWNED_BY, stringifyEntityRef, parseEntityName } from '@backstage/catalog-model';
12
12
  import useEffectOnce from 'react-use/lib/useEffectOnce';
13
13
  import { Autocomplete as Autocomplete$1 } from '@material-ui/lab';
14
14
  import { scmIntegrationsApiRef, scmAuthApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
@@ -52,15 +52,20 @@ class ScaffolderClient {
52
52
  this.useLongPollingLogs = (_b = options.useLongPollingLogs) != null ? _b : false;
53
53
  }
54
54
  async getIntegrationsList(options) {
55
- return [
55
+ const integrations = [
56
56
  ...this.scmIntegrationsApi.azure.list(),
57
57
  ...this.scmIntegrationsApi.bitbucket.list(),
58
58
  ...this.scmIntegrationsApi.github.list(),
59
59
  ...this.scmIntegrationsApi.gitlab.list()
60
60
  ].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
61
+ return {
62
+ integrations
63
+ };
61
64
  }
62
- async getTemplateParameterSchema(templateName) {
63
- const { namespace, kind, name } = templateName;
65
+ async getTemplateParameterSchema(templateRef) {
66
+ const { namespace, kind, name } = parseEntityRef(templateRef, {
67
+ defaultKind: "template"
68
+ });
64
69
  const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
65
70
  const templatePath = [namespace, kind, name].map((s) => encodeURIComponent(s)).join("/");
66
71
  const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;
@@ -71,7 +76,8 @@ class ScaffolderClient {
71
76
  const schema = await response.json();
72
77
  return schema;
73
78
  }
74
- async scaffold(templateName, values, secrets = {}) {
79
+ async scaffold(options) {
80
+ const { templateRef, values, secrets = {} } = options;
75
81
  const url = `${await this.discoveryApi.getBaseUrl("scaffolder")}/v2/tasks`;
76
82
  const response = await this.fetchApi.fetch(url, {
77
83
  method: "POST",
@@ -79,7 +85,7 @@ class ScaffolderClient {
79
85
  "Content-Type": "application/json"
80
86
  },
81
87
  body: JSON.stringify({
82
- templateName,
88
+ templateRef,
83
89
  values: { ...values },
84
90
  secrets
85
91
  })
@@ -90,7 +96,7 @@ class ScaffolderClient {
90
96
  throw new Error(`Backend request failed, ${status} ${body.trim()}`);
91
97
  }
92
98
  const { id } = await response.json();
93
- return id;
99
+ return { taskId: id };
94
100
  }
95
101
  async getTask(taskId) {
96
102
  const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
@@ -184,20 +190,17 @@ class ScaffolderClient {
184
190
  }
185
191
  }
186
192
 
187
- const allowArbitraryValues = (uiSchema) => {
188
- var _a, _b;
189
- return (_b = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowArbitraryValues) != null ? _b : true;
190
- };
191
- const EntityPicker = ({
192
- onChange,
193
- schema: { title = "Entity", description = "An entity from the catalog" },
194
- required,
195
- uiSchema,
196
- rawErrors,
197
- formData,
198
- idSchema
199
- }) => {
200
- var _a, _b;
193
+ const EntityPicker = (props) => {
194
+ var _a, _b, _c, _d;
195
+ const {
196
+ onChange,
197
+ schema: { title = "Entity", description = "An entity from the catalog" },
198
+ required,
199
+ uiSchema,
200
+ rawErrors,
201
+ formData,
202
+ idSchema
203
+ } = props;
201
204
  const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
202
205
  const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
203
206
  const catalogApi = useApi(catalogApiRef);
@@ -223,7 +226,7 @@ const EntityPicker = ({
223
226
  onChange: onSelect,
224
227
  options: entityRefs || [],
225
228
  autoSelect: true,
226
- freeSolo: allowArbitraryValues(uiSchema),
229
+ freeSolo: (_d = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.allowArbitraryValues) != null ? _d : true,
227
230
  renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, {
228
231
  ...params,
229
232
  label: title,
@@ -236,35 +239,30 @@ const EntityPicker = ({
236
239
  }));
237
240
  };
238
241
 
239
- const TextValuePicker = ({
240
- onChange,
241
- required,
242
- schema: { title, description },
243
- rawErrors,
244
- formData,
245
- uiSchema: { "ui:autofocus": autoFocus },
246
- idSchema,
247
- placeholder
248
- }) => /* @__PURE__ */ React.createElement(TextField, {
249
- id: idSchema == null ? void 0 : idSchema.$id,
250
- label: title,
251
- placeholder,
252
- helperText: description,
253
- required,
254
- value: formData != null ? formData : "",
255
- onChange: ({ target: { value } }) => onChange(value),
256
- margin: "normal",
257
- error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
258
- inputProps: { autoFocus }
259
- });
260
-
261
- const EntityNamePicker = ({
262
- schema: { title = "Name", description = "Unique name of the component" },
263
- ...props
264
- }) => /* @__PURE__ */ React.createElement(TextValuePicker, {
265
- schema: { title, description },
266
- ...props
267
- });
242
+ const EntityNamePicker = (props) => {
243
+ const {
244
+ onChange,
245
+ required,
246
+ schema: { title = "Name", description = "Unique name of the component" },
247
+ rawErrors,
248
+ formData,
249
+ uiSchema: { "ui:autofocus": autoFocus },
250
+ idSchema,
251
+ placeholder
252
+ } = props;
253
+ return /* @__PURE__ */ React.createElement(TextField, {
254
+ id: idSchema == null ? void 0 : idSchema.$id,
255
+ label: title,
256
+ placeholder,
257
+ helperText: description,
258
+ required,
259
+ value: formData != null ? formData : "",
260
+ onChange: ({ target: { value } }) => onChange(value),
261
+ margin: "normal",
262
+ error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
263
+ inputProps: { autoFocus }
264
+ });
265
+ };
268
266
 
269
267
  const entityNamePickerValidation = (value, validation) => {
270
268
  if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
@@ -272,12 +270,9 @@ const entityNamePickerValidation = (value, validation) => {
272
270
  }
273
271
  };
274
272
 
275
- const EntityTagsPicker = ({
276
- formData,
277
- onChange,
278
- uiSchema
279
- }) => {
273
+ const EntityTagsPicker = (props) => {
280
274
  var _a;
275
+ const { formData, onChange, uiSchema } = props;
281
276
  const catalogApi = useApi(catalogApiRef);
282
277
  const [inputValue, setInputValue] = useState("");
283
278
  const [inputError, setInputError] = useState(false);
@@ -334,12 +329,13 @@ const EntityTagsPicker = ({
334
329
  }));
335
330
  };
336
331
 
337
- const OwnerPicker = ({
338
- schema: { title = "Owner", description = "The owner of the component" },
339
- uiSchema,
340
- ...props
341
- }) => {
332
+ const OwnerPicker = (props) => {
342
333
  var _a;
334
+ const {
335
+ schema: { title = "Owner", description = "The owner of the component" },
336
+ uiSchema,
337
+ ...restProps
338
+ } = props;
343
339
  const ownerUiSchema = {
344
340
  ...uiSchema,
345
341
  "ui:options": {
@@ -351,7 +347,7 @@ const OwnerPicker = ({
351
347
  }
352
348
  };
353
349
  return /* @__PURE__ */ React.createElement(EntityPicker, {
354
- ...props,
350
+ ...restProps,
355
351
  schema: { title, description },
356
352
  uiSchema: ownerUiSchema
357
353
  });
@@ -502,7 +498,7 @@ const BitbucketRepoPicker = (props) => {
502
498
  const RepoUrlPickerHost = (props) => {
503
499
  const { host, hosts, onChange, rawErrors } = props;
504
500
  const scaffolderApi = useApi(scaffolderApiRef);
505
- const { value: integrations, loading } = useAsync(async () => {
501
+ const { value: { integrations } = { integrations: [] }, loading } = useAsync(async () => {
506
502
  return await scaffolderApi.getIntegrationsList({
507
503
  allowedHosts: hosts != null ? hosts : []
508
504
  });
@@ -700,16 +696,17 @@ const repoPickerValidation = (value, validation, context) => {
700
696
  }
701
697
  };
702
698
 
703
- const OwnedEntityPicker = ({
704
- onChange,
705
- schema: { title = "Entity", description = "An entity from the catalog" },
706
- required,
707
- uiSchema,
708
- rawErrors,
709
- formData,
710
- idSchema
711
- }) => {
699
+ const OwnedEntityPicker = (props) => {
712
700
  var _a, _b;
701
+ const {
702
+ onChange,
703
+ schema: { title = "Entity", description = "An entity from the catalog" },
704
+ required,
705
+ uiSchema,
706
+ rawErrors,
707
+ formData,
708
+ idSchema
709
+ } = props;
713
710
  const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
714
711
  const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
715
712
  const { ownedEntities, loading } = useOwnedEntities(allowedKinds);
@@ -807,7 +804,7 @@ const OwnerPickerFieldExtension = scaffolderPlugin.provide(createScaffolderField
807
804
  }));
808
805
  const ScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
809
806
  name: "ScaffolderPage",
810
- component: () => import('./Router-5df57206.esm.js').then((m) => m.Router),
807
+ component: () => import('./Router-8ca04a51.esm.js').then((m) => m.Router),
811
808
  mountPoint: rootRouteRef
812
809
  }));
813
810
  const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
@@ -906,13 +903,13 @@ const DeprecationWarning = () => {
906
903
  const styles = useDeprecationStyles();
907
904
  const Title = /* @__PURE__ */ React.createElement(Typography, {
908
905
  style: { padding: 10, maxWidth: 300 }
909
- }, "This template syntax is deprecated. Click for more info.");
906
+ }, "This template uses a syntax that has been deprecated, and should be migrated to a newer syntax. Click for more info.");
910
907
  return /* @__PURE__ */ React.createElement("div", {
911
908
  className: styles.deprecationIcon
912
909
  }, /* @__PURE__ */ React.createElement(Tooltip, {
913
910
  title: Title
914
911
  }, /* @__PURE__ */ React.createElement(Link, {
915
- href: "https://backstage.io/docs/features/software-templates/migrating-from-v1alpha1-to-v1beta2",
912
+ href: "https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3",
916
913
  className: styles.link
917
914
  }, /* @__PURE__ */ React.createElement(WarningIcon, null))));
918
915
  };
@@ -976,7 +973,7 @@ const TemplateList = ({
976
973
  TemplateCardComponent,
977
974
  group
978
975
  }) => {
979
- const { loading, error, entities } = useEntityListProvider();
976
+ const { loading, error, entities } = useEntityList();
980
977
  const Card = TemplateCardComponent || TemplateCard;
981
978
  const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
982
979
  const title = group ? group.titleComponent || /* @__PURE__ */ React.createElement(ContentHeader, {
@@ -995,7 +992,8 @@ const TemplateList = ({
995
992
  to: "https://backstage.io/docs/features/software-templates/adding-templates"
996
993
  }, "adding templates"), "."), /* @__PURE__ */ React.createElement(Content, null, title, /* @__PURE__ */ React.createElement(ItemCardGrid, null, maybeFilteredEntities && (maybeFilteredEntities == null ? void 0 : maybeFilteredEntities.length) > 0 && maybeFilteredEntities.map((template) => /* @__PURE__ */ React.createElement(Card, {
997
994
  key: stringifyEntityRef(template),
998
- template
995
+ template,
996
+ deprecated: template.apiVersion === "backstage.io/v1beta2"
999
997
  })))));
1000
998
  };
1001
999
 
@@ -1223,7 +1221,7 @@ const TaskPageLinks = ({ output }) => {
1223
1221
  pb: 3
1224
1222
  }, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
1225
1223
  if (entityRef) {
1226
- const entityName = parseEntityName(entityRef);
1224
+ const entityName = parseEntityRef(entityRef);
1227
1225
  const target = entityRoute(entityName);
1228
1226
  return { title, icon, url: target };
1229
1227
  }
@@ -1357,7 +1355,11 @@ const TaskStatusStepper = memo(({
1357
1355
  })))));
1358
1356
  })));
1359
1357
  });
1360
- const hasLinks = ({ entityRef, remoteUrl, links = [] }) => !!(entityRef || remoteUrl || links.length > 0);
1358
+ const hasLinks = ({
1359
+ entityRef,
1360
+ remoteUrl,
1361
+ links = []
1362
+ }) => !!(entityRef || remoteUrl || links.length > 0);
1361
1363
  const TaskPage = ({ loadingText }) => {
1362
1364
  const classes = useStyles();
1363
1365
  const navigate = useNavigate();
@@ -1400,15 +1402,17 @@ const TaskPage = ({ loadingText }) => {
1400
1402
  const taskNotFound = taskStream.completed === true && taskStream.loading === false && !taskStream.task;
1401
1403
  const { output } = taskStream;
1402
1404
  const handleStartOver = () => {
1403
- var _a, _b;
1404
- if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.metadata) == null ? void 0 : _b.name)) {
1405
+ var _a, _b, _c;
1406
+ if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.templateInfo) == null ? void 0 : _b.entityRef)) {
1405
1407
  navigate(generatePath(rootLink()));
1408
+ return;
1406
1409
  }
1407
1410
  const formData = taskStream.task.spec.apiVersion === "backstage.io/v1beta2" ? taskStream.task.spec.values : taskStream.task.spec.parameters;
1411
+ const { name } = parseEntityRef((_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef);
1408
1412
  navigate(generatePath(`${rootLink()}/templates/:templateName?${qs.stringify({
1409
1413
  formData: JSON.stringify(formData)
1410
1414
  })}`, {
1411
- templateName: taskStream.task.spec.metadata.name
1415
+ templateName: name
1412
1416
  }));
1413
1417
  };
1414
1418
  return /* @__PURE__ */ React.createElement(Page, {
@@ -1451,5 +1455,5 @@ const TaskPage = ({ loadingText }) => {
1451
1455
  })))))));
1452
1456
  };
1453
1457
 
1454
- export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, EntityNamePicker as a, EntityTagsPicker as b, OwnedEntityPicker as c, registerComponentRouteRef as d, entityNamePickerValidation as e, TemplateList as f, rootRouteRef as g, FIELD_EXTENSION_KEY as h, SecretsContextProvider as i, TaskPage as j, ScaffolderClient as k, createScaffolderFieldExtension as l, ScaffolderFieldExtensions as m, EntityPickerFieldExtension as n, EntityNamePickerFieldExtension as o, EntityTagsPickerFieldExtension as p, OwnerPickerFieldExtension as q, repoPickerValidation as r, scaffolderApiRef as s, OwnedEntityPickerFieldExtension as t, RepoUrlPickerFieldExtension as u, ScaffolderPage as v, scaffolderPlugin as w, TextValuePicker as x, FavouriteTemplate as y, useTemplateSecrets as z };
1455
- //# sourceMappingURL=index-71578268.esm.js.map
1458
+ export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, EntityNamePicker as a, EntityTagsPicker as b, OwnedEntityPicker as c, registerComponentRouteRef as d, entityNamePickerValidation as e, TemplateList as f, rootRouteRef as g, FIELD_EXTENSION_KEY as h, SecretsContextProvider as i, TaskPage as j, ScaffolderClient as k, createScaffolderFieldExtension as l, ScaffolderFieldExtensions as m, EntityPickerFieldExtension as n, EntityNamePickerFieldExtension as o, EntityTagsPickerFieldExtension as p, OwnerPickerFieldExtension as q, repoPickerValidation as r, scaffolderApiRef as s, OwnedEntityPickerFieldExtension as t, RepoUrlPickerFieldExtension as u, ScaffolderPage as v, scaffolderPlugin as w, FavouriteTemplate as x, useTemplateSecrets as y };
1459
+ //# sourceMappingURL=index-7ce19edf.esm.js.map