@backstage/plugin-scaffolder 1.11.0-next.1 → 1.11.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 +67 -0
- package/alpha/package.json +1 -1
- package/dist/esm/ListTasksPage-a0fe74a9.esm.js +192 -0
- package/dist/esm/ListTasksPage-a0fe74a9.esm.js.map +1 -0
- package/dist/esm/{Router-aedb6d68.esm.js → Router-fae7a62f.esm.js} +80 -1278
- package/dist/esm/Router-fae7a62f.esm.js.map +1 -0
- package/dist/esm/index-5b3a75fa.esm.js +3716 -0
- package/dist/esm/index-5b3a75fa.esm.js.map +1 -0
- package/dist/esm/{index-203b9f93.esm.js → index-83c9fe8a.esm.js} +165 -17
- package/dist/esm/index-83c9fe8a.esm.js.map +1 -0
- package/dist/index.alpha.d.ts +11 -0
- package/dist/index.esm.js +57 -9
- package/dist/index.esm.js.map +1 -1
- package/package.json +19 -18
- package/dist/esm/Router-aedb6d68.esm.js.map +0 -1
- package/dist/esm/default-ad36f5e9.esm.js +0 -39
- package/dist/esm/default-ad36f5e9.esm.js.map +0 -1
- package/dist/esm/index-203b9f93.esm.js.map +0 -1
- package/dist/esm/index-e0e59ed8.esm.js +0 -1813
- package/dist/esm/index-e0e59ed8.esm.js.map +0 -1
|
@@ -1,1813 +0,0 @@
|
|
|
1
|
-
import { parseEntityRef, KubernetesValidatorFunctions, RELATION_OWNED_BY, makeValidator } from '@backstage/catalog-model';
|
|
2
|
-
import { ResponseError } from '@backstage/errors';
|
|
3
|
-
import qs from 'qs';
|
|
4
|
-
import ObservableImpl from 'zen-observable';
|
|
5
|
-
import { scmIntegrationsApiRef, scmAuthApiRef } from '@backstage/integration-react';
|
|
6
|
-
import { scaffolderApiRef as scaffolderApiRef$1, useTemplateSecrets as useTemplateSecrets$1, createScaffolderFieldExtension as createScaffolderFieldExtension$1, ScaffolderFieldExtensions as ScaffolderFieldExtensions$1, createScaffolderLayout as createScaffolderLayout$1, ScaffolderLayouts as ScaffolderLayouts$1 } from '@backstage/plugin-scaffolder-react';
|
|
7
|
-
import { useApi, identityApiRef, createExternalRouteRef, createRouteRef, createSubRouteRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, alertApiRef, useApp, useRouteRef, useRouteRefParams } from '@backstage/core-plugin-api';
|
|
8
|
-
import { catalogApiRef, humanizeEntityRef, useEntityTypeFilter, entityRouteRef } from '@backstage/plugin-catalog-react';
|
|
9
|
-
import { TextField, FormControl as FormControl$1, Box, Typography, FormControlLabel, Checkbox, makeStyles, Grid, StepButton, Paper, Button, CircularProgress } from '@material-ui/core';
|
|
10
|
-
import FormControl from '@material-ui/core/FormControl';
|
|
11
|
-
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
12
|
-
import React, { useCallback, useEffect, useState, useMemo, useRef, memo } from 'react';
|
|
13
|
-
import useAsync from 'react-use/lib/useAsync';
|
|
14
|
-
import { z } from 'zod';
|
|
15
|
-
import zodToJsonSchema from 'zod-to-json-schema';
|
|
16
|
-
import FormHelperText from '@material-ui/core/FormHelperText';
|
|
17
|
-
import Input from '@material-ui/core/Input';
|
|
18
|
-
import InputLabel from '@material-ui/core/InputLabel';
|
|
19
|
-
import { Select, Progress, DismissableBanner, Link, Page, Header, Content, ErrorPage, LogViewer } from '@backstage/core-components';
|
|
20
|
-
import useDebounce from 'react-use/lib/useDebounce';
|
|
21
|
-
import useEffectOnce from 'react-use/lib/useEffectOnce';
|
|
22
|
-
import { Autocomplete as Autocomplete$1 } from '@material-ui/lab';
|
|
23
|
-
import { useNavigate } from 'react-router-dom';
|
|
24
|
-
import capitalize from 'lodash/capitalize';
|
|
25
|
-
import CheckBoxIcon from '@material-ui/icons/CheckBox';
|
|
26
|
-
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
|
|
27
|
-
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
28
|
-
import '@material-ui/core/Button';
|
|
29
|
-
import '@material-ui/core/IconButton';
|
|
30
|
-
import '@material-ui/core/useMediaQuery';
|
|
31
|
-
import '@material-ui/icons/AddCircleOutline';
|
|
32
|
-
import '@backstage/plugin-catalog-common';
|
|
33
|
-
import '@backstage/plugin-permission-react';
|
|
34
|
-
import Grid$1 from '@material-ui/core/Grid';
|
|
35
|
-
import Step from '@material-ui/core/Step';
|
|
36
|
-
import StepLabel from '@material-ui/core/StepLabel';
|
|
37
|
-
import Stepper from '@material-ui/core/Stepper';
|
|
38
|
-
import { makeStyles as makeStyles$1, createStyles } from '@material-ui/core/styles';
|
|
39
|
-
import Typography$1 from '@material-ui/core/Typography';
|
|
40
|
-
import Cancel from '@material-ui/icons/Cancel';
|
|
41
|
-
import Check from '@material-ui/icons/Check';
|
|
42
|
-
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
|
43
|
-
import classNames from 'classnames';
|
|
44
|
-
import { DateTime, Interval } from 'luxon';
|
|
45
|
-
import useInterval from 'react-use/lib/useInterval';
|
|
46
|
-
import { useImmerReducer } from 'use-immer';
|
|
47
|
-
import LanguageIcon from '@material-ui/icons/Language';
|
|
48
|
-
|
|
49
|
-
class ScaffolderClient {
|
|
50
|
-
constructor(options) {
|
|
51
|
-
var _a, _b;
|
|
52
|
-
this.discoveryApi = options.discoveryApi;
|
|
53
|
-
this.fetchApi = (_a = options.fetchApi) != null ? _a : { fetch };
|
|
54
|
-
this.scmIntegrationsApi = options.scmIntegrationsApi;
|
|
55
|
-
this.useLongPollingLogs = (_b = options.useLongPollingLogs) != null ? _b : false;
|
|
56
|
-
this.identityApi = options.identityApi;
|
|
57
|
-
}
|
|
58
|
-
async listTasks(options) {
|
|
59
|
-
if (!this.identityApi) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
"IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method"
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
65
|
-
const { userEntityRef } = await this.identityApi.getBackstageIdentity();
|
|
66
|
-
const query = qs.stringify(
|
|
67
|
-
options.filterByOwnership === "owned" ? { createdBy: userEntityRef } : {}
|
|
68
|
-
);
|
|
69
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/tasks?${query}`);
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
throw await ResponseError.fromResponse(response);
|
|
72
|
-
}
|
|
73
|
-
return await response.json();
|
|
74
|
-
}
|
|
75
|
-
async getIntegrationsList(options) {
|
|
76
|
-
const integrations = [
|
|
77
|
-
...this.scmIntegrationsApi.azure.list(),
|
|
78
|
-
...this.scmIntegrationsApi.bitbucket.list().filter(
|
|
79
|
-
(item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)
|
|
80
|
-
),
|
|
81
|
-
...this.scmIntegrationsApi.bitbucketCloud.list(),
|
|
82
|
-
...this.scmIntegrationsApi.bitbucketServer.list(),
|
|
83
|
-
...this.scmIntegrationsApi.gerrit.list(),
|
|
84
|
-
...this.scmIntegrationsApi.github.list(),
|
|
85
|
-
...this.scmIntegrationsApi.gitlab.list()
|
|
86
|
-
].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
|
|
87
|
-
return {
|
|
88
|
-
integrations
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
async getTemplateParameterSchema(templateRef) {
|
|
92
|
-
const { namespace, kind, name } = parseEntityRef(templateRef, {
|
|
93
|
-
defaultKind: "template"
|
|
94
|
-
});
|
|
95
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
96
|
-
const templatePath = [namespace, kind, name].map((s) => encodeURIComponent(s)).join("/");
|
|
97
|
-
const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;
|
|
98
|
-
const response = await this.fetchApi.fetch(url);
|
|
99
|
-
if (!response.ok) {
|
|
100
|
-
throw await ResponseError.fromResponse(response);
|
|
101
|
-
}
|
|
102
|
-
const schema = await response.json();
|
|
103
|
-
return schema;
|
|
104
|
-
}
|
|
105
|
-
async scaffold(options) {
|
|
106
|
-
const { templateRef, values, secrets = {} } = options;
|
|
107
|
-
const url = `${await this.discoveryApi.getBaseUrl("scaffolder")}/v2/tasks`;
|
|
108
|
-
const response = await this.fetchApi.fetch(url, {
|
|
109
|
-
method: "POST",
|
|
110
|
-
headers: {
|
|
111
|
-
"Content-Type": "application/json"
|
|
112
|
-
},
|
|
113
|
-
body: JSON.stringify({
|
|
114
|
-
templateRef,
|
|
115
|
-
values: { ...values },
|
|
116
|
-
secrets
|
|
117
|
-
})
|
|
118
|
-
});
|
|
119
|
-
if (response.status !== 201) {
|
|
120
|
-
const status = `${response.status} ${response.statusText}`;
|
|
121
|
-
const body = await response.text();
|
|
122
|
-
throw new Error(`Backend request failed, ${status} ${body.trim()}`);
|
|
123
|
-
}
|
|
124
|
-
const { id } = await response.json();
|
|
125
|
-
return { taskId: id };
|
|
126
|
-
}
|
|
127
|
-
async getTask(taskId) {
|
|
128
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
129
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`;
|
|
130
|
-
const response = await this.fetchApi.fetch(url);
|
|
131
|
-
if (!response.ok) {
|
|
132
|
-
throw await ResponseError.fromResponse(response);
|
|
133
|
-
}
|
|
134
|
-
return await response.json();
|
|
135
|
-
}
|
|
136
|
-
streamLogs(options) {
|
|
137
|
-
if (this.useLongPollingLogs) {
|
|
138
|
-
return this.streamLogsPolling(options);
|
|
139
|
-
}
|
|
140
|
-
return this.streamLogsEventStream(options);
|
|
141
|
-
}
|
|
142
|
-
async dryRun(options) {
|
|
143
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
144
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/dry-run`, {
|
|
145
|
-
method: "POST",
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "application/json"
|
|
148
|
-
},
|
|
149
|
-
body: JSON.stringify({
|
|
150
|
-
template: options.template,
|
|
151
|
-
values: options.values,
|
|
152
|
-
secrets: options.secrets,
|
|
153
|
-
directoryContents: options.directoryContents
|
|
154
|
-
})
|
|
155
|
-
});
|
|
156
|
-
if (!response.ok) {
|
|
157
|
-
throw await ResponseError.fromResponse(response);
|
|
158
|
-
}
|
|
159
|
-
return response.json();
|
|
160
|
-
}
|
|
161
|
-
streamLogsEventStream({
|
|
162
|
-
taskId,
|
|
163
|
-
after
|
|
164
|
-
}) {
|
|
165
|
-
return new ObservableImpl((subscriber) => {
|
|
166
|
-
const params = new URLSearchParams();
|
|
167
|
-
if (after !== void 0) {
|
|
168
|
-
params.set("after", String(Number(after)));
|
|
169
|
-
}
|
|
170
|
-
this.discoveryApi.getBaseUrl("scaffolder").then(
|
|
171
|
-
(baseUrl) => {
|
|
172
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
|
|
173
|
-
taskId
|
|
174
|
-
)}/eventstream`;
|
|
175
|
-
const eventSource = new EventSource(url, { withCredentials: true });
|
|
176
|
-
eventSource.addEventListener("log", (event) => {
|
|
177
|
-
if (event.data) {
|
|
178
|
-
try {
|
|
179
|
-
subscriber.next(JSON.parse(event.data));
|
|
180
|
-
} catch (ex) {
|
|
181
|
-
subscriber.error(ex);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
eventSource.addEventListener("completion", (event) => {
|
|
186
|
-
if (event.data) {
|
|
187
|
-
try {
|
|
188
|
-
subscriber.next(JSON.parse(event.data));
|
|
189
|
-
} catch (ex) {
|
|
190
|
-
subscriber.error(ex);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
eventSource.close();
|
|
194
|
-
subscriber.complete();
|
|
195
|
-
});
|
|
196
|
-
eventSource.addEventListener("error", (event) => {
|
|
197
|
-
subscriber.error(event);
|
|
198
|
-
});
|
|
199
|
-
},
|
|
200
|
-
(error) => {
|
|
201
|
-
subscriber.error(error);
|
|
202
|
-
}
|
|
203
|
-
);
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
streamLogsPolling({
|
|
207
|
-
taskId,
|
|
208
|
-
after: inputAfter
|
|
209
|
-
}) {
|
|
210
|
-
let after = inputAfter;
|
|
211
|
-
return new ObservableImpl((subscriber) => {
|
|
212
|
-
this.discoveryApi.getBaseUrl("scaffolder").then(async (baseUrl) => {
|
|
213
|
-
while (!subscriber.closed) {
|
|
214
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
|
|
215
|
-
taskId
|
|
216
|
-
)}/events?${qs.stringify({ after })}`;
|
|
217
|
-
const response = await this.fetchApi.fetch(url);
|
|
218
|
-
if (!response.ok) {
|
|
219
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
const logs = await response.json();
|
|
223
|
-
for (const event of logs) {
|
|
224
|
-
after = Number(event.id);
|
|
225
|
-
subscriber.next(event);
|
|
226
|
-
if (event.type === "completion") {
|
|
227
|
-
subscriber.complete();
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
async listActions() {
|
|
236
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
237
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/actions`);
|
|
238
|
-
if (!response.ok) {
|
|
239
|
-
throw await ResponseError.fromResponse(response);
|
|
240
|
-
}
|
|
241
|
-
return await response.json();
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function makeFieldSchemaFromZod(returnSchema, uiOptionsSchema) {
|
|
246
|
-
return {
|
|
247
|
-
schema: {
|
|
248
|
-
returnValue: zodToJsonSchema(returnSchema),
|
|
249
|
-
uiOptions: uiOptionsSchema ? zodToJsonSchema(uiOptionsSchema) : void 0
|
|
250
|
-
},
|
|
251
|
-
type: null,
|
|
252
|
-
uiOptionsType: null
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const entityQueryFilterExpressionSchema = z.record(
|
|
257
|
-
z.string().or(z.array(z.string()))
|
|
258
|
-
);
|
|
259
|
-
const EntityPickerFieldSchema = makeFieldSchemaFromZod(
|
|
260
|
-
z.string(),
|
|
261
|
-
z.object({
|
|
262
|
-
/**
|
|
263
|
-
* @deprecated Use `catalogFilter` instead.
|
|
264
|
-
*/
|
|
265
|
-
allowedKinds: z.array(z.string()).optional().describe(
|
|
266
|
-
"DEPRECATED: Use `catalogFilter` instead. List of kinds of entities to derive options from"
|
|
267
|
-
),
|
|
268
|
-
defaultKind: z.string().optional().describe(
|
|
269
|
-
"The default entity kind. Options of this kind will not be prefixed."
|
|
270
|
-
),
|
|
271
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
272
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
273
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
274
|
-
),
|
|
275
|
-
catalogFilter: z.array(entityQueryFilterExpressionSchema).or(entityQueryFilterExpressionSchema).optional().describe("List of key-value filter expression for entities")
|
|
276
|
-
})
|
|
277
|
-
);
|
|
278
|
-
const EntityPickerSchema = EntityPickerFieldSchema.schema;
|
|
279
|
-
|
|
280
|
-
const EntityPicker = (props) => {
|
|
281
|
-
var _a, _b, _c, _d, _e, _f;
|
|
282
|
-
const {
|
|
283
|
-
onChange,
|
|
284
|
-
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
285
|
-
required,
|
|
286
|
-
uiSchema,
|
|
287
|
-
rawErrors,
|
|
288
|
-
formData,
|
|
289
|
-
idSchema
|
|
290
|
-
} = props;
|
|
291
|
-
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
292
|
-
const catalogFilter = ((_b = uiSchema["ui:options"]) == null ? void 0 : _b.catalogFilter) || allowedKinds && { kind: allowedKinds };
|
|
293
|
-
const defaultKind = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.defaultKind;
|
|
294
|
-
const defaultNamespace = (_d = uiSchema["ui:options"]) == null ? void 0 : _d.defaultNamespace;
|
|
295
|
-
const catalogApi = useApi(catalogApiRef);
|
|
296
|
-
const { value: entities, loading } = useAsync(
|
|
297
|
-
() => catalogApi.getEntities(
|
|
298
|
-
catalogFilter ? { filter: catalogFilter } : void 0
|
|
299
|
-
)
|
|
300
|
-
);
|
|
301
|
-
const entityRefs = entities == null ? void 0 : entities.items.map(
|
|
302
|
-
(e) => humanizeEntityRef(e, { defaultKind, defaultNamespace })
|
|
303
|
-
);
|
|
304
|
-
const onSelect = useCallback(
|
|
305
|
-
(_, value) => {
|
|
306
|
-
onChange(value != null ? value : void 0);
|
|
307
|
-
},
|
|
308
|
-
[onChange]
|
|
309
|
-
);
|
|
310
|
-
useEffect(() => {
|
|
311
|
-
if ((entityRefs == null ? void 0 : entityRefs.length) === 1) {
|
|
312
|
-
onChange(entityRefs[0]);
|
|
313
|
-
}
|
|
314
|
-
}, [entityRefs, onChange]);
|
|
315
|
-
return /* @__PURE__ */ React.createElement(
|
|
316
|
-
FormControl,
|
|
317
|
-
{
|
|
318
|
-
margin: "normal",
|
|
319
|
-
required,
|
|
320
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData
|
|
321
|
-
},
|
|
322
|
-
/* @__PURE__ */ React.createElement(
|
|
323
|
-
Autocomplete,
|
|
324
|
-
{
|
|
325
|
-
disabled: (entityRefs == null ? void 0 : entityRefs.length) === 1,
|
|
326
|
-
id: idSchema == null ? void 0 : idSchema.$id,
|
|
327
|
-
value: formData || "",
|
|
328
|
-
loading,
|
|
329
|
-
onChange: onSelect,
|
|
330
|
-
options: entityRefs || [],
|
|
331
|
-
autoSelect: true,
|
|
332
|
-
freeSolo: (_f = (_e = uiSchema["ui:options"]) == null ? void 0 : _e.allowArbitraryValues) != null ? _f : true,
|
|
333
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
334
|
-
TextField,
|
|
335
|
-
{
|
|
336
|
-
...params,
|
|
337
|
-
label: title,
|
|
338
|
-
margin: "dense",
|
|
339
|
-
helperText: description,
|
|
340
|
-
FormHelperTextProps: { margin: "dense", style: { marginLeft: 0 } },
|
|
341
|
-
variant: "outlined",
|
|
342
|
-
required,
|
|
343
|
-
InputProps: params.InputProps
|
|
344
|
-
}
|
|
345
|
-
)
|
|
346
|
-
}
|
|
347
|
-
)
|
|
348
|
-
);
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
const entityNamePickerValidation = (value, validation) => {
|
|
352
|
-
if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
|
|
353
|
-
validation.addError(
|
|
354
|
-
"Must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters."
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
const EntityNamePickerFieldSchema = makeFieldSchemaFromZod(z.string());
|
|
360
|
-
const EntityNamePickerSchema = EntityNamePickerFieldSchema.schema;
|
|
361
|
-
|
|
362
|
-
const EntityNamePicker = (props) => {
|
|
363
|
-
const {
|
|
364
|
-
onChange,
|
|
365
|
-
required,
|
|
366
|
-
schema: { title = "Name", description = "Unique name of the component" },
|
|
367
|
-
rawErrors,
|
|
368
|
-
formData,
|
|
369
|
-
uiSchema: { "ui:autofocus": autoFocus },
|
|
370
|
-
idSchema,
|
|
371
|
-
placeholder
|
|
372
|
-
} = props;
|
|
373
|
-
return /* @__PURE__ */ React.createElement(
|
|
374
|
-
TextField,
|
|
375
|
-
{
|
|
376
|
-
id: idSchema == null ? void 0 : idSchema.$id,
|
|
377
|
-
label: title,
|
|
378
|
-
placeholder,
|
|
379
|
-
helperText: description,
|
|
380
|
-
required,
|
|
381
|
-
value: formData != null ? formData : "",
|
|
382
|
-
onChange: ({ target: { value } }) => onChange(value),
|
|
383
|
-
margin: "normal",
|
|
384
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
|
|
385
|
-
inputProps: { autoFocus }
|
|
386
|
-
}
|
|
387
|
-
);
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
const OwnerPickerFieldSchema = makeFieldSchemaFromZod(
|
|
391
|
-
z.string(),
|
|
392
|
-
z.object({
|
|
393
|
-
/**
|
|
394
|
-
* @deprecated Use `catalogFilter` instead.
|
|
395
|
-
*/
|
|
396
|
-
allowedKinds: z.array(z.string()).default(["Group", "User"]).optional().describe(
|
|
397
|
-
"DEPRECATED: Use `catalogFilter` instead. List of kinds of entities to derive options from. Defaults to Group and User"
|
|
398
|
-
),
|
|
399
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
400
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
401
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
402
|
-
),
|
|
403
|
-
catalogFilter: z.array(entityQueryFilterExpressionSchema).or(entityQueryFilterExpressionSchema).optional().describe("List of key-value filter expression for entities")
|
|
404
|
-
})
|
|
405
|
-
);
|
|
406
|
-
const OwnerPickerSchema = OwnerPickerFieldSchema.schema;
|
|
407
|
-
|
|
408
|
-
const OwnerPicker = (props) => {
|
|
409
|
-
var _a, _b, _c, _d, _e;
|
|
410
|
-
const {
|
|
411
|
-
schema: { title = "Owner", description = "The owner of the component" },
|
|
412
|
-
uiSchema,
|
|
413
|
-
...restProps
|
|
414
|
-
} = props;
|
|
415
|
-
const defaultNamespace = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.defaultNamespace;
|
|
416
|
-
const allowedKinds = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.allowedKinds;
|
|
417
|
-
const catalogFilter = ((_c = uiSchema["ui:options"]) == null ? void 0 : _c.catalogFilter) || {
|
|
418
|
-
kind: allowedKinds || ["Group", "User"]
|
|
419
|
-
};
|
|
420
|
-
const ownerUiSchema = {
|
|
421
|
-
...uiSchema,
|
|
422
|
-
"ui:options": {
|
|
423
|
-
catalogFilter,
|
|
424
|
-
defaultKind: "Group",
|
|
425
|
-
allowArbitraryValues: (_e = (_d = uiSchema["ui:options"]) == null ? void 0 : _d.allowArbitraryValues) != null ? _e : true,
|
|
426
|
-
...defaultNamespace !== void 0 ? { defaultNamespace } : {}
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
return /* @__PURE__ */ React.createElement(
|
|
430
|
-
EntityPicker,
|
|
431
|
-
{
|
|
432
|
-
...restProps,
|
|
433
|
-
schema: { title, description },
|
|
434
|
-
uiSchema: ownerUiSchema
|
|
435
|
-
}
|
|
436
|
-
);
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
const RepoUrlPickerFieldSchema = makeFieldSchemaFromZod(
|
|
440
|
-
z.string(),
|
|
441
|
-
z.object({
|
|
442
|
-
allowedHosts: z.array(z.string()).optional().describe("List of allowed SCM platform hosts"),
|
|
443
|
-
allowedOrganizations: z.array(z.string()).optional().describe("List of allowed organizations in the given SCM platform"),
|
|
444
|
-
allowedOwners: z.array(z.string()).optional().describe("List of allowed owners in the given SCM platform"),
|
|
445
|
-
allowedProjects: z.array(z.string()).optional().describe("List of allowed projects in the given SCM platform"),
|
|
446
|
-
allowedRepos: z.array(z.string()).optional().describe("List of allowed repos in the given SCM platform"),
|
|
447
|
-
requestUserCredentials: z.object({
|
|
448
|
-
secretsKey: z.string().describe(
|
|
449
|
-
"Key used within the template secrets context to store the credential"
|
|
450
|
-
),
|
|
451
|
-
additionalScopes: z.object({
|
|
452
|
-
gerrit: z.array(z.string()).optional().describe("Additional Gerrit scopes to request"),
|
|
453
|
-
github: z.array(z.string()).optional().describe("Additional GitHub scopes to request"),
|
|
454
|
-
gitlab: z.array(z.string()).optional().describe("Additional GitLab scopes to request"),
|
|
455
|
-
bitbucket: z.array(z.string()).optional().describe("Additional BitBucket scopes to request"),
|
|
456
|
-
azure: z.array(z.string()).optional().describe("Additional Azure scopes to request")
|
|
457
|
-
}).optional().describe("Additional permission scopes to request")
|
|
458
|
-
}).optional().describe(
|
|
459
|
-
"If defined will request user credentials to auth against the given SCM platform"
|
|
460
|
-
)
|
|
461
|
-
})
|
|
462
|
-
);
|
|
463
|
-
const RepoUrlPickerSchema = RepoUrlPickerFieldSchema.schema;
|
|
464
|
-
|
|
465
|
-
const repoPickerValidation = (value, validation, context) => {
|
|
466
|
-
var _a, _b;
|
|
467
|
-
try {
|
|
468
|
-
const { host, searchParams } = new URL(`https://${value}`);
|
|
469
|
-
const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);
|
|
470
|
-
if (!host) {
|
|
471
|
-
validation.addError(
|
|
472
|
-
"Incomplete repository location provided, host not provided"
|
|
473
|
-
);
|
|
474
|
-
} else {
|
|
475
|
-
if (((_a = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _a.type) === "bitbucket") {
|
|
476
|
-
if (host === "bitbucket.org" && !searchParams.get("workspace")) {
|
|
477
|
-
validation.addError(
|
|
478
|
-
"Incomplete repository location provided, workspace not provided"
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
if (!searchParams.get("project")) {
|
|
482
|
-
validation.addError(
|
|
483
|
-
"Incomplete repository location provided, project not provided"
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
} else if (((_b = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _b.type) !== "gerrit") {
|
|
487
|
-
if (!searchParams.get("owner")) {
|
|
488
|
-
validation.addError(
|
|
489
|
-
"Incomplete repository location provided, owner not provided"
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
if (!searchParams.get("repo")) {
|
|
494
|
-
validation.addError(
|
|
495
|
-
"Incomplete repository location provided, repo not provided"
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
} catch {
|
|
500
|
-
validation.addError("Unable to parse the Repository URL");
|
|
501
|
-
}
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
const GithubRepoPicker = (props) => {
|
|
505
|
-
const { allowedOwners = [], rawErrors, state, onChange } = props;
|
|
506
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
507
|
-
const { owner } = state;
|
|
508
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
509
|
-
FormControl,
|
|
510
|
-
{
|
|
511
|
-
margin: "normal",
|
|
512
|
-
required: true,
|
|
513
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
514
|
-
},
|
|
515
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
516
|
-
Select,
|
|
517
|
-
{
|
|
518
|
-
native: true,
|
|
519
|
-
label: "Owner Available",
|
|
520
|
-
onChange: (s) => onChange({ owner: String(Array.isArray(s) ? s[0] : s) }),
|
|
521
|
-
disabled: allowedOwners.length === 1,
|
|
522
|
-
selected: owner,
|
|
523
|
-
items: ownerItems
|
|
524
|
-
}
|
|
525
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Owner"), /* @__PURE__ */ React.createElement(
|
|
526
|
-
Input,
|
|
527
|
-
{
|
|
528
|
-
id: "ownerInput",
|
|
529
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
530
|
-
value: owner
|
|
531
|
-
}
|
|
532
|
-
)),
|
|
533
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The organization, user or project that this repo will belong to")
|
|
534
|
-
));
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
const GitlabRepoPicker = (props) => {
|
|
538
|
-
const { allowedOwners = [], state, onChange, rawErrors } = props;
|
|
539
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
540
|
-
const { owner } = state;
|
|
541
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
542
|
-
FormControl,
|
|
543
|
-
{
|
|
544
|
-
margin: "normal",
|
|
545
|
-
required: true,
|
|
546
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
547
|
-
},
|
|
548
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
549
|
-
Select,
|
|
550
|
-
{
|
|
551
|
-
native: true,
|
|
552
|
-
label: "Owner Available",
|
|
553
|
-
onChange: (selected) => onChange({
|
|
554
|
-
owner: String(Array.isArray(selected) ? selected[0] : selected)
|
|
555
|
-
}),
|
|
556
|
-
disabled: allowedOwners.length === 1,
|
|
557
|
-
selected: owner,
|
|
558
|
-
items: ownerItems
|
|
559
|
-
}
|
|
560
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Owner"), /* @__PURE__ */ React.createElement(
|
|
561
|
-
Input,
|
|
562
|
-
{
|
|
563
|
-
id: "ownerInput",
|
|
564
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
565
|
-
value: owner
|
|
566
|
-
}
|
|
567
|
-
)),
|
|
568
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "GitLab namespace where this repository will belong to. It can be the name of organization, group, subgroup, user, or the project.")
|
|
569
|
-
));
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
const AzureRepoPicker = (props) => {
|
|
573
|
-
const {
|
|
574
|
-
allowedOrganizations = [],
|
|
575
|
-
allowedOwners = [],
|
|
576
|
-
rawErrors,
|
|
577
|
-
state,
|
|
578
|
-
onChange
|
|
579
|
-
} = props;
|
|
580
|
-
const organizationItems = allowedOrganizations ? allowedOrganizations.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
581
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
582
|
-
const { organization, owner } = state;
|
|
583
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
584
|
-
FormControl,
|
|
585
|
-
{
|
|
586
|
-
margin: "normal",
|
|
587
|
-
required: true,
|
|
588
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !organization
|
|
589
|
-
},
|
|
590
|
-
(allowedOrganizations == null ? void 0 : allowedOrganizations.length) ? /* @__PURE__ */ React.createElement(
|
|
591
|
-
Select,
|
|
592
|
-
{
|
|
593
|
-
native: true,
|
|
594
|
-
label: "Organization",
|
|
595
|
-
onChange: (s) => onChange({ organization: String(Array.isArray(s) ? s[0] : s) }),
|
|
596
|
-
disabled: allowedOrganizations.length === 1,
|
|
597
|
-
selected: organization,
|
|
598
|
-
items: organizationItems
|
|
599
|
-
}
|
|
600
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "orgInput" }, "Organization"), /* @__PURE__ */ React.createElement(
|
|
601
|
-
Input,
|
|
602
|
-
{
|
|
603
|
-
id: "orgInput",
|
|
604
|
-
onChange: (e) => onChange({ organization: e.target.value }),
|
|
605
|
-
value: organization
|
|
606
|
-
}
|
|
607
|
-
)),
|
|
608
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Organization that this repo will belong to")
|
|
609
|
-
), /* @__PURE__ */ React.createElement(
|
|
610
|
-
FormControl,
|
|
611
|
-
{
|
|
612
|
-
margin: "normal",
|
|
613
|
-
required: true,
|
|
614
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
615
|
-
},
|
|
616
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
617
|
-
Select,
|
|
618
|
-
{
|
|
619
|
-
native: true,
|
|
620
|
-
label: "Owner",
|
|
621
|
-
onChange: (s) => onChange({ owner: String(Array.isArray(s) ? s[0] : s) }),
|
|
622
|
-
disabled: allowedOwners.length === 1,
|
|
623
|
-
selected: owner,
|
|
624
|
-
items: ownerItems
|
|
625
|
-
}
|
|
626
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Project"), /* @__PURE__ */ React.createElement(
|
|
627
|
-
Input,
|
|
628
|
-
{
|
|
629
|
-
id: "ownerInput",
|
|
630
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
631
|
-
value: owner
|
|
632
|
-
}
|
|
633
|
-
)),
|
|
634
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Project that this repo will belong to")
|
|
635
|
-
));
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
const BitbucketRepoPicker = (props) => {
|
|
639
|
-
const {
|
|
640
|
-
allowedOwners = [],
|
|
641
|
-
allowedProjects = [],
|
|
642
|
-
onChange,
|
|
643
|
-
rawErrors,
|
|
644
|
-
state
|
|
645
|
-
} = props;
|
|
646
|
-
const { host, workspace, project } = state;
|
|
647
|
-
const ownerItems = allowedOwners ? allowedOwners == null ? void 0 : allowedOwners.map((i) => ({ label: i, value: i })) : [];
|
|
648
|
-
const projectItems = allowedProjects ? allowedProjects == null ? void 0 : allowedProjects.map((i) => ({ label: i, value: i })) : [];
|
|
649
|
-
useEffect(() => {
|
|
650
|
-
if (host === "bitbucket.org" && allowedOwners.length) {
|
|
651
|
-
onChange({ workspace: allowedOwners[0] });
|
|
652
|
-
}
|
|
653
|
-
}, [allowedOwners, host, onChange]);
|
|
654
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, host === "bitbucket.org" && /* @__PURE__ */ React.createElement(
|
|
655
|
-
FormControl,
|
|
656
|
-
{
|
|
657
|
-
margin: "normal",
|
|
658
|
-
required: true,
|
|
659
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
|
|
660
|
-
},
|
|
661
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
662
|
-
Select,
|
|
663
|
-
{
|
|
664
|
-
native: true,
|
|
665
|
-
label: "Allowed Workspaces",
|
|
666
|
-
onChange: (s) => onChange({ workspace: String(Array.isArray(s) ? s[0] : s) }),
|
|
667
|
-
disabled: allowedOwners.length === 1,
|
|
668
|
-
selected: workspace,
|
|
669
|
-
items: ownerItems
|
|
670
|
-
}
|
|
671
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "workspaceInput" }, "Workspace"), /* @__PURE__ */ React.createElement(
|
|
672
|
-
Input,
|
|
673
|
-
{
|
|
674
|
-
id: "workspaceInput",
|
|
675
|
-
onChange: (e) => onChange({ workspace: e.target.value }),
|
|
676
|
-
value: workspace
|
|
677
|
-
}
|
|
678
|
-
)),
|
|
679
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Workspace that this repo will belong to")
|
|
680
|
-
), /* @__PURE__ */ React.createElement(
|
|
681
|
-
FormControl,
|
|
682
|
-
{
|
|
683
|
-
margin: "normal",
|
|
684
|
-
required: true,
|
|
685
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !project
|
|
686
|
-
},
|
|
687
|
-
(allowedProjects == null ? void 0 : allowedProjects.length) ? /* @__PURE__ */ React.createElement(
|
|
688
|
-
Select,
|
|
689
|
-
{
|
|
690
|
-
native: true,
|
|
691
|
-
label: "Allowed Projects",
|
|
692
|
-
onChange: (s) => onChange({ project: String(Array.isArray(s) ? s[0] : s) }),
|
|
693
|
-
disabled: allowedProjects.length === 1,
|
|
694
|
-
selected: project,
|
|
695
|
-
items: projectItems
|
|
696
|
-
}
|
|
697
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "projectInput" }, "Project"), /* @__PURE__ */ React.createElement(
|
|
698
|
-
Input,
|
|
699
|
-
{
|
|
700
|
-
id: "projectInput",
|
|
701
|
-
onChange: (e) => onChange({ project: e.target.value }),
|
|
702
|
-
value: project
|
|
703
|
-
}
|
|
704
|
-
)),
|
|
705
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Project that this repo will belong to")
|
|
706
|
-
));
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
const GerritRepoPicker = (props) => {
|
|
710
|
-
const { onChange, rawErrors, state } = props;
|
|
711
|
-
const { workspace, owner } = state;
|
|
712
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormControl, { margin: "normal", error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace }, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Owner"), /* @__PURE__ */ React.createElement(
|
|
713
|
-
Input,
|
|
714
|
-
{
|
|
715
|
-
id: "ownerInput",
|
|
716
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
717
|
-
value: owner
|
|
718
|
-
}
|
|
719
|
-
), /* @__PURE__ */ React.createElement(FormHelperText, null, "The owner of the project (optional)")), /* @__PURE__ */ React.createElement(
|
|
720
|
-
FormControl,
|
|
721
|
-
{
|
|
722
|
-
margin: "normal",
|
|
723
|
-
required: true,
|
|
724
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
|
|
725
|
-
},
|
|
726
|
-
/* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "parentInput" }, "Parent"),
|
|
727
|
-
/* @__PURE__ */ React.createElement(
|
|
728
|
-
Input,
|
|
729
|
-
{
|
|
730
|
-
id: "parentInput",
|
|
731
|
-
onChange: (e) => onChange({ workspace: e.target.value }),
|
|
732
|
-
value: workspace
|
|
733
|
-
}
|
|
734
|
-
),
|
|
735
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The project parent that the repo will belong to")
|
|
736
|
-
));
|
|
737
|
-
};
|
|
738
|
-
|
|
739
|
-
const RepoUrlPickerHost = (props) => {
|
|
740
|
-
const { host, hosts, onChange, rawErrors } = props;
|
|
741
|
-
const scaffolderApi = useApi(scaffolderApiRef$1);
|
|
742
|
-
const { value: { integrations } = { integrations: [] }, loading } = useAsync(
|
|
743
|
-
async () => {
|
|
744
|
-
return await scaffolderApi.getIntegrationsList({
|
|
745
|
-
allowedHosts: hosts != null ? hosts : []
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
);
|
|
749
|
-
useEffect(() => {
|
|
750
|
-
if (!host) {
|
|
751
|
-
if (hosts == null ? void 0 : hosts.length) {
|
|
752
|
-
onChange(hosts[0]);
|
|
753
|
-
} else if (integrations == null ? void 0 : integrations.length) {
|
|
754
|
-
onChange(integrations[0].host);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}, [hosts, host, onChange, integrations]);
|
|
758
|
-
const hostsOptions = integrations ? integrations.filter((i) => (hosts == null ? void 0 : hosts.length) ? hosts == null ? void 0 : hosts.includes(i.host) : true).map((i) => ({ label: i.title, value: i.host })) : [{ label: "Loading...", value: "loading" }];
|
|
759
|
-
if (loading) {
|
|
760
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
761
|
-
}
|
|
762
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
763
|
-
FormControl,
|
|
764
|
-
{
|
|
765
|
-
margin: "normal",
|
|
766
|
-
required: true,
|
|
767
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !host
|
|
768
|
-
},
|
|
769
|
-
/* @__PURE__ */ React.createElement(
|
|
770
|
-
Select,
|
|
771
|
-
{
|
|
772
|
-
native: true,
|
|
773
|
-
disabled: (hosts == null ? void 0 : hosts.length) === 1,
|
|
774
|
-
label: "Host",
|
|
775
|
-
onChange: (s) => onChange(String(Array.isArray(s) ? s[0] : s)),
|
|
776
|
-
selected: host,
|
|
777
|
-
items: hostsOptions,
|
|
778
|
-
"data-testid": "host-select"
|
|
779
|
-
}
|
|
780
|
-
),
|
|
781
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The host where the repository will be created")
|
|
782
|
-
));
|
|
783
|
-
};
|
|
784
|
-
|
|
785
|
-
const RepoUrlPickerRepoName = (props) => {
|
|
786
|
-
const { repoName, allowedRepos, onChange, rawErrors } = props;
|
|
787
|
-
useEffect(() => {
|
|
788
|
-
if (!repoName) {
|
|
789
|
-
if (allowedRepos == null ? void 0 : allowedRepos.length) {
|
|
790
|
-
onChange(allowedRepos[0]);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}, [allowedRepos, repoName, onChange]);
|
|
794
|
-
const repoItems = allowedRepos ? allowedRepos.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
795
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
796
|
-
FormControl,
|
|
797
|
-
{
|
|
798
|
-
margin: "normal",
|
|
799
|
-
required: true,
|
|
800
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !repoName
|
|
801
|
-
},
|
|
802
|
-
(allowedRepos == null ? void 0 : allowedRepos.length) ? /* @__PURE__ */ React.createElement(
|
|
803
|
-
Select,
|
|
804
|
-
{
|
|
805
|
-
native: true,
|
|
806
|
-
label: "Repositories Available",
|
|
807
|
-
onChange: (selected) => String(Array.isArray(selected) ? selected[0] : selected),
|
|
808
|
-
disabled: allowedRepos.length === 1,
|
|
809
|
-
selected: repoName,
|
|
810
|
-
items: repoItems
|
|
811
|
-
}
|
|
812
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "repoNameInput" }, "Repository"), /* @__PURE__ */ React.createElement(
|
|
813
|
-
Input,
|
|
814
|
-
{
|
|
815
|
-
id: "repoNameInput",
|
|
816
|
-
onChange: (e) => onChange(String(e.target.value)),
|
|
817
|
-
value: repoName
|
|
818
|
-
}
|
|
819
|
-
)),
|
|
820
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The name of the repository")
|
|
821
|
-
));
|
|
822
|
-
};
|
|
823
|
-
|
|
824
|
-
function serializeRepoPickerUrl(data) {
|
|
825
|
-
if (!data.host) {
|
|
826
|
-
return void 0;
|
|
827
|
-
}
|
|
828
|
-
const params = new URLSearchParams();
|
|
829
|
-
if (data.owner) {
|
|
830
|
-
params.set("owner", data.owner);
|
|
831
|
-
}
|
|
832
|
-
if (data.repoName) {
|
|
833
|
-
params.set("repo", data.repoName);
|
|
834
|
-
}
|
|
835
|
-
if (data.organization) {
|
|
836
|
-
params.set("organization", data.organization);
|
|
837
|
-
}
|
|
838
|
-
if (data.workspace) {
|
|
839
|
-
params.set("workspace", data.workspace);
|
|
840
|
-
}
|
|
841
|
-
if (data.project) {
|
|
842
|
-
params.set("project", data.project);
|
|
843
|
-
}
|
|
844
|
-
return `${data.host}?${params.toString()}`;
|
|
845
|
-
}
|
|
846
|
-
function parseRepoPickerUrl(url) {
|
|
847
|
-
let host = "";
|
|
848
|
-
let owner = "";
|
|
849
|
-
let repoName = "";
|
|
850
|
-
let organization = "";
|
|
851
|
-
let workspace = "";
|
|
852
|
-
let project = "";
|
|
853
|
-
try {
|
|
854
|
-
if (url) {
|
|
855
|
-
const parsed = new URL(`https://${url}`);
|
|
856
|
-
host = parsed.host;
|
|
857
|
-
owner = parsed.searchParams.get("owner") || "";
|
|
858
|
-
repoName = parsed.searchParams.get("repo") || "";
|
|
859
|
-
organization = parsed.searchParams.get("organization") || "";
|
|
860
|
-
workspace = parsed.searchParams.get("workspace") || "";
|
|
861
|
-
project = parsed.searchParams.get("project") || "";
|
|
862
|
-
}
|
|
863
|
-
} catch {
|
|
864
|
-
}
|
|
865
|
-
return { host, owner, repoName, organization, workspace, project };
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
const RepoUrlPicker = (props) => {
|
|
869
|
-
var _a, _b;
|
|
870
|
-
const { uiSchema, onChange, rawErrors, formData } = props;
|
|
871
|
-
const [state, setState] = useState(
|
|
872
|
-
parseRepoPickerUrl(formData)
|
|
873
|
-
);
|
|
874
|
-
const integrationApi = useApi(scmIntegrationsApiRef);
|
|
875
|
-
const scmAuthApi = useApi(scmAuthApiRef);
|
|
876
|
-
const { setSecrets } = useTemplateSecrets$1();
|
|
877
|
-
const allowedHosts = useMemo(
|
|
878
|
-
() => {
|
|
879
|
-
var _a2, _b2;
|
|
880
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedHosts) != null ? _b2 : [];
|
|
881
|
-
},
|
|
882
|
-
[uiSchema]
|
|
883
|
-
);
|
|
884
|
-
const allowedOrganizations = useMemo(
|
|
885
|
-
() => {
|
|
886
|
-
var _a2, _b2;
|
|
887
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOrganizations) != null ? _b2 : [];
|
|
888
|
-
},
|
|
889
|
-
[uiSchema]
|
|
890
|
-
);
|
|
891
|
-
const allowedOwners = useMemo(
|
|
892
|
-
() => {
|
|
893
|
-
var _a2, _b2;
|
|
894
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOwners) != null ? _b2 : [];
|
|
895
|
-
},
|
|
896
|
-
[uiSchema]
|
|
897
|
-
);
|
|
898
|
-
const allowedProjects = useMemo(
|
|
899
|
-
() => {
|
|
900
|
-
var _a2, _b2;
|
|
901
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedProjects) != null ? _b2 : [];
|
|
902
|
-
},
|
|
903
|
-
[uiSchema]
|
|
904
|
-
);
|
|
905
|
-
const allowedRepos = useMemo(
|
|
906
|
-
() => {
|
|
907
|
-
var _a2, _b2;
|
|
908
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedRepos) != null ? _b2 : [];
|
|
909
|
-
},
|
|
910
|
-
[uiSchema]
|
|
911
|
-
);
|
|
912
|
-
const { owner, organization, project, repoName } = state;
|
|
913
|
-
useEffect(() => {
|
|
914
|
-
onChange(serializeRepoPickerUrl(state));
|
|
915
|
-
}, [state, onChange]);
|
|
916
|
-
useEffect(() => {
|
|
917
|
-
if (allowedOrganizations.length > 0 && !organization) {
|
|
918
|
-
setState((prevState) => ({
|
|
919
|
-
...prevState,
|
|
920
|
-
organization: allowedOrganizations[0]
|
|
921
|
-
}));
|
|
922
|
-
}
|
|
923
|
-
}, [setState, allowedOrganizations, organization]);
|
|
924
|
-
useEffect(() => {
|
|
925
|
-
if (allowedOwners.length > 0 && !owner) {
|
|
926
|
-
setState((prevState) => ({
|
|
927
|
-
...prevState,
|
|
928
|
-
owner: allowedOwners[0]
|
|
929
|
-
}));
|
|
930
|
-
}
|
|
931
|
-
}, [setState, allowedOwners, owner]);
|
|
932
|
-
useEffect(() => {
|
|
933
|
-
if (allowedProjects.length > 0 && !project) {
|
|
934
|
-
setState((prevState) => ({
|
|
935
|
-
...prevState,
|
|
936
|
-
project: allowedProjects[0]
|
|
937
|
-
}));
|
|
938
|
-
}
|
|
939
|
-
}, [setState, allowedProjects, project]);
|
|
940
|
-
useEffect(() => {
|
|
941
|
-
if (allowedRepos.length > 0 && !repoName) {
|
|
942
|
-
setState((prevState) => ({ ...prevState, repoName: allowedRepos[0] }));
|
|
943
|
-
}
|
|
944
|
-
}, [setState, allowedRepos, repoName]);
|
|
945
|
-
const updateLocalState = useCallback(
|
|
946
|
-
(newState) => {
|
|
947
|
-
setState((prevState) => ({ ...prevState, ...newState }));
|
|
948
|
-
},
|
|
949
|
-
[setState]
|
|
950
|
-
);
|
|
951
|
-
useDebounce(
|
|
952
|
-
async () => {
|
|
953
|
-
var _a2;
|
|
954
|
-
const { requestUserCredentials } = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) != null ? _a2 : {};
|
|
955
|
-
if (!requestUserCredentials || !(state.host && state.owner && state.repoName)) {
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
const [encodedHost, encodedOwner, encodedRepoName] = [
|
|
959
|
-
state.host,
|
|
960
|
-
state.owner,
|
|
961
|
-
state.repoName
|
|
962
|
-
].map(encodeURIComponent);
|
|
963
|
-
const { token } = await scmAuthApi.getCredentials({
|
|
964
|
-
url: `https://${encodedHost}/${encodedOwner}/${encodedRepoName}`,
|
|
965
|
-
additionalScope: {
|
|
966
|
-
repoWrite: true,
|
|
967
|
-
customScopes: requestUserCredentials.additionalScopes
|
|
968
|
-
}
|
|
969
|
-
});
|
|
970
|
-
setSecrets({ [requestUserCredentials.secretsKey]: token });
|
|
971
|
-
},
|
|
972
|
-
500,
|
|
973
|
-
[state, uiSchema]
|
|
974
|
-
);
|
|
975
|
-
const hostType = (_b = state.host && ((_a = integrationApi.byHost(state.host)) == null ? void 0 : _a.type)) != null ? _b : null;
|
|
976
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
977
|
-
RepoUrlPickerHost,
|
|
978
|
-
{
|
|
979
|
-
host: state.host,
|
|
980
|
-
hosts: allowedHosts,
|
|
981
|
-
onChange: (host) => setState((prevState) => ({ ...prevState, host })),
|
|
982
|
-
rawErrors
|
|
983
|
-
}
|
|
984
|
-
), hostType === "github" && /* @__PURE__ */ React.createElement(
|
|
985
|
-
GithubRepoPicker,
|
|
986
|
-
{
|
|
987
|
-
allowedOwners,
|
|
988
|
-
onChange: updateLocalState,
|
|
989
|
-
rawErrors,
|
|
990
|
-
state
|
|
991
|
-
}
|
|
992
|
-
), hostType === "gitlab" && /* @__PURE__ */ React.createElement(
|
|
993
|
-
GitlabRepoPicker,
|
|
994
|
-
{
|
|
995
|
-
allowedOwners,
|
|
996
|
-
rawErrors,
|
|
997
|
-
state,
|
|
998
|
-
onChange: updateLocalState
|
|
999
|
-
}
|
|
1000
|
-
), hostType === "bitbucket" && /* @__PURE__ */ React.createElement(
|
|
1001
|
-
BitbucketRepoPicker,
|
|
1002
|
-
{
|
|
1003
|
-
allowedOwners,
|
|
1004
|
-
allowedProjects,
|
|
1005
|
-
rawErrors,
|
|
1006
|
-
state,
|
|
1007
|
-
onChange: updateLocalState
|
|
1008
|
-
}
|
|
1009
|
-
), hostType === "azure" && /* @__PURE__ */ React.createElement(
|
|
1010
|
-
AzureRepoPicker,
|
|
1011
|
-
{
|
|
1012
|
-
allowedOrganizations,
|
|
1013
|
-
allowedOwners,
|
|
1014
|
-
rawErrors,
|
|
1015
|
-
state,
|
|
1016
|
-
onChange: updateLocalState
|
|
1017
|
-
}
|
|
1018
|
-
), hostType === "gerrit" && /* @__PURE__ */ React.createElement(
|
|
1019
|
-
GerritRepoPicker,
|
|
1020
|
-
{
|
|
1021
|
-
rawErrors,
|
|
1022
|
-
state,
|
|
1023
|
-
onChange: updateLocalState
|
|
1024
|
-
}
|
|
1025
|
-
), /* @__PURE__ */ React.createElement(
|
|
1026
|
-
RepoUrlPickerRepoName,
|
|
1027
|
-
{
|
|
1028
|
-
repoName: state.repoName,
|
|
1029
|
-
allowedRepos,
|
|
1030
|
-
onChange: (repo) => setState((prevState) => ({ ...prevState, repoName: repo })),
|
|
1031
|
-
rawErrors
|
|
1032
|
-
}
|
|
1033
|
-
));
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
const OwnedEntityPickerFieldSchema = makeFieldSchemaFromZod(
|
|
1037
|
-
z.string(),
|
|
1038
|
-
z.object({
|
|
1039
|
-
allowedKinds: z.array(z.string()).optional().describe("List of kinds of entities to derive options from"),
|
|
1040
|
-
defaultKind: z.string().optional().describe(
|
|
1041
|
-
"The default entity kind. Options of this kind will not be prefixed."
|
|
1042
|
-
),
|
|
1043
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
1044
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
1045
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
1046
|
-
)
|
|
1047
|
-
})
|
|
1048
|
-
);
|
|
1049
|
-
const OwnedEntityPickerSchema = OwnedEntityPickerFieldSchema.schema;
|
|
1050
|
-
|
|
1051
|
-
const OwnedEntityPicker = (props) => {
|
|
1052
|
-
var _a, _b, _c, _d, _e;
|
|
1053
|
-
const {
|
|
1054
|
-
onChange,
|
|
1055
|
-
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
1056
|
-
required,
|
|
1057
|
-
uiSchema,
|
|
1058
|
-
rawErrors,
|
|
1059
|
-
formData,
|
|
1060
|
-
idSchema
|
|
1061
|
-
} = props;
|
|
1062
|
-
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
1063
|
-
const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
|
|
1064
|
-
const defaultNamespace = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.defaultNamespace;
|
|
1065
|
-
const allowArbitraryValues = (_e = (_d = uiSchema["ui:options"]) == null ? void 0 : _d.allowArbitraryValues) != null ? _e : true;
|
|
1066
|
-
const { ownedEntities, loading } = useOwnedEntities(allowedKinds);
|
|
1067
|
-
const entityRefs = ownedEntities == null ? void 0 : ownedEntities.items.map((e) => humanizeEntityRef(e, { defaultKind, defaultNamespace })).filter((n) => n);
|
|
1068
|
-
const onSelect = (_, value) => {
|
|
1069
|
-
onChange(value || "");
|
|
1070
|
-
};
|
|
1071
|
-
return /* @__PURE__ */ React.createElement(
|
|
1072
|
-
FormControl,
|
|
1073
|
-
{
|
|
1074
|
-
margin: "normal",
|
|
1075
|
-
required,
|
|
1076
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData
|
|
1077
|
-
},
|
|
1078
|
-
/* @__PURE__ */ React.createElement(
|
|
1079
|
-
Autocomplete,
|
|
1080
|
-
{
|
|
1081
|
-
id: idSchema == null ? void 0 : idSchema.$id,
|
|
1082
|
-
value: formData || "",
|
|
1083
|
-
loading,
|
|
1084
|
-
onChange: onSelect,
|
|
1085
|
-
options: entityRefs || [],
|
|
1086
|
-
autoSelect: true,
|
|
1087
|
-
freeSolo: allowArbitraryValues,
|
|
1088
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
1089
|
-
TextField,
|
|
1090
|
-
{
|
|
1091
|
-
...params,
|
|
1092
|
-
label: title,
|
|
1093
|
-
margin: "normal",
|
|
1094
|
-
helperText: description,
|
|
1095
|
-
variant: "outlined",
|
|
1096
|
-
required,
|
|
1097
|
-
InputProps: params.InputProps
|
|
1098
|
-
}
|
|
1099
|
-
)
|
|
1100
|
-
}
|
|
1101
|
-
)
|
|
1102
|
-
);
|
|
1103
|
-
};
|
|
1104
|
-
function useOwnedEntities(allowedKinds) {
|
|
1105
|
-
const identityApi = useApi(identityApiRef);
|
|
1106
|
-
const catalogApi = useApi(catalogApiRef);
|
|
1107
|
-
const { loading, value: refs } = useAsync(async () => {
|
|
1108
|
-
const identity = await identityApi.getBackstageIdentity();
|
|
1109
|
-
const identityRefs = identity.ownershipEntityRefs;
|
|
1110
|
-
const catalogs = await catalogApi.getEntities(
|
|
1111
|
-
allowedKinds ? {
|
|
1112
|
-
filter: {
|
|
1113
|
-
kind: allowedKinds,
|
|
1114
|
-
[`relations.${RELATION_OWNED_BY}`]: identityRefs || []
|
|
1115
|
-
}
|
|
1116
|
-
} : {
|
|
1117
|
-
filter: {
|
|
1118
|
-
[`relations.${RELATION_OWNED_BY}`]: identityRefs || []
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
);
|
|
1122
|
-
return catalogs;
|
|
1123
|
-
}, []);
|
|
1124
|
-
const ownedEntities = useMemo(() => {
|
|
1125
|
-
return refs;
|
|
1126
|
-
}, [refs]);
|
|
1127
|
-
return useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]);
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
const EntityTagsPickerFieldSchema = makeFieldSchemaFromZod(
|
|
1131
|
-
z.array(z.string()),
|
|
1132
|
-
z.object({
|
|
1133
|
-
kinds: z.array(z.string()).optional().describe("List of kinds of entities to derive tags from"),
|
|
1134
|
-
showCounts: z.boolean().optional().describe("Whether to show usage counts per tag"),
|
|
1135
|
-
helperText: z.string().optional().describe("Helper text to display")
|
|
1136
|
-
})
|
|
1137
|
-
);
|
|
1138
|
-
const EntityTagsPickerSchema = EntityTagsPickerFieldSchema.schema;
|
|
1139
|
-
|
|
1140
|
-
const EntityTagsPicker = (props) => {
|
|
1141
|
-
var _a, _b, _c;
|
|
1142
|
-
const { formData, onChange, uiSchema } = props;
|
|
1143
|
-
const catalogApi = useApi(catalogApiRef);
|
|
1144
|
-
const [tagOptions, setTagOptions] = useState([]);
|
|
1145
|
-
const [inputValue, setInputValue] = useState("");
|
|
1146
|
-
const [inputError, setInputError] = useState(false);
|
|
1147
|
-
const tagValidator = makeValidator().isValidTag;
|
|
1148
|
-
const kinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.kinds;
|
|
1149
|
-
const showCounts = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.showCounts;
|
|
1150
|
-
const helperText = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.helperText;
|
|
1151
|
-
const { loading, value: existingTags } = useAsync(async () => {
|
|
1152
|
-
const facet = "metadata.tags";
|
|
1153
|
-
const tagsRequest = { facets: [facet] };
|
|
1154
|
-
if (kinds) {
|
|
1155
|
-
tagsRequest.filter = { kind: kinds };
|
|
1156
|
-
}
|
|
1157
|
-
const { facets } = await catalogApi.getEntityFacets(tagsRequest);
|
|
1158
|
-
const tagFacets = Object.fromEntries(
|
|
1159
|
-
facets[facet].map(({ value, count }) => [value, count])
|
|
1160
|
-
);
|
|
1161
|
-
setTagOptions(
|
|
1162
|
-
Object.keys(tagFacets).sort(
|
|
1163
|
-
(a, b) => showCounts ? tagFacets[b] - tagFacets[a] : a.localeCompare(b)
|
|
1164
|
-
)
|
|
1165
|
-
);
|
|
1166
|
-
return tagFacets;
|
|
1167
|
-
});
|
|
1168
|
-
const setTags = (_, values) => {
|
|
1169
|
-
let hasError = false;
|
|
1170
|
-
let addDuplicate = false;
|
|
1171
|
-
const currentTags = formData || [];
|
|
1172
|
-
if ((values == null ? void 0 : values.length) && currentTags.length < values.length) {
|
|
1173
|
-
const newTag = values[values.length - 1] = values[values.length - 1].toLocaleLowerCase("en-US").trim();
|
|
1174
|
-
hasError = !tagValidator(newTag);
|
|
1175
|
-
addDuplicate = currentTags.indexOf(newTag) !== -1;
|
|
1176
|
-
}
|
|
1177
|
-
setInputError(hasError);
|
|
1178
|
-
setInputValue(!hasError ? "" : inputValue);
|
|
1179
|
-
if (!hasError && !addDuplicate) {
|
|
1180
|
-
onChange(values || []);
|
|
1181
|
-
}
|
|
1182
|
-
};
|
|
1183
|
-
useEffectOnce(() => onChange(formData || []));
|
|
1184
|
-
return /* @__PURE__ */ React.createElement(FormControl$1, { margin: "normal" }, /* @__PURE__ */ React.createElement(
|
|
1185
|
-
Autocomplete$1,
|
|
1186
|
-
{
|
|
1187
|
-
multiple: true,
|
|
1188
|
-
freeSolo: true,
|
|
1189
|
-
filterSelectedOptions: true,
|
|
1190
|
-
onChange: setTags,
|
|
1191
|
-
value: formData || [],
|
|
1192
|
-
inputValue,
|
|
1193
|
-
loading,
|
|
1194
|
-
options: tagOptions,
|
|
1195
|
-
ChipProps: { size: "small" },
|
|
1196
|
-
renderOption: (option) => showCounts ? `${option} (${existingTags == null ? void 0 : existingTags[option]})` : option,
|
|
1197
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
1198
|
-
TextField,
|
|
1199
|
-
{
|
|
1200
|
-
...params,
|
|
1201
|
-
label: "Tags",
|
|
1202
|
-
onChange: (e) => setInputValue(e.target.value),
|
|
1203
|
-
error: inputError,
|
|
1204
|
-
helperText: helperText != null ? helperText : "Add any relevant tags, hit 'Enter' to add new tags. Valid format: [a-z0-9+#] separated by [-], at most 63 characters"
|
|
1205
|
-
}
|
|
1206
|
-
)
|
|
1207
|
-
}
|
|
1208
|
-
));
|
|
1209
|
-
};
|
|
1210
|
-
|
|
1211
|
-
const registerComponentRouteRef = createExternalRouteRef({
|
|
1212
|
-
id: "register-component",
|
|
1213
|
-
optional: true
|
|
1214
|
-
});
|
|
1215
|
-
const viewTechDocRouteRef = createExternalRouteRef({
|
|
1216
|
-
id: "view-techdoc",
|
|
1217
|
-
optional: true,
|
|
1218
|
-
params: ["namespace", "kind", "name"]
|
|
1219
|
-
});
|
|
1220
|
-
const rootRouteRef$1 = createRouteRef({
|
|
1221
|
-
id: "scaffolder"
|
|
1222
|
-
});
|
|
1223
|
-
const legacySelectedTemplateRouteRef = createSubRouteRef({
|
|
1224
|
-
id: "scaffolder/legacy/selected-template",
|
|
1225
|
-
parent: rootRouteRef$1,
|
|
1226
|
-
path: "/templates/:templateName"
|
|
1227
|
-
});
|
|
1228
|
-
const selectedTemplateRouteRef = createSubRouteRef({
|
|
1229
|
-
id: "scaffolder/selected-template",
|
|
1230
|
-
parent: rootRouteRef$1,
|
|
1231
|
-
path: "/templates/:namespace/:templateName"
|
|
1232
|
-
});
|
|
1233
|
-
const scaffolderTaskRouteRef = createSubRouteRef({
|
|
1234
|
-
id: "scaffolder/task",
|
|
1235
|
-
parent: rootRouteRef$1,
|
|
1236
|
-
path: "/tasks/:taskId"
|
|
1237
|
-
});
|
|
1238
|
-
const scaffolderListTaskRouteRef = createSubRouteRef({
|
|
1239
|
-
id: "scaffolder/list-tasks",
|
|
1240
|
-
parent: rootRouteRef$1,
|
|
1241
|
-
path: "/tasks"
|
|
1242
|
-
});
|
|
1243
|
-
const actionsRouteRef = createSubRouteRef({
|
|
1244
|
-
id: "scaffolder/actions",
|
|
1245
|
-
parent: rootRouteRef$1,
|
|
1246
|
-
path: "/actions"
|
|
1247
|
-
});
|
|
1248
|
-
const editRouteRef = createSubRouteRef({
|
|
1249
|
-
id: "scaffolder/edit",
|
|
1250
|
-
parent: rootRouteRef$1,
|
|
1251
|
-
path: "/edit"
|
|
1252
|
-
});
|
|
1253
|
-
|
|
1254
|
-
const nextRouteRef = createRouteRef({
|
|
1255
|
-
id: "scaffolder/next"
|
|
1256
|
-
});
|
|
1257
|
-
const nextSelectedTemplateRouteRef = createSubRouteRef({
|
|
1258
|
-
id: "scaffolder/next/selected-template",
|
|
1259
|
-
parent: nextRouteRef,
|
|
1260
|
-
path: "/templates/:namespace/:templateName"
|
|
1261
|
-
});
|
|
1262
|
-
const nextScaffolderTaskRouteRef = createSubRouteRef({
|
|
1263
|
-
id: "scaffolder/next/task",
|
|
1264
|
-
parent: nextRouteRef,
|
|
1265
|
-
path: "/tasks/:taskId"
|
|
1266
|
-
});
|
|
1267
|
-
|
|
1268
|
-
const scaffolderPlugin = createPlugin({
|
|
1269
|
-
id: "scaffolder",
|
|
1270
|
-
apis: [
|
|
1271
|
-
createApiFactory({
|
|
1272
|
-
api: scaffolderApiRef$1,
|
|
1273
|
-
deps: {
|
|
1274
|
-
discoveryApi: discoveryApiRef,
|
|
1275
|
-
scmIntegrationsApi: scmIntegrationsApiRef,
|
|
1276
|
-
fetchApi: fetchApiRef,
|
|
1277
|
-
identityApi: identityApiRef
|
|
1278
|
-
},
|
|
1279
|
-
factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => new ScaffolderClient({
|
|
1280
|
-
discoveryApi,
|
|
1281
|
-
scmIntegrationsApi,
|
|
1282
|
-
fetchApi,
|
|
1283
|
-
identityApi
|
|
1284
|
-
})
|
|
1285
|
-
})
|
|
1286
|
-
],
|
|
1287
|
-
routes: {
|
|
1288
|
-
root: rootRouteRef$1,
|
|
1289
|
-
selectedTemplate: selectedTemplateRouteRef,
|
|
1290
|
-
ongoingTask: scaffolderTaskRouteRef
|
|
1291
|
-
},
|
|
1292
|
-
externalRoutes: {
|
|
1293
|
-
registerComponent: registerComponentRouteRef,
|
|
1294
|
-
viewTechDoc: viewTechDocRouteRef
|
|
1295
|
-
}
|
|
1296
|
-
});
|
|
1297
|
-
const EntityPickerFieldExtension = scaffolderPlugin.provide(
|
|
1298
|
-
createScaffolderFieldExtension$1({
|
|
1299
|
-
component: EntityPicker,
|
|
1300
|
-
name: "EntityPicker",
|
|
1301
|
-
schema: EntityPickerSchema
|
|
1302
|
-
})
|
|
1303
|
-
);
|
|
1304
|
-
const EntityNamePickerFieldExtension = scaffolderPlugin.provide(
|
|
1305
|
-
createScaffolderFieldExtension$1({
|
|
1306
|
-
component: EntityNamePicker,
|
|
1307
|
-
name: "EntityNamePicker",
|
|
1308
|
-
validation: entityNamePickerValidation,
|
|
1309
|
-
schema: EntityNamePickerSchema
|
|
1310
|
-
})
|
|
1311
|
-
);
|
|
1312
|
-
const RepoUrlPickerFieldExtension = scaffolderPlugin.provide(
|
|
1313
|
-
createScaffolderFieldExtension$1({
|
|
1314
|
-
component: RepoUrlPicker,
|
|
1315
|
-
name: "RepoUrlPicker",
|
|
1316
|
-
validation: repoPickerValidation,
|
|
1317
|
-
schema: RepoUrlPickerSchema
|
|
1318
|
-
})
|
|
1319
|
-
);
|
|
1320
|
-
const OwnerPickerFieldExtension = scaffolderPlugin.provide(
|
|
1321
|
-
createScaffolderFieldExtension$1({
|
|
1322
|
-
component: OwnerPicker,
|
|
1323
|
-
name: "OwnerPicker",
|
|
1324
|
-
schema: OwnerPickerSchema
|
|
1325
|
-
})
|
|
1326
|
-
);
|
|
1327
|
-
const ScaffolderPage = scaffolderPlugin.provide(
|
|
1328
|
-
createRoutableExtension({
|
|
1329
|
-
name: "ScaffolderPage",
|
|
1330
|
-
component: () => import('./Router-aedb6d68.esm.js').then((m) => m.Router),
|
|
1331
|
-
mountPoint: rootRouteRef$1
|
|
1332
|
-
})
|
|
1333
|
-
);
|
|
1334
|
-
const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(
|
|
1335
|
-
createScaffolderFieldExtension$1({
|
|
1336
|
-
component: OwnedEntityPicker,
|
|
1337
|
-
name: "OwnedEntityPicker",
|
|
1338
|
-
schema: OwnedEntityPickerSchema
|
|
1339
|
-
})
|
|
1340
|
-
);
|
|
1341
|
-
const EntityTagsPickerFieldExtension = scaffolderPlugin.provide(
|
|
1342
|
-
createScaffolderFieldExtension$1({
|
|
1343
|
-
component: EntityTagsPicker,
|
|
1344
|
-
name: "EntityTagsPicker",
|
|
1345
|
-
schema: EntityTagsPickerSchema
|
|
1346
|
-
})
|
|
1347
|
-
);
|
|
1348
|
-
const NextScaffolderPage = scaffolderPlugin.provide(
|
|
1349
|
-
createRoutableExtension({
|
|
1350
|
-
name: "NextScaffolderPage",
|
|
1351
|
-
component: () => import('./index-203b9f93.esm.js').then((m) => m.Router),
|
|
1352
|
-
mountPoint: nextRouteRef
|
|
1353
|
-
})
|
|
1354
|
-
);
|
|
1355
|
-
|
|
1356
|
-
const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
|
|
1357
|
-
const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
|
|
1358
|
-
const TemplateTypePicker = () => {
|
|
1359
|
-
const alertApi = useApi(alertApiRef);
|
|
1360
|
-
const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter();
|
|
1361
|
-
if (loading)
|
|
1362
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
1363
|
-
if (!availableTypes)
|
|
1364
|
-
return null;
|
|
1365
|
-
if (error) {
|
|
1366
|
-
alertApi.post({
|
|
1367
|
-
message: `Failed to load entity types`,
|
|
1368
|
-
severity: "error"
|
|
1369
|
-
});
|
|
1370
|
-
return null;
|
|
1371
|
-
}
|
|
1372
|
-
return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button" }, "Categories"), /* @__PURE__ */ React.createElement(
|
|
1373
|
-
Autocomplete$1,
|
|
1374
|
-
{
|
|
1375
|
-
multiple: true,
|
|
1376
|
-
"aria-label": "Categories",
|
|
1377
|
-
options: availableTypes,
|
|
1378
|
-
value: selectedTypes,
|
|
1379
|
-
onChange: (_, value) => setSelectedTypes(value),
|
|
1380
|
-
renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
|
|
1381
|
-
FormControlLabel,
|
|
1382
|
-
{
|
|
1383
|
-
control: /* @__PURE__ */ React.createElement(
|
|
1384
|
-
Checkbox,
|
|
1385
|
-
{
|
|
1386
|
-
icon,
|
|
1387
|
-
checkedIcon,
|
|
1388
|
-
checked: selected
|
|
1389
|
-
}
|
|
1390
|
-
),
|
|
1391
|
-
label: capitalize(option)
|
|
1392
|
-
}
|
|
1393
|
-
),
|
|
1394
|
-
size: "small",
|
|
1395
|
-
popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { "data-testid": "categories-picker-expand" }),
|
|
1396
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "outlined" })
|
|
1397
|
-
}
|
|
1398
|
-
));
|
|
1399
|
-
};
|
|
1400
|
-
|
|
1401
|
-
function reducer(draft, action) {
|
|
1402
|
-
var _a, _b, _c;
|
|
1403
|
-
switch (action.type) {
|
|
1404
|
-
case "INIT": {
|
|
1405
|
-
draft.steps = action.data.spec.steps.reduce((current, next) => {
|
|
1406
|
-
current[next.id] = { status: "open", id: next.id };
|
|
1407
|
-
return current;
|
|
1408
|
-
}, {});
|
|
1409
|
-
draft.stepLogs = action.data.spec.steps.reduce((current, next) => {
|
|
1410
|
-
current[next.id] = [];
|
|
1411
|
-
return current;
|
|
1412
|
-
}, {});
|
|
1413
|
-
draft.loading = false;
|
|
1414
|
-
draft.error = void 0;
|
|
1415
|
-
draft.completed = false;
|
|
1416
|
-
draft.task = action.data;
|
|
1417
|
-
return;
|
|
1418
|
-
}
|
|
1419
|
-
case "LOGS": {
|
|
1420
|
-
const entries = action.data;
|
|
1421
|
-
for (const entry of entries) {
|
|
1422
|
-
const logLine = `${entry.createdAt} ${entry.body.message}`;
|
|
1423
|
-
if (!entry.body.stepId || !((_a = draft.steps) == null ? void 0 : _a[entry.body.stepId])) {
|
|
1424
|
-
continue;
|
|
1425
|
-
}
|
|
1426
|
-
const currentStepLog = (_b = draft.stepLogs) == null ? void 0 : _b[entry.body.stepId];
|
|
1427
|
-
const currentStep = (_c = draft.steps) == null ? void 0 : _c[entry.body.stepId];
|
|
1428
|
-
if (entry.body.status && entry.body.status !== currentStep.status) {
|
|
1429
|
-
currentStep.status = entry.body.status;
|
|
1430
|
-
if (currentStep.status === "processing") {
|
|
1431
|
-
currentStep.startedAt = entry.createdAt;
|
|
1432
|
-
}
|
|
1433
|
-
if (["cancelled", "failed", "completed"].includes(currentStep.status)) {
|
|
1434
|
-
currentStep.endedAt = entry.createdAt;
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
currentStepLog == null ? void 0 : currentStepLog.push(logLine);
|
|
1438
|
-
}
|
|
1439
|
-
return;
|
|
1440
|
-
}
|
|
1441
|
-
case "COMPLETED": {
|
|
1442
|
-
draft.completed = true;
|
|
1443
|
-
draft.output = action.data.body.output;
|
|
1444
|
-
draft.error = action.data.body.error;
|
|
1445
|
-
return;
|
|
1446
|
-
}
|
|
1447
|
-
case "ERROR": {
|
|
1448
|
-
draft.error = action.data;
|
|
1449
|
-
draft.loading = false;
|
|
1450
|
-
draft.completed = true;
|
|
1451
|
-
return;
|
|
1452
|
-
}
|
|
1453
|
-
default:
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
const useTaskEventStream = (taskId) => {
|
|
1458
|
-
const scaffolderApi = useApi(scaffolderApiRef$1);
|
|
1459
|
-
const [state, dispatch] = useImmerReducer(reducer, {
|
|
1460
|
-
loading: true,
|
|
1461
|
-
completed: false,
|
|
1462
|
-
stepLogs: {},
|
|
1463
|
-
steps: {}
|
|
1464
|
-
});
|
|
1465
|
-
useEffect(() => {
|
|
1466
|
-
let didCancel = false;
|
|
1467
|
-
let subscription;
|
|
1468
|
-
let logPusher;
|
|
1469
|
-
scaffolderApi.getTask(taskId).then(
|
|
1470
|
-
(task) => {
|
|
1471
|
-
if (didCancel) {
|
|
1472
|
-
return;
|
|
1473
|
-
}
|
|
1474
|
-
dispatch({ type: "INIT", data: task });
|
|
1475
|
-
const observable = scaffolderApi.streamLogs({ taskId });
|
|
1476
|
-
const collectedLogEvents = new Array();
|
|
1477
|
-
function emitLogs() {
|
|
1478
|
-
if (collectedLogEvents.length) {
|
|
1479
|
-
const logs = collectedLogEvents.splice(
|
|
1480
|
-
0,
|
|
1481
|
-
collectedLogEvents.length
|
|
1482
|
-
);
|
|
1483
|
-
dispatch({ type: "LOGS", data: logs });
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
logPusher = setInterval(emitLogs, 500);
|
|
1487
|
-
subscription = observable.subscribe({
|
|
1488
|
-
next: (event) => {
|
|
1489
|
-
switch (event.type) {
|
|
1490
|
-
case "log":
|
|
1491
|
-
return collectedLogEvents.push(event);
|
|
1492
|
-
case "completion":
|
|
1493
|
-
emitLogs();
|
|
1494
|
-
dispatch({ type: "COMPLETED", data: event });
|
|
1495
|
-
return void 0;
|
|
1496
|
-
default:
|
|
1497
|
-
throw new Error(
|
|
1498
|
-
`Unhandled event type ${event.type} in observer`
|
|
1499
|
-
);
|
|
1500
|
-
}
|
|
1501
|
-
},
|
|
1502
|
-
error: (error) => {
|
|
1503
|
-
emitLogs();
|
|
1504
|
-
dispatch({ type: "ERROR", data: error });
|
|
1505
|
-
}
|
|
1506
|
-
});
|
|
1507
|
-
},
|
|
1508
|
-
(error) => {
|
|
1509
|
-
if (!didCancel) {
|
|
1510
|
-
dispatch({ type: "ERROR", data: error });
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
);
|
|
1514
|
-
return () => {
|
|
1515
|
-
didCancel = true;
|
|
1516
|
-
if (subscription) {
|
|
1517
|
-
subscription.unsubscribe();
|
|
1518
|
-
}
|
|
1519
|
-
if (logPusher) {
|
|
1520
|
-
clearInterval(logPusher);
|
|
1521
|
-
}
|
|
1522
|
-
};
|
|
1523
|
-
}, [scaffolderApi, dispatch, taskId]);
|
|
1524
|
-
return state;
|
|
1525
|
-
};
|
|
1526
|
-
|
|
1527
|
-
const TaskErrors = ({ error }) => {
|
|
1528
|
-
const id = useRef("");
|
|
1529
|
-
useEffect(() => {
|
|
1530
|
-
id.current = String(Math.random());
|
|
1531
|
-
}, [error]);
|
|
1532
|
-
return error ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
|
|
1533
|
-
DismissableBanner,
|
|
1534
|
-
{
|
|
1535
|
-
id: id.current,
|
|
1536
|
-
variant: "warning",
|
|
1537
|
-
message: error.message
|
|
1538
|
-
}
|
|
1539
|
-
)) : null;
|
|
1540
|
-
};
|
|
1541
|
-
|
|
1542
|
-
const useStyles$1 = makeStyles({
|
|
1543
|
-
svgIcon: {
|
|
1544
|
-
display: "inline-block",
|
|
1545
|
-
"& svg": {
|
|
1546
|
-
display: "inline-block",
|
|
1547
|
-
fontSize: "inherit",
|
|
1548
|
-
verticalAlign: "baseline"
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
});
|
|
1552
|
-
const IconLink = (props) => {
|
|
1553
|
-
const { href, text, Icon, ...linkProps } = props;
|
|
1554
|
-
const classes = useStyles$1();
|
|
1555
|
-
return /* @__PURE__ */ React.createElement(Grid, { container: true, direction: "row", spacing: 1 }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Typography, { component: "div", className: classes.svgIcon }, Icon ? /* @__PURE__ */ React.createElement(Icon, null) : /* @__PURE__ */ React.createElement(LanguageIcon, null))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Link, { to: href, ...linkProps }, text || href)));
|
|
1556
|
-
};
|
|
1557
|
-
|
|
1558
|
-
const TaskPageLinks = ({ output }) => {
|
|
1559
|
-
const { links = [] } = output;
|
|
1560
|
-
const app = useApp();
|
|
1561
|
-
const entityRoute = useRouteRef(entityRouteRef);
|
|
1562
|
-
const iconResolver = (key) => {
|
|
1563
|
-
var _a;
|
|
1564
|
-
return key ? (_a = app.getSystemIcon(key)) != null ? _a : LanguageIcon : LanguageIcon;
|
|
1565
|
-
};
|
|
1566
|
-
return /* @__PURE__ */ React.createElement(Box, { px: 3, pb: 3 }, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
|
|
1567
|
-
if (entityRef) {
|
|
1568
|
-
const entityName = parseEntityRef(entityRef, {
|
|
1569
|
-
defaultKind: "<unknown>",
|
|
1570
|
-
defaultNamespace: "<unknown>"
|
|
1571
|
-
});
|
|
1572
|
-
const target = entityRoute(entityName);
|
|
1573
|
-
return { title, icon, url: target };
|
|
1574
|
-
}
|
|
1575
|
-
return { title, icon, url };
|
|
1576
|
-
}).map(({ url, title, icon }, i) => /* @__PURE__ */ React.createElement(
|
|
1577
|
-
IconLink,
|
|
1578
|
-
{
|
|
1579
|
-
key: `output-link-${i}`,
|
|
1580
|
-
href: url,
|
|
1581
|
-
text: title != null ? title : url,
|
|
1582
|
-
Icon: iconResolver(icon),
|
|
1583
|
-
target: "_blank"
|
|
1584
|
-
}
|
|
1585
|
-
)));
|
|
1586
|
-
};
|
|
1587
|
-
|
|
1588
|
-
const humanizeDuration = require("humanize-duration");
|
|
1589
|
-
const useStyles = makeStyles$1(
|
|
1590
|
-
(theme) => createStyles({
|
|
1591
|
-
root: {
|
|
1592
|
-
width: "100%"
|
|
1593
|
-
},
|
|
1594
|
-
button: {
|
|
1595
|
-
marginBottom: theme.spacing(2),
|
|
1596
|
-
marginLeft: theme.spacing(2)
|
|
1597
|
-
},
|
|
1598
|
-
actionsContainer: {
|
|
1599
|
-
marginBottom: theme.spacing(2)
|
|
1600
|
-
},
|
|
1601
|
-
resetContainer: {
|
|
1602
|
-
padding: theme.spacing(3)
|
|
1603
|
-
},
|
|
1604
|
-
labelWrapper: {
|
|
1605
|
-
display: "flex",
|
|
1606
|
-
flex: 1,
|
|
1607
|
-
flexDirection: "row",
|
|
1608
|
-
justifyContent: "space-between"
|
|
1609
|
-
},
|
|
1610
|
-
stepWrapper: {
|
|
1611
|
-
width: "100%"
|
|
1612
|
-
}
|
|
1613
|
-
})
|
|
1614
|
-
);
|
|
1615
|
-
const StepTimeTicker = ({ step }) => {
|
|
1616
|
-
const [time, setTime] = useState("");
|
|
1617
|
-
useInterval(() => {
|
|
1618
|
-
if (!step.startedAt) {
|
|
1619
|
-
setTime("");
|
|
1620
|
-
return;
|
|
1621
|
-
}
|
|
1622
|
-
const end = step.endedAt ? DateTime.fromISO(step.endedAt) : DateTime.local();
|
|
1623
|
-
const startedAt = DateTime.fromISO(step.startedAt);
|
|
1624
|
-
const formatted = Interval.fromDateTimes(startedAt, end).toDuration().valueOf();
|
|
1625
|
-
setTime(humanizeDuration(formatted, { round: true }));
|
|
1626
|
-
}, 1e3);
|
|
1627
|
-
return /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, time);
|
|
1628
|
-
};
|
|
1629
|
-
const useStepIconStyles = makeStyles$1(
|
|
1630
|
-
(theme) => createStyles({
|
|
1631
|
-
root: {
|
|
1632
|
-
color: theme.palette.text.disabled,
|
|
1633
|
-
display: "flex",
|
|
1634
|
-
height: 22,
|
|
1635
|
-
alignItems: "center"
|
|
1636
|
-
},
|
|
1637
|
-
completed: {
|
|
1638
|
-
color: theme.palette.status.ok
|
|
1639
|
-
},
|
|
1640
|
-
error: {
|
|
1641
|
-
color: theme.palette.status.error
|
|
1642
|
-
}
|
|
1643
|
-
})
|
|
1644
|
-
);
|
|
1645
|
-
function TaskStepIconComponent(props) {
|
|
1646
|
-
const classes = useStepIconStyles();
|
|
1647
|
-
const { active, completed, error } = props;
|
|
1648
|
-
const getMiddle = () => {
|
|
1649
|
-
if (active) {
|
|
1650
|
-
return /* @__PURE__ */ React.createElement(CircularProgress, { size: "24px" });
|
|
1651
|
-
}
|
|
1652
|
-
if (completed) {
|
|
1653
|
-
return /* @__PURE__ */ React.createElement(Check, null);
|
|
1654
|
-
}
|
|
1655
|
-
if (error) {
|
|
1656
|
-
return /* @__PURE__ */ React.createElement(Cancel, null);
|
|
1657
|
-
}
|
|
1658
|
-
return /* @__PURE__ */ React.createElement(FiberManualRecordIcon, null);
|
|
1659
|
-
};
|
|
1660
|
-
return /* @__PURE__ */ React.createElement(
|
|
1661
|
-
"div",
|
|
1662
|
-
{
|
|
1663
|
-
className: classNames(classes.root, {
|
|
1664
|
-
[classes.completed]: completed,
|
|
1665
|
-
[classes.error]: error
|
|
1666
|
-
})
|
|
1667
|
-
},
|
|
1668
|
-
getMiddle()
|
|
1669
|
-
);
|
|
1670
|
-
}
|
|
1671
|
-
const TaskStatusStepper = memo(
|
|
1672
|
-
(props) => {
|
|
1673
|
-
const { steps, currentStepId, onUserStepChange } = props;
|
|
1674
|
-
const classes = useStyles(props);
|
|
1675
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(
|
|
1676
|
-
Stepper,
|
|
1677
|
-
{
|
|
1678
|
-
activeStep: steps.findIndex((s) => s.id === currentStepId),
|
|
1679
|
-
orientation: "vertical",
|
|
1680
|
-
nonLinear: true
|
|
1681
|
-
},
|
|
1682
|
-
steps.map((step, index) => {
|
|
1683
|
-
const isCompleted = step.status === "completed";
|
|
1684
|
-
const isFailed = step.status === "failed";
|
|
1685
|
-
const isActive = step.status === "processing";
|
|
1686
|
-
const isSkipped = step.status === "skipped";
|
|
1687
|
-
return /* @__PURE__ */ React.createElement(Step, { key: String(index), expanded: true }, /* @__PURE__ */ React.createElement(StepButton, { onClick: () => onUserStepChange(step.id) }, /* @__PURE__ */ React.createElement(
|
|
1688
|
-
StepLabel,
|
|
1689
|
-
{
|
|
1690
|
-
StepIconProps: {
|
|
1691
|
-
completed: isCompleted,
|
|
1692
|
-
error: isFailed,
|
|
1693
|
-
active: isActive
|
|
1694
|
-
},
|
|
1695
|
-
StepIconComponent: TaskStepIconComponent,
|
|
1696
|
-
className: classes.stepWrapper
|
|
1697
|
-
},
|
|
1698
|
-
/* @__PURE__ */ React.createElement("div", { className: classes.labelWrapper }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "subtitle2" }, step.name), isSkipped ? /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, "Skipped") : /* @__PURE__ */ React.createElement(StepTimeTicker, { step }))
|
|
1699
|
-
)));
|
|
1700
|
-
})
|
|
1701
|
-
));
|
|
1702
|
-
}
|
|
1703
|
-
);
|
|
1704
|
-
const hasLinks = ({ links = [] }) => links.length > 0;
|
|
1705
|
-
const TaskPage = ({ loadingText }) => {
|
|
1706
|
-
const classes = useStyles();
|
|
1707
|
-
const navigate = useNavigate();
|
|
1708
|
-
const rootPath = useRouteRef(rootRouteRef$1);
|
|
1709
|
-
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
1710
|
-
const [userSelectedStepId, setUserSelectedStepId] = useState(void 0);
|
|
1711
|
-
const [lastActiveStepId, setLastActiveStepId] = useState(
|
|
1712
|
-
void 0
|
|
1713
|
-
);
|
|
1714
|
-
const { taskId } = useRouteRefParams(scaffolderTaskRouteRef);
|
|
1715
|
-
const taskStream = useTaskEventStream(taskId);
|
|
1716
|
-
const completed = taskStream.completed;
|
|
1717
|
-
const steps = useMemo(
|
|
1718
|
-
() => {
|
|
1719
|
-
var _a, _b;
|
|
1720
|
-
return (_b = (_a = taskStream.task) == null ? void 0 : _a.spec.steps.map((step) => {
|
|
1721
|
-
var _a2;
|
|
1722
|
-
return {
|
|
1723
|
-
...step,
|
|
1724
|
-
...(_a2 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a2[step.id]
|
|
1725
|
-
};
|
|
1726
|
-
})) != null ? _b : [];
|
|
1727
|
-
},
|
|
1728
|
-
[taskStream]
|
|
1729
|
-
);
|
|
1730
|
-
useEffect(() => {
|
|
1731
|
-
var _a;
|
|
1732
|
-
const mostRecentFailedOrActiveStep = steps.find(
|
|
1733
|
-
(step) => ["failed", "processing"].includes(step.status)
|
|
1734
|
-
);
|
|
1735
|
-
if (completed && !mostRecentFailedOrActiveStep) {
|
|
1736
|
-
setLastActiveStepId((_a = steps[steps.length - 1]) == null ? void 0 : _a.id);
|
|
1737
|
-
return;
|
|
1738
|
-
}
|
|
1739
|
-
setLastActiveStepId(mostRecentFailedOrActiveStep == null ? void 0 : mostRecentFailedOrActiveStep.id);
|
|
1740
|
-
}, [steps, completed]);
|
|
1741
|
-
const currentStepId = userSelectedStepId != null ? userSelectedStepId : lastActiveStepId;
|
|
1742
|
-
const logAsString = useMemo(() => {
|
|
1743
|
-
if (!currentStepId) {
|
|
1744
|
-
return loadingText ? loadingText : "Loading...";
|
|
1745
|
-
}
|
|
1746
|
-
const log = taskStream.stepLogs[currentStepId];
|
|
1747
|
-
if (!(log == null ? void 0 : log.length)) {
|
|
1748
|
-
return "Waiting for logs...";
|
|
1749
|
-
}
|
|
1750
|
-
return log.join("\n");
|
|
1751
|
-
}, [taskStream.stepLogs, currentStepId, loadingText]);
|
|
1752
|
-
const taskNotFound = taskStream.completed === true && taskStream.loading === false && !taskStream.task;
|
|
1753
|
-
const { output } = taskStream;
|
|
1754
|
-
const handleStartOver = () => {
|
|
1755
|
-
var _a, _b, _c;
|
|
1756
|
-
if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.templateInfo) == null ? void 0 : _b.entityRef)) {
|
|
1757
|
-
navigate(rootPath());
|
|
1758
|
-
return;
|
|
1759
|
-
}
|
|
1760
|
-
const formData = taskStream.task.spec.parameters;
|
|
1761
|
-
const { name, namespace } = parseEntityRef(
|
|
1762
|
-
(_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef
|
|
1763
|
-
);
|
|
1764
|
-
navigate(
|
|
1765
|
-
`${templateRoute({ templateName: name, namespace })}?${qs.stringify({
|
|
1766
|
-
formData: JSON.stringify(formData)
|
|
1767
|
-
})}`
|
|
1768
|
-
);
|
|
1769
|
-
};
|
|
1770
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
1771
|
-
Header,
|
|
1772
|
-
{
|
|
1773
|
-
pageTitleOverride: `Task ${taskId}`,
|
|
1774
|
-
title: "Task Activity",
|
|
1775
|
-
subtitle: `Activity for task: ${taskId}`
|
|
1776
|
-
}
|
|
1777
|
-
), /* @__PURE__ */ React.createElement(Content, null, taskNotFound ? /* @__PURE__ */ React.createElement(
|
|
1778
|
-
ErrorPage,
|
|
1779
|
-
{
|
|
1780
|
-
status: "404",
|
|
1781
|
-
statusMessage: "Task not found",
|
|
1782
|
-
additionalInfo: "No task found with this ID"
|
|
1783
|
-
}
|
|
1784
|
-
) : /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Grid$1, { container: true }, /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 3 }, /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(
|
|
1785
|
-
TaskStatusStepper,
|
|
1786
|
-
{
|
|
1787
|
-
steps,
|
|
1788
|
-
currentStepId,
|
|
1789
|
-
onUserStepChange: setUserSelectedStepId
|
|
1790
|
-
}
|
|
1791
|
-
), output && hasLinks(output) && /* @__PURE__ */ React.createElement(TaskPageLinks, { output }), /* @__PURE__ */ React.createElement(
|
|
1792
|
-
Button,
|
|
1793
|
-
{
|
|
1794
|
-
className: classes.button,
|
|
1795
|
-
onClick: handleStartOver,
|
|
1796
|
-
disabled: !completed,
|
|
1797
|
-
variant: "contained",
|
|
1798
|
-
color: "primary"
|
|
1799
|
-
},
|
|
1800
|
-
"Start Over"
|
|
1801
|
-
))), /* @__PURE__ */ React.createElement(Grid$1, { item: true, xs: 9 }, !currentStepId && /* @__PURE__ */ React.createElement(Progress, null), /* @__PURE__ */ React.createElement("div", { style: { height: "80vh" } }, /* @__PURE__ */ React.createElement(TaskErrors, { error: taskStream.error }), /* @__PURE__ */ React.createElement(LogViewer, { text: logAsString })))))));
|
|
1802
|
-
};
|
|
1803
|
-
|
|
1804
|
-
const rootRouteRef = rootRouteRef$1;
|
|
1805
|
-
const createScaffolderFieldExtension = createScaffolderFieldExtension$1;
|
|
1806
|
-
const ScaffolderFieldExtensions = ScaffolderFieldExtensions$1;
|
|
1807
|
-
const useTemplateSecrets = useTemplateSecrets$1;
|
|
1808
|
-
const scaffolderApiRef = scaffolderApiRef$1;
|
|
1809
|
-
const createScaffolderLayout = createScaffolderLayout$1;
|
|
1810
|
-
const ScaffolderLayouts = ScaffolderLayouts$1;
|
|
1811
|
-
|
|
1812
|
-
export { EntityNamePickerFieldExtension as A, EntityTagsPickerFieldExtension as B, OwnerPickerFieldExtension as C, OwnedEntityPickerFieldExtension as D, EntityPicker as E, RepoUrlPickerFieldExtension as F, ScaffolderPage as G, scaffolderPlugin as H, nextScaffolderTaskRouteRef as I, makeFieldSchemaFromZod as J, EntityPickerFieldSchema as K, OwnerPickerFieldSchema as L, RepoUrlPickerFieldSchema as M, NextScaffolderPage as N, OwnerPicker as O, OwnedEntityPickerFieldSchema as P, EntityTagsPickerFieldSchema as Q, RepoUrlPicker as R, ScaffolderClient as S, TemplateTypePicker as T, rootRouteRef as U, createScaffolderFieldExtension as V, ScaffolderFieldExtensions as W, useTemplateSecrets as X, scaffolderApiRef as Y, createScaffolderLayout as Z, ScaffolderLayouts as _, actionsRouteRef as a, scaffolderListTaskRouteRef as b, scaffolderTaskRouteRef as c, rootRouteRef$1 as d, editRouteRef as e, TaskStatusStepper as f, TaskPageLinks as g, TaskPage as h, EntityPickerSchema as i, EntityNamePicker as j, entityNamePickerValidation as k, legacySelectedTemplateRouteRef as l, EntityNamePickerSchema as m, EntityTagsPicker as n, EntityTagsPickerSchema as o, repoPickerValidation as p, RepoUrlPickerSchema as q, registerComponentRouteRef as r, selectedTemplateRouteRef as s, OwnerPickerSchema as t, OwnedEntityPicker as u, viewTechDocRouteRef as v, OwnedEntityPickerSchema as w, nextSelectedTemplateRouteRef as x, nextRouteRef as y, EntityPickerFieldExtension as z };
|
|
1813
|
-
//# sourceMappingURL=index-e0e59ed8.esm.js.map
|