@backstage/plugin-scaffolder 1.13.0-next.0 → 1.13.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/alpha/package.json +1 -1
- package/dist/alpha.d.ts +12 -70
- package/dist/alpha.esm.js +21 -18
- package/dist/alpha.esm.js.map +1 -1
- package/dist/esm/{alpha/ListTasksPage-a9fab591.esm.js → ListTasksPage-caaca86d.esm.js} +3 -2
- package/dist/esm/ListTasksPage-caaca86d.esm.js.map +1 -0
- package/dist/esm/{index/Router-f32000f9.esm.js → Router-f509f2e0.esm.js} +19 -16
- package/dist/esm/Router-f509f2e0.esm.js.map +1 -0
- package/dist/esm/{index/index-8321766a.esm.js → TaskPage-f304e0fc.esm.js} +31 -88
- package/dist/esm/TaskPage-f304e0fc.esm.js.map +1 -0
- package/dist/esm/{index/ListTasksPage-64779a2d.esm.js → TemplateEditorIntro-f7f6d664.esm.js} +396 -530
- package/dist/esm/TemplateEditorIntro-f7f6d664.esm.js.map +1 -0
- package/dist/esm/{index/index-e3edaa49.esm.js → TemplateFormPreviewer-299c316c.esm.js} +18 -379
- package/dist/esm/TemplateFormPreviewer-299c316c.esm.js.map +1 -0
- package/dist/esm/TemplateTypePicker-4f07b216.esm.js +58 -0
- package/dist/esm/TemplateTypePicker-4f07b216.esm.js.map +1 -0
- package/dist/esm/{alpha/index-d45f106a.esm.js → index-64f5b7a5.esm.js} +26 -23
- package/dist/esm/index-64f5b7a5.esm.js.map +1 -0
- package/dist/index.d.ts +46 -205
- package/dist/index.esm.js +19 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/types/plugin.d-7a7914d1.d.ts +232 -0
- package/package.json +24 -22
- package/dist/esm/alpha/ListTasksPage-a9fab591.esm.js.map +0 -1
- package/dist/esm/alpha/Router-ea3122d2.esm.js +0 -1581
- package/dist/esm/alpha/Router-ea3122d2.esm.js.map +0 -1
- package/dist/esm/alpha/alpha-0764fae7.esm.js +0 -3410
- package/dist/esm/alpha/alpha-0764fae7.esm.js.map +0 -1
- package/dist/esm/alpha/index-d45f106a.esm.js.map +0 -1
- package/dist/esm/index/ListTasksPage-64779a2d.esm.js.map +0 -1
- package/dist/esm/index/Router-f32000f9.esm.js.map +0 -1
- package/dist/esm/index/index-8321766a.esm.js.map +0 -1
- package/dist/esm/index/index-e3edaa49.esm.js.map +0 -1
|
@@ -1,3410 +0,0 @@
|
|
|
1
|
-
import { scmIntegrationsApiRef, scmAuthApiRef } from '@backstage/integration-react';
|
|
2
|
-
import { scaffolderApiRef, useTemplateSecrets, createScaffolderFieldExtension, useTaskEventStream } from '@backstage/plugin-scaffolder-react';
|
|
3
|
-
import { parseEntityRef, stringifyEntityRef, KubernetesValidatorFunctions, RELATION_OWNED_BY, makeValidator } from '@backstage/catalog-model';
|
|
4
|
-
import { ResponseError } from '@backstage/errors';
|
|
5
|
-
import qs from 'qs';
|
|
6
|
-
import ObservableImpl from 'zen-observable';
|
|
7
|
-
import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client';
|
|
8
|
-
import { useApi, identityApiRef, createExternalRouteRef, createRouteRef, createSubRouteRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, useRouteRef, useApiHolder, useApp, useRouteRefParams, alertApiRef } from '@backstage/core-plugin-api';
|
|
9
|
-
import { catalogApiRef, humanizeEntityRef, entityRouteRef } from '@backstage/plugin-catalog-react';
|
|
10
|
-
import { TextField, FormControl as FormControl$1, makeStyles, IconButton, Popover, MenuList, MenuItem, ListItemIcon, ListItemText, Box, Paper, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Chip, Card, List, InputLabel as InputLabel$1, Select as Select$1, CardHeader, CardContent, Button, StepButton, CircularProgress, Tooltip, Divider as Divider$1, LinearProgress } from '@material-ui/core';
|
|
11
|
-
import FormControl from '@material-ui/core/FormControl';
|
|
12
|
-
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
13
|
-
import React, { useCallback, useEffect, useState, useMemo, Fragment, createContext, useRef, useContext, Component, memo, Children } from 'react';
|
|
14
|
-
import useAsync from 'react-use/lib/useAsync';
|
|
15
|
-
import { z } from 'zod';
|
|
16
|
-
import zodToJsonSchema from 'zod-to-json-schema';
|
|
17
|
-
import FormHelperText from '@material-ui/core/FormHelperText';
|
|
18
|
-
import Input from '@material-ui/core/Input';
|
|
19
|
-
import InputLabel from '@material-ui/core/InputLabel';
|
|
20
|
-
import { Select, Progress, Page, Header, Content, ErrorPanel, ErrorPage, MarkdownContent, CodeSnippet, DismissableBanner, Link, LogViewer } from '@backstage/core-components';
|
|
21
|
-
import useDebounce from 'react-use/lib/useDebounce';
|
|
22
|
-
import useEffectOnce from 'react-use/lib/useEffectOnce';
|
|
23
|
-
import { Autocomplete as Autocomplete$1 } from '@material-ui/lab';
|
|
24
|
-
import { useParams, useNavigate } from 'react-router-dom';
|
|
25
|
-
import { DefaultTemplateOutputs, TaskSteps, TaskLogStream, Stepper, Form } from '@backstage/plugin-scaffolder-react/alpha';
|
|
26
|
-
import '@material-ui/core/Button';
|
|
27
|
-
import IconButton$1 from '@material-ui/core/IconButton';
|
|
28
|
-
import '@material-ui/core/useMediaQuery';
|
|
29
|
-
import '@material-ui/icons/AddCircleOutline';
|
|
30
|
-
import '@backstage/plugin-catalog-common/alpha';
|
|
31
|
-
import '@backstage/plugin-permission-react';
|
|
32
|
-
import { useAsync as useAsync$1, useRerender, usePrevious, useKeyboardEvent } from '@react-hookz/web';
|
|
33
|
-
import Cancel from '@material-ui/icons/Cancel';
|
|
34
|
-
import Retry from '@material-ui/icons/Repeat';
|
|
35
|
-
import Toc from '@material-ui/icons/Toc';
|
|
36
|
-
import MoreVert from '@material-ui/icons/MoreVert';
|
|
37
|
-
import classNames from 'classnames';
|
|
38
|
-
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
39
|
-
import SettingsIcon from '@material-ui/icons/Settings';
|
|
40
|
-
import AllIcon from '@material-ui/icons/FontDownload';
|
|
41
|
-
import { DateTime, Interval } from 'luxon';
|
|
42
|
-
import 'humanize-duration';
|
|
43
|
-
import Typography$1 from '@material-ui/core/Typography';
|
|
44
|
-
import { StreamLanguage } from '@codemirror/language';
|
|
45
|
-
import { yaml as yaml$1 } from '@codemirror/legacy-modes/mode/yaml';
|
|
46
|
-
import CloseIcon from '@material-ui/icons/Close';
|
|
47
|
-
import CodeMirror from '@uiw/react-codemirror';
|
|
48
|
-
import yaml from 'yaml';
|
|
49
|
-
import { makeStyles as makeStyles$1, createStyles } from '@material-ui/core/styles';
|
|
50
|
-
import validator from '@rjsf/validator-ajv8';
|
|
51
|
-
import Accordion$1 from '@material-ui/core/Accordion';
|
|
52
|
-
import AccordionDetails$1 from '@material-ui/core/AccordionDetails';
|
|
53
|
-
import AccordionSummary$1 from '@material-ui/core/AccordionSummary';
|
|
54
|
-
import Divider from '@material-ui/core/Divider';
|
|
55
|
-
import ExpandMoreIcon$1 from '@material-ui/icons/ExpandLess';
|
|
56
|
-
import List$1 from '@material-ui/core/List';
|
|
57
|
-
import ListItem from '@material-ui/core/ListItem';
|
|
58
|
-
import ListItemIcon$1 from '@material-ui/core/ListItemIcon';
|
|
59
|
-
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
|
60
|
-
import ListItemText$1 from '@material-ui/core/ListItemText';
|
|
61
|
-
import CheckIcon from '@material-ui/icons/Check';
|
|
62
|
-
import DeleteIcon from '@material-ui/icons/Delete';
|
|
63
|
-
import Box$1 from '@material-ui/core/Box';
|
|
64
|
-
import Tab from '@material-ui/core/Tab';
|
|
65
|
-
import Tabs from '@material-ui/core/Tabs';
|
|
66
|
-
import Grid$1 from '@material-ui/core/Grid';
|
|
67
|
-
import Step from '@material-ui/core/Step';
|
|
68
|
-
import StepLabel from '@material-ui/core/StepLabel';
|
|
69
|
-
import Stepper$1 from '@material-ui/core/Stepper';
|
|
70
|
-
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
|
71
|
-
import useInterval from 'react-use/lib/useInterval';
|
|
72
|
-
import LanguageIcon from '@material-ui/icons/Language';
|
|
73
|
-
import TreeView from '@material-ui/lab/TreeView';
|
|
74
|
-
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
|
|
75
|
-
import TreeItem from '@material-ui/lab/TreeItem';
|
|
76
|
-
import RefreshIcon from '@material-ui/icons/Refresh';
|
|
77
|
-
import SaveIcon from '@material-ui/icons/Save';
|
|
78
|
-
import { showPanel } from '@codemirror/view';
|
|
79
|
-
import Card$1 from '@material-ui/core/Card';
|
|
80
|
-
import CardActionArea from '@material-ui/core/CardActionArea';
|
|
81
|
-
import CardContent$1 from '@material-ui/core/CardContent';
|
|
82
|
-
import Tooltip$1 from '@material-ui/core/Tooltip';
|
|
83
|
-
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
|
|
84
|
-
|
|
85
|
-
class ScaffolderClient {
|
|
86
|
-
constructor(options) {
|
|
87
|
-
var _a, _b;
|
|
88
|
-
this.discoveryApi = options.discoveryApi;
|
|
89
|
-
this.fetchApi = (_a = options.fetchApi) != null ? _a : { fetch };
|
|
90
|
-
this.scmIntegrationsApi = options.scmIntegrationsApi;
|
|
91
|
-
this.useLongPollingLogs = (_b = options.useLongPollingLogs) != null ? _b : false;
|
|
92
|
-
this.identityApi = options.identityApi;
|
|
93
|
-
}
|
|
94
|
-
async listTasks(options) {
|
|
95
|
-
if (!this.identityApi) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method"
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
101
|
-
const { userEntityRef } = await this.identityApi.getBackstageIdentity();
|
|
102
|
-
const query = qs.stringify(
|
|
103
|
-
options.filterByOwnership === "owned" ? { createdBy: userEntityRef } : {}
|
|
104
|
-
);
|
|
105
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/tasks?${query}`);
|
|
106
|
-
if (!response.ok) {
|
|
107
|
-
throw await ResponseError.fromResponse(response);
|
|
108
|
-
}
|
|
109
|
-
return await response.json();
|
|
110
|
-
}
|
|
111
|
-
async getIntegrationsList(options) {
|
|
112
|
-
const integrations = [
|
|
113
|
-
...this.scmIntegrationsApi.azure.list(),
|
|
114
|
-
...this.scmIntegrationsApi.bitbucket.list().filter(
|
|
115
|
-
(item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)
|
|
116
|
-
),
|
|
117
|
-
...this.scmIntegrationsApi.bitbucketCloud.list(),
|
|
118
|
-
...this.scmIntegrationsApi.bitbucketServer.list(),
|
|
119
|
-
...this.scmIntegrationsApi.gerrit.list(),
|
|
120
|
-
...this.scmIntegrationsApi.github.list(),
|
|
121
|
-
...this.scmIntegrationsApi.gitlab.list()
|
|
122
|
-
].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
|
|
123
|
-
return {
|
|
124
|
-
integrations
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
async getTemplateParameterSchema(templateRef) {
|
|
128
|
-
const { namespace, kind, name } = parseEntityRef(templateRef, {
|
|
129
|
-
defaultKind: "template"
|
|
130
|
-
});
|
|
131
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
132
|
-
const templatePath = [namespace, kind, name].map((s) => encodeURIComponent(s)).join("/");
|
|
133
|
-
const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;
|
|
134
|
-
const response = await this.fetchApi.fetch(url);
|
|
135
|
-
if (!response.ok) {
|
|
136
|
-
throw await ResponseError.fromResponse(response);
|
|
137
|
-
}
|
|
138
|
-
const schema = await response.json();
|
|
139
|
-
return schema;
|
|
140
|
-
}
|
|
141
|
-
async scaffold(options) {
|
|
142
|
-
const { templateRef, values, secrets = {} } = options;
|
|
143
|
-
const url = `${await this.discoveryApi.getBaseUrl("scaffolder")}/v2/tasks`;
|
|
144
|
-
const response = await this.fetchApi.fetch(url, {
|
|
145
|
-
method: "POST",
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "application/json"
|
|
148
|
-
},
|
|
149
|
-
body: JSON.stringify({
|
|
150
|
-
templateRef,
|
|
151
|
-
values: { ...values },
|
|
152
|
-
secrets
|
|
153
|
-
})
|
|
154
|
-
});
|
|
155
|
-
if (response.status !== 201) {
|
|
156
|
-
const status = `${response.status} ${response.statusText}`;
|
|
157
|
-
const body = await response.text();
|
|
158
|
-
throw new Error(`Backend request failed, ${status} ${body.trim()}`);
|
|
159
|
-
}
|
|
160
|
-
const { id } = await response.json();
|
|
161
|
-
return { taskId: id };
|
|
162
|
-
}
|
|
163
|
-
async getTask(taskId) {
|
|
164
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
165
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`;
|
|
166
|
-
const response = await this.fetchApi.fetch(url);
|
|
167
|
-
if (!response.ok) {
|
|
168
|
-
throw await ResponseError.fromResponse(response);
|
|
169
|
-
}
|
|
170
|
-
return await response.json();
|
|
171
|
-
}
|
|
172
|
-
streamLogs(options) {
|
|
173
|
-
if (this.useLongPollingLogs) {
|
|
174
|
-
return this.streamLogsPolling(options);
|
|
175
|
-
}
|
|
176
|
-
return this.streamLogsEventStream(options);
|
|
177
|
-
}
|
|
178
|
-
async dryRun(options) {
|
|
179
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
180
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/dry-run`, {
|
|
181
|
-
method: "POST",
|
|
182
|
-
headers: {
|
|
183
|
-
"Content-Type": "application/json"
|
|
184
|
-
},
|
|
185
|
-
body: JSON.stringify({
|
|
186
|
-
template: options.template,
|
|
187
|
-
values: options.values,
|
|
188
|
-
secrets: options.secrets,
|
|
189
|
-
directoryContents: options.directoryContents
|
|
190
|
-
})
|
|
191
|
-
});
|
|
192
|
-
if (!response.ok) {
|
|
193
|
-
throw await ResponseError.fromResponse(response);
|
|
194
|
-
}
|
|
195
|
-
return response.json();
|
|
196
|
-
}
|
|
197
|
-
streamLogsEventStream({
|
|
198
|
-
taskId,
|
|
199
|
-
after
|
|
200
|
-
}) {
|
|
201
|
-
return new ObservableImpl((subscriber) => {
|
|
202
|
-
const params = new URLSearchParams();
|
|
203
|
-
if (after !== void 0) {
|
|
204
|
-
params.set("after", String(Number(after)));
|
|
205
|
-
}
|
|
206
|
-
this.discoveryApi.getBaseUrl("scaffolder").then(
|
|
207
|
-
(baseUrl) => {
|
|
208
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
|
|
209
|
-
taskId
|
|
210
|
-
)}/eventstream`;
|
|
211
|
-
const processEvent = (event) => {
|
|
212
|
-
if (event.data) {
|
|
213
|
-
try {
|
|
214
|
-
subscriber.next(JSON.parse(event.data));
|
|
215
|
-
} catch (ex) {
|
|
216
|
-
subscriber.error(ex);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
const eventSource = new EventSource(url, { withCredentials: true });
|
|
221
|
-
eventSource.addEventListener("log", processEvent);
|
|
222
|
-
eventSource.addEventListener("cancelled", processEvent);
|
|
223
|
-
eventSource.addEventListener("completion", (event) => {
|
|
224
|
-
processEvent(event);
|
|
225
|
-
eventSource.close();
|
|
226
|
-
subscriber.complete();
|
|
227
|
-
});
|
|
228
|
-
eventSource.addEventListener("error", (event) => {
|
|
229
|
-
subscriber.error(event);
|
|
230
|
-
});
|
|
231
|
-
},
|
|
232
|
-
(error) => {
|
|
233
|
-
subscriber.error(error);
|
|
234
|
-
}
|
|
235
|
-
);
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
streamLogsPolling({
|
|
239
|
-
taskId,
|
|
240
|
-
after: inputAfter
|
|
241
|
-
}) {
|
|
242
|
-
let after = inputAfter;
|
|
243
|
-
return new ObservableImpl((subscriber) => {
|
|
244
|
-
this.discoveryApi.getBaseUrl("scaffolder").then(async (baseUrl) => {
|
|
245
|
-
while (!subscriber.closed) {
|
|
246
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
|
|
247
|
-
taskId
|
|
248
|
-
)}/events?${qs.stringify({ after })}`;
|
|
249
|
-
const response = await this.fetchApi.fetch(url);
|
|
250
|
-
if (!response.ok) {
|
|
251
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const logs = await response.json();
|
|
255
|
-
for (const event of logs) {
|
|
256
|
-
after = Number(event.id);
|
|
257
|
-
subscriber.next(event);
|
|
258
|
-
if (event.type === "completion") {
|
|
259
|
-
subscriber.complete();
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
async listActions() {
|
|
268
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
269
|
-
const response = await this.fetchApi.fetch(`${baseUrl}/v2/actions`);
|
|
270
|
-
if (!response.ok) {
|
|
271
|
-
throw await ResponseError.fromResponse(response);
|
|
272
|
-
}
|
|
273
|
-
return await response.json();
|
|
274
|
-
}
|
|
275
|
-
async cancelTask(taskId) {
|
|
276
|
-
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
277
|
-
const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/cancel`;
|
|
278
|
-
const response = await this.fetchApi.fetch(url, {
|
|
279
|
-
method: "POST"
|
|
280
|
-
});
|
|
281
|
-
if (!response.ok) {
|
|
282
|
-
throw await ResponseError.fromResponse(response);
|
|
283
|
-
}
|
|
284
|
-
return await response.json();
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function makeFieldSchemaFromZod(returnSchema, uiOptionsSchema) {
|
|
289
|
-
return {
|
|
290
|
-
schema: {
|
|
291
|
-
returnValue: zodToJsonSchema(returnSchema),
|
|
292
|
-
uiOptions: uiOptionsSchema ? zodToJsonSchema(uiOptionsSchema) : void 0
|
|
293
|
-
},
|
|
294
|
-
type: null,
|
|
295
|
-
uiOptionsType: null
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const entityQueryFilterExpressionSchema = z.record(
|
|
300
|
-
z.string().or(z.object({ exists: z.boolean().optional() })).or(z.array(z.string()))
|
|
301
|
-
);
|
|
302
|
-
const EntityPickerFieldSchema = makeFieldSchemaFromZod(
|
|
303
|
-
z.string(),
|
|
304
|
-
z.object({
|
|
305
|
-
/**
|
|
306
|
-
* @deprecated Use `catalogFilter` instead.
|
|
307
|
-
*/
|
|
308
|
-
allowedKinds: z.array(z.string()).optional().describe(
|
|
309
|
-
"DEPRECATED: Use `catalogFilter` instead. List of kinds of entities to derive options from"
|
|
310
|
-
),
|
|
311
|
-
defaultKind: z.string().optional().describe(
|
|
312
|
-
"The default entity kind. Options of this kind will not be prefixed."
|
|
313
|
-
),
|
|
314
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
315
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
316
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
317
|
-
),
|
|
318
|
-
catalogFilter: z.array(entityQueryFilterExpressionSchema).or(entityQueryFilterExpressionSchema).optional().describe("List of key-value filter expression for entities")
|
|
319
|
-
})
|
|
320
|
-
);
|
|
321
|
-
const EntityPickerSchema = EntityPickerFieldSchema.schema;
|
|
322
|
-
|
|
323
|
-
const EntityPicker = (props) => {
|
|
324
|
-
var _a, _b, _c, _d, _e;
|
|
325
|
-
const {
|
|
326
|
-
onChange,
|
|
327
|
-
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
328
|
-
required,
|
|
329
|
-
uiSchema,
|
|
330
|
-
rawErrors,
|
|
331
|
-
formData,
|
|
332
|
-
idSchema
|
|
333
|
-
} = props;
|
|
334
|
-
const catalogFilter = buildCatalogFilter(uiSchema);
|
|
335
|
-
const defaultKind = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.defaultKind;
|
|
336
|
-
const defaultNamespace = ((_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultNamespace) || void 0;
|
|
337
|
-
const catalogApi = useApi(catalogApiRef);
|
|
338
|
-
const { value: entities, loading } = useAsync(async () => {
|
|
339
|
-
const { items } = await catalogApi.getEntities(
|
|
340
|
-
catalogFilter ? { filter: catalogFilter } : void 0
|
|
341
|
-
);
|
|
342
|
-
return items;
|
|
343
|
-
});
|
|
344
|
-
const allowArbitraryValues = (_d = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.allowArbitraryValues) != null ? _d : true;
|
|
345
|
-
const getLabel = useCallback(
|
|
346
|
-
(ref) => {
|
|
347
|
-
try {
|
|
348
|
-
return humanizeEntityRef(
|
|
349
|
-
parseEntityRef(ref, { defaultKind, defaultNamespace }),
|
|
350
|
-
{
|
|
351
|
-
defaultKind,
|
|
352
|
-
defaultNamespace
|
|
353
|
-
}
|
|
354
|
-
);
|
|
355
|
-
} catch (err) {
|
|
356
|
-
return ref;
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
[defaultKind, defaultNamespace]
|
|
360
|
-
);
|
|
361
|
-
const onSelect = useCallback(
|
|
362
|
-
(_, ref, reason) => {
|
|
363
|
-
if (typeof ref !== "string") {
|
|
364
|
-
onChange(ref ? stringifyEntityRef(ref) : "");
|
|
365
|
-
} else {
|
|
366
|
-
if (reason === "blur" || reason === "create-option") {
|
|
367
|
-
let entityRef = ref;
|
|
368
|
-
try {
|
|
369
|
-
entityRef = stringifyEntityRef(
|
|
370
|
-
parseEntityRef(ref, {
|
|
371
|
-
defaultKind,
|
|
372
|
-
defaultNamespace
|
|
373
|
-
})
|
|
374
|
-
);
|
|
375
|
-
} catch (err) {
|
|
376
|
-
}
|
|
377
|
-
if (formData !== ref || allowArbitraryValues) {
|
|
378
|
-
onChange(entityRef);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
[onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues]
|
|
384
|
-
);
|
|
385
|
-
useEffect(() => {
|
|
386
|
-
if ((entities == null ? void 0 : entities.length) === 1) {
|
|
387
|
-
onChange(stringifyEntityRef(entities[0]));
|
|
388
|
-
}
|
|
389
|
-
}, [entities, onChange]);
|
|
390
|
-
return /* @__PURE__ */ React.createElement(
|
|
391
|
-
FormControl,
|
|
392
|
-
{
|
|
393
|
-
margin: "normal",
|
|
394
|
-
required,
|
|
395
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData
|
|
396
|
-
},
|
|
397
|
-
/* @__PURE__ */ React.createElement(
|
|
398
|
-
Autocomplete,
|
|
399
|
-
{
|
|
400
|
-
disabled: (entities == null ? void 0 : entities.length) === 1,
|
|
401
|
-
id: idSchema == null ? void 0 : idSchema.$id,
|
|
402
|
-
value: (
|
|
403
|
-
// Since free solo can be enabled, attempt to parse as a full entity ref first, then fall
|
|
404
|
-
// back to the given value.
|
|
405
|
-
(_e = entities == null ? void 0 : entities.find((e) => stringifyEntityRef(e) === formData)) != null ? _e : allowArbitraryValues && formData ? getLabel(formData) : ""
|
|
406
|
-
),
|
|
407
|
-
loading,
|
|
408
|
-
onChange: onSelect,
|
|
409
|
-
options: entities || [],
|
|
410
|
-
getOptionLabel: (option) => (
|
|
411
|
-
// option can be a string due to freeSolo.
|
|
412
|
-
typeof option === "string" ? option : humanizeEntityRef(option, { defaultKind, defaultNamespace })
|
|
413
|
-
),
|
|
414
|
-
autoSelect: true,
|
|
415
|
-
freeSolo: allowArbitraryValues,
|
|
416
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
417
|
-
TextField,
|
|
418
|
-
{
|
|
419
|
-
...params,
|
|
420
|
-
label: title,
|
|
421
|
-
margin: "dense",
|
|
422
|
-
helperText: description,
|
|
423
|
-
FormHelperTextProps: { margin: "dense", style: { marginLeft: 0 } },
|
|
424
|
-
variant: "outlined",
|
|
425
|
-
required,
|
|
426
|
-
InputProps: params.InputProps
|
|
427
|
-
}
|
|
428
|
-
)
|
|
429
|
-
}
|
|
430
|
-
)
|
|
431
|
-
);
|
|
432
|
-
};
|
|
433
|
-
function convertOpsValues(value) {
|
|
434
|
-
if (typeof value === "object" && value.exists) {
|
|
435
|
-
return CATALOG_FILTER_EXISTS;
|
|
436
|
-
}
|
|
437
|
-
return value == null ? void 0 : value.toString();
|
|
438
|
-
}
|
|
439
|
-
function convertSchemaFiltersToQuery(schemaFilters) {
|
|
440
|
-
const query = {};
|
|
441
|
-
for (const [key, value] of Object.entries(schemaFilters)) {
|
|
442
|
-
if (Array.isArray(value)) {
|
|
443
|
-
query[key] = value;
|
|
444
|
-
} else {
|
|
445
|
-
query[key] = convertOpsValues(value);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return query;
|
|
449
|
-
}
|
|
450
|
-
function buildCatalogFilter(uiSchema) {
|
|
451
|
-
var _a, _b;
|
|
452
|
-
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
453
|
-
const catalogFilter = ((_b = uiSchema["ui:options"]) == null ? void 0 : _b.catalogFilter) || allowedKinds && { kind: allowedKinds };
|
|
454
|
-
if (!catalogFilter) {
|
|
455
|
-
return void 0;
|
|
456
|
-
}
|
|
457
|
-
if (Array.isArray(catalogFilter)) {
|
|
458
|
-
return catalogFilter.map(convertSchemaFiltersToQuery);
|
|
459
|
-
}
|
|
460
|
-
return convertSchemaFiltersToQuery(catalogFilter);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
const entityNamePickerValidation = (value, validation) => {
|
|
464
|
-
if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
|
|
465
|
-
validation.addError(
|
|
466
|
-
"Must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters."
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
const EntityNamePickerFieldSchema = makeFieldSchemaFromZod(z.string());
|
|
472
|
-
const EntityNamePickerSchema = EntityNamePickerFieldSchema.schema;
|
|
473
|
-
|
|
474
|
-
const EntityNamePicker = (props) => {
|
|
475
|
-
const {
|
|
476
|
-
onChange,
|
|
477
|
-
required,
|
|
478
|
-
schema: { title = "Name", description = "Unique name of the component" },
|
|
479
|
-
rawErrors,
|
|
480
|
-
formData,
|
|
481
|
-
uiSchema: { "ui:autofocus": autoFocus },
|
|
482
|
-
idSchema,
|
|
483
|
-
placeholder
|
|
484
|
-
} = props;
|
|
485
|
-
return /* @__PURE__ */ React.createElement(
|
|
486
|
-
TextField,
|
|
487
|
-
{
|
|
488
|
-
id: idSchema == null ? void 0 : idSchema.$id,
|
|
489
|
-
label: title,
|
|
490
|
-
placeholder,
|
|
491
|
-
helperText: description,
|
|
492
|
-
required,
|
|
493
|
-
value: formData != null ? formData : "",
|
|
494
|
-
onChange: ({ target: { value } }) => onChange(value),
|
|
495
|
-
margin: "normal",
|
|
496
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
|
|
497
|
-
inputProps: { autoFocus }
|
|
498
|
-
}
|
|
499
|
-
);
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
const OwnerPickerFieldSchema = makeFieldSchemaFromZod(
|
|
503
|
-
z.string(),
|
|
504
|
-
z.object({
|
|
505
|
-
/**
|
|
506
|
-
* @deprecated Use `catalogFilter` instead.
|
|
507
|
-
*/
|
|
508
|
-
allowedKinds: z.array(z.string()).default(["Group", "User"]).optional().describe(
|
|
509
|
-
"DEPRECATED: Use `catalogFilter` instead. List of kinds of entities to derive options from. Defaults to Group and User"
|
|
510
|
-
),
|
|
511
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
512
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
513
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
514
|
-
),
|
|
515
|
-
catalogFilter: z.array(entityQueryFilterExpressionSchema).or(entityQueryFilterExpressionSchema).optional().describe("List of key-value filter expression for entities")
|
|
516
|
-
})
|
|
517
|
-
);
|
|
518
|
-
const OwnerPickerSchema = OwnerPickerFieldSchema.schema;
|
|
519
|
-
|
|
520
|
-
const OwnerPicker = (props) => {
|
|
521
|
-
var _a, _b, _c, _d, _e;
|
|
522
|
-
const {
|
|
523
|
-
schema: { title = "Owner", description = "The owner of the component" },
|
|
524
|
-
uiSchema,
|
|
525
|
-
...restProps
|
|
526
|
-
} = props;
|
|
527
|
-
const defaultNamespace = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.defaultNamespace;
|
|
528
|
-
const allowedKinds = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.allowedKinds;
|
|
529
|
-
const catalogFilter = ((_c = uiSchema["ui:options"]) == null ? void 0 : _c.catalogFilter) || {
|
|
530
|
-
kind: allowedKinds || ["Group", "User"]
|
|
531
|
-
};
|
|
532
|
-
const ownerUiSchema = {
|
|
533
|
-
...uiSchema,
|
|
534
|
-
"ui:options": {
|
|
535
|
-
catalogFilter,
|
|
536
|
-
defaultKind: "Group",
|
|
537
|
-
allowArbitraryValues: (_e = (_d = uiSchema["ui:options"]) == null ? void 0 : _d.allowArbitraryValues) != null ? _e : true,
|
|
538
|
-
...defaultNamespace !== void 0 ? { defaultNamespace } : {}
|
|
539
|
-
}
|
|
540
|
-
};
|
|
541
|
-
return /* @__PURE__ */ React.createElement(
|
|
542
|
-
EntityPicker,
|
|
543
|
-
{
|
|
544
|
-
...restProps,
|
|
545
|
-
schema: { title, description },
|
|
546
|
-
uiSchema: ownerUiSchema
|
|
547
|
-
}
|
|
548
|
-
);
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
const RepoUrlPickerFieldSchema = makeFieldSchemaFromZod(
|
|
552
|
-
z.string(),
|
|
553
|
-
z.object({
|
|
554
|
-
allowedHosts: z.array(z.string()).optional().describe("List of allowed SCM platform hosts"),
|
|
555
|
-
allowedOrganizations: z.array(z.string()).optional().describe("List of allowed organizations in the given SCM platform"),
|
|
556
|
-
allowedOwners: z.array(z.string()).optional().describe("List of allowed owners in the given SCM platform"),
|
|
557
|
-
allowedProjects: z.array(z.string()).optional().describe("List of allowed projects in the given SCM platform"),
|
|
558
|
-
allowedRepos: z.array(z.string()).optional().describe("List of allowed repos in the given SCM platform"),
|
|
559
|
-
requestUserCredentials: z.object({
|
|
560
|
-
secretsKey: z.string().describe(
|
|
561
|
-
"Key used within the template secrets context to store the credential"
|
|
562
|
-
),
|
|
563
|
-
additionalScopes: z.object({
|
|
564
|
-
gerrit: z.array(z.string()).optional().describe("Additional Gerrit scopes to request"),
|
|
565
|
-
github: z.array(z.string()).optional().describe("Additional GitHub scopes to request"),
|
|
566
|
-
gitlab: z.array(z.string()).optional().describe("Additional GitLab scopes to request"),
|
|
567
|
-
bitbucket: z.array(z.string()).optional().describe("Additional BitBucket scopes to request"),
|
|
568
|
-
azure: z.array(z.string()).optional().describe("Additional Azure scopes to request")
|
|
569
|
-
}).optional().describe("Additional permission scopes to request")
|
|
570
|
-
}).optional().describe(
|
|
571
|
-
"If defined will request user credentials to auth against the given SCM platform"
|
|
572
|
-
)
|
|
573
|
-
})
|
|
574
|
-
);
|
|
575
|
-
const RepoUrlPickerSchema = RepoUrlPickerFieldSchema.schema;
|
|
576
|
-
|
|
577
|
-
const repoPickerValidation = (value, validation, context) => {
|
|
578
|
-
var _a, _b;
|
|
579
|
-
try {
|
|
580
|
-
const { host, searchParams } = new URL(`https://${value}`);
|
|
581
|
-
const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);
|
|
582
|
-
if (!host) {
|
|
583
|
-
validation.addError(
|
|
584
|
-
"Incomplete repository location provided, host not provided"
|
|
585
|
-
);
|
|
586
|
-
} else {
|
|
587
|
-
if (((_a = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _a.type) === "bitbucket") {
|
|
588
|
-
if (host === "bitbucket.org" && !searchParams.get("workspace")) {
|
|
589
|
-
validation.addError(
|
|
590
|
-
"Incomplete repository location provided, workspace not provided"
|
|
591
|
-
);
|
|
592
|
-
}
|
|
593
|
-
if (!searchParams.get("project")) {
|
|
594
|
-
validation.addError(
|
|
595
|
-
"Incomplete repository location provided, project not provided"
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
} else if (((_b = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _b.type) !== "gerrit") {
|
|
599
|
-
if (!searchParams.get("owner")) {
|
|
600
|
-
validation.addError(
|
|
601
|
-
"Incomplete repository location provided, owner not provided"
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (!searchParams.get("repo")) {
|
|
606
|
-
validation.addError(
|
|
607
|
-
"Incomplete repository location provided, repo not provided"
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
} catch {
|
|
612
|
-
validation.addError("Unable to parse the Repository URL");
|
|
613
|
-
}
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
const GithubRepoPicker = (props) => {
|
|
617
|
-
const { allowedOwners = [], rawErrors, state, onChange } = props;
|
|
618
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
619
|
-
const { owner } = state;
|
|
620
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
621
|
-
FormControl,
|
|
622
|
-
{
|
|
623
|
-
margin: "normal",
|
|
624
|
-
required: true,
|
|
625
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
626
|
-
},
|
|
627
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
628
|
-
Select,
|
|
629
|
-
{
|
|
630
|
-
native: true,
|
|
631
|
-
label: "Owner Available",
|
|
632
|
-
onChange: (s) => onChange({ owner: String(Array.isArray(s) ? s[0] : s) }),
|
|
633
|
-
disabled: allowedOwners.length === 1,
|
|
634
|
-
selected: owner,
|
|
635
|
-
items: ownerItems
|
|
636
|
-
}
|
|
637
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Owner"), /* @__PURE__ */ React.createElement(
|
|
638
|
-
Input,
|
|
639
|
-
{
|
|
640
|
-
id: "ownerInput",
|
|
641
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
642
|
-
value: owner
|
|
643
|
-
}
|
|
644
|
-
)),
|
|
645
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The organization, user or project that this repo will belong to")
|
|
646
|
-
));
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
const GitlabRepoPicker = (props) => {
|
|
650
|
-
const { allowedOwners = [], state, onChange, rawErrors } = props;
|
|
651
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
652
|
-
const { owner } = state;
|
|
653
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
654
|
-
FormControl,
|
|
655
|
-
{
|
|
656
|
-
margin: "normal",
|
|
657
|
-
required: true,
|
|
658
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
659
|
-
},
|
|
660
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
661
|
-
Select,
|
|
662
|
-
{
|
|
663
|
-
native: true,
|
|
664
|
-
label: "Owner Available",
|
|
665
|
-
onChange: (selected) => onChange({
|
|
666
|
-
owner: String(Array.isArray(selected) ? selected[0] : selected)
|
|
667
|
-
}),
|
|
668
|
-
disabled: allowedOwners.length === 1,
|
|
669
|
-
selected: owner,
|
|
670
|
-
items: ownerItems
|
|
671
|
-
}
|
|
672
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Owner"), /* @__PURE__ */ React.createElement(
|
|
673
|
-
Input,
|
|
674
|
-
{
|
|
675
|
-
id: "ownerInput",
|
|
676
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
677
|
-
value: owner
|
|
678
|
-
}
|
|
679
|
-
)),
|
|
680
|
-
/* @__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.")
|
|
681
|
-
));
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
const AzureRepoPicker = (props) => {
|
|
685
|
-
const {
|
|
686
|
-
allowedOrganizations = [],
|
|
687
|
-
allowedOwners = [],
|
|
688
|
-
rawErrors,
|
|
689
|
-
state,
|
|
690
|
-
onChange
|
|
691
|
-
} = props;
|
|
692
|
-
const organizationItems = allowedOrganizations ? allowedOrganizations.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
693
|
-
const ownerItems = allowedOwners ? allowedOwners.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
694
|
-
const { organization, owner } = state;
|
|
695
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
696
|
-
FormControl,
|
|
697
|
-
{
|
|
698
|
-
margin: "normal",
|
|
699
|
-
required: true,
|
|
700
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !organization
|
|
701
|
-
},
|
|
702
|
-
(allowedOrganizations == null ? void 0 : allowedOrganizations.length) ? /* @__PURE__ */ React.createElement(
|
|
703
|
-
Select,
|
|
704
|
-
{
|
|
705
|
-
native: true,
|
|
706
|
-
label: "Organization",
|
|
707
|
-
onChange: (s) => onChange({ organization: String(Array.isArray(s) ? s[0] : s) }),
|
|
708
|
-
disabled: allowedOrganizations.length === 1,
|
|
709
|
-
selected: organization,
|
|
710
|
-
items: organizationItems
|
|
711
|
-
}
|
|
712
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "orgInput" }, "Organization"), /* @__PURE__ */ React.createElement(
|
|
713
|
-
Input,
|
|
714
|
-
{
|
|
715
|
-
id: "orgInput",
|
|
716
|
-
onChange: (e) => onChange({ organization: e.target.value }),
|
|
717
|
-
value: organization
|
|
718
|
-
}
|
|
719
|
-
)),
|
|
720
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Organization that this repo will belong to")
|
|
721
|
-
), /* @__PURE__ */ React.createElement(
|
|
722
|
-
FormControl,
|
|
723
|
-
{
|
|
724
|
-
margin: "normal",
|
|
725
|
-
required: true,
|
|
726
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !owner
|
|
727
|
-
},
|
|
728
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
729
|
-
Select,
|
|
730
|
-
{
|
|
731
|
-
native: true,
|
|
732
|
-
label: "Owner",
|
|
733
|
-
onChange: (s) => onChange({ owner: String(Array.isArray(s) ? s[0] : s) }),
|
|
734
|
-
disabled: allowedOwners.length === 1,
|
|
735
|
-
selected: owner,
|
|
736
|
-
items: ownerItems
|
|
737
|
-
}
|
|
738
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "ownerInput" }, "Project"), /* @__PURE__ */ React.createElement(
|
|
739
|
-
Input,
|
|
740
|
-
{
|
|
741
|
-
id: "ownerInput",
|
|
742
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
743
|
-
value: owner
|
|
744
|
-
}
|
|
745
|
-
)),
|
|
746
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Project that this repo will belong to")
|
|
747
|
-
));
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
const BitbucketRepoPicker = (props) => {
|
|
751
|
-
const {
|
|
752
|
-
allowedOwners = [],
|
|
753
|
-
allowedProjects = [],
|
|
754
|
-
onChange,
|
|
755
|
-
rawErrors,
|
|
756
|
-
state
|
|
757
|
-
} = props;
|
|
758
|
-
const { host, workspace, project } = state;
|
|
759
|
-
const ownerItems = allowedOwners ? allowedOwners == null ? void 0 : allowedOwners.map((i) => ({ label: i, value: i })) : [];
|
|
760
|
-
const projectItems = allowedProjects ? allowedProjects == null ? void 0 : allowedProjects.map((i) => ({ label: i, value: i })) : [];
|
|
761
|
-
useEffect(() => {
|
|
762
|
-
if (host === "bitbucket.org" && allowedOwners.length) {
|
|
763
|
-
onChange({ workspace: allowedOwners[0] });
|
|
764
|
-
}
|
|
765
|
-
}, [allowedOwners, host, onChange]);
|
|
766
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, host === "bitbucket.org" && /* @__PURE__ */ React.createElement(
|
|
767
|
-
FormControl,
|
|
768
|
-
{
|
|
769
|
-
margin: "normal",
|
|
770
|
-
required: true,
|
|
771
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
|
|
772
|
-
},
|
|
773
|
-
(allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(
|
|
774
|
-
Select,
|
|
775
|
-
{
|
|
776
|
-
native: true,
|
|
777
|
-
label: "Allowed Workspaces",
|
|
778
|
-
onChange: (s) => onChange({ workspace: String(Array.isArray(s) ? s[0] : s) }),
|
|
779
|
-
disabled: allowedOwners.length === 1,
|
|
780
|
-
selected: workspace,
|
|
781
|
-
items: ownerItems
|
|
782
|
-
}
|
|
783
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "workspaceInput" }, "Workspace"), /* @__PURE__ */ React.createElement(
|
|
784
|
-
Input,
|
|
785
|
-
{
|
|
786
|
-
id: "workspaceInput",
|
|
787
|
-
onChange: (e) => onChange({ workspace: e.target.value }),
|
|
788
|
-
value: workspace
|
|
789
|
-
}
|
|
790
|
-
)),
|
|
791
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Workspace that this repo will belong to")
|
|
792
|
-
), /* @__PURE__ */ React.createElement(
|
|
793
|
-
FormControl,
|
|
794
|
-
{
|
|
795
|
-
margin: "normal",
|
|
796
|
-
required: true,
|
|
797
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !project
|
|
798
|
-
},
|
|
799
|
-
(allowedProjects == null ? void 0 : allowedProjects.length) ? /* @__PURE__ */ React.createElement(
|
|
800
|
-
Select,
|
|
801
|
-
{
|
|
802
|
-
native: true,
|
|
803
|
-
label: "Allowed Projects",
|
|
804
|
-
onChange: (s) => onChange({ project: String(Array.isArray(s) ? s[0] : s) }),
|
|
805
|
-
disabled: allowedProjects.length === 1,
|
|
806
|
-
selected: project,
|
|
807
|
-
items: projectItems
|
|
808
|
-
}
|
|
809
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "projectInput" }, "Project"), /* @__PURE__ */ React.createElement(
|
|
810
|
-
Input,
|
|
811
|
-
{
|
|
812
|
-
id: "projectInput",
|
|
813
|
-
onChange: (e) => onChange({ project: e.target.value }),
|
|
814
|
-
value: project
|
|
815
|
-
}
|
|
816
|
-
)),
|
|
817
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The Project that this repo will belong to")
|
|
818
|
-
));
|
|
819
|
-
};
|
|
820
|
-
|
|
821
|
-
const GerritRepoPicker = (props) => {
|
|
822
|
-
const { onChange, rawErrors, state } = props;
|
|
823
|
-
const { workspace, owner } = state;
|
|
824
|
-
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(
|
|
825
|
-
Input,
|
|
826
|
-
{
|
|
827
|
-
id: "ownerInput",
|
|
828
|
-
onChange: (e) => onChange({ owner: e.target.value }),
|
|
829
|
-
value: owner
|
|
830
|
-
}
|
|
831
|
-
), /* @__PURE__ */ React.createElement(FormHelperText, null, "The owner of the project (optional)")), /* @__PURE__ */ React.createElement(
|
|
832
|
-
FormControl,
|
|
833
|
-
{
|
|
834
|
-
margin: "normal",
|
|
835
|
-
required: true,
|
|
836
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
|
|
837
|
-
},
|
|
838
|
-
/* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "parentInput" }, "Parent"),
|
|
839
|
-
/* @__PURE__ */ React.createElement(
|
|
840
|
-
Input,
|
|
841
|
-
{
|
|
842
|
-
id: "parentInput",
|
|
843
|
-
onChange: (e) => onChange({ workspace: e.target.value }),
|
|
844
|
-
value: workspace
|
|
845
|
-
}
|
|
846
|
-
),
|
|
847
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The project parent that the repo will belong to")
|
|
848
|
-
));
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
const RepoUrlPickerHost = (props) => {
|
|
852
|
-
const { host, hosts, onChange, rawErrors } = props;
|
|
853
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
854
|
-
const { value: { integrations } = { integrations: [] }, loading } = useAsync(
|
|
855
|
-
async () => {
|
|
856
|
-
return await scaffolderApi.getIntegrationsList({
|
|
857
|
-
allowedHosts: hosts != null ? hosts : []
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
);
|
|
861
|
-
useEffect(() => {
|
|
862
|
-
if (!host) {
|
|
863
|
-
if (hosts == null ? void 0 : hosts.length) {
|
|
864
|
-
onChange(hosts[0]);
|
|
865
|
-
} else if (integrations == null ? void 0 : integrations.length) {
|
|
866
|
-
onChange(integrations[0].host);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}, [hosts, host, onChange, integrations]);
|
|
870
|
-
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" }];
|
|
871
|
-
if (loading) {
|
|
872
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
873
|
-
}
|
|
874
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
875
|
-
FormControl,
|
|
876
|
-
{
|
|
877
|
-
margin: "normal",
|
|
878
|
-
required: true,
|
|
879
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !host
|
|
880
|
-
},
|
|
881
|
-
/* @__PURE__ */ React.createElement(
|
|
882
|
-
Select,
|
|
883
|
-
{
|
|
884
|
-
native: true,
|
|
885
|
-
disabled: (hosts == null ? void 0 : hosts.length) === 1,
|
|
886
|
-
label: "Host",
|
|
887
|
-
onChange: (s) => onChange(String(Array.isArray(s) ? s[0] : s)),
|
|
888
|
-
selected: host,
|
|
889
|
-
items: hostsOptions,
|
|
890
|
-
"data-testid": "host-select"
|
|
891
|
-
}
|
|
892
|
-
),
|
|
893
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The host where the repository will be created")
|
|
894
|
-
));
|
|
895
|
-
};
|
|
896
|
-
|
|
897
|
-
const RepoUrlPickerRepoName = (props) => {
|
|
898
|
-
const { repoName, allowedRepos, onChange, rawErrors } = props;
|
|
899
|
-
useEffect(() => {
|
|
900
|
-
if (!repoName) {
|
|
901
|
-
if (allowedRepos == null ? void 0 : allowedRepos.length) {
|
|
902
|
-
onChange(allowedRepos[0]);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
}, [allowedRepos, repoName, onChange]);
|
|
906
|
-
const repoItems = allowedRepos ? allowedRepos.map((i) => ({ label: i, value: i })) : [{ label: "Loading...", value: "loading" }];
|
|
907
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
908
|
-
FormControl,
|
|
909
|
-
{
|
|
910
|
-
margin: "normal",
|
|
911
|
-
required: true,
|
|
912
|
-
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !repoName
|
|
913
|
-
},
|
|
914
|
-
(allowedRepos == null ? void 0 : allowedRepos.length) ? /* @__PURE__ */ React.createElement(
|
|
915
|
-
Select,
|
|
916
|
-
{
|
|
917
|
-
native: true,
|
|
918
|
-
label: "Repositories Available",
|
|
919
|
-
onChange: (selected) => String(Array.isArray(selected) ? selected[0] : selected),
|
|
920
|
-
disabled: allowedRepos.length === 1,
|
|
921
|
-
selected: repoName,
|
|
922
|
-
items: repoItems
|
|
923
|
-
}
|
|
924
|
-
) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, { htmlFor: "repoNameInput" }, "Repository"), /* @__PURE__ */ React.createElement(
|
|
925
|
-
Input,
|
|
926
|
-
{
|
|
927
|
-
id: "repoNameInput",
|
|
928
|
-
onChange: (e) => onChange(String(e.target.value)),
|
|
929
|
-
value: repoName
|
|
930
|
-
}
|
|
931
|
-
)),
|
|
932
|
-
/* @__PURE__ */ React.createElement(FormHelperText, null, "The name of the repository")
|
|
933
|
-
));
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
function serializeRepoPickerUrl(data) {
|
|
937
|
-
if (!data.host) {
|
|
938
|
-
return void 0;
|
|
939
|
-
}
|
|
940
|
-
const params = new URLSearchParams();
|
|
941
|
-
if (data.owner) {
|
|
942
|
-
params.set("owner", data.owner);
|
|
943
|
-
}
|
|
944
|
-
if (data.repoName) {
|
|
945
|
-
params.set("repo", data.repoName);
|
|
946
|
-
}
|
|
947
|
-
if (data.organization) {
|
|
948
|
-
params.set("organization", data.organization);
|
|
949
|
-
}
|
|
950
|
-
if (data.workspace) {
|
|
951
|
-
params.set("workspace", data.workspace);
|
|
952
|
-
}
|
|
953
|
-
if (data.project) {
|
|
954
|
-
params.set("project", data.project);
|
|
955
|
-
}
|
|
956
|
-
return `${data.host}?${params.toString()}`;
|
|
957
|
-
}
|
|
958
|
-
function parseRepoPickerUrl(url) {
|
|
959
|
-
let host = "";
|
|
960
|
-
let owner = "";
|
|
961
|
-
let repoName = "";
|
|
962
|
-
let organization = "";
|
|
963
|
-
let workspace = "";
|
|
964
|
-
let project = "";
|
|
965
|
-
try {
|
|
966
|
-
if (url) {
|
|
967
|
-
const parsed = new URL(`https://${url}`);
|
|
968
|
-
host = parsed.host;
|
|
969
|
-
owner = parsed.searchParams.get("owner") || "";
|
|
970
|
-
repoName = parsed.searchParams.get("repo") || "";
|
|
971
|
-
organization = parsed.searchParams.get("organization") || "";
|
|
972
|
-
workspace = parsed.searchParams.get("workspace") || "";
|
|
973
|
-
project = parsed.searchParams.get("project") || "";
|
|
974
|
-
}
|
|
975
|
-
} catch {
|
|
976
|
-
}
|
|
977
|
-
return { host, owner, repoName, organization, workspace, project };
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
const RepoUrlPicker = (props) => {
|
|
981
|
-
var _a, _b;
|
|
982
|
-
const { uiSchema, onChange, rawErrors, formData } = props;
|
|
983
|
-
const [state, setState] = useState(
|
|
984
|
-
parseRepoPickerUrl(formData)
|
|
985
|
-
);
|
|
986
|
-
const integrationApi = useApi(scmIntegrationsApiRef);
|
|
987
|
-
const scmAuthApi = useApi(scmAuthApiRef);
|
|
988
|
-
const { setSecrets } = useTemplateSecrets();
|
|
989
|
-
const allowedHosts = useMemo(
|
|
990
|
-
() => {
|
|
991
|
-
var _a2, _b2;
|
|
992
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedHosts) != null ? _b2 : [];
|
|
993
|
-
},
|
|
994
|
-
[uiSchema]
|
|
995
|
-
);
|
|
996
|
-
const allowedOrganizations = useMemo(
|
|
997
|
-
() => {
|
|
998
|
-
var _a2, _b2;
|
|
999
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOrganizations) != null ? _b2 : [];
|
|
1000
|
-
},
|
|
1001
|
-
[uiSchema]
|
|
1002
|
-
);
|
|
1003
|
-
const allowedOwners = useMemo(
|
|
1004
|
-
() => {
|
|
1005
|
-
var _a2, _b2;
|
|
1006
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOwners) != null ? _b2 : [];
|
|
1007
|
-
},
|
|
1008
|
-
[uiSchema]
|
|
1009
|
-
);
|
|
1010
|
-
const allowedProjects = useMemo(
|
|
1011
|
-
() => {
|
|
1012
|
-
var _a2, _b2;
|
|
1013
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedProjects) != null ? _b2 : [];
|
|
1014
|
-
},
|
|
1015
|
-
[uiSchema]
|
|
1016
|
-
);
|
|
1017
|
-
const allowedRepos = useMemo(
|
|
1018
|
-
() => {
|
|
1019
|
-
var _a2, _b2;
|
|
1020
|
-
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedRepos) != null ? _b2 : [];
|
|
1021
|
-
},
|
|
1022
|
-
[uiSchema]
|
|
1023
|
-
);
|
|
1024
|
-
const { owner, organization, project, repoName } = state;
|
|
1025
|
-
useEffect(() => {
|
|
1026
|
-
onChange(serializeRepoPickerUrl(state));
|
|
1027
|
-
}, [state, onChange]);
|
|
1028
|
-
useEffect(() => {
|
|
1029
|
-
if (allowedOrganizations.length > 0 && !organization) {
|
|
1030
|
-
setState((prevState) => ({
|
|
1031
|
-
...prevState,
|
|
1032
|
-
organization: allowedOrganizations[0]
|
|
1033
|
-
}));
|
|
1034
|
-
}
|
|
1035
|
-
}, [setState, allowedOrganizations, organization]);
|
|
1036
|
-
useEffect(() => {
|
|
1037
|
-
if (allowedOwners.length > 0 && !owner) {
|
|
1038
|
-
setState((prevState) => ({
|
|
1039
|
-
...prevState,
|
|
1040
|
-
owner: allowedOwners[0]
|
|
1041
|
-
}));
|
|
1042
|
-
}
|
|
1043
|
-
}, [setState, allowedOwners, owner]);
|
|
1044
|
-
useEffect(() => {
|
|
1045
|
-
if (allowedProjects.length > 0 && !project) {
|
|
1046
|
-
setState((prevState) => ({
|
|
1047
|
-
...prevState,
|
|
1048
|
-
project: allowedProjects[0]
|
|
1049
|
-
}));
|
|
1050
|
-
}
|
|
1051
|
-
}, [setState, allowedProjects, project]);
|
|
1052
|
-
useEffect(() => {
|
|
1053
|
-
if (allowedRepos.length > 0 && !repoName) {
|
|
1054
|
-
setState((prevState) => ({ ...prevState, repoName: allowedRepos[0] }));
|
|
1055
|
-
}
|
|
1056
|
-
}, [setState, allowedRepos, repoName]);
|
|
1057
|
-
const updateLocalState = useCallback(
|
|
1058
|
-
(newState) => {
|
|
1059
|
-
setState((prevState) => ({ ...prevState, ...newState }));
|
|
1060
|
-
},
|
|
1061
|
-
[setState]
|
|
1062
|
-
);
|
|
1063
|
-
useDebounce(
|
|
1064
|
-
async () => {
|
|
1065
|
-
var _a2;
|
|
1066
|
-
const { requestUserCredentials } = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) != null ? _a2 : {};
|
|
1067
|
-
const workspace = state.owner ? state.owner : state.project;
|
|
1068
|
-
if (!requestUserCredentials || !(state.host && workspace && state.repoName)) {
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
1071
|
-
const [encodedHost, encodedWorkspace, encodedRepoName] = [
|
|
1072
|
-
state.host,
|
|
1073
|
-
workspace,
|
|
1074
|
-
state.repoName
|
|
1075
|
-
].map(encodeURIComponent);
|
|
1076
|
-
const { token } = await scmAuthApi.getCredentials({
|
|
1077
|
-
url: `https://${encodedHost}/${encodedWorkspace}/${encodedRepoName}`,
|
|
1078
|
-
additionalScope: {
|
|
1079
|
-
repoWrite: true,
|
|
1080
|
-
customScopes: requestUserCredentials.additionalScopes
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
setSecrets({ [requestUserCredentials.secretsKey]: token });
|
|
1084
|
-
},
|
|
1085
|
-
500,
|
|
1086
|
-
[state, uiSchema]
|
|
1087
|
-
);
|
|
1088
|
-
const hostType = (_b = state.host && ((_a = integrationApi.byHost(state.host)) == null ? void 0 : _a.type)) != null ? _b : null;
|
|
1089
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
1090
|
-
RepoUrlPickerHost,
|
|
1091
|
-
{
|
|
1092
|
-
host: state.host,
|
|
1093
|
-
hosts: allowedHosts,
|
|
1094
|
-
onChange: (host) => setState((prevState) => ({ ...prevState, host })),
|
|
1095
|
-
rawErrors
|
|
1096
|
-
}
|
|
1097
|
-
), hostType === "github" && /* @__PURE__ */ React.createElement(
|
|
1098
|
-
GithubRepoPicker,
|
|
1099
|
-
{
|
|
1100
|
-
allowedOwners,
|
|
1101
|
-
onChange: updateLocalState,
|
|
1102
|
-
rawErrors,
|
|
1103
|
-
state
|
|
1104
|
-
}
|
|
1105
|
-
), hostType === "gitlab" && /* @__PURE__ */ React.createElement(
|
|
1106
|
-
GitlabRepoPicker,
|
|
1107
|
-
{
|
|
1108
|
-
allowedOwners,
|
|
1109
|
-
rawErrors,
|
|
1110
|
-
state,
|
|
1111
|
-
onChange: updateLocalState
|
|
1112
|
-
}
|
|
1113
|
-
), hostType === "bitbucket" && /* @__PURE__ */ React.createElement(
|
|
1114
|
-
BitbucketRepoPicker,
|
|
1115
|
-
{
|
|
1116
|
-
allowedOwners,
|
|
1117
|
-
allowedProjects,
|
|
1118
|
-
rawErrors,
|
|
1119
|
-
state,
|
|
1120
|
-
onChange: updateLocalState
|
|
1121
|
-
}
|
|
1122
|
-
), hostType === "azure" && /* @__PURE__ */ React.createElement(
|
|
1123
|
-
AzureRepoPicker,
|
|
1124
|
-
{
|
|
1125
|
-
allowedOrganizations,
|
|
1126
|
-
allowedOwners,
|
|
1127
|
-
rawErrors,
|
|
1128
|
-
state,
|
|
1129
|
-
onChange: updateLocalState
|
|
1130
|
-
}
|
|
1131
|
-
), hostType === "gerrit" && /* @__PURE__ */ React.createElement(
|
|
1132
|
-
GerritRepoPicker,
|
|
1133
|
-
{
|
|
1134
|
-
rawErrors,
|
|
1135
|
-
state,
|
|
1136
|
-
onChange: updateLocalState
|
|
1137
|
-
}
|
|
1138
|
-
), /* @__PURE__ */ React.createElement(
|
|
1139
|
-
RepoUrlPickerRepoName,
|
|
1140
|
-
{
|
|
1141
|
-
repoName: state.repoName,
|
|
1142
|
-
allowedRepos,
|
|
1143
|
-
onChange: (repo) => setState((prevState) => ({ ...prevState, repoName: repo })),
|
|
1144
|
-
rawErrors
|
|
1145
|
-
}
|
|
1146
|
-
));
|
|
1147
|
-
};
|
|
1148
|
-
|
|
1149
|
-
const OwnedEntityPickerFieldSchema = makeFieldSchemaFromZod(
|
|
1150
|
-
z.string(),
|
|
1151
|
-
z.object({
|
|
1152
|
-
allowedKinds: z.array(z.string()).optional().describe("List of kinds of entities to derive options from"),
|
|
1153
|
-
defaultKind: z.string().optional().describe(
|
|
1154
|
-
"The default entity kind. Options of this kind will not be prefixed."
|
|
1155
|
-
),
|
|
1156
|
-
allowArbitraryValues: z.boolean().optional().describe("Whether to allow arbitrary user input. Defaults to true"),
|
|
1157
|
-
defaultNamespace: z.union([z.string(), z.literal(false)]).optional().describe(
|
|
1158
|
-
"The default namespace. Options with this namespace will not be prefixed."
|
|
1159
|
-
)
|
|
1160
|
-
})
|
|
1161
|
-
);
|
|
1162
|
-
const OwnedEntityPickerSchema = OwnedEntityPickerFieldSchema.schema;
|
|
1163
|
-
|
|
1164
|
-
const OwnedEntityPicker = (props) => {
|
|
1165
|
-
var _a;
|
|
1166
|
-
const {
|
|
1167
|
-
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
1168
|
-
uiSchema,
|
|
1169
|
-
required
|
|
1170
|
-
} = props;
|
|
1171
|
-
const identityApi = useApi(identityApiRef);
|
|
1172
|
-
const { loading, value: identityRefs } = useAsync(async () => {
|
|
1173
|
-
const identity = await identityApi.getBackstageIdentity();
|
|
1174
|
-
return identity.ownershipEntityRefs;
|
|
1175
|
-
});
|
|
1176
|
-
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
1177
|
-
if (loading)
|
|
1178
|
-
return /* @__PURE__ */ React.createElement(
|
|
1179
|
-
Autocomplete,
|
|
1180
|
-
{
|
|
1181
|
-
loading,
|
|
1182
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
1183
|
-
TextField,
|
|
1184
|
-
{
|
|
1185
|
-
...params,
|
|
1186
|
-
label: title,
|
|
1187
|
-
margin: "dense",
|
|
1188
|
-
helperText: description,
|
|
1189
|
-
FormHelperTextProps: { margin: "dense", style: { marginLeft: 0 } },
|
|
1190
|
-
variant: "outlined",
|
|
1191
|
-
required,
|
|
1192
|
-
InputProps: params.InputProps
|
|
1193
|
-
}
|
|
1194
|
-
),
|
|
1195
|
-
options: []
|
|
1196
|
-
}
|
|
1197
|
-
);
|
|
1198
|
-
return /* @__PURE__ */ React.createElement(
|
|
1199
|
-
EntityPicker,
|
|
1200
|
-
{
|
|
1201
|
-
...props,
|
|
1202
|
-
schema: { title, description },
|
|
1203
|
-
allowedKinds,
|
|
1204
|
-
catalogFilter: allowedKinds ? {
|
|
1205
|
-
filter: {
|
|
1206
|
-
kind: allowedKinds,
|
|
1207
|
-
[`relations.${RELATION_OWNED_BY}`]: identityRefs || []
|
|
1208
|
-
}
|
|
1209
|
-
} : {
|
|
1210
|
-
filter: {
|
|
1211
|
-
[`relations.${RELATION_OWNED_BY}`]: identityRefs || []
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
);
|
|
1216
|
-
};
|
|
1217
|
-
|
|
1218
|
-
const EntityTagsPickerFieldSchema = makeFieldSchemaFromZod(
|
|
1219
|
-
z.array(z.string()),
|
|
1220
|
-
z.object({
|
|
1221
|
-
kinds: z.array(z.string()).optional().describe("List of kinds of entities to derive tags from"),
|
|
1222
|
-
showCounts: z.boolean().optional().describe("Whether to show usage counts per tag"),
|
|
1223
|
-
helperText: z.string().optional().describe("Helper text to display")
|
|
1224
|
-
})
|
|
1225
|
-
);
|
|
1226
|
-
const EntityTagsPickerSchema = EntityTagsPickerFieldSchema.schema;
|
|
1227
|
-
|
|
1228
|
-
const EntityTagsPicker = (props) => {
|
|
1229
|
-
var _a, _b, _c;
|
|
1230
|
-
const { formData, onChange, uiSchema } = props;
|
|
1231
|
-
const catalogApi = useApi(catalogApiRef);
|
|
1232
|
-
const [tagOptions, setTagOptions] = useState([]);
|
|
1233
|
-
const [inputValue, setInputValue] = useState("");
|
|
1234
|
-
const [inputError, setInputError] = useState(false);
|
|
1235
|
-
const tagValidator = makeValidator().isValidTag;
|
|
1236
|
-
const kinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.kinds;
|
|
1237
|
-
const showCounts = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.showCounts;
|
|
1238
|
-
const helperText = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.helperText;
|
|
1239
|
-
const { loading, value: existingTags } = useAsync(async () => {
|
|
1240
|
-
const facet = "metadata.tags";
|
|
1241
|
-
const tagsRequest = { facets: [facet] };
|
|
1242
|
-
if (kinds) {
|
|
1243
|
-
tagsRequest.filter = { kind: kinds };
|
|
1244
|
-
}
|
|
1245
|
-
const { facets } = await catalogApi.getEntityFacets(tagsRequest);
|
|
1246
|
-
const tagFacets = Object.fromEntries(
|
|
1247
|
-
facets[facet].map(({ value, count }) => [value, count])
|
|
1248
|
-
);
|
|
1249
|
-
setTagOptions(
|
|
1250
|
-
Object.keys(tagFacets).sort(
|
|
1251
|
-
(a, b) => showCounts ? tagFacets[b] - tagFacets[a] : a.localeCompare(b)
|
|
1252
|
-
)
|
|
1253
|
-
);
|
|
1254
|
-
return tagFacets;
|
|
1255
|
-
});
|
|
1256
|
-
const setTags = (_, values) => {
|
|
1257
|
-
let hasError = false;
|
|
1258
|
-
let addDuplicate = false;
|
|
1259
|
-
const currentTags = formData || [];
|
|
1260
|
-
if ((values == null ? void 0 : values.length) && currentTags.length < values.length) {
|
|
1261
|
-
const newTag = values[values.length - 1] = values[values.length - 1].toLocaleLowerCase("en-US").trim();
|
|
1262
|
-
hasError = !tagValidator(newTag);
|
|
1263
|
-
addDuplicate = currentTags.indexOf(newTag) !== -1;
|
|
1264
|
-
}
|
|
1265
|
-
setInputError(hasError);
|
|
1266
|
-
setInputValue(!hasError ? "" : inputValue);
|
|
1267
|
-
if (!hasError && !addDuplicate) {
|
|
1268
|
-
onChange(values || []);
|
|
1269
|
-
}
|
|
1270
|
-
};
|
|
1271
|
-
useEffectOnce(() => onChange(formData || []));
|
|
1272
|
-
return /* @__PURE__ */ React.createElement(FormControl$1, { margin: "normal" }, /* @__PURE__ */ React.createElement(
|
|
1273
|
-
Autocomplete$1,
|
|
1274
|
-
{
|
|
1275
|
-
multiple: true,
|
|
1276
|
-
freeSolo: true,
|
|
1277
|
-
filterSelectedOptions: true,
|
|
1278
|
-
onChange: setTags,
|
|
1279
|
-
value: formData || [],
|
|
1280
|
-
inputValue,
|
|
1281
|
-
loading,
|
|
1282
|
-
options: tagOptions,
|
|
1283
|
-
ChipProps: { size: "small" },
|
|
1284
|
-
renderOption: (option) => showCounts ? `${option} (${existingTags == null ? void 0 : existingTags[option]})` : option,
|
|
1285
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
1286
|
-
TextField,
|
|
1287
|
-
{
|
|
1288
|
-
...params,
|
|
1289
|
-
label: "Tags",
|
|
1290
|
-
onChange: (e) => setInputValue(e.target.value),
|
|
1291
|
-
error: inputError,
|
|
1292
|
-
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"
|
|
1293
|
-
}
|
|
1294
|
-
)
|
|
1295
|
-
}
|
|
1296
|
-
));
|
|
1297
|
-
};
|
|
1298
|
-
|
|
1299
|
-
const registerComponentRouteRef = createExternalRouteRef({
|
|
1300
|
-
id: "register-component",
|
|
1301
|
-
optional: true
|
|
1302
|
-
});
|
|
1303
|
-
const viewTechDocRouteRef = createExternalRouteRef({
|
|
1304
|
-
id: "view-techdoc",
|
|
1305
|
-
optional: true,
|
|
1306
|
-
params: ["namespace", "kind", "name"]
|
|
1307
|
-
});
|
|
1308
|
-
const rootRouteRef = createRouteRef({
|
|
1309
|
-
id: "scaffolder"
|
|
1310
|
-
});
|
|
1311
|
-
const legacySelectedTemplateRouteRef = createSubRouteRef({
|
|
1312
|
-
id: "scaffolder/legacy/selected-template",
|
|
1313
|
-
parent: rootRouteRef,
|
|
1314
|
-
path: "/templates/:templateName"
|
|
1315
|
-
});
|
|
1316
|
-
const selectedTemplateRouteRef = createSubRouteRef({
|
|
1317
|
-
id: "scaffolder/selected-template",
|
|
1318
|
-
parent: rootRouteRef,
|
|
1319
|
-
path: "/templates/:namespace/:templateName"
|
|
1320
|
-
});
|
|
1321
|
-
const scaffolderTaskRouteRef = createSubRouteRef({
|
|
1322
|
-
id: "scaffolder/task",
|
|
1323
|
-
parent: rootRouteRef,
|
|
1324
|
-
path: "/tasks/:taskId"
|
|
1325
|
-
});
|
|
1326
|
-
const scaffolderListTaskRouteRef = createSubRouteRef({
|
|
1327
|
-
id: "scaffolder/list-tasks",
|
|
1328
|
-
parent: rootRouteRef,
|
|
1329
|
-
path: "/tasks"
|
|
1330
|
-
});
|
|
1331
|
-
const actionsRouteRef = createSubRouteRef({
|
|
1332
|
-
id: "scaffolder/actions",
|
|
1333
|
-
parent: rootRouteRef,
|
|
1334
|
-
path: "/actions"
|
|
1335
|
-
});
|
|
1336
|
-
const editRouteRef = createSubRouteRef({
|
|
1337
|
-
id: "scaffolder/edit",
|
|
1338
|
-
parent: rootRouteRef,
|
|
1339
|
-
path: "/edit"
|
|
1340
|
-
});
|
|
1341
|
-
|
|
1342
|
-
const scaffolderPlugin = createPlugin({
|
|
1343
|
-
id: "scaffolder",
|
|
1344
|
-
apis: [
|
|
1345
|
-
createApiFactory({
|
|
1346
|
-
api: scaffolderApiRef,
|
|
1347
|
-
deps: {
|
|
1348
|
-
discoveryApi: discoveryApiRef,
|
|
1349
|
-
scmIntegrationsApi: scmIntegrationsApiRef,
|
|
1350
|
-
fetchApi: fetchApiRef,
|
|
1351
|
-
identityApi: identityApiRef
|
|
1352
|
-
},
|
|
1353
|
-
factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => new ScaffolderClient({
|
|
1354
|
-
discoveryApi,
|
|
1355
|
-
scmIntegrationsApi,
|
|
1356
|
-
fetchApi,
|
|
1357
|
-
identityApi
|
|
1358
|
-
})
|
|
1359
|
-
})
|
|
1360
|
-
],
|
|
1361
|
-
routes: {
|
|
1362
|
-
root: rootRouteRef,
|
|
1363
|
-
selectedTemplate: selectedTemplateRouteRef,
|
|
1364
|
-
ongoingTask: scaffolderTaskRouteRef,
|
|
1365
|
-
actions: actionsRouteRef,
|
|
1366
|
-
listTasks: scaffolderListTaskRouteRef,
|
|
1367
|
-
edit: editRouteRef
|
|
1368
|
-
},
|
|
1369
|
-
externalRoutes: {
|
|
1370
|
-
registerComponent: registerComponentRouteRef,
|
|
1371
|
-
viewTechDoc: viewTechDocRouteRef
|
|
1372
|
-
}
|
|
1373
|
-
});
|
|
1374
|
-
scaffolderPlugin.provide(
|
|
1375
|
-
createScaffolderFieldExtension({
|
|
1376
|
-
component: EntityPicker,
|
|
1377
|
-
name: "EntityPicker",
|
|
1378
|
-
schema: EntityPickerSchema
|
|
1379
|
-
})
|
|
1380
|
-
);
|
|
1381
|
-
scaffolderPlugin.provide(
|
|
1382
|
-
createScaffolderFieldExtension({
|
|
1383
|
-
component: EntityNamePicker,
|
|
1384
|
-
name: "EntityNamePicker",
|
|
1385
|
-
validation: entityNamePickerValidation,
|
|
1386
|
-
schema: EntityNamePickerSchema
|
|
1387
|
-
})
|
|
1388
|
-
);
|
|
1389
|
-
scaffolderPlugin.provide(
|
|
1390
|
-
createScaffolderFieldExtension({
|
|
1391
|
-
component: RepoUrlPicker,
|
|
1392
|
-
name: "RepoUrlPicker",
|
|
1393
|
-
validation: repoPickerValidation,
|
|
1394
|
-
schema: RepoUrlPickerSchema
|
|
1395
|
-
})
|
|
1396
|
-
);
|
|
1397
|
-
scaffolderPlugin.provide(
|
|
1398
|
-
createScaffolderFieldExtension({
|
|
1399
|
-
component: OwnerPicker,
|
|
1400
|
-
name: "OwnerPicker",
|
|
1401
|
-
schema: OwnerPickerSchema
|
|
1402
|
-
})
|
|
1403
|
-
);
|
|
1404
|
-
scaffolderPlugin.provide(
|
|
1405
|
-
createRoutableExtension({
|
|
1406
|
-
name: "ScaffolderPage",
|
|
1407
|
-
component: () => import('./Router-ea3122d2.esm.js').then((m) => m.Router),
|
|
1408
|
-
mountPoint: rootRouteRef
|
|
1409
|
-
})
|
|
1410
|
-
);
|
|
1411
|
-
scaffolderPlugin.provide(
|
|
1412
|
-
createScaffolderFieldExtension({
|
|
1413
|
-
component: OwnedEntityPicker,
|
|
1414
|
-
name: "OwnedEntityPicker",
|
|
1415
|
-
schema: OwnedEntityPickerSchema
|
|
1416
|
-
})
|
|
1417
|
-
);
|
|
1418
|
-
scaffolderPlugin.provide(
|
|
1419
|
-
createScaffolderFieldExtension({
|
|
1420
|
-
component: EntityTagsPicker,
|
|
1421
|
-
name: "EntityTagsPicker",
|
|
1422
|
-
schema: EntityTagsPickerSchema
|
|
1423
|
-
})
|
|
1424
|
-
);
|
|
1425
|
-
const NextScaffolderPage = scaffolderPlugin.provide(
|
|
1426
|
-
createRoutableExtension({
|
|
1427
|
-
name: "NextScaffolderPage",
|
|
1428
|
-
component: () => import('./index-d45f106a.esm.js').then((m) => m.Router),
|
|
1429
|
-
mountPoint: rootRouteRef
|
|
1430
|
-
})
|
|
1431
|
-
);
|
|
1432
|
-
|
|
1433
|
-
const useStyles$h = makeStyles((theme) => ({
|
|
1434
|
-
button: {
|
|
1435
|
-
color: theme.palette.common.white
|
|
1436
|
-
}
|
|
1437
|
-
}));
|
|
1438
|
-
const ContextMenu = (props) => {
|
|
1439
|
-
const { cancelEnabled, logsVisible, onStartOver, onToggleLogs, taskId } = props;
|
|
1440
|
-
const classes = useStyles$h();
|
|
1441
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
1442
|
-
const [anchorEl, setAnchorEl] = useState();
|
|
1443
|
-
const [{ status: cancelStatus }, { execute: cancel }] = useAsync$1(async () => {
|
|
1444
|
-
if (taskId) {
|
|
1445
|
-
await scaffolderApi.cancelTask(taskId);
|
|
1446
|
-
}
|
|
1447
|
-
});
|
|
1448
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
1449
|
-
IconButton,
|
|
1450
|
-
{
|
|
1451
|
-
"aria-label": "more",
|
|
1452
|
-
"aria-controls": "long-menu",
|
|
1453
|
-
"aria-haspopup": "true",
|
|
1454
|
-
onClick: (event) => {
|
|
1455
|
-
setAnchorEl(event.currentTarget);
|
|
1456
|
-
},
|
|
1457
|
-
"data-testid": "menu-button",
|
|
1458
|
-
color: "inherit",
|
|
1459
|
-
className: classes.button
|
|
1460
|
-
},
|
|
1461
|
-
/* @__PURE__ */ React.createElement(MoreVert, null)
|
|
1462
|
-
), /* @__PURE__ */ React.createElement(
|
|
1463
|
-
Popover,
|
|
1464
|
-
{
|
|
1465
|
-
open: Boolean(anchorEl),
|
|
1466
|
-
onClose: () => setAnchorEl(void 0),
|
|
1467
|
-
anchorEl,
|
|
1468
|
-
anchorOrigin: { vertical: "bottom", horizontal: "right" },
|
|
1469
|
-
transformOrigin: { vertical: "top", horizontal: "right" }
|
|
1470
|
-
},
|
|
1471
|
-
/* @__PURE__ */ React.createElement(MenuList, null, /* @__PURE__ */ React.createElement(MenuItem, { onClick: () => onToggleLogs == null ? void 0 : onToggleLogs(!logsVisible) }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Toc, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: logsVisible ? "Hide Logs" : "Show Logs" })), /* @__PURE__ */ React.createElement(MenuItem, { onClick: onStartOver }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Retry, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Start Over" })), /* @__PURE__ */ React.createElement(
|
|
1472
|
-
MenuItem,
|
|
1473
|
-
{
|
|
1474
|
-
onClick: cancel,
|
|
1475
|
-
disabled: !cancelEnabled || cancelStatus !== "not-executed",
|
|
1476
|
-
"data-testid": "cancel-task"
|
|
1477
|
-
},
|
|
1478
|
-
/* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Cancel, { fontSize: "small" })),
|
|
1479
|
-
/* @__PURE__ */ React.createElement(ListItemText, { primary: "Cancel" })
|
|
1480
|
-
))
|
|
1481
|
-
));
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
const useStyles$g = makeStyles({
|
|
1485
|
-
contentWrapper: {
|
|
1486
|
-
display: "flex",
|
|
1487
|
-
flexDirection: "column"
|
|
1488
|
-
}
|
|
1489
|
-
});
|
|
1490
|
-
const OngoingTask = (props) => {
|
|
1491
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1492
|
-
const { taskId } = useParams();
|
|
1493
|
-
const templateRouteRef = useRouteRef(selectedTemplateRouteRef);
|
|
1494
|
-
const navigate = useNavigate();
|
|
1495
|
-
const taskStream = useTaskEventStream(taskId);
|
|
1496
|
-
const classes = useStyles$g();
|
|
1497
|
-
const steps = useMemo(
|
|
1498
|
-
() => {
|
|
1499
|
-
var _a2, _b2;
|
|
1500
|
-
return (_b2 = (_a2 = taskStream.task) == null ? void 0 : _a2.spec.steps.map((step) => {
|
|
1501
|
-
var _a3;
|
|
1502
|
-
return {
|
|
1503
|
-
...step,
|
|
1504
|
-
...(_a3 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a3[step.id]
|
|
1505
|
-
};
|
|
1506
|
-
})) != null ? _b2 : [];
|
|
1507
|
-
},
|
|
1508
|
-
[taskStream]
|
|
1509
|
-
);
|
|
1510
|
-
const [logsVisible, setLogVisibleState] = useState(false);
|
|
1511
|
-
useEffect(() => {
|
|
1512
|
-
if (taskStream.error) {
|
|
1513
|
-
setLogVisibleState(true);
|
|
1514
|
-
}
|
|
1515
|
-
}, [taskStream.error]);
|
|
1516
|
-
const activeStep = useMemo(() => {
|
|
1517
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1518
|
-
if (steps[i].status !== "open") {
|
|
1519
|
-
return i;
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
return 0;
|
|
1523
|
-
}, [steps]);
|
|
1524
|
-
const startOver = useCallback(() => {
|
|
1525
|
-
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
1526
|
-
const { namespace, name } = (_d2 = (_c2 = (_b2 = (_a2 = taskStream.task) == null ? void 0 : _a2.spec.templateInfo) == null ? void 0 : _b2.entity) == null ? void 0 : _c2.metadata) != null ? _d2 : {};
|
|
1527
|
-
const formData = (_f2 = (_e2 = taskStream.task) == null ? void 0 : _e2.spec.parameters) != null ? _f2 : {};
|
|
1528
|
-
if (!namespace || !name) {
|
|
1529
|
-
return;
|
|
1530
|
-
}
|
|
1531
|
-
navigate({
|
|
1532
|
-
pathname: templateRouteRef({
|
|
1533
|
-
namespace,
|
|
1534
|
-
templateName: name
|
|
1535
|
-
}),
|
|
1536
|
-
search: `?${qs.stringify({ formData: JSON.stringify(formData) })}`
|
|
1537
|
-
});
|
|
1538
|
-
}, [
|
|
1539
|
-
navigate,
|
|
1540
|
-
(_a = taskStream.task) == null ? void 0 : _a.spec.parameters,
|
|
1541
|
-
(_d = (_c = (_b = taskStream.task) == null ? void 0 : _b.spec.templateInfo) == null ? void 0 : _c.entity) == null ? void 0 : _d.metadata,
|
|
1542
|
-
templateRouteRef
|
|
1543
|
-
]);
|
|
1544
|
-
const Outputs = (_e = props.TemplateOutputsComponent) != null ? _e : DefaultTemplateOutputs;
|
|
1545
|
-
const templateName = (_h = (_g = (_f = taskStream.task) == null ? void 0 : _f.spec.templateInfo) == null ? void 0 : _g.entity) == null ? void 0 : _h.metadata.name;
|
|
1546
|
-
const cancelEnabled = !(taskStream.cancelled || taskStream.completed);
|
|
1547
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "website" }, /* @__PURE__ */ React.createElement(
|
|
1548
|
-
Header,
|
|
1549
|
-
{
|
|
1550
|
-
pageTitleOverride: `Run of ${templateName}`,
|
|
1551
|
-
title: /* @__PURE__ */ React.createElement("div", null, "Run of ", /* @__PURE__ */ React.createElement("code", null, templateName)),
|
|
1552
|
-
subtitle: `Task ${taskId}`
|
|
1553
|
-
},
|
|
1554
|
-
/* @__PURE__ */ React.createElement(
|
|
1555
|
-
ContextMenu,
|
|
1556
|
-
{
|
|
1557
|
-
cancelEnabled,
|
|
1558
|
-
logsVisible,
|
|
1559
|
-
onStartOver: startOver,
|
|
1560
|
-
onToggleLogs: setLogVisibleState,
|
|
1561
|
-
taskId
|
|
1562
|
-
}
|
|
1563
|
-
)
|
|
1564
|
-
), /* @__PURE__ */ React.createElement(Content, { className: classes.contentWrapper }, taskStream.error ? /* @__PURE__ */ React.createElement(Box, { paddingBottom: 2 }, /* @__PURE__ */ React.createElement(
|
|
1565
|
-
ErrorPanel,
|
|
1566
|
-
{
|
|
1567
|
-
error: taskStream.error,
|
|
1568
|
-
title: taskStream.error.message
|
|
1569
|
-
}
|
|
1570
|
-
)) : null, /* @__PURE__ */ React.createElement(Box, { paddingBottom: 2 }, /* @__PURE__ */ React.createElement(
|
|
1571
|
-
TaskSteps,
|
|
1572
|
-
{
|
|
1573
|
-
steps,
|
|
1574
|
-
activeStep,
|
|
1575
|
-
isComplete: taskStream.completed,
|
|
1576
|
-
isError: Boolean(taskStream.error)
|
|
1577
|
-
}
|
|
1578
|
-
)), /* @__PURE__ */ React.createElement(Outputs, { output: taskStream.output }), logsVisible ? /* @__PURE__ */ React.createElement(Box, { paddingBottom: 2, height: "100%" }, /* @__PURE__ */ React.createElement(Paper, { style: { height: "100%" } }, /* @__PURE__ */ React.createElement(Box, { padding: 2, height: "100%" }, /* @__PURE__ */ React.createElement(TaskLogStream, { logs: taskStream.stepLogs })))) : null));
|
|
1579
|
-
};
|
|
1580
|
-
|
|
1581
|
-
const useStyles$f = makeStyles((theme) => ({
|
|
1582
|
-
code: {
|
|
1583
|
-
fontFamily: "Menlo, monospace",
|
|
1584
|
-
padding: theme.spacing(1),
|
|
1585
|
-
backgroundColor: theme.palette.type === "dark" ? theme.palette.grey[700] : theme.palette.grey[300],
|
|
1586
|
-
display: "inline-block",
|
|
1587
|
-
borderRadius: 5,
|
|
1588
|
-
border: `1px solid ${theme.palette.grey[500]}`,
|
|
1589
|
-
position: "relative"
|
|
1590
|
-
},
|
|
1591
|
-
codeRequired: {
|
|
1592
|
-
"&::after": {
|
|
1593
|
-
position: "absolute",
|
|
1594
|
-
content: '"*"',
|
|
1595
|
-
top: 0,
|
|
1596
|
-
right: theme.spacing(0.5),
|
|
1597
|
-
fontWeight: "bolder",
|
|
1598
|
-
color: theme.palette.error.light
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
}));
|
|
1602
|
-
const ExamplesTable = (props) => {
|
|
1603
|
-
return /* @__PURE__ */ React.createElement(Grid, { container: true }, props.examples.map((example, index) => {
|
|
1604
|
-
return /* @__PURE__ */ React.createElement(Fragment, { key: `example-${index}` }, /* @__PURE__ */ React.createElement(Grid, { item: true, lg: 3 }, /* @__PURE__ */ React.createElement(Box, { padding: 4 }, /* @__PURE__ */ React.createElement(Typography, null, example.description))), /* @__PURE__ */ React.createElement(Grid, { item: true, lg: 9 }, /* @__PURE__ */ React.createElement(Box, { padding: 1 }, /* @__PURE__ */ React.createElement(
|
|
1605
|
-
CodeSnippet,
|
|
1606
|
-
{
|
|
1607
|
-
text: example.example,
|
|
1608
|
-
showLineNumbers: true,
|
|
1609
|
-
showCopyCodeButton: true,
|
|
1610
|
-
language: "yaml"
|
|
1611
|
-
}
|
|
1612
|
-
))));
|
|
1613
|
-
}));
|
|
1614
|
-
};
|
|
1615
|
-
const ActionsPage = () => {
|
|
1616
|
-
const api = useApi(scaffolderApiRef);
|
|
1617
|
-
const classes = useStyles$f();
|
|
1618
|
-
const { loading, value, error } = useAsync(async () => {
|
|
1619
|
-
return api.listActions();
|
|
1620
|
-
});
|
|
1621
|
-
if (loading) {
|
|
1622
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
1623
|
-
}
|
|
1624
|
-
if (error) {
|
|
1625
|
-
return /* @__PURE__ */ React.createElement(
|
|
1626
|
-
ErrorPage,
|
|
1627
|
-
{
|
|
1628
|
-
statusMessage: "Failed to load installed actions",
|
|
1629
|
-
status: "500"
|
|
1630
|
-
}
|
|
1631
|
-
);
|
|
1632
|
-
}
|
|
1633
|
-
const formatRows = (input) => {
|
|
1634
|
-
const properties = input.properties;
|
|
1635
|
-
if (!properties) {
|
|
1636
|
-
return void 0;
|
|
1637
|
-
}
|
|
1638
|
-
return Object.entries(properties).map((entry) => {
|
|
1639
|
-
var _a;
|
|
1640
|
-
const [key] = entry;
|
|
1641
|
-
const props = entry[1];
|
|
1642
|
-
const codeClassname = classNames(classes.code, {
|
|
1643
|
-
[classes.codeRequired]: (_a = input.required) == null ? void 0 : _a.includes(key)
|
|
1644
|
-
});
|
|
1645
|
-
return /* @__PURE__ */ React.createElement(TableRow, { key }, /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement("div", { className: codeClassname }, key)), /* @__PURE__ */ React.createElement(TableCell, null, props.title), /* @__PURE__ */ React.createElement(TableCell, null, props.description), /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement(React.Fragment, null, [props.type].flat().map((type) => /* @__PURE__ */ React.createElement(Chip, { label: type, key: type })))));
|
|
1646
|
-
});
|
|
1647
|
-
};
|
|
1648
|
-
const renderTable = (input) => {
|
|
1649
|
-
if (!input.properties) {
|
|
1650
|
-
return void 0;
|
|
1651
|
-
}
|
|
1652
|
-
return /* @__PURE__ */ React.createElement(TableContainer, { component: Paper }, /* @__PURE__ */ React.createElement(Table, { size: "small" }, /* @__PURE__ */ React.createElement(TableHead, null, /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, null, "Name"), /* @__PURE__ */ React.createElement(TableCell, null, "Title"), /* @__PURE__ */ React.createElement(TableCell, null, "Description"), /* @__PURE__ */ React.createElement(TableCell, null, "Type"))), /* @__PURE__ */ React.createElement(TableBody, null, formatRows(input))));
|
|
1653
|
-
};
|
|
1654
|
-
const renderTables = (name, input) => {
|
|
1655
|
-
if (!input) {
|
|
1656
|
-
return void 0;
|
|
1657
|
-
}
|
|
1658
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, name), input.map((i, index) => /* @__PURE__ */ React.createElement("div", { key: index }, renderTable(i))));
|
|
1659
|
-
};
|
|
1660
|
-
const items = value == null ? void 0 : value.map((action) => {
|
|
1661
|
-
var _a, _b, _c, _d;
|
|
1662
|
-
if (action.id.startsWith("legacy:")) {
|
|
1663
|
-
return void 0;
|
|
1664
|
-
}
|
|
1665
|
-
const oneOf = renderTables("oneOf", (_b = (_a = action.schema) == null ? void 0 : _a.input) == null ? void 0 : _b.oneOf);
|
|
1666
|
-
return /* @__PURE__ */ React.createElement(Box, { pb: 4, key: action.id }, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", className: classes.code }, action.id), action.description && /* @__PURE__ */ React.createElement(MarkdownContent, { content: action.description }), ((_c = action.schema) == null ? void 0 : _c.input) && /* @__PURE__ */ React.createElement(Box, { pb: 2 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Input"), renderTable(action.schema.input), oneOf), ((_d = action.schema) == null ? void 0 : _d.output) && /* @__PURE__ */ React.createElement(Box, { pb: 2 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Output"), renderTable(action.schema.output)), action.examples && /* @__PURE__ */ React.createElement(Accordion, null, /* @__PURE__ */ React.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null) }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Examples")), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(Box, { pb: 2 }, /* @__PURE__ */ React.createElement(ExamplesTable, { examples: action.examples })))));
|
|
1667
|
-
});
|
|
1668
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
1669
|
-
Header,
|
|
1670
|
-
{
|
|
1671
|
-
pageTitleOverride: "Create a New Component",
|
|
1672
|
-
title: "Installed actions",
|
|
1673
|
-
subtitle: "This is the collection of all installed actions"
|
|
1674
|
-
}
|
|
1675
|
-
), /* @__PURE__ */ React.createElement(Content, null, items));
|
|
1676
|
-
};
|
|
1677
|
-
|
|
1678
|
-
const useStyles$e = makeStyles(
|
|
1679
|
-
(theme) => ({
|
|
1680
|
-
root: {
|
|
1681
|
-
backgroundColor: "rgba(0, 0, 0, .11)",
|
|
1682
|
-
boxShadow: "none",
|
|
1683
|
-
margin: theme.spacing(1, 0, 1, 0)
|
|
1684
|
-
},
|
|
1685
|
-
title: {
|
|
1686
|
-
margin: theme.spacing(1, 0, 0, 1),
|
|
1687
|
-
textTransform: "uppercase",
|
|
1688
|
-
fontSize: 12,
|
|
1689
|
-
fontWeight: "bold"
|
|
1690
|
-
},
|
|
1691
|
-
listIcon: {
|
|
1692
|
-
minWidth: 30,
|
|
1693
|
-
color: theme.palette.text.primary
|
|
1694
|
-
},
|
|
1695
|
-
menuItem: {
|
|
1696
|
-
minHeight: theme.spacing(6)
|
|
1697
|
-
},
|
|
1698
|
-
groupWrapper: {
|
|
1699
|
-
margin: theme.spacing(1, 1, 2, 1)
|
|
1700
|
-
}
|
|
1701
|
-
}),
|
|
1702
|
-
{
|
|
1703
|
-
name: "ScaffolderReactOwnerListPicker"
|
|
1704
|
-
}
|
|
1705
|
-
);
|
|
1706
|
-
function getFilterGroups() {
|
|
1707
|
-
return [
|
|
1708
|
-
{
|
|
1709
|
-
name: "Task Owner",
|
|
1710
|
-
items: [
|
|
1711
|
-
{
|
|
1712
|
-
id: "owned",
|
|
1713
|
-
label: "Owned",
|
|
1714
|
-
icon: SettingsIcon
|
|
1715
|
-
},
|
|
1716
|
-
{
|
|
1717
|
-
id: "all",
|
|
1718
|
-
label: "All",
|
|
1719
|
-
icon: AllIcon
|
|
1720
|
-
}
|
|
1721
|
-
]
|
|
1722
|
-
}
|
|
1723
|
-
];
|
|
1724
|
-
}
|
|
1725
|
-
const OwnerListPicker = (props) => {
|
|
1726
|
-
const { filter, onSelectOwner } = props;
|
|
1727
|
-
const classes = useStyles$e();
|
|
1728
|
-
const filterGroups = getFilterGroups();
|
|
1729
|
-
return /* @__PURE__ */ React.createElement(Card, { className: classes.root }, filterGroups.map((group) => /* @__PURE__ */ React.createElement(Fragment, { key: group.name }, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2", className: classes.title }, group.name), /* @__PURE__ */ React.createElement(Card, { className: classes.groupWrapper }, /* @__PURE__ */ React.createElement(List, { disablePadding: true, dense: true }, group.items.map((item) => /* @__PURE__ */ React.createElement(
|
|
1730
|
-
MenuItem,
|
|
1731
|
-
{
|
|
1732
|
-
key: item.id,
|
|
1733
|
-
button: true,
|
|
1734
|
-
divider: true,
|
|
1735
|
-
onClick: () => onSelectOwner(item.id),
|
|
1736
|
-
selected: item.id === filter,
|
|
1737
|
-
className: classes.menuItem,
|
|
1738
|
-
"data-testid": `owner-picker-${item.id}`
|
|
1739
|
-
},
|
|
1740
|
-
item.icon && /* @__PURE__ */ React.createElement(ListItemIcon, { className: classes.listIcon }, /* @__PURE__ */ React.createElement(item.icon, { fontSize: "small" })),
|
|
1741
|
-
/* @__PURE__ */ React.createElement(ListItemText, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, item.label))
|
|
1742
|
-
)))))));
|
|
1743
|
-
};
|
|
1744
|
-
|
|
1745
|
-
const showDirectoryPicker = window.showDirectoryPicker;
|
|
1746
|
-
class WebFileAccess {
|
|
1747
|
-
constructor(path, handle) {
|
|
1748
|
-
this.path = path;
|
|
1749
|
-
this.handle = handle;
|
|
1750
|
-
}
|
|
1751
|
-
file() {
|
|
1752
|
-
return this.handle.getFile();
|
|
1753
|
-
}
|
|
1754
|
-
async save(data) {
|
|
1755
|
-
const writable = await this.handle.createWritable();
|
|
1756
|
-
await writable.write(data);
|
|
1757
|
-
await writable.close();
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
class WebDirectoryAccess {
|
|
1761
|
-
constructor(handle) {
|
|
1762
|
-
this.handle = handle;
|
|
1763
|
-
}
|
|
1764
|
-
async listFiles() {
|
|
1765
|
-
const content = [];
|
|
1766
|
-
for await (const entry of this.listDirectoryContents(this.handle)) {
|
|
1767
|
-
content.push(entry);
|
|
1768
|
-
}
|
|
1769
|
-
return content;
|
|
1770
|
-
}
|
|
1771
|
-
async *listDirectoryContents(dirHandle, basePath = []) {
|
|
1772
|
-
for await (const handle of dirHandle.values()) {
|
|
1773
|
-
if (handle.kind === "file") {
|
|
1774
|
-
yield new WebFileAccess([...basePath, handle.name].join("/"), handle);
|
|
1775
|
-
} else if (handle.kind === "directory") {
|
|
1776
|
-
if (handle.name === ".git") {
|
|
1777
|
-
continue;
|
|
1778
|
-
}
|
|
1779
|
-
yield* this.listDirectoryContents(handle, [...basePath, handle.name]);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
class WebFileSystemAccess {
|
|
1785
|
-
static isSupported() {
|
|
1786
|
-
return Boolean(showDirectoryPicker);
|
|
1787
|
-
}
|
|
1788
|
-
static async requestDirectoryAccess() {
|
|
1789
|
-
if (!showDirectoryPicker) {
|
|
1790
|
-
throw new Error("File system access is not supported");
|
|
1791
|
-
}
|
|
1792
|
-
const handle = await showDirectoryPicker();
|
|
1793
|
-
return new WebDirectoryAccess(handle);
|
|
1794
|
-
}
|
|
1795
|
-
constructor() {
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
|
-
const MAX_CONTENT_SIZE = 64 * 1024;
|
|
1800
|
-
const CHUNK_SIZE = 32 * 1024;
|
|
1801
|
-
const DryRunContext = createContext(void 0);
|
|
1802
|
-
function base64EncodeContent(content) {
|
|
1803
|
-
if (content.length > MAX_CONTENT_SIZE) {
|
|
1804
|
-
return window.btoa("<file too large>");
|
|
1805
|
-
}
|
|
1806
|
-
try {
|
|
1807
|
-
return window.btoa(content);
|
|
1808
|
-
} catch {
|
|
1809
|
-
const decoder = new TextEncoder();
|
|
1810
|
-
const buffer = decoder.encode(content);
|
|
1811
|
-
const chunks = new Array();
|
|
1812
|
-
for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
|
|
1813
|
-
chunks.push(
|
|
1814
|
-
String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE))
|
|
1815
|
-
);
|
|
1816
|
-
}
|
|
1817
|
-
return window.btoa(chunks.join(""));
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
function DryRunProvider(props) {
|
|
1821
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
1822
|
-
const [state, setState] = useState({
|
|
1823
|
-
results: [],
|
|
1824
|
-
selectedResult: void 0
|
|
1825
|
-
});
|
|
1826
|
-
const idRef = useRef(1);
|
|
1827
|
-
const selectResult = useCallback((id) => {
|
|
1828
|
-
setState((prevState) => {
|
|
1829
|
-
const result = prevState.results.find((r) => r.id === id);
|
|
1830
|
-
if (result === prevState.selectedResult) {
|
|
1831
|
-
return prevState;
|
|
1832
|
-
}
|
|
1833
|
-
return {
|
|
1834
|
-
results: prevState.results,
|
|
1835
|
-
selectedResult: result
|
|
1836
|
-
};
|
|
1837
|
-
});
|
|
1838
|
-
}, []);
|
|
1839
|
-
const deleteResult = useCallback((id) => {
|
|
1840
|
-
setState((prevState) => {
|
|
1841
|
-
var _a;
|
|
1842
|
-
const index = prevState.results.findIndex((r) => r.id === id);
|
|
1843
|
-
if (index === -1) {
|
|
1844
|
-
return prevState;
|
|
1845
|
-
}
|
|
1846
|
-
const newResults = prevState.results.slice();
|
|
1847
|
-
const [deleted] = newResults.splice(index, 1);
|
|
1848
|
-
return {
|
|
1849
|
-
results: newResults,
|
|
1850
|
-
selectedResult: ((_a = prevState.selectedResult) == null ? void 0 : _a.id) === deleted.id ? newResults[0] : prevState.selectedResult
|
|
1851
|
-
};
|
|
1852
|
-
});
|
|
1853
|
-
}, []);
|
|
1854
|
-
const execute = useCallback(
|
|
1855
|
-
async (options) => {
|
|
1856
|
-
if (!scaffolderApi.dryRun) {
|
|
1857
|
-
throw new Error("Scaffolder API does not support dry-run");
|
|
1858
|
-
}
|
|
1859
|
-
const parsed = yaml.parse(options.templateContent);
|
|
1860
|
-
const response = await scaffolderApi.dryRun({
|
|
1861
|
-
template: parsed,
|
|
1862
|
-
values: options.values,
|
|
1863
|
-
secrets: {},
|
|
1864
|
-
directoryContents: options.files.map((file) => ({
|
|
1865
|
-
path: file.path,
|
|
1866
|
-
base64Content: base64EncodeContent(file.content)
|
|
1867
|
-
}))
|
|
1868
|
-
});
|
|
1869
|
-
const result = {
|
|
1870
|
-
...response,
|
|
1871
|
-
id: idRef.current++
|
|
1872
|
-
};
|
|
1873
|
-
setState((prevState) => {
|
|
1874
|
-
var _a;
|
|
1875
|
-
return {
|
|
1876
|
-
results: [...prevState.results, result],
|
|
1877
|
-
selectedResult: (_a = prevState.selectedResult) != null ? _a : result
|
|
1878
|
-
};
|
|
1879
|
-
});
|
|
1880
|
-
},
|
|
1881
|
-
[scaffolderApi]
|
|
1882
|
-
);
|
|
1883
|
-
const dryRun = useMemo(
|
|
1884
|
-
() => ({
|
|
1885
|
-
...state,
|
|
1886
|
-
selectResult,
|
|
1887
|
-
deleteResult,
|
|
1888
|
-
execute
|
|
1889
|
-
}),
|
|
1890
|
-
[state, selectResult, deleteResult, execute]
|
|
1891
|
-
);
|
|
1892
|
-
return /* @__PURE__ */ React.createElement(DryRunContext.Provider, { value: dryRun }, props.children);
|
|
1893
|
-
}
|
|
1894
|
-
function useDryRun() {
|
|
1895
|
-
const value = useContext(DryRunContext);
|
|
1896
|
-
if (!value) {
|
|
1897
|
-
throw new Error("must be used within a DryRunProvider");
|
|
1898
|
-
}
|
|
1899
|
-
return value;
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
var __accessCheck = (obj, member, msg) => {
|
|
1903
|
-
if (!member.has(obj))
|
|
1904
|
-
throw TypeError("Cannot " + msg);
|
|
1905
|
-
};
|
|
1906
|
-
var __privateGet = (obj, member, getter) => {
|
|
1907
|
-
__accessCheck(obj, member, "read from private field");
|
|
1908
|
-
return getter ? getter.call(obj) : member.get(obj);
|
|
1909
|
-
};
|
|
1910
|
-
var __privateAdd = (obj, member, value) => {
|
|
1911
|
-
if (member.has(obj))
|
|
1912
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
1913
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
1914
|
-
};
|
|
1915
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
1916
|
-
__accessCheck(obj, member, "write to private field");
|
|
1917
|
-
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
1918
|
-
return value;
|
|
1919
|
-
};
|
|
1920
|
-
var _access, _signalUpdate, _content, _savedContent, _access2, _listeners, _files, _selectedFile, _signalUpdate2;
|
|
1921
|
-
const MAX_SIZE = 1024 * 1024;
|
|
1922
|
-
const MAX_SIZE_MESSAGE = "This file is too large to be displayed";
|
|
1923
|
-
class DirectoryEditorFileManager {
|
|
1924
|
-
constructor(access, signalUpdate) {
|
|
1925
|
-
__privateAdd(this, _access, void 0);
|
|
1926
|
-
__privateAdd(this, _signalUpdate, void 0);
|
|
1927
|
-
__privateAdd(this, _content, void 0);
|
|
1928
|
-
__privateAdd(this, _savedContent, void 0);
|
|
1929
|
-
__privateSet(this, _access, access);
|
|
1930
|
-
__privateSet(this, _signalUpdate, signalUpdate);
|
|
1931
|
-
}
|
|
1932
|
-
get path() {
|
|
1933
|
-
return __privateGet(this, _access).path;
|
|
1934
|
-
}
|
|
1935
|
-
get content() {
|
|
1936
|
-
var _a;
|
|
1937
|
-
return (_a = __privateGet(this, _content)) != null ? _a : MAX_SIZE_MESSAGE;
|
|
1938
|
-
}
|
|
1939
|
-
updateContent(content) {
|
|
1940
|
-
if (__privateGet(this, _content) === void 0) {
|
|
1941
|
-
return;
|
|
1942
|
-
}
|
|
1943
|
-
__privateSet(this, _content, content);
|
|
1944
|
-
__privateGet(this, _signalUpdate).call(this);
|
|
1945
|
-
}
|
|
1946
|
-
get dirty() {
|
|
1947
|
-
return __privateGet(this, _content) !== __privateGet(this, _savedContent);
|
|
1948
|
-
}
|
|
1949
|
-
async save() {
|
|
1950
|
-
if (__privateGet(this, _content) !== void 0) {
|
|
1951
|
-
await __privateGet(this, _access).save(__privateGet(this, _content));
|
|
1952
|
-
__privateSet(this, _savedContent, __privateGet(this, _content));
|
|
1953
|
-
__privateGet(this, _signalUpdate).call(this);
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
async reload() {
|
|
1957
|
-
const file = await __privateGet(this, _access).file();
|
|
1958
|
-
if (file.size > MAX_SIZE) {
|
|
1959
|
-
if (__privateGet(this, _content) !== void 0) {
|
|
1960
|
-
__privateSet(this, _content, void 0);
|
|
1961
|
-
__privateSet(this, _savedContent, void 0);
|
|
1962
|
-
__privateGet(this, _signalUpdate).call(this);
|
|
1963
|
-
}
|
|
1964
|
-
return;
|
|
1965
|
-
}
|
|
1966
|
-
const content = await file.text();
|
|
1967
|
-
if (__privateGet(this, _content) !== content) {
|
|
1968
|
-
__privateSet(this, _content, content);
|
|
1969
|
-
__privateSet(this, _savedContent, content);
|
|
1970
|
-
__privateGet(this, _signalUpdate).call(this);
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
_access = new WeakMap();
|
|
1975
|
-
_signalUpdate = new WeakMap();
|
|
1976
|
-
_content = new WeakMap();
|
|
1977
|
-
_savedContent = new WeakMap();
|
|
1978
|
-
class DirectoryEditorManager {
|
|
1979
|
-
constructor(access) {
|
|
1980
|
-
__privateAdd(this, _access2, void 0);
|
|
1981
|
-
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
1982
|
-
__privateAdd(this, _files, []);
|
|
1983
|
-
__privateAdd(this, _selectedFile, void 0);
|
|
1984
|
-
this.setSelectedFile = (path) => {
|
|
1985
|
-
const prev = __privateGet(this, _selectedFile);
|
|
1986
|
-
const next = __privateGet(this, _files).find((file) => file.path === path);
|
|
1987
|
-
if (prev !== next) {
|
|
1988
|
-
__privateSet(this, _selectedFile, next);
|
|
1989
|
-
__privateGet(this, _signalUpdate2).call(this);
|
|
1990
|
-
}
|
|
1991
|
-
};
|
|
1992
|
-
__privateAdd(this, _signalUpdate2, () => {
|
|
1993
|
-
__privateGet(this, _listeners).forEach((listener) => listener());
|
|
1994
|
-
});
|
|
1995
|
-
__privateSet(this, _access2, access);
|
|
1996
|
-
}
|
|
1997
|
-
get files() {
|
|
1998
|
-
return __privateGet(this, _files);
|
|
1999
|
-
}
|
|
2000
|
-
get selectedFile() {
|
|
2001
|
-
return __privateGet(this, _selectedFile);
|
|
2002
|
-
}
|
|
2003
|
-
get dirty() {
|
|
2004
|
-
return __privateGet(this, _files).some((file) => file.dirty);
|
|
2005
|
-
}
|
|
2006
|
-
async save() {
|
|
2007
|
-
await Promise.all(__privateGet(this, _files).map((file) => file.save()));
|
|
2008
|
-
}
|
|
2009
|
-
async reload() {
|
|
2010
|
-
var _a;
|
|
2011
|
-
const selectedPath = (_a = __privateGet(this, _selectedFile)) == null ? void 0 : _a.path;
|
|
2012
|
-
const files = await __privateGet(this, _access2).listFiles();
|
|
2013
|
-
const fileManagers = await Promise.all(
|
|
2014
|
-
files.map(async (file) => {
|
|
2015
|
-
const manager = new DirectoryEditorFileManager(
|
|
2016
|
-
file,
|
|
2017
|
-
__privateGet(this, _signalUpdate2)
|
|
2018
|
-
);
|
|
2019
|
-
await manager.reload();
|
|
2020
|
-
return manager;
|
|
2021
|
-
})
|
|
2022
|
-
);
|
|
2023
|
-
__privateGet(this, _files).length = 0;
|
|
2024
|
-
__privateGet(this, _files).push(...fileManagers);
|
|
2025
|
-
this.setSelectedFile(selectedPath);
|
|
2026
|
-
__privateGet(this, _signalUpdate2).call(this);
|
|
2027
|
-
}
|
|
2028
|
-
subscribe(listener) {
|
|
2029
|
-
__privateGet(this, _listeners).add(listener);
|
|
2030
|
-
return () => {
|
|
2031
|
-
__privateGet(this, _listeners).delete(listener);
|
|
2032
|
-
};
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
_access2 = new WeakMap();
|
|
2036
|
-
_listeners = new WeakMap();
|
|
2037
|
-
_files = new WeakMap();
|
|
2038
|
-
_selectedFile = new WeakMap();
|
|
2039
|
-
_signalUpdate2 = new WeakMap();
|
|
2040
|
-
const DirectoryEditorContext = createContext(
|
|
2041
|
-
void 0
|
|
2042
|
-
);
|
|
2043
|
-
function useDirectoryEditor() {
|
|
2044
|
-
const value = useContext(DirectoryEditorContext);
|
|
2045
|
-
const rerender = useRerender();
|
|
2046
|
-
useEffect(() => value == null ? void 0 : value.subscribe(rerender), [value, rerender]);
|
|
2047
|
-
if (!value) {
|
|
2048
|
-
throw new Error("must be used within a DirectoryEditorProvider");
|
|
2049
|
-
}
|
|
2050
|
-
return value;
|
|
2051
|
-
}
|
|
2052
|
-
function DirectoryEditorProvider(props) {
|
|
2053
|
-
const { directory } = props;
|
|
2054
|
-
const [{ result, error }, { execute }] = useAsync$1(
|
|
2055
|
-
async (dir) => {
|
|
2056
|
-
const manager = new DirectoryEditorManager(dir);
|
|
2057
|
-
await manager.reload();
|
|
2058
|
-
const firstYaml = manager.files.find((file) => file.path.match(/\.ya?ml$/));
|
|
2059
|
-
if (firstYaml) {
|
|
2060
|
-
manager.setSelectedFile(firstYaml.path);
|
|
2061
|
-
}
|
|
2062
|
-
return manager;
|
|
2063
|
-
}
|
|
2064
|
-
);
|
|
2065
|
-
useEffect(() => {
|
|
2066
|
-
execute(directory);
|
|
2067
|
-
}, [execute, directory]);
|
|
2068
|
-
if (error) {
|
|
2069
|
-
return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
|
|
2070
|
-
} else if (!result) {
|
|
2071
|
-
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
2072
|
-
}
|
|
2073
|
-
return /* @__PURE__ */ React.createElement(DirectoryEditorContext.Provider, { value: result }, props.children);
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2076
|
-
const useStyles$d = makeStyles$1({
|
|
2077
|
-
containerWrapper: {
|
|
2078
|
-
position: "relative",
|
|
2079
|
-
width: "100%",
|
|
2080
|
-
height: "100%"
|
|
2081
|
-
},
|
|
2082
|
-
container: {
|
|
2083
|
-
position: "absolute",
|
|
2084
|
-
top: 0,
|
|
2085
|
-
bottom: 0,
|
|
2086
|
-
left: 0,
|
|
2087
|
-
right: 0,
|
|
2088
|
-
overflow: "auto"
|
|
2089
|
-
}
|
|
2090
|
-
});
|
|
2091
|
-
class ErrorBoundary extends Component {
|
|
2092
|
-
constructor() {
|
|
2093
|
-
super(...arguments);
|
|
2094
|
-
this.state = {
|
|
2095
|
-
shouldRender: true
|
|
2096
|
-
};
|
|
2097
|
-
}
|
|
2098
|
-
componentDidUpdate(prevProps) {
|
|
2099
|
-
if (prevProps.invalidator !== this.props.invalidator) {
|
|
2100
|
-
this.setState({ shouldRender: true });
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
componentDidCatch(error) {
|
|
2104
|
-
this.props.setErrorText(error.message);
|
|
2105
|
-
this.setState({ shouldRender: false });
|
|
2106
|
-
}
|
|
2107
|
-
render() {
|
|
2108
|
-
return this.state.shouldRender ? this.props.children : null;
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
function isJsonObject(value) {
|
|
2112
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2113
|
-
}
|
|
2114
|
-
function TemplateEditorForm(props) {
|
|
2115
|
-
const {
|
|
2116
|
-
content,
|
|
2117
|
-
contentIsSpec,
|
|
2118
|
-
onDryRun,
|
|
2119
|
-
setErrorText,
|
|
2120
|
-
fieldExtensions = [],
|
|
2121
|
-
layouts = []
|
|
2122
|
-
} = props;
|
|
2123
|
-
const classes = useStyles$d();
|
|
2124
|
-
const apiHolder = useApiHolder();
|
|
2125
|
-
const [steps, setSteps] = useState();
|
|
2126
|
-
useDebounce(
|
|
2127
|
-
() => {
|
|
2128
|
-
try {
|
|
2129
|
-
if (!content) {
|
|
2130
|
-
setSteps(void 0);
|
|
2131
|
-
return;
|
|
2132
|
-
}
|
|
2133
|
-
const parsed = yaml.parse(content);
|
|
2134
|
-
if (!isJsonObject(parsed)) {
|
|
2135
|
-
setSteps(void 0);
|
|
2136
|
-
return;
|
|
2137
|
-
}
|
|
2138
|
-
let rootObj = parsed;
|
|
2139
|
-
if (!contentIsSpec) {
|
|
2140
|
-
const isTemplate = String(parsed.kind).toLocaleLowerCase("en-US") === "template";
|
|
2141
|
-
if (!isTemplate) {
|
|
2142
|
-
setSteps(void 0);
|
|
2143
|
-
return;
|
|
2144
|
-
}
|
|
2145
|
-
rootObj = isJsonObject(parsed.spec) ? parsed.spec : {};
|
|
2146
|
-
}
|
|
2147
|
-
const { parameters } = rootObj;
|
|
2148
|
-
if (!Array.isArray(parameters)) {
|
|
2149
|
-
setErrorText("Template parameters must be an array");
|
|
2150
|
-
setSteps(void 0);
|
|
2151
|
-
return;
|
|
2152
|
-
}
|
|
2153
|
-
setErrorText();
|
|
2154
|
-
setSteps(
|
|
2155
|
-
parameters.flatMap(
|
|
2156
|
-
(param) => isJsonObject(param) ? [
|
|
2157
|
-
{
|
|
2158
|
-
title: String(param.title),
|
|
2159
|
-
schema: param
|
|
2160
|
-
}
|
|
2161
|
-
] : []
|
|
2162
|
-
)
|
|
2163
|
-
);
|
|
2164
|
-
} catch (e) {
|
|
2165
|
-
setErrorText(e.message);
|
|
2166
|
-
}
|
|
2167
|
-
},
|
|
2168
|
-
250,
|
|
2169
|
-
[contentIsSpec, content, apiHolder]
|
|
2170
|
-
);
|
|
2171
|
-
if (!steps) {
|
|
2172
|
-
return null;
|
|
2173
|
-
}
|
|
2174
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.containerWrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(ErrorBoundary, { invalidator: steps, setErrorText }, /* @__PURE__ */ React.createElement(
|
|
2175
|
-
Stepper,
|
|
2176
|
-
{
|
|
2177
|
-
manifest: { steps, title: "Template Editor" },
|
|
2178
|
-
extensions: fieldExtensions,
|
|
2179
|
-
onCreate: async (data) => {
|
|
2180
|
-
await (onDryRun == null ? void 0 : onDryRun(data));
|
|
2181
|
-
},
|
|
2182
|
-
layouts,
|
|
2183
|
-
components: { createButtonText: onDryRun && "Try It" }
|
|
2184
|
-
}
|
|
2185
|
-
))));
|
|
2186
|
-
}
|
|
2187
|
-
function TemplateEditorFormDirectoryEditorDryRun(props) {
|
|
2188
|
-
const { setErrorText, fieldExtensions = [], layouts } = props;
|
|
2189
|
-
const dryRun = useDryRun();
|
|
2190
|
-
const directoryEditor = useDirectoryEditor();
|
|
2191
|
-
const { selectedFile } = directoryEditor;
|
|
2192
|
-
const handleDryRun = async (values) => {
|
|
2193
|
-
if (!selectedFile) {
|
|
2194
|
-
return;
|
|
2195
|
-
}
|
|
2196
|
-
try {
|
|
2197
|
-
await dryRun.execute({
|
|
2198
|
-
templateContent: selectedFile.content,
|
|
2199
|
-
values,
|
|
2200
|
-
files: directoryEditor.files
|
|
2201
|
-
});
|
|
2202
|
-
setErrorText();
|
|
2203
|
-
} catch (e) {
|
|
2204
|
-
setErrorText(String(e.cause || e));
|
|
2205
|
-
throw e;
|
|
2206
|
-
}
|
|
2207
|
-
};
|
|
2208
|
-
const content = selectedFile && selectedFile.path.match(/\.ya?ml$/) ? selectedFile.content : void 0;
|
|
2209
|
-
return /* @__PURE__ */ React.createElement(
|
|
2210
|
-
TemplateEditorForm,
|
|
2211
|
-
{
|
|
2212
|
-
onDryRun: handleDryRun,
|
|
2213
|
-
fieldExtensions,
|
|
2214
|
-
setErrorText,
|
|
2215
|
-
content,
|
|
2216
|
-
layouts
|
|
2217
|
-
}
|
|
2218
|
-
);
|
|
2219
|
-
}
|
|
2220
|
-
TemplateEditorForm.DirectoryEditorDryRun = TemplateEditorFormDirectoryEditorDryRun;
|
|
2221
|
-
|
|
2222
|
-
const useStyles$c = makeStyles((theme) => ({
|
|
2223
|
-
root: {
|
|
2224
|
-
gridArea: "pageContent",
|
|
2225
|
-
display: "grid",
|
|
2226
|
-
gridTemplateAreas: `
|
|
2227
|
-
"controls controls"
|
|
2228
|
-
"fieldForm preview"
|
|
2229
|
-
`,
|
|
2230
|
-
gridTemplateRows: "auto 1fr",
|
|
2231
|
-
gridTemplateColumns: "1fr 1fr"
|
|
2232
|
-
},
|
|
2233
|
-
controls: {
|
|
2234
|
-
gridArea: "controls",
|
|
2235
|
-
display: "flex",
|
|
2236
|
-
flexFlow: "row nowrap",
|
|
2237
|
-
alignItems: "center",
|
|
2238
|
-
margin: theme.spacing(1)
|
|
2239
|
-
},
|
|
2240
|
-
fieldForm: {
|
|
2241
|
-
gridArea: "fieldForm"
|
|
2242
|
-
},
|
|
2243
|
-
preview: {
|
|
2244
|
-
gridArea: "preview"
|
|
2245
|
-
}
|
|
2246
|
-
}));
|
|
2247
|
-
const CustomFieldExplorer = ({
|
|
2248
|
-
customFieldExtensions = [],
|
|
2249
|
-
onClose
|
|
2250
|
-
}) => {
|
|
2251
|
-
var _a, _b;
|
|
2252
|
-
const classes = useStyles$c();
|
|
2253
|
-
const fieldOptions = customFieldExtensions.filter((field) => !!field.schema);
|
|
2254
|
-
const [selectedField, setSelectedField] = useState(fieldOptions[0]);
|
|
2255
|
-
const [fieldFormState, setFieldFormState] = useState({});
|
|
2256
|
-
const [refreshKey, setRefreshKey] = useState(Date.now());
|
|
2257
|
-
const sampleFieldTemplate = useMemo(
|
|
2258
|
-
() => {
|
|
2259
|
-
var _a2, _b2;
|
|
2260
|
-
return yaml.stringify({
|
|
2261
|
-
parameters: [
|
|
2262
|
-
{
|
|
2263
|
-
title: `${selectedField.name} Example`,
|
|
2264
|
-
properties: {
|
|
2265
|
-
[selectedField.name]: {
|
|
2266
|
-
type: (_b2 = (_a2 = selectedField.schema) == null ? void 0 : _a2.returnValue) == null ? void 0 : _b2.type,
|
|
2267
|
-
"ui:field": selectedField.name,
|
|
2268
|
-
"ui:options": fieldFormState
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
]
|
|
2273
|
-
});
|
|
2274
|
-
},
|
|
2275
|
-
[fieldFormState, selectedField]
|
|
2276
|
-
);
|
|
2277
|
-
const fieldComponents = useMemo(() => {
|
|
2278
|
-
return Object.fromEntries(
|
|
2279
|
-
customFieldExtensions.map(({ name, component }) => [name, component])
|
|
2280
|
-
);
|
|
2281
|
-
}, [customFieldExtensions]);
|
|
2282
|
-
const handleSelectionChange = useCallback(
|
|
2283
|
-
(selection) => {
|
|
2284
|
-
setSelectedField(selection);
|
|
2285
|
-
setFieldFormState({});
|
|
2286
|
-
},
|
|
2287
|
-
[setFieldFormState, setSelectedField]
|
|
2288
|
-
);
|
|
2289
|
-
const handleFieldConfigChange = useCallback(
|
|
2290
|
-
(state) => {
|
|
2291
|
-
setFieldFormState(state);
|
|
2292
|
-
setRefreshKey(Date.now());
|
|
2293
|
-
},
|
|
2294
|
-
[setFieldFormState, setRefreshKey]
|
|
2295
|
-
);
|
|
2296
|
-
return /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classes.controls }, /* @__PURE__ */ React.createElement(FormControl$1, { variant: "outlined", size: "small", fullWidth: true }, /* @__PURE__ */ React.createElement(InputLabel$1, { id: "select-field-label" }, "Choose Custom Field Extension"), /* @__PURE__ */ React.createElement(
|
|
2297
|
-
Select$1,
|
|
2298
|
-
{
|
|
2299
|
-
value: selectedField,
|
|
2300
|
-
label: "Choose Custom Field Extension",
|
|
2301
|
-
labelId: "select-field-label",
|
|
2302
|
-
onChange: (e) => handleSelectionChange(e.target.value)
|
|
2303
|
-
},
|
|
2304
|
-
fieldOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, { key: idx, value: option }, option.name))
|
|
2305
|
-
)), /* @__PURE__ */ React.createElement(IconButton, { size: "medium", onClick: onClose }, /* @__PURE__ */ React.createElement(CloseIcon, null))), /* @__PURE__ */ React.createElement("div", { className: classes.fieldForm }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { title: "Field Options" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
|
|
2306
|
-
Form,
|
|
2307
|
-
{
|
|
2308
|
-
showErrorList: false,
|
|
2309
|
-
fields: { ...fieldComponents },
|
|
2310
|
-
noHtml5Validate: true,
|
|
2311
|
-
formData: fieldFormState,
|
|
2312
|
-
formContext: { fieldFormState },
|
|
2313
|
-
onSubmit: (e) => handleFieldConfigChange(e.formData),
|
|
2314
|
-
validator,
|
|
2315
|
-
schema: ((_a = selectedField.schema) == null ? void 0 : _a.uiOptions) || {}
|
|
2316
|
-
},
|
|
2317
|
-
/* @__PURE__ */ React.createElement(
|
|
2318
|
-
Button,
|
|
2319
|
-
{
|
|
2320
|
-
variant: "contained",
|
|
2321
|
-
color: "primary",
|
|
2322
|
-
type: "submit",
|
|
2323
|
-
disabled: !((_b = selectedField.schema) == null ? void 0 : _b.uiOptions)
|
|
2324
|
-
},
|
|
2325
|
-
"Apply"
|
|
2326
|
-
)
|
|
2327
|
-
)))), /* @__PURE__ */ React.createElement("div", { className: classes.preview }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { title: "Example Template Spec" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
|
|
2328
|
-
CodeMirror,
|
|
2329
|
-
{
|
|
2330
|
-
readOnly: true,
|
|
2331
|
-
theme: "dark",
|
|
2332
|
-
height: "100%",
|
|
2333
|
-
extensions: [StreamLanguage.define(yaml$1)],
|
|
2334
|
-
value: sampleFieldTemplate
|
|
2335
|
-
}
|
|
2336
|
-
))), /* @__PURE__ */ React.createElement(
|
|
2337
|
-
TemplateEditorForm,
|
|
2338
|
-
{
|
|
2339
|
-
key: refreshKey,
|
|
2340
|
-
content: sampleFieldTemplate,
|
|
2341
|
-
contentIsSpec: true,
|
|
2342
|
-
fieldExtensions: customFieldExtensions,
|
|
2343
|
-
setErrorText: () => null
|
|
2344
|
-
}
|
|
2345
|
-
)));
|
|
2346
|
-
};
|
|
2347
|
-
|
|
2348
|
-
const useStyles$b = makeStyles$1((theme) => ({
|
|
2349
|
-
root: {
|
|
2350
|
-
overflowY: "auto",
|
|
2351
|
-
background: theme.palette.background.default
|
|
2352
|
-
},
|
|
2353
|
-
iconSuccess: {
|
|
2354
|
-
minWidth: 0,
|
|
2355
|
-
marginRight: theme.spacing(1),
|
|
2356
|
-
color: theme.palette.status.ok
|
|
2357
|
-
},
|
|
2358
|
-
iconFailure: {
|
|
2359
|
-
minWidth: 0,
|
|
2360
|
-
marginRight: theme.spacing(1),
|
|
2361
|
-
color: theme.palette.status.error
|
|
2362
|
-
}
|
|
2363
|
-
}));
|
|
2364
|
-
function DryRunResultsList() {
|
|
2365
|
-
const classes = useStyles$b();
|
|
2366
|
-
const dryRun = useDryRun();
|
|
2367
|
-
return /* @__PURE__ */ React.createElement(List$1, { className: classes.root, dense: true }, dryRun.results.map((result) => {
|
|
2368
|
-
var _a;
|
|
2369
|
-
const failed = result.log.some((l) => l.body.status === "failed");
|
|
2370
|
-
return /* @__PURE__ */ React.createElement(
|
|
2371
|
-
ListItem,
|
|
2372
|
-
{
|
|
2373
|
-
button: true,
|
|
2374
|
-
key: result.id,
|
|
2375
|
-
selected: ((_a = dryRun.selectedResult) == null ? void 0 : _a.id) === result.id,
|
|
2376
|
-
onClick: () => dryRun.selectResult(result.id)
|
|
2377
|
-
},
|
|
2378
|
-
/* @__PURE__ */ React.createElement(
|
|
2379
|
-
ListItemIcon$1,
|
|
2380
|
-
{
|
|
2381
|
-
className: failed ? classes.iconFailure : classes.iconSuccess
|
|
2382
|
-
},
|
|
2383
|
-
failed ? /* @__PURE__ */ React.createElement(Cancel, null) : /* @__PURE__ */ React.createElement(CheckIcon, null)
|
|
2384
|
-
),
|
|
2385
|
-
/* @__PURE__ */ React.createElement(ListItemText$1, { primary: `Result ${result.id}` }),
|
|
2386
|
-
/* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(
|
|
2387
|
-
IconButton$1,
|
|
2388
|
-
{
|
|
2389
|
-
edge: "end",
|
|
2390
|
-
"aria-label": "delete",
|
|
2391
|
-
onClick: () => dryRun.deleteResult(result.id)
|
|
2392
|
-
},
|
|
2393
|
-
/* @__PURE__ */ React.createElement(DeleteIcon, null)
|
|
2394
|
-
))
|
|
2395
|
-
);
|
|
2396
|
-
}));
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2399
|
-
const TaskErrors = ({ error }) => {
|
|
2400
|
-
const id = useRef("");
|
|
2401
|
-
useEffect(() => {
|
|
2402
|
-
id.current = String(Math.random());
|
|
2403
|
-
}, [error]);
|
|
2404
|
-
return error ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
|
|
2405
|
-
DismissableBanner,
|
|
2406
|
-
{
|
|
2407
|
-
id: id.current,
|
|
2408
|
-
variant: "warning",
|
|
2409
|
-
message: error.message
|
|
2410
|
-
}
|
|
2411
|
-
)) : null;
|
|
2412
|
-
};
|
|
2413
|
-
|
|
2414
|
-
const useStyles$a = makeStyles({
|
|
2415
|
-
svgIcon: {
|
|
2416
|
-
display: "inline-block",
|
|
2417
|
-
"& svg": {
|
|
2418
|
-
display: "inline-block",
|
|
2419
|
-
fontSize: "inherit",
|
|
2420
|
-
verticalAlign: "baseline"
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
});
|
|
2424
|
-
const IconLink = (props) => {
|
|
2425
|
-
const { href, text, Icon, ...linkProps } = props;
|
|
2426
|
-
const classes = useStyles$a();
|
|
2427
|
-
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)));
|
|
2428
|
-
};
|
|
2429
|
-
|
|
2430
|
-
const TaskPageLinks = ({ output }) => {
|
|
2431
|
-
const { links = [] } = output;
|
|
2432
|
-
const app = useApp();
|
|
2433
|
-
const entityRoute = useRouteRef(entityRouteRef);
|
|
2434
|
-
const iconResolver = (key) => {
|
|
2435
|
-
var _a;
|
|
2436
|
-
return key ? (_a = app.getSystemIcon(key)) != null ? _a : LanguageIcon : LanguageIcon;
|
|
2437
|
-
};
|
|
2438
|
-
return /* @__PURE__ */ React.createElement(Box, { px: 3, pb: 3 }, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
|
|
2439
|
-
if (entityRef) {
|
|
2440
|
-
const entityName = parseEntityRef(entityRef, {
|
|
2441
|
-
defaultKind: "<unknown>",
|
|
2442
|
-
defaultNamespace: "<unknown>"
|
|
2443
|
-
});
|
|
2444
|
-
const target = entityRoute(entityName);
|
|
2445
|
-
return { title, icon, url: target };
|
|
2446
|
-
}
|
|
2447
|
-
return { title, icon, url };
|
|
2448
|
-
}).map(({ url, title, icon }, i) => /* @__PURE__ */ React.createElement(
|
|
2449
|
-
IconLink,
|
|
2450
|
-
{
|
|
2451
|
-
key: `output-link-${i}`,
|
|
2452
|
-
href: url,
|
|
2453
|
-
text: title != null ? title : url,
|
|
2454
|
-
Icon: iconResolver(icon),
|
|
2455
|
-
target: "_blank"
|
|
2456
|
-
}
|
|
2457
|
-
)));
|
|
2458
|
-
};
|
|
2459
|
-
|
|
2460
|
-
const humanizeDuration = require("humanize-duration");
|
|
2461
|
-
const useStyles$9 = makeStyles$1(
|
|
2462
|
-
(theme) => createStyles({
|
|
2463
|
-
root: {
|
|
2464
|
-
width: "100%"
|
|
2465
|
-
},
|
|
2466
|
-
button: {
|
|
2467
|
-
marginBottom: theme.spacing(2),
|
|
2468
|
-
marginLeft: theme.spacing(2)
|
|
2469
|
-
},
|
|
2470
|
-
actionsContainer: {
|
|
2471
|
-
marginBottom: theme.spacing(2)
|
|
2472
|
-
},
|
|
2473
|
-
resetContainer: {
|
|
2474
|
-
padding: theme.spacing(3)
|
|
2475
|
-
},
|
|
2476
|
-
labelWrapper: {
|
|
2477
|
-
display: "flex",
|
|
2478
|
-
flex: 1,
|
|
2479
|
-
flexDirection: "row",
|
|
2480
|
-
justifyContent: "space-between"
|
|
2481
|
-
},
|
|
2482
|
-
stepWrapper: {
|
|
2483
|
-
width: "100%"
|
|
2484
|
-
}
|
|
2485
|
-
})
|
|
2486
|
-
);
|
|
2487
|
-
const StepTimeTicker = ({ step }) => {
|
|
2488
|
-
const [time, setTime] = useState("");
|
|
2489
|
-
useInterval(() => {
|
|
2490
|
-
if (!step.startedAt) {
|
|
2491
|
-
setTime("");
|
|
2492
|
-
return;
|
|
2493
|
-
}
|
|
2494
|
-
const end = step.endedAt ? DateTime.fromISO(step.endedAt) : DateTime.local();
|
|
2495
|
-
const startedAt = DateTime.fromISO(step.startedAt);
|
|
2496
|
-
const formatted = Interval.fromDateTimes(startedAt, end).toDuration().valueOf();
|
|
2497
|
-
setTime(humanizeDuration(formatted, { round: true }));
|
|
2498
|
-
}, 1e3);
|
|
2499
|
-
return /* @__PURE__ */ React.createElement(Typography$1, { variant: "caption" }, time);
|
|
2500
|
-
};
|
|
2501
|
-
const useStepIconStyles = makeStyles$1(
|
|
2502
|
-
(theme) => createStyles({
|
|
2503
|
-
root: {
|
|
2504
|
-
color: theme.palette.text.disabled,
|
|
2505
|
-
display: "flex",
|
|
2506
|
-
height: 22,
|
|
2507
|
-
alignItems: "center"
|
|
2508
|
-
},
|
|
2509
|
-
completed: {
|
|
2510
|
-
color: theme.palette.status.ok
|
|
2511
|
-
},
|
|
2512
|
-
error: {
|
|
2513
|
-
color: theme.palette.status.error
|
|
2514
|
-
}
|
|
2515
|
-
})
|
|
2516
|
-
);
|
|
2517
|
-
function TaskStepIconComponent(props) {
|
|
2518
|
-
const classes = useStepIconStyles();
|
|
2519
|
-
const { active, completed, error } = props;
|
|
2520
|
-
const getMiddle = () => {
|
|
2521
|
-
if (active) {
|
|
2522
|
-
return /* @__PURE__ */ React.createElement(CircularProgress, { size: "24px" });
|
|
2523
|
-
}
|
|
2524
|
-
if (completed) {
|
|
2525
|
-
return /* @__PURE__ */ React.createElement(CheckIcon, null);
|
|
2526
|
-
}
|
|
2527
|
-
if (error) {
|
|
2528
|
-
return /* @__PURE__ */ React.createElement(Cancel, null);
|
|
2529
|
-
}
|
|
2530
|
-
return /* @__PURE__ */ React.createElement(FiberManualRecordIcon, null);
|
|
2531
|
-
};
|
|
2532
|
-
return /* @__PURE__ */ React.createElement(
|
|
2533
|
-
"div",
|
|
2534
|
-
{
|
|
2535
|
-
className: classNames(classes.root, {
|
|
2536
|
-
[classes.completed]: completed,
|
|
2537
|
-
[classes.error]: error
|
|
2538
|
-
})
|
|
2539
|
-
},
|
|
2540
|
-
getMiddle()
|
|
2541
|
-
);
|
|
2542
|
-
}
|
|
2543
|
-
const TaskStatusStepper = memo(
|
|
2544
|
-
(props) => {
|
|
2545
|
-
const { steps, currentStepId, onUserStepChange } = props;
|
|
2546
|
-
const classes = useStyles$9(props);
|
|
2547
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(
|
|
2548
|
-
Stepper$1,
|
|
2549
|
-
{
|
|
2550
|
-
activeStep: steps.findIndex((s) => s.id === currentStepId),
|
|
2551
|
-
orientation: "vertical",
|
|
2552
|
-
nonLinear: true
|
|
2553
|
-
},
|
|
2554
|
-
steps.map((step, index) => {
|
|
2555
|
-
const isCancelled = step.status === "cancelled";
|
|
2556
|
-
const isActive = step.status === "processing";
|
|
2557
|
-
const isCompleted = step.status === "completed";
|
|
2558
|
-
const isFailed = step.status === "failed";
|
|
2559
|
-
const isSkipped = step.status === "skipped";
|
|
2560
|
-
return /* @__PURE__ */ React.createElement(Step, { key: String(index), expanded: true }, /* @__PURE__ */ React.createElement(StepButton, { onClick: () => onUserStepChange(step.id) }, /* @__PURE__ */ React.createElement(
|
|
2561
|
-
StepLabel,
|
|
2562
|
-
{
|
|
2563
|
-
StepIconProps: {
|
|
2564
|
-
completed: isCompleted,
|
|
2565
|
-
error: isFailed || isCancelled,
|
|
2566
|
-
active: isActive
|
|
2567
|
-
},
|
|
2568
|
-
StepIconComponent: TaskStepIconComponent,
|
|
2569
|
-
className: classes.stepWrapper
|
|
2570
|
-
},
|
|
2571
|
-
/* @__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 }))
|
|
2572
|
-
)));
|
|
2573
|
-
})
|
|
2574
|
-
));
|
|
2575
|
-
}
|
|
2576
|
-
);
|
|
2577
|
-
const hasLinks = ({ links = [] }) => links.length > 0;
|
|
2578
|
-
const TaskPage = (props) => {
|
|
2579
|
-
const { loadingText } = props;
|
|
2580
|
-
const classes = useStyles$9();
|
|
2581
|
-
const navigate = useNavigate();
|
|
2582
|
-
const rootPath = useRouteRef(rootRouteRef);
|
|
2583
|
-
const scaffolderApi = useApi(scaffolderApiRef);
|
|
2584
|
-
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
2585
|
-
const [userSelectedStepId, setUserSelectedStepId] = useState(void 0);
|
|
2586
|
-
const [clickedToCancel, setClickedToCancel] = useState(false);
|
|
2587
|
-
const [lastActiveStepId, setLastActiveStepId] = useState(
|
|
2588
|
-
void 0
|
|
2589
|
-
);
|
|
2590
|
-
const { taskId } = useRouteRefParams(scaffolderTaskRouteRef);
|
|
2591
|
-
const taskStream = useTaskEventStream(taskId);
|
|
2592
|
-
const completed = taskStream.completed;
|
|
2593
|
-
const taskCancelled = taskStream.cancelled;
|
|
2594
|
-
const steps = useMemo(
|
|
2595
|
-
() => {
|
|
2596
|
-
var _a, _b;
|
|
2597
|
-
return (_b = (_a = taskStream.task) == null ? void 0 : _a.spec.steps.map((step) => {
|
|
2598
|
-
var _a2;
|
|
2599
|
-
return {
|
|
2600
|
-
...step,
|
|
2601
|
-
...(_a2 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a2[step.id]
|
|
2602
|
-
};
|
|
2603
|
-
})) != null ? _b : [];
|
|
2604
|
-
},
|
|
2605
|
-
[taskStream]
|
|
2606
|
-
);
|
|
2607
|
-
useEffect(() => {
|
|
2608
|
-
var _a;
|
|
2609
|
-
const mostRecentFailedOrActiveStep = steps.find(
|
|
2610
|
-
(step) => ["failed", "processing"].includes(step.status)
|
|
2611
|
-
);
|
|
2612
|
-
if (completed && !mostRecentFailedOrActiveStep) {
|
|
2613
|
-
setLastActiveStepId((_a = steps[steps.length - 1]) == null ? void 0 : _a.id);
|
|
2614
|
-
return;
|
|
2615
|
-
}
|
|
2616
|
-
setLastActiveStepId(mostRecentFailedOrActiveStep == null ? void 0 : mostRecentFailedOrActiveStep.id);
|
|
2617
|
-
}, [steps, completed]);
|
|
2618
|
-
const currentStepId = userSelectedStepId != null ? userSelectedStepId : lastActiveStepId;
|
|
2619
|
-
const logAsString = useMemo(() => {
|
|
2620
|
-
if (!currentStepId) {
|
|
2621
|
-
return loadingText ? loadingText : "Loading...";
|
|
2622
|
-
}
|
|
2623
|
-
const log = taskStream.stepLogs[currentStepId];
|
|
2624
|
-
if (!(log == null ? void 0 : log.length)) {
|
|
2625
|
-
return "Waiting for logs...";
|
|
2626
|
-
}
|
|
2627
|
-
return log.join("\n");
|
|
2628
|
-
}, [taskStream.stepLogs, currentStepId, loadingText]);
|
|
2629
|
-
const taskNotFound = taskStream.completed && !taskStream.loading && !taskStream.task;
|
|
2630
|
-
const { output } = taskStream;
|
|
2631
|
-
const handleStartOver = () => {
|
|
2632
|
-
var _a, _b, _c;
|
|
2633
|
-
if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.templateInfo) == null ? void 0 : _b.entityRef)) {
|
|
2634
|
-
navigate(rootPath());
|
|
2635
|
-
return;
|
|
2636
|
-
}
|
|
2637
|
-
const formData = taskStream.task.spec.parameters;
|
|
2638
|
-
const { name, namespace } = parseEntityRef(
|
|
2639
|
-
(_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef
|
|
2640
|
-
);
|
|
2641
|
-
navigate(
|
|
2642
|
-
`${templateRoute({ templateName: name, namespace })}?${qs.stringify({
|
|
2643
|
-
formData: JSON.stringify(formData)
|
|
2644
|
-
})}`
|
|
2645
|
-
);
|
|
2646
|
-
};
|
|
2647
|
-
const handleCancel = async () => {
|
|
2648
|
-
setClickedToCancel(true);
|
|
2649
|
-
await scaffolderApi.cancelTask(taskId);
|
|
2650
|
-
};
|
|
2651
|
-
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
2652
|
-
Header,
|
|
2653
|
-
{
|
|
2654
|
-
pageTitleOverride: `Task ${taskId}`,
|
|
2655
|
-
title: "Task Activity",
|
|
2656
|
-
subtitle: `Activity for task: ${taskId}`
|
|
2657
|
-
}
|
|
2658
|
-
), /* @__PURE__ */ React.createElement(Content, null, taskNotFound ? /* @__PURE__ */ React.createElement(
|
|
2659
|
-
ErrorPage,
|
|
2660
|
-
{
|
|
2661
|
-
status: "404",
|
|
2662
|
-
statusMessage: "Task not found",
|
|
2663
|
-
additionalInfo: "No task found with this ID"
|
|
2664
|
-
}
|
|
2665
|
-
) : /* @__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(
|
|
2666
|
-
TaskStatusStepper,
|
|
2667
|
-
{
|
|
2668
|
-
steps,
|
|
2669
|
-
currentStepId,
|
|
2670
|
-
onUserStepChange: setUserSelectedStepId
|
|
2671
|
-
}
|
|
2672
|
-
), output && hasLinks(output) && /* @__PURE__ */ React.createElement(TaskPageLinks, { output }), /* @__PURE__ */ React.createElement(
|
|
2673
|
-
Button,
|
|
2674
|
-
{
|
|
2675
|
-
className: classes.button,
|
|
2676
|
-
onClick: handleStartOver,
|
|
2677
|
-
disabled: !completed,
|
|
2678
|
-
variant: "contained",
|
|
2679
|
-
color: "primary"
|
|
2680
|
-
},
|
|
2681
|
-
"Start Over"
|
|
2682
|
-
), /* @__PURE__ */ React.createElement(
|
|
2683
|
-
Button,
|
|
2684
|
-
{
|
|
2685
|
-
className: classes.button,
|
|
2686
|
-
onClick: handleCancel,
|
|
2687
|
-
disabled: completed || taskCancelled || clickedToCancel,
|
|
2688
|
-
variant: "outlined",
|
|
2689
|
-
color: "secondary"
|
|
2690
|
-
},
|
|
2691
|
-
(taskCancelled || clickedToCancel) && !completed ? "Cancelling..." : "Cancel"
|
|
2692
|
-
))), /* @__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 })))))));
|
|
2693
|
-
};
|
|
2694
|
-
|
|
2695
|
-
const useStyles$8 = makeStyles$1({
|
|
2696
|
-
root: {
|
|
2697
|
-
whiteSpace: "nowrap",
|
|
2698
|
-
overflowY: "auto"
|
|
2699
|
-
}
|
|
2700
|
-
});
|
|
2701
|
-
function parseFileEntires(paths) {
|
|
2702
|
-
const root = {
|
|
2703
|
-
type: "directory",
|
|
2704
|
-
name: "",
|
|
2705
|
-
path: "",
|
|
2706
|
-
children: []
|
|
2707
|
-
};
|
|
2708
|
-
for (const path of paths.slice().sort()) {
|
|
2709
|
-
const parts = path.split("/");
|
|
2710
|
-
let current = root;
|
|
2711
|
-
for (let i = 0; i < parts.length; i++) {
|
|
2712
|
-
const part = parts[i];
|
|
2713
|
-
if (part === "") {
|
|
2714
|
-
throw new Error(`Invalid path part: ''`);
|
|
2715
|
-
}
|
|
2716
|
-
const entryPath = parts.slice(0, i + 1).join("/");
|
|
2717
|
-
const existing = current.children.find((child) => child.name === part);
|
|
2718
|
-
if ((existing == null ? void 0 : existing.type) === "file") {
|
|
2719
|
-
throw new Error(`Duplicate filename at '${entryPath}'`);
|
|
2720
|
-
} else if (existing) {
|
|
2721
|
-
current = existing;
|
|
2722
|
-
} else {
|
|
2723
|
-
if (i < parts.length - 1) {
|
|
2724
|
-
const newEntry = {
|
|
2725
|
-
type: "directory",
|
|
2726
|
-
name: part,
|
|
2727
|
-
path: entryPath,
|
|
2728
|
-
children: []
|
|
2729
|
-
};
|
|
2730
|
-
const firstFileIndex = current.children.findIndex(
|
|
2731
|
-
(child) => child.type === "file"
|
|
2732
|
-
);
|
|
2733
|
-
current.children.splice(firstFileIndex, 0, newEntry);
|
|
2734
|
-
current = newEntry;
|
|
2735
|
-
} else {
|
|
2736
|
-
current.children.push({
|
|
2737
|
-
type: "file",
|
|
2738
|
-
name: part,
|
|
2739
|
-
path: entryPath
|
|
2740
|
-
});
|
|
2741
|
-
}
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
return root.children;
|
|
2746
|
-
}
|
|
2747
|
-
function FileTreeItem({ entry }) {
|
|
2748
|
-
if (entry.type === "file") {
|
|
2749
|
-
return /* @__PURE__ */ React.createElement(TreeItem, { nodeId: entry.path, label: entry.name });
|
|
2750
|
-
}
|
|
2751
|
-
return /* @__PURE__ */ React.createElement(TreeItem, { nodeId: entry.path, label: entry.name }, entry.children.map((child) => /* @__PURE__ */ React.createElement(FileTreeItem, { key: child.path, entry: child })));
|
|
2752
|
-
}
|
|
2753
|
-
function FileBrowser(props) {
|
|
2754
|
-
const classes = useStyles$8();
|
|
2755
|
-
const fileTree = useMemo(
|
|
2756
|
-
() => parseFileEntires(props.filePaths),
|
|
2757
|
-
[props.filePaths]
|
|
2758
|
-
);
|
|
2759
|
-
return /* @__PURE__ */ React.createElement(
|
|
2760
|
-
TreeView,
|
|
2761
|
-
{
|
|
2762
|
-
selected: props.selected,
|
|
2763
|
-
className: classes.root,
|
|
2764
|
-
defaultCollapseIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
|
|
2765
|
-
defaultExpandIcon: /* @__PURE__ */ React.createElement(ChevronRightIcon, null),
|
|
2766
|
-
onNodeSelect: (_e, nodeId) => {
|
|
2767
|
-
if (props.onSelect && props.filePaths.includes(nodeId)) {
|
|
2768
|
-
props.onSelect(nodeId);
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
},
|
|
2772
|
-
fileTree.map((entry) => /* @__PURE__ */ React.createElement(FileTreeItem, { key: entry.path, entry }))
|
|
2773
|
-
);
|
|
2774
|
-
}
|
|
2775
|
-
|
|
2776
|
-
const useStyles$7 = makeStyles$1((theme) => ({
|
|
2777
|
-
root: {
|
|
2778
|
-
display: "grid",
|
|
2779
|
-
gridTemplateColumns: "280px auto 3fr",
|
|
2780
|
-
gridTemplateRows: "1fr"
|
|
2781
|
-
},
|
|
2782
|
-
child: {
|
|
2783
|
-
overflowY: "auto",
|
|
2784
|
-
height: "100%",
|
|
2785
|
-
minHeight: 0
|
|
2786
|
-
},
|
|
2787
|
-
firstChild: {
|
|
2788
|
-
background: theme.palette.background.paper
|
|
2789
|
-
}
|
|
2790
|
-
}));
|
|
2791
|
-
function DryRunResultsSplitView(props) {
|
|
2792
|
-
const classes = useStyles$7();
|
|
2793
|
-
const childArray = Children.toArray(props.children);
|
|
2794
|
-
if (childArray.length !== 2) {
|
|
2795
|
-
throw new Error("must have exactly 2 children");
|
|
2796
|
-
}
|
|
2797
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classNames(classes.child, classes.firstChild) }, childArray[0]), /* @__PURE__ */ React.createElement(Divider, { orientation: "horizontal" }), /* @__PURE__ */ React.createElement("div", { className: classes.child }, childArray[1]));
|
|
2798
|
-
}
|
|
2799
|
-
|
|
2800
|
-
const useStyles$6 = makeStyles$1({
|
|
2801
|
-
root: {
|
|
2802
|
-
display: "flex",
|
|
2803
|
-
flexFlow: "column nowrap"
|
|
2804
|
-
},
|
|
2805
|
-
contentWrapper: {
|
|
2806
|
-
flex: 1,
|
|
2807
|
-
position: "relative"
|
|
2808
|
-
},
|
|
2809
|
-
content: {
|
|
2810
|
-
position: "absolute",
|
|
2811
|
-
top: 0,
|
|
2812
|
-
left: 0,
|
|
2813
|
-
right: 0,
|
|
2814
|
-
bottom: 0,
|
|
2815
|
-
display: "flex",
|
|
2816
|
-
"& > *": {
|
|
2817
|
-
flex: 1
|
|
2818
|
-
}
|
|
2819
|
-
},
|
|
2820
|
-
codeMirror: {
|
|
2821
|
-
height: "100%",
|
|
2822
|
-
overflowY: "auto"
|
|
2823
|
-
}
|
|
2824
|
-
});
|
|
2825
|
-
function FilesContent() {
|
|
2826
|
-
const classes = useStyles$6();
|
|
2827
|
-
const { selectedResult } = useDryRun();
|
|
2828
|
-
const [selectedPath, setSelectedPath] = useState("");
|
|
2829
|
-
const selectedFile = selectedResult == null ? void 0 : selectedResult.directoryContents.find(
|
|
2830
|
-
(f) => f.path === selectedPath
|
|
2831
|
-
);
|
|
2832
|
-
useEffect(() => {
|
|
2833
|
-
if (selectedResult) {
|
|
2834
|
-
const [firstFile] = selectedResult.directoryContents;
|
|
2835
|
-
if (firstFile) {
|
|
2836
|
-
setSelectedPath(firstFile.path);
|
|
2837
|
-
} else {
|
|
2838
|
-
setSelectedPath("");
|
|
2839
|
-
}
|
|
2840
|
-
}
|
|
2841
|
-
return void 0;
|
|
2842
|
-
}, [selectedResult]);
|
|
2843
|
-
if (!selectedResult) {
|
|
2844
|
-
return null;
|
|
2845
|
-
}
|
|
2846
|
-
return /* @__PURE__ */ React.createElement(DryRunResultsSplitView, null, /* @__PURE__ */ React.createElement(
|
|
2847
|
-
FileBrowser,
|
|
2848
|
-
{
|
|
2849
|
-
selected: selectedPath,
|
|
2850
|
-
onSelect: setSelectedPath,
|
|
2851
|
-
filePaths: selectedResult.directoryContents.map((file) => file.path)
|
|
2852
|
-
}
|
|
2853
|
-
), /* @__PURE__ */ React.createElement(
|
|
2854
|
-
CodeMirror,
|
|
2855
|
-
{
|
|
2856
|
-
className: classes.codeMirror,
|
|
2857
|
-
theme: "dark",
|
|
2858
|
-
height: "100%",
|
|
2859
|
-
extensions: [StreamLanguage.define(yaml$1)],
|
|
2860
|
-
readOnly: true,
|
|
2861
|
-
value: (selectedFile == null ? void 0 : selectedFile.base64Content) ? atob(selectedFile.base64Content) : ""
|
|
2862
|
-
}
|
|
2863
|
-
));
|
|
2864
|
-
}
|
|
2865
|
-
function LogContent() {
|
|
2866
|
-
var _a, _b;
|
|
2867
|
-
const { selectedResult } = useDryRun();
|
|
2868
|
-
const [currentStepId, setUserSelectedStepId] = useState();
|
|
2869
|
-
const steps = useMemo(() => {
|
|
2870
|
-
var _a2;
|
|
2871
|
-
if (!selectedResult) {
|
|
2872
|
-
return [];
|
|
2873
|
-
}
|
|
2874
|
-
return (_a2 = selectedResult.steps.map((step) => {
|
|
2875
|
-
var _a3, _b2;
|
|
2876
|
-
const stepLog = selectedResult.log.filter(
|
|
2877
|
-
(l) => l.body.stepId === step.id
|
|
2878
|
-
);
|
|
2879
|
-
return {
|
|
2880
|
-
id: step.id,
|
|
2881
|
-
name: step.name,
|
|
2882
|
-
logString: stepLog.map((l) => l.body.message).join("\n"),
|
|
2883
|
-
status: (_b2 = (_a3 = stepLog[stepLog.length - 1]) == null ? void 0 : _a3.body.status) != null ? _b2 : "completed"
|
|
2884
|
-
};
|
|
2885
|
-
})) != null ? _a2 : [];
|
|
2886
|
-
}, [selectedResult]);
|
|
2887
|
-
if (!selectedResult) {
|
|
2888
|
-
return null;
|
|
2889
|
-
}
|
|
2890
|
-
const selectedStep = (_a = steps.find((s) => s.id === currentStepId)) != null ? _a : steps[0];
|
|
2891
|
-
return /* @__PURE__ */ React.createElement(DryRunResultsSplitView, null, /* @__PURE__ */ React.createElement(
|
|
2892
|
-
TaskStatusStepper,
|
|
2893
|
-
{
|
|
2894
|
-
steps,
|
|
2895
|
-
currentStepId: selectedStep.id,
|
|
2896
|
-
onUserStepChange: setUserSelectedStepId
|
|
2897
|
-
}
|
|
2898
|
-
), /* @__PURE__ */ React.createElement(LogViewer, { text: (_b = selectedStep == null ? void 0 : selectedStep.logString) != null ? _b : "" }));
|
|
2899
|
-
}
|
|
2900
|
-
function OutputContent() {
|
|
2901
|
-
var _a, _b;
|
|
2902
|
-
const classes = useStyles$6();
|
|
2903
|
-
const { selectedResult } = useDryRun();
|
|
2904
|
-
if (!selectedResult) {
|
|
2905
|
-
return null;
|
|
2906
|
-
}
|
|
2907
|
-
return /* @__PURE__ */ React.createElement(DryRunResultsSplitView, null, /* @__PURE__ */ React.createElement(Box$1, { pt: 2 }, ((_b = (_a = selectedResult.output) == null ? void 0 : _a.links) == null ? void 0 : _b.length) && /* @__PURE__ */ React.createElement(TaskPageLinks, { output: selectedResult.output })), /* @__PURE__ */ React.createElement(
|
|
2908
|
-
CodeMirror,
|
|
2909
|
-
{
|
|
2910
|
-
className: classes.codeMirror,
|
|
2911
|
-
theme: "dark",
|
|
2912
|
-
height: "100%",
|
|
2913
|
-
extensions: [StreamLanguage.define(yaml$1)],
|
|
2914
|
-
readOnly: true,
|
|
2915
|
-
value: JSON.stringify(selectedResult.output, null, 2)
|
|
2916
|
-
}
|
|
2917
|
-
));
|
|
2918
|
-
}
|
|
2919
|
-
function DryRunResultsView() {
|
|
2920
|
-
const classes = useStyles$6();
|
|
2921
|
-
const [selectedTab, setSelectedTab] = useState(
|
|
2922
|
-
"files"
|
|
2923
|
-
);
|
|
2924
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Tabs, { value: selectedTab, onChange: (_, v) => setSelectedTab(v) }, /* @__PURE__ */ React.createElement(Tab, { value: "files", label: "Files" }), /* @__PURE__ */ React.createElement(Tab, { value: "log", label: "Log" }), /* @__PURE__ */ React.createElement(Tab, { value: "output", label: "Output" })), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement("div", { className: classes.contentWrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.content }, selectedTab === "files" && /* @__PURE__ */ React.createElement(FilesContent, null), selectedTab === "log" && /* @__PURE__ */ React.createElement(LogContent, null), selectedTab === "output" && /* @__PURE__ */ React.createElement(OutputContent, null))));
|
|
2925
|
-
}
|
|
2926
|
-
|
|
2927
|
-
const useStyles$5 = makeStyles$1((theme) => ({
|
|
2928
|
-
header: {
|
|
2929
|
-
height: 48,
|
|
2930
|
-
minHeight: 0,
|
|
2931
|
-
"&.Mui-expanded": {
|
|
2932
|
-
height: 48,
|
|
2933
|
-
minHeight: 0
|
|
2934
|
-
}
|
|
2935
|
-
},
|
|
2936
|
-
content: {
|
|
2937
|
-
display: "grid",
|
|
2938
|
-
background: theme.palette.background.default,
|
|
2939
|
-
gridTemplateColumns: "180px auto 1fr",
|
|
2940
|
-
gridTemplateRows: "1fr",
|
|
2941
|
-
padding: 0,
|
|
2942
|
-
height: 400
|
|
2943
|
-
}
|
|
2944
|
-
}));
|
|
2945
|
-
function DryRunResults() {
|
|
2946
|
-
const classes = useStyles$5();
|
|
2947
|
-
const dryRun = useDryRun();
|
|
2948
|
-
const [expanded, setExpanded] = useState(false);
|
|
2949
|
-
const [hidden, setHidden] = useState(true);
|
|
2950
|
-
const resultsLength = dryRun.results.length;
|
|
2951
|
-
const prevResultsLength = usePrevious(resultsLength);
|
|
2952
|
-
useEffect(() => {
|
|
2953
|
-
if (prevResultsLength === 0 && resultsLength === 1) {
|
|
2954
|
-
setHidden(false);
|
|
2955
|
-
setExpanded(true);
|
|
2956
|
-
} else if (prevResultsLength === 1 && resultsLength === 0) {
|
|
2957
|
-
setExpanded(false);
|
|
2958
|
-
}
|
|
2959
|
-
}, [prevResultsLength, resultsLength]);
|
|
2960
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
2961
|
-
Accordion$1,
|
|
2962
|
-
{
|
|
2963
|
-
variant: "outlined",
|
|
2964
|
-
expanded,
|
|
2965
|
-
hidden: resultsLength === 0 && hidden,
|
|
2966
|
-
onChange: (_, exp) => setExpanded(exp),
|
|
2967
|
-
onTransitionEnd: () => resultsLength === 0 && setHidden(true)
|
|
2968
|
-
},
|
|
2969
|
-
/* @__PURE__ */ React.createElement(
|
|
2970
|
-
AccordionSummary$1,
|
|
2971
|
-
{
|
|
2972
|
-
className: classes.header,
|
|
2973
|
-
expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon$1, null)
|
|
2974
|
-
},
|
|
2975
|
-
/* @__PURE__ */ React.createElement(Typography$1, null, "Dry-run results")
|
|
2976
|
-
),
|
|
2977
|
-
/* @__PURE__ */ React.createElement(Divider, { orientation: "horizontal" }),
|
|
2978
|
-
/* @__PURE__ */ React.createElement(AccordionDetails$1, { className: classes.content }, /* @__PURE__ */ React.createElement(DryRunResultsList, null), /* @__PURE__ */ React.createElement(Divider, { orientation: "horizontal" }), /* @__PURE__ */ React.createElement(DryRunResultsView, null))
|
|
2979
|
-
));
|
|
2980
|
-
}
|
|
2981
|
-
|
|
2982
|
-
const useStyles$4 = makeStyles((theme) => ({
|
|
2983
|
-
button: {
|
|
2984
|
-
padding: theme.spacing(1)
|
|
2985
|
-
},
|
|
2986
|
-
buttons: {
|
|
2987
|
-
display: "flex",
|
|
2988
|
-
flexFlow: "row nowrap",
|
|
2989
|
-
alignItems: "center",
|
|
2990
|
-
justifyContent: "flex-start"
|
|
2991
|
-
},
|
|
2992
|
-
buttonsGap: {
|
|
2993
|
-
flex: "1 1 auto"
|
|
2994
|
-
},
|
|
2995
|
-
buttonsDivider: {
|
|
2996
|
-
marginBottom: theme.spacing(1)
|
|
2997
|
-
}
|
|
2998
|
-
}));
|
|
2999
|
-
function TemplateEditorBrowser(props) {
|
|
3000
|
-
var _a, _b;
|
|
3001
|
-
const classes = useStyles$4();
|
|
3002
|
-
const directoryEditor = useDirectoryEditor();
|
|
3003
|
-
const changedFiles = directoryEditor.files.filter((file) => file.dirty);
|
|
3004
|
-
const handleClose = () => {
|
|
3005
|
-
if (!props.onClose) {
|
|
3006
|
-
return;
|
|
3007
|
-
}
|
|
3008
|
-
if (changedFiles.length > 0) {
|
|
3009
|
-
const accepted = window.confirm(
|
|
3010
|
-
"Are you sure? Unsaved changes will be lost"
|
|
3011
|
-
);
|
|
3012
|
-
if (!accepted) {
|
|
3013
|
-
return;
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
props.onClose();
|
|
3017
|
-
};
|
|
3018
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: classes.buttons }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Save all files" }, /* @__PURE__ */ React.createElement(
|
|
3019
|
-
IconButton,
|
|
3020
|
-
{
|
|
3021
|
-
className: classes.button,
|
|
3022
|
-
disabled: directoryEditor.files.every((file) => !file.dirty),
|
|
3023
|
-
onClick: () => directoryEditor.save()
|
|
3024
|
-
},
|
|
3025
|
-
/* @__PURE__ */ React.createElement(SaveIcon, null)
|
|
3026
|
-
)), /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload directory" }, /* @__PURE__ */ React.createElement(
|
|
3027
|
-
IconButton,
|
|
3028
|
-
{
|
|
3029
|
-
className: classes.button,
|
|
3030
|
-
onClick: () => directoryEditor.reload()
|
|
3031
|
-
},
|
|
3032
|
-
/* @__PURE__ */ React.createElement(RefreshIcon, null)
|
|
3033
|
-
)), /* @__PURE__ */ React.createElement("div", { className: classes.buttonsGap }), /* @__PURE__ */ React.createElement(Tooltip, { title: "Close directory" }, /* @__PURE__ */ React.createElement(IconButton, { className: classes.button, onClick: handleClose }, /* @__PURE__ */ React.createElement(CloseIcon, null)))), /* @__PURE__ */ React.createElement(Divider$1, { className: classes.buttonsDivider }), /* @__PURE__ */ React.createElement(
|
|
3034
|
-
FileBrowser,
|
|
3035
|
-
{
|
|
3036
|
-
selected: (_b = (_a = directoryEditor.selectedFile) == null ? void 0 : _a.path) != null ? _b : "",
|
|
3037
|
-
onSelect: directoryEditor.setSelectedFile,
|
|
3038
|
-
filePaths: directoryEditor.files.map((file) => file.path)
|
|
3039
|
-
}
|
|
3040
|
-
));
|
|
3041
|
-
}
|
|
3042
|
-
|
|
3043
|
-
const useStyles$3 = makeStyles((theme) => ({
|
|
3044
|
-
container: {
|
|
3045
|
-
position: "relative",
|
|
3046
|
-
width: "100%",
|
|
3047
|
-
height: "100%"
|
|
3048
|
-
},
|
|
3049
|
-
codeMirror: {
|
|
3050
|
-
position: "absolute",
|
|
3051
|
-
top: 0,
|
|
3052
|
-
bottom: 0,
|
|
3053
|
-
left: 0,
|
|
3054
|
-
right: 0
|
|
3055
|
-
},
|
|
3056
|
-
errorPanel: {
|
|
3057
|
-
color: theme.palette.error.main,
|
|
3058
|
-
lineHeight: 2,
|
|
3059
|
-
margin: theme.spacing(0, 1)
|
|
3060
|
-
},
|
|
3061
|
-
floatingButtons: {
|
|
3062
|
-
position: "absolute",
|
|
3063
|
-
top: theme.spacing(1),
|
|
3064
|
-
right: theme.spacing(3)
|
|
3065
|
-
},
|
|
3066
|
-
floatingButton: {
|
|
3067
|
-
padding: theme.spacing(1)
|
|
3068
|
-
}
|
|
3069
|
-
}));
|
|
3070
|
-
function TemplateEditorTextArea(props) {
|
|
3071
|
-
const { errorText } = props;
|
|
3072
|
-
const classes = useStyles$3();
|
|
3073
|
-
const panelExtension = useMemo(() => {
|
|
3074
|
-
if (!errorText) {
|
|
3075
|
-
return showPanel.of(null);
|
|
3076
|
-
}
|
|
3077
|
-
const dom = document.createElement("div");
|
|
3078
|
-
dom.classList.add(classes.errorPanel);
|
|
3079
|
-
dom.textContent = errorText;
|
|
3080
|
-
return showPanel.of(() => ({ dom, bottom: true }));
|
|
3081
|
-
}, [classes, errorText]);
|
|
3082
|
-
useKeyboardEvent(
|
|
3083
|
-
(e) => e.key === "s" && (e.ctrlKey || e.metaKey),
|
|
3084
|
-
(e) => {
|
|
3085
|
-
e.preventDefault();
|
|
3086
|
-
if (props.onSave) {
|
|
3087
|
-
props.onSave();
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
);
|
|
3091
|
-
return /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(
|
|
3092
|
-
CodeMirror,
|
|
3093
|
-
{
|
|
3094
|
-
className: classes.codeMirror,
|
|
3095
|
-
theme: "dark",
|
|
3096
|
-
height: "100%",
|
|
3097
|
-
extensions: [StreamLanguage.define(yaml$1), panelExtension],
|
|
3098
|
-
value: props.content,
|
|
3099
|
-
onChange: props.onUpdate
|
|
3100
|
-
}
|
|
3101
|
-
), (props.onSave || props.onReload) && /* @__PURE__ */ React.createElement("div", { className: classes.floatingButtons }, /* @__PURE__ */ React.createElement(Paper, null, props.onSave && /* @__PURE__ */ React.createElement(Tooltip, { title: "Save file" }, /* @__PURE__ */ React.createElement(
|
|
3102
|
-
IconButton,
|
|
3103
|
-
{
|
|
3104
|
-
className: classes.floatingButton,
|
|
3105
|
-
onClick: () => {
|
|
3106
|
-
var _a;
|
|
3107
|
-
return (_a = props.onSave) == null ? void 0 : _a.call(props);
|
|
3108
|
-
}
|
|
3109
|
-
},
|
|
3110
|
-
/* @__PURE__ */ React.createElement(SaveIcon, null)
|
|
3111
|
-
)), props.onReload && /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload file" }, /* @__PURE__ */ React.createElement(
|
|
3112
|
-
IconButton,
|
|
3113
|
-
{
|
|
3114
|
-
className: classes.floatingButton,
|
|
3115
|
-
onClick: () => {
|
|
3116
|
-
var _a;
|
|
3117
|
-
return (_a = props.onReload) == null ? void 0 : _a.call(props);
|
|
3118
|
-
}
|
|
3119
|
-
},
|
|
3120
|
-
/* @__PURE__ */ React.createElement(RefreshIcon, null)
|
|
3121
|
-
)))));
|
|
3122
|
-
}
|
|
3123
|
-
function TemplateEditorDirectoryEditorTextArea(props) {
|
|
3124
|
-
var _a, _b;
|
|
3125
|
-
const directoryEditor = useDirectoryEditor();
|
|
3126
|
-
const actions = ((_a = directoryEditor.selectedFile) == null ? void 0 : _a.dirty) ? {
|
|
3127
|
-
onSave: () => directoryEditor.save(),
|
|
3128
|
-
onReload: () => directoryEditor.reload()
|
|
3129
|
-
} : {
|
|
3130
|
-
onReload: () => directoryEditor.reload()
|
|
3131
|
-
};
|
|
3132
|
-
return /* @__PURE__ */ React.createElement(
|
|
3133
|
-
TemplateEditorTextArea,
|
|
3134
|
-
{
|
|
3135
|
-
errorText: props.errorText,
|
|
3136
|
-
content: (_b = directoryEditor.selectedFile) == null ? void 0 : _b.content,
|
|
3137
|
-
onUpdate: (content) => {
|
|
3138
|
-
var _a2;
|
|
3139
|
-
return (_a2 = directoryEditor.selectedFile) == null ? void 0 : _a2.updateContent(content);
|
|
3140
|
-
},
|
|
3141
|
-
...actions
|
|
3142
|
-
}
|
|
3143
|
-
);
|
|
3144
|
-
}
|
|
3145
|
-
TemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;
|
|
3146
|
-
|
|
3147
|
-
const useStyles$2 = makeStyles({
|
|
3148
|
-
// Reset and fix sizing to make sure scrolling behaves correctly
|
|
3149
|
-
root: {
|
|
3150
|
-
gridArea: "pageContent",
|
|
3151
|
-
display: "grid",
|
|
3152
|
-
gridTemplateAreas: `
|
|
3153
|
-
"browser editor preview"
|
|
3154
|
-
"results results results"
|
|
3155
|
-
`,
|
|
3156
|
-
gridTemplateColumns: "1fr 3fr 2fr",
|
|
3157
|
-
gridTemplateRows: "1fr auto"
|
|
3158
|
-
},
|
|
3159
|
-
browser: {
|
|
3160
|
-
gridArea: "browser",
|
|
3161
|
-
overflow: "auto"
|
|
3162
|
-
},
|
|
3163
|
-
editor: {
|
|
3164
|
-
gridArea: "editor",
|
|
3165
|
-
overflow: "auto"
|
|
3166
|
-
},
|
|
3167
|
-
preview: {
|
|
3168
|
-
gridArea: "preview",
|
|
3169
|
-
overflow: "auto"
|
|
3170
|
-
},
|
|
3171
|
-
results: {
|
|
3172
|
-
gridArea: "results"
|
|
3173
|
-
}
|
|
3174
|
-
});
|
|
3175
|
-
const TemplateEditor = (props) => {
|
|
3176
|
-
const classes = useStyles$2();
|
|
3177
|
-
const [errorText, setErrorText] = useState();
|
|
3178
|
-
return /* @__PURE__ */ React.createElement(DirectoryEditorProvider, { directory: props.directory }, /* @__PURE__ */ React.createElement(DryRunProvider, null, /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("section", { className: classes.browser }, /* @__PURE__ */ React.createElement(TemplateEditorBrowser, { onClose: props.onClose })), /* @__PURE__ */ React.createElement("section", { className: classes.editor }, /* @__PURE__ */ React.createElement(TemplateEditorTextArea.DirectoryEditor, { errorText })), /* @__PURE__ */ React.createElement("section", { className: classes.preview }, /* @__PURE__ */ React.createElement(
|
|
3179
|
-
TemplateEditorForm.DirectoryEditorDryRun,
|
|
3180
|
-
{
|
|
3181
|
-
setErrorText,
|
|
3182
|
-
fieldExtensions: props.fieldExtensions,
|
|
3183
|
-
layouts: props.layouts
|
|
3184
|
-
}
|
|
3185
|
-
)), /* @__PURE__ */ React.createElement("section", { className: classes.results }, /* @__PURE__ */ React.createElement(DryRunResults, null)))));
|
|
3186
|
-
};
|
|
3187
|
-
|
|
3188
|
-
const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI
|
|
3189
|
-
parameters:
|
|
3190
|
-
- title: Fill in some steps
|
|
3191
|
-
required:
|
|
3192
|
-
- name
|
|
3193
|
-
properties:
|
|
3194
|
-
name:
|
|
3195
|
-
title: Name
|
|
3196
|
-
type: string
|
|
3197
|
-
description: Unique name of the component
|
|
3198
|
-
owner:
|
|
3199
|
-
title: Owner
|
|
3200
|
-
type: string
|
|
3201
|
-
description: Owner of the component
|
|
3202
|
-
ui:field: OwnerPicker
|
|
3203
|
-
ui:options:
|
|
3204
|
-
catalogFilter:
|
|
3205
|
-
kind: Group
|
|
3206
|
-
- title: Choose a location
|
|
3207
|
-
required:
|
|
3208
|
-
- repoUrl
|
|
3209
|
-
properties:
|
|
3210
|
-
repoUrl:
|
|
3211
|
-
title: Repository Location
|
|
3212
|
-
type: string
|
|
3213
|
-
ui:field: RepoUrlPicker
|
|
3214
|
-
ui:options:
|
|
3215
|
-
allowedHosts:
|
|
3216
|
-
- github.com
|
|
3217
|
-
steps:
|
|
3218
|
-
- id: fetch-base
|
|
3219
|
-
name: Fetch Base
|
|
3220
|
-
action: fetch:template
|
|
3221
|
-
input:
|
|
3222
|
-
url: ./template
|
|
3223
|
-
values:
|
|
3224
|
-
name: \${{parameters.name}}
|
|
3225
|
-
`;
|
|
3226
|
-
const useStyles$1 = makeStyles((theme) => ({
|
|
3227
|
-
root: {
|
|
3228
|
-
gridArea: "pageContent",
|
|
3229
|
-
display: "grid",
|
|
3230
|
-
gridTemplateAreas: `
|
|
3231
|
-
"controls controls"
|
|
3232
|
-
"textArea preview"
|
|
3233
|
-
`,
|
|
3234
|
-
gridTemplateRows: "auto 1fr",
|
|
3235
|
-
gridTemplateColumns: "1fr 1fr"
|
|
3236
|
-
},
|
|
3237
|
-
controls: {
|
|
3238
|
-
gridArea: "controls",
|
|
3239
|
-
display: "flex",
|
|
3240
|
-
flexFlow: "row nowrap",
|
|
3241
|
-
alignItems: "center",
|
|
3242
|
-
margin: theme.spacing(1)
|
|
3243
|
-
},
|
|
3244
|
-
textArea: {
|
|
3245
|
-
gridArea: "textArea"
|
|
3246
|
-
},
|
|
3247
|
-
preview: {
|
|
3248
|
-
gridArea: "preview"
|
|
3249
|
-
}
|
|
3250
|
-
}));
|
|
3251
|
-
const TemplateFormPreviewer = ({
|
|
3252
|
-
defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,
|
|
3253
|
-
customFieldExtensions = [],
|
|
3254
|
-
onClose,
|
|
3255
|
-
layouts = []
|
|
3256
|
-
}) => {
|
|
3257
|
-
const classes = useStyles$1();
|
|
3258
|
-
const alertApi = useApi(alertApiRef);
|
|
3259
|
-
const catalogApi = useApi(catalogApiRef);
|
|
3260
|
-
const [selectedTemplate, setSelectedTemplate] = useState("");
|
|
3261
|
-
const [errorText, setErrorText] = useState();
|
|
3262
|
-
const [templateOptions, setTemplateOptions] = useState([]);
|
|
3263
|
-
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
3264
|
-
const { loading } = useAsync(
|
|
3265
|
-
() => catalogApi.getEntities({
|
|
3266
|
-
filter: { kind: "template" },
|
|
3267
|
-
fields: [
|
|
3268
|
-
"kind",
|
|
3269
|
-
"metadata.namespace",
|
|
3270
|
-
"metadata.name",
|
|
3271
|
-
"metadata.title",
|
|
3272
|
-
"spec.parameters",
|
|
3273
|
-
"spec.steps",
|
|
3274
|
-
"spec.output"
|
|
3275
|
-
]
|
|
3276
|
-
}).then(
|
|
3277
|
-
({ items }) => setTemplateOptions(
|
|
3278
|
-
items.map((template) => {
|
|
3279
|
-
var _a;
|
|
3280
|
-
return {
|
|
3281
|
-
label: (_a = template.metadata.title) != null ? _a : humanizeEntityRef(template, { defaultKind: "template" }),
|
|
3282
|
-
value: template
|
|
3283
|
-
};
|
|
3284
|
-
})
|
|
3285
|
-
)
|
|
3286
|
-
).catch(
|
|
3287
|
-
(e) => alertApi.post({
|
|
3288
|
-
message: `Error loading exisiting templates: ${e.message}`,
|
|
3289
|
-
severity: "error"
|
|
3290
|
-
})
|
|
3291
|
-
),
|
|
3292
|
-
[catalogApi]
|
|
3293
|
-
);
|
|
3294
|
-
const handleSelectChange = useCallback(
|
|
3295
|
-
(selected) => {
|
|
3296
|
-
setSelectedTemplate(selected);
|
|
3297
|
-
setTemplateYaml(yaml.stringify(selected.spec));
|
|
3298
|
-
},
|
|
3299
|
-
[setTemplateYaml]
|
|
3300
|
-
);
|
|
3301
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classes.controls }, /* @__PURE__ */ React.createElement(FormControl$1, { variant: "outlined", size: "small", fullWidth: true }, /* @__PURE__ */ React.createElement(InputLabel$1, { id: "select-template-label" }, "Load Existing Template"), /* @__PURE__ */ React.createElement(
|
|
3302
|
-
Select$1,
|
|
3303
|
-
{
|
|
3304
|
-
value: selectedTemplate,
|
|
3305
|
-
label: "Load Existing Template",
|
|
3306
|
-
labelId: "select-template-label",
|
|
3307
|
-
onChange: (e) => handleSelectChange(e.target.value)
|
|
3308
|
-
},
|
|
3309
|
-
templateOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, { key: idx, value: option.value }, option.label))
|
|
3310
|
-
)), /* @__PURE__ */ React.createElement(IconButton, { size: "medium", onClick: onClose }, /* @__PURE__ */ React.createElement(CloseIcon, null))), /* @__PURE__ */ React.createElement("div", { className: classes.textArea }, /* @__PURE__ */ React.createElement(
|
|
3311
|
-
TemplateEditorTextArea,
|
|
3312
|
-
{
|
|
3313
|
-
content: templateYaml,
|
|
3314
|
-
onUpdate: setTemplateYaml,
|
|
3315
|
-
errorText
|
|
3316
|
-
}
|
|
3317
|
-
)), /* @__PURE__ */ React.createElement("div", { className: classes.preview }, /* @__PURE__ */ React.createElement(
|
|
3318
|
-
TemplateEditorForm,
|
|
3319
|
-
{
|
|
3320
|
-
content: templateYaml,
|
|
3321
|
-
contentIsSpec: true,
|
|
3322
|
-
fieldExtensions: customFieldExtensions,
|
|
3323
|
-
setErrorText,
|
|
3324
|
-
layouts
|
|
3325
|
-
}
|
|
3326
|
-
))));
|
|
3327
|
-
};
|
|
3328
|
-
|
|
3329
|
-
const useStyles = makeStyles$1((theme) => ({
|
|
3330
|
-
introText: {
|
|
3331
|
-
textAlign: "center",
|
|
3332
|
-
marginTop: theme.spacing(2)
|
|
3333
|
-
},
|
|
3334
|
-
card: {
|
|
3335
|
-
position: "relative",
|
|
3336
|
-
maxWidth: 340,
|
|
3337
|
-
marginTop: theme.spacing(4),
|
|
3338
|
-
margin: theme.spacing(0, 2)
|
|
3339
|
-
},
|
|
3340
|
-
infoIcon: {
|
|
3341
|
-
position: "absolute",
|
|
3342
|
-
top: theme.spacing(1),
|
|
3343
|
-
right: theme.spacing(1)
|
|
3344
|
-
}
|
|
3345
|
-
}));
|
|
3346
|
-
function TemplateEditorIntro(props) {
|
|
3347
|
-
const classes = useStyles();
|
|
3348
|
-
const supportsLoad = WebFileSystemAccess.isSupported();
|
|
3349
|
-
const cardLoadLocal = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(
|
|
3350
|
-
CardActionArea,
|
|
3351
|
-
{
|
|
3352
|
-
disabled: !supportsLoad,
|
|
3353
|
-
onClick: () => {
|
|
3354
|
-
var _a;
|
|
3355
|
-
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "local");
|
|
3356
|
-
}
|
|
3357
|
-
},
|
|
3358
|
-
/* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(
|
|
3359
|
-
Typography$1,
|
|
3360
|
-
{
|
|
3361
|
-
variant: "h5",
|
|
3362
|
-
gutterBottom: true,
|
|
3363
|
-
color: supportsLoad ? void 0 : "textSecondary",
|
|
3364
|
-
style: { display: "flex", flexFlow: "row nowrap" }
|
|
3365
|
-
},
|
|
3366
|
-
"Load Template Directory"
|
|
3367
|
-
), /* @__PURE__ */ React.createElement(
|
|
3368
|
-
Typography$1,
|
|
3369
|
-
{
|
|
3370
|
-
variant: "body1",
|
|
3371
|
-
color: supportsLoad ? void 0 : "textSecondary"
|
|
3372
|
-
},
|
|
3373
|
-
"Load a local template directory, allowing you to both edit and try executing your own template."
|
|
3374
|
-
))
|
|
3375
|
-
), !supportsLoad && /* @__PURE__ */ React.createElement("div", { className: classes.infoIcon }, /* @__PURE__ */ React.createElement(
|
|
3376
|
-
Tooltip$1,
|
|
3377
|
-
{
|
|
3378
|
-
placement: "top",
|
|
3379
|
-
title: "Only supported in some Chromium-based browsers"
|
|
3380
|
-
},
|
|
3381
|
-
/* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
|
|
3382
|
-
)));
|
|
3383
|
-
const cardFormEditor = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
3384
|
-
var _a;
|
|
3385
|
-
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
|
|
3386
|
-
} }, /* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h5", gutterBottom: true }, "Edit Template Form"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "Preview and edit a template form, either using a sample template or by loading a template from the catalog."))));
|
|
3387
|
-
const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
|
|
3388
|
-
var _a;
|
|
3389
|
-
return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
|
|
3390
|
-
} }, /* @__PURE__ */ React.createElement(CardContent$1, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h5", gutterBottom: true }, "Custom Field Explorer"), /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "View and play around with available installed custom field extensions."))));
|
|
3391
|
-
return /* @__PURE__ */ React.createElement("div", { style: props.style }, /* @__PURE__ */ React.createElement(Typography$1, { variant: "h6", className: classes.introText }, "Get started by choosing one of the options below"), /* @__PURE__ */ React.createElement(
|
|
3392
|
-
"div",
|
|
3393
|
-
{
|
|
3394
|
-
style: {
|
|
3395
|
-
display: "flex",
|
|
3396
|
-
flexFlow: "row wrap",
|
|
3397
|
-
alignItems: "flex-start",
|
|
3398
|
-
justifyContent: "center",
|
|
3399
|
-
alignContent: "flex-start"
|
|
3400
|
-
}
|
|
3401
|
-
},
|
|
3402
|
-
supportsLoad && cardLoadLocal,
|
|
3403
|
-
cardFormEditor,
|
|
3404
|
-
!supportsLoad && cardLoadLocal,
|
|
3405
|
-
cardFieldExplorer
|
|
3406
|
-
));
|
|
3407
|
-
}
|
|
3408
|
-
|
|
3409
|
-
export { ActionsPage as A, OwnedEntityPickerSchema as B, OwnerListPicker as C, DirectoryEditorProvider as D, EntityPicker as E, TemplateEditor as F, TemplateFormPreviewer as G, CustomFieldExplorer as H, OngoingTask as I, NextScaffolderPage as N, OwnerPicker as O, RepoUrlPicker as R, TemplateEditorBrowser as T, WebFileSystemAccess as W, actionsRouteRef as a, scaffolderListTaskRouteRef as b, scaffolderTaskRouteRef as c, rootRouteRef as d, editRouteRef as e, useDirectoryEditor as f, DryRunProvider as g, TemplateEditorTextArea as h, DryRunResults as i, TemplateEditorIntro as j, TaskPage as k, legacySelectedTemplateRouteRef as l, EntityPickerSchema as m, EntityNamePicker as n, entityNamePickerValidation as o, EntityNamePickerSchema as p, EntityTagsPicker as q, registerComponentRouteRef as r, selectedTemplateRouteRef as s, EntityTagsPickerSchema as t, useDryRun as u, viewTechDocRouteRef as v, repoPickerValidation as w, RepoUrlPickerSchema as x, OwnerPickerSchema as y, OwnedEntityPicker as z };
|
|
3410
|
-
//# sourceMappingURL=alpha-0764fae7.esm.js.map
|