@backstage/plugin-scaffolder 1.36.3-next.0 → 1.37.0-next.2
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 +76 -0
- package/dist/alpha/api/FormDecoratorsApi.esm.js.map +1 -1
- package/dist/alpha/api/ref.esm.js.map +1 -1
- package/dist/alpha/components/TemplateEditorPage/CustomFieldExplorer.esm.js +4 -4
- package/dist/alpha/components/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -1
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlayground.esm.js +5 -5
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlayground.esm.js.map +1 -1
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js +14 -14
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js.map +1 -1
- package/dist/alpha/components/TemplatesSubPage.esm.js +20 -10
- package/dist/alpha/components/TemplatesSubPage.esm.js.map +1 -1
- package/dist/alpha/extensions.esm.js +28 -2
- package/dist/alpha/extensions.esm.js.map +1 -1
- package/dist/alpha/hooks/useFormDecorators.esm.js +34 -3
- package/dist/alpha/hooks/useFormDecorators.esm.js.map +1 -1
- package/dist/alpha/lib/createGroupsWithOther.esm.js +13 -0
- package/dist/alpha/lib/createGroupsWithOther.esm.js.map +1 -0
- package/dist/alpha.d.ts +14 -4
- package/dist/components/TemplateTypePicker/TemplateTypePicker.esm.js +4 -4
- package/dist/components/TemplateTypePicker/TemplateTypePicker.esm.js.map +1 -1
- package/dist/components/TemplatingExtensionsPage/TemplatingExtensionsPage.esm.js +4 -4
- package/dist/components/TemplatingExtensionsPage/TemplatingExtensionsPage.esm.js.map +1 -1
- package/dist/components/fields/Autocomplete/Autocomplete.esm.js +23 -0
- package/dist/components/fields/Autocomplete/Autocomplete.esm.js.map +1 -0
- package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js +23 -2
- package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js.map +1 -1
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js +125 -9
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -1
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js +106 -7
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js.map +1 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +128 -10
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js +66 -6
- package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js.map +1 -1
- package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js +29 -6
- package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/OwnedEntityPicker/schema.esm.js +1 -0
- package/dist/components/fields/OwnedEntityPicker/schema.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.esm.js +29 -5
- package/dist/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.esm.js +20 -3
- package/dist/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/GitHubRepoBranchPicker.esm.js +29 -5
- package/dist/components/fields/RepoBranchPicker/GitHubRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/RepoBranchPicker.esm.js +18 -6
- package/dist/components/fields/RepoBranchPicker/RepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.esm.js +20 -3
- package/dist/components/fields/RepoOwnerPicker/DefaultRepoOwnerPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.esm.js +29 -5
- package/dist/components/fields/RepoOwnerPicker/GitHubRepoOwnerPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoOwnerPicker/RepoOwnerPicker.esm.js +28 -31
- package/dist/components/fields/RepoOwnerPicker/RepoOwnerPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js +86 -4
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js +107 -11
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js +33 -3
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js +42 -5
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js +52 -7
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js +60 -16
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js +23 -9
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js +27 -3
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js +60 -6
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js.map +1 -1
- package/dist/components/fields/SecretInput/SecretInput.esm.js +57 -2
- package/dist/components/fields/SecretInput/SecretInput.esm.js.map +1 -1
- package/dist/components/fields/buiChipStyles.esm.js +25 -0
- package/dist/components/fields/buiChipStyles.esm.js.map +1 -0
- package/dist/components/fields/scaffolderFieldOverrides.module.css.esm.js +8 -0
- package/dist/components/fields/scaffolderFieldOverrides.module.css.esm.js.map +1 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/node_modules_dist/style-inject/dist/style-inject.es.esm.js +29 -0
- package/dist/node_modules_dist/style-inject/dist/style-inject.es.esm.js.map +1 -0
- package/dist/plugins/scaffolder/package.json.esm.js +4 -2
- package/dist/plugins/scaffolder/package.json.esm.js.map +1 -1
- package/package.json +18 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 1.37.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- dbeb7aa: Added experimental BUI (Backstage UI) form theme for scaffolder forms. All default field extensions render BUI variants when enabled.
|
|
8
|
+
|
|
9
|
+
**Extension config:**
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
app:
|
|
13
|
+
extensions:
|
|
14
|
+
- sub-page:scaffolder/templates:
|
|
15
|
+
config:
|
|
16
|
+
enableBackstageUi: true
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**JSX props:**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<ScaffolderPage formProps={{ EXPERIMENTAL_theme: 'bui' }} />
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- 8006acf: Promoted `formDecoratorsApiRef`, `ScaffolderFormDecoratorsApi`,
|
|
26
|
+
`DefaultScaffolderFormDecoratorsApi`, and `formDecoratorsApi` from `@alpha`
|
|
27
|
+
to `@public`.
|
|
28
|
+
- d09c21c: The `sub-page:scaffolder/templates` extension now accepts a `groups` config
|
|
29
|
+
field that lets you define template groups on the template list page. Each group
|
|
30
|
+
has a `title` and a `filter` predicate. Templates not matched by any
|
|
31
|
+
configured group fall into an automatically appended "Other Templates" group.
|
|
32
|
+
With no groups configured, the page renders a single "Templates" group as
|
|
33
|
+
before.
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
app:
|
|
39
|
+
extensions:
|
|
40
|
+
- sub-page:scaffolder/templates:
|
|
41
|
+
config:
|
|
42
|
+
groups:
|
|
43
|
+
- title: Recommended Services
|
|
44
|
+
filter:
|
|
45
|
+
spec.type: service
|
|
46
|
+
- title: Documentation
|
|
47
|
+
filter:
|
|
48
|
+
spec.type: documentation
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Patch Changes
|
|
52
|
+
|
|
53
|
+
- 1ecc3ca: Fixed spelling mistakes in internal code
|
|
54
|
+
- 8006acf: Form decorator input is now parsed against the zod schema configured on the
|
|
55
|
+
decorator before the decorator runs, so defaults declared via `.default()`
|
|
56
|
+
are applied and invalid input is reported through the error API instead of
|
|
57
|
+
silently passing through.
|
|
58
|
+
- 8006acf: The template wizard now reads form decorators from the new
|
|
59
|
+
`spec.formDecorators` field on a template, falling back to the deprecated
|
|
60
|
+
`spec.EXPERIMENTAL_formDecorators` for templates that have not been migrated.
|
|
61
|
+
- Updated dependencies
|
|
62
|
+
- @backstage/plugin-scaffolder-react@1.21.0-next.1
|
|
63
|
+
- @backstage/ui@0.15.0-next.3
|
|
64
|
+
- @backstage/plugin-scaffolder-common@2.2.0-next.1
|
|
65
|
+
- @backstage/plugin-catalog-react@2.1.5-next.1
|
|
66
|
+
|
|
67
|
+
## 1.36.3-next.1
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- f635139: Limited `@remixicon/react` dependency to versions below 4.9.0 due to a license change in that release.
|
|
72
|
+
- Updated dependencies
|
|
73
|
+
- @backstage/ui@0.15.0-next.1
|
|
74
|
+
- @backstage/frontend-plugin-api@0.17.0-next.1
|
|
75
|
+
- @backstage/catalog-model@1.8.1-next.1
|
|
76
|
+
- @backstage/core-plugin-api@1.12.6-next.1
|
|
77
|
+
- @backstage/plugin-catalog-react@2.1.5-next.1
|
|
78
|
+
|
|
3
79
|
## 1.36.3-next.0
|
|
4
80
|
|
|
5
81
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormDecoratorsApi.esm.js","sources":["../../../src/alpha/api/FormDecoratorsApi.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n ApiBlueprint,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport { ScaffolderFormDecoratorsApi } from './types';\nimport { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha';\nimport { formDecoratorsApiRef } from './ref';\nimport { FormDecoratorBlueprint } from '@backstage/plugin-scaffolder-react/alpha';\n\n/** @
|
|
1
|
+
{"version":3,"file":"FormDecoratorsApi.esm.js","sources":["../../../src/alpha/api/FormDecoratorsApi.ts"],"sourcesContent":["/*\n * Copyright 2024 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 {\n ApiBlueprint,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport { ScaffolderFormDecoratorsApi } from './types';\nimport { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha';\nimport { formDecoratorsApiRef } from './ref';\nimport { FormDecoratorBlueprint } from '@backstage/plugin-scaffolder-react/alpha';\n\n/** @public */\nexport class DefaultScaffolderFormDecoratorsApi\n implements ScaffolderFormDecoratorsApi\n{\n private readonly options: {\n decorators: Array<ScaffolderFormDecorator>;\n };\n\n private constructor(options: { decorators: Array<ScaffolderFormDecorator> }) {\n this.options = options;\n }\n\n static create(options?: { decorators: ScaffolderFormDecorator[] }) {\n return new DefaultScaffolderFormDecoratorsApi(\n options ?? { decorators: [] },\n );\n }\n\n async getFormDecorators(): Promise<ScaffolderFormDecorator[]> {\n return this.options.decorators;\n }\n}\n\n/** @public */\nexport const formDecoratorsApi = ApiBlueprint.makeWithOverrides({\n name: 'form-decorators',\n inputs: {\n formDecorators: createExtensionInput([\n FormDecoratorBlueprint.dataRefs.formDecoratorLoader,\n ]),\n },\n factory(originalFactory, { inputs }) {\n const formDecorators = inputs.formDecorators.map(e =>\n e.get(FormDecoratorBlueprint.dataRefs.formDecoratorLoader),\n );\n\n return originalFactory(defineParams =>\n defineParams({\n api: formDecoratorsApiRef,\n deps: {},\n factory: () =>\n DefaultScaffolderFormDecoratorsApi.create({\n decorators: formDecorators,\n }),\n }),\n );\n },\n});\n"],"names":[],"mappings":";;;;AA0BO,MAAM,kCAAA,CAEb;AAAA,EACmB,OAAA;AAAA,EAIT,YAAY,OAAA,EAAyD;AAC3E,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAEA,OAAO,OAAO,OAAA,EAAqD;AACjE,IAAA,OAAO,IAAI,kCAAA;AAAA,MACT,OAAA,IAAW,EAAE,UAAA,EAAY,EAAC;AAAE,KAC9B;AAAA,EACF;AAAA,EAEA,MAAM,iBAAA,GAAwD;AAC5D,IAAA,OAAO,KAAK,OAAA,CAAQ,UAAA;AAAA,EACtB;AACF;AAGO,MAAM,iBAAA,GAAoB,aAAa,iBAAA,CAAkB;AAAA,EAC9D,IAAA,EAAM,iBAAA;AAAA,EACN,MAAA,EAAQ;AAAA,IACN,gBAAgB,oBAAA,CAAqB;AAAA,MACnC,uBAAuB,QAAA,CAAS;AAAA,KACjC;AAAA,GACH;AAAA,EACA,OAAA,CAAQ,eAAA,EAAiB,EAAE,MAAA,EAAO,EAAG;AACnC,IAAA,MAAM,cAAA,GAAiB,OAAO,cAAA,CAAe,GAAA;AAAA,MAAI,CAAA,CAAA,KAC/C,CAAA,CAAE,GAAA,CAAI,sBAAA,CAAuB,SAAS,mBAAmB;AAAA,KAC3D;AAEA,IAAA,OAAO,eAAA;AAAA,MAAgB,kBACrB,YAAA,CAAa;AAAA,QACX,GAAA,EAAK,oBAAA;AAAA,QACL,MAAM,EAAC;AAAA,QACP,OAAA,EAAS,MACP,kCAAA,CAAmC,MAAA,CAAO;AAAA,UACxC,UAAA,EAAY;AAAA,SACb;AAAA,OACJ;AAAA,KACH;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref.esm.js","sources":["../../../src/alpha/api/ref.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { createApiRef } from '@backstage/frontend-plugin-api';\nimport { ScaffolderFormDecoratorsApi } from './types';\n\n/** @
|
|
1
|
+
{"version":3,"file":"ref.esm.js","sources":["../../../src/alpha/api/ref.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { createApiRef } from '@backstage/frontend-plugin-api';\nimport { ScaffolderFormDecoratorsApi } from './types';\n\n/** @public */\nexport const formDecoratorsApiRef = createApiRef<ScaffolderFormDecoratorsApi>({\n id: 'plugin.scaffolder.form-decorators',\n});\n"],"names":[],"mappings":";;AAoBO,MAAM,uBAAuB,YAAA,CAA0C;AAAA,EAC5E,EAAA,EAAI;AACN,CAAC;;;;"}
|
|
@@ -15,9 +15,9 @@ import validator from '@rjsf/validator-ajv8';
|
|
|
15
15
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
16
16
|
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
17
17
|
import InputAdornment from '@material-ui/core/InputAdornment';
|
|
18
|
-
import
|
|
18
|
+
import MuiTextField from '@material-ui/core/TextField';
|
|
19
19
|
import SearchIcon from '@material-ui/icons/Search';
|
|
20
|
-
import
|
|
20
|
+
import MuiAutocomplete from '@material-ui/lab/Autocomplete';
|
|
21
21
|
|
|
22
22
|
const useStyles = makeStyles(
|
|
23
23
|
(theme) => ({
|
|
@@ -106,14 +106,14 @@ const CustomFieldExplorer = ({
|
|
|
106
106
|
);
|
|
107
107
|
return /* @__PURE__ */ jsxs("main", { className: classes.root, children: [
|
|
108
108
|
/* @__PURE__ */ jsx("div", { className: classes.controls, children: /* @__PURE__ */ jsx(
|
|
109
|
-
|
|
109
|
+
MuiAutocomplete,
|
|
110
110
|
{
|
|
111
111
|
id: "custom-fields-autocomplete",
|
|
112
112
|
value: selectedField,
|
|
113
113
|
options: fieldOptions,
|
|
114
114
|
getOptionLabel: (option) => option.name,
|
|
115
115
|
renderInput: (params) => /* @__PURE__ */ jsx(
|
|
116
|
-
|
|
116
|
+
MuiTextField,
|
|
117
117
|
{
|
|
118
118
|
...params,
|
|
119
119
|
"aria-label": t(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomFieldExplorer.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldExplorer.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 { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport Button from '@material-ui/core/Button';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport validator from '@rjsf/validator-ajv8';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport InputAdornment from '@material-ui/core/InputAdornment';\nimport TextField from '@material-ui/core/TextField';\nimport SearchIcon from '@material-ui/icons/Search';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\n\n/** @public */\nexport type ScaffolderCustomFieldExplorerClassKey =\n | 'root'\n | 'controls'\n | 'fieldForm'\n | 'preview';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridGap: theme.spacing(2),\n gridTemplateAreas: `\n \"controls\"\n \"fieldForm\"\n \"preview\"\n `,\n [theme.breakpoints.up('md')]: {\n gridTemplateAreas: `\n \"controls controls\"\n \"fieldForm preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n },\n controls: {\n gridArea: 'controls',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n },\n fieldForm: {\n gridArea: 'fieldForm',\n },\n preview: {\n gridArea: 'preview',\n display: 'grid',\n gridGap: theme.spacing(2),\n alignContent: 'start',\n },\n }),\n { name: 'ScaffolderCustomFieldExplorer' },\n);\n\nexport const CustomFieldExplorer = ({\n customFieldExtensions = [],\n}: {\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = customFieldExtensions.filter(field => !!field.schema);\n const [selectedField, setSelectedField] = useState(fieldOptions?.[0]);\n const [fieldFormState, setFieldFormState] = useState({});\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const sampleFieldTemplate = useMemo(() => {\n if (!selectedField) {\n return '';\n }\n return yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n });\n }, [fieldFormState, selectedField]);\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [customFieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <Autocomplete\n id=\"custom-fields-autocomplete\"\n value={selectedField}\n options={fieldOptions}\n getOptionLabel={option => option.name}\n renderInput={params => (\n <TextField\n {...params}\n aria-label={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n placeholder={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n )}\n onChange={(_event, option) => {\n if (option) {\n handleSelectionChange(option);\n }\n }}\n disableClearable\n fullWidth\n />\n </div>\n <div className={classes.fieldForm}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n />\n <CardContent>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField?.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField?.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </CardContent>\n </Card>\n </div>\n <div className={classes.preview}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.preview.title')}\n />\n <CardContent>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </CardContent>\n </Card>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={() => null}\n />\n </div>\n </main>\n );\n};\n"],"names":["yamlSupport"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CustomFieldExplorer.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldExplorer.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 { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport Button from '@material-ui/core/Button';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport validator from '@rjsf/validator-ajv8';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport InputAdornment from '@material-ui/core/InputAdornment';\nimport TextField from '@material-ui/core/TextField';\nimport SearchIcon from '@material-ui/icons/Search';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\n\n/** @public */\nexport type ScaffolderCustomFieldExplorerClassKey =\n | 'root'\n | 'controls'\n | 'fieldForm'\n | 'preview';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridGap: theme.spacing(2),\n gridTemplateAreas: `\n \"controls\"\n \"fieldForm\"\n \"preview\"\n `,\n [theme.breakpoints.up('md')]: {\n gridTemplateAreas: `\n \"controls controls\"\n \"fieldForm preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n },\n controls: {\n gridArea: 'controls',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n },\n fieldForm: {\n gridArea: 'fieldForm',\n },\n preview: {\n gridArea: 'preview',\n display: 'grid',\n gridGap: theme.spacing(2),\n alignContent: 'start',\n },\n }),\n { name: 'ScaffolderCustomFieldExplorer' },\n);\n\nexport const CustomFieldExplorer = ({\n customFieldExtensions = [],\n}: {\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = customFieldExtensions.filter(field => !!field.schema);\n const [selectedField, setSelectedField] = useState(fieldOptions?.[0]);\n const [fieldFormState, setFieldFormState] = useState({});\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const sampleFieldTemplate = useMemo(() => {\n if (!selectedField) {\n return '';\n }\n return yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n });\n }, [fieldFormState, selectedField]);\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [customFieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <Autocomplete\n id=\"custom-fields-autocomplete\"\n value={selectedField}\n options={fieldOptions}\n getOptionLabel={option => option.name}\n renderInput={params => (\n <TextField\n {...params}\n aria-label={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n placeholder={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n )}\n onChange={(_event, option) => {\n if (option) {\n handleSelectionChange(option);\n }\n }}\n disableClearable\n fullWidth\n />\n </div>\n <div className={classes.fieldForm}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n />\n <CardContent>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField?.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField?.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </CardContent>\n </Card>\n </div>\n <div className={classes.preview}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.preview.title')}\n />\n <CardContent>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </CardContent>\n </Card>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={() => null}\n />\n </div>\n </main>\n );\n};\n"],"names":["Autocomplete","TextField","yamlSupport"],"mappings":"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"}
|
|
@@ -9,8 +9,8 @@ import { makeStyles } from '@material-ui/core/styles';
|
|
|
9
9
|
import Accordion from '@material-ui/core/Accordion';
|
|
10
10
|
import AccordionSummary from '@material-ui/core/AccordionSummary';
|
|
11
11
|
import AccordionDetails from '@material-ui/core/AccordionDetails';
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import MuiAutocomplete from '@material-ui/lab/Autocomplete';
|
|
13
|
+
import MuiTextField from '@material-ui/core/TextField';
|
|
14
14
|
import Button from '@material-ui/core/Button';
|
|
15
15
|
import InputAdornment from '@material-ui/core/InputAdornment';
|
|
16
16
|
import Typography from '@material-ui/core/Typography';
|
|
@@ -35,7 +35,7 @@ const useStyles = makeStyles(
|
|
|
35
35
|
width: "100%"
|
|
36
36
|
}
|
|
37
37
|
}),
|
|
38
|
-
{ name: "
|
|
38
|
+
{ name: "ScaffolderCustomFieldExtensionsPlayground" }
|
|
39
39
|
);
|
|
40
40
|
const CustomFieldPlayground = ({
|
|
41
41
|
fieldExtensions = []
|
|
@@ -83,14 +83,14 @@ const CustomFieldPlayground = ({
|
|
|
83
83
|
}, []);
|
|
84
84
|
return /* @__PURE__ */ jsxs("main", { className: classes.root, children: [
|
|
85
85
|
/* @__PURE__ */ jsx("div", { className: classes.controls, children: /* @__PURE__ */ jsx(
|
|
86
|
-
|
|
86
|
+
MuiAutocomplete,
|
|
87
87
|
{
|
|
88
88
|
id: "custom-fields-autocomplete",
|
|
89
89
|
value: selectedField,
|
|
90
90
|
options: fieldOptions,
|
|
91
91
|
getOptionLabel: (option) => option.name,
|
|
92
92
|
renderInput: (params) => /* @__PURE__ */ jsx(
|
|
93
|
-
|
|
93
|
+
MuiTextField,
|
|
94
94
|
{
|
|
95
95
|
...params,
|
|
96
96
|
"aria-label": t(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomFieldPlayground.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldPlayground.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 */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport validator from '@rjsf/validator-ajv8';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport TextField from '@material-ui/core/TextField';\nimport Button from '@material-ui/core/Button';\nimport InputAdornment from '@material-ui/core/InputAdornment';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport SearchIcon from '@material-ui/icons/Search';\n\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { TemplateEditorForm } from './TemplateEditorForm';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateRows: 'auto 1fr',\n },\n controls: {\n marginBottom: theme.spacing(3),\n },\n code: {\n width: '100%',\n },\n }),\n { name: 'ScaffolderCustomFieldExtensionsPlaygroud' },\n);\n\nexport const CustomFieldPlayground = ({\n fieldExtensions = [],\n}: {\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = fieldExtensions.filter(field => !!field.schema);\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const [fieldFormState, setFieldFormState] = useState({});\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const sampleFieldTemplate = useMemo(() => {\n if (!selectedField) {\n return '';\n }\n\n return yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n });\n }, [fieldFormState, selectedField]);\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n fieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [fieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [],\n );\n\n const handleFieldConfigChange = useCallback((state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n }, []);\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <Autocomplete\n id=\"custom-fields-autocomplete\"\n value={selectedField}\n options={fieldOptions}\n getOptionLabel={option => option.name}\n renderInput={params => (\n <TextField\n {...params}\n aria-label={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n placeholder={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n )}\n onChange={(_event, option) => {\n if (option) {\n handleSelectionChange(option);\n }\n }}\n disableClearable\n fullWidth\n />\n </div>\n <div>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-code-content\"\n id=\"panel-code-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.preview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <div className={classes.code}>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n width=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </div>\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-preview-content\"\n id=\"panel-preview-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldPreview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={fieldExtensions}\n setErrorText={() => null}\n />\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-options-content\"\n id=\"panel-options-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField?.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField?.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </AccordionDetails>\n </Accordion>\n </div>\n </main>\n );\n};\n"],"names":["yamlSupport"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CustomFieldPlayground.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldPlayground.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 */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport validator from '@rjsf/validator-ajv8';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport TextField from '@material-ui/core/TextField';\nimport Button from '@material-ui/core/Button';\nimport InputAdornment from '@material-ui/core/InputAdornment';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport SearchIcon from '@material-ui/icons/Search';\n\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { TemplateEditorForm } from './TemplateEditorForm';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateRows: 'auto 1fr',\n },\n controls: {\n marginBottom: theme.spacing(3),\n },\n code: {\n width: '100%',\n },\n }),\n { name: 'ScaffolderCustomFieldExtensionsPlayground' },\n);\n\nexport const CustomFieldPlayground = ({\n fieldExtensions = [],\n}: {\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = fieldExtensions.filter(field => !!field.schema);\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const [fieldFormState, setFieldFormState] = useState({});\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const sampleFieldTemplate = useMemo(() => {\n if (!selectedField) {\n return '';\n }\n\n return yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n });\n }, [fieldFormState, selectedField]);\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n fieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [fieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [],\n );\n\n const handleFieldConfigChange = useCallback((state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n }, []);\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <Autocomplete\n id=\"custom-fields-autocomplete\"\n value={selectedField}\n options={fieldOptions}\n getOptionLabel={option => option.name}\n renderInput={params => (\n <TextField\n {...params}\n aria-label={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n placeholder={t(\n 'templateEditorPage.customFieldExplorer.selectFieldLabel',\n )}\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n )}\n onChange={(_event, option) => {\n if (option) {\n handleSelectionChange(option);\n }\n }}\n disableClearable\n fullWidth\n />\n </div>\n <div>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-code-content\"\n id=\"panel-code-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.preview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <div className={classes.code}>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n width=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </div>\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-preview-content\"\n id=\"panel-preview-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldPreview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={fieldExtensions}\n setErrorText={() => null}\n />\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-options-content\"\n id=\"panel-options-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField?.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField?.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </AccordionDetails>\n </Accordion>\n </div>\n </main>\n );\n};\n"],"names":["Autocomplete","TextField","yamlSupport"],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useCallback } from 'react';
|
|
2
|
+
import { useMemo, useCallback } from 'react';
|
|
3
3
|
import { useNavigate } from 'react-router-dom';
|
|
4
4
|
import { useRouteRef, useApp } from '@backstage/core-plugin-api';
|
|
5
5
|
import { DocsIcon, Page, Header, Content, ContentHeader, SupportButton } from '@backstage/core-components';
|
|
6
6
|
import { EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, EntityOwnerPicker } from '@backstage/plugin-catalog-react';
|
|
7
7
|
import { ScaffolderPageContextMenu, TemplateCategoryPicker, TemplateGroups } from '@backstage/plugin-scaffolder-react/alpha';
|
|
8
|
+
import { createGroupsWithOther } from '../../lib/createGroupsWithOther.esm.js';
|
|
8
9
|
import { RegisterExistingButton } from './RegisterExistingButton.esm.js';
|
|
9
10
|
import { registerComponentRouteRef, editRouteRef, actionsRouteRef, scaffolderListTaskRouteRef, viewTechDocRouteRef, selectedTemplateRouteRef, templatingExtensionsRouteRef } from '../../../routes.esm.js';
|
|
10
11
|
import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
@@ -13,13 +14,6 @@ import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
|
13
14
|
import { buildTechDocsURL } from '@backstage/plugin-techdocs-react';
|
|
14
15
|
import { TECHDOCS_ANNOTATION, TECHDOCS_EXTERNAL_ANNOTATION } from '@backstage/plugin-techdocs-common';
|
|
15
16
|
|
|
16
|
-
const createGroupsWithOther = (groups, t) => [
|
|
17
|
-
...groups,
|
|
18
|
-
{
|
|
19
|
-
title: t("templateListPage.templateGroups.otherTitle"),
|
|
20
|
-
filter: (e) => ![...groups].some(({ filter }) => filter(e))
|
|
21
|
-
}
|
|
22
|
-
];
|
|
23
17
|
const TemplateListPage = (props) => {
|
|
24
18
|
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
25
19
|
const {
|
|
@@ -37,12 +31,18 @@ const TemplateListPage = (props) => {
|
|
|
37
31
|
const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);
|
|
38
32
|
const app = useApp();
|
|
39
33
|
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
40
|
-
const groups =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
const groups = useMemo(
|
|
35
|
+
() => givenGroups.length ? createGroupsWithOther(
|
|
36
|
+
givenGroups,
|
|
37
|
+
t("templateListPage.templateGroups.otherTitle")
|
|
38
|
+
) : [
|
|
39
|
+
{
|
|
40
|
+
title: t("templateListPage.templateGroups.defaultTitle"),
|
|
41
|
+
filter: () => true
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
[givenGroups, t]
|
|
45
|
+
);
|
|
46
46
|
const scaffolderPageContextMenuProps = {
|
|
47
47
|
onEditorClicked: props?.contextMenu?.editor !== false ? () => navigate(editorLink()) : void 0,
|
|
48
48
|
onActionsClicked: props?.contextMenu?.actions !== false ? () => navigate(actionsLink()) : void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateListPage.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/TemplateListPage.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 */\n\nimport { ComponentType, useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n Header,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n ScaffolderPageContextMenu,\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\n\nimport { RegisterExistingButton } from './RegisterExistingButton';\nimport {\n actionsRouteRef,\n editRouteRef,\n registerComponentRouteRef,\n scaffolderListTaskRouteRef,\n selectedTemplateRouteRef,\n templatingExtensionsRouteRef,\n viewTechDocRouteRef,\n} from '../../../routes';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';\nimport {\n TranslationFunction,\n useTranslationRef,\n} from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { buildTechDocsURL } from '@backstage/plugin-techdocs-react';\nimport {\n TECHDOCS_ANNOTATION,\n TECHDOCS_EXTERNAL_ANNOTATION,\n} from '@backstage/plugin-techdocs-common';\n\n/**\n * @alpha\n */\nexport type TemplateListPageProps = {\n TemplateCardComponent?: ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n contextMenu?: {\n editor?: boolean;\n actions?: boolean;\n tasks?: boolean;\n templatingExtensions?: boolean;\n };\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\nconst createGroupsWithOther = (\n groups: TemplateGroupFilter[],\n t: TranslationFunction<typeof scaffolderTranslationRef.T>,\n): TemplateGroupFilter[] => [\n ...groups,\n {\n title: t('templateListPage.templateGroups.otherTitle'),\n filter: e => ![...groups].some(({ filter }) => filter(e)),\n },\n];\n\n/**\n * @alpha\n */\nexport const TemplateListPage = (props: TemplateListPageProps) => {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const {\n TemplateCardComponent,\n groups: givenGroups = [],\n templateFilter,\n headerOptions,\n } = props;\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = givenGroups.length\n ? createGroupsWithOther(givenGroups, t)\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ];\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked:\n props?.contextMenu?.editor !== false\n ? () => navigate(editorLink())\n : undefined,\n onActionsClicked:\n props?.contextMenu?.actions !== false\n ? () => navigate(actionsLink())\n : undefined,\n onTasksClicked:\n props?.contextMenu?.tasks !== false\n ? () => navigate(tasksLink())\n : undefined,\n onTemplatingExtensionsClicked:\n props?.contextMenu?.templatingExtensions !== false\n ? () => navigate(templatingExtensionsLink())\n : undefined,\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\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templateListPage.pageTitle')}\n title={t('templateListPage.title')}\n subtitle={t('templateListPage.subtitle')}\n {...headerOptions}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\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 templateFilter={templateFilter}\n TemplateCardComponent={TemplateCardComponent}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </Page>\n </EntityListProvider>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateListPage.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/TemplateListPage.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 */\n\nimport { ComponentType, useCallback, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n Header,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n ScaffolderPageContextMenu,\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport { createGroupsWithOther } from '../../lib/createGroupsWithOther';\n\nimport { RegisterExistingButton } from './RegisterExistingButton';\nimport {\n actionsRouteRef,\n editRouteRef,\n registerComponentRouteRef,\n scaffolderListTaskRouteRef,\n selectedTemplateRouteRef,\n templatingExtensionsRouteRef,\n viewTechDocRouteRef,\n} from '../../../routes';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { buildTechDocsURL } from '@backstage/plugin-techdocs-react';\nimport {\n TECHDOCS_ANNOTATION,\n TECHDOCS_EXTERNAL_ANNOTATION,\n} from '@backstage/plugin-techdocs-common';\n\n/**\n * @alpha\n */\nexport type TemplateListPageProps = {\n TemplateCardComponent?: ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n contextMenu?: {\n editor?: boolean;\n actions?: boolean;\n tasks?: boolean;\n templatingExtensions?: boolean;\n };\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\n/**\n * @alpha\n */\nexport const TemplateListPage = (props: TemplateListPageProps) => {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const {\n TemplateCardComponent,\n groups: givenGroups = [],\n templateFilter,\n headerOptions,\n } = props;\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = useMemo(\n () =>\n givenGroups.length\n ? createGroupsWithOther(\n givenGroups,\n t('templateListPage.templateGroups.otherTitle'),\n )\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ],\n [givenGroups, t],\n );\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked:\n props?.contextMenu?.editor !== false\n ? () => navigate(editorLink())\n : undefined,\n onActionsClicked:\n props?.contextMenu?.actions !== false\n ? () => navigate(actionsLink())\n : undefined,\n onTasksClicked:\n props?.contextMenu?.tasks !== false\n ? () => navigate(tasksLink())\n : undefined,\n onTemplatingExtensionsClicked:\n props?.contextMenu?.templatingExtensions !== false\n ? () => navigate(templatingExtensionsLink())\n : undefined,\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\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templateListPage.pageTitle')}\n title={t('templateListPage.title')}\n subtitle={t('templateListPage.subtitle')}\n {...headerOptions}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\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 templateFilter={templateFilter}\n TemplateCardComponent={TemplateCardComponent}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </Page>\n </EntityListProvider>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useCallback } from 'react';
|
|
2
|
+
import { useMemo, useCallback } from 'react';
|
|
3
3
|
import { Routes, Route, useNavigate } from 'react-router-dom';
|
|
4
4
|
import { DocsIcon, Content, ContentHeader, SupportButton } from '@backstage/core-components';
|
|
5
5
|
import { useRouteRef, useApp } from '@backstage/core-plugin-api';
|
|
6
6
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
7
7
|
import { EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, EntityOwnerPicker } from '@backstage/plugin-catalog-react';
|
|
8
8
|
import { TemplateCategoryPicker, TemplateGroups } from '@backstage/plugin-scaffolder-react/alpha';
|
|
9
|
+
import { createGroupsWithOther } from '../lib/createGroupsWithOther.esm.js';
|
|
9
10
|
import { useCustomFieldExtensions, useCustomLayouts, SecretsContextProvider } from '@backstage/plugin-scaffolder-react';
|
|
10
11
|
import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
11
12
|
import { RegisterExistingButton } from './TemplateListPage/RegisterExistingButton.esm.js';
|
|
@@ -18,19 +19,27 @@ import { TECHDOCS_ANNOTATION, TECHDOCS_EXTERNAL_ANNOTATION } from '@backstage/pl
|
|
|
18
19
|
import { OpaqueFormField } from '../../packages/scaffolder-internal/src/wiring/InternalFormField.esm.js';
|
|
19
20
|
import '../../packages/scaffolder-internal/src/wiring/InternalFormDecorator.esm.js';
|
|
20
21
|
|
|
21
|
-
function TemplateListContent(
|
|
22
|
+
function TemplateListContent({
|
|
23
|
+
groups: configuredGroups
|
|
24
|
+
}) {
|
|
22
25
|
const registerComponentLink = useRouteRef(registerComponentRouteRef);
|
|
23
26
|
const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);
|
|
24
27
|
const templateRoute = useRouteRef(selectedTemplateRouteRef);
|
|
25
28
|
const navigate = useNavigate();
|
|
26
29
|
const app = useApp();
|
|
27
30
|
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
28
|
-
const groups =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const groups = useMemo(
|
|
32
|
+
() => configuredGroups?.length ? createGroupsWithOther(
|
|
33
|
+
configuredGroups,
|
|
34
|
+
t("templateListPage.templateGroups.otherTitle")
|
|
35
|
+
) : [
|
|
36
|
+
{
|
|
37
|
+
title: t("templateListPage.templateGroups.defaultTitle"),
|
|
38
|
+
filter: () => true
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
[configuredGroups, t]
|
|
42
|
+
);
|
|
34
43
|
const additionalLinksForEntity = useCallback(
|
|
35
44
|
(template) => {
|
|
36
45
|
if (!(template.metadata.annotations?.[TECHDOCS_ANNOTATION] || template.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) || !viewTechDocsLink) {
|
|
@@ -108,7 +117,7 @@ function TemplatesSubPage(props) {
|
|
|
108
117
|
)
|
|
109
118
|
];
|
|
110
119
|
return /* @__PURE__ */ jsxs(Routes, { children: [
|
|
111
|
-
/* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(TemplateListContent, {}) }),
|
|
120
|
+
/* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(TemplateListContent, { groups: props.groups }) }),
|
|
112
121
|
/* @__PURE__ */ jsx(
|
|
113
122
|
Route,
|
|
114
123
|
{
|
|
@@ -117,7 +126,8 @@ function TemplatesSubPage(props) {
|
|
|
117
126
|
TemplateWizardPageContent,
|
|
118
127
|
{
|
|
119
128
|
customFieldExtensions: fieldExtensions,
|
|
120
|
-
layouts: customLayouts
|
|
129
|
+
layouts: customLayouts,
|
|
130
|
+
formProps: props.formProps
|
|
121
131
|
}
|
|
122
132
|
) })
|
|
123
133
|
}
|
|
@@ -1 +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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"}
|
|
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, useMemo } 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 { createGroupsWithOther } from '../lib/createGroupsWithOther';\nimport {\n FieldExtensionOptions,\n FormProps,\n SecretsContextProvider,\n TemplateGroupFilter,\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 groups: configuredGroups,\n}: {\n groups?: TemplateGroupFilter[];\n}) {\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 = useMemo(\n () =>\n configuredGroups?.length\n ? createGroupsWithOther(\n configuredGroups,\n t('templateListPage.templateGroups.otherTitle'),\n )\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ],\n [configuredGroups, t],\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: {\n formFields?: Array<FormField>;\n formProps?: FormProps;\n groups?: TemplateGroupFilter[];\n}) {\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 groups={props.groups} />} />\n <Route\n path=\":namespace/:templateName\"\n element={\n <SecretsContextProvider>\n <TemplateWizardPageContent\n customFieldExtensions={fieldExtensions}\n layouts={customLayouts}\n formProps={props.formProps}\n />\n </SecretsContextProvider>\n }\n />\n </Routes>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { PageBlueprint, createExtensionInput, SubPageBlueprint, NavItemBlueprint, ApiBlueprint, identityApiRef, fetchApiRef, discoveryApiRef } from '@backstage/frontend-plugin-api';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
import { filterPredicateToFilterFunction, createZodV4FilterPredicateSchema } from '@backstage/filter-predicates';
|
|
3
5
|
import { rootRouteRef } from '../routes.esm.js';
|
|
4
6
|
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
|
|
5
7
|
import { FormFieldBlueprint, formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha';
|
|
@@ -23,14 +25,38 @@ const scaffolderPage = PageBlueprint.makeWithOverrides({
|
|
|
23
25
|
});
|
|
24
26
|
const scaffolderTemplatesSubPage = SubPageBlueprint.makeWithOverrides({
|
|
25
27
|
name: "templates",
|
|
26
|
-
|
|
28
|
+
configSchema: {
|
|
29
|
+
enableBackstageUi: z.boolean().optional().default(false),
|
|
30
|
+
groups: z.array(
|
|
31
|
+
z.object({
|
|
32
|
+
title: z.string(),
|
|
33
|
+
filter: createZodV4FilterPredicateSchema()
|
|
34
|
+
})
|
|
35
|
+
).optional()
|
|
36
|
+
},
|
|
37
|
+
factory(originalFactory, { apis, config }) {
|
|
27
38
|
const formFieldsApi = apis.get(formFieldsApiRef);
|
|
39
|
+
const groups = config.groups?.map(
|
|
40
|
+
(group) => ({
|
|
41
|
+
title: group.title,
|
|
42
|
+
filter: filterPredicateToFilterFunction(group.filter)
|
|
43
|
+
})
|
|
44
|
+
);
|
|
28
45
|
return originalFactory({
|
|
29
46
|
path: "templates",
|
|
30
47
|
title: "Templates",
|
|
31
48
|
loader: async () => {
|
|
32
49
|
const formFields = await formFieldsApi?.loadFormFields() ?? [];
|
|
33
|
-
return import('./components/TemplatesSubPage.esm.js').then((m) => /* @__PURE__ */ jsx(
|
|
50
|
+
return import('./components/TemplatesSubPage.esm.js').then((m) => /* @__PURE__ */ jsx(
|
|
51
|
+
m.TemplatesSubPage,
|
|
52
|
+
{
|
|
53
|
+
formFields,
|
|
54
|
+
groups,
|
|
55
|
+
formProps: {
|
|
56
|
+
EXPERIMENTAL_theme: config.enableBackstageUi ? "bui" : "mui"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
));
|
|
34
60
|
}
|
|
35
61
|
});
|
|
36
62
|
}
|