@backstage/plugin-scaffolder 0.15.0-next.0 → 1.0.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +91 -0
- package/alpha/package.json +6 -0
- package/dist/esm/{Router-722c3528.esm.js → Router-6d65a0e4.esm.js} +190 -64
- package/dist/esm/Router-6d65a0e4.esm.js.map +1 -0
- package/dist/esm/default-ae106e61.esm.js +33 -0
- package/dist/esm/default-ae106e61.esm.js.map +1 -0
- package/dist/esm/index-284296f7.esm.js +336 -0
- package/dist/esm/index-284296f7.esm.js.map +1 -0
- package/dist/esm/{index-3fd3ab40.esm.js → index-d7094787.esm.js} +10 -8
- package/dist/esm/index-d7094787.esm.js.map +1 -0
- package/dist/index.alpha.d.ts +498 -0
- package/dist/index.beta.d.ts +475 -0
- package/dist/index.d.ts +277 -226
- package/dist/index.esm.js +1 -1
- package/package.json +31 -24
- package/dist/esm/Router-722c3528.esm.js.map +0 -1
- package/dist/esm/index-3fd3ab40.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 1.0.1-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d34900af81: Added a new `NextScaffolderRouter` which will eventually replace the exiting router
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/catalog-model@1.0.1-next.0
|
|
10
|
+
- @backstage/integration@1.0.1-next.0
|
|
11
|
+
- @backstage/plugin-catalog-react@1.0.1-next.0
|
|
12
|
+
- @backstage/core-components@0.9.3-next.0
|
|
13
|
+
- @backstage/catalog-client@1.0.1-next.0
|
|
14
|
+
- @backstage/plugin-scaffolder-common@1.0.1-next.0
|
|
15
|
+
- @backstage/integration-react@1.0.1-next.0
|
|
16
|
+
- @backstage/plugin-catalog-common@1.0.1-next.0
|
|
17
|
+
|
|
18
|
+
## 1.0.0
|
|
19
|
+
|
|
20
|
+
### Major Changes
|
|
21
|
+
|
|
22
|
+
- b58c70c223: This package has been promoted to v1.0! To understand how this change affects the package, please check out our [versioning policy](https://backstage.io/docs/overview/versioning-policy).
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- 9a408928a1: **BREAKING**: Removed the unused `titleComponent` property of `groups` passed to the `ScaffolderPage`. The property was already ignored, but existing usage should migrated to use the `title` property instead, which now accepts any `ReactNode`.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 9b7e361783: Remove beta labels
|
|
31
|
+
- a422d7ce5e: chore(deps): bump `@testing-library/react` from 11.2.6 to 12.1.3
|
|
32
|
+
- 20a262c214: The `ScaffolderPage` now uses the `CatalogFilterLayout`, which means the filters are put in a drawer on smaller screens.
|
|
33
|
+
- f24ef7864e: Minor typo fixes
|
|
34
|
+
- d8716924d6: Implement a template preview page (`/create/preview`) to test creating form UIs
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- @backstage/core-components@0.9.2
|
|
37
|
+
- @backstage/core-plugin-api@1.0.0
|
|
38
|
+
- @backstage/integration-react@1.0.0
|
|
39
|
+
- @backstage/plugin-catalog-react@1.0.0
|
|
40
|
+
- @backstage/plugin-permission-react@0.3.4
|
|
41
|
+
- @backstage/catalog-model@1.0.0
|
|
42
|
+
- @backstage/plugin-scaffolder-common@1.0.0
|
|
43
|
+
- @backstage/integration@1.0.0
|
|
44
|
+
- @backstage/catalog-client@1.0.0
|
|
45
|
+
- @backstage/config@1.0.0
|
|
46
|
+
- @backstage/errors@1.0.0
|
|
47
|
+
- @backstage/types@1.0.0
|
|
48
|
+
- @backstage/plugin-catalog-common@1.0.0
|
|
49
|
+
|
|
50
|
+
## 0.15.0
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- 310e905998: The following deprecations are now breaking and have been removed:
|
|
55
|
+
|
|
56
|
+
- **BREAKING**: Support for `backstage.io/v1beta2` Software Templates has been removed. Please migrate your legacy templates to the new `scaffolder.backstage.io/v1beta3` `apiVersion` by following the [migration guide](https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3)
|
|
57
|
+
|
|
58
|
+
- **BREAKING**: Removed the deprecated `TemplateMetadata`. Please use `TemplateInfo` instead.
|
|
59
|
+
|
|
60
|
+
- **BREAKING**: Removed the deprecated `context.baseUrl`. It's now available on `context.templateInfo.baseUrl`.
|
|
61
|
+
|
|
62
|
+
- **BREAKING**: Removed the deprecated `DispatchResult`, use `TaskBrokerDispatchResult` instead.
|
|
63
|
+
|
|
64
|
+
- **BREAKING**: Removed the deprecated `runCommand`, use `executeShellCommond` instead.
|
|
65
|
+
|
|
66
|
+
- **BREAKING**: Removed the deprecated `Status` in favour of `TaskStatus` instead.
|
|
67
|
+
|
|
68
|
+
- **BREAKING**: Removed the deprecated `TaskState` in favour of `CurrentClaimedTask` instead.
|
|
69
|
+
|
|
70
|
+
- 1360f7d73a: **BREAKING**: Removed `ScaffolderTaskOutput.entityRef` and `ScaffolderTaskOutput.remoteUrl`, which both have been deprecated for over a year. Please use the `links` output instead.
|
|
71
|
+
- e63e5a9452: Removed the following previously deprecated exports:
|
|
72
|
+
|
|
73
|
+
- **BREAKING**: Removed the deprecated `TemplateList` component and the `TemplateListProps` type. Please use the `TemplateCard` to create your own list component instead to render these lists.
|
|
74
|
+
|
|
75
|
+
- **BREAKING**: Removed the deprecated `setSecret` method, please use `setSecrets` instead.
|
|
76
|
+
|
|
77
|
+
- **BREAKING**: Removed the deprecated `TemplateCardComponent` and `TaskPageComponent` props from the `ScaffolderPage` component. These are now provided using the `components` prop with the shape `{{ TemplateCardComponent: () => JSX.Element, TaskPageComponent: () => JSX.Element }}`
|
|
78
|
+
|
|
79
|
+
- **BREAKING**: Removed `JobStatus` as this type was actually a legacy type used in `v1alpha` templates and the workflow engine and should no longer be used or depended on.
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- d741c97b98: Render markdown for description in software templates
|
|
84
|
+
- 33e58456b5: Fixing the border color for the `FavoriteEntity` star button on the `TemplateCard`
|
|
85
|
+
- Updated dependencies
|
|
86
|
+
- @backstage/plugin-catalog-react@0.9.0
|
|
87
|
+
- @backstage/core-components@0.9.1
|
|
88
|
+
- @backstage/plugin-scaffolder-common@0.3.0
|
|
89
|
+
- @backstage/catalog-model@0.13.0
|
|
90
|
+
- @backstage/plugin-catalog-common@0.2.2
|
|
91
|
+
- @backstage/catalog-client@0.9.0
|
|
92
|
+
- @backstage/integration-react@0.1.25
|
|
93
|
+
|
|
3
94
|
## 0.15.0-next.0
|
|
4
95
|
|
|
5
96
|
### Minor Changes
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useState, useContext, useCallback } 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,
|
|
4
|
-
import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
|
-
import { getEntityRelations, getEntitySourceLocation, FavoriteEntity, EntityRefLinks, useEntityList, EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker } from '@backstage/plugin-catalog-react';
|
|
6
|
-
import {
|
|
7
|
-
import { E as EntityPicker, a as EntityNamePicker, e as entityNamePickerValidation, b as EntityTagsPicker, R as RepoUrlPicker, r as repoPickerValidation, O as OwnerPicker, c as OwnedEntityPicker, s as selectedTemplateRouteRef, d as registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, f as scaffolderApiRef, g as scaffolderTaskRouteRef, h as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, i as FIELD_EXTENSION_KEY, j as SecretsContextProvider, k as TaskPage } from './index-3fd3ab40.esm.js';
|
|
3
|
+
import { ItemCardHeader, MarkdownContent, Button, ContentHeader, Progress, WarningPanel, Link as Link$1, Content, ItemCardGrid, Page, Header, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage } from '@backstage/core-components';
|
|
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 registerComponentRouteRef, T as TemplateTypePicker, S as SecretsContext, a as scaffolderApiRef, b as scaffolderTaskRouteRef, c as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, d as FIELD_EXTENSION_KEY, e as SecretsContextProvider, f as TaskPage } from './index-d7094787.esm.js';
|
|
8
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, Grid, FormControl, InputLabel, Select, MenuItem } 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';
|
|
@@ -17,6 +17,13 @@ import { withTheme } from '@rjsf/core';
|
|
|
17
17
|
import { Theme } from '@rjsf/material-ui';
|
|
18
18
|
import cloneDeep from 'lodash/cloneDeep';
|
|
19
19
|
import classNames from 'classnames';
|
|
20
|
+
import useDebounce from 'react-use/lib/useDebounce';
|
|
21
|
+
import { yaml as yaml$1 } from '@codemirror/legacy-modes/mode/yaml';
|
|
22
|
+
import { showPanel } from '@codemirror/panel';
|
|
23
|
+
import { StreamLanguage } from '@codemirror/stream-parser';
|
|
24
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
25
|
+
import yaml from 'yaml';
|
|
26
|
+
import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-ae106e61.esm.js';
|
|
20
27
|
import '@backstage/errors';
|
|
21
28
|
import 'zen-observable';
|
|
22
29
|
import '@material-ui/core/FormControl';
|
|
@@ -26,7 +33,6 @@ import '@material-ui/lab';
|
|
|
26
33
|
import '@material-ui/core/FormHelperText';
|
|
27
34
|
import '@material-ui/core/Input';
|
|
28
35
|
import '@material-ui/core/InputLabel';
|
|
29
|
-
import 'react-use/lib/useDebounce';
|
|
30
36
|
import 'lodash/capitalize';
|
|
31
37
|
import '@material-ui/icons/CheckBox';
|
|
32
38
|
import '@material-ui/icons/CheckBoxOutlineBlank';
|
|
@@ -45,35 +51,6 @@ import 'react-use/lib/useInterval';
|
|
|
45
51
|
import 'use-immer';
|
|
46
52
|
import '@material-ui/icons/Language';
|
|
47
53
|
|
|
48
|
-
const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [
|
|
49
|
-
{
|
|
50
|
-
component: EntityPicker,
|
|
51
|
-
name: "EntityPicker"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
component: EntityNamePicker,
|
|
55
|
-
name: "EntityNamePicker",
|
|
56
|
-
validation: entityNamePickerValidation
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
component: EntityTagsPicker,
|
|
60
|
-
name: "EntityTagsPicker"
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
component: RepoUrlPicker,
|
|
64
|
-
name: "RepoUrlPicker",
|
|
65
|
-
validation: repoPickerValidation
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
component: OwnerPicker,
|
|
69
|
-
name: "OwnerPicker"
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
component: OwnedEntityPicker,
|
|
73
|
-
name: "OwnedEntityPicker"
|
|
74
|
-
}
|
|
75
|
-
];
|
|
76
|
-
|
|
77
54
|
const useStyles$2 = makeStyles((theme) => ({
|
|
78
55
|
cardHeader: {
|
|
79
56
|
position: "relative"
|
|
@@ -105,7 +82,8 @@ const useStyles$2 = makeStyles((theme) => ({
|
|
|
105
82
|
position: "absolute",
|
|
106
83
|
top: theme.spacing(0.5),
|
|
107
84
|
right: theme.spacing(0.5),
|
|
108
|
-
padding: "0.25rem"
|
|
85
|
+
padding: "0.25rem",
|
|
86
|
+
color: "#fff"
|
|
109
87
|
}
|
|
110
88
|
}));
|
|
111
89
|
const useDeprecationStyles = makeStyles((theme) => ({
|
|
@@ -209,10 +187,6 @@ const TemplateList = ({
|
|
|
209
187
|
const Card = TemplateCardComponent || TemplateCard;
|
|
210
188
|
const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
|
|
211
189
|
const titleComponent = (() => {
|
|
212
|
-
if (group == null ? void 0 : group.titleComponent) {
|
|
213
|
-
console.warn("DEPRECATED: group.titleComponent is now deprecated. Use group.title instead, it can be a string or a react component");
|
|
214
|
-
return group == null ? void 0 : group.titleComponent;
|
|
215
|
-
}
|
|
216
190
|
if (group && group.title) {
|
|
217
191
|
if (typeof group.title === "string") {
|
|
218
192
|
return /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
@@ -241,19 +215,10 @@ const TemplateList = ({
|
|
|
241
215
|
})))));
|
|
242
216
|
};
|
|
243
217
|
|
|
244
|
-
const useStyles$1 = makeStyles((theme) => ({
|
|
245
|
-
contentWrapper: {
|
|
246
|
-
display: "grid",
|
|
247
|
-
gridTemplateAreas: "'filters' 'grid'",
|
|
248
|
-
gridTemplateColumns: "250px 1fr",
|
|
249
|
-
gridColumnGap: theme.spacing(2)
|
|
250
|
-
}
|
|
251
|
-
}));
|
|
252
218
|
const ScaffolderPageContents = ({
|
|
253
219
|
TemplateCardComponent,
|
|
254
220
|
groups
|
|
255
221
|
}) => {
|
|
256
|
-
const styles = useStyles$1();
|
|
257
222
|
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
258
223
|
const otherTemplatesGroup = {
|
|
259
224
|
title: groups ? "Other Templates" : "Templates",
|
|
@@ -267,24 +232,20 @@ const ScaffolderPageContents = ({
|
|
|
267
232
|
themeId: "home"
|
|
268
233
|
}, /* @__PURE__ */ React.createElement(Header, {
|
|
269
234
|
pageTitleOverride: "Create a New Component",
|
|
270
|
-
title:
|
|
271
|
-
shorthand: true
|
|
272
|
-
})),
|
|
235
|
+
title: "Create a New Component",
|
|
273
236
|
subtitle: "Create new software components using standard templates"
|
|
274
237
|
}), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
275
238
|
title: "Available Templates"
|
|
276
239
|
}, allowed && /* @__PURE__ */ React.createElement(CreateButton, {
|
|
277
240
|
title: "Register Existing Component",
|
|
278
241
|
to: registerComponentLink && registerComponentLink()
|
|
279
|
-
}), /* @__PURE__ */ React.createElement(SupportButton, null, "Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).")), /* @__PURE__ */ React.createElement(
|
|
280
|
-
className: styles.contentWrapper
|
|
281
|
-
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(EntitySearchBar, null), /* @__PURE__ */ React.createElement(EntityKindPicker, {
|
|
242
|
+
}), /* @__PURE__ */ React.createElement(SupportButton, null, "Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).")), /* @__PURE__ */ React.createElement(CatalogFilterLayout, null, /* @__PURE__ */ React.createElement(CatalogFilterLayout.Filters, null, /* @__PURE__ */ React.createElement(EntitySearchBar, null), /* @__PURE__ */ React.createElement(EntityKindPicker, {
|
|
282
243
|
initialFilter: "template",
|
|
283
244
|
hidden: true
|
|
284
245
|
}), /* @__PURE__ */ React.createElement(UserListPicker, {
|
|
285
246
|
initialFilter: "all",
|
|
286
247
|
availableFilters: ["all", "starred"]
|
|
287
|
-
}), /* @__PURE__ */ React.createElement(TemplateTypePicker, null), /* @__PURE__ */ React.createElement(EntityTagPicker, null)), /* @__PURE__ */ React.createElement(
|
|
248
|
+
}), /* @__PURE__ */ React.createElement(TemplateTypePicker, null), /* @__PURE__ */ React.createElement(EntityTagPicker, null)), /* @__PURE__ */ React.createElement(CatalogFilterLayout.Content, null, groups && groups.map((group, index) => /* @__PURE__ */ React.createElement(TemplateList, {
|
|
288
249
|
key: index,
|
|
289
250
|
TemplateCardComponent,
|
|
290
251
|
group
|
|
@@ -476,6 +437,9 @@ const MultistepJsonForm = (props) => {
|
|
|
476
437
|
};
|
|
477
438
|
const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0));
|
|
478
439
|
const handleCreate = async () => {
|
|
440
|
+
if (!onFinish) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
479
443
|
setDisableButtons(true);
|
|
480
444
|
try {
|
|
481
445
|
await onFinish();
|
|
@@ -540,7 +504,7 @@ const MultistepJsonForm = (props) => {
|
|
|
540
504
|
variant: "contained",
|
|
541
505
|
color: "primary",
|
|
542
506
|
onClick: handleCreate,
|
|
543
|
-
disabled: disableButtons
|
|
507
|
+
disabled: !onFinish || disableButtons
|
|
544
508
|
}, "Create"))));
|
|
545
509
|
};
|
|
546
510
|
|
|
@@ -638,9 +602,7 @@ const TemplatePage = ({
|
|
|
638
602
|
themeId: "home"
|
|
639
603
|
}, /* @__PURE__ */ React.createElement(Header, {
|
|
640
604
|
pageTitleOverride: "Create a New Component",
|
|
641
|
-
title:
|
|
642
|
-
shorthand: true
|
|
643
|
-
})),
|
|
605
|
+
title: "Create a New Component",
|
|
644
606
|
subtitle: "Create new software components using standard templates"
|
|
645
607
|
}), /* @__PURE__ */ React.createElement(Content, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, {
|
|
646
608
|
"data-testid": "loading-progress"
|
|
@@ -663,7 +625,7 @@ const TemplatePage = ({
|
|
|
663
625
|
}))));
|
|
664
626
|
};
|
|
665
627
|
|
|
666
|
-
const useStyles = makeStyles((theme) => ({
|
|
628
|
+
const useStyles$1 = makeStyles((theme) => ({
|
|
667
629
|
code: {
|
|
668
630
|
fontFamily: "Menlo, monospace",
|
|
669
631
|
padding: theme.spacing(1),
|
|
@@ -686,7 +648,7 @@ const useStyles = makeStyles((theme) => ({
|
|
|
686
648
|
}));
|
|
687
649
|
const ActionsPage = () => {
|
|
688
650
|
const api = useApi(scaffolderApiRef);
|
|
689
|
-
const classes = useStyles();
|
|
651
|
+
const classes = useStyles$1();
|
|
690
652
|
const { loading, value, error } = useAsync(async () => {
|
|
691
653
|
return api.listActions();
|
|
692
654
|
});
|
|
@@ -771,8 +733,166 @@ const ActionsPage = () => {
|
|
|
771
733
|
}), /* @__PURE__ */ React.createElement(Content, null, items));
|
|
772
734
|
};
|
|
773
735
|
|
|
736
|
+
const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI
|
|
737
|
+
parameters:
|
|
738
|
+
- title: Fill in some steps
|
|
739
|
+
required:
|
|
740
|
+
- name
|
|
741
|
+
properties:
|
|
742
|
+
name:
|
|
743
|
+
title: Name
|
|
744
|
+
type: string
|
|
745
|
+
description: Unique name of the component
|
|
746
|
+
owner:
|
|
747
|
+
title: Owner
|
|
748
|
+
type: string
|
|
749
|
+
description: Owner of the component
|
|
750
|
+
ui:field: OwnerPicker
|
|
751
|
+
ui:options:
|
|
752
|
+
allowedKinds:
|
|
753
|
+
- Group
|
|
754
|
+
- title: Choose a location
|
|
755
|
+
required:
|
|
756
|
+
- repoUrl
|
|
757
|
+
properties:
|
|
758
|
+
repoUrl:
|
|
759
|
+
title: Repository Location
|
|
760
|
+
type: string
|
|
761
|
+
ui:field: RepoUrlPicker
|
|
762
|
+
ui:options:
|
|
763
|
+
allowedHosts:
|
|
764
|
+
- github.com
|
|
765
|
+
`;
|
|
766
|
+
const useStyles = makeStyles({
|
|
767
|
+
templateSelect: {
|
|
768
|
+
marginBottom: "10px"
|
|
769
|
+
},
|
|
770
|
+
grid: {
|
|
771
|
+
height: "100%"
|
|
772
|
+
},
|
|
773
|
+
codeMirror: {
|
|
774
|
+
height: "95%"
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
const TemplatePreviewPage = ({
|
|
778
|
+
defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,
|
|
779
|
+
customFieldExtensions = []
|
|
780
|
+
}) => {
|
|
781
|
+
const classes = useStyles();
|
|
782
|
+
const alertApi = useApi(alertApiRef);
|
|
783
|
+
const catalogApi = useApi(catalogApiRef);
|
|
784
|
+
const apiHolder = useApiHolder();
|
|
785
|
+
const [selectedTemplate, setSelectedTemplate] = useState("");
|
|
786
|
+
const [schema, setSchema] = useState({
|
|
787
|
+
title: "",
|
|
788
|
+
steps: []
|
|
789
|
+
});
|
|
790
|
+
const [templateOptions, setTemplateOptions] = useState([]);
|
|
791
|
+
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
792
|
+
const [formState, setFormState] = useState({});
|
|
793
|
+
const { loading } = useAsync(() => catalogApi.getEntities({
|
|
794
|
+
filter: { kind: "template" },
|
|
795
|
+
fields: [
|
|
796
|
+
"kind",
|
|
797
|
+
"metadata.namespace",
|
|
798
|
+
"metadata.name",
|
|
799
|
+
"metadata.title",
|
|
800
|
+
"spec.parameters"
|
|
801
|
+
]
|
|
802
|
+
}).then(({ items }) => setTemplateOptions(items.map((template) => {
|
|
803
|
+
var _a;
|
|
804
|
+
return {
|
|
805
|
+
label: (_a = template.metadata.title) != null ? _a : humanizeEntityRef(template, { defaultKind: "template" }),
|
|
806
|
+
value: template
|
|
807
|
+
};
|
|
808
|
+
}))).catch((e) => alertApi.post({
|
|
809
|
+
message: `Error loading exisiting templates: ${e.message}`,
|
|
810
|
+
severity: "error"
|
|
811
|
+
})), [catalogApi]);
|
|
812
|
+
const errorPanel = document.createElement("div");
|
|
813
|
+
errorPanel.style.color = "red";
|
|
814
|
+
useDebounce(() => {
|
|
815
|
+
try {
|
|
816
|
+
const parsedTemplate = yaml.parse(templateYaml);
|
|
817
|
+
setSchema({
|
|
818
|
+
title: "Preview",
|
|
819
|
+
steps: parsedTemplate.parameters.map((param) => ({
|
|
820
|
+
title: param.title,
|
|
821
|
+
schema: param
|
|
822
|
+
}))
|
|
823
|
+
});
|
|
824
|
+
setFormState({});
|
|
825
|
+
} catch (e) {
|
|
826
|
+
errorPanel.textContent = e.message;
|
|
827
|
+
}
|
|
828
|
+
}, 250, [setFormState, setSchema, templateYaml]);
|
|
829
|
+
const handleSelectChange = useCallback((selected) => {
|
|
830
|
+
setSelectedTemplate(selected);
|
|
831
|
+
setTemplateYaml(yaml.stringify(selected.spec));
|
|
832
|
+
}, [setTemplateYaml]);
|
|
833
|
+
const handleFormReset = () => setFormState({});
|
|
834
|
+
const handleFormChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
835
|
+
const handleCodeChange = useCallback((code) => {
|
|
836
|
+
setTemplateYaml(code);
|
|
837
|
+
}, [setTemplateYaml]);
|
|
838
|
+
const customFieldComponents = Object.fromEntries(customFieldExtensions.map(({ name, component }) => [name, component]));
|
|
839
|
+
const customFieldValidators = Object.fromEntries(customFieldExtensions.map(({ name, validation }) => [name, validation]));
|
|
840
|
+
return /* @__PURE__ */ React.createElement(Page, {
|
|
841
|
+
themeId: "home"
|
|
842
|
+
}, /* @__PURE__ */ React.createElement(Header, {
|
|
843
|
+
title: "Template Preview",
|
|
844
|
+
subtitle: "Preview your template parameter UI"
|
|
845
|
+
}), /* @__PURE__ */ React.createElement(Content, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement(Grid, {
|
|
846
|
+
container: true,
|
|
847
|
+
className: classes.grid
|
|
848
|
+
}, /* @__PURE__ */ React.createElement(Grid, {
|
|
849
|
+
item: true,
|
|
850
|
+
xs: 6
|
|
851
|
+
}, /* @__PURE__ */ React.createElement(FormControl, {
|
|
852
|
+
className: classes.templateSelect,
|
|
853
|
+
variant: "outlined",
|
|
854
|
+
fullWidth: true
|
|
855
|
+
}, /* @__PURE__ */ React.createElement(InputLabel, {
|
|
856
|
+
id: "select-template-label"
|
|
857
|
+
}, "Load Existing Template"), /* @__PURE__ */ React.createElement(Select, {
|
|
858
|
+
value: selectedTemplate,
|
|
859
|
+
label: "Load Existing Template",
|
|
860
|
+
labelId: "select-template-label",
|
|
861
|
+
onChange: (e) => handleSelectChange(e.target.value)
|
|
862
|
+
}, templateOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, {
|
|
863
|
+
key: idx,
|
|
864
|
+
value: option.value
|
|
865
|
+
}, option.label)))), /* @__PURE__ */ React.createElement(CodeMirror, {
|
|
866
|
+
className: classes.codeMirror,
|
|
867
|
+
value: templateYaml,
|
|
868
|
+
theme: "dark",
|
|
869
|
+
height: "100%",
|
|
870
|
+
extensions: [
|
|
871
|
+
StreamLanguage.define(yaml$1),
|
|
872
|
+
showPanel.of(() => ({ dom: errorPanel, top: true }))
|
|
873
|
+
],
|
|
874
|
+
onChange: handleCodeChange
|
|
875
|
+
})), /* @__PURE__ */ React.createElement(Grid, {
|
|
876
|
+
item: true,
|
|
877
|
+
xs: 6
|
|
878
|
+
}, schema && /* @__PURE__ */ React.createElement(InfoCard, {
|
|
879
|
+
key: JSON.stringify(schema)
|
|
880
|
+
}, /* @__PURE__ */ React.createElement(MultistepJsonForm, {
|
|
881
|
+
formData: formState,
|
|
882
|
+
fields: customFieldComponents,
|
|
883
|
+
onChange: handleFormChange,
|
|
884
|
+
onReset: handleFormReset,
|
|
885
|
+
steps: schema.steps.map((step) => {
|
|
886
|
+
return {
|
|
887
|
+
...step,
|
|
888
|
+
validate: createValidator(step.schema, customFieldValidators, { apiHolder })
|
|
889
|
+
};
|
|
890
|
+
})
|
|
891
|
+
}))))));
|
|
892
|
+
};
|
|
893
|
+
|
|
774
894
|
const Router = (props) => {
|
|
775
|
-
const { groups, components = {} } = props;
|
|
895
|
+
const { groups, components = {}, defaultPreviewTemplate } = props;
|
|
776
896
|
const { TemplateCardComponent, TaskPageComponent } = components;
|
|
777
897
|
const outlet = useOutlet();
|
|
778
898
|
const TaskPageElement = TaskPageComponent != null ? TaskPageComponent : TaskPage;
|
|
@@ -802,8 +922,14 @@ const Router = (props) => {
|
|
|
802
922
|
}), /* @__PURE__ */ React.createElement(Route, {
|
|
803
923
|
path: "/actions",
|
|
804
924
|
element: /* @__PURE__ */ React.createElement(ActionsPage, null)
|
|
925
|
+
}), /* @__PURE__ */ React.createElement(Route, {
|
|
926
|
+
path: "/preview",
|
|
927
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplatePreviewPage, {
|
|
928
|
+
defaultPreviewTemplate,
|
|
929
|
+
customFieldExtensions: fieldExtensions
|
|
930
|
+
}))
|
|
805
931
|
}));
|
|
806
932
|
};
|
|
807
933
|
|
|
808
934
|
export { Router };
|
|
809
|
-
//# sourceMappingURL=Router-
|
|
935
|
+
//# sourceMappingURL=Router-6d65a0e4.esm.js.map
|