@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.
Files changed (34) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/alpha/package.json +1 -1
  3. package/dist/alpha.d.ts +12 -70
  4. package/dist/alpha.esm.js +21 -18
  5. package/dist/alpha.esm.js.map +1 -1
  6. package/dist/esm/{alpha/ListTasksPage-a9fab591.esm.js → ListTasksPage-caaca86d.esm.js} +3 -2
  7. package/dist/esm/ListTasksPage-caaca86d.esm.js.map +1 -0
  8. package/dist/esm/{index/Router-f32000f9.esm.js → Router-f509f2e0.esm.js} +19 -16
  9. package/dist/esm/Router-f509f2e0.esm.js.map +1 -0
  10. package/dist/esm/{index/index-8321766a.esm.js → TaskPage-f304e0fc.esm.js} +31 -88
  11. package/dist/esm/TaskPage-f304e0fc.esm.js.map +1 -0
  12. package/dist/esm/{index/ListTasksPage-64779a2d.esm.js → TemplateEditorIntro-f7f6d664.esm.js} +396 -530
  13. package/dist/esm/TemplateEditorIntro-f7f6d664.esm.js.map +1 -0
  14. package/dist/esm/{index/index-e3edaa49.esm.js → TemplateFormPreviewer-299c316c.esm.js} +18 -379
  15. package/dist/esm/TemplateFormPreviewer-299c316c.esm.js.map +1 -0
  16. package/dist/esm/TemplateTypePicker-4f07b216.esm.js +58 -0
  17. package/dist/esm/TemplateTypePicker-4f07b216.esm.js.map +1 -0
  18. package/dist/esm/{alpha/index-d45f106a.esm.js → index-64f5b7a5.esm.js} +26 -23
  19. package/dist/esm/index-64f5b7a5.esm.js.map +1 -0
  20. package/dist/index.d.ts +46 -205
  21. package/dist/index.esm.js +19 -7
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/types/plugin.d-7a7914d1.d.ts +232 -0
  24. package/package.json +24 -22
  25. package/dist/esm/alpha/ListTasksPage-a9fab591.esm.js.map +0 -1
  26. package/dist/esm/alpha/Router-ea3122d2.esm.js +0 -1581
  27. package/dist/esm/alpha/Router-ea3122d2.esm.js.map +0 -1
  28. package/dist/esm/alpha/alpha-0764fae7.esm.js +0 -3410
  29. package/dist/esm/alpha/alpha-0764fae7.esm.js.map +0 -1
  30. package/dist/esm/alpha/index-d45f106a.esm.js.map +0 -1
  31. package/dist/esm/index/ListTasksPage-64779a2d.esm.js.map +0 -1
  32. package/dist/esm/index/Router-f32000f9.esm.js.map +0 -1
  33. package/dist/esm/index/index-8321766a.esm.js.map +0 -1
  34. package/dist/esm/index/index-e3edaa49.esm.js.map +0 -1
@@ -1,31 +1,29 @@
1
- import React, { Fragment, createContext, useEffect, useContext, useState, useRef, useCallback, useMemo, Children } from 'react';
1
+ import React, { useState, Fragment, createContext, useRef, useCallback, useMemo, useContext, useEffect, Children } from 'react';
2
2
  import useAsync from 'react-use/lib/useAsync';
3
3
  import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
4
- import { makeStyles, Box, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody, Chip, Tooltip as Tooltip$1, IconButton as IconButton$1, Divider as Divider$1, Card as Card$1, List as List$1, MenuItem, ListItemIcon as ListItemIcon$1, ListItemText as ListItemText$1 } from '@material-ui/core';
4
+ import { makeStyles, Box, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody, Collapse, Card, List, MenuItem, ListItemIcon, ListItemText, Tooltip, IconButton as IconButton$1, Divider as Divider$1 } from '@material-ui/core';
5
5
  import classNames from 'classnames';
6
6
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
7
- import { useApi, useRouteRef } from '@backstage/core-plugin-api';
8
- import { Progress, ErrorPage, MarkdownContent, Page, Header, Content, CodeSnippet, ErrorPanel, LogViewer, StatusError, StatusOK, StatusPending, Lifecycle, EmptyState, Table as Table$1, Link } from '@backstage/core-components';
9
- import Card from '@material-ui/core/Card';
10
- import CardActionArea from '@material-ui/core/CardActionArea';
11
- import CardContent from '@material-ui/core/CardContent';
12
- import Tooltip from '@material-ui/core/Tooltip';
13
- import Typography$1 from '@material-ui/core/Typography';
14
- import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
15
- import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
7
+ import ExpandLessIcon from '@material-ui/icons/ExpandLess';
8
+ import { useApi } from '@backstage/core-plugin-api';
9
+ import { Progress, ErrorPage, MarkdownContent, Page, Header, Content, CodeSnippet, ErrorPanel, LogViewer } from '@backstage/core-components';
10
+ import Chip from '@material-ui/core/Chip';
11
+ import SettingsIcon from '@material-ui/icons/Settings';
12
+ import AllIcon from '@material-ui/icons/FontDownload';
16
13
  import Accordion$1 from '@material-ui/core/Accordion';
17
14
  import AccordionDetails$1 from '@material-ui/core/AccordionDetails';
18
15
  import AccordionSummary$1 from '@material-ui/core/AccordionSummary';
19
16
  import Divider from '@material-ui/core/Divider';
20
- import ExpandMoreIcon$1 from '@material-ui/icons/ExpandLess';
17
+ import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
18
+ import Typography$1 from '@material-ui/core/Typography';
21
19
  import { useAsync as useAsync$1, useRerender, usePrevious, useKeyboardEvent } from '@react-hookz/web';
22
20
  import yaml from 'yaml';
23
21
  import IconButton from '@material-ui/core/IconButton';
24
- import List from '@material-ui/core/List';
22
+ import List$1 from '@material-ui/core/List';
25
23
  import ListItem from '@material-ui/core/ListItem';
26
- import ListItemIcon from '@material-ui/core/ListItemIcon';
24
+ import ListItemIcon$1 from '@material-ui/core/ListItemIcon';
27
25
  import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
28
- import ListItemText from '@material-ui/core/ListItemText';
26
+ import ListItemText$1 from '@material-ui/core/ListItemText';
29
27
  import Cancel from '@material-ui/icons/Cancel';
30
28
  import Check from '@material-ui/icons/Check';
31
29
  import DeleteIcon from '@material-ui/icons/Delete';
@@ -35,7 +33,7 @@ import Box$1 from '@material-ui/core/Box';
35
33
  import Tab from '@material-ui/core/Tab';
36
34
  import Tabs from '@material-ui/core/Tabs';
37
35
  import CodeMirror from '@uiw/react-codemirror';
38
- import { g as TaskStatusStepper, h as TaskPageLinks, E as EntityPicker, i as EntityPickerSchema, j as EntityNamePicker, k as entityNamePickerValidation, m as EntityNamePickerSchema, n as EntityTagsPicker, o as EntityTagsPickerSchema, R as RepoUrlPicker, p as repoPickerValidation, q as RepoUrlPickerSchema, O as OwnerPicker, t as OwnerPickerSchema, u as OwnedEntityPicker, w as OwnedEntityPickerSchema, d as rootRouteRef } from './index-8321766a.esm.js';
36
+ import { l as TaskStatusStepper, n as TaskPageLinks } from './TaskPage-f304e0fc.esm.js';
39
37
  import CloseIcon from '@material-ui/icons/Close';
40
38
  import RefreshIcon from '@material-ui/icons/Refresh';
41
39
  import SaveIcon from '@material-ui/icons/Save';
@@ -43,12 +41,11 @@ import TreeView from '@material-ui/lab/TreeView';
43
41
  import ChevronRightIcon from '@material-ui/icons/ChevronRight';
44
42
  import TreeItem from '@material-ui/lab/TreeItem';
45
43
  import { showPanel } from '@codemirror/view';
46
- import { catalogApiRef, EntityRefLink, CatalogFilterLayout } from '@backstage/plugin-catalog-react';
47
- import SettingsIcon from '@material-ui/icons/Settings';
48
- import AllIcon from '@material-ui/icons/FontDownload';
49
- import { DateTime, Interval } from 'luxon';
50
- import humanizeDuration from 'humanize-duration';
51
- import { parseEntityRef } from '@backstage/catalog-model';
44
+ import Card$1 from '@material-ui/core/Card';
45
+ import CardActionArea from '@material-ui/core/CardActionArea';
46
+ import CardContent from '@material-ui/core/CardContent';
47
+ import Tooltip$1 from '@material-ui/core/Tooltip';
48
+ import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
52
49
 
53
50
  const useStyles$9 = makeStyles((theme) => ({
54
51
  code: {
@@ -90,6 +87,7 @@ const ActionsPage = () => {
90
87
  const { loading, value, error } = useAsync(async () => {
91
88
  return api.listActions();
92
89
  });
90
+ const [isExpanded, setIsExpanded] = useState({});
93
91
  if (loading) {
94
92
  return /* @__PURE__ */ React.createElement(Progress, null);
95
93
  }
@@ -102,40 +100,86 @@ const ActionsPage = () => {
102
100
  }
103
101
  );
104
102
  }
105
- const formatRows = (input) => {
106
- const properties = input.properties;
103
+ const renderTable = (rows) => {
104
+ if (!rows || rows.length < 1) {
105
+ return /* @__PURE__ */ React.createElement(Typography, null, "No schema defined");
106
+ }
107
+ 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, rows)));
108
+ };
109
+ const getTypes = (properties) => {
110
+ var _a, _b;
111
+ if (!properties.type) {
112
+ return ["unknown"];
113
+ }
114
+ if (properties.type !== "array") {
115
+ return [properties.type].flat();
116
+ }
117
+ return [
118
+ `${properties.type}(${(_b = (_a = properties.items) == null ? void 0 : _a.type) != null ? _b : "unknown"})`
119
+ ];
120
+ };
121
+ const formatRows = (parentId, input) => {
122
+ const properties = input == null ? void 0 : input.properties;
107
123
  if (!properties) {
108
124
  return void 0;
109
125
  }
110
126
  return Object.entries(properties).map((entry) => {
111
- var _a;
127
+ var _a, _b, _c;
112
128
  const [key] = entry;
129
+ const id = `${parentId}.${key}`;
113
130
  const props = entry[1];
114
131
  const codeClassname = classNames(classes.code, {
115
132
  [classes.codeRequired]: (_a = input.required) == null ? void 0 : _a.includes(key)
116
133
  });
117
- 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 })))));
134
+ const types = getTypes(props);
135
+ return /* @__PURE__ */ React.createElement(React.Fragment, { key: id }, /* @__PURE__ */ React.createElement(TableRow, { key: id }, /* @__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, types.map(
136
+ (type) => type.includes("object") ? /* @__PURE__ */ React.createElement(
137
+ Chip,
138
+ {
139
+ label: type,
140
+ key: type,
141
+ icon: isExpanded[id] ? /* @__PURE__ */ React.createElement(ExpandLessIcon, null) : /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
142
+ variant: "outlined",
143
+ onClick: () => setIsExpanded((prevState) => {
144
+ const state = { ...prevState };
145
+ state[id] = !prevState[id];
146
+ return state;
147
+ })
148
+ }
149
+ ) : /* @__PURE__ */ React.createElement(Chip, { label: type, key: type, variant: "outlined" })
150
+ ))), /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { style: { paddingBottom: 0, paddingTop: 0 }, colSpan: 6 }, /* @__PURE__ */ React.createElement(Collapse, { in: isExpanded[id], timeout: "auto", unmountOnExit: true }, /* @__PURE__ */ React.createElement(Box, { sx: { margin: 1 } }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", component: "div" }, key), renderTable(
151
+ formatRows(
152
+ id,
153
+ props.type === "array" ? {
154
+ properties: (_c = (_b = props.items) == null ? void 0 : _b.properties) != null ? _c : {}
155
+ } : props
156
+ )
157
+ ))))));
118
158
  });
119
159
  };
120
- const renderTable = (input) => {
121
- if (!input.properties) {
122
- return void 0;
123
- }
124
- 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))));
125
- };
126
- const renderTables = (name, input) => {
160
+ const renderTables = (name, id, input) => {
127
161
  if (!input) {
128
162
  return void 0;
129
163
  }
130
- 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))));
164
+ 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(
165
+ formatRows(`${id}.${index}`, i)
166
+ ))));
131
167
  };
132
168
  const items = value == null ? void 0 : value.map((action) => {
133
- var _a, _b, _c, _d;
169
+ var _a, _b, _c, _d, _e, _f;
134
170
  if (action.id.startsWith("legacy:")) {
135
171
  return void 0;
136
172
  }
137
- const oneOf = renderTables("oneOf", (_b = (_a = action.schema) == null ? void 0 : _a.input) == null ? void 0 : _b.oneOf);
138
- 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 })))));
173
+ const oneOf = renderTables(
174
+ "oneOf",
175
+ `${action.id}.input`,
176
+ (_b = (_a = action.schema) == null ? void 0 : _a.input) == null ? void 0 : _b.oneOf
177
+ );
178
+ 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(
179
+ formatRows(`${action.id}.input`, (_d = action == null ? void 0 : action.schema) == null ? void 0 : _d.input)
180
+ ), oneOf), ((_e = action.schema) == null ? void 0 : _e.output) && /* @__PURE__ */ React.createElement(Box, { pb: 2 }, /* @__PURE__ */ React.createElement(Typography, { variant: "h5" }, "Output"), renderTable(
181
+ formatRows(`${action.id}.output`, (_f = action == null ? void 0 : action.schema) == null ? void 0 : _f.output)
182
+ )), 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 })))));
139
183
  });
140
184
  return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
141
185
  Header,
@@ -147,6 +191,73 @@ const ActionsPage = () => {
147
191
  ), /* @__PURE__ */ React.createElement(Content, null, items));
148
192
  };
149
193
 
194
+ const useStyles$8 = makeStyles(
195
+ (theme) => ({
196
+ root: {
197
+ backgroundColor: "rgba(0, 0, 0, .11)",
198
+ boxShadow: "none",
199
+ margin: theme.spacing(1, 0, 1, 0)
200
+ },
201
+ title: {
202
+ margin: theme.spacing(1, 0, 0, 1),
203
+ textTransform: "uppercase",
204
+ fontSize: 12,
205
+ fontWeight: "bold"
206
+ },
207
+ listIcon: {
208
+ minWidth: 30,
209
+ color: theme.palette.text.primary
210
+ },
211
+ menuItem: {
212
+ minHeight: theme.spacing(6)
213
+ },
214
+ groupWrapper: {
215
+ margin: theme.spacing(1, 1, 2, 1)
216
+ }
217
+ }),
218
+ {
219
+ name: "ScaffolderReactOwnerListPicker"
220
+ }
221
+ );
222
+ function getFilterGroups() {
223
+ return [
224
+ {
225
+ name: "Task Owner",
226
+ items: [
227
+ {
228
+ id: "owned",
229
+ label: "Owned",
230
+ icon: SettingsIcon
231
+ },
232
+ {
233
+ id: "all",
234
+ label: "All",
235
+ icon: AllIcon
236
+ }
237
+ ]
238
+ }
239
+ ];
240
+ }
241
+ const OwnerListPicker = (props) => {
242
+ const { filter, onSelectOwner } = props;
243
+ const classes = useStyles$8();
244
+ const filterGroups = getFilterGroups();
245
+ 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(
246
+ MenuItem,
247
+ {
248
+ key: item.id,
249
+ button: true,
250
+ divider: true,
251
+ onClick: () => onSelectOwner(item.id),
252
+ selected: item.id === filter,
253
+ className: classes.menuItem,
254
+ "data-testid": `owner-picker-${item.id}`
255
+ },
256
+ item.icon && /* @__PURE__ */ React.createElement(ListItemIcon, { className: classes.listIcon }, /* @__PURE__ */ React.createElement(item.icon, { fontSize: "small" })),
257
+ /* @__PURE__ */ React.createElement(ListItemText, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, item.label))
258
+ )))))));
259
+ };
260
+
150
261
  const showDirectoryPicker = window.showDirectoryPicker;
151
262
  class WebFileAccess {
152
263
  constructor(path, handle) {
@@ -201,6 +312,109 @@ class WebFileSystemAccess {
201
312
  }
202
313
  }
203
314
 
315
+ const MAX_CONTENT_SIZE = 64 * 1024;
316
+ const CHUNK_SIZE = 32 * 1024;
317
+ const DryRunContext = createContext(void 0);
318
+ function base64EncodeContent(content) {
319
+ if (content.length > MAX_CONTENT_SIZE) {
320
+ return window.btoa("<file too large>");
321
+ }
322
+ try {
323
+ return window.btoa(content);
324
+ } catch {
325
+ const decoder = new TextEncoder();
326
+ const buffer = decoder.encode(content);
327
+ const chunks = new Array();
328
+ for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
329
+ chunks.push(
330
+ String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE))
331
+ );
332
+ }
333
+ return window.btoa(chunks.join(""));
334
+ }
335
+ }
336
+ function DryRunProvider(props) {
337
+ const scaffolderApi = useApi(scaffolderApiRef);
338
+ const [state, setState] = useState({
339
+ results: [],
340
+ selectedResult: void 0
341
+ });
342
+ const idRef = useRef(1);
343
+ const selectResult = useCallback((id) => {
344
+ setState((prevState) => {
345
+ const result = prevState.results.find((r) => r.id === id);
346
+ if (result === prevState.selectedResult) {
347
+ return prevState;
348
+ }
349
+ return {
350
+ results: prevState.results,
351
+ selectedResult: result
352
+ };
353
+ });
354
+ }, []);
355
+ const deleteResult = useCallback((id) => {
356
+ setState((prevState) => {
357
+ var _a;
358
+ const index = prevState.results.findIndex((r) => r.id === id);
359
+ if (index === -1) {
360
+ return prevState;
361
+ }
362
+ const newResults = prevState.results.slice();
363
+ const [deleted] = newResults.splice(index, 1);
364
+ return {
365
+ results: newResults,
366
+ selectedResult: ((_a = prevState.selectedResult) == null ? void 0 : _a.id) === deleted.id ? newResults[0] : prevState.selectedResult
367
+ };
368
+ });
369
+ }, []);
370
+ const execute = useCallback(
371
+ async (options) => {
372
+ if (!scaffolderApi.dryRun) {
373
+ throw new Error("Scaffolder API does not support dry-run");
374
+ }
375
+ const parsed = yaml.parse(options.templateContent);
376
+ const response = await scaffolderApi.dryRun({
377
+ template: parsed,
378
+ values: options.values,
379
+ secrets: {},
380
+ directoryContents: options.files.map((file) => ({
381
+ path: file.path,
382
+ base64Content: base64EncodeContent(file.content)
383
+ }))
384
+ });
385
+ const result = {
386
+ ...response,
387
+ id: idRef.current++
388
+ };
389
+ setState((prevState) => {
390
+ var _a;
391
+ return {
392
+ results: [...prevState.results, result],
393
+ selectedResult: (_a = prevState.selectedResult) != null ? _a : result
394
+ };
395
+ });
396
+ },
397
+ [scaffolderApi]
398
+ );
399
+ const dryRun = useMemo(
400
+ () => ({
401
+ ...state,
402
+ selectResult,
403
+ deleteResult,
404
+ execute
405
+ }),
406
+ [state, selectResult, deleteResult, execute]
407
+ );
408
+ return /* @__PURE__ */ React.createElement(DryRunContext.Provider, { value: dryRun }, props.children);
409
+ }
410
+ function useDryRun() {
411
+ const value = useContext(DryRunContext);
412
+ if (!value) {
413
+ throw new Error("must be used within a DryRunProvider");
414
+ }
415
+ return value;
416
+ }
417
+
204
418
  var __accessCheck = (obj, member, msg) => {
205
419
  if (!member.has(obj))
206
420
  throw TypeError("Cannot " + msg);
@@ -307,255 +521,72 @@ class DirectoryEditorManager {
307
521
  }
308
522
  async save() {
309
523
  await Promise.all(__privateGet(this, _files).map((file) => file.save()));
310
- }
311
- async reload() {
312
- var _a;
313
- const selectedPath = (_a = __privateGet(this, _selectedFile)) == null ? void 0 : _a.path;
314
- const files = await __privateGet(this, _access2).listFiles();
315
- const fileManagers = await Promise.all(
316
- files.map(async (file) => {
317
- const manager = new DirectoryEditorFileManager(
318
- file,
319
- __privateGet(this, _signalUpdate2)
320
- );
321
- await manager.reload();
322
- return manager;
323
- })
324
- );
325
- __privateGet(this, _files).length = 0;
326
- __privateGet(this, _files).push(...fileManagers);
327
- this.setSelectedFile(selectedPath);
328
- __privateGet(this, _signalUpdate2).call(this);
329
- }
330
- subscribe(listener) {
331
- __privateGet(this, _listeners).add(listener);
332
- return () => {
333
- __privateGet(this, _listeners).delete(listener);
334
- };
335
- }
336
- }
337
- _access2 = new WeakMap();
338
- _listeners = new WeakMap();
339
- _files = new WeakMap();
340
- _selectedFile = new WeakMap();
341
- _signalUpdate2 = new WeakMap();
342
- const DirectoryEditorContext = createContext(
343
- void 0
344
- );
345
- function useDirectoryEditor() {
346
- const value = useContext(DirectoryEditorContext);
347
- const rerender = useRerender();
348
- useEffect(() => value == null ? void 0 : value.subscribe(rerender), [value, rerender]);
349
- if (!value) {
350
- throw new Error("must be used within a DirectoryEditorProvider");
351
- }
352
- return value;
353
- }
354
- function DirectoryEditorProvider(props) {
355
- const { directory } = props;
356
- const [{ result, error }, { execute }] = useAsync$1(
357
- async (dir) => {
358
- const manager = new DirectoryEditorManager(dir);
359
- await manager.reload();
360
- const firstYaml = manager.files.find((file) => file.path.match(/\.ya?ml$/));
361
- if (firstYaml) {
362
- manager.setSelectedFile(firstYaml.path);
363
- }
364
- return manager;
365
- }
366
- );
367
- useEffect(() => {
368
- execute(directory);
369
- }, [execute, directory]);
370
- if (error) {
371
- return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
372
- } else if (!result) {
373
- return /* @__PURE__ */ React.createElement(Progress, null);
374
- }
375
- return /* @__PURE__ */ React.createElement(DirectoryEditorContext.Provider, { value: result }, props.children);
376
- }
377
-
378
- const MAX_CONTENT_SIZE = 64 * 1024;
379
- const CHUNK_SIZE = 32 * 1024;
380
- const DryRunContext = createContext(void 0);
381
- function base64EncodeContent(content) {
382
- if (content.length > MAX_CONTENT_SIZE) {
383
- return window.btoa("<file too large>");
384
- }
385
- try {
386
- return window.btoa(content);
387
- } catch {
388
- const decoder = new TextEncoder();
389
- const buffer = decoder.encode(content);
390
- const chunks = new Array();
391
- for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
392
- chunks.push(
393
- String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE))
394
- );
395
- }
396
- return window.btoa(chunks.join(""));
397
- }
398
- }
399
- function DryRunProvider(props) {
400
- const scaffolderApi = useApi(scaffolderApiRef);
401
- const [state, setState] = useState({
402
- results: [],
403
- selectedResult: void 0
404
- });
405
- const idRef = useRef(1);
406
- const selectResult = useCallback((id) => {
407
- setState((prevState) => {
408
- const result = prevState.results.find((r) => r.id === id);
409
- if (result === prevState.selectedResult) {
410
- return prevState;
411
- }
412
- return {
413
- results: prevState.results,
414
- selectedResult: result
415
- };
416
- });
417
- }, []);
418
- const deleteResult = useCallback((id) => {
419
- setState((prevState) => {
420
- var _a;
421
- const index = prevState.results.findIndex((r) => r.id === id);
422
- if (index === -1) {
423
- return prevState;
424
- }
425
- const newResults = prevState.results.slice();
426
- const [deleted] = newResults.splice(index, 1);
427
- return {
428
- results: newResults,
429
- selectedResult: ((_a = prevState.selectedResult) == null ? void 0 : _a.id) === deleted.id ? newResults[0] : prevState.selectedResult
430
- };
431
- });
432
- }, []);
433
- const execute = useCallback(
434
- async (options) => {
435
- if (!scaffolderApi.dryRun) {
436
- throw new Error("Scaffolder API does not support dry-run");
437
- }
438
- const parsed = yaml.parse(options.templateContent);
439
- const response = await scaffolderApi.dryRun({
440
- template: parsed,
441
- values: options.values,
442
- secrets: {},
443
- directoryContents: options.files.map((file) => ({
444
- path: file.path,
445
- base64Content: base64EncodeContent(file.content)
446
- }))
447
- });
448
- const result = {
449
- ...response,
450
- id: idRef.current++
451
- };
452
- setState((prevState) => {
453
- var _a;
454
- return {
455
- results: [...prevState.results, result],
456
- selectedResult: (_a = prevState.selectedResult) != null ? _a : result
457
- };
458
- });
459
- },
460
- [scaffolderApi]
461
- );
462
- const dryRun = useMemo(
463
- () => ({
464
- ...state,
465
- selectResult,
466
- deleteResult,
467
- execute
468
- }),
469
- [state, selectResult, deleteResult, execute]
470
- );
471
- return /* @__PURE__ */ React.createElement(DryRunContext.Provider, { value: dryRun }, props.children);
472
- }
473
- function useDryRun() {
474
- const value = useContext(DryRunContext);
475
- if (!value) {
476
- throw new Error("must be used within a DryRunProvider");
477
- }
478
- return value;
479
- }
480
-
481
- const useStyles$8 = makeStyles$1((theme) => ({
482
- introText: {
483
- textAlign: "center",
484
- marginTop: theme.spacing(2)
485
- },
486
- card: {
487
- position: "relative",
488
- maxWidth: 340,
489
- marginTop: theme.spacing(4),
490
- margin: theme.spacing(0, 2)
491
- },
492
- infoIcon: {
493
- position: "absolute",
494
- top: theme.spacing(1),
495
- right: theme.spacing(1)
496
- }
497
- }));
498
- function TemplateEditorIntro(props) {
499
- const classes = useStyles$8();
500
- const supportsLoad = WebFileSystemAccess.isSupported();
501
- const cardLoadLocal = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(
502
- CardActionArea,
503
- {
504
- disabled: !supportsLoad,
505
- onClick: () => {
506
- var _a;
507
- return (_a = props.onSelect) == null ? void 0 : _a.call(props, "local");
508
- }
509
- },
510
- /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
511
- Typography$1,
512
- {
513
- variant: "h5",
514
- gutterBottom: true,
515
- color: supportsLoad ? void 0 : "textSecondary",
516
- style: { display: "flex", flexFlow: "row nowrap" }
517
- },
518
- "Load Template Directory"
519
- ), /* @__PURE__ */ React.createElement(
520
- Typography$1,
521
- {
522
- variant: "body1",
523
- color: supportsLoad ? void 0 : "textSecondary"
524
- },
525
- "Load a local template directory, allowing you to both edit and try executing your own template."
526
- ))
527
- ), !supportsLoad && /* @__PURE__ */ React.createElement("div", { className: classes.infoIcon }, /* @__PURE__ */ React.createElement(
528
- Tooltip,
529
- {
530
- placement: "top",
531
- title: "Only supported in some Chromium-based browsers"
532
- },
533
- /* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
534
- )));
535
- const cardFormEditor = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
536
- var _a;
537
- return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
538
- } }, /* @__PURE__ */ React.createElement(CardContent, 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."))));
539
- const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
540
- var _a;
541
- return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
542
- } }, /* @__PURE__ */ React.createElement(CardContent, 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."))));
543
- 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(
544
- "div",
545
- {
546
- style: {
547
- display: "flex",
548
- flexFlow: "row wrap",
549
- alignItems: "flex-start",
550
- justifyContent: "center",
551
- alignContent: "flex-start"
524
+ }
525
+ async reload() {
526
+ var _a;
527
+ const selectedPath = (_a = __privateGet(this, _selectedFile)) == null ? void 0 : _a.path;
528
+ const files = await __privateGet(this, _access2).listFiles();
529
+ const fileManagers = await Promise.all(
530
+ files.map(async (file) => {
531
+ const manager = new DirectoryEditorFileManager(
532
+ file,
533
+ __privateGet(this, _signalUpdate2)
534
+ );
535
+ await manager.reload();
536
+ return manager;
537
+ })
538
+ );
539
+ __privateGet(this, _files).length = 0;
540
+ __privateGet(this, _files).push(...fileManagers);
541
+ this.setSelectedFile(selectedPath);
542
+ __privateGet(this, _signalUpdate2).call(this);
543
+ }
544
+ subscribe(listener) {
545
+ __privateGet(this, _listeners).add(listener);
546
+ return () => {
547
+ __privateGet(this, _listeners).delete(listener);
548
+ };
549
+ }
550
+ }
551
+ _access2 = new WeakMap();
552
+ _listeners = new WeakMap();
553
+ _files = new WeakMap();
554
+ _selectedFile = new WeakMap();
555
+ _signalUpdate2 = new WeakMap();
556
+ const DirectoryEditorContext = createContext(
557
+ void 0
558
+ );
559
+ function useDirectoryEditor() {
560
+ const value = useContext(DirectoryEditorContext);
561
+ const rerender = useRerender();
562
+ useEffect(() => value == null ? void 0 : value.subscribe(rerender), [value, rerender]);
563
+ if (!value) {
564
+ throw new Error("must be used within a DirectoryEditorProvider");
565
+ }
566
+ return value;
567
+ }
568
+ function DirectoryEditorProvider(props) {
569
+ const { directory } = props;
570
+ const [{ result, error }, { execute }] = useAsync$1(
571
+ async (dir) => {
572
+ const manager = new DirectoryEditorManager(dir);
573
+ await manager.reload();
574
+ const firstYaml = manager.files.find((file) => file.path.match(/\.ya?ml$/));
575
+ if (firstYaml) {
576
+ manager.setSelectedFile(firstYaml.path);
552
577
  }
553
- },
554
- supportsLoad && cardLoadLocal,
555
- cardFormEditor,
556
- !supportsLoad && cardLoadLocal,
557
- cardFieldExplorer
558
- ));
578
+ return manager;
579
+ }
580
+ );
581
+ useEffect(() => {
582
+ execute(directory);
583
+ }, [execute, directory]);
584
+ if (error) {
585
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
586
+ } else if (!result) {
587
+ return /* @__PURE__ */ React.createElement(Progress, null);
588
+ }
589
+ return /* @__PURE__ */ React.createElement(DirectoryEditorContext.Provider, { value: result }, props.children);
559
590
  }
560
591
 
561
592
  const useStyles$7 = makeStyles$1((theme) => ({
@@ -577,7 +608,7 @@ const useStyles$7 = makeStyles$1((theme) => ({
577
608
  function DryRunResultsList() {
578
609
  const classes = useStyles$7();
579
610
  const dryRun = useDryRun();
580
- return /* @__PURE__ */ React.createElement(List, { className: classes.root, dense: true }, dryRun.results.map((result) => {
611
+ return /* @__PURE__ */ React.createElement(List$1, { className: classes.root, dense: true }, dryRun.results.map((result) => {
581
612
  var _a;
582
613
  const failed = result.log.some((l) => l.body.status === "failed");
583
614
  return /* @__PURE__ */ React.createElement(
@@ -589,13 +620,13 @@ function DryRunResultsList() {
589
620
  onClick: () => dryRun.selectResult(result.id)
590
621
  },
591
622
  /* @__PURE__ */ React.createElement(
592
- ListItemIcon,
623
+ ListItemIcon$1,
593
624
  {
594
625
  className: failed ? classes.iconFailure : classes.iconSuccess
595
626
  },
596
627
  failed ? /* @__PURE__ */ React.createElement(Cancel, null) : /* @__PURE__ */ React.createElement(Check, null)
597
628
  ),
598
- /* @__PURE__ */ React.createElement(ListItemText, { primary: `Result ${result.id}` }),
629
+ /* @__PURE__ */ React.createElement(ListItemText$1, { primary: `Result ${result.id}` }),
599
630
  /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(
600
631
  IconButton,
601
632
  {
@@ -887,7 +918,7 @@ function DryRunResults() {
887
918
  AccordionSummary$1,
888
919
  {
889
920
  className: classes.header,
890
- expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon$1, null)
921
+ expandIcon: /* @__PURE__ */ React.createElement(ExpandLessIcon, null)
891
922
  },
892
923
  /* @__PURE__ */ React.createElement(Typography$1, null, "Dry-run results")
893
924
  ),
@@ -932,7 +963,7 @@ function TemplateEditorBrowser(props) {
932
963
  }
933
964
  props.onClose();
934
965
  };
935
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: classes.buttons }, /* @__PURE__ */ React.createElement(Tooltip$1, { title: "Save all files" }, /* @__PURE__ */ React.createElement(
966
+ 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(
936
967
  IconButton$1,
937
968
  {
938
969
  className: classes.button,
@@ -940,14 +971,14 @@ function TemplateEditorBrowser(props) {
940
971
  onClick: () => directoryEditor.save()
941
972
  },
942
973
  /* @__PURE__ */ React.createElement(SaveIcon, null)
943
- )), /* @__PURE__ */ React.createElement(Tooltip$1, { title: "Reload directory" }, /* @__PURE__ */ React.createElement(
974
+ )), /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload directory" }, /* @__PURE__ */ React.createElement(
944
975
  IconButton$1,
945
976
  {
946
977
  className: classes.button,
947
978
  onClick: () => directoryEditor.reload()
948
979
  },
949
980
  /* @__PURE__ */ React.createElement(RefreshIcon, null)
950
- )), /* @__PURE__ */ React.createElement("div", { className: classes.buttonsGap }), /* @__PURE__ */ React.createElement(Tooltip$1, { title: "Close directory" }, /* @__PURE__ */ React.createElement(IconButton$1, { className: classes.button, onClick: handleClose }, /* @__PURE__ */ React.createElement(CloseIcon, null)))), /* @__PURE__ */ React.createElement(Divider$1, { className: classes.buttonsDivider }), /* @__PURE__ */ React.createElement(
981
+ )), /* @__PURE__ */ React.createElement("div", { className: classes.buttonsGap }), /* @__PURE__ */ React.createElement(Tooltip, { title: "Close directory" }, /* @__PURE__ */ React.createElement(IconButton$1, { className: classes.button, onClick: handleClose }, /* @__PURE__ */ React.createElement(CloseIcon, null)))), /* @__PURE__ */ React.createElement(Divider$1, { className: classes.buttonsDivider }), /* @__PURE__ */ React.createElement(
951
982
  FileBrowser,
952
983
  {
953
984
  selected: (_b = (_a = directoryEditor.selectedFile) == null ? void 0 : _a.path) != null ? _b : "",
@@ -1015,7 +1046,7 @@ function TemplateEditorTextArea(props) {
1015
1046
  value: props.content,
1016
1047
  onChange: props.onUpdate
1017
1048
  }
1018
- ), (props.onSave || props.onReload) && /* @__PURE__ */ React.createElement("div", { className: classes.floatingButtons }, /* @__PURE__ */ React.createElement(Paper, null, props.onSave && /* @__PURE__ */ React.createElement(Tooltip$1, { title: "Save file" }, /* @__PURE__ */ React.createElement(
1049
+ ), (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(
1019
1050
  IconButton$1,
1020
1051
  {
1021
1052
  className: classes.floatingButton,
@@ -1025,7 +1056,7 @@ function TemplateEditorTextArea(props) {
1025
1056
  }
1026
1057
  },
1027
1058
  /* @__PURE__ */ React.createElement(SaveIcon, null)
1028
- )), props.onReload && /* @__PURE__ */ React.createElement(Tooltip$1, { title: "Reload file" }, /* @__PURE__ */ React.createElement(
1059
+ )), props.onReload && /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload file" }, /* @__PURE__ */ React.createElement(
1029
1060
  IconButton$1,
1030
1061
  {
1031
1062
  className: classes.floatingButton,
@@ -1061,250 +1092,85 @@ function TemplateEditorDirectoryEditorTextArea(props) {
1061
1092
  }
1062
1093
  TemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;
1063
1094
 
1064
- const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [
1065
- {
1066
- component: EntityPicker,
1067
- name: "EntityPicker",
1068
- schema: EntityPickerSchema
1069
- },
1070
- {
1071
- component: EntityNamePicker,
1072
- name: "EntityNamePicker",
1073
- validation: entityNamePickerValidation,
1074
- schema: EntityNamePickerSchema
1075
- },
1076
- {
1077
- component: EntityTagsPicker,
1078
- name: "EntityTagsPicker",
1079
- schema: EntityTagsPickerSchema
1080
- },
1081
- {
1082
- component: RepoUrlPicker,
1083
- name: "RepoUrlPicker",
1084
- validation: repoPickerValidation,
1085
- schema: RepoUrlPickerSchema
1095
+ const useStyles = makeStyles$1((theme) => ({
1096
+ introText: {
1097
+ textAlign: "center",
1098
+ marginTop: theme.spacing(2)
1086
1099
  },
1087
- {
1088
- component: OwnerPicker,
1089
- name: "OwnerPicker",
1090
- schema: OwnerPickerSchema
1100
+ card: {
1101
+ position: "relative",
1102
+ maxWidth: 340,
1103
+ marginTop: theme.spacing(4),
1104
+ margin: theme.spacing(0, 2)
1091
1105
  },
1092
- {
1093
- component: OwnedEntityPicker,
1094
- name: "OwnedEntityPicker",
1095
- schema: OwnedEntityPickerSchema
1096
- }
1097
- ];
1098
-
1099
- const useStyles = makeStyles(
1100
- (theme) => ({
1101
- root: {
1102
- backgroundColor: "rgba(0, 0, 0, .11)",
1103
- boxShadow: "none",
1104
- margin: theme.spacing(1, 0, 1, 0)
1105
- },
1106
- title: {
1107
- margin: theme.spacing(1, 0, 0, 1),
1108
- textTransform: "uppercase",
1109
- fontSize: 12,
1110
- fontWeight: "bold"
1111
- },
1112
- listIcon: {
1113
- minWidth: 30,
1114
- color: theme.palette.text.primary
1115
- },
1116
- menuItem: {
1117
- minHeight: theme.spacing(6)
1118
- },
1119
- groupWrapper: {
1120
- margin: theme.spacing(1, 1, 2, 1)
1121
- }
1122
- }),
1123
- {
1124
- name: "ScaffolderReactOwnerListPicker"
1106
+ infoIcon: {
1107
+ position: "absolute",
1108
+ top: theme.spacing(1),
1109
+ right: theme.spacing(1)
1125
1110
  }
1126
- );
1127
- function getFilterGroups() {
1128
- return [
1129
- {
1130
- name: "Task Owner",
1131
- items: [
1132
- {
1133
- id: "owned",
1134
- label: "Owned",
1135
- icon: SettingsIcon
1136
- },
1137
- {
1138
- id: "all",
1139
- label: "All",
1140
- icon: AllIcon
1141
- }
1142
- ]
1143
- }
1144
- ];
1145
- }
1146
- const OwnerListPicker = (props) => {
1147
- const { filter, onSelectOwner } = props;
1111
+ }));
1112
+ function TemplateEditorIntro(props) {
1148
1113
  const classes = useStyles();
1149
- const filterGroups = getFilterGroups();
1150
- return /* @__PURE__ */ React.createElement(Card$1, { 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$1, { className: classes.groupWrapper }, /* @__PURE__ */ React.createElement(List$1, { disablePadding: true, dense: true }, group.items.map((item) => /* @__PURE__ */ React.createElement(
1151
- MenuItem,
1114
+ const supportsLoad = WebFileSystemAccess.isSupported();
1115
+ const cardLoadLocal = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(
1116
+ CardActionArea,
1152
1117
  {
1153
- key: item.id,
1154
- button: true,
1155
- divider: true,
1156
- onClick: () => onSelectOwner(item.id),
1157
- selected: item.id === filter,
1158
- className: classes.menuItem,
1159
- "data-testid": `owner-picker-${item.id}`
1118
+ disabled: !supportsLoad,
1119
+ onClick: () => {
1120
+ var _a;
1121
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "local");
1122
+ }
1160
1123
  },
1161
- item.icon && /* @__PURE__ */ React.createElement(ListItemIcon$1, { className: classes.listIcon }, /* @__PURE__ */ React.createElement(item.icon, { fontSize: "small" })),
1162
- /* @__PURE__ */ React.createElement(ListItemText$1, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, item.label))
1163
- )))))));
1164
- };
1165
-
1166
- const CreatedAtColumn = ({ createdAt }) => {
1167
- const createdAtTime = DateTime.fromISO(createdAt);
1168
- const formatted = Interval.fromDateTimes(createdAtTime, DateTime.local()).toDuration().valueOf();
1169
- return /* @__PURE__ */ React.createElement(Typography$1, { paragraph: true }, humanizeDuration(formatted, { round: true }), " ago");
1170
- };
1171
-
1172
- const OwnerEntityColumn = ({ entityRef }) => {
1173
- var _a, _b, _c;
1174
- const catalogApi = useApi(catalogApiRef);
1175
- const { value, loading, error } = useAsync(
1176
- () => catalogApi.getEntityByRef(entityRef || ""),
1177
- [catalogApi, entityRef]
1178
- );
1179
- if (!entityRef) {
1180
- return /* @__PURE__ */ React.createElement(Typography$1, { paragraph: true }, "Unknown");
1181
- }
1182
- if (loading || error) {
1183
- return null;
1184
- }
1185
- return /* @__PURE__ */ React.createElement(
1186
- EntityRefLink,
1187
- {
1188
- entityRef: parseEntityRef(entityRef),
1189
- title: (_c = (_b = (_a = value == null ? void 0 : value.spec) == null ? void 0 : _a.profile) == null ? void 0 : _b.displayName) != null ? _c : value == null ? void 0 : value.metadata.name
1190
- }
1191
- );
1192
- };
1193
-
1194
- const TaskStatusColumn = ({ status }) => {
1195
- switch (status) {
1196
- case "processing":
1197
- return /* @__PURE__ */ React.createElement(StatusPending, null, status);
1198
- case "completed":
1199
- return /* @__PURE__ */ React.createElement(StatusOK, null, status);
1200
- case "error":
1201
- default:
1202
- return /* @__PURE__ */ React.createElement(StatusError, null, status);
1203
- }
1204
- };
1205
-
1206
- const TemplateTitleColumn = ({ entityRef }) => {
1207
- const scaffolder = useApi(scaffolderApiRef);
1208
- const { value, loading, error } = useAsync(
1209
- () => scaffolder.getTemplateParameterSchema(entityRef || ""),
1210
- [scaffolder, entityRef]
1211
- );
1212
- if (loading || error || !entityRef) {
1213
- return null;
1214
- }
1215
- return /* @__PURE__ */ React.createElement(EntityRefLink, { entityRef: parseEntityRef(entityRef), title: value == null ? void 0 : value.title });
1216
- };
1217
-
1218
- const ListTaskPageContent = (props) => {
1219
- var _a;
1220
- const { initiallySelectedFilter = "owned" } = props;
1221
- const scaffolderApi = useApi(scaffolderApiRef);
1222
- const rootLink = useRouteRef(rootRouteRef);
1223
- const [ownerFilter, setOwnerFilter] = useState(initiallySelectedFilter);
1224
- const { value, loading, error } = useAsync(() => {
1225
- var _a2;
1226
- if (scaffolderApi.listTasks) {
1227
- return (_a2 = scaffolderApi.listTasks) == null ? void 0 : _a2.call(scaffolderApi, { filterByOwnership: ownerFilter });
1228
- }
1229
- console.warn(
1230
- "listTasks is not implemented in the scaffolderApi, please make sure to implement this method."
1231
- );
1232
- return Promise.resolve({ tasks: [] });
1233
- }, [scaffolderApi, ownerFilter]);
1234
- if (loading) {
1235
- return /* @__PURE__ */ React.createElement(Progress, null);
1236
- }
1237
- if (error) {
1238
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ErrorPanel, { error }), /* @__PURE__ */ React.createElement(
1239
- EmptyState,
1124
+ /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
1125
+ Typography$1,
1240
1126
  {
1241
- missing: "info",
1242
- title: "No information to display",
1243
- description: "There is no Tasks or there was an issue communicating with backend."
1244
- }
1245
- ));
1246
- }
1247
- return /* @__PURE__ */ React.createElement(CatalogFilterLayout, null, /* @__PURE__ */ React.createElement(CatalogFilterLayout.Filters, null, /* @__PURE__ */ React.createElement(
1248
- OwnerListPicker,
1249
- {
1250
- filter: ownerFilter,
1251
- onSelectOwner: (id) => setOwnerFilter(id)
1252
- }
1253
- )), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, /* @__PURE__ */ React.createElement(
1254
- Table$1,
1127
+ variant: "h5",
1128
+ gutterBottom: true,
1129
+ color: supportsLoad ? void 0 : "textSecondary",
1130
+ style: { display: "flex", flexFlow: "row nowrap" }
1131
+ },
1132
+ "Load Template Directory"
1133
+ ), /* @__PURE__ */ React.createElement(
1134
+ Typography$1,
1135
+ {
1136
+ variant: "body1",
1137
+ color: supportsLoad ? void 0 : "textSecondary"
1138
+ },
1139
+ "Load a local template directory, allowing you to both edit and try executing your own template."
1140
+ ))
1141
+ ), !supportsLoad && /* @__PURE__ */ React.createElement("div", { className: classes.infoIcon }, /* @__PURE__ */ React.createElement(
1142
+ Tooltip$1,
1255
1143
  {
1256
- data: (_a = value == null ? void 0 : value.tasks) != null ? _a : [],
1257
- title: "Tasks",
1258
- columns: [
1259
- {
1260
- title: "Task ID",
1261
- field: "id",
1262
- render: (row) => /* @__PURE__ */ React.createElement(Link, { to: `${rootLink()}/tasks/${row.id}` }, row.id)
1263
- },
1264
- {
1265
- title: "Template",
1266
- render: (row) => {
1267
- var _a2;
1268
- return /* @__PURE__ */ React.createElement(
1269
- TemplateTitleColumn,
1270
- {
1271
- entityRef: (_a2 = row.spec.templateInfo) == null ? void 0 : _a2.entityRef
1272
- }
1273
- );
1274
- }
1275
- },
1276
- {
1277
- title: "Created",
1278
- field: "createdAt",
1279
- render: (row) => /* @__PURE__ */ React.createElement(CreatedAtColumn, { createdAt: row.createdAt })
1280
- },
1281
- {
1282
- title: "Owner",
1283
- field: "createdBy",
1284
- render: (row) => {
1285
- var _a2, _b;
1286
- return /* @__PURE__ */ React.createElement(OwnerEntityColumn, { entityRef: (_b = (_a2 = row.spec) == null ? void 0 : _a2.user) == null ? void 0 : _b.ref });
1287
- }
1288
- },
1289
- {
1290
- title: "Status",
1291
- field: "status",
1292
- render: (row) => /* @__PURE__ */ React.createElement(TaskStatusColumn, { status: row.status })
1293
- }
1294
- ]
1295
- }
1144
+ placement: "top",
1145
+ title: "Only supported in some Chromium-based browsers"
1146
+ },
1147
+ /* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
1296
1148
  )));
1297
- };
1298
- const ListTasksPage = (props) => {
1299
- return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
1300
- Header,
1149
+ const cardFormEditor = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
1150
+ var _a;
1151
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
1152
+ } }, /* @__PURE__ */ React.createElement(CardContent, 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."))));
1153
+ const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card$1, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
1154
+ var _a;
1155
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
1156
+ } }, /* @__PURE__ */ React.createElement(CardContent, 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."))));
1157
+ 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(
1158
+ "div",
1301
1159
  {
1302
- pageTitleOverride: "Templates Tasks",
1303
- title: /* @__PURE__ */ React.createElement(React.Fragment, null, "List template tasks ", /* @__PURE__ */ React.createElement(Lifecycle, { shorthand: true, alpha: true })),
1304
- subtitle: "All tasks that have been started"
1305
- }
1306
- ), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ListTaskPageContent, { ...props })));
1307
- };
1160
+ style: {
1161
+ display: "flex",
1162
+ flexFlow: "row wrap",
1163
+ alignItems: "flex-start",
1164
+ justifyContent: "center",
1165
+ alignContent: "flex-start"
1166
+ }
1167
+ },
1168
+ supportsLoad && cardLoadLocal,
1169
+ cardFormEditor,
1170
+ !supportsLoad && cardLoadLocal,
1171
+ cardFieldExplorer
1172
+ ));
1173
+ }
1308
1174
 
1309
- export { ActionsPage as A, DirectoryEditorProvider as D, ListTasksPage as L, TemplateEditorBrowser as T, WebFileSystemAccess as W, useDirectoryEditor as a, DryRunProvider as b, TemplateEditorTextArea as c, DryRunResults as d, TemplateEditorIntro as e, DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS as f, useDryRun as u };
1310
- //# sourceMappingURL=ListTasksPage-64779a2d.esm.js.map
1175
+ export { ActionsPage as A, DirectoryEditorProvider as D, OwnerListPicker as O, TemplateEditorBrowser as T, WebFileSystemAccess as W, useDirectoryEditor as a, DryRunProvider as b, TemplateEditorTextArea as c, DryRunResults as d, TemplateEditorIntro as e, useDryRun as u };
1176
+ //# sourceMappingURL=TemplateEditorIntro-f7f6d664.esm.js.map