@backstage/plugin-scaffolder 1.6.0-next.3 → 1.7.0-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,71 @@
1
1
  # @backstage/plugin-scaffolder
2
2
 
3
+ ## 1.7.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f13d5f3f06: Add support for link to TechDocs and other links defined in template entity specification metadata on TemplateCard
8
+ - 05f22193c5: EntityPickers now support flags to control when to include default namespace
9
+ in result
10
+
11
+ ### Patch Changes
12
+
13
+ - 8960d83013: Add support for `allowedOrganizations` and `allowedOwners` to the `AzureRepoPicker`.
14
+ - b681275e69: Ignore .git directories in Template Editor, increase upload limit for dry-runs to 10MB.
15
+ - Updated dependencies
16
+ - @backstage/catalog-model@1.1.2-next.0
17
+ - @backstage/core-components@0.11.2-next.0
18
+ - @backstage/catalog-client@1.1.1-next.0
19
+ - @backstage/plugin-catalog-react@1.1.5-next.0
20
+ - @backstage/plugin-scaffolder-common@1.2.1-next.0
21
+ - @backstage/integration-react@1.1.5-next.0
22
+ - @backstage/config@1.0.3-next.0
23
+ - @backstage/core-plugin-api@1.0.7-next.0
24
+ - @backstage/errors@1.1.2-next.0
25
+ - @backstage/integration@1.3.2-next.0
26
+ - @backstage/theme@0.2.16
27
+ - @backstage/types@1.0.0
28
+ - @backstage/plugin-catalog-common@1.0.7-next.0
29
+ - @backstage/plugin-permission-react@0.4.6-next.0
30
+
31
+ ## 1.6.0
32
+
33
+ ### Minor Changes
34
+
35
+ - 3424a8075d: Added support for `async` validation for the `next` version of the plugin
36
+ - ad036784e9: Ability to modify the layout of the step form
37
+ - 192d856495: Implementing review step for the scaffolder under `create/next`
38
+
39
+ ### Patch Changes
40
+
41
+ - 817f3196f6: Updated React Router dependencies to be peer dependencies.
42
+ - eadf56bbbf: Bump `git-url-parse` version to `^13.0.0`
43
+ - 9ffb75616d: Fix bug with empty strings in `EntityPicker`
44
+ - 3f739be9d9: Minor API signatures cleanup
45
+ - 763fb81e82: Internal refactor to use more type safe code when dealing with route parameters.
46
+ - a66d44b72b: Fixing bug when the workspace would not be automatically saved when using `allowedOwners`
47
+ - 7d47def9c4: Removed dependency on `@types/jest`.
48
+ - 6522e459aa: Support displaying and ordering by counts in `EntityTagPicker` field. Add the `showCounts` option to enable this. Also support configuring `helperText`.
49
+ - f0510a20b5: Addition of a dismissible Error Banner in Scaffolder page
50
+ - 667d917488: Updated dependency `msw` to `^0.47.0`.
51
+ - 87ec2ba4d6: Updated dependency `msw` to `^0.46.0`.
52
+ - 9097278df2: Updated dependency `json-schema-library` to `^7.0.0`.
53
+ - bf5e9030eb: Updated dependency `msw` to `^0.45.0`.
54
+ - de336de9cd: fix uiSchema generation when using complex dependencies
55
+ - Updated dependencies
56
+ - @backstage/core-components@0.11.1
57
+ - @backstage/core-plugin-api@1.0.6
58
+ - @backstage/plugin-catalog-react@1.1.4
59
+ - @backstage/plugin-permission-react@0.4.5
60
+ - @backstage/integration@1.3.1
61
+ - @backstage/catalog-client@1.1.0
62
+ - @backstage/catalog-model@1.1.1
63
+ - @backstage/config@1.0.2
64
+ - @backstage/errors@1.1.1
65
+ - @backstage/integration-react@1.1.4
66
+ - @backstage/plugin-scaffolder-common@1.2.0
67
+ - @backstage/plugin-catalog-common@1.0.6
68
+
3
69
  ## 1.6.0-next.3
4
70
 
5
71
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder",
3
- "version": "1.6.0-next.3",
3
+ "version": "1.7.0-next.0",
4
4
  "main": "../dist/index.esm.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -1,12 +1,13 @@
1
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
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, Table as Table$1 } from '@backstage/core-components';
4
- import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, useRouteRefParams, alertApiRef, useElementFilter } from '@backstage/core-plugin-api';
4
+ import { useApp, useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, useRouteRefParams, alertApiRef, useElementFilter } from '@backstage/core-plugin-api';
5
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, l as legacySelectedTemplateRouteRef, j as SecretsContextProvider, k as TaskPage } from './index-3b8e3839.esm.js';
7
- import { RELATION_OWNED_BY, parseEntityRef, 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, List as List$2, ListItemIcon as ListItemIcon$1, ListItemText as ListItemText$1 } from '@material-ui/core';
6
+ import { s as selectedTemplateRouteRef, v as viewTechDocRouteRef, 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, L as LAYOUTS_WRAPPER_KEY, j as LAYOUTS_KEY, l as legacySelectedTemplateRouteRef, k as SecretsContextProvider, m as TaskPage } from './index-f96a52f0.esm.js';
7
+ import { RELATION_OWNED_BY, parseEntityRef, stringifyEntityRef, DEFAULT_NAMESPACE } from '@backstage/catalog-model';
8
+ import { makeStyles, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, Tooltip, IconButton, 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
+ import LanguageIcon from '@material-ui/icons/Language';
10
11
  import WarningIcon from '@material-ui/icons/Warning';
11
12
  import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
12
13
  import { usePermission } from '@backstage/plugin-permission-react';
@@ -65,7 +66,7 @@ import SettingsIcon from '@material-ui/icons/Settings';
65
66
  import AllIcon from '@material-ui/icons/FontDownload';
66
67
  import { DateTime, Interval } from 'luxon';
67
68
  import humanizeDuration from 'humanize-duration';
68
- import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-77c6fe10.esm.js';
69
+ import { D as DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default-21c262f6.esm.js';
69
70
  import '@backstage/errors';
70
71
  import 'zen-observable';
71
72
  import '@material-ui/core/FormControl';
@@ -85,7 +86,6 @@ import '@material-ui/core/Stepper';
85
86
  import '@material-ui/icons/FiberManualRecord';
86
87
  import 'react-use/lib/useInterval';
87
88
  import 'use-immer';
88
- import '@material-ui/icons/Language';
89
89
 
90
90
  const useStyles$e = makeStyles((theme) => ({
91
91
  cardHeader: {
@@ -99,8 +99,7 @@ const useStyles$e = makeStyles((theme) => ({
99
99
  textOverflow: "ellipsis",
100
100
  display: "-webkit-box",
101
101
  "-webkit-line-clamp": 10,
102
- "-webkit-box-orient": "vertical",
103
- paddingBottom: "0.8em"
102
+ "-webkit-box-orient": "vertical"
104
103
  },
105
104
  label: {
106
105
  color: theme.palette.text.secondary,
@@ -111,6 +110,14 @@ const useStyles$e = makeStyles((theme) => ({
111
110
  lineHeight: 1,
112
111
  paddingBottom: "0.2rem"
113
112
  },
113
+ linksLabel: {
114
+ padding: "0 16px"
115
+ },
116
+ description: {
117
+ "& p": {
118
+ margin: "0px"
119
+ }
120
+ },
114
121
  leftButton: {
115
122
  marginRight: "auto"
116
123
  },
@@ -122,6 +129,7 @@ const useStyles$e = makeStyles((theme) => ({
122
129
  color: "#fff"
123
130
  }
124
131
  }));
132
+ const MuiIcon = ({ icon: Icon }) => /* @__PURE__ */ React.createElement(Icon, null);
125
133
  const useDeprecationStyles = makeStyles((theme) => ({
126
134
  deprecationIcon: {
127
135
  position: "absolute",
@@ -134,14 +142,15 @@ const useDeprecationStyles = makeStyles((theme) => ({
134
142
  }
135
143
  }));
136
144
  const getTemplateCardProps = (template) => {
137
- var _a, _b, _c, _d, _e;
145
+ var _a, _b, _c, _d, _e, _f;
138
146
  return {
139
147
  key: template.metadata.uid,
140
148
  name: template.metadata.name,
141
149
  title: `${(_a = template.metadata.title || template.metadata.name) != null ? _a : ""}`,
142
150
  type: (_b = template.spec.type) != null ? _b : "",
143
151
  description: (_c = template.metadata.description) != null ? _c : "-",
144
- tags: (_e = (_d = template.metadata) == null ? void 0 : _d.tags) != null ? _e : []
152
+ tags: (_e = (_d = template.metadata) == null ? void 0 : _d.tags) != null ? _e : [],
153
+ links: (_f = template.metadata.links) != null ? _f : []
145
154
  };
146
155
  };
147
156
  const DeprecationWarning = () => {
@@ -159,7 +168,8 @@ const DeprecationWarning = () => {
159
168
  }, /* @__PURE__ */ React.createElement(WarningIcon, null))));
160
169
  };
161
170
  const TemplateCard = ({ template, deprecated }) => {
162
- var _a;
171
+ var _a, _b, _c;
172
+ const app = useApp();
163
173
  const backstageTheme = useTheme();
164
174
  const templateRoute = useRouteRef(selectedTemplateRouteRef);
165
175
  const templateProps = getTemplateCardProps(template);
@@ -172,6 +182,17 @@ const TemplateCard = ({ template, deprecated }) => {
172
182
  const classes = useStyles$e({ backgroundImage: theme.backgroundImage });
173
183
  const { name, namespace } = parseEntityRef(stringifyEntityRef(template));
174
184
  const href = templateRoute({ templateName: name, namespace });
185
+ const viewTechDoc = useRouteRef(viewTechDocRouteRef);
186
+ const viewTechDocsAnnotation = (_a = template.metadata.annotations) == null ? void 0 : _a["backstage.io/techdocs-ref"];
187
+ const viewTechDocsLink = !!viewTechDocsAnnotation && !!viewTechDoc && viewTechDoc({
188
+ namespace: template.metadata.namespace || DEFAULT_NAMESPACE,
189
+ kind: template.kind,
190
+ name: template.metadata.name
191
+ });
192
+ const iconResolver = (key) => {
193
+ var _a2;
194
+ return key ? (_a2 = app.getSystemIcon(key)) != null ? _a2 : LanguageIcon : LanguageIcon;
195
+ };
175
196
  const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
176
197
  const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);
177
198
  return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardMedia, {
@@ -184,13 +205,14 @@ const TemplateCard = ({ template, deprecated }) => {
184
205
  subtitle: templateProps.type,
185
206
  classes: { root: classes.title }
186
207
  })), /* @__PURE__ */ React.createElement(CardContent, {
187
- style: { display: "grid" }
208
+ style: { display: "flex", flexDirection: "column", gap: "16px" }
188
209
  }, /* @__PURE__ */ React.createElement(Box, {
189
210
  className: classes.box
190
211
  }, /* @__PURE__ */ React.createElement(Typography, {
191
212
  variant: "body2",
192
213
  className: classes.label
193
214
  }, "Description"), /* @__PURE__ */ React.createElement(MarkdownContent, {
215
+ className: classes.description,
194
216
  content: templateProps.description
195
217
  })), /* @__PURE__ */ React.createElement(Box, {
196
218
  className: classes.box
@@ -201,18 +223,41 @@ const TemplateCard = ({ template, deprecated }) => {
201
223
  entityRefs: ownedByRelations,
202
224
  defaultKind: "Group"
203
225
  })), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, {
226
+ style: { marginBottom: "4px" },
204
227
  variant: "body2",
205
228
  className: classes.label
206
- }, "Tags"), (_a = templateProps.tags) == null ? void 0 : _a.map((tag) => /* @__PURE__ */ React.createElement(Chip, {
229
+ }, "Tags"), (_b = templateProps.tags) == null ? void 0 : _b.map((tag) => /* @__PURE__ */ React.createElement(Chip, {
207
230
  size: "small",
208
231
  label: tag,
209
232
  key: tag
210
- })))), /* @__PURE__ */ React.createElement(CardActions, null, sourceLocation && /* @__PURE__ */ React.createElement(IconButton, {
233
+ })))), /* @__PURE__ */ React.createElement(Typography, {
234
+ variant: "body2",
235
+ className: [classes.label, classes.linksLabel].join(" ")
236
+ }, "Links"), /* @__PURE__ */ React.createElement(CardActions, null, /* @__PURE__ */ React.createElement("div", {
237
+ className: classes.leftButton
238
+ }, sourceLocation && /* @__PURE__ */ React.createElement(Tooltip, {
239
+ title: sourceLocation.integrationType || sourceLocation.locationTargetUrl
240
+ }, /* @__PURE__ */ React.createElement(IconButton, {
211
241
  className: classes.leftButton,
212
242
  href: sourceLocation.locationTargetUrl
213
243
  }, /* @__PURE__ */ React.createElement(ScmIntegrationIcon, {
214
244
  type: sourceLocation.integrationType
215
- })), /* @__PURE__ */ React.createElement(Button, {
245
+ }))), viewTechDocsLink && /* @__PURE__ */ React.createElement(Tooltip, {
246
+ title: "View TechDocs"
247
+ }, /* @__PURE__ */ React.createElement(IconButton, {
248
+ className: classes.leftButton,
249
+ href: viewTechDocsLink
250
+ }, /* @__PURE__ */ React.createElement(MuiIcon, {
251
+ icon: iconResolver("docs")
252
+ }))), (_c = templateProps.links) == null ? void 0 : _c.map((link, i) => /* @__PURE__ */ React.createElement(Tooltip, {
253
+ key: `${link.url}_${i}`,
254
+ title: link.title || link.url
255
+ }, /* @__PURE__ */ React.createElement(IconButton, {
256
+ size: "medium",
257
+ href: link.url
258
+ }, /* @__PURE__ */ React.createElement(MuiIcon, {
259
+ icon: iconResolver(link.icon)
260
+ }))))), /* @__PURE__ */ React.createElement(Button, {
216
261
  color: "primary",
217
262
  to: href,
218
263
  "aria-label": `Choose ${templateProps.title}`
@@ -439,12 +484,22 @@ function extractUiSchema(schema, uiSchema) {
439
484
  }
440
485
  }
441
486
  }
442
- function transformSchemaToProps(inputSchema) {
487
+ function transformSchemaToProps(inputSchema, layouts = []) {
488
+ var _a;
489
+ const customLayoutName = inputSchema["ui:ObjectFieldTemplate"];
443
490
  inputSchema.type = inputSchema.type || "object";
444
491
  const schema = JSON.parse(JSON.stringify(inputSchema));
445
492
  delete schema.title;
446
493
  const uiSchema = {};
447
494
  extractUiSchema(schema, uiSchema);
495
+ if (customLayoutName) {
496
+ const Layout = (_a = layouts.find(
497
+ (layout) => layout.name === customLayoutName
498
+ )) == null ? void 0 : _a.component;
499
+ if (Layout) {
500
+ uiSchema["ui:ObjectFieldTemplate"] = Layout;
501
+ }
502
+ }
448
503
  return { schema, uiSchema };
449
504
  }
450
505
 
@@ -512,7 +567,8 @@ const MultistepJsonForm = (props) => {
512
567
  onFinish,
513
568
  fields,
514
569
  widgets,
515
- finishButtonLabel
570
+ finishButtonLabel,
571
+ layouts
516
572
  } = props;
517
573
  const [activeStep, setActiveStep] = useState(0);
518
574
  const [disableButtons, setDisableButtons] = useState(false);
@@ -597,7 +653,7 @@ const MultistepJsonForm = (props) => {
597
653
  handleNext();
598
654
  },
599
655
  ...formProps,
600
- ...transformSchemaToProps(schema)
656
+ ...transformSchemaToProps(schema, layouts)
601
657
  }, /* @__PURE__ */ React.createElement(Button$1, {
602
658
  disabled: activeStep === 0,
603
659
  onClick: handleBack
@@ -686,7 +742,8 @@ const useTemplateParameterSchema = (templateRef) => {
686
742
  return { schema: value, loading, error };
687
743
  };
688
744
  const TemplatePage = ({
689
- customFieldExtensions = []
745
+ customFieldExtensions = [],
746
+ layouts = []
690
747
  }) => {
691
748
  const apiHolder = useApiHolder();
692
749
  const secretsContext = useContext(SecretsContext);
@@ -771,6 +828,7 @@ const TemplatePage = ({
771
828
  onChange: handleChange,
772
829
  onReset: handleFormReset,
773
830
  onFinish: handleCreate,
831
+ layouts,
774
832
  steps: schema.steps.map((step) => {
775
833
  return {
776
834
  ...step,
@@ -923,6 +981,9 @@ class WebDirectoryAccess {
923
981
  if (handle.kind === "file") {
924
982
  yield new WebFileAccess([...basePath, handle.name].join("/"), handle);
925
983
  } else if (handle.kind === "directory") {
984
+ if (handle.name === ".git") {
985
+ continue;
986
+ }
926
987
  yield* this.listDirectoryContents(handle, [...basePath, handle.name]);
927
988
  }
928
989
  }
@@ -1763,7 +1824,8 @@ function TemplateEditorForm(props) {
1763
1824
  onUpdate,
1764
1825
  onDryRun,
1765
1826
  setErrorText,
1766
- fieldExtensions = []
1827
+ fieldExtensions = [],
1828
+ layouts = []
1767
1829
  } = props;
1768
1830
  const classes = useStyles$4();
1769
1831
  const apiHolder = useApiHolder();
@@ -1841,7 +1903,8 @@ function TemplateEditorForm(props) {
1841
1903
  onChange: (e) => onUpdate(e.formData),
1842
1904
  onReset: () => onUpdate({}),
1843
1905
  finishButtonLabel: onDryRun && "Try It",
1844
- onFinish: onDryRun && (() => onDryRun(data))
1906
+ onFinish: onDryRun && (() => onDryRun(data)),
1907
+ layouts
1845
1908
  }))));
1846
1909
  }
1847
1910
  function TemplateEditorFormDirectoryEditorDryRun(props) {
@@ -2022,7 +2085,8 @@ const TemplateEditor = (props) => {
2022
2085
  className: classes.preview
2023
2086
  }, /* @__PURE__ */ React.createElement(TemplateEditorForm.DirectoryEditorDryRun, {
2024
2087
  setErrorText,
2025
- fieldExtensions: props.fieldExtensions
2088
+ fieldExtensions: props.fieldExtensions,
2089
+ layouts: props.layouts
2026
2090
  })), /* @__PURE__ */ React.createElement("section", {
2027
2091
  className: classes.results
2028
2092
  }, /* @__PURE__ */ React.createElement(DryRunResults, null)))));
@@ -2094,7 +2158,8 @@ const useStyles$1 = makeStyles((theme) => ({
2094
2158
  const TemplateFormPreviewer = ({
2095
2159
  defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,
2096
2160
  customFieldExtensions = [],
2097
- onClose
2161
+ onClose,
2162
+ layouts = []
2098
2163
  }) => {
2099
2164
  const classes = useStyles$1();
2100
2165
  const alertApi = useApi(alertApiRef);
@@ -2176,7 +2241,8 @@ const TemplateFormPreviewer = ({
2176
2241
  fieldExtensions: customFieldExtensions,
2177
2242
  data: formState,
2178
2243
  onUpdate: setFormState,
2179
- setErrorText
2244
+ setErrorText,
2245
+ layouts
2180
2246
  }))));
2181
2247
  };
2182
2248
 
@@ -2187,13 +2253,15 @@ function TemplateEditorPage(props) {
2187
2253
  content = /* @__PURE__ */ React.createElement(TemplateEditor, {
2188
2254
  directory: selection.directory,
2189
2255
  fieldExtensions: props.customFieldExtensions,
2190
- onClose: () => setSelection(void 0)
2256
+ onClose: () => setSelection(void 0),
2257
+ layouts: props.layouts
2191
2258
  });
2192
2259
  } else if ((selection == null ? void 0 : selection.type) === "form") {
2193
2260
  content = /* @__PURE__ */ React.createElement(TemplateFormPreviewer, {
2194
2261
  defaultPreviewTemplate: props.defaultPreviewTemplate,
2195
2262
  customFieldExtensions: props.customFieldExtensions,
2196
- onClose: () => setSelection(void 0)
2263
+ onClose: () => setSelection(void 0),
2264
+ layouts: props.layouts
2197
2265
  });
2198
2266
  } else {
2199
2267
  content = /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(TemplateEditorIntro, {
@@ -2461,6 +2529,14 @@ const Router = (props) => {
2461
2529
  )
2462
2530
  )
2463
2531
  ];
2532
+ const customLayouts = useElementFilter(
2533
+ outlet,
2534
+ (elements) => elements.selectByComponentData({
2535
+ key: LAYOUTS_WRAPPER_KEY
2536
+ }).findComponentData({
2537
+ key: LAYOUTS_KEY
2538
+ })
2539
+ );
2464
2540
  const RedirectingComponent = () => {
2465
2541
  const { templateName } = useRouteRefParams(legacySelectedTemplateRouteRef);
2466
2542
  const newLink = useRouteRef(selectedTemplateRouteRef);
@@ -2487,7 +2563,8 @@ const Router = (props) => {
2487
2563
  }), /* @__PURE__ */ React.createElement(Route, {
2488
2564
  path: selectedTemplateRouteRef.path,
2489
2565
  element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplatePage, {
2490
- customFieldExtensions: fieldExtensions
2566
+ customFieldExtensions: fieldExtensions,
2567
+ layouts: customLayouts
2491
2568
  }))
2492
2569
  }), /* @__PURE__ */ React.createElement(Route, {
2493
2570
  path: scaffolderListTaskRouteRef.path,
@@ -2502,7 +2579,8 @@ const Router = (props) => {
2502
2579
  path: editRouteRef.path,
2503
2580
  element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplateEditorPage, {
2504
2581
  defaultPreviewTemplate,
2505
- customFieldExtensions: fieldExtensions
2582
+ customFieldExtensions: fieldExtensions,
2583
+ layouts: customLayouts
2506
2584
  }))
2507
2585
  }), /* @__PURE__ */ React.createElement(Route, {
2508
2586
  path: "preview",
@@ -2513,4 +2591,4 @@ const Router = (props) => {
2513
2591
  };
2514
2592
 
2515
2593
  export { Router };
2516
- //# sourceMappingURL=Router-7a18bcf2.esm.js.map
2594
+ //# sourceMappingURL=Router-7e8b8be7.esm.js.map