@backstage/plugin-scaffolder 0.12.3 → 0.15.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +146 -0
- package/dist/esm/{Router-fe84df85.esm.js → Router-722c3528.esm.js} +232 -45
- package/dist/esm/Router-722c3528.esm.js.map +1 -0
- package/dist/esm/{index-87e5c74b.esm.js → index-3fd3ab40.esm.js} +140 -302
- package/dist/esm/index-3fd3ab40.esm.js.map +1 -0
- package/dist/index.d.ts +264 -112
- package/dist/index.esm.js +3 -6
- package/dist/index.esm.js.map +1 -1
- package/package.json +21 -20
- package/dist/esm/Router-fe84df85.esm.js.map +0 -1
- package/dist/esm/index-87e5c74b.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,151 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 0.15.0-next.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 310e905998: The following deprecations are now breaking and have been removed:
|
|
8
|
+
|
|
9
|
+
- **BREAKING**: Support for `backstage.io/v1beta2` Software Templates has been removed. Please migrate your legacy templates to the new `scaffolder.backstage.io/v1beta3` `apiVersion` by following the [migration guide](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3)
|
|
10
|
+
|
|
11
|
+
- **BREAKING**: Removed the deprecated `TemplateMetadata`. Please use `TemplateInfo` instead.
|
|
12
|
+
|
|
13
|
+
- **BREAKING**: Removed the deprecated `context.baseUrl`. It's now available on `context.templateInfo.baseUrl`.
|
|
14
|
+
|
|
15
|
+
- **BREAKING**: Removed the deprecated `DispatchResult`, use `TaskBrokerDispatchResult` instead.
|
|
16
|
+
|
|
17
|
+
- **BREAKING**: Removed the deprecated `runCommand`, use `executeShellCommond` instead.
|
|
18
|
+
|
|
19
|
+
- **BREAKING**: Removed the deprecated `Status` in favour of `TaskStatus` instead.
|
|
20
|
+
|
|
21
|
+
- **BREAKING**: Removed the deprecated `TaskState` in favour of `CurrentClaimedTask` instead.
|
|
22
|
+
|
|
23
|
+
- 1360f7d73a: **BREAKING**: Removed `ScaffolderTaskOutput.entityRef` and `ScaffolderTaskOutput.remoteUrl`, which both have been deprecated for over a year. Please use the `links` output instead.
|
|
24
|
+
- e63e5a9452: Removed the following previously deprecated exports:
|
|
25
|
+
|
|
26
|
+
- **BREAKING**: Removed the deprecated `TemplateList` component and the `TemplateListProps` type. Please use the `TemplateCard` to create your own list component instead to render these lists.
|
|
27
|
+
|
|
28
|
+
- **BREAKING**: Removed the deprecated `setSecret` method, please use `setSecrets` instead.
|
|
29
|
+
|
|
30
|
+
- **BREAKING**: Removed the deprecated `TemplateCardComponent` and `TaskPageComponent` props from the `ScaffolderPage` component. These are now provided using the `components` prop with the shape `{{ TemplateCardComponent: () => JSX.Element, TaskPageComponent: () => JSX.Element }}`
|
|
31
|
+
|
|
32
|
+
- **BREAKING**: Removed `JobStatus` as this type was actually a legacy type used in `v1alpha` templates and the workflow engine and should no longer be used or depended on.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- d741c97b98: Render markdown for description in software templates
|
|
37
|
+
- Updated dependencies
|
|
38
|
+
- @backstage/plugin-catalog-react@0.9.0-next.0
|
|
39
|
+
- @backstage/core-components@0.9.1-next.0
|
|
40
|
+
- @backstage/plugin-scaffolder-common@0.3.0-next.0
|
|
41
|
+
- @backstage/catalog-model@0.13.0-next.0
|
|
42
|
+
- @backstage/plugin-catalog-common@0.2.2-next.0
|
|
43
|
+
- @backstage/catalog-client@0.9.0-next.0
|
|
44
|
+
- @backstage/integration-react@0.1.25-next.0
|
|
45
|
+
|
|
46
|
+
## 0.14.0
|
|
47
|
+
|
|
48
|
+
### Minor Changes
|
|
49
|
+
|
|
50
|
+
- 1c2755991d: - **BREAKING**: Removed the `FavouriteTemplate` export in favor of the `FavoriteEntity` from `@backstage/plugin-catalog-react`. Please migrate any usages to that component instead if you are creating your own `TemplateCard` page.
|
|
51
|
+
- 86da51cec5: **BREAKING**: Removing the exports of the raw components that back the `CustomFieldExtensions`.
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- f41a293231: - **DEPRECATION**: Deprecated `formatEntityRefTitle` in favor of the new `humanizeEntityRef` method instead. Please migrate to using the new method instead.
|
|
56
|
+
- 55361f3f7b: Added some deprecations as follows:
|
|
57
|
+
|
|
58
|
+
- **DEPRECATED**: `TemplateCardComponent` and `TaskPageComponent` props have been deprecated, and moved to a `components` prop instead. You can pass them in through there instead.
|
|
59
|
+
- **DEPRECATED**: `TemplateList` and `TemplateListProps` has been deprecated. Please use the `TemplateCard` to create your own list component instead.
|
|
60
|
+
- **DEPRECATED**: `setSecret` has been deprecated in favour of `setSecrets` when calling `useTemplateSecrets`
|
|
61
|
+
|
|
62
|
+
Other notable changes:
|
|
63
|
+
|
|
64
|
+
- `scaffolderApi.scaffold()` `values` type has been narrowed from `Record<string, any>` to `Record<string, JsonValue>` instead.
|
|
65
|
+
- Moved all navigation internally over to using `routeRefs` and `subRouteRefs`
|
|
66
|
+
|
|
67
|
+
- Updated dependencies
|
|
68
|
+
- @backstage/catalog-model@0.12.0
|
|
69
|
+
- @backstage/catalog-client@0.8.0
|
|
70
|
+
- @backstage/core-components@0.9.0
|
|
71
|
+
- @backstage/plugin-catalog-react@0.8.0
|
|
72
|
+
- @backstage/plugin-catalog-common@0.2.0
|
|
73
|
+
- @backstage/integration@0.8.0
|
|
74
|
+
- @backstage/core-plugin-api@0.8.0
|
|
75
|
+
- @backstage/plugin-scaffolder-common@0.2.3
|
|
76
|
+
- @backstage/integration-react@0.1.24
|
|
77
|
+
- @backstage/plugin-permission-react@0.3.3
|
|
78
|
+
|
|
79
|
+
## 0.13.0
|
|
80
|
+
|
|
81
|
+
### Minor Changes
|
|
82
|
+
|
|
83
|
+
- 50e0242ac2: - **BREAKING** - `scaffolderApi.scaffold()` now takes one `options` argument instead of 3, the existing arguments should just be wrapped up in one object instead.
|
|
84
|
+
- **BREAKING** - `scaffolderApi.scaffold()` now returns an object instead of a single string for the job ID. It's now `{ taskId: string }`
|
|
85
|
+
- **BREAKING** - `scaffolderApi.scaffold()` now takes a `templateRef` instead of `templateName` as an argument in the options. This should be a valid stringified `entityRef`.
|
|
86
|
+
- **BREAKING** - `scaffolderApi.getIntegrationsList` now returns an object `{ integrations: { type: string, title: string, host: string }[] }` instead of just an array.
|
|
87
|
+
- a2589000ee: - **BREAKING** - Removed the `plugin` export, use `scaffolderPlugin` instead.
|
|
88
|
+
- **BREAKING** - Removed the `TextValuePicker` component export, you can inline this component instead as it's a simple wrapper around a `TextField` from `@material-ui/core`.
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- 67a7c02d26: Remove usages of `EntityRef` and `parseEntityName` from `@backstage/catalog-model`
|
|
93
|
+
- 6e1cbc12a6: Updated according to the new `getEntityFacets` catalog API method
|
|
94
|
+
- b776ce5aab: Replaced use of deprecated `useEntityListProvider` hook with `useEntityList`.
|
|
95
|
+
- 0f37cdef19: Migrated over from the deprecated `spec.metadata` to `spec.templateInfo` for the `name` and the `baseUrl` of the template.
|
|
96
|
+
- 50e0242ac2: - Moved the `JSONSchema` type from `@backstage/catalog-model` to `JSONSchema7`.
|
|
97
|
+
- Renamed and prefixed some types ready for exporting.
|
|
98
|
+
- a2589000ee: - Reworking the `FieldExtensionComponentType` so we can export the `ui:schema:options` props in the `api-report.md`.
|
|
99
|
+
- Exporting all of the `UiOptions` types for the `FieldExtensions` so we can see them in the `api-report.md`.
|
|
100
|
+
- Removing the redundant type in the `CustomFieldValidator` union.
|
|
101
|
+
- 2f2543592c: You can now hide sections or fields in your templates based on a feature flag. For example, take this template:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
title: 'my-schema',
|
|
106
|
+
steps: [
|
|
107
|
+
{
|
|
108
|
+
title: 'Fill in some steps',
|
|
109
|
+
schema: {
|
|
110
|
+
title: 'Fill in some steps',
|
|
111
|
+
'backstage:featureFlag': 'experimental-feature',
|
|
112
|
+
properties: {
|
|
113
|
+
name: {
|
|
114
|
+
title: 'Name',
|
|
115
|
+
type: 'string',
|
|
116
|
+
'backstage:featureFlag': 'should-show-some-stuff-first-option',
|
|
117
|
+
},
|
|
118
|
+
description: {
|
|
119
|
+
title: 'Description',
|
|
120
|
+
type: 'string',
|
|
121
|
+
description: 'A description for the component',
|
|
122
|
+
},
|
|
123
|
+
owner: {
|
|
124
|
+
title: 'Owner',
|
|
125
|
+
type: 'string',
|
|
126
|
+
description: 'Owner of the component',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
type: 'object',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If you have a feature flag that is called `experimental-feature` then your first step would be shown if you that feature flag was not active then it wouldn't be shown. The same goes for the properties in the schema. Make sure to use the key `backstage:featureFlag` in your templates if you want to use this functionality.
|
|
137
|
+
|
|
138
|
+
- Updated dependencies
|
|
139
|
+
- @backstage/core-components@0.8.10
|
|
140
|
+
- @backstage/plugin-scaffolder-common@0.2.2
|
|
141
|
+
- @backstage/plugin-catalog-react@0.7.0
|
|
142
|
+
- @backstage/catalog-model@0.11.0
|
|
143
|
+
- @backstage/catalog-client@0.7.2
|
|
144
|
+
- @backstage/core-plugin-api@0.7.0
|
|
145
|
+
- @backstage/integration@0.7.5
|
|
146
|
+
- @backstage/integration-react@0.1.23
|
|
147
|
+
- @backstage/plugin-permission-react@0.3.2
|
|
148
|
+
|
|
3
149
|
## 0.12.3
|
|
4
150
|
|
|
5
151
|
### Patch Changes
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React, { useState, useContext, useCallback } from 'react';
|
|
2
|
-
import { useNavigate, Navigate,
|
|
3
|
-
import {
|
|
4
|
-
import { useRouteRef, useApi, errorApiRef, useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
|
-
import { EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker } from '@backstage/plugin-catalog-react';
|
|
6
|
-
import { makeStyles, Stepper, Step, StepLabel,
|
|
7
|
-
import { E as EntityPicker, a as EntityNamePicker, e as entityNamePickerValidation, b as EntityTagsPicker, R as RepoUrlPicker, r as repoPickerValidation, O as OwnerPicker, c as OwnedEntityPicker,
|
|
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, Lifecycle, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage } from '@backstage/core-components';
|
|
4
|
+
import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
|
+
import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker } from '@backstage/plugin-catalog-react';
|
|
6
|
+
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 } from '@material-ui/core';
|
|
7
|
+
import { E as EntityPicker, a as EntityNamePicker, e as entityNamePickerValidation, b as EntityTagsPicker, R as RepoUrlPicker, r as repoPickerValidation, O as OwnerPicker, c as OwnedEntityPicker, s as selectedTemplateRouteRef, d as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, f as scaffolderApiRef, g as scaffolderTaskRouteRef, h as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, i as FIELD_EXTENSION_KEY, j as SecretsContextProvider, k as TaskPage } from './index-3fd3ab40.esm.js';
|
|
8
|
+
import { RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
|
|
9
|
+
import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
10
|
+
import WarningIcon from '@material-ui/icons/Warning';
|
|
8
11
|
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
|
|
9
12
|
import { usePermission } from '@backstage/plugin-permission-react';
|
|
10
13
|
import qs from 'qs';
|
|
@@ -12,22 +15,18 @@ import { useParams } from 'react-router-dom';
|
|
|
12
15
|
import useAsync from 'react-use/lib/useAsync';
|
|
13
16
|
import { withTheme } from '@rjsf/core';
|
|
14
17
|
import { Theme } from '@rjsf/material-ui';
|
|
18
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
15
19
|
import classNames from 'classnames';
|
|
16
20
|
import '@backstage/errors';
|
|
17
21
|
import 'zen-observable';
|
|
18
22
|
import '@material-ui/core/FormControl';
|
|
19
23
|
import '@material-ui/lab/Autocomplete';
|
|
20
|
-
import '@backstage/catalog-model';
|
|
21
24
|
import 'react-use/lib/useEffectOnce';
|
|
22
25
|
import '@material-ui/lab';
|
|
23
|
-
import '@backstage/integration-react';
|
|
24
26
|
import '@material-ui/core/FormHelperText';
|
|
25
27
|
import '@material-ui/core/Input';
|
|
26
28
|
import '@material-ui/core/InputLabel';
|
|
27
29
|
import 'react-use/lib/useDebounce';
|
|
28
|
-
import '@material-ui/icons/Star';
|
|
29
|
-
import '@material-ui/icons/StarBorder';
|
|
30
|
-
import '@material-ui/icons/Warning';
|
|
31
30
|
import 'lodash/capitalize';
|
|
32
31
|
import '@material-ui/icons/CheckBox';
|
|
33
32
|
import '@material-ui/icons/CheckBoxOutlineBlank';
|
|
@@ -75,6 +74,173 @@ const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [
|
|
|
75
74
|
}
|
|
76
75
|
];
|
|
77
76
|
|
|
77
|
+
const useStyles$2 = makeStyles((theme) => ({
|
|
78
|
+
cardHeader: {
|
|
79
|
+
position: "relative"
|
|
80
|
+
},
|
|
81
|
+
title: {
|
|
82
|
+
backgroundImage: ({ backgroundImage }) => backgroundImage
|
|
83
|
+
},
|
|
84
|
+
box: {
|
|
85
|
+
overflow: "hidden",
|
|
86
|
+
textOverflow: "ellipsis",
|
|
87
|
+
display: "-webkit-box",
|
|
88
|
+
"-webkit-line-clamp": 10,
|
|
89
|
+
"-webkit-box-orient": "vertical",
|
|
90
|
+
paddingBottom: "0.8em"
|
|
91
|
+
},
|
|
92
|
+
label: {
|
|
93
|
+
color: theme.palette.text.secondary,
|
|
94
|
+
textTransform: "uppercase",
|
|
95
|
+
fontSize: "0.65rem",
|
|
96
|
+
fontWeight: "bold",
|
|
97
|
+
letterSpacing: 0.5,
|
|
98
|
+
lineHeight: 1,
|
|
99
|
+
paddingBottom: "0.2rem"
|
|
100
|
+
},
|
|
101
|
+
leftButton: {
|
|
102
|
+
marginRight: "auto"
|
|
103
|
+
},
|
|
104
|
+
starButton: {
|
|
105
|
+
position: "absolute",
|
|
106
|
+
top: theme.spacing(0.5),
|
|
107
|
+
right: theme.spacing(0.5),
|
|
108
|
+
padding: "0.25rem"
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
const useDeprecationStyles = makeStyles((theme) => ({
|
|
112
|
+
deprecationIcon: {
|
|
113
|
+
position: "absolute",
|
|
114
|
+
top: theme.spacing(0.5),
|
|
115
|
+
right: theme.spacing(3.5),
|
|
116
|
+
padding: "0.25rem"
|
|
117
|
+
},
|
|
118
|
+
link: {
|
|
119
|
+
color: theme.palette.warning.light
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
const getTemplateCardProps = (template) => {
|
|
123
|
+
var _a, _b, _c, _d, _e;
|
|
124
|
+
return {
|
|
125
|
+
key: template.metadata.uid,
|
|
126
|
+
name: template.metadata.name,
|
|
127
|
+
title: `${(_a = template.metadata.title || template.metadata.name) != null ? _a : ""}`,
|
|
128
|
+
type: (_b = template.spec.type) != null ? _b : "",
|
|
129
|
+
description: (_c = template.metadata.description) != null ? _c : "-",
|
|
130
|
+
tags: (_e = (_d = template.metadata) == null ? void 0 : _d.tags) != null ? _e : []
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const DeprecationWarning = () => {
|
|
134
|
+
const styles = useDeprecationStyles();
|
|
135
|
+
const Title = /* @__PURE__ */ React.createElement(Typography, {
|
|
136
|
+
style: { padding: 10, maxWidth: 300 }
|
|
137
|
+
}, "This template uses a syntax that has been deprecated, and should be migrated to a newer syntax. Click for more info.");
|
|
138
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
139
|
+
className: styles.deprecationIcon
|
|
140
|
+
}, /* @__PURE__ */ React.createElement(Tooltip, {
|
|
141
|
+
title: Title
|
|
142
|
+
}, /* @__PURE__ */ React.createElement(Link, {
|
|
143
|
+
href: "https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3",
|
|
144
|
+
className: styles.link
|
|
145
|
+
}, /* @__PURE__ */ React.createElement(WarningIcon, null))));
|
|
146
|
+
};
|
|
147
|
+
const TemplateCard = ({ template, deprecated }) => {
|
|
148
|
+
var _a;
|
|
149
|
+
const backstageTheme = useTheme();
|
|
150
|
+
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
151
|
+
const templateProps = getTemplateCardProps(template);
|
|
152
|
+
const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
|
|
153
|
+
const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type }) ? templateProps.type : "other";
|
|
154
|
+
const theme = backstageTheme.getPageTheme({ themeId });
|
|
155
|
+
const classes = useStyles$2({ backgroundImage: theme.backgroundImage });
|
|
156
|
+
const href = templateRoute({ templateName: templateProps.name });
|
|
157
|
+
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
|
158
|
+
const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);
|
|
159
|
+
return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardMedia, {
|
|
160
|
+
className: classes.cardHeader
|
|
161
|
+
}, /* @__PURE__ */ React.createElement(FavoriteEntity, {
|
|
162
|
+
className: classes.starButton,
|
|
163
|
+
entity: template
|
|
164
|
+
}), deprecated && /* @__PURE__ */ React.createElement(DeprecationWarning, null), /* @__PURE__ */ React.createElement(ItemCardHeader, {
|
|
165
|
+
title: templateProps.title,
|
|
166
|
+
subtitle: templateProps.type,
|
|
167
|
+
classes: { root: classes.title }
|
|
168
|
+
})), /* @__PURE__ */ React.createElement(CardContent, {
|
|
169
|
+
style: { display: "grid" }
|
|
170
|
+
}, /* @__PURE__ */ React.createElement(Box, {
|
|
171
|
+
className: classes.box
|
|
172
|
+
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
173
|
+
variant: "body2",
|
|
174
|
+
className: classes.label
|
|
175
|
+
}, "Description"), /* @__PURE__ */ React.createElement(MarkdownContent, {
|
|
176
|
+
content: templateProps.description
|
|
177
|
+
})), /* @__PURE__ */ React.createElement(Box, {
|
|
178
|
+
className: classes.box
|
|
179
|
+
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
180
|
+
variant: "body2",
|
|
181
|
+
className: classes.label
|
|
182
|
+
}, "Owner"), /* @__PURE__ */ React.createElement(EntityRefLinks, {
|
|
183
|
+
entityRefs: ownedByRelations,
|
|
184
|
+
defaultKind: "Group"
|
|
185
|
+
})), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, {
|
|
186
|
+
variant: "body2",
|
|
187
|
+
className: classes.label
|
|
188
|
+
}, "Tags"), (_a = templateProps.tags) == null ? void 0 : _a.map((tag) => /* @__PURE__ */ React.createElement(Chip, {
|
|
189
|
+
size: "small",
|
|
190
|
+
label: tag,
|
|
191
|
+
key: tag
|
|
192
|
+
})))), /* @__PURE__ */ React.createElement(CardActions, null, sourceLocation && /* @__PURE__ */ React.createElement(IconButton, {
|
|
193
|
+
className: classes.leftButton,
|
|
194
|
+
href: sourceLocation.locationTargetUrl
|
|
195
|
+
}, /* @__PURE__ */ React.createElement(ScmIntegrationIcon, {
|
|
196
|
+
type: sourceLocation.integrationType
|
|
197
|
+
})), /* @__PURE__ */ React.createElement(Button, {
|
|
198
|
+
color: "primary",
|
|
199
|
+
to: href,
|
|
200
|
+
"aria-label": `Choose ${templateProps.title}`
|
|
201
|
+
}, "Choose")));
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const TemplateList = ({
|
|
205
|
+
TemplateCardComponent,
|
|
206
|
+
group
|
|
207
|
+
}) => {
|
|
208
|
+
const { loading, error, entities } = useEntityList();
|
|
209
|
+
const Card = TemplateCardComponent || TemplateCard;
|
|
210
|
+
const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
|
|
211
|
+
const titleComponent = (() => {
|
|
212
|
+
if (group == null ? void 0 : group.titleComponent) {
|
|
213
|
+
console.warn("DEPRECATED: group.titleComponent is now deprecated. Use group.title instead, it can be a string or a react component");
|
|
214
|
+
return group == null ? void 0 : group.titleComponent;
|
|
215
|
+
}
|
|
216
|
+
if (group && group.title) {
|
|
217
|
+
if (typeof group.title === "string") {
|
|
218
|
+
return /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
219
|
+
title: group.title
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return group.title;
|
|
223
|
+
}
|
|
224
|
+
return /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
225
|
+
title: "Other Templates"
|
|
226
|
+
});
|
|
227
|
+
})();
|
|
228
|
+
if (group && maybeFilteredEntities.length === 0) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(Progress, null), error && /* @__PURE__ */ React.createElement(WarningPanel, {
|
|
232
|
+
title: "Oops! Something went wrong loading the templates"
|
|
233
|
+
}, error.message), !error && !loading && !entities.length && /* @__PURE__ */ React.createElement(Typography, {
|
|
234
|
+
variant: "body2"
|
|
235
|
+
}, "No templates found that match your filter. Learn more about", " ", /* @__PURE__ */ React.createElement(Link$1, {
|
|
236
|
+
to: "https://backstage.io/docs/features/software-templates/adding-templates"
|
|
237
|
+
}, "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, {
|
|
238
|
+
key: stringifyEntityRef(template),
|
|
239
|
+
template,
|
|
240
|
+
deprecated: template.apiVersion === "backstage.io/v1beta2"
|
|
241
|
+
})))));
|
|
242
|
+
};
|
|
243
|
+
|
|
78
244
|
const useStyles$1 = makeStyles((theme) => ({
|
|
79
245
|
contentWrapper: {
|
|
80
246
|
display: "grid",
|
|
@@ -271,18 +437,36 @@ function getReviewData(formData, steps) {
|
|
|
271
437
|
}
|
|
272
438
|
return reviewData;
|
|
273
439
|
}
|
|
274
|
-
const MultistepJsonForm = ({
|
|
275
|
-
|
|
276
|
-
formData,
|
|
277
|
-
onChange,
|
|
278
|
-
onReset,
|
|
279
|
-
onFinish,
|
|
280
|
-
fields,
|
|
281
|
-
widgets
|
|
282
|
-
}) => {
|
|
440
|
+
const MultistepJsonForm = (props) => {
|
|
441
|
+
const { formData, onChange, onReset, onFinish, fields, widgets } = props;
|
|
283
442
|
const [activeStep, setActiveStep] = useState(0);
|
|
284
443
|
const [disableButtons, setDisableButtons] = useState(false);
|
|
285
444
|
const errorApi = useApi(errorApiRef);
|
|
445
|
+
const featureFlagApi = useApi(featureFlagsApiRef);
|
|
446
|
+
const featureFlagKey = "backstage:featureFlag";
|
|
447
|
+
const filterOutProperties = (step) => {
|
|
448
|
+
var _a;
|
|
449
|
+
const filteredStep = cloneDeep(step);
|
|
450
|
+
const removedPropertyKeys = [];
|
|
451
|
+
if (filteredStep.schema.properties) {
|
|
452
|
+
filteredStep.schema.properties = Object.fromEntries(Object.entries(filteredStep.schema.properties).filter(([key, value]) => {
|
|
453
|
+
if (value[featureFlagKey]) {
|
|
454
|
+
if (featureFlagApi.isActive(value[featureFlagKey])) {
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
removedPropertyKeys.push(key);
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
return true;
|
|
461
|
+
}));
|
|
462
|
+
filteredStep.schema.required = Array.isArray(filteredStep.schema.required) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter((r) => !removedPropertyKeys.includes(r)) : filteredStep.schema.required;
|
|
463
|
+
}
|
|
464
|
+
return filteredStep;
|
|
465
|
+
};
|
|
466
|
+
const steps = props.steps.filter((step) => {
|
|
467
|
+
const featureFlag = step.schema[featureFlagKey];
|
|
468
|
+
return typeof featureFlag !== "string" || featureFlagApi.isActive(featureFlag);
|
|
469
|
+
}).map(filterOutProperties);
|
|
286
470
|
const handleReset = () => {
|
|
287
471
|
setActiveStep(0);
|
|
288
472
|
onReset();
|
|
@@ -328,10 +512,10 @@ const MultistepJsonForm = ({
|
|
|
328
512
|
},
|
|
329
513
|
...formProps,
|
|
330
514
|
...transformSchemaToProps(schema)
|
|
331
|
-
}, /* @__PURE__ */ React.createElement(Button, {
|
|
515
|
+
}, /* @__PURE__ */ React.createElement(Button$1, {
|
|
332
516
|
disabled: activeStep === 0,
|
|
333
517
|
onClick: handleBack
|
|
334
|
-
}, "Back"), /* @__PURE__ */ React.createElement(Button, {
|
|
518
|
+
}, "Back"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
335
519
|
variant: "contained",
|
|
336
520
|
color: "primary",
|
|
337
521
|
type: "submit"
|
|
@@ -346,13 +530,13 @@ const MultistepJsonForm = ({
|
|
|
346
530
|
metadata: getReviewData(formData, steps)
|
|
347
531
|
}), /* @__PURE__ */ React.createElement(Box, {
|
|
348
532
|
mb: 4
|
|
349
|
-
}), /* @__PURE__ */ React.createElement(Button, {
|
|
533
|
+
}), /* @__PURE__ */ React.createElement(Button$1, {
|
|
350
534
|
onClick: handleBack,
|
|
351
535
|
disabled: disableButtons
|
|
352
|
-
}, "Back"), /* @__PURE__ */ React.createElement(Button, {
|
|
536
|
+
}, "Back"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
353
537
|
onClick: handleReset,
|
|
354
538
|
disabled: disableButtons
|
|
355
|
-
}, "Reset"), /* @__PURE__ */ React.createElement(Button, {
|
|
539
|
+
}, "Reset"), /* @__PURE__ */ React.createElement(Button$1, {
|
|
356
540
|
variant: "contained",
|
|
357
541
|
color: "primary",
|
|
358
542
|
onClick: handleCreate,
|
|
@@ -360,13 +544,9 @@ const MultistepJsonForm = ({
|
|
|
360
544
|
}, "Create"))));
|
|
361
545
|
};
|
|
362
546
|
|
|
363
|
-
const useTemplateParameterSchema = (
|
|
547
|
+
const useTemplateParameterSchema = (templateRef) => {
|
|
364
548
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
365
|
-
const { value, loading, error } = useAsync(() => scaffolderApi.getTemplateParameterSchema(
|
|
366
|
-
name: templateName,
|
|
367
|
-
kind: "template",
|
|
368
|
-
namespace: "default"
|
|
369
|
-
}), [scaffolderApi, templateName]);
|
|
549
|
+
const { value, loading, error } = useAsync(() => scaffolderApi.getTemplateParameterSchema(templateRef), [scaffolderApi, templateRef]);
|
|
370
550
|
return { schema: value, loading, error };
|
|
371
551
|
};
|
|
372
552
|
function isObject(obj) {
|
|
@@ -408,7 +588,8 @@ const TemplatePage = ({
|
|
|
408
588
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
409
589
|
const { templateName } = useParams();
|
|
410
590
|
const navigate = useNavigate();
|
|
411
|
-
const
|
|
591
|
+
const scaffolderTaskRoute = useRouteRef(scaffolderTaskRouteRef);
|
|
592
|
+
const rootRoute = useRouteRef(rootRouteRef);
|
|
412
593
|
const { schema, loading, error } = useTemplateParameterSchema(templateName);
|
|
413
594
|
const [formState, setFormState] = useState(() => {
|
|
414
595
|
var _a;
|
|
@@ -425,22 +606,30 @@ const TemplatePage = ({
|
|
|
425
606
|
const handleChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
426
607
|
const handleCreate = async () => {
|
|
427
608
|
var _a;
|
|
428
|
-
const
|
|
609
|
+
const { taskId } = await scaffolderApi.scaffold({
|
|
610
|
+
templateRef: stringifyEntityRef({
|
|
611
|
+
name: templateName,
|
|
612
|
+
kind: "template",
|
|
613
|
+
namespace: "default"
|
|
614
|
+
}),
|
|
615
|
+
values: formState,
|
|
616
|
+
secrets: secretsContext == null ? void 0 : secretsContext.secrets
|
|
617
|
+
});
|
|
429
618
|
const formParams = qs.stringify({ formData: formState }, { addQueryPrefix: true });
|
|
430
619
|
const newUrl = `${window.location.pathname}${formParams}`;
|
|
431
620
|
(_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
|
|
432
|
-
navigate(
|
|
621
|
+
navigate(scaffolderTaskRoute({ taskId }));
|
|
433
622
|
};
|
|
434
623
|
if (error) {
|
|
435
624
|
errorApi.post(new Error(`Failed to load template, ${error}`));
|
|
436
625
|
return /* @__PURE__ */ React.createElement(Navigate, {
|
|
437
|
-
to:
|
|
626
|
+
to: rootRoute()
|
|
438
627
|
});
|
|
439
628
|
}
|
|
440
629
|
if (!loading && !schema) {
|
|
441
630
|
errorApi.post(new Error("Template was not found."));
|
|
442
631
|
return /* @__PURE__ */ React.createElement(Navigate, {
|
|
443
|
-
to:
|
|
632
|
+
to: rootRoute()
|
|
444
633
|
});
|
|
445
634
|
}
|
|
446
635
|
const customFieldComponents = Object.fromEntries(customFieldExtensions.map(({ name, component }) => [name, component]));
|
|
@@ -582,13 +771,11 @@ const ActionsPage = () => {
|
|
|
582
771
|
}), /* @__PURE__ */ React.createElement(Content, null, items));
|
|
583
772
|
};
|
|
584
773
|
|
|
585
|
-
const Router = ({
|
|
586
|
-
|
|
587
|
-
TaskPageComponent
|
|
588
|
-
groups
|
|
589
|
-
}) => {
|
|
774
|
+
const Router = (props) => {
|
|
775
|
+
const { groups, components = {} } = props;
|
|
776
|
+
const { TemplateCardComponent, TaskPageComponent } = components;
|
|
590
777
|
const outlet = useOutlet();
|
|
591
|
-
const TaskPageElement = TaskPageComponent
|
|
778
|
+
const TaskPageElement = TaskPageComponent != null ? TaskPageComponent : TaskPage;
|
|
592
779
|
const customFieldExtensions = useElementFilter(outlet, (elements) => elements.selectByComponentData({
|
|
593
780
|
key: FIELD_EXTENSION_WRAPPER_KEY
|
|
594
781
|
}).findComponentData({
|
|
@@ -601,8 +788,8 @@ const Router = ({
|
|
|
601
788
|
return /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
|
|
602
789
|
path: "/",
|
|
603
790
|
element: /* @__PURE__ */ React.createElement(ScaffolderPage, {
|
|
604
|
-
|
|
605
|
-
|
|
791
|
+
groups,
|
|
792
|
+
TemplateCardComponent
|
|
606
793
|
})
|
|
607
794
|
}), /* @__PURE__ */ React.createElement(Route, {
|
|
608
795
|
path: "/templates/:templateName",
|
|
@@ -619,4 +806,4 @@ const Router = ({
|
|
|
619
806
|
};
|
|
620
807
|
|
|
621
808
|
export { Router };
|
|
622
|
-
//# sourceMappingURL=Router-
|
|
809
|
+
//# sourceMappingURL=Router-722c3528.esm.js.map
|