@backstage/plugin-scaffolder 1.35.5-next.2 → 1.36.1
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 +36 -0
- package/README.md +61 -53
- package/dist/alpha/components/EditorSubPage.esm.js +71 -0
- package/dist/alpha/components/EditorSubPage.esm.js.map +1 -0
- package/dist/alpha/components/TasksSubPage.esm.js +21 -0
- package/dist/alpha/components/TasksSubPage.esm.js.map +1 -0
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js +54 -4
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -1
- package/dist/alpha/components/TemplatesSubPage.esm.js +128 -0
- package/dist/alpha/components/TemplatesSubPage.esm.js.map +1 -0
- package/dist/alpha/extensions.esm.js +55 -14
- package/dist/alpha/extensions.esm.js.map +1 -1
- package/dist/alpha/formFieldsApi.esm.js +25 -8
- package/dist/alpha/formFieldsApi.esm.js.map +1 -1
- package/dist/alpha/plugin.esm.js +7 -2
- package/dist/alpha/plugin.esm.js.map +1 -1
- package/dist/alpha.d.ts +316 -185
- package/dist/alpha.esm.js +5 -1
- package/dist/alpha.esm.js.map +1 -1
- package/dist/components/ActionsPage/index.esm.js +2 -0
- package/dist/components/ActionsPage/index.esm.js.map +1 -0
- package/dist/components/ListTasksPage/ListTasksPage.esm.js +1 -1
- package/dist/components/ListTasksPage/ListTasksPage.esm.js.map +1 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js +283 -101
- package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -1
- package/dist/components/OngoingTask/OngoingTaskContextMenu.esm.js +97 -0
- package/dist/components/OngoingTask/OngoingTaskContextMenu.esm.js.map +1 -0
- package/dist/components/TemplatingExtensionsPage/index.esm.js +2 -0
- package/dist/components/TemplatingExtensionsPage/index.esm.js.map +1 -0
- package/dist/components/fields/EntityPicker/schema.esm.js.map +1 -1
- package/dist/components/fields/MultiEntityPicker/schema.esm.js +1 -1
- package/dist/components/fields/MultiEntityPicker/schema.esm.js.map +1 -1
- package/dist/components/fields/utils.esm.js.map +1 -1
- package/dist/index.d.ts +189 -3
- package/dist/index.esm.js +1 -1
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormDecorator.esm.js.map +1 -1
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -1
- package/dist/plugins/scaffolder/package.json.esm.js +4 -2
- package/dist/plugins/scaffolder/package.json.esm.js.map +1 -1
- package/dist/translation.esm.js +1 -0
- package/dist/translation.esm.js.map +1 -1
- package/package.json +28 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 1.36.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 29238ae: Fixed the layout of the scaffolder plugin in the new frontend system to use the new page layout.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/ui@0.13.1
|
|
10
|
+
- @backstage/frontend-plugin-api@0.15.1
|
|
11
|
+
|
|
12
|
+
## 1.36.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 0be2541: Promoted the plugin's translation ref to the stable package entry point. It was previously only available through the alpha entry point.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- e27bd4e: Removed check for deprecated `bitbucket` integration from `repoPickerValidation` function used by the `RepoUrlPicker`, it now validates the `bitbucketServer` and `bitbucketCloud` integrations instead.
|
|
21
|
+
- 538c985: Updated installation documentation to use feature discovery as the default.
|
|
22
|
+
- bd5b842: Added a new `ui:autoSelect` option to the EntityPicker field that controls whether an entity is automatically selected when the field loses focus. When set to `false`, the field will remain empty if the user closes it without explicitly selecting an entity, preventing unintentional selections. Defaults to `true` for backward compatibility.
|
|
23
|
+
- 3f36ce1: Updated alpha plugin icons to follow the new frontend icon sizing rules when rendered in plugin and navigation surfaces.
|
|
24
|
+
- a49a40d: Updated dependency `zod` to `^3.25.76 || ^4.0.0` & migrated to `/v3` or `/v4` imports.
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- @backstage/plugin-catalog-react@2.1.0
|
|
27
|
+
- @backstage/core-plugin-api@1.12.4
|
|
28
|
+
- @backstage/core-components@0.18.8
|
|
29
|
+
- @backstage/frontend-plugin-api@0.15.0
|
|
30
|
+
- @backstage/catalog-client@1.14.0
|
|
31
|
+
- @backstage/plugin-scaffolder-react@1.20.0
|
|
32
|
+
- @backstage/integration@2.0.0
|
|
33
|
+
- @backstage/plugin-permission-react@0.4.41
|
|
34
|
+
- @backstage/plugin-scaffolder-common@2.0.0
|
|
35
|
+
- @backstage/catalog-model@1.7.7
|
|
36
|
+
- @backstage/integration-react@1.2.16
|
|
37
|
+
- @backstage/plugin-techdocs-react@1.3.9
|
|
38
|
+
|
|
3
39
|
## 1.35.5-next.2
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -15,13 +15,72 @@ To check if you already have the package, look under
|
|
|
15
15
|
`@backstage/plugin-scaffolder`. The instructions below walk through restoring
|
|
16
16
|
the plugin, if you previously removed it.
|
|
17
17
|
|
|
18
|
-
### Install the package
|
|
19
|
-
|
|
20
18
|
```bash
|
|
21
19
|
# From your Backstage root directory
|
|
22
20
|
yarn --cwd packages/app add @backstage/plugin-scaffolder
|
|
23
21
|
```
|
|
24
22
|
|
|
23
|
+
Once installed, the plugin is automatically available in your app through the default feature discovery. For more details and alternative installation methods, see [installing plugins](https://backstage.io/docs/frontend-system/building-apps/installing-plugins).
|
|
24
|
+
|
|
25
|
+
### Troubleshooting
|
|
26
|
+
|
|
27
|
+
If you encounter [issues with early closure of the `EventStream`](https://github.com/backstage/backstage/issues/5535)
|
|
28
|
+
used to auto-update logs during task execution, you can work around them by enabling
|
|
29
|
+
long polling. To do so, update your `packages/app/src/apis.ts` file to register a
|
|
30
|
+
`ScaffolderClient` with `useLongPollingLogs` set to `true`. By default, it is `false`.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import {
|
|
34
|
+
AnyApiFactory,
|
|
35
|
+
createApiFactory,
|
|
36
|
+
discoveryApiRef,
|
|
37
|
+
fetchApiRef,
|
|
38
|
+
identityApiRef,
|
|
39
|
+
} from '@backstage/core-plugin-api';
|
|
40
|
+
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
|
41
|
+
import {
|
|
42
|
+
scaffolderApiRef,
|
|
43
|
+
ScaffolderClient,
|
|
44
|
+
} from '@backstage/plugin-scaffolder';
|
|
45
|
+
|
|
46
|
+
export const apis: AnyApiFactory[] = [
|
|
47
|
+
createApiFactory({
|
|
48
|
+
api: scaffolderApiRef,
|
|
49
|
+
deps: {
|
|
50
|
+
discoveryApi: discoveryApiRef,
|
|
51
|
+
identityApi: identityApiRef,
|
|
52
|
+
scmIntegrationsApi: scmIntegrationsApiRef,
|
|
53
|
+
fetchApi: fetchApiRef,
|
|
54
|
+
},
|
|
55
|
+
factory: ({ scmIntegrationsApi, discoveryApi, identityApi, fetchApi }) =>
|
|
56
|
+
new ScaffolderClient({
|
|
57
|
+
discoveryApi,
|
|
58
|
+
identityApi,
|
|
59
|
+
scmIntegrationsApi,
|
|
60
|
+
fetchApi,
|
|
61
|
+
useLongPollingLogs: true,
|
|
62
|
+
}),
|
|
63
|
+
}),
|
|
64
|
+
// ... other factories
|
|
65
|
+
];
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This replaces the default implementation of the `scaffolderApiRef`.
|
|
69
|
+
|
|
70
|
+
### Local development
|
|
71
|
+
|
|
72
|
+
When you develop a new template, action or new `<ScaffolderFieldExtensions/>`, then we recommend
|
|
73
|
+
to launch the plugin locally using the `createDevApp` of the `./dev/index.tsx` file for testing/Debugging purposes
|
|
74
|
+
|
|
75
|
+
To play with it, open a terminal and run the command: `yarn start` within the `./plugins/scaffolder` folder
|
|
76
|
+
|
|
77
|
+
**NOTE:** Don't forget to open a second terminal, start your Backstage backend there,
|
|
78
|
+
and configure the template locations that you want to test.
|
|
79
|
+
|
|
80
|
+
## Old Frontend System
|
|
81
|
+
|
|
82
|
+
If your Backstage app uses the old frontend system, you need to manually wire the plugin into your app as outlined in this section. If you are on the new frontend system, you can skip this.
|
|
83
|
+
|
|
25
84
|
### Add the plugin to your `packages/app`
|
|
26
85
|
|
|
27
86
|
Add the root page that the scaffolder plugin provides to your app. You can
|
|
@@ -78,57 +137,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
|
|
|
78
137
|
</Sidebar>
|
|
79
138
|
```
|
|
80
139
|
|
|
81
|
-
### Troubleshooting
|
|
82
|
-
|
|
83
|
-
If you encounter the [issue of closing EventStream](https://github.com/backstage/backstage/issues/5535)
|
|
84
|
-
which auto-updates logs during task execution, you can enable long polling. To do so,
|
|
85
|
-
update your `packages/app/src/apis.ts` file to register a `ScaffolderClient` with the
|
|
86
|
-
`useLongPollingLogs` set to `true`. By default, it is `false`.
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
import {
|
|
90
|
-
createApiFactory,
|
|
91
|
-
discoveryApiRef,
|
|
92
|
-
fetchApiRef,
|
|
93
|
-
identityApiRef,
|
|
94
|
-
} from '@backstage/core-plugin-api';
|
|
95
|
-
import {
|
|
96
|
-
scaffolderApiRef,
|
|
97
|
-
ScaffolderClient,
|
|
98
|
-
} from '@backstage/plugin-scaffolder';
|
|
99
|
-
|
|
100
|
-
export const apis: AnyApiFactory[] = [
|
|
101
|
-
createApiFactory({
|
|
102
|
-
api: scaffolderApiRef,
|
|
103
|
-
deps: {
|
|
104
|
-
discoveryApi: discoveryApiRef,
|
|
105
|
-
identityApi: identityApiRef,
|
|
106
|
-
scmIntegrationsApi: scmIntegrationsApiRef,
|
|
107
|
-
fetchApi: fetchApiRef,
|
|
108
|
-
},
|
|
109
|
-
factory: ({ scmIntegrationsApi, discoveryApi, identityApi, fetchApi }) =>
|
|
110
|
-
new ScaffolderClient({
|
|
111
|
-
discoveryApi,
|
|
112
|
-
identityApi,
|
|
113
|
-
scmIntegrationsApi,
|
|
114
|
-
fetchApi,
|
|
115
|
-
useLongPollingLogs: true,
|
|
116
|
-
}),
|
|
117
|
-
}),
|
|
118
|
-
// ... other factories
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
This replaces the default implementation of the `scaffolderApiRef`.
|
|
122
|
-
|
|
123
|
-
### Local development
|
|
124
|
-
|
|
125
|
-
When you develop a new template, action or new `<ScaffolderFieldExtensions/>`, then we recommend
|
|
126
|
-
to launch the plugin locally using the `createDevApp` of the `./dev/index.tsx` file for testing/Debugging purposes
|
|
127
|
-
|
|
128
|
-
To play with it, open a terminal and run the command: `yarn start` within the `./plugins/scaffolder` folder
|
|
129
|
-
|
|
130
|
-
**NOTE:** Don't forget to open a second terminal and to launch the backend or [backend-next](../../docs/backend-system/index.md) there, using `yarn start` and to specify the locations of the templates to play with !
|
|
131
|
-
|
|
132
140
|
## Links
|
|
133
141
|
|
|
134
142
|
- [scaffolder-backend](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { Routes, Route, useNavigate } from 'react-router-dom';
|
|
4
|
+
import { Content } from '@backstage/core-components';
|
|
5
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
6
|
+
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
7
|
+
import { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha';
|
|
8
|
+
import { SecretsContextProvider } from '@backstage/plugin-scaffolder-react';
|
|
9
|
+
import { TemplateEditorIntro } from './TemplateEditorPage/TemplateEditorIntro.esm.js';
|
|
10
|
+
import { TemplateEditor } from './TemplateEditorPage/TemplateEditor.esm.js';
|
|
11
|
+
import { TemplateFormPreviewer } from './TemplateEditorPage/TemplateFormPreviewer.esm.js';
|
|
12
|
+
import { CustomFieldExplorer } from './TemplateEditorPage/CustomFieldExplorer.esm.js';
|
|
13
|
+
import { useTemplateDirectory } from './TemplateEditorPage/useTemplateDirectory.esm.js';
|
|
14
|
+
|
|
15
|
+
const useEditorStyles = makeStyles({
|
|
16
|
+
editorContent: {
|
|
17
|
+
padding: 0,
|
|
18
|
+
height: "calc(100dvh - var(--bui-header-height, 0px))"
|
|
19
|
+
},
|
|
20
|
+
formContent: {
|
|
21
|
+
padding: 0,
|
|
22
|
+
height: "calc(100dvh - var(--bui-header-height, 0px))"
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
function EditorIntroContent() {
|
|
26
|
+
const navigate = useNavigate();
|
|
27
|
+
const { openDirectory, createDirectory } = useTemplateDirectory();
|
|
28
|
+
const handleSelect = useCallback(
|
|
29
|
+
(option) => {
|
|
30
|
+
if (option === "local") {
|
|
31
|
+
openDirectory().then(() => navigate("template")).catch(() => {
|
|
32
|
+
});
|
|
33
|
+
} else if (option === "create-template") {
|
|
34
|
+
createDirectory().then(() => navigate("template")).catch(() => {
|
|
35
|
+
});
|
|
36
|
+
} else if (option === "form") {
|
|
37
|
+
navigate("template-form");
|
|
38
|
+
} else if (option === "field-explorer") {
|
|
39
|
+
navigate("custom-fields");
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
[openDirectory, createDirectory, navigate]
|
|
43
|
+
);
|
|
44
|
+
return /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(TemplateEditorIntro, { onSelect: handleSelect }) });
|
|
45
|
+
}
|
|
46
|
+
function EditorContent() {
|
|
47
|
+
const classes = useEditorStyles();
|
|
48
|
+
return /* @__PURE__ */ jsx(Content, { className: classes.editorContent, children: /* @__PURE__ */ jsx(TemplateEditor, {}) });
|
|
49
|
+
}
|
|
50
|
+
function FormPreviewContent() {
|
|
51
|
+
const classes = useEditorStyles();
|
|
52
|
+
const navigate = useNavigate();
|
|
53
|
+
const handleClose = useCallback(() => {
|
|
54
|
+
navigate("..");
|
|
55
|
+
}, [navigate]);
|
|
56
|
+
return /* @__PURE__ */ jsx(Content, { className: classes.formContent, children: /* @__PURE__ */ jsx(TemplateFormPreviewer, { onClose: handleClose }) });
|
|
57
|
+
}
|
|
58
|
+
function CustomFieldsContent() {
|
|
59
|
+
return /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(CustomFieldExplorer, {}) });
|
|
60
|
+
}
|
|
61
|
+
function EditorSubPage() {
|
|
62
|
+
return /* @__PURE__ */ jsx(RequirePermission, { permission: templateManagementPermission, children: /* @__PURE__ */ jsx(SecretsContextProvider, { children: /* @__PURE__ */ jsxs(Routes, { children: [
|
|
63
|
+
/* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(EditorIntroContent, {}) }),
|
|
64
|
+
/* @__PURE__ */ jsx(Route, { path: "template", element: /* @__PURE__ */ jsx(EditorContent, {}) }),
|
|
65
|
+
/* @__PURE__ */ jsx(Route, { path: "template-form", element: /* @__PURE__ */ jsx(FormPreviewContent, {}) }),
|
|
66
|
+
/* @__PURE__ */ jsx(Route, { path: "custom-fields", element: /* @__PURE__ */ jsx(CustomFieldsContent, {}) })
|
|
67
|
+
] }) }) });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { EditorSubPage };
|
|
71
|
+
//# sourceMappingURL=EditorSubPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorSubPage.esm.js","sources":["../../../src/alpha/components/EditorSubPage.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback } from 'react';\nimport { Routes, Route, useNavigate } from 'react-router-dom';\nimport { Content } from '@backstage/core-components';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { SecretsContextProvider } from '@backstage/plugin-scaffolder-react';\nimport { TemplateEditorIntro } from './TemplateEditorPage/TemplateEditorIntro';\nimport { TemplateEditor } from './TemplateEditorPage/TemplateEditor';\nimport { TemplateFormPreviewer } from './TemplateEditorPage/TemplateFormPreviewer';\nimport { CustomFieldExplorer } from './TemplateEditorPage/CustomFieldExplorer';\nimport { useTemplateDirectory } from './TemplateEditorPage/useTemplateDirectory';\n\nconst useEditorStyles = makeStyles({\n editorContent: {\n padding: 0,\n height: 'calc(100dvh - var(--bui-header-height, 0px))',\n },\n formContent: {\n padding: 0,\n height: 'calc(100dvh - var(--bui-header-height, 0px))',\n },\n});\n\nfunction EditorIntroContent() {\n const navigate = useNavigate();\n const { openDirectory, createDirectory } = useTemplateDirectory();\n\n const handleSelect = useCallback(\n (option: 'create-template' | 'local' | 'form' | 'field-explorer') => {\n if (option === 'local') {\n openDirectory()\n .then(() => navigate('template'))\n .catch(() => {});\n } else if (option === 'create-template') {\n createDirectory()\n .then(() => navigate('template'))\n .catch(() => {});\n } else if (option === 'form') {\n navigate('template-form');\n } else if (option === 'field-explorer') {\n navigate('custom-fields');\n }\n },\n [openDirectory, createDirectory, navigate],\n );\n\n return (\n <Content>\n <TemplateEditorIntro onSelect={handleSelect} />\n </Content>\n );\n}\n\nfunction EditorContent() {\n const classes = useEditorStyles();\n return (\n <Content className={classes.editorContent}>\n <TemplateEditor />\n </Content>\n );\n}\n\nfunction FormPreviewContent() {\n const classes = useEditorStyles();\n const navigate = useNavigate();\n\n const handleClose = useCallback(() => {\n navigate('..');\n }, [navigate]);\n\n return (\n <Content className={classes.formContent}>\n <TemplateFormPreviewer onClose={handleClose} />\n </Content>\n );\n}\n\nfunction CustomFieldsContent() {\n return (\n <Content>\n <CustomFieldExplorer />\n </Content>\n );\n}\n\n/**\n * Sub-page for the template editor tab. Renders the editor intro at the index,\n * with sub-routes for the full editor, form previewer, and custom fields explorer.\n *\n * @internal\n */\nexport function EditorSubPage() {\n return (\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <Routes>\n <Route index element={<EditorIntroContent />} />\n <Route path=\"template\" element={<EditorContent />} />\n <Route path=\"template-form\" element={<FormPreviewContent />} />\n <Route path=\"custom-fields\" element={<CustomFieldsContent />} />\n </Routes>\n </SecretsContextProvider>\n </RequirePermission>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3
|
+
import { Content } from '@backstage/core-components';
|
|
4
|
+
import { OngoingTaskBody } from '../../components/OngoingTask/OngoingTask.esm.js';
|
|
5
|
+
import { ListTaskPageContent } from '../../components/ListTasksPage/ListTasksPage.esm.js';
|
|
6
|
+
|
|
7
|
+
function TasksSubPage() {
|
|
8
|
+
return /* @__PURE__ */ jsxs(Routes, { children: [
|
|
9
|
+
/* @__PURE__ */ jsx(
|
|
10
|
+
Route,
|
|
11
|
+
{
|
|
12
|
+
index: true,
|
|
13
|
+
element: /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(ListTaskPageContent, {}) })
|
|
14
|
+
}
|
|
15
|
+
),
|
|
16
|
+
/* @__PURE__ */ jsx(Route, { path: ":taskId", element: /* @__PURE__ */ jsx(OngoingTaskBody, {}) })
|
|
17
|
+
] });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { TasksSubPage };
|
|
21
|
+
//# sourceMappingURL=TasksSubPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TasksSubPage.esm.js","sources":["../../../src/alpha/components/TasksSubPage.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Routes, Route } from 'react-router-dom';\nimport { Content } from '@backstage/core-components';\nimport { OngoingTaskBody } from '../../components/OngoingTask';\nimport { ListTaskPageContent } from '../../components/ListTasksPage';\n\n/**\n * Sub-page for the tasks tab. Renders the task list at the index route\n * and the ongoing task detail at the parameterized route.\n *\n * @internal\n */\nexport function TasksSubPage() {\n return (\n <Routes>\n <Route\n index\n element={\n <Content>\n <ListTaskPageContent />\n </Content>\n }\n />\n <Route path=\":taskId\" element={<OngoingTaskBody />} />\n </Routes>\n );\n}\n"],"names":[],"mappings":";;;;;;AA2BO,SAAS,YAAA,GAAe;AAC7B,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAK,IAAA;AAAA,QACL,OAAA,kBACE,GAAA,CAAC,OAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,uBAAoB,CAAA,EACvB;AAAA;AAAA,KAEJ;AAAA,wBACC,KAAA,EAAA,EAAM,IAAA,EAAK,WAAU,OAAA,kBAAS,GAAA,CAAC,mBAAgB,CAAA,EAAI;AAAA,GAAA,EACtD,CAAA;AAEJ;;;;"}
|
|
@@ -3,10 +3,10 @@ import { useState, useCallback } from 'react';
|
|
|
3
3
|
import { useNavigate, Navigate } from 'react-router-dom';
|
|
4
4
|
import useAsync from 'react-use/esm/useAsync';
|
|
5
5
|
import { stringifyEntityRef, ANNOTATION_EDIT_URL } from '@backstage/catalog-model';
|
|
6
|
-
import { useRouteRef, useApi, useRouteRefParams
|
|
6
|
+
import { AnalyticsContext, useRouteRef, useApi, useRouteRefParams } from '@backstage/core-plugin-api';
|
|
7
7
|
import { useTemplateSecrets, scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
|
|
8
8
|
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
|
9
|
-
import {
|
|
9
|
+
import { Workflow, useTemplateParameterSchema } from '@backstage/plugin-scaffolder-react/alpha';
|
|
10
10
|
import { Page, Header, Progress } from '@backstage/core-components';
|
|
11
11
|
import { rootRouteRef, scaffolderTaskRouteRef, selectedTemplateRouteRef } from '../../../routes.esm.js';
|
|
12
12
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
@@ -14,7 +14,7 @@ import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
|
14
14
|
import { TemplateWizardPageContextMenu } from './TemplateWizardPageContextMenu.esm.js';
|
|
15
15
|
import { useFormDecorators } from '../../hooks/useFormDecorators.esm.js';
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
function useTemplateWizard(_props) {
|
|
18
18
|
const rootRef = useRouteRef(rootRouteRef);
|
|
19
19
|
const taskRoute = useRouteRef(scaffolderTaskRouteRef);
|
|
20
20
|
const { secrets: contextSecrets } = useTemplateSecrets();
|
|
@@ -67,6 +67,56 @@ const TemplateWizardPage = (props) => {
|
|
|
67
67
|
]
|
|
68
68
|
);
|
|
69
69
|
const onError = useCallback(() => /* @__PURE__ */ jsx(Navigate, { to: rootRef() }), [rootRef]);
|
|
70
|
+
return {
|
|
71
|
+
templateRef,
|
|
72
|
+
templateName,
|
|
73
|
+
namespace,
|
|
74
|
+
manifest,
|
|
75
|
+
editUrl,
|
|
76
|
+
isCreating,
|
|
77
|
+
onCreate,
|
|
78
|
+
onError,
|
|
79
|
+
t
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const TemplateWizardPageContent = (props) => {
|
|
83
|
+
const {
|
|
84
|
+
templateRef,
|
|
85
|
+
templateName,
|
|
86
|
+
namespace,
|
|
87
|
+
isCreating,
|
|
88
|
+
onCreate,
|
|
89
|
+
onError
|
|
90
|
+
} = useTemplateWizard();
|
|
91
|
+
return /* @__PURE__ */ jsxs(AnalyticsContext, { attributes: { entityRef: templateRef }, children: [
|
|
92
|
+
isCreating && /* @__PURE__ */ jsx(Progress, {}),
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
Workflow,
|
|
95
|
+
{
|
|
96
|
+
namespace,
|
|
97
|
+
templateName,
|
|
98
|
+
onCreate,
|
|
99
|
+
components: props.components,
|
|
100
|
+
onError,
|
|
101
|
+
extensions: props.customFieldExtensions,
|
|
102
|
+
formProps: props.formProps,
|
|
103
|
+
layouts: props.layouts
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
] });
|
|
107
|
+
};
|
|
108
|
+
const TemplateWizardPage = (props) => {
|
|
109
|
+
const {
|
|
110
|
+
templateRef,
|
|
111
|
+
templateName,
|
|
112
|
+
namespace,
|
|
113
|
+
manifest,
|
|
114
|
+
editUrl,
|
|
115
|
+
isCreating,
|
|
116
|
+
onCreate,
|
|
117
|
+
onError,
|
|
118
|
+
t
|
|
119
|
+
} = useTemplateWizard();
|
|
70
120
|
return /* @__PURE__ */ jsx(AnalyticsContext, { attributes: { entityRef: templateRef }, children: /* @__PURE__ */ jsxs(Page, { themeId: "website", children: [
|
|
71
121
|
/* @__PURE__ */ jsx(
|
|
72
122
|
Header,
|
|
@@ -97,5 +147,5 @@ const TemplateWizardPage = (props) => {
|
|
|
97
147
|
] }) });
|
|
98
148
|
};
|
|
99
149
|
|
|
100
|
-
export { TemplateWizardPage };
|
|
150
|
+
export { TemplateWizardPage, TemplateWizardPageContent };
|
|
101
151
|
//# sourceMappingURL=TemplateWizardPage.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateWizardPage.esm.js","sources":["../../../../src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ComponentType, useCallback, useState } from 'react';\nimport { Navigate, useNavigate } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n stringifyEntityRef,\n ANNOTATION_EDIT_URL,\n} from '@backstage/catalog-model';\nimport {\n AnalyticsContext,\n useApi,\n useRouteRef,\n useRouteRefParams,\n} from '@backstage/core-plugin-api';\nimport {\n scaffolderApiRef,\n useTemplateSecrets,\n type LayoutOptions,\n FormProps,\n FieldExtensionOptions,\n ReviewStepProps,\n} from '@backstage/plugin-scaffolder-react';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\n\nimport {\n Workflow,\n useTemplateParameterSchema,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport { JsonValue } from '@backstage/types';\nimport { Header, Page, Progress } from '@backstage/core-components';\n\nimport {\n rootRouteRef,\n scaffolderTaskRouteRef,\n selectedTemplateRouteRef,\n} from '../../../routes';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nimport { TemplateWizardPageContextMenu } from './TemplateWizardPageContextMenu';\nimport { useFormDecorators } from '../../hooks';\n\n/**\n * @alpha\n */\nexport type TemplateWizardPageProps = {\n customFieldExtensions: FieldExtensionOptions<any, any>[];\n components?: {\n ReviewStepComponent?: ComponentType<ReviewStepProps>;\n };\n layouts?: LayoutOptions[];\n formProps?: FormProps;\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\
|
|
1
|
+
{"version":3,"file":"TemplateWizardPage.esm.js","sources":["../../../../src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ComponentType, useCallback, useState } from 'react';\nimport { Navigate, useNavigate } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n stringifyEntityRef,\n ANNOTATION_EDIT_URL,\n} from '@backstage/catalog-model';\nimport {\n AnalyticsContext,\n useApi,\n useRouteRef,\n useRouteRefParams,\n} from '@backstage/core-plugin-api';\nimport {\n scaffolderApiRef,\n useTemplateSecrets,\n type LayoutOptions,\n FormProps,\n FieldExtensionOptions,\n ReviewStepProps,\n} from '@backstage/plugin-scaffolder-react';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\n\nimport {\n Workflow,\n useTemplateParameterSchema,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport { JsonValue } from '@backstage/types';\nimport { Header, Page, Progress } from '@backstage/core-components';\n\nimport {\n rootRouteRef,\n scaffolderTaskRouteRef,\n selectedTemplateRouteRef,\n} from '../../../routes';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nimport { TemplateWizardPageContextMenu } from './TemplateWizardPageContextMenu';\nimport { useFormDecorators } from '../../hooks';\n\n/**\n * @alpha\n */\nexport type TemplateWizardPageProps = {\n customFieldExtensions: FieldExtensionOptions<any, any>[];\n components?: {\n ReviewStepComponent?: ComponentType<ReviewStepProps>;\n };\n layouts?: LayoutOptions[];\n formProps?: FormProps;\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\nfunction useTemplateWizard(_props: TemplateWizardPageProps) {\n const rootRef = useRouteRef(rootRouteRef);\n const taskRoute = useRouteRef(scaffolderTaskRouteRef);\n const { secrets: contextSecrets } = useTemplateSecrets();\n const scaffolderApi = useApi(scaffolderApiRef);\n const catalogApi = useApi(catalogApiRef);\n const [isCreating, setIsCreating] = useState(false);\n const navigate = useNavigate();\n const { templateName, namespace } = useRouteRefParams(\n selectedTemplateRouteRef,\n );\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const templateRef = stringifyEntityRef({\n kind: 'Template',\n namespace,\n name: templateName,\n });\n\n const { manifest } = useTemplateParameterSchema(templateRef);\n const decorators = useFormDecorators();\n\n const { value: editUrl } = useAsync(async () => {\n const data = await catalogApi.getEntityByRef(templateRef);\n return data?.metadata.annotations?.[ANNOTATION_EDIT_URL];\n }, [templateRef, catalogApi]);\n\n const onCreate = useCallback(\n async (initialValues: Record<string, JsonValue>) => {\n if (isCreating) {\n return;\n }\n\n setIsCreating(true);\n\n const { formState: values, secrets } = await decorators.run({\n formState: initialValues,\n secrets: contextSecrets,\n manifest,\n });\n\n const { taskId } = await scaffolderApi.scaffold({\n templateRef,\n values,\n secrets,\n });\n\n navigate(taskRoute({ taskId }));\n },\n [\n contextSecrets,\n decorators,\n isCreating,\n manifest,\n navigate,\n scaffolderApi,\n taskRoute,\n templateRef,\n ],\n );\n\n const onError = useCallback(() => <Navigate to={rootRef()} />, [rootRef]);\n\n return {\n templateRef,\n templateName,\n namespace,\n manifest,\n editUrl,\n isCreating,\n onCreate,\n onError,\n t,\n };\n}\n\n/**\n * Content-only version of the template wizard, for use within the NFS page layout\n * where the header is provided by the framework.\n *\n * @internal\n */\nexport const TemplateWizardPageContent = (props: TemplateWizardPageProps) => {\n const {\n templateRef,\n templateName,\n namespace,\n isCreating,\n onCreate,\n onError,\n } = useTemplateWizard(props);\n\n return (\n <AnalyticsContext attributes={{ entityRef: templateRef }}>\n {isCreating && <Progress />}\n <Workflow\n namespace={namespace}\n templateName={templateName}\n onCreate={onCreate}\n components={props.components}\n onError={onError}\n extensions={props.customFieldExtensions}\n formProps={props.formProps}\n layouts={props.layouts}\n />\n </AnalyticsContext>\n );\n};\n\nexport const TemplateWizardPage = (props: TemplateWizardPageProps) => {\n const {\n templateRef,\n templateName,\n namespace,\n manifest,\n editUrl,\n isCreating,\n onCreate,\n onError,\n t,\n } = useTemplateWizard(props);\n\n return (\n <AnalyticsContext attributes={{ entityRef: templateRef }}>\n <Page themeId=\"website\">\n <Header\n pageTitleOverride={\n manifest?.title\n ? t('templateWizardPage.templateWithTitle', {\n templateTitle: manifest.title,\n })\n : t('templateWizardPage.pageTitle')\n }\n title={t('templateWizardPage.title')}\n subtitle={t('templateWizardPage.subtitle')}\n {...props.headerOptions}\n >\n <TemplateWizardPageContextMenu editUrl={editUrl} />\n </Header>\n {isCreating && <Progress />}\n <Workflow\n namespace={namespace}\n templateName={templateName}\n onCreate={onCreate}\n components={props.components}\n onError={onError}\n extensions={props.customFieldExtensions}\n formProps={props.formProps}\n layouts={props.layouts}\n />\n </Page>\n </AnalyticsContext>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { Routes, Route, useNavigate } from 'react-router-dom';
|
|
4
|
+
import { DocsIcon, Content, ContentHeader, SupportButton } from '@backstage/core-components';
|
|
5
|
+
import { useRouteRef, useApp } from '@backstage/core-plugin-api';
|
|
6
|
+
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
7
|
+
import { EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, EntityOwnerPicker } from '@backstage/plugin-catalog-react';
|
|
8
|
+
import { TemplateCategoryPicker, TemplateGroups } from '@backstage/plugin-scaffolder-react/alpha';
|
|
9
|
+
import { useCustomFieldExtensions, useCustomLayouts, SecretsContextProvider } from '@backstage/plugin-scaffolder-react';
|
|
10
|
+
import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
11
|
+
import { RegisterExistingButton } from './TemplateListPage/RegisterExistingButton.esm.js';
|
|
12
|
+
import { TemplateWizardPageContent } from './TemplateWizardPage/TemplateWizardPage.esm.js';
|
|
13
|
+
import { registerComponentRouteRef, viewTechDocRouteRef, selectedTemplateRouteRef } from '../../routes.esm.js';
|
|
14
|
+
import { scaffolderTranslationRef } from '../../translation.esm.js';
|
|
15
|
+
import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default.esm.js';
|
|
16
|
+
import { buildTechDocsURL } from '@backstage/plugin-techdocs-react';
|
|
17
|
+
import { TECHDOCS_ANNOTATION, TECHDOCS_EXTERNAL_ANNOTATION } from '@backstage/plugin-techdocs-common';
|
|
18
|
+
import { OpaqueFormField } from '../../packages/scaffolder-internal/src/wiring/InternalFormField.esm.js';
|
|
19
|
+
|
|
20
|
+
function TemplateListContent() {
|
|
21
|
+
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
22
|
+
const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);
|
|
23
|
+
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
24
|
+
const navigate = useNavigate();
|
|
25
|
+
const app = useApp();
|
|
26
|
+
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
27
|
+
const groups = [
|
|
28
|
+
{
|
|
29
|
+
title: t("templateListPage.templateGroups.defaultTitle"),
|
|
30
|
+
filter: () => true
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
const additionalLinksForEntity = useCallback(
|
|
34
|
+
(template) => {
|
|
35
|
+
if (!(template.metadata.annotations?.[TECHDOCS_ANNOTATION] || template.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) || !viewTechDocsLink) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const url = buildTechDocsURL(template, viewTechDocsLink);
|
|
39
|
+
return url ? [
|
|
40
|
+
{
|
|
41
|
+
icon: app.getSystemIcon("docs") ?? DocsIcon,
|
|
42
|
+
text: t(
|
|
43
|
+
"templateListPage.additionalLinksForEntity.viewTechDocsTitle"
|
|
44
|
+
),
|
|
45
|
+
url
|
|
46
|
+
}
|
|
47
|
+
] : [];
|
|
48
|
+
},
|
|
49
|
+
[app, viewTechDocsLink, t]
|
|
50
|
+
);
|
|
51
|
+
const onTemplateSelected = useCallback(
|
|
52
|
+
(template) => {
|
|
53
|
+
const { namespace, name } = parseEntityRef(stringifyEntityRef(template));
|
|
54
|
+
navigate(templateRoute({ namespace, templateName: name }));
|
|
55
|
+
},
|
|
56
|
+
[navigate, templateRoute]
|
|
57
|
+
);
|
|
58
|
+
return /* @__PURE__ */ jsx(EntityListProvider, { children: /* @__PURE__ */ jsxs(Content, { children: [
|
|
59
|
+
/* @__PURE__ */ jsxs(ContentHeader, { children: [
|
|
60
|
+
/* @__PURE__ */ jsx(
|
|
61
|
+
RegisterExistingButton,
|
|
62
|
+
{
|
|
63
|
+
title: t(
|
|
64
|
+
"templateListPage.contentHeader.registerExistingButtonTitle"
|
|
65
|
+
),
|
|
66
|
+
to: registerComponentLink && registerComponentLink()
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
/* @__PURE__ */ jsx(SupportButton, { children: t("templateListPage.contentHeader.supportButtonTitle") })
|
|
70
|
+
] }),
|
|
71
|
+
/* @__PURE__ */ jsxs(CatalogFilterLayout, { children: [
|
|
72
|
+
/* @__PURE__ */ jsxs(CatalogFilterLayout.Filters, { children: [
|
|
73
|
+
/* @__PURE__ */ jsx(EntitySearchBar, {}),
|
|
74
|
+
/* @__PURE__ */ jsx(EntityKindPicker, { initialFilter: "template", hidden: true }),
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
UserListPicker,
|
|
77
|
+
{
|
|
78
|
+
initialFilter: "all",
|
|
79
|
+
availableFilters: ["all", "starred"]
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
/* @__PURE__ */ jsx(TemplateCategoryPicker, {}),
|
|
83
|
+
/* @__PURE__ */ jsx(EntityTagPicker, {}),
|
|
84
|
+
/* @__PURE__ */ jsx(EntityOwnerPicker, {})
|
|
85
|
+
] }),
|
|
86
|
+
/* @__PURE__ */ jsx(CatalogFilterLayout.Content, { children: /* @__PURE__ */ jsx(
|
|
87
|
+
TemplateGroups,
|
|
88
|
+
{
|
|
89
|
+
groups,
|
|
90
|
+
onTemplateSelected,
|
|
91
|
+
additionalLinksForEntity
|
|
92
|
+
}
|
|
93
|
+
) })
|
|
94
|
+
] })
|
|
95
|
+
] }) });
|
|
96
|
+
}
|
|
97
|
+
function TemplatesSubPage(props) {
|
|
98
|
+
const customFieldExtensions = useCustomFieldExtensions(void 0);
|
|
99
|
+
const customLayouts = useCustomLayouts(void 0);
|
|
100
|
+
const fieldExtensions = [
|
|
101
|
+
...customFieldExtensions,
|
|
102
|
+
...props.formFields?.map(OpaqueFormField.toInternal) ?? [],
|
|
103
|
+
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(
|
|
104
|
+
({ name }) => !customFieldExtensions.some(
|
|
105
|
+
(customFieldExtension) => customFieldExtension.name === name
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
];
|
|
109
|
+
return /* @__PURE__ */ jsxs(Routes, { children: [
|
|
110
|
+
/* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(TemplateListContent, {}) }),
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
Route,
|
|
113
|
+
{
|
|
114
|
+
path: ":namespace/:templateName",
|
|
115
|
+
element: /* @__PURE__ */ jsx(SecretsContextProvider, { children: /* @__PURE__ */ jsx(
|
|
116
|
+
TemplateWizardPageContent,
|
|
117
|
+
{
|
|
118
|
+
customFieldExtensions: fieldExtensions,
|
|
119
|
+
layouts: customLayouts
|
|
120
|
+
}
|
|
121
|
+
) })
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
] });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { TemplatesSubPage };
|
|
128
|
+
//# sourceMappingURL=TemplatesSubPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatesSubPage.esm.js","sources":["../../../src/alpha/components/TemplatesSubPage.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback } from 'react';\nimport { Routes, Route, useNavigate } from 'react-router-dom';\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n SupportButton,\n} from '@backstage/core-components';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport {\n FieldExtensionOptions,\n SecretsContextProvider,\n useCustomFieldExtensions,\n useCustomLayouts,\n} from '@backstage/plugin-scaffolder-react';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { FormField } from '@backstage/plugin-scaffolder-react/alpha';\nimport { OpaqueFormField } from '@internal/scaffolder';\nimport { RegisterExistingButton } from './TemplateListPage/RegisterExistingButton';\nimport { TemplateWizardPageContent } from './TemplateWizardPage';\nimport {\n registerComponentRouteRef,\n selectedTemplateRouteRef,\n viewTechDocRouteRef,\n} from '../../routes';\nimport { scaffolderTranslationRef } from '../../translation';\nimport { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default';\nimport { buildTechDocsURL } from '@backstage/plugin-techdocs-react';\nimport {\n TECHDOCS_ANNOTATION,\n TECHDOCS_EXTERNAL_ANNOTATION,\n} from '@backstage/plugin-techdocs-common';\n\nfunction TemplateListContent() {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const navigate = useNavigate();\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ];\n\n const additionalLinksForEntity = useCallback(\n (template: TemplateEntityV1beta3) => {\n if (\n !(\n template.metadata.annotations?.[TECHDOCS_ANNOTATION] ||\n template.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]\n ) ||\n !viewTechDocsLink\n ) {\n return [];\n }\n\n const url = buildTechDocsURL(template, viewTechDocsLink);\n return url\n ? [\n {\n icon: app.getSystemIcon('docs') ?? DocsIcon,\n text: t(\n 'templateListPage.additionalLinksForEntity.viewTechDocsTitle',\n ),\n url,\n },\n ]\n : [];\n },\n [app, viewTechDocsLink, t],\n );\n\n const onTemplateSelected = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { namespace, name } = parseEntityRef(stringifyEntityRef(template));\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Content>\n <ContentHeader>\n <RegisterExistingButton\n title={t(\n 'templateListPage.contentHeader.registerExistingButtonTitle',\n )}\n to={registerComponentLink && registerComponentLink()}\n />\n <SupportButton>\n {t('templateListPage.contentHeader.supportButtonTitle')}\n </SupportButton>\n </ContentHeader>\n\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <EntitySearchBar />\n <EntityKindPicker initialFilter=\"template\" hidden />\n <UserListPicker\n initialFilter=\"all\"\n availableFilters={['all', 'starred']}\n />\n <TemplateCategoryPicker />\n <EntityTagPicker />\n <EntityOwnerPicker />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n <TemplateGroups\n groups={groups}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </EntityListProvider>\n );\n}\n\n/**\n * Sub-page for the templates tab. Renders the template list at the index route\n * and the template wizard at the parameterized route.\n *\n * @internal\n */\nexport function TemplatesSubPage(props: { formFields?: Array<FormField> }) {\n const customFieldExtensions = useCustomFieldExtensions(undefined);\n const customLayouts = useCustomLayouts(undefined);\n\n const fieldExtensions = [\n ...customFieldExtensions,\n ...(props.formFields?.map(OpaqueFormField.toInternal) ?? []),\n ...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(\n ({ name }) =>\n !customFieldExtensions.some(\n (customFieldExtension: FieldExtensionOptions) =>\n customFieldExtension.name === name,\n ),\n ),\n ] as FieldExtensionOptions[];\n\n return (\n <Routes>\n <Route index element={<TemplateListContent />} />\n <Route\n path=\":namespace/:templateName\"\n element={\n <SecretsContextProvider>\n <TemplateWizardPageContent\n customFieldExtensions={fieldExtensions}\n layouts={customLayouts}\n />\n </SecretsContextProvider>\n }\n />\n </Routes>\n );\n}\n"],"names":[],"mappings":"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"}
|