@backstage/plugin-scaffolder 0.11.11 → 0.11.15
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 +70 -0
- package/dist/esm/{Router-de99a5d2.esm.js → Router-6eee3fa9.esm.js} +85 -68
- package/dist/esm/Router-6eee3fa9.esm.js.map +1 -0
- package/dist/esm/{index-8b883a7e.esm.js → index-210d6da0.esm.js} +159 -75
- package/dist/esm/index-210d6da0.esm.js.map +1 -0
- package/dist/index.d.ts +20 -7
- package/dist/index.esm.js +4 -5
- package/dist/index.esm.js.map +1 -1
- package/package.json +21 -20
- package/dist/esm/Router-de99a5d2.esm.js.map +0 -1
- package/dist/esm/index-8b883a7e.esm.js.map +0 -1
|
@@ -2,19 +2,18 @@ import { createApiRef, useApi, attachComponentData, createExternalRouteRef, crea
|
|
|
2
2
|
import { ResponseError } from '@backstage/errors';
|
|
3
3
|
import qs from 'qs';
|
|
4
4
|
import ObservableImpl from 'zen-observable';
|
|
5
|
-
import { catalogApiRef, formatEntityRefTitle, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks, useEntityListProvider, useEntityTypeFilter } from '@backstage/plugin-catalog-react';
|
|
5
|
+
import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks, useEntityListProvider, useEntityTypeFilter } from '@backstage/plugin-catalog-react';
|
|
6
6
|
import { TextField, withStyles, makeStyles, IconButton, Tooltip, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, Link, FormControlLabel, Checkbox } from '@material-ui/core';
|
|
7
7
|
import FormControl from '@material-ui/core/FormControl';
|
|
8
8
|
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
9
9
|
import React, { useCallback, useEffect } from 'react';
|
|
10
10
|
import { useAsync } from 'react-use';
|
|
11
11
|
import { KubernetesValidatorFunctions, RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
|
|
12
|
+
import { Progress, Select, ItemCardHeader, Button, ContentHeader, WarningPanel, Link as Link$1, Content, ItemCardGrid } from '@backstage/core-components';
|
|
12
13
|
import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
13
|
-
import Select from '@material-ui/core/Select';
|
|
14
|
-
import InputLabel from '@material-ui/core/InputLabel';
|
|
15
|
-
import Input from '@material-ui/core/Input';
|
|
16
14
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
|
17
|
-
import
|
|
15
|
+
import Input from '@material-ui/core/Input';
|
|
16
|
+
import InputLabel from '@material-ui/core/InputLabel';
|
|
18
17
|
import Star from '@material-ui/icons/Star';
|
|
19
18
|
import StarBorder from '@material-ui/icons/StarBorder';
|
|
20
19
|
import WarningIcon from '@material-ui/icons/Warning';
|
|
@@ -26,8 +25,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
|
26
25
|
import { Autocomplete as Autocomplete$1 } from '@material-ui/lab';
|
|
27
26
|
|
|
28
27
|
const scaffolderApiRef = createApiRef({
|
|
29
|
-
id: "plugin.scaffolder.service"
|
|
30
|
-
description: "Used to make requests towards the scaffolder backend"
|
|
28
|
+
id: "plugin.scaffolder.service"
|
|
31
29
|
});
|
|
32
30
|
class ScaffolderClient {
|
|
33
31
|
constructor(options) {
|
|
@@ -43,17 +41,17 @@ class ScaffolderClient {
|
|
|
43
41
|
...this.scmIntegrationsApi.bitbucket.list(),
|
|
44
42
|
...this.scmIntegrationsApi.github.list(),
|
|
45
43
|
...this.scmIntegrationsApi.gitlab.list()
|
|
46
|
-
].map((c) => ({type: c.type, title: c.title, host: c.config.host})).filter((c) => options.allowedHosts.includes(c.host));
|
|
44
|
+
].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
|
|
47
45
|
}
|
|
48
46
|
async getTemplateParameterSchema(templateName) {
|
|
49
|
-
const {namespace, kind, name} = templateName;
|
|
47
|
+
const { namespace, kind, name } = templateName;
|
|
50
48
|
const token = await this.identityApi.getIdToken();
|
|
51
49
|
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
52
50
|
const templatePath = [namespace, kind, name].map((s) => encodeURIComponent(s)).join("/");
|
|
53
51
|
const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;
|
|
54
52
|
const response = await fetch(url, {
|
|
55
53
|
headers: {
|
|
56
|
-
...token && {Authorization: `Bearer ${token}`}
|
|
54
|
+
...token && { Authorization: `Bearer ${token}` }
|
|
57
55
|
}
|
|
58
56
|
});
|
|
59
57
|
if (!response.ok) {
|
|
@@ -69,16 +67,16 @@ class ScaffolderClient {
|
|
|
69
67
|
method: "POST",
|
|
70
68
|
headers: {
|
|
71
69
|
"Content-Type": "application/json",
|
|
72
|
-
...token && {Authorization: `Bearer ${token}`}
|
|
70
|
+
...token && { Authorization: `Bearer ${token}` }
|
|
73
71
|
},
|
|
74
|
-
body: JSON.stringify({templateName, values: {...values}})
|
|
72
|
+
body: JSON.stringify({ templateName, values: { ...values } })
|
|
75
73
|
});
|
|
76
74
|
if (response.status !== 201) {
|
|
77
75
|
const status = `${response.status} ${response.statusText}`;
|
|
78
76
|
const body = await response.text();
|
|
79
77
|
throw new Error(`Backend request failed, ${status} ${body.trim()}`);
|
|
80
78
|
}
|
|
81
|
-
const {id} = await response.json();
|
|
79
|
+
const { id } = await response.json();
|
|
82
80
|
return id;
|
|
83
81
|
}
|
|
84
82
|
async getTask(taskId) {
|
|
@@ -86,10 +84,10 @@ class ScaffolderClient {
|
|
|
86
84
|
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
87
85
|
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`;
|
|
88
86
|
const response = await fetch(url, {
|
|
89
|
-
headers: token ? {Authorization: `Bearer ${token}`} : {}
|
|
87
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {}
|
|
90
88
|
});
|
|
91
89
|
if (!response.ok) {
|
|
92
|
-
throw ResponseError.fromResponse(response);
|
|
90
|
+
throw await ResponseError.fromResponse(response);
|
|
93
91
|
}
|
|
94
92
|
return await response.json();
|
|
95
93
|
}
|
|
@@ -110,7 +108,7 @@ class ScaffolderClient {
|
|
|
110
108
|
}
|
|
111
109
|
this.discoveryApi.getBaseUrl("scaffolder").then((baseUrl) => {
|
|
112
110
|
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/eventstream`;
|
|
113
|
-
const eventSource = new EventSource(url, {withCredentials: true});
|
|
111
|
+
const eventSource = new EventSource(url, { withCredentials: true });
|
|
114
112
|
eventSource.addEventListener("log", (event) => {
|
|
115
113
|
if (event.data) {
|
|
116
114
|
try {
|
|
@@ -147,7 +145,7 @@ class ScaffolderClient {
|
|
|
147
145
|
return new ObservableImpl((subscriber) => {
|
|
148
146
|
this.discoveryApi.getBaseUrl("scaffolder").then(async (baseUrl) => {
|
|
149
147
|
while (!subscriber.closed) {
|
|
150
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/events?${qs.stringify({after})}`;
|
|
148
|
+
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/events?${qs.stringify({ after })}`;
|
|
151
149
|
const response = await fetch(url);
|
|
152
150
|
if (!response.ok) {
|
|
153
151
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
@@ -170,18 +168,22 @@ class ScaffolderClient {
|
|
|
170
168
|
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
171
169
|
const token = await this.identityApi.getIdToken();
|
|
172
170
|
const response = await fetch(`${baseUrl}/v2/actions`, {
|
|
173
|
-
headers: token ? {Authorization: `Bearer ${token}`} : {}
|
|
171
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {}
|
|
174
172
|
});
|
|
175
173
|
if (!response.ok) {
|
|
176
|
-
throw ResponseError.fromResponse(response);
|
|
174
|
+
throw await ResponseError.fromResponse(response);
|
|
177
175
|
}
|
|
178
176
|
return await response.json();
|
|
179
177
|
}
|
|
180
178
|
}
|
|
181
179
|
|
|
180
|
+
const allowArbitraryValues = (uiSchema) => {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
return (_b = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowArbitraryValues) != null ? _b : true;
|
|
183
|
+
};
|
|
182
184
|
const EntityPicker = ({
|
|
183
185
|
onChange,
|
|
184
|
-
schema: {title = "Entity", description = "An entity from the catalog"},
|
|
186
|
+
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
185
187
|
required,
|
|
186
188
|
uiSchema,
|
|
187
189
|
rawErrors,
|
|
@@ -192,23 +194,29 @@ const EntityPicker = ({
|
|
|
192
194
|
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
193
195
|
const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
|
|
194
196
|
const catalogApi = useApi(catalogApiRef);
|
|
195
|
-
const {value: entities, loading} = useAsync(() => catalogApi.getEntities(allowedKinds ? {filter: {kind: allowedKinds}} : void 0));
|
|
196
|
-
const entityRefs = entities == null ? void 0 : entities.items.map((e) => formatEntityRefTitle(e, {defaultKind}));
|
|
197
|
-
const onSelect = (_, value) => {
|
|
197
|
+
const { value: entities, loading } = useAsync(() => catalogApi.getEntities(allowedKinds ? { filter: { kind: allowedKinds } } : void 0));
|
|
198
|
+
const entityRefs = entities == null ? void 0 : entities.items.map((e) => formatEntityRefTitle(e, { defaultKind }));
|
|
199
|
+
const onSelect = useCallback((_, value) => {
|
|
198
200
|
onChange(value || "");
|
|
199
|
-
};
|
|
201
|
+
}, [onChange]);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if ((entityRefs == null ? void 0 : entityRefs.length) === 1) {
|
|
204
|
+
onChange(entityRefs[0]);
|
|
205
|
+
}
|
|
206
|
+
}, [entityRefs, onChange]);
|
|
200
207
|
return /* @__PURE__ */ React.createElement(FormControl, {
|
|
201
208
|
margin: "normal",
|
|
202
209
|
required,
|
|
203
210
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData
|
|
204
211
|
}, /* @__PURE__ */ React.createElement(Autocomplete, {
|
|
212
|
+
disabled: (entityRefs == null ? void 0 : entityRefs.length) === 1,
|
|
205
213
|
id: idSchema == null ? void 0 : idSchema.$id,
|
|
206
214
|
value: formData || "",
|
|
207
215
|
loading,
|
|
208
216
|
onChange: onSelect,
|
|
209
217
|
options: entityRefs || [],
|
|
210
218
|
autoSelect: true,
|
|
211
|
-
freeSolo:
|
|
219
|
+
freeSolo: allowArbitraryValues(uiSchema),
|
|
212
220
|
renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, {
|
|
213
221
|
...params,
|
|
214
222
|
label: title,
|
|
@@ -224,10 +232,10 @@ const EntityPicker = ({
|
|
|
224
232
|
const TextValuePicker = ({
|
|
225
233
|
onChange,
|
|
226
234
|
required,
|
|
227
|
-
schema: {title, description},
|
|
235
|
+
schema: { title, description },
|
|
228
236
|
rawErrors,
|
|
229
237
|
formData,
|
|
230
|
-
uiSchema: {"ui:autofocus": autoFocus},
|
|
238
|
+
uiSchema: { "ui:autofocus": autoFocus },
|
|
231
239
|
idSchema,
|
|
232
240
|
placeholder
|
|
233
241
|
}) => /* @__PURE__ */ React.createElement(TextField, {
|
|
@@ -237,17 +245,17 @@ const TextValuePicker = ({
|
|
|
237
245
|
helperText: description,
|
|
238
246
|
required,
|
|
239
247
|
value: formData != null ? formData : "",
|
|
240
|
-
onChange: ({target: {value}}) => onChange(value),
|
|
248
|
+
onChange: ({ target: { value } }) => onChange(value),
|
|
241
249
|
margin: "normal",
|
|
242
250
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
|
|
243
|
-
inputProps: {autoFocus}
|
|
251
|
+
inputProps: { autoFocus }
|
|
244
252
|
});
|
|
245
253
|
|
|
246
254
|
const EntityNamePicker = ({
|
|
247
|
-
schema: {title = "Name", description = "Unique name of the component"},
|
|
255
|
+
schema: { title = "Name", description = "Unique name of the component" },
|
|
248
256
|
...props
|
|
249
257
|
}) => /* @__PURE__ */ React.createElement(TextValuePicker, {
|
|
250
|
-
schema: {title, description},
|
|
258
|
+
schema: { title, description },
|
|
251
259
|
...props
|
|
252
260
|
});
|
|
253
261
|
|
|
@@ -258,7 +266,7 @@ const entityNamePickerValidation = (value, validation) => {
|
|
|
258
266
|
};
|
|
259
267
|
|
|
260
268
|
const OwnerPicker = ({
|
|
261
|
-
schema: {title = "Owner", description = "The owner of the component"},
|
|
269
|
+
schema: { title = "Owner", description = "The owner of the component" },
|
|
262
270
|
uiSchema,
|
|
263
271
|
...props
|
|
264
272
|
}) => {
|
|
@@ -275,12 +283,12 @@ const OwnerPicker = ({
|
|
|
275
283
|
};
|
|
276
284
|
return /* @__PURE__ */ React.createElement(EntityPicker, {
|
|
277
285
|
...props,
|
|
278
|
-
schema: {title, description},
|
|
286
|
+
schema: { title, description },
|
|
279
287
|
uiSchema: ownerUiSchema
|
|
280
288
|
});
|
|
281
289
|
};
|
|
282
290
|
|
|
283
|
-
function splitFormData(url) {
|
|
291
|
+
function splitFormData(url, allowedOwners) {
|
|
284
292
|
let host = void 0;
|
|
285
293
|
let owner = void 0;
|
|
286
294
|
let repo = void 0;
|
|
@@ -291,7 +299,7 @@ function splitFormData(url) {
|
|
|
291
299
|
if (url) {
|
|
292
300
|
const parsed = new URL(`https://${url}`);
|
|
293
301
|
host = parsed.host;
|
|
294
|
-
owner = parsed.searchParams.get("owner") || void 0;
|
|
302
|
+
owner = parsed.searchParams.get("owner") || (allowedOwners == null ? void 0 : allowedOwners[0]);
|
|
295
303
|
repo = parsed.searchParams.get("repo") || void 0;
|
|
296
304
|
organization = parsed.searchParams.get("organization") || void 0;
|
|
297
305
|
workspace = parsed.searchParams.get("workspace") || void 0;
|
|
@@ -299,7 +307,7 @@ function splitFormData(url) {
|
|
|
299
307
|
}
|
|
300
308
|
} catch {
|
|
301
309
|
}
|
|
302
|
-
return {host, owner, repo, organization, workspace, project};
|
|
310
|
+
return { host, owner, repo, organization, workspace, project };
|
|
303
311
|
}
|
|
304
312
|
function serializeFormData(data) {
|
|
305
313
|
if (!data.host) {
|
|
@@ -329,17 +337,18 @@ const RepoUrlPicker = ({
|
|
|
329
337
|
rawErrors,
|
|
330
338
|
formData
|
|
331
339
|
}) => {
|
|
332
|
-
var _a, _b, _c;
|
|
340
|
+
var _a, _b, _c, _d, _e;
|
|
333
341
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
334
342
|
const integrationApi = useApi(scmIntegrationsApiRef);
|
|
335
343
|
const allowedHosts = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedHosts;
|
|
336
|
-
const
|
|
337
|
-
|
|
344
|
+
const allowedOwners = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.allowedOwners;
|
|
345
|
+
const { value: integrations, loading } = useAsync(async () => {
|
|
346
|
+
return await scaffolderApi.getIntegrationsList({ allowedHosts });
|
|
338
347
|
});
|
|
339
|
-
const {host, owner, repo, organization, workspace, project} = splitFormData(formData);
|
|
340
|
-
const updateHost = useCallback((
|
|
348
|
+
const { host, owner, repo, organization, workspace, project } = splitFormData(formData, allowedOwners);
|
|
349
|
+
const updateHost = useCallback((value) => {
|
|
341
350
|
onChange(serializeFormData({
|
|
342
|
-
host:
|
|
351
|
+
host: value,
|
|
343
352
|
owner,
|
|
344
353
|
repo,
|
|
345
354
|
organization,
|
|
@@ -347,6 +356,14 @@ const RepoUrlPicker = ({
|
|
|
347
356
|
project
|
|
348
357
|
}));
|
|
349
358
|
}, [onChange, owner, repo, organization, workspace, project]);
|
|
359
|
+
const updateOwnerSelect = useCallback((value) => onChange(serializeFormData({
|
|
360
|
+
host,
|
|
361
|
+
owner: value,
|
|
362
|
+
repo,
|
|
363
|
+
organization,
|
|
364
|
+
workspace,
|
|
365
|
+
project
|
|
366
|
+
})), [onChange, host, repo, organization, workspace, project]);
|
|
350
367
|
const updateOwner = useCallback((evt) => onChange(serializeFormData({
|
|
351
368
|
host,
|
|
352
369
|
owner: evt.target.value,
|
|
@@ -411,21 +428,20 @@ const RepoUrlPicker = ({
|
|
|
411
428
|
if (loading) {
|
|
412
429
|
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
413
430
|
}
|
|
431
|
+
const hostsOptions = integrations ? integrations.filter((i) => allowedHosts == null ? void 0 : allowedHosts.includes(i.host)).map((i) => ({ label: i.title, value: i.host })) : [{ label: "Loading...", value: "loading" }];
|
|
432
|
+
const ownersOptions = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
414
433
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormControl, {
|
|
415
434
|
margin: "normal",
|
|
416
435
|
required: true,
|
|
417
436
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !host
|
|
418
|
-
}, /* @__PURE__ */ React.createElement(
|
|
419
|
-
htmlFor: "hostInput"
|
|
420
|
-
}, "Host"), /* @__PURE__ */ React.createElement(Select, {
|
|
437
|
+
}, /* @__PURE__ */ React.createElement(Select, {
|
|
421
438
|
native: true,
|
|
422
|
-
|
|
439
|
+
disabled: hostsOptions.length === 1,
|
|
440
|
+
label: "Host",
|
|
423
441
|
onChange: updateHost,
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
value: i.host
|
|
428
|
-
}, i.title)) : /* @__PURE__ */ React.createElement("p", null, "loading")), /* @__PURE__ */ React.createElement(FormHelperText, null, "The host where the repository will be created")), host === "dev.azure.com" && /* @__PURE__ */ React.createElement(FormControl, {
|
|
442
|
+
selected: host,
|
|
443
|
+
items: hostsOptions
|
|
444
|
+
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The host where the repository will be created")), host === "dev.azure.com" && /* @__PURE__ */ React.createElement(FormControl, {
|
|
429
445
|
margin: "normal",
|
|
430
446
|
required: true,
|
|
431
447
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !organization
|
|
@@ -435,7 +451,7 @@ const RepoUrlPicker = ({
|
|
|
435
451
|
id: "repoInput",
|
|
436
452
|
onChange: updateOrganization,
|
|
437
453
|
value: organization
|
|
438
|
-
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The name of the organization")), host && ((
|
|
454
|
+
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The name of the organization")), host && ((_c = integrationApi.byHost(host)) == null ? void 0 : _c.type) === "bitbucket" && /* @__PURE__ */ React.createElement(React.Fragment, null, host === "bitbucket.org" && /* @__PURE__ */ React.createElement(FormControl, {
|
|
439
455
|
margin: "normal",
|
|
440
456
|
required: true,
|
|
441
457
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
|
|
@@ -455,7 +471,7 @@ const RepoUrlPicker = ({
|
|
|
455
471
|
id: "wokrspaceInput",
|
|
456
472
|
onChange: updateProject,
|
|
457
473
|
value: project
|
|
458
|
-
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The project where the repository will be created"))), host && ((
|
|
474
|
+
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The project where the repository will be created"))), host && ((_d = integrationApi.byHost(host)) == null ? void 0 : _d.type) !== "bitbucket" && !allowedOwners && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormControl, {
|
|
459
475
|
margin: "normal",
|
|
460
476
|
required: true,
|
|
461
477
|
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
@@ -465,6 +481,17 @@ const RepoUrlPicker = ({
|
|
|
465
481
|
id: "ownerInput",
|
|
466
482
|
onChange: updateOwner,
|
|
467
483
|
value: owner
|
|
484
|
+
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The organization, user or project that this repo will belong to"))), host && ((_e = integrationApi.byHost(host)) == null ? void 0 : _e.type) !== "bitbucket" && allowedOwners && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormControl, {
|
|
485
|
+
margin: "normal",
|
|
486
|
+
required: true,
|
|
487
|
+
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
488
|
+
}, /* @__PURE__ */ React.createElement(Select, {
|
|
489
|
+
native: true,
|
|
490
|
+
label: "Owner Available",
|
|
491
|
+
onChange: updateOwnerSelect,
|
|
492
|
+
disabled: ownersOptions.length === 1,
|
|
493
|
+
selected: owner,
|
|
494
|
+
items: ownersOptions
|
|
468
495
|
}), /* @__PURE__ */ React.createElement(FormHelperText, null, "The organization, user or project that this repo will belong to"))), /* @__PURE__ */ React.createElement(FormControl, {
|
|
469
496
|
margin: "normal",
|
|
470
497
|
required: true,
|
|
@@ -481,7 +508,7 @@ const RepoUrlPicker = ({
|
|
|
481
508
|
const repoPickerValidation = (value, validation, context) => {
|
|
482
509
|
var _a;
|
|
483
510
|
try {
|
|
484
|
-
const {host, searchParams} = new URL(`https://${value}`);
|
|
511
|
+
const { host, searchParams } = new URL(`https://${value}`);
|
|
485
512
|
const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);
|
|
486
513
|
if (!host) {
|
|
487
514
|
validation.addError("Incomplete repository location provided, host not provided");
|
|
@@ -507,6 +534,47 @@ const repoPickerValidation = (value, validation, context) => {
|
|
|
507
534
|
}
|
|
508
535
|
};
|
|
509
536
|
|
|
537
|
+
const OwnedEntityPicker = ({
|
|
538
|
+
onChange,
|
|
539
|
+
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
540
|
+
required,
|
|
541
|
+
uiSchema,
|
|
542
|
+
rawErrors,
|
|
543
|
+
formData,
|
|
544
|
+
idSchema
|
|
545
|
+
}) => {
|
|
546
|
+
var _a, _b;
|
|
547
|
+
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
548
|
+
const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
|
|
549
|
+
const { ownedEntities, loading } = useOwnedEntities(allowedKinds);
|
|
550
|
+
const entityRefs = ownedEntities == null ? void 0 : ownedEntities.items.map((e) => formatEntityRefTitle(e, { defaultKind })).filter((n) => n);
|
|
551
|
+
const onSelect = (_, value) => {
|
|
552
|
+
onChange(value || "");
|
|
553
|
+
};
|
|
554
|
+
return /* @__PURE__ */ React.createElement(FormControl, {
|
|
555
|
+
margin: "normal",
|
|
556
|
+
required,
|
|
557
|
+
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData
|
|
558
|
+
}, /* @__PURE__ */ React.createElement(Autocomplete, {
|
|
559
|
+
id: idSchema == null ? void 0 : idSchema.$id,
|
|
560
|
+
value: formData || "",
|
|
561
|
+
loading,
|
|
562
|
+
onChange: onSelect,
|
|
563
|
+
options: entityRefs || [],
|
|
564
|
+
autoSelect: true,
|
|
565
|
+
freeSolo: true,
|
|
566
|
+
renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, {
|
|
567
|
+
...params,
|
|
568
|
+
label: title,
|
|
569
|
+
margin: "normal",
|
|
570
|
+
helperText: description,
|
|
571
|
+
variant: "outlined",
|
|
572
|
+
required,
|
|
573
|
+
InputProps: params.InputProps
|
|
574
|
+
})
|
|
575
|
+
}));
|
|
576
|
+
};
|
|
577
|
+
|
|
510
578
|
const FIELD_EXTENSION_WRAPPER_KEY = "scaffolder.extensions.wrapper.v1";
|
|
511
579
|
const FIELD_EXTENSION_KEY = "scaffolder.extensions.field.v1";
|
|
512
580
|
function createScaffolderFieldExtension(options) {
|
|
@@ -539,7 +607,7 @@ const scaffolderPlugin = createPlugin({
|
|
|
539
607
|
identityApi: identityApiRef,
|
|
540
608
|
scmIntegrationsApi: scmIntegrationsApiRef
|
|
541
609
|
},
|
|
542
|
-
factory: ({discoveryApi, identityApi, scmIntegrationsApi}) => new ScaffolderClient({discoveryApi, identityApi, scmIntegrationsApi})
|
|
610
|
+
factory: ({ discoveryApi, identityApi, scmIntegrationsApi }) => new ScaffolderClient({ discoveryApi, identityApi, scmIntegrationsApi })
|
|
543
611
|
})
|
|
544
612
|
],
|
|
545
613
|
routes: {
|
|
@@ -569,9 +637,13 @@ const OwnerPickerFieldExtension = scaffolderPlugin.provide(createScaffolderField
|
|
|
569
637
|
}));
|
|
570
638
|
const ScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
|
|
571
639
|
name: "ScaffolderPage",
|
|
572
|
-
component: () => import('./Router-
|
|
640
|
+
component: () => import('./Router-6eee3fa9.esm.js').then((m) => m.Router),
|
|
573
641
|
mountPoint: rootRouteRef
|
|
574
642
|
}));
|
|
643
|
+
const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
|
|
644
|
+
component: OwnedEntityPicker,
|
|
645
|
+
name: "OwnedEntityPicker"
|
|
646
|
+
}));
|
|
575
647
|
|
|
576
648
|
const YellowStar = withStyles({
|
|
577
649
|
root: {
|
|
@@ -595,7 +667,7 @@ const favouriteTemplateTooltip = (isStarred) => isStarred ? "Remove from favorit
|
|
|
595
667
|
const favouriteTemplateIcon = (isStarred) => isStarred ? /* @__PURE__ */ React.createElement(YellowStar, null) : /* @__PURE__ */ React.createElement(WhiteBorderStar, null);
|
|
596
668
|
const FavouriteTemplate = (props) => {
|
|
597
669
|
const classes = useStyles$1();
|
|
598
|
-
const {toggleStarredEntity, isStarredEntity} = useStarredEntity(props.entity);
|
|
670
|
+
const { toggleStarredEntity, isStarredEntity } = useStarredEntity(props.entity);
|
|
599
671
|
return /* @__PURE__ */ React.createElement(IconButton, {
|
|
600
672
|
color: "inherit",
|
|
601
673
|
className: classes.starButton,
|
|
@@ -611,7 +683,7 @@ const useStyles = makeStyles((theme) => ({
|
|
|
611
683
|
position: "relative"
|
|
612
684
|
},
|
|
613
685
|
title: {
|
|
614
|
-
backgroundImage: ({backgroundImage}) => backgroundImage
|
|
686
|
+
backgroundImage: ({ backgroundImage }) => backgroundImage
|
|
615
687
|
},
|
|
616
688
|
box: {
|
|
617
689
|
overflow: "hidden",
|
|
@@ -659,7 +731,7 @@ const getTemplateCardProps = (template) => {
|
|
|
659
731
|
const DeprecationWarning = () => {
|
|
660
732
|
const styles = useDeprecationStyles();
|
|
661
733
|
const Title = /* @__PURE__ */ React.createElement(Typography, {
|
|
662
|
-
style: {padding: 10, maxWidth: 300}
|
|
734
|
+
style: { padding: 10, maxWidth: 300 }
|
|
663
735
|
}, "This template syntax is deprecated. Click for more info.");
|
|
664
736
|
return /* @__PURE__ */ React.createElement("div", {
|
|
665
737
|
className: styles.deprecationIcon
|
|
@@ -670,15 +742,15 @@ const DeprecationWarning = () => {
|
|
|
670
742
|
className: styles.link
|
|
671
743
|
}, /* @__PURE__ */ React.createElement(WarningIcon, null))));
|
|
672
744
|
};
|
|
673
|
-
const TemplateCard = ({template, deprecated}) => {
|
|
745
|
+
const TemplateCard = ({ template, deprecated }) => {
|
|
674
746
|
var _a;
|
|
675
747
|
const backstageTheme = useTheme();
|
|
676
748
|
const rootLink = useRouteRef(rootRouteRef);
|
|
677
749
|
const templateProps = getTemplateCardProps(template);
|
|
678
750
|
const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
|
|
679
|
-
const themeId = backstageTheme.getPageTheme({themeId: templateProps.type}) ? templateProps.type : "other";
|
|
680
|
-
const theme = backstageTheme.getPageTheme({themeId});
|
|
681
|
-
const classes = useStyles({backgroundImage: theme.backgroundImage});
|
|
751
|
+
const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type }) ? templateProps.type : "other";
|
|
752
|
+
const theme = backstageTheme.getPageTheme({ themeId });
|
|
753
|
+
const classes = useStyles({ backgroundImage: theme.backgroundImage });
|
|
682
754
|
const href = generatePath(`${rootLink()}/templates/:templateName`, {
|
|
683
755
|
templateName: templateProps.name
|
|
684
756
|
});
|
|
@@ -691,9 +763,9 @@ const TemplateCard = ({template, deprecated}) => {
|
|
|
691
763
|
}), deprecated && /* @__PURE__ */ React.createElement(DeprecationWarning, null), /* @__PURE__ */ React.createElement(ItemCardHeader, {
|
|
692
764
|
title: templateProps.title,
|
|
693
765
|
subtitle: templateProps.type,
|
|
694
|
-
classes: {root: classes.title}
|
|
766
|
+
classes: { root: classes.title }
|
|
695
767
|
})), /* @__PURE__ */ React.createElement(CardContent, {
|
|
696
|
-
style: {display: "grid"}
|
|
768
|
+
style: { display: "grid" }
|
|
697
769
|
}, /* @__PURE__ */ React.createElement(Box, {
|
|
698
770
|
className: classes.box
|
|
699
771
|
}, /* @__PURE__ */ React.createElement(Typography, {
|
|
@@ -726,19 +798,31 @@ const TemplateCard = ({template, deprecated}) => {
|
|
|
726
798
|
}, "Choose")));
|
|
727
799
|
};
|
|
728
800
|
|
|
729
|
-
const TemplateList = ({
|
|
730
|
-
|
|
801
|
+
const TemplateList = ({
|
|
802
|
+
TemplateCardComponent,
|
|
803
|
+
group
|
|
804
|
+
}) => {
|
|
805
|
+
const { loading, error, entities } = useEntityListProvider();
|
|
731
806
|
const Card = TemplateCardComponent || TemplateCard;
|
|
807
|
+
const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
|
|
808
|
+
const title = group ? group.titleComponent || /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
809
|
+
title: group.title
|
|
810
|
+
}) : /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
811
|
+
title: "Other Templates"
|
|
812
|
+
});
|
|
813
|
+
if (group && maybeFilteredEntities.length === 0) {
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
732
816
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(Progress, null), error && /* @__PURE__ */ React.createElement(WarningPanel, {
|
|
733
817
|
title: "Oops! Something went wrong loading the templates"
|
|
734
818
|
}, error.message), !error && !loading && !entities.length && /* @__PURE__ */ React.createElement(Typography, {
|
|
735
819
|
variant: "body2"
|
|
736
|
-
}, "No templates found that match your filter. Learn more about", " ", /* @__PURE__ */ React.createElement(Link, {
|
|
737
|
-
|
|
738
|
-
}, "adding templates"), "."), /* @__PURE__ */ React.createElement(ItemCardGrid, null,
|
|
820
|
+
}, "No templates found that match your filter. Learn more about", " ", /* @__PURE__ */ React.createElement(Link$1, {
|
|
821
|
+
to: "https://backstage.io/docs/features/software-templates/adding-templates"
|
|
822
|
+
}, "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, {
|
|
739
823
|
key: stringifyEntityRef(template),
|
|
740
824
|
template
|
|
741
|
-
}))));
|
|
825
|
+
})))));
|
|
742
826
|
};
|
|
743
827
|
|
|
744
828
|
const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, {
|
|
@@ -749,7 +833,7 @@ const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, {
|
|
|
749
833
|
});
|
|
750
834
|
const TemplateTypePicker = () => {
|
|
751
835
|
const alertApi = useApi(alertApiRef);
|
|
752
|
-
const {error, loading, availableTypes, selectedTypes, setSelectedTypes} = useEntityTypeFilter();
|
|
836
|
+
const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter();
|
|
753
837
|
if (loading)
|
|
754
838
|
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
755
839
|
if (!availableTypes)
|
|
@@ -772,7 +856,7 @@ const TemplateTypePicker = () => {
|
|
|
772
856
|
options: availableTypes,
|
|
773
857
|
value: selectedTypes,
|
|
774
858
|
onChange: (_, value) => setSelectedTypes(value),
|
|
775
|
-
renderOption: (option, {selected}) => /* @__PURE__ */ React.createElement(FormControlLabel, {
|
|
859
|
+
renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(FormControlLabel, {
|
|
776
860
|
control: /* @__PURE__ */ React.createElement(Checkbox, {
|
|
777
861
|
icon,
|
|
778
862
|
checkedIcon,
|
|
@@ -791,5 +875,5 @@ const TemplateTypePicker = () => {
|
|
|
791
875
|
}));
|
|
792
876
|
};
|
|
793
877
|
|
|
794
|
-
export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, ScaffolderClient as S, TemplateTypePicker as T, EntityNamePicker as a,
|
|
795
|
-
//# sourceMappingURL=index-
|
|
878
|
+
export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, ScaffolderClient as S, TemplateTypePicker as T, EntityNamePicker as a, OwnedEntityPicker as b, registerComponentRouteRef as c, TemplateList as d, entityNamePickerValidation as e, rootRouteRef as f, FIELD_EXTENSION_KEY as g, createScaffolderFieldExtension as h, ScaffolderFieldExtensions as i, EntityPickerFieldExtension as j, EntityNamePickerFieldExtension as k, OwnerPickerFieldExtension as l, OwnedEntityPickerFieldExtension as m, RepoUrlPickerFieldExtension as n, ScaffolderPage as o, scaffolderPlugin as p, TextValuePicker as q, repoPickerValidation as r, scaffolderApiRef as s, FavouriteTemplate as t };
|
|
879
|
+
//# sourceMappingURL=index-210d6da0.esm.js.map
|