@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 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
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@backstage/plugin-scaffolder",
3
+ "version": "1.0.1-next.0",
4
+ "main": "../dist/index.esm.js",
5
+ "types": "../dist/index.alpha.d.ts"
6
+ }
@@ -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, Lifecycle, CreateButton, SupportButton, StructuredMetadataTable, InfoCard, ErrorPage } from '@backstage/core-components';
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 { 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 } from '@material-ui/core';
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: /* @__PURE__ */ React.createElement(React.Fragment, null, "Create a New Component ", /* @__PURE__ */ React.createElement(Lifecycle, {
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("div", {
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("div", null, groups && groups.map((group, index) => /* @__PURE__ */ React.createElement(TemplateList, {
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: /* @__PURE__ */ React.createElement(React.Fragment, null, "Create a New Component ", /* @__PURE__ */ React.createElement(Lifecycle, {
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-722c3528.esm.js.map
935
+ //# sourceMappingURL=Router-6d65a0e4.esm.js.map