@backstage/plugin-scaffolder 0.0.0-nightly-20220601025619 → 0.0.0-nightly-20220602024936

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 CHANGED
@@ -1,9 +1,12 @@
1
1
  # @backstage/plugin-scaffolder
2
2
 
3
- ## 0.0.0-nightly-20220601025619
3
+ ## 0.0.0-nightly-20220602024936
4
4
 
5
5
  ### Minor Changes
6
6
 
7
+ - dc39366bdb: - Added a new page under `/create/tasks` to show tasks that have been run by the Scaffolder.
8
+ - Ability to filter these tasks by the signed in user, and all tasks.
9
+ - Added optional method to the `ScaffolderApi` interface called `listTasks` to get tasks with an required `filterByOwnership` parameter.
7
10
  - 86a4a0f72d: Get data of other fields in Form from a custom field in template Scaffolder.
8
11
  following:
9
12
 
@@ -26,18 +29,19 @@
26
29
 
27
30
  ### Patch Changes
28
31
 
32
+ - ac0c7e45ee: Fixes review mask in `MultistepJsonForm` to work as documented. `show: true` no longer needed when mask is set.
29
33
  - 8f7b1835df: Updated dependency `msw` to `^0.41.0`.
30
34
  - Updated dependencies
31
- - @backstage/plugin-catalog-react@0.0.0-nightly-20220601025619
32
- - @backstage/core-components@0.0.0-nightly-20220601025619
33
- - @backstage/integration@0.0.0-nightly-20220601025619
34
- - @backstage/catalog-client@0.0.0-nightly-20220601025619
35
- - @backstage/core-plugin-api@0.0.0-nightly-20220601025619
36
- - @backstage/integration-react@0.0.0-nightly-20220601025619
37
- - @backstage/catalog-model@0.0.0-nightly-20220601025619
38
- - @backstage/plugin-catalog-common@0.0.0-nightly-20220601025619
39
- - @backstage/plugin-permission-react@0.0.0-nightly-20220601025619
40
- - @backstage/plugin-scaffolder-common@0.0.0-nightly-20220601025619
35
+ - @backstage/plugin-catalog-react@0.0.0-nightly-20220602024936
36
+ - @backstage/core-components@0.0.0-nightly-20220602024936
37
+ - @backstage/integration@0.0.0-nightly-20220602024936
38
+ - @backstage/catalog-client@0.0.0-nightly-20220602024936
39
+ - @backstage/core-plugin-api@0.0.0-nightly-20220602024936
40
+ - @backstage/integration-react@0.0.0-nightly-20220602024936
41
+ - @backstage/catalog-model@0.0.0-nightly-20220602024936
42
+ - @backstage/plugin-catalog-common@0.0.0-nightly-20220602024936
43
+ - @backstage/plugin-permission-react@0.0.0-nightly-20220602024936
44
+ - @backstage/plugin-scaffolder-common@0.0.0-nightly-20220602024936
41
45
 
42
46
  ## 1.3.0-next.1
43
47
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder",
3
- "version": "0.0.0-nightly-20220601025619",
3
+ "version": "0.0.0-nightly-20220602024936",
4
4
  "main": "../dist/index.esm.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -1,11 +1,11 @@
1
- import React, { useState, useContext, useCallback, createContext, useEffect, useRef, useMemo, Children, Component } from 'react';
1
+ import React, { useState, useContext, useCallback, createContext, useEffect, useRef, useMemo, Children, Component, Fragment } from 'react';
2
2
  import { useNavigate, Navigate, useOutlet, Routes, Route } from 'react-router';
3
- import { ItemCardHeader, MarkdownContent, Button, ContentHeader, Progress, WarningPanel, Link as Link$1, Content, ItemCardGrid, Page, Header, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage, ErrorPanel, LogViewer } from '@backstage/core-components';
3
+ import { ItemCardHeader, MarkdownContent, Button, ContentHeader, Progress, WarningPanel, Link as Link$1, Content, ItemCardGrid, Page, Header, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage, ErrorPanel, LogViewer, StatusError, StatusOK, StatusPending, Lifecycle, EmptyState } from '@backstage/core-components';
4
4
  import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, alertApiRef, useElementFilter } from '@backstage/core-plugin-api';
5
- import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, catalogApiRef, humanizeEntityRef } from '@backstage/plugin-catalog-react';
6
- import { s as selectedTemplateRouteRef, r as rootRouteRef, a as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, b as scaffolderApiRef, c as scaffolderTaskRouteRef, d as TaskStatusStepper, e as TaskPageLinks, F as FIELD_EXTENSION_WRAPPER_KEY, f as FIELD_EXTENSION_KEY, g as SecretsContextProvider, h as actionsRouteRef, i as editRouteRef, j as TaskPage } from './index-6a2f3be9.esm.js';
7
- import { RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
8
- import { makeStyles, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, IconButton, Tooltip, Link, Stepper, Step, StepLabel, StepContent, Button as Button$1, Paper, LinearProgress, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Divider as Divider$1, FormControl, InputLabel, Select, MenuItem as MenuItem$1 } from '@material-ui/core';
5
+ import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, catalogApiRef, humanizeEntityRef, EntityRefLink } from '@backstage/plugin-catalog-react';
6
+ import { s as selectedTemplateRouteRef, e as editRouteRef, a as actionsRouteRef, b as scaffolderListTaskRouteRef, r as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, c as scaffolderApiRef, d as scaffolderTaskRouteRef, f as rootRouteRef, g as TaskStatusStepper, h as TaskPageLinks, F as FIELD_EXTENSION_WRAPPER_KEY, i as FIELD_EXTENSION_KEY, j as SecretsContextProvider, k as TaskPage } from './index-742a34c6.esm.js';
7
+ import { RELATION_OWNED_BY, stringifyEntityRef, parseEntityRef } from '@backstage/catalog-model';
8
+ import { makeStyles, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, IconButton, Tooltip, Link, Stepper, Step, StepLabel, StepContent, Button as Button$1, Paper, LinearProgress, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, Divider as Divider$1, FormControl, InputLabel, Select, MenuItem as MenuItem$1, List as List$2, ListItemIcon as ListItemIcon$1, ListItemText as ListItemText$1 } from '@material-ui/core';
9
9
  import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
10
10
  import WarningIcon from '@material-ui/icons/Warning';
11
11
  import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
@@ -19,6 +19,7 @@ import Popover from '@material-ui/core/Popover';
19
19
  import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
20
20
  import Description from '@material-ui/icons/Description';
21
21
  import Edit from '@material-ui/icons/Edit';
22
+ import List from '@material-ui/icons/List';
22
23
  import MoreVert from '@material-ui/icons/MoreVert';
23
24
  import qs from 'qs';
24
25
  import { useParams } from 'react-router-dom';
@@ -40,7 +41,7 @@ import AccordionDetails from '@material-ui/core/AccordionDetails';
40
41
  import AccordionSummary from '@material-ui/core/AccordionSummary';
41
42
  import Divider from '@material-ui/core/Divider';
42
43
  import ExpandMoreIcon$1 from '@material-ui/icons/ExpandLess';
43
- import List from '@material-ui/core/List';
44
+ import List$1 from '@material-ui/core/List';
44
45
  import ListItem from '@material-ui/core/ListItem';
45
46
  import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
46
47
  import Cancel from '@material-ui/icons/Cancel';
@@ -61,7 +62,12 @@ import RefreshIcon from '@material-ui/icons/Refresh';
61
62
  import SaveIcon from '@material-ui/icons/Save';
62
63
  import useDebounce from 'react-use/lib/useDebounce';
63
64
  import { showPanel } from '@codemirror/view';
64
- import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-bff55719.esm.js';
65
+ import MaterialTable from '@material-table/core';
66
+ import SettingsIcon from '@material-ui/icons/Settings';
67
+ import AllIcon from '@material-ui/icons/FontDownload';
68
+ import { DateTime, Interval } from 'luxon';
69
+ import humanizeDuration from 'humanize-duration';
70
+ import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-23066066.esm.js';
65
71
  import '@backstage/errors';
66
72
  import 'zen-observable';
67
73
  import '@material-ui/core/FormControl';
@@ -79,12 +85,11 @@ import '@material-ui/core/Step';
79
85
  import '@material-ui/core/StepLabel';
80
86
  import '@material-ui/core/Stepper';
81
87
  import '@material-ui/icons/FiberManualRecord';
82
- import 'luxon';
83
88
  import 'react-use/lib/useInterval';
84
89
  import 'use-immer';
85
90
  import '@material-ui/icons/Language';
86
91
 
87
- const useStyles$d = makeStyles((theme) => ({
92
+ const useStyles$e = makeStyles((theme) => ({
88
93
  cardHeader: {
89
94
  position: "relative"
90
95
  },
@@ -163,7 +168,7 @@ const TemplateCard = ({ template, deprecated }) => {
163
168
  const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
164
169
  const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type }) ? templateProps.type : "other";
165
170
  const theme = backstageTheme.getPageTheme({ themeId });
166
- const classes = useStyles$d({ backgroundImage: theme.backgroundImage });
171
+ const classes = useStyles$e({ backgroundImage: theme.backgroundImage });
167
172
  const href = templateRoute({ templateName: templateProps.name });
168
173
  const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
169
174
  const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);
@@ -248,18 +253,21 @@ const TemplateList = ({
248
253
  })))));
249
254
  };
250
255
 
251
- const useStyles$c = makeStyles$1({
256
+ const useStyles$d = makeStyles$1({
252
257
  button: {
253
258
  color: "white"
254
259
  }
255
260
  });
256
261
  function ScaffolderPageContextMenu(props) {
257
- const classes = useStyles$c();
262
+ const classes = useStyles$d();
258
263
  const [anchorEl, setAnchorEl] = useState();
259
- const pageLink = useRouteRef(rootRouteRef);
264
+ const editLink = useRouteRef(editRouteRef);
265
+ const actionsLink = useRouteRef(actionsRouteRef);
266
+ const tasksLink = useRouteRef(scaffolderListTaskRouteRef);
260
267
  const navigate = useNavigate();
261
268
  const showEditor = props.editor !== false;
262
269
  const showActions = props.actions !== false;
270
+ const showTasks = props.tasks !== false;
263
271
  if (!showEditor && !showActions) {
264
272
  return null;
265
273
  }
@@ -284,17 +292,23 @@ function ScaffolderPageContextMenu(props) {
284
292
  anchorOrigin: { vertical: "bottom", horizontal: "right" },
285
293
  transformOrigin: { vertical: "top", horizontal: "right" }
286
294
  }, /* @__PURE__ */ React.createElement(MenuList, null, showEditor && /* @__PURE__ */ React.createElement(MenuItem, {
287
- onClick: () => navigate(`${pageLink()}/edit`)
295
+ onClick: () => navigate(editLink())
288
296
  }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Edit, {
289
297
  fontSize: "small"
290
298
  })), /* @__PURE__ */ React.createElement(ListItemText, {
291
299
  primary: "Template Editor"
292
300
  })), showActions && /* @__PURE__ */ React.createElement(MenuItem, {
293
- onClick: () => navigate(`${pageLink()}/actions`)
301
+ onClick: () => navigate(actionsLink())
294
302
  }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Description, {
295
303
  fontSize: "small"
296
304
  })), /* @__PURE__ */ React.createElement(ListItemText, {
297
305
  primary: "Installed Actions"
306
+ })), showTasks && /* @__PURE__ */ React.createElement(MenuItem, {
307
+ onClick: () => navigate(tasksLink())
308
+ }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(List, {
309
+ fontSize: "small"
310
+ })), /* @__PURE__ */ React.createElement(ListItemText, {
311
+ primary: "Task List"
298
312
  })))));
299
313
  }
300
314
 
@@ -474,13 +488,13 @@ function getReviewData(formData, steps) {
474
488
  continue;
475
489
  }
476
490
  const review = uiSchema["ui:backstage"].review;
477
- if (!review.show) {
478
- continue;
479
- }
480
491
  if (review.mask) {
481
492
  reviewData[key] = review.mask;
482
493
  continue;
483
494
  }
495
+ if (!review.show) {
496
+ continue;
497
+ }
484
498
  reviewData[key] = formData[key];
485
499
  }
486
500
  }
@@ -732,7 +746,7 @@ const TemplatePage = ({
732
746
  }))));
733
747
  };
734
748
 
735
- const useStyles$b = makeStyles((theme) => ({
749
+ const useStyles$c = makeStyles((theme) => ({
736
750
  code: {
737
751
  fontFamily: "Menlo, monospace",
738
752
  padding: theme.spacing(1),
@@ -755,7 +769,7 @@ const useStyles$b = makeStyles((theme) => ({
755
769
  }));
756
770
  const ActionsPage = () => {
757
771
  const api = useApi(scaffolderApiRef);
758
- const classes = useStyles$b();
772
+ const classes = useStyles$c();
759
773
  const { loading, value, error } = useAsync(async () => {
760
774
  return api.listActions();
761
775
  });
@@ -891,7 +905,7 @@ class WebFileSystemAccess {
891
905
  }
892
906
  }
893
907
 
894
- const useStyles$a = makeStyles$1((theme) => ({
908
+ const useStyles$b = makeStyles$1((theme) => ({
895
909
  introText: {
896
910
  textAlign: "center",
897
911
  marginTop: theme.spacing(2)
@@ -909,7 +923,7 @@ const useStyles$a = makeStyles$1((theme) => ({
909
923
  }
910
924
  }));
911
925
  function TemplateEditorIntro(props) {
912
- const classes = useStyles$a();
926
+ const classes = useStyles$b();
913
927
  const supportsLoad = WebFileSystemAccess.isSupported();
914
928
  const cardLoadLocal = /* @__PURE__ */ React.createElement(Card$1, {
915
929
  className: classes.card,
@@ -1212,7 +1226,7 @@ function useDryRun() {
1212
1226
  return value;
1213
1227
  }
1214
1228
 
1215
- const useStyles$9 = makeStyles$1((theme) => ({
1229
+ const useStyles$a = makeStyles$1((theme) => ({
1216
1230
  root: {
1217
1231
  overflowY: "auto",
1218
1232
  background: theme.palette.background.default
@@ -1229,9 +1243,9 @@ const useStyles$9 = makeStyles$1((theme) => ({
1229
1243
  }
1230
1244
  }));
1231
1245
  function DryRunResultsList() {
1232
- const classes = useStyles$9();
1246
+ const classes = useStyles$a();
1233
1247
  const dryRun = useDryRun();
1234
- return /* @__PURE__ */ React.createElement(List, {
1248
+ return /* @__PURE__ */ React.createElement(List$1, {
1235
1249
  className: classes.root,
1236
1250
  dense: true
1237
1251
  }, dryRun.results.map((result) => {
@@ -1254,7 +1268,7 @@ function DryRunResultsList() {
1254
1268
  }));
1255
1269
  }
1256
1270
 
1257
- const useStyles$8 = makeStyles$1({
1271
+ const useStyles$9 = makeStyles$1({
1258
1272
  root: {
1259
1273
  whiteSpace: "nowrap",
1260
1274
  overflowY: "auto"
@@ -1320,7 +1334,7 @@ function FileTreeItem({ entry }) {
1320
1334
  })));
1321
1335
  }
1322
1336
  function FileBrowser(props) {
1323
- const classes = useStyles$8();
1337
+ const classes = useStyles$9();
1324
1338
  const fileTree = useMemo(() => parseFileEntires(props.filePaths), [props.filePaths]);
1325
1339
  return /* @__PURE__ */ React.createElement(TreeView, {
1326
1340
  selected: props.selected,
@@ -1338,7 +1352,7 @@ function FileBrowser(props) {
1338
1352
  })));
1339
1353
  }
1340
1354
 
1341
- const useStyles$7 = makeStyles$1((theme) => ({
1355
+ const useStyles$8 = makeStyles$1((theme) => ({
1342
1356
  root: {
1343
1357
  display: "grid",
1344
1358
  gridTemplateColumns: "280px auto 3fr",
@@ -1354,7 +1368,7 @@ const useStyles$7 = makeStyles$1((theme) => ({
1354
1368
  }
1355
1369
  }));
1356
1370
  function DryRunResultsSplitView(props) {
1357
- const classes = useStyles$7();
1371
+ const classes = useStyles$8();
1358
1372
  const childArray = Children.toArray(props.children);
1359
1373
  if (childArray.length !== 2) {
1360
1374
  throw new Error("must have exactly 2 children");
@@ -1370,7 +1384,7 @@ function DryRunResultsSplitView(props) {
1370
1384
  }, childArray[1]));
1371
1385
  }
1372
1386
 
1373
- const useStyles$6 = makeStyles$1({
1387
+ const useStyles$7 = makeStyles$1({
1374
1388
  root: {
1375
1389
  display: "flex",
1376
1390
  flexFlow: "column nowrap"
@@ -1396,7 +1410,7 @@ const useStyles$6 = makeStyles$1({
1396
1410
  }
1397
1411
  });
1398
1412
  function FilesContent() {
1399
- const classes = useStyles$6();
1413
+ const classes = useStyles$7();
1400
1414
  const { selectedResult } = useDryRun();
1401
1415
  const [selectedPath, setSelectedPath] = useState("");
1402
1416
  const selectedFile = selectedResult == null ? void 0 : selectedResult.directoryContents.find((f) => f.path === selectedPath);
@@ -1461,7 +1475,7 @@ function LogContent() {
1461
1475
  }
1462
1476
  function OutputContent() {
1463
1477
  var _a, _b;
1464
- const classes = useStyles$6();
1478
+ const classes = useStyles$7();
1465
1479
  const { selectedResult } = useDryRun();
1466
1480
  if (!selectedResult) {
1467
1481
  return null;
@@ -1480,7 +1494,7 @@ function OutputContent() {
1480
1494
  }));
1481
1495
  }
1482
1496
  function DryRunResultsView() {
1483
- const classes = useStyles$6();
1497
+ const classes = useStyles$7();
1484
1498
  const [selectedTab, setSelectedTab] = useState("files");
1485
1499
  return /* @__PURE__ */ React.createElement("div", {
1486
1500
  className: classes.root
@@ -1503,7 +1517,7 @@ function DryRunResultsView() {
1503
1517
  }, selectedTab === "files" && /* @__PURE__ */ React.createElement(FilesContent, null), selectedTab === "log" && /* @__PURE__ */ React.createElement(LogContent, null), selectedTab === "output" && /* @__PURE__ */ React.createElement(OutputContent, null))));
1504
1518
  }
1505
1519
 
1506
- const useStyles$5 = makeStyles$1((theme) => ({
1520
+ const useStyles$6 = makeStyles$1((theme) => ({
1507
1521
  header: {
1508
1522
  height: 48,
1509
1523
  minHeight: 0,
@@ -1522,7 +1536,7 @@ const useStyles$5 = makeStyles$1((theme) => ({
1522
1536
  }
1523
1537
  }));
1524
1538
  function DryRunResults() {
1525
- const classes = useStyles$5();
1539
+ const classes = useStyles$6();
1526
1540
  const dryRun = useDryRun();
1527
1541
  const [expanded, setExpanded] = useState(false);
1528
1542
  const [hidden, setHidden] = useState(true);
@@ -1554,7 +1568,7 @@ function DryRunResults() {
1554
1568
  }), /* @__PURE__ */ React.createElement(DryRunResultsView, null))));
1555
1569
  }
1556
1570
 
1557
- const useStyles$4 = makeStyles((theme) => ({
1571
+ const useStyles$5 = makeStyles((theme) => ({
1558
1572
  button: {
1559
1573
  padding: theme.spacing(1)
1560
1574
  },
@@ -1573,7 +1587,7 @@ const useStyles$4 = makeStyles((theme) => ({
1573
1587
  }));
1574
1588
  function TemplateEditorBrowser(props) {
1575
1589
  var _a, _b;
1576
- const classes = useStyles$4();
1590
+ const classes = useStyles$5();
1577
1591
  const directoryEditor = useDirectoryEditor();
1578
1592
  const changedFiles = directoryEditor.files.filter((file) => file.dirty);
1579
1593
  const handleClose = () => {
@@ -1617,7 +1631,7 @@ function TemplateEditorBrowser(props) {
1617
1631
  }));
1618
1632
  }
1619
1633
 
1620
- const useStyles$3 = makeStyles$1({
1634
+ const useStyles$4 = makeStyles$1({
1621
1635
  containerWrapper: {
1622
1636
  position: "relative",
1623
1637
  width: "100%",
@@ -1665,7 +1679,7 @@ function TemplateEditorForm(props) {
1665
1679
  setErrorText,
1666
1680
  fieldExtensions = []
1667
1681
  } = props;
1668
- const classes = useStyles$3();
1682
+ const classes = useStyles$4();
1669
1683
  const apiHolder = useApiHolder();
1670
1684
  const [steps, setSteps] = useState();
1671
1685
  const fields = useMemo(() => {
@@ -1760,7 +1774,7 @@ function TemplateEditorFormDirectoryEditorDryRun(props) {
1760
1774
  }
1761
1775
  TemplateEditorForm.DirectoryEditorDryRun = TemplateEditorFormDirectoryEditorDryRun;
1762
1776
 
1763
- const useStyles$2 = makeStyles((theme) => ({
1777
+ const useStyles$3 = makeStyles((theme) => ({
1764
1778
  container: {
1765
1779
  position: "relative",
1766
1780
  width: "100%",
@@ -1789,7 +1803,7 @@ const useStyles$2 = makeStyles((theme) => ({
1789
1803
  }));
1790
1804
  function TemplateEditorTextArea(props) {
1791
1805
  const { errorText } = props;
1792
- const classes = useStyles$2();
1806
+ const classes = useStyles$3();
1793
1807
  const panelExtension = useMemo(() => {
1794
1808
  if (!errorText) {
1795
1809
  return showPanel.of(null);
@@ -1855,7 +1869,7 @@ function TemplateEditorDirectoryEditorTextArea(props) {
1855
1869
  }
1856
1870
  TemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;
1857
1871
 
1858
- const useStyles$1 = makeStyles({
1872
+ const useStyles$2 = makeStyles({
1859
1873
  root: {
1860
1874
  gridArea: "pageContent",
1861
1875
  display: "grid",
@@ -1883,7 +1897,7 @@ const useStyles$1 = makeStyles({
1883
1897
  }
1884
1898
  });
1885
1899
  const TemplateEditor = (props) => {
1886
- const classes = useStyles$1();
1900
+ const classes = useStyles$2();
1887
1901
  const [errorText, setErrorText] = useState();
1888
1902
  return /* @__PURE__ */ React.createElement(DirectoryEditorProvider, {
1889
1903
  directory: props.directory
@@ -1945,7 +1959,7 @@ steps:
1945
1959
  values:
1946
1960
  name: \${{parameters.name}}
1947
1961
  `;
1948
- const useStyles = makeStyles((theme) => ({
1962
+ const useStyles$1 = makeStyles((theme) => ({
1949
1963
  root: {
1950
1964
  gridArea: "pageContent",
1951
1965
  display: "grid",
@@ -1975,7 +1989,7 @@ const TemplateFormPreviewer = ({
1975
1989
  customFieldExtensions = [],
1976
1990
  onClose
1977
1991
  }) => {
1978
- const classes = useStyles();
1992
+ const classes = useStyles$1();
1979
1993
  const alertApi = useApi(alertApiRef);
1980
1994
  const catalogApi = useApi(catalogApiRef);
1981
1995
  const [selectedTemplate, setSelectedTemplate] = useState("");
@@ -2082,6 +2096,220 @@ function TemplateEditorPage(props) {
2082
2096
  }), content);
2083
2097
  }
2084
2098
 
2099
+ const useStyles = makeStyles((theme) => ({
2100
+ root: {
2101
+ backgroundColor: "rgba(0, 0, 0, .11)",
2102
+ boxShadow: "none",
2103
+ margin: theme.spacing(1, 0, 1, 0)
2104
+ },
2105
+ title: {
2106
+ margin: theme.spacing(1, 0, 0, 1),
2107
+ textTransform: "uppercase",
2108
+ fontSize: 12,
2109
+ fontWeight: "bold"
2110
+ },
2111
+ listIcon: {
2112
+ minWidth: 30,
2113
+ color: theme.palette.text.primary
2114
+ },
2115
+ menuItem: {
2116
+ minHeight: theme.spacing(6)
2117
+ },
2118
+ groupWrapper: {
2119
+ margin: theme.spacing(1, 1, 2, 1)
2120
+ }
2121
+ }), {
2122
+ name: "ScaffolderReactOwnerListPicker"
2123
+ });
2124
+ function getFilterGroups() {
2125
+ return [
2126
+ {
2127
+ name: "Task Owner",
2128
+ items: [
2129
+ {
2130
+ id: "owned",
2131
+ label: "Owned",
2132
+ icon: SettingsIcon
2133
+ },
2134
+ {
2135
+ id: "all",
2136
+ label: "All",
2137
+ icon: AllIcon
2138
+ }
2139
+ ]
2140
+ }
2141
+ ];
2142
+ }
2143
+ const OwnerListPicker = (props) => {
2144
+ const { filter, onSelectOwner } = props;
2145
+ const classes = useStyles();
2146
+ const filterGroups = getFilterGroups();
2147
+ return /* @__PURE__ */ React.createElement(Card, {
2148
+ className: classes.root
2149
+ }, filterGroups.map((group) => /* @__PURE__ */ React.createElement(Fragment, {
2150
+ key: group.name
2151
+ }, /* @__PURE__ */ React.createElement(Typography, {
2152
+ variant: "subtitle2",
2153
+ className: classes.title
2154
+ }, group.name), /* @__PURE__ */ React.createElement(Card, {
2155
+ className: classes.groupWrapper
2156
+ }, /* @__PURE__ */ React.createElement(List$2, {
2157
+ disablePadding: true,
2158
+ dense: true
2159
+ }, group.items.map((item) => /* @__PURE__ */ React.createElement(MenuItem$1, {
2160
+ key: item.id,
2161
+ button: true,
2162
+ divider: true,
2163
+ onClick: () => onSelectOwner(item.id),
2164
+ selected: item.id === filter,
2165
+ className: classes.menuItem,
2166
+ "data-testid": `owner-picker-${item.id}`
2167
+ }, item.icon && /* @__PURE__ */ React.createElement(ListItemIcon$1, {
2168
+ className: classes.listIcon
2169
+ }, /* @__PURE__ */ React.createElement(item.icon, {
2170
+ fontSize: "small"
2171
+ })), /* @__PURE__ */ React.createElement(ListItemText$1, null, /* @__PURE__ */ React.createElement(Typography, {
2172
+ variant: "body1"
2173
+ }, item.label)))))))));
2174
+ };
2175
+
2176
+ const CreatedAtColumn = ({ createdAt }) => {
2177
+ const createdAtTime = DateTime.fromISO(createdAt);
2178
+ const formatted = Interval.fromDateTimes(createdAtTime, DateTime.local()).toDuration().valueOf();
2179
+ return /* @__PURE__ */ React.createElement("p", null, humanizeDuration(formatted, { round: true }), " ago");
2180
+ };
2181
+
2182
+ const OwnerEntityColumn = ({ entityRef }) => {
2183
+ var _a, _b, _c;
2184
+ const catalogApi = useApi(catalogApiRef);
2185
+ const { value, loading, error } = useAsync(() => catalogApi.getEntityByRef(entityRef || ""), [catalogApi, entityRef]);
2186
+ if (!entityRef) {
2187
+ return /* @__PURE__ */ React.createElement("p", null, "Unknown");
2188
+ }
2189
+ if (loading || error) {
2190
+ return null;
2191
+ }
2192
+ return /* @__PURE__ */ React.createElement(EntityRefLink, {
2193
+ entityRef: parseEntityRef(entityRef),
2194
+ 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
2195
+ });
2196
+ };
2197
+
2198
+ const TaskStatusColumn = ({ status }) => {
2199
+ switch (status) {
2200
+ case "processing":
2201
+ return /* @__PURE__ */ React.createElement(StatusPending, null, status);
2202
+ case "completed":
2203
+ return /* @__PURE__ */ React.createElement(StatusOK, null, status);
2204
+ case "error":
2205
+ default:
2206
+ return /* @__PURE__ */ React.createElement(StatusError, null, status);
2207
+ }
2208
+ };
2209
+
2210
+ const TemplateTitleColumn = ({ entityRef }) => {
2211
+ const scaffolder = useApi(scaffolderApiRef);
2212
+ const { value, loading, error } = useAsync(() => scaffolder.getTemplateParameterSchema(entityRef || ""), [scaffolder, entityRef]);
2213
+ if (loading || error || !entityRef) {
2214
+ return null;
2215
+ }
2216
+ return /* @__PURE__ */ React.createElement(EntityRefLink, {
2217
+ entityRef: parseEntityRef(entityRef),
2218
+ title: value == null ? void 0 : value.title
2219
+ });
2220
+ };
2221
+
2222
+ const ListTaskPageContent = (props) => {
2223
+ var _a;
2224
+ const { initiallySelectedFilter = "owned" } = props;
2225
+ const scaffolderApi = useApi(scaffolderApiRef);
2226
+ const rootLink = useRouteRef(rootRouteRef);
2227
+ const [ownerFilter, setOwnerFilter] = useState(initiallySelectedFilter);
2228
+ const { value, loading, error } = useAsync(() => {
2229
+ var _a2;
2230
+ if (scaffolderApi.listTasks) {
2231
+ return (_a2 = scaffolderApi.listTasks) == null ? void 0 : _a2.call(scaffolderApi, { filterByOwnership: ownerFilter });
2232
+ }
2233
+ console.warn("listTasks is not implemented in the scaffolderApi, please make sure to implement this method.");
2234
+ return Promise.resolve({ tasks: [] });
2235
+ }, [scaffolderApi, ownerFilter]);
2236
+ if (loading) {
2237
+ return /* @__PURE__ */ React.createElement(Progress, null);
2238
+ }
2239
+ if (error) {
2240
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ErrorPanel, {
2241
+ error
2242
+ }), /* @__PURE__ */ React.createElement(EmptyState, {
2243
+ missing: "info",
2244
+ title: "No information to display",
2245
+ description: "There is no Tasks or there was an issue communicating with backend."
2246
+ }));
2247
+ }
2248
+ return /* @__PURE__ */ React.createElement(CatalogFilterLayout, null, /* @__PURE__ */ React.createElement(CatalogFilterLayout.Filters, null, /* @__PURE__ */ React.createElement(OwnerListPicker, {
2249
+ filter: ownerFilter,
2250
+ onSelectOwner: (id) => setOwnerFilter(id)
2251
+ })), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, /* @__PURE__ */ React.createElement(MaterialTable, {
2252
+ data: (_a = value == null ? void 0 : value.tasks) != null ? _a : [],
2253
+ title: "Tasks",
2254
+ columns: [
2255
+ {
2256
+ title: "Task ID",
2257
+ field: "id",
2258
+ render: (row) => /* @__PURE__ */ React.createElement(Link$1, {
2259
+ to: `${rootLink()}/tasks/${row.id}`
2260
+ }, row.id)
2261
+ },
2262
+ {
2263
+ title: "Template",
2264
+ render: (row) => {
2265
+ var _a2;
2266
+ return /* @__PURE__ */ React.createElement(TemplateTitleColumn, {
2267
+ entityRef: (_a2 = row.spec.templateInfo) == null ? void 0 : _a2.entityRef
2268
+ });
2269
+ }
2270
+ },
2271
+ {
2272
+ title: "Created",
2273
+ field: "createdAt",
2274
+ render: (row) => /* @__PURE__ */ React.createElement(CreatedAtColumn, {
2275
+ createdAt: row.createdAt
2276
+ })
2277
+ },
2278
+ {
2279
+ title: "Owner",
2280
+ field: "createdBy",
2281
+ render: (row) => {
2282
+ var _a2, _b;
2283
+ return /* @__PURE__ */ React.createElement(OwnerEntityColumn, {
2284
+ entityRef: (_b = (_a2 = row.spec) == null ? void 0 : _a2.user) == null ? void 0 : _b.ref
2285
+ });
2286
+ }
2287
+ },
2288
+ {
2289
+ title: "Status",
2290
+ field: "status",
2291
+ render: (row) => /* @__PURE__ */ React.createElement(TaskStatusColumn, {
2292
+ status: row.status
2293
+ })
2294
+ }
2295
+ ]
2296
+ })));
2297
+ };
2298
+ const ListTasksPage = (props) => {
2299
+ return /* @__PURE__ */ React.createElement(Page, {
2300
+ themeId: "home"
2301
+ }, /* @__PURE__ */ React.createElement(Header, {
2302
+ pageTitleOverride: "Templates Tasks",
2303
+ title: /* @__PURE__ */ React.createElement(React.Fragment, null, "List template tasks ", /* @__PURE__ */ React.createElement(Lifecycle, {
2304
+ shorthand: true,
2305
+ alpha: true
2306
+ })),
2307
+ subtitle: "All tasks that have been started"
2308
+ }), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ListTaskPageContent, {
2309
+ ...props
2310
+ })));
2311
+ };
2312
+
2085
2313
  const Router = (props) => {
2086
2314
  const { groups, components = {}, defaultPreviewTemplate } = props;
2087
2315
  const { TemplateCardComponent, TaskPageComponent } = components;
@@ -2107,6 +2335,9 @@ const Router = (props) => {
2107
2335
  element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplatePage, {
2108
2336
  customFieldExtensions: fieldExtensions
2109
2337
  }))
2338
+ }), /* @__PURE__ */ React.createElement(Route, {
2339
+ path: scaffolderListTaskRouteRef.path,
2340
+ element: /* @__PURE__ */ React.createElement(ListTasksPage, null)
2110
2341
  }), /* @__PURE__ */ React.createElement(Route, {
2111
2342
  path: scaffolderTaskRouteRef.path,
2112
2343
  element: /* @__PURE__ */ React.createElement(TaskPageElement, null)
@@ -2128,4 +2359,4 @@ const Router = (props) => {
2128
2359
  };
2129
2360
 
2130
2361
  export { Router };
2131
- //# sourceMappingURL=Router-0396362f.esm.js.map
2362
+ //# sourceMappingURL=Router-05ffdd73.esm.js.map