@backstage/plugin-scaffolder 1.25.0-next.2 → 1.26.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/alpha/package.json +1 -1
- package/dist/alpha/api/FormFieldsApi.esm.js +40 -0
- package/dist/alpha/api/FormFieldsApi.esm.js.map +1 -0
- package/dist/alpha/api/ref.esm.js +8 -0
- package/dist/alpha/api/ref.esm.js.map +1 -0
- package/dist/alpha/api.esm.js +27 -0
- package/dist/alpha/api.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/CustomFieldExplorer.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js +167 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js +33 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DirectoryEditorContext.esm.js +4 -7
- package/dist/alpha/components/TemplateEditorPage/DirectoryEditorContext.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunContext.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResults.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js +2 -2
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js +2 -2
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js +94 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorBrowser.esm.js +36 -38
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorForm.esm.js +12 -20
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorForm.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorIntro.esm.js +39 -2
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorIntro.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js +61 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorTextArea.esm.js +36 -3
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js +98 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js +43 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateFormPreviewer.esm.js +77 -39
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js +52 -0
- package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js.map +1 -0
- package/dist/alpha/components/TemplateListPage/RegisterExistingButton.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateListPage/TemplateListPage.esm.js +2 -2
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPage.esm.js +2 -2
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js +1 -1
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +1 -0
- package/dist/alpha/extensions.esm.js +30 -0
- package/dist/alpha/extensions.esm.js.map +1 -0
- package/dist/alpha/fields/RepoUrlPicker.esm.js +37 -0
- package/dist/alpha/fields/RepoUrlPicker.esm.js.map +1 -0
- package/dist/alpha/plugin.esm.js +32 -0
- package/dist/alpha/plugin.esm.js.map +1 -0
- package/dist/alpha.d.ts +78 -7
- package/dist/alpha.esm.js +1 -60
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api.esm.js +14 -2
- package/dist/api.esm.js.map +1 -1
- package/dist/components/ActionsPage/ActionsPage.esm.js +30 -5
- package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -1
- package/dist/components/FileBrowser/FileBrowser.esm.js +4 -3
- package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -1
- package/dist/components/ListTasksPage/OwnerListPicker.esm.js +2 -2
- package/dist/components/ListTasksPage/OwnerListPicker.esm.js.map +1 -1
- package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js +10 -5
- package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js.map +1 -1
- package/dist/components/OngoingTask/ContextMenu.esm.js +15 -2
- package/dist/components/OngoingTask/ContextMenu.esm.js.map +1 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js +24 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -1
- package/dist/components/Router/Router.esm.js +35 -7
- package/dist/components/Router/Router.esm.js.map +1 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +5 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/schema.esm.js +5 -6
- package/dist/components/fields/RepoUrlPicker/schema.esm.js.map +1 -1
- package/dist/components/fields/utils.esm.js +2 -1
- package/dist/components/fields/utils.esm.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/lib/filesystem/WebFileSystemAccess.esm.js +34 -1
- package/dist/lib/filesystem/WebFileSystemAccess.esm.js.map +1 -1
- package/dist/lib/filesystem/createExampleTemplate.esm.js +76 -0
- package/dist/lib/filesystem/createExampleTemplate.esm.js.map +1 -0
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js +103 -0
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js.map +1 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js +6 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -0
- package/dist/plugin.esm.js +5 -2
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +16 -1
- package/dist/routes.esm.js.map +1 -1
- package/dist/translation.esm.js +20 -1
- package/dist/translation.esm.js.map +1 -1
- package/package.json +25 -23
- package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunContext.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditor.esm.js +0 -56
- package/dist/next/TemplateEditorPage/TemplateEditor.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js +0 -87
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +0 -1
- package/dist/next/TemplateListPage/RegisterExistingButton.esm.js.map +0 -1
- package/dist/next/TemplateListPage/TemplateListPage.esm.js.map +0 -1
- package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js.map +0 -1
- package/dist/next/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +0 -1
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunContext.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/IconLink.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateListPage/RegisterExistingButton.esm.js +0 -0
|
@@ -2,14 +2,17 @@ import React from 'react';
|
|
|
2
2
|
import { useOutlet, Routes, Route } from 'react-router-dom';
|
|
3
3
|
import { useCustomFieldExtensions, useCustomLayouts, SecretsContextProvider } from '@backstage/plugin-scaffolder-react';
|
|
4
4
|
import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default.esm.js';
|
|
5
|
-
import { selectedTemplateRouteRef, scaffolderTaskRouteRef, editRouteRef, actionsRouteRef, scaffolderListTaskRouteRef } from '../../routes.esm.js';
|
|
5
|
+
import { selectedTemplateRouteRef, scaffolderTaskRouteRef, editRouteRef, customFieldsRouteRef, templateFormRouteRef, actionsRouteRef, scaffolderListTaskRouteRef, editorRouteRef } from '../../routes.esm.js';
|
|
6
6
|
import { ErrorPage } from '@backstage/core-components';
|
|
7
7
|
import { ActionsPage } from '../ActionsPage/ActionsPage.esm.js';
|
|
8
8
|
import { ListTasksPage } from '../ListTasksPage/ListTasksPage.esm.js';
|
|
9
|
-
import { TemplateListPage } from '../../
|
|
10
|
-
import { TemplateWizardPage } from '../../
|
|
9
|
+
import { TemplateListPage } from '../../alpha/components/TemplateListPage/TemplateListPage.esm.js';
|
|
10
|
+
import { TemplateWizardPage } from '../../alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js';
|
|
11
11
|
import { OngoingTask } from '../OngoingTask/OngoingTask.esm.js';
|
|
12
|
-
import {
|
|
12
|
+
import { TemplatePage } from '../../alpha/components/TemplateEditorPage/TemplatePage.esm.js';
|
|
13
|
+
import { TemplateFormPage } from '../../alpha/components/TemplateEditorPage/TemplateFormPage.esm.js';
|
|
14
|
+
import { TemplateEditorPage } from '../../alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js';
|
|
15
|
+
import { CustomFieldsPage } from '../../alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js';
|
|
13
16
|
|
|
14
17
|
const Router = (props) => {
|
|
15
18
|
const {
|
|
@@ -78,12 +81,24 @@ const Router = (props) => {
|
|
|
78
81
|
Route,
|
|
79
82
|
{
|
|
80
83
|
path: editRouteRef.path,
|
|
84
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplateEditorPage, null))
|
|
85
|
+
}
|
|
86
|
+
), /* @__PURE__ */ React.createElement(
|
|
87
|
+
Route,
|
|
88
|
+
{
|
|
89
|
+
path: customFieldsRouteRef.path,
|
|
90
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(CustomFieldsPage, { fieldExtensions }))
|
|
91
|
+
}
|
|
92
|
+
), /* @__PURE__ */ React.createElement(
|
|
93
|
+
Route,
|
|
94
|
+
{
|
|
95
|
+
path: templateFormRouteRef.path,
|
|
81
96
|
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(
|
|
82
|
-
|
|
97
|
+
TemplateFormPage,
|
|
83
98
|
{
|
|
84
|
-
customFieldExtensions: fieldExtensions,
|
|
85
99
|
layouts: customLayouts,
|
|
86
|
-
formProps: props.formProps
|
|
100
|
+
formProps: props.formProps,
|
|
101
|
+
fieldExtensions
|
|
87
102
|
}
|
|
88
103
|
))
|
|
89
104
|
}
|
|
@@ -93,6 +108,19 @@ const Router = (props) => {
|
|
|
93
108
|
path: scaffolderListTaskRouteRef.path,
|
|
94
109
|
element: /* @__PURE__ */ React.createElement(ListTasksPage, null)
|
|
95
110
|
}
|
|
111
|
+
), /* @__PURE__ */ React.createElement(
|
|
112
|
+
Route,
|
|
113
|
+
{
|
|
114
|
+
path: editorRouteRef.path,
|
|
115
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(
|
|
116
|
+
TemplatePage,
|
|
117
|
+
{
|
|
118
|
+
layouts: customLayouts,
|
|
119
|
+
formProps: props.formProps,
|
|
120
|
+
fieldExtensions
|
|
121
|
+
}
|
|
122
|
+
))
|
|
123
|
+
}
|
|
96
124
|
), /* @__PURE__ */ React.createElement(
|
|
97
125
|
Route,
|
|
98
126
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.esm.js","sources":["../../../src/components/Router/Router.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 React, { PropsWithChildren } from 'react';\nimport { Routes, Route, useOutlet } from 'react-router-dom';\n\nimport {\n FieldExtensionOptions,\n FormProps,\n ReviewStepProps,\n TemplateGroupFilter,\n} from '@backstage/plugin-scaffolder-react';\nimport {\n ScaffolderTaskOutput,\n SecretsContextProvider,\n useCustomFieldExtensions,\n useCustomLayouts,\n} from '@backstage/plugin-scaffolder-react';\n\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default';\n\nimport {\n actionsRouteRef,\n editRouteRef,\n scaffolderListTaskRouteRef,\n scaffolderTaskRouteRef,\n selectedTemplateRouteRef,\n} from '../../routes';\nimport { ErrorPage } from '@backstage/core-components';\n\nimport { ActionsPage } from '../../components/ActionsPage';\nimport { ListTasksPage } from '../../components/ListTasksPage';\n\nimport {\n TemplateListPageProps,\n TemplateWizardPageProps,\n} from '@backstage/plugin-scaffolder/alpha';\nimport { TemplateListPage, TemplateWizardPage } from '../../
|
|
1
|
+
{"version":3,"file":"Router.esm.js","sources":["../../../src/components/Router/Router.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 React, { PropsWithChildren } from 'react';\nimport { Routes, Route, useOutlet } from 'react-router-dom';\n\nimport {\n FieldExtensionOptions,\n FormProps,\n ReviewStepProps,\n TemplateGroupFilter,\n} from '@backstage/plugin-scaffolder-react';\nimport {\n ScaffolderTaskOutput,\n SecretsContextProvider,\n useCustomFieldExtensions,\n useCustomLayouts,\n} from '@backstage/plugin-scaffolder-react';\n\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default';\n\nimport {\n actionsRouteRef,\n editorRouteRef,\n customFieldsRouteRef,\n editRouteRef,\n scaffolderListTaskRouteRef,\n scaffolderTaskRouteRef,\n selectedTemplateRouteRef,\n templateFormRouteRef,\n} from '../../routes';\nimport { ErrorPage } from '@backstage/core-components';\n\nimport { ActionsPage } from '../../components/ActionsPage';\nimport { ListTasksPage } from '../../components/ListTasksPage';\n\nimport {\n TemplateListPageProps,\n TemplateWizardPageProps,\n} from '@backstage/plugin-scaffolder/alpha';\nimport { TemplateListPage, TemplateWizardPage } from '../../alpha/components';\nimport { OngoingTask } from '../OngoingTask';\nimport {\n TemplatePage,\n TemplateFormPage,\n TemplateEditorPage,\n CustomFieldsPage,\n} from '../../alpha/components/TemplateEditorPage';\n\n/**\n * The Props for the Scaffolder Router\n *\n * @public\n */\nexport type RouterProps = {\n components?: {\n ReviewStepComponent?: React.ComponentType<ReviewStepProps>;\n TemplateCardComponent?: React.ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n TaskPageComponent?: React.ComponentType<PropsWithChildren<{}>>;\n EXPERIMENTAL_TemplateOutputsComponent?: React.ComponentType<{\n output?: ScaffolderTaskOutput;\n }>;\n EXPERIMENTAL_TemplateListPageComponent?: React.ComponentType<TemplateListPageProps>;\n EXPERIMENTAL_TemplateWizardPageComponent?: React.ComponentType<TemplateWizardPageProps>;\n };\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n defaultPreviewTemplate?: string;\n formProps?: FormProps;\n contextMenu?: {\n /** Whether to show a link to the template editor */\n editor?: boolean;\n /** Whether to show a link to the actions documentation */\n actions?: boolean;\n /** Whether to show a link to the tasks page */\n tasks?: boolean;\n };\n};\n\n/**\n * The Scaffolder Router\n *\n * @public\n */\nexport const Router = (props: PropsWithChildren<RouterProps>) => {\n const {\n components: {\n TemplateCardComponent,\n TaskPageComponent = OngoingTask,\n ReviewStepComponent,\n EXPERIMENTAL_TemplateOutputsComponent: TemplateOutputsComponent,\n EXPERIMENTAL_TemplateListPageComponent:\n TemplateListPageComponent = TemplateListPage,\n EXPERIMENTAL_TemplateWizardPageComponent:\n TemplateWizardPageComponent = TemplateWizardPage,\n } = {},\n } = props;\n const outlet = useOutlet() || props.children;\n const customFieldExtensions =\n useCustomFieldExtensions<FieldExtensionOptions>(outlet);\n\n const fieldExtensions = [\n ...customFieldExtensions,\n ...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(\n ({ name }) =>\n !customFieldExtensions.some(\n customFieldExtension => customFieldExtension.name === name,\n ),\n ),\n ] as FieldExtensionOptions[];\n\n const customLayouts = useCustomLayouts(outlet);\n\n return (\n <Routes>\n <Route\n path=\"/\"\n element={\n <TemplateListPageComponent\n TemplateCardComponent={TemplateCardComponent}\n contextMenu={props.contextMenu}\n groups={props.groups}\n templateFilter={props.templateFilter}\n headerOptions={props.headerOptions}\n />\n }\n />\n <Route\n path={selectedTemplateRouteRef.path}\n element={\n <SecretsContextProvider>\n <TemplateWizardPageComponent\n headerOptions={props.headerOptions}\n customFieldExtensions={fieldExtensions}\n layouts={customLayouts}\n components={{ ReviewStepComponent }}\n formProps={props.formProps}\n />\n </SecretsContextProvider>\n }\n />\n <Route\n path={scaffolderTaskRouteRef.path}\n element={\n <TaskPageComponent\n TemplateOutputsComponent={TemplateOutputsComponent}\n />\n }\n />\n <Route\n path={editRouteRef.path}\n element={\n <SecretsContextProvider>\n <TemplateEditorPage />\n </SecretsContextProvider>\n }\n />\n <Route\n path={customFieldsRouteRef.path}\n element={\n <SecretsContextProvider>\n <CustomFieldsPage fieldExtensions={fieldExtensions} />\n </SecretsContextProvider>\n }\n />\n <Route\n path={templateFormRouteRef.path}\n element={\n <SecretsContextProvider>\n <TemplateFormPage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n }\n />\n\n <Route path={actionsRouteRef.path} element={<ActionsPage />} />\n <Route\n path={scaffolderListTaskRouteRef.path}\n element={<ListTasksPage />}\n />\n <Route\n path={editorRouteRef.path}\n element={\n <SecretsContextProvider>\n <TemplatePage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n }\n />\n <Route\n path=\"*\"\n element={<ErrorPage status=\"404\" statusMessage=\"Page not found\" />}\n />\n </Routes>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { catalogApiRef, entityPresentationApiRef, EntityDisplayName } from '@bac
|
|
|
5
5
|
import TextField from '@material-ui/core/TextField';
|
|
6
6
|
import FormControl from '@material-ui/core/FormControl';
|
|
7
7
|
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
8
|
-
import React, { useCallback, useEffect } from 'react';
|
|
8
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
9
9
|
import useAsync from 'react-use/esm/useAsync';
|
|
10
10
|
import { VirtualizedListbox } from '../VirtualizedListbox.esm.js';
|
|
11
11
|
export { MultiEntityPickerSchema } from './schema.esm.js';
|
|
@@ -23,6 +23,7 @@ const MultiEntityPicker = (props) => {
|
|
|
23
23
|
const catalogFilter = buildCatalogFilter(uiSchema);
|
|
24
24
|
const defaultKind = uiSchema["ui:options"]?.defaultKind;
|
|
25
25
|
const defaultNamespace = uiSchema["ui:options"]?.defaultNamespace || void 0;
|
|
26
|
+
const [noOfItemsSelected, setNoOfItemsSelected] = useState(0);
|
|
26
27
|
const catalogApi = useApi(catalogApiRef);
|
|
27
28
|
const entityPresentationApi = useApi(entityPresentationApiRef);
|
|
28
29
|
const { value: entities, loading } = useAsync(async () => {
|
|
@@ -40,6 +41,7 @@ const MultiEntityPicker = (props) => {
|
|
|
40
41
|
return { entities: items, entityRefToPresentation };
|
|
41
42
|
});
|
|
42
43
|
const allowArbitraryValues = uiSchema["ui:options"]?.allowArbitraryValues ?? true;
|
|
44
|
+
const maxItems = props.schema.maxItems;
|
|
43
45
|
const onSelect = useCallback(
|
|
44
46
|
(_, refs, reason) => {
|
|
45
47
|
const values = refs.map((ref) => {
|
|
@@ -63,6 +65,7 @@ const MultiEntityPicker = (props) => {
|
|
|
63
65
|
}
|
|
64
66
|
return void 0;
|
|
65
67
|
}).filter((ref) => ref !== void 0);
|
|
68
|
+
setNoOfItemsSelected(values.length);
|
|
66
69
|
onChange(values);
|
|
67
70
|
},
|
|
68
71
|
[onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues]
|
|
@@ -94,6 +97,7 @@ const MultiEntityPicker = (props) => {
|
|
|
94
97
|
// option can be a string due to freeSolo.
|
|
95
98
|
typeof option === "string" ? option : entities?.entityRefToPresentation.get(stringifyEntityRef(option))?.entityRef
|
|
96
99
|
),
|
|
100
|
+
getOptionDisabled: (_options) => maxItems ? noOfItemsSelected >= maxItems : false,
|
|
97
101
|
autoSelect: true,
|
|
98
102
|
freeSolo: allowArbitraryValues,
|
|
99
103
|
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiEntityPicker.esm.js","sources":["../../../../src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 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 {\n type EntityFilterQuery,\n CATALOG_FILTER_EXISTS,\n} from '@backstage/catalog-client';\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n entityPresentationApiRef,\n EntityDisplayName,\n EntityRefPresentationSnapshot,\n} from '@backstage/plugin-catalog-react';\nimport TextField from '@material-ui/core/TextField';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete, {\n AutocompleteChangeReason,\n} from '@material-ui/lab/Autocomplete';\nimport React, { useCallback, useEffect } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { FieldValidation } from '@rjsf/utils';\nimport {\n MultiEntityPickerFilterQueryValue,\n MultiEntityPickerProps,\n MultiEntityPickerUiOptions,\n MultiEntityPickerFilterQuery,\n} from './schema';\nimport { VirtualizedListbox } from '../VirtualizedListbox';\n\nexport { MultiEntityPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `MultiEntityPicker`\n * field extension.\n */\nexport const MultiEntityPicker = (props: MultiEntityPickerProps) => {\n const {\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n } = props;\n const catalogFilter = buildCatalogFilter(uiSchema);\n const defaultKind = uiSchema['ui:options']?.defaultKind;\n const defaultNamespace =\n uiSchema['ui:options']?.defaultNamespace || undefined;\n\n const catalogApi = useApi(catalogApiRef);\n const entityPresentationApi = useApi(entityPresentationApiRef);\n const { value: entities, loading } = useAsync(async () => {\n const { items } = await catalogApi.getEntities(\n catalogFilter ? { filter: catalogFilter } : undefined,\n );\n const entityRefToPresentation = new Map<\n string,\n EntityRefPresentationSnapshot\n >(\n await Promise.all(\n items.map(async item => {\n const presentation = await entityPresentationApi.forEntity(item)\n .promise;\n return [stringifyEntityRef(item), presentation] as [\n string,\n EntityRefPresentationSnapshot,\n ];\n }),\n ),\n );\n return { entities: items, entityRefToPresentation };\n });\n const allowArbitraryValues =\n uiSchema['ui:options']?.allowArbitraryValues ?? true;\n\n const onSelect = useCallback(\n (_: any, refs: (string | Entity)[], reason: AutocompleteChangeReason) => {\n const values = refs\n .map(ref => {\n if (typeof ref !== 'string') {\n // if ref does not exist: pass 'undefined' to trigger validation for required value\n return ref ? stringifyEntityRef(ref as Entity) : undefined;\n }\n if (reason === 'blur' || reason === 'create-option') {\n // Add in default namespace, etc.\n let entityRef = ref;\n try {\n // Attempt to parse the entity ref into it's full form.\n entityRef = stringifyEntityRef(\n parseEntityRef(ref as string, {\n defaultKind,\n defaultNamespace,\n }),\n );\n } catch (err) {\n // If the passed in value isn't an entity ref, do nothing.\n }\n\n // We need to check against formData here as that's the previous value for this field.\n if (formData?.includes(ref) || allowArbitraryValues) {\n return entityRef;\n }\n }\n\n return undefined;\n })\n .filter(ref => ref !== undefined) as string[];\n\n onChange(values);\n },\n [onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues],\n );\n\n useEffect(() => {\n if (entities?.entities?.length === 1) {\n onChange([stringifyEntityRef(entities?.entities[0])]);\n }\n }, [entities, onChange]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n multiple\n filterSelectedOptions\n disabled={entities?.entities?.length === 1}\n id={idSchema?.$id}\n loading={loading}\n onChange={onSelect}\n options={entities?.entities || []}\n renderOption={option => <EntityDisplayName entityRef={option} />}\n getOptionLabel={option =>\n // option can be a string due to freeSolo.\n typeof option === 'string'\n ? option\n : entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.entityRef!\n }\n autoSelect\n freeSolo={allowArbitraryValues}\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"dense\"\n helperText={description}\n FormHelperTextProps={{\n margin: 'dense',\n style: { marginLeft: 0 },\n }}\n variant=\"outlined\"\n required={required}\n InputProps={{\n ...params.InputProps,\n required: formData?.length === 0 && required,\n }}\n />\n )}\n ListboxComponent={VirtualizedListbox}\n />\n </FormControl>\n );\n};\n\nexport const validateMultiEntityPickerValidation = (\n values: string[],\n validation: FieldValidation,\n) => {\n values.forEach(value => {\n try {\n parseEntityRef(value);\n } catch {\n validation.addError(`${value} is not a valid entity ref`);\n }\n });\n};\n\n/**\n * Converts a special `{exists: true}` value to the `CATALOG_FILTER_EXISTS` symbol.\n *\n * @param value - The value to convert.\n * @returns The converted value.\n */\nfunction convertOpsValues(\n value: Exclude<MultiEntityPickerFilterQueryValue, Array<any>>,\n): string | symbol {\n if (typeof value === 'object' && value.exists) {\n return CATALOG_FILTER_EXISTS;\n }\n return value?.toString();\n}\n\n/**\n * Converts schema filters to entity filter query, replacing `{exists:true}` values\n * with the constant `CATALOG_FILTER_EXISTS`.\n *\n * @param schemaFilters - An object containing schema filters with keys as filter names\n * and values as filter values.\n * @returns An object with the same keys as the input object, but with `{exists:true}` values\n * transformed to `CATALOG_FILTER_EXISTS` symbol.\n */\nfunction convertSchemaFiltersToQuery(\n schemaFilters: MultiEntityPickerFilterQuery,\n): Exclude<EntityFilterQuery, Array<any>> {\n const query: EntityFilterQuery = {};\n\n for (const [key, value] of Object.entries(schemaFilters)) {\n if (Array.isArray(value)) {\n query[key] = value;\n } else {\n query[key] = convertOpsValues(value);\n }\n }\n\n return query;\n}\n\n/**\n * Builds an `EntityFilterQuery` based on the `uiSchema` passed in.\n * If `catalogFilter` is specified in the `uiSchema`, it is converted to a `EntityFilterQuery`.\n *\n * @param uiSchema The `uiSchema` of an `EntityPicker` component.\n * @returns An `EntityFilterQuery` based on the `uiSchema`, or `undefined` if `catalogFilter` is not specified in the `uiSchema`.\n */\nfunction buildCatalogFilter(\n uiSchema: MultiEntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const catalogFilter: MultiEntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter;\n\n if (!catalogFilter) {\n return undefined;\n }\n\n if (Array.isArray(catalogFilter)) {\n return catalogFilter.map(convertSchemaFiltersToQuery);\n }\n\n return convertSchemaFiltersToQuery(catalogFilter);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MultiEntityPicker.esm.js","sources":["../../../../src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 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 {\n type EntityFilterQuery,\n CATALOG_FILTER_EXISTS,\n} from '@backstage/catalog-client';\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n entityPresentationApiRef,\n EntityDisplayName,\n EntityRefPresentationSnapshot,\n} from '@backstage/plugin-catalog-react';\nimport TextField from '@material-ui/core/TextField';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete, {\n AutocompleteChangeReason,\n} from '@material-ui/lab/Autocomplete';\nimport React, { useCallback, useEffect, useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { FieldValidation } from '@rjsf/utils';\nimport {\n MultiEntityPickerFilterQueryValue,\n MultiEntityPickerProps,\n MultiEntityPickerUiOptions,\n MultiEntityPickerFilterQuery,\n} from './schema';\nimport { VirtualizedListbox } from '../VirtualizedListbox';\n\nexport { MultiEntityPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `MultiEntityPicker`\n * field extension.\n */\nexport const MultiEntityPicker = (props: MultiEntityPickerProps) => {\n const {\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n } = props;\n const catalogFilter = buildCatalogFilter(uiSchema);\n const defaultKind = uiSchema['ui:options']?.defaultKind;\n const defaultNamespace =\n uiSchema['ui:options']?.defaultNamespace || undefined;\n const [noOfItemsSelected, setNoOfItemsSelected] = useState(0);\n\n const catalogApi = useApi(catalogApiRef);\n const entityPresentationApi = useApi(entityPresentationApiRef);\n const { value: entities, loading } = useAsync(async () => {\n const { items } = await catalogApi.getEntities(\n catalogFilter ? { filter: catalogFilter } : undefined,\n );\n const entityRefToPresentation = new Map<\n string,\n EntityRefPresentationSnapshot\n >(\n await Promise.all(\n items.map(async item => {\n const presentation = await entityPresentationApi.forEntity(item)\n .promise;\n return [stringifyEntityRef(item), presentation] as [\n string,\n EntityRefPresentationSnapshot,\n ];\n }),\n ),\n );\n return { entities: items, entityRefToPresentation };\n });\n const allowArbitraryValues =\n uiSchema['ui:options']?.allowArbitraryValues ?? true;\n\n // if not specified, maxItems defaults to undefined\n const maxItems = props.schema.maxItems;\n\n const onSelect = useCallback(\n (_: any, refs: (string | Entity)[], reason: AutocompleteChangeReason) => {\n const values = refs\n .map(ref => {\n if (typeof ref !== 'string') {\n // if ref does not exist: pass 'undefined' to trigger validation for required value\n return ref ? stringifyEntityRef(ref as Entity) : undefined;\n }\n if (reason === 'blur' || reason === 'create-option') {\n // Add in default namespace, etc.\n let entityRef = ref;\n try {\n // Attempt to parse the entity ref into it's full form.\n entityRef = stringifyEntityRef(\n parseEntityRef(ref as string, {\n defaultKind,\n defaultNamespace,\n }),\n );\n } catch (err) {\n // If the passed in value isn't an entity ref, do nothing.\n }\n\n // We need to check against formData here as that's the previous value for this field.\n if (formData?.includes(ref) || allowArbitraryValues) {\n return entityRef;\n }\n }\n\n return undefined;\n })\n .filter(ref => ref !== undefined) as string[];\n\n setNoOfItemsSelected(values.length);\n onChange(values);\n },\n [onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues],\n );\n\n useEffect(() => {\n if (entities?.entities?.length === 1) {\n onChange([stringifyEntityRef(entities?.entities[0])]);\n }\n }, [entities, onChange]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n multiple\n filterSelectedOptions\n disabled={entities?.entities?.length === 1}\n id={idSchema?.$id}\n loading={loading}\n onChange={onSelect}\n options={entities?.entities || []}\n renderOption={option => <EntityDisplayName entityRef={option} />}\n getOptionLabel={option =>\n // option can be a string due to freeSolo.\n typeof option === 'string'\n ? option\n : entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.entityRef!\n }\n getOptionDisabled={_options =>\n maxItems ? noOfItemsSelected >= maxItems : false\n }\n autoSelect\n freeSolo={allowArbitraryValues}\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"dense\"\n helperText={description}\n FormHelperTextProps={{\n margin: 'dense',\n style: { marginLeft: 0 },\n }}\n variant=\"outlined\"\n required={required}\n InputProps={{\n ...params.InputProps,\n required: formData?.length === 0 && required,\n }}\n />\n )}\n ListboxComponent={VirtualizedListbox}\n />\n </FormControl>\n );\n};\n\nexport const validateMultiEntityPickerValidation = (\n values: string[],\n validation: FieldValidation,\n) => {\n values.forEach(value => {\n try {\n parseEntityRef(value);\n } catch {\n validation.addError(`${value} is not a valid entity ref`);\n }\n });\n};\n\n/**\n * Converts a special `{exists: true}` value to the `CATALOG_FILTER_EXISTS` symbol.\n *\n * @param value - The value to convert.\n * @returns The converted value.\n */\nfunction convertOpsValues(\n value: Exclude<MultiEntityPickerFilterQueryValue, Array<any>>,\n): string | symbol {\n if (typeof value === 'object' && value.exists) {\n return CATALOG_FILTER_EXISTS;\n }\n return value?.toString();\n}\n\n/**\n * Converts schema filters to entity filter query, replacing `{exists:true}` values\n * with the constant `CATALOG_FILTER_EXISTS`.\n *\n * @param schemaFilters - An object containing schema filters with keys as filter names\n * and values as filter values.\n * @returns An object with the same keys as the input object, but with `{exists:true}` values\n * transformed to `CATALOG_FILTER_EXISTS` symbol.\n */\nfunction convertSchemaFiltersToQuery(\n schemaFilters: MultiEntityPickerFilterQuery,\n): Exclude<EntityFilterQuery, Array<any>> {\n const query: EntityFilterQuery = {};\n\n for (const [key, value] of Object.entries(schemaFilters)) {\n if (Array.isArray(value)) {\n query[key] = value;\n } else {\n query[key] = convertOpsValues(value);\n }\n }\n\n return query;\n}\n\n/**\n * Builds an `EntityFilterQuery` based on the `uiSchema` passed in.\n * If `catalogFilter` is specified in the `uiSchema`, it is converted to a `EntityFilterQuery`.\n *\n * @param uiSchema The `uiSchema` of an `EntityPicker` component.\n * @returns An `EntityFilterQuery` based on the `uiSchema`, or `undefined` if `catalogFilter` is not specified in the `uiSchema`.\n */\nfunction buildCatalogFilter(\n uiSchema: MultiEntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const catalogFilter: MultiEntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter;\n\n if (!catalogFilter) {\n return undefined;\n }\n\n if (Array.isArray(catalogFilter)) {\n return catalogFilter.map(convertSchemaFiltersToQuery);\n }\n\n return convertSchemaFiltersToQuery(catalogFilter);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepoUrlPicker.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 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 { useApi } from '@backstage/core-plugin-api';\nimport {\n scmIntegrationsApiRef,\n scmAuthApiRef,\n} from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GiteaRepoPicker } from './GiteaRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { GerritRepoPicker } from './GerritRepoPicker';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerProps } from './schema';\nimport { RepoUrlPickerState } from './types';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport Typography from '@material-ui/core/Typography';\n\nexport { RepoUrlPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `RepoUrlPicker`\n * field extension.\n *\n * @public\n */\nexport const RepoUrlPicker = (props: RepoUrlPickerProps) => {\n const { uiSchema, onChange, rawErrors, formData, schema } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const [credentialsHost, setCredentialsHost] = useState<string | undefined>(\n undefined,\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n const scmAuthApi = useApi(scmAuthApiRef);\n const { secrets, setSecrets } = useTemplateSecrets();\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOrganizations = useMemo(\n () => uiSchema?.['ui:options']?.allowedOrganizations ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n const allowedProjects = useMemo(\n () => uiSchema?.['ui:options']?.allowedProjects ?? [],\n [uiSchema],\n );\n const allowedRepos = useMemo(\n () => uiSchema?.['ui:options']?.allowedRepos ?? [],\n [uiSchema],\n );\n\n const { owner, organization, project, repoName } = state;\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOrganizations.length > 0 && !organization) {\n setState(prevState => ({\n ...prevState,\n organization: allowedOrganizations[0],\n }));\n }\n }, [setState, allowedOrganizations, organization]);\n\n useEffect(() => {\n if (allowedOwners.length > 0 && !owner) {\n setState(prevState => ({\n ...prevState,\n owner: allowedOwners[0],\n }));\n }\n }, [setState, allowedOwners, owner]);\n\n useEffect(() => {\n if (allowedProjects.length > 0 && !project) {\n setState(prevState => ({\n ...prevState,\n project: allowedProjects[0],\n }));\n }\n }, [setState, allowedProjects, project]);\n\n useEffect(() => {\n if (allowedRepos.length > 0 && !repoName) {\n setState(prevState => ({ ...prevState, repoName: allowedRepos[0] }));\n }\n }, [setState, allowedRepos, repoName]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n useDebounce(\n async () => {\n const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {};\n\n if (!requestUserCredentials || !state.host) {\n return;\n }\n\n // don't show login prompt if secret value is already in state for selected host\n if (\n secrets[requestUserCredentials.secretsKey] &&\n credentialsHost === state.host\n ) {\n return;\n }\n\n // user has requested that we use the users credentials\n // so lets grab them using the scmAuthApi and pass through\n // any additional scopes from the ui:options\n const { token } = await scmAuthApi.getCredentials({\n url: `https://${state.host}`,\n additionalScope: {\n repoWrite: true,\n customScopes: requestUserCredentials.additionalScopes,\n },\n });\n\n // set the secret using the key provided in the ui:options for use\n // in the templating the manifest with ${{ secrets[secretsKey] }}\n setSecrets({ [requestUserCredentials.secretsKey]: token });\n setCredentialsHost(state.host);\n },\n 500,\n [state, uiSchema],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n return (\n <>\n {schema.title && (\n <Box my={1}>\n <Typography variant=\"h5\">{schema.title}</Typography>\n <Divider />\n </Box>\n )}\n {schema.description && (\n <Typography variant=\"body1\">{schema.description}</Typography>\n )}\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n onChange={updateLocalState}\n rawErrors={rawErrors}\n state={state}\n />\n )}\n {hostType === 'gitea' && (\n <GiteaRepoPicker\n allowedOwners={allowedOwners}\n allowedRepos={allowedRepos}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n allowedOwners={allowedOwners}\n allowedProjects={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n accessToken={\n uiSchema?.['ui:options']?.requestUserCredentials?.secretsKey &&\n secrets[uiSchema['ui:options'].requestUserCredentials.secretsKey]\n }\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n allowedOrganizations={allowedOrganizations}\n allowedProject={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gerrit' && (\n <GerritRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n <RepoUrlPickerRepoName\n repoName={state.repoName}\n allowedRepos={allowedRepos}\n onChange={repo =>\n setState(prevState => ({ ...prevState, repoName: repo }))\n }\n rawErrors={rawErrors}\n availableRepos={state.availableRepos}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RepoUrlPicker.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 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 { useApi } from '@backstage/core-plugin-api';\nimport {\n scmIntegrationsApiRef,\n scmAuthApiRef,\n} from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GiteaRepoPicker } from './GiteaRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { GerritRepoPicker } from './GerritRepoPicker';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerFieldSchema } from './schema';\nimport { RepoUrlPickerState } from './types';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport Typography from '@material-ui/core/Typography';\n\nexport { RepoUrlPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `RepoUrlPicker`\n * field extension.\n *\n * @public\n */\nexport const RepoUrlPicker = (\n props: typeof RepoUrlPickerFieldSchema.TProps,\n) => {\n const { uiSchema, onChange, rawErrors, formData, schema } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const [credentialsHost, setCredentialsHost] = useState<string | undefined>(\n undefined,\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n const scmAuthApi = useApi(scmAuthApiRef);\n const { secrets, setSecrets } = useTemplateSecrets();\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOrganizations = useMemo(\n () => uiSchema?.['ui:options']?.allowedOrganizations ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n const allowedProjects = useMemo(\n () => uiSchema?.['ui:options']?.allowedProjects ?? [],\n [uiSchema],\n );\n const allowedRepos = useMemo(\n () => uiSchema?.['ui:options']?.allowedRepos ?? [],\n [uiSchema],\n );\n\n const { owner, organization, project, repoName } = state;\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOrganizations.length > 0 && !organization) {\n setState(prevState => ({\n ...prevState,\n organization: allowedOrganizations[0],\n }));\n }\n }, [setState, allowedOrganizations, organization]);\n\n useEffect(() => {\n if (allowedOwners.length > 0 && !owner) {\n setState(prevState => ({\n ...prevState,\n owner: allowedOwners[0],\n }));\n }\n }, [setState, allowedOwners, owner]);\n\n useEffect(() => {\n if (allowedProjects.length > 0 && !project) {\n setState(prevState => ({\n ...prevState,\n project: allowedProjects[0],\n }));\n }\n }, [setState, allowedProjects, project]);\n\n useEffect(() => {\n if (allowedRepos.length > 0 && !repoName) {\n setState(prevState => ({ ...prevState, repoName: allowedRepos[0] }));\n }\n }, [setState, allowedRepos, repoName]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n useDebounce(\n async () => {\n const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {};\n\n if (!requestUserCredentials || !state.host) {\n return;\n }\n\n // don't show login prompt if secret value is already in state for selected host\n if (\n secrets[requestUserCredentials.secretsKey] &&\n credentialsHost === state.host\n ) {\n return;\n }\n\n // user has requested that we use the users credentials\n // so lets grab them using the scmAuthApi and pass through\n // any additional scopes from the ui:options\n const { token } = await scmAuthApi.getCredentials({\n url: `https://${state.host}`,\n additionalScope: {\n repoWrite: true,\n customScopes: requestUserCredentials.additionalScopes,\n },\n });\n\n // set the secret using the key provided in the ui:options for use\n // in the templating the manifest with ${{ secrets[secretsKey] }}\n setSecrets({ [requestUserCredentials.secretsKey]: token });\n setCredentialsHost(state.host);\n },\n 500,\n [state, uiSchema],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n return (\n <>\n {schema.title && (\n <Box my={1}>\n <Typography variant=\"h5\">{schema.title}</Typography>\n <Divider />\n </Box>\n )}\n {schema.description && (\n <Typography variant=\"body1\">{schema.description}</Typography>\n )}\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n onChange={updateLocalState}\n rawErrors={rawErrors}\n state={state}\n />\n )}\n {hostType === 'gitea' && (\n <GiteaRepoPicker\n allowedOwners={allowedOwners}\n allowedRepos={allowedRepos}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n allowedOwners={allowedOwners}\n allowedProjects={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n accessToken={\n uiSchema?.['ui:options']?.requestUserCredentials?.secretsKey &&\n secrets[uiSchema['ui:options'].requestUserCredentials.secretsKey]\n }\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n allowedOrganizations={allowedOrganizations}\n allowedProject={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gerrit' && (\n <GerritRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n <RepoUrlPickerRepoName\n repoName={state.repoName}\n allowedRepos={allowedRepos}\n onChange={repo =>\n setState(prevState => ({ ...prevState, repoName: repo }))\n }\n rawErrors={rawErrors}\n availableRepos={state.availableRepos}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { makeFieldSchemaFromZod } from '../utils.esm.js';
|
|
1
|
+
import { makeFieldSchema } from '@backstage/plugin-scaffolder-react';
|
|
3
2
|
|
|
4
|
-
const RepoUrlPickerFieldSchema =
|
|
5
|
-
z.string(),
|
|
6
|
-
z.object({
|
|
3
|
+
const RepoUrlPickerFieldSchema = makeFieldSchema({
|
|
4
|
+
output: (z) => z.string(),
|
|
5
|
+
uiOptions: (z) => z.object({
|
|
7
6
|
allowedHosts: z.array(z.string()).optional().describe("List of allowed SCM platform hosts"),
|
|
8
7
|
allowedOrganizations: z.array(z.string()).optional().describe("List of allowed organizations in the given SCM platform"),
|
|
9
8
|
allowedOwners: z.array(z.string()).optional().describe("List of allowed owners in the given SCM platform"),
|
|
@@ -25,7 +24,7 @@ const RepoUrlPickerFieldSchema = makeFieldSchemaFromZod(
|
|
|
25
24
|
"If defined will request user credentials to auth against the given SCM platform"
|
|
26
25
|
)
|
|
27
26
|
})
|
|
28
|
-
);
|
|
27
|
+
});
|
|
29
28
|
const RepoUrlPickerSchema = RepoUrlPickerFieldSchema.schema;
|
|
30
29
|
|
|
31
30
|
export { RepoUrlPickerFieldSchema, RepoUrlPickerSchema };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/schema.ts"],"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 {
|
|
1
|
+
{"version":3,"file":"schema.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/schema.ts"],"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 { makeFieldSchema } from '@backstage/plugin-scaffolder-react';\n\n/**\n * @public\n */\nexport const RepoUrlPickerFieldSchema = makeFieldSchema({\n output: z => z.string(),\n uiOptions: z =>\n z.object({\n allowedHosts: z\n .array(z.string())\n .optional()\n .describe('List of allowed SCM platform hosts'),\n allowedOrganizations: z\n .array(z.string())\n .optional()\n .describe('List of allowed organizations in the given SCM platform'),\n allowedOwners: z\n .array(z.string())\n .optional()\n .describe('List of allowed owners in the given SCM platform'),\n allowedProjects: z\n .array(z.string())\n .optional()\n .describe('List of allowed projects in the given SCM platform'),\n allowedRepos: z\n .array(z.string())\n .optional()\n .describe('List of allowed repos in the given SCM platform'),\n requestUserCredentials: z\n .object({\n secretsKey: z\n .string()\n .describe(\n 'Key used within the template secrets context to store the credential',\n ),\n additionalScopes: z\n .object({\n gitea: z\n .array(z.string())\n .optional()\n .describe('Additional Gitea scopes to request'),\n gerrit: z\n .array(z.string())\n .optional()\n .describe('Additional Gerrit scopes to request'),\n github: z\n .array(z.string())\n .optional()\n .describe('Additional GitHub scopes to request'),\n gitlab: z\n .array(z.string())\n .optional()\n .describe('Additional GitLab scopes to request'),\n bitbucket: z\n .array(z.string())\n .optional()\n .describe('Additional BitBucket scopes to request'),\n azure: z\n .array(z.string())\n .optional()\n .describe('Additional Azure scopes to request'),\n })\n .optional()\n .describe('Additional permission scopes to request'),\n })\n .optional()\n .describe(\n 'If defined will request user credentials to auth against the given SCM platform',\n ),\n }),\n});\n\n/**\n * The input props that can be specified under `ui:options` for the\n * `RepoUrlPicker` field extension.\n *\n * @public\n * @deprecated this will be removed as it's no longer used\n */\nexport type RepoUrlPickerUiOptions =\n typeof RepoUrlPickerFieldSchema.uiOptionsType;\n\nexport type RepoUrlPickerProps = typeof RepoUrlPickerFieldSchema.type;\n\n// This has been duplicated to /plugins/scaffolder/src/components/fields/RepoBranchPicker/schema.ts\n// NOTE: There is a bug with this failing validation in the custom field explorer due\n// to https://github.com/rjsf-team/react-jsonschema-form/issues/675 even if\n// requestUserCredentials is not defined\nexport const RepoUrlPickerSchema = RepoUrlPickerFieldSchema.schema;\n"],"names":[],"mappings":";;AAqBO,MAAM,2BAA2B,eAAgB,CAAA;AAAA,EACtD,MAAA,EAAQ,CAAK,CAAA,KAAA,CAAA,CAAE,MAAO,EAAA;AAAA,EACtB,SAAA,EAAW,CACT,CAAA,KAAA,CAAA,CAAE,MAAO,CAAA;AAAA,IACP,YAAA,EAAc,CACX,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,oCAAoC,CAAA;AAAA,IAChD,oBAAA,EAAsB,CACnB,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,yDAAyD,CAAA;AAAA,IACrE,aAAA,EAAe,CACZ,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,kDAAkD,CAAA;AAAA,IAC9D,eAAA,EAAiB,CACd,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,oDAAoD,CAAA;AAAA,IAChE,YAAA,EAAc,CACX,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,iDAAiD,CAAA;AAAA,IAC7D,sBAAA,EAAwB,EACrB,MAAO,CAAA;AAAA,MACN,UAAA,EAAY,CACT,CAAA,MAAA,EACA,CAAA,QAAA;AAAA,QACC,sEAAA;AAAA,OACF;AAAA,MACF,gBAAA,EAAkB,EACf,MAAO,CAAA;AAAA,QACN,KAAA,EAAO,CACJ,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,oCAAoC,CAAA;AAAA,QAChD,MAAA,EAAQ,CACL,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,qCAAqC,CAAA;AAAA,QACjD,MAAA,EAAQ,CACL,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,qCAAqC,CAAA;AAAA,QACjD,MAAA,EAAQ,CACL,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,qCAAqC,CAAA;AAAA,QACjD,SAAA,EAAW,CACR,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,wCAAwC,CAAA;AAAA,QACpD,KAAA,EAAO,CACJ,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA,EACA,CAAA,QAAA,CAAS,oCAAoC,CAAA;AAAA,OACjD,CAAA,CACA,QAAS,EAAA,CACT,SAAS,yCAAyC,CAAA;AAAA,KACtD,CACA,CAAA,QAAA,EACA,CAAA,QAAA;AAAA,MACC,iFAAA;AAAA,KACF;AAAA,GACH,CAAA;AACL,CAAC,EAAA;AAkBM,MAAM,sBAAsB,wBAAyB,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.esm.js","sources":["../../../src/components/fields/utils.ts"],"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 { JSONSchema7 } from 'json-schema';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport {
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../../../src/components/fields/utils.ts"],"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 { JSONSchema7 } from 'json-schema';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { FieldSchema as FieldSchemaType } from '@backstage/plugin-scaffolder-react';\n\n/**\n * @public\n * @deprecated - import from {@link @backstage/plugin-scaffolder-react#FieldSchema} instead\n */\nexport interface FieldSchema<T, P> extends FieldSchemaType<T, P> {}\n\n/**\n * @public\n * @deprecated use `makeFieldSchema` instead\n * Utility function to convert zod return and UI options schemas to a\n * CustomFieldExtensionSchema with FieldExtensionComponentProps type inference\n */\n\nexport function makeFieldSchemaFromZod<\n TReturnSchema extends z.ZodType,\n TUiOptionsSchema extends z.ZodType = z.ZodType<any, any, {}>,\n>(\n returnSchema: TReturnSchema,\n uiOptionsSchema?: TUiOptionsSchema,\n): FieldSchema<\n TReturnSchema extends z.ZodType<any, any, infer IReturn> ? IReturn : never,\n TUiOptionsSchema extends z.ZodType<any, any, infer IUiOptions>\n ? IUiOptions\n : never\n> {\n return {\n schema: {\n returnValue: zodToJsonSchema(returnSchema) as JSONSchema7,\n uiOptions: uiOptionsSchema\n ? (zodToJsonSchema(uiOptionsSchema) as JSONSchema7)\n : undefined,\n },\n type: null as any,\n uiOptionsType: null as any,\n TProps: undefined as any,\n };\n}\n"],"names":[],"mappings":";;AAiCgB,SAAA,sBAAA,CAId,cACA,eAMA,EAAA;AACA,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA;AAAA,MACN,WAAA,EAAa,gBAAgB,YAAY,CAAA;AAAA,MACzC,SAAW,EAAA,eAAA,GACN,eAAgB,CAAA,eAAe,CAChC,GAAA,KAAA,CAAA;AAAA,KACN;AAAA,IACA,IAAM,EAAA,IAAA;AAAA,IACN,aAAe,EAAA,IAAA;AAAA,IACf,MAAQ,EAAA,KAAA,CAAA;AAAA,GACV,CAAA;AACF;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DiscoveryApi, FetchApi, IdentityApi, ApiHolder } from '@backstage/core-
|
|
|
4
4
|
import { ScmIntegrationRegistry } from '@backstage/integration';
|
|
5
5
|
import { Observable } from '@backstage/types';
|
|
6
6
|
import * as _backstage_plugin_scaffolder_react from '@backstage/plugin-scaffolder-react';
|
|
7
|
-
import { ScaffolderApi as ScaffolderApi$1, ScaffolderTask as ScaffolderTask$1, ScaffolderGetIntegrationsListOptions as ScaffolderGetIntegrationsListOptions$1, ScaffolderGetIntegrationsListResponse as ScaffolderGetIntegrationsListResponse$1, TemplateParameterSchema as TemplateParameterSchema$1, ScaffolderScaffoldOptions as ScaffolderScaffoldOptions$1, ScaffolderScaffoldResponse as ScaffolderScaffoldResponse$1, ScaffolderStreamLogsOptions as ScaffolderStreamLogsOptions$1, LogEvent as LogEvent$1, ScaffolderDryRunOptions as ScaffolderDryRunOptions$1, ScaffolderDryRunResponse as ScaffolderDryRunResponse$1, ListActionsResponse as ListActionsResponse$1, ReviewStepProps, ScaffolderTaskOutput as ScaffolderTaskOutput$1, TemplateGroupFilter, FormProps,
|
|
7
|
+
import { ScaffolderApi as ScaffolderApi$1, ScaffolderTask as ScaffolderTask$1, ScaffolderGetIntegrationsListOptions as ScaffolderGetIntegrationsListOptions$1, ScaffolderGetIntegrationsListResponse as ScaffolderGetIntegrationsListResponse$1, TemplateParameterSchema as TemplateParameterSchema$1, ScaffolderScaffoldOptions as ScaffolderScaffoldOptions$1, ScaffolderScaffoldResponse as ScaffolderScaffoldResponse$1, ScaffolderStreamLogsOptions as ScaffolderStreamLogsOptions$1, LogEvent as LogEvent$1, ScaffolderDryRunOptions as ScaffolderDryRunOptions$1, ScaffolderDryRunResponse as ScaffolderDryRunResponse$1, ListActionsResponse as ListActionsResponse$1, ReviewStepProps, ScaffolderTaskOutput as ScaffolderTaskOutput$1, TemplateGroupFilter, FormProps, FieldSchema as FieldSchema$1, createScaffolderFieldExtension as createScaffolderFieldExtension$1, ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecrets$1, CustomFieldExtensionSchema as CustomFieldExtensionSchema$1, CustomFieldValidator as CustomFieldValidator$1, FieldExtensionOptions as FieldExtensionOptions$1, FieldExtensionComponentProps as FieldExtensionComponentProps$1, FieldExtensionComponent as FieldExtensionComponent$1, ScaffolderOutputLink, ScaffolderTaskStatus as ScaffolderTaskStatus$1, createScaffolderLayout as createScaffolderLayout$1, LayoutTemplate as LayoutTemplate$1, LayoutOptions as LayoutOptions$1 } from '@backstage/plugin-scaffolder-react';
|
|
8
8
|
export { ReviewStepProps } from '@backstage/plugin-scaffolder-react';
|
|
9
9
|
import * as React from 'react';
|
|
10
10
|
import React__default, { PropsWithChildren } from 'react';
|
|
@@ -46,6 +46,7 @@ declare class ScaffolderClient implements ScaffolderApi$1 {
|
|
|
46
46
|
private streamLogsPolling;
|
|
47
47
|
listActions(): Promise<ListActionsResponse$1>;
|
|
48
48
|
cancelTask(taskId: string): Promise<void>;
|
|
49
|
+
retry?(taskId: string): Promise<void>;
|
|
49
50
|
autocomplete({ token, resource, provider, context, }: {
|
|
50
51
|
token: string;
|
|
51
52
|
provider: string;
|
|
@@ -106,6 +107,9 @@ declare const scaffolderPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
|
106
107
|
actions: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
107
108
|
listTasks: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
108
109
|
edit: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
110
|
+
editor: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
111
|
+
customFields: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
112
|
+
templateForm: _backstage_core_plugin_api.SubRouteRef<undefined>;
|
|
109
113
|
}, {
|
|
110
114
|
registerComponent: _backstage_core_plugin_api.ExternalRouteRef<undefined, true>;
|
|
111
115
|
viewTechDoc: _backstage_core_plugin_api.ExternalRouteRef<{
|
|
@@ -251,16 +255,13 @@ declare const RepoBranchPickerFieldExtension: _backstage_plugin_scaffolder_react
|
|
|
251
255
|
|
|
252
256
|
/**
|
|
253
257
|
* @public
|
|
254
|
-
*
|
|
255
|
-
* matching FieldExtensionComponentProps type for a field extension.
|
|
258
|
+
* @deprecated - import from {@link @backstage/plugin-scaffolder-react#FieldSchema} instead
|
|
256
259
|
*/
|
|
257
|
-
interface FieldSchema<
|
|
258
|
-
readonly schema: CustomFieldExtensionSchema$1;
|
|
259
|
-
readonly type: FieldExtensionComponentProps$1<TReturn, TUiOptions>;
|
|
260
|
-
readonly uiOptionsType: TUiOptions;
|
|
260
|
+
interface FieldSchema<T, P> extends FieldSchema$1<T, P> {
|
|
261
261
|
}
|
|
262
262
|
/**
|
|
263
263
|
* @public
|
|
264
|
+
* @deprecated use `makeFieldSchema` instead
|
|
264
265
|
* Utility function to convert zod return and UI options schemas to a
|
|
265
266
|
* CustomFieldExtensionSchema with FieldExtensionComponentProps type inference
|
|
266
267
|
*/
|
|
@@ -312,7 +313,7 @@ type OwnerPickerUiOptions = typeof OwnerPickerFieldSchema.uiOptionsType;
|
|
|
312
313
|
/**
|
|
313
314
|
* @public
|
|
314
315
|
*/
|
|
315
|
-
declare const RepoUrlPickerFieldSchema: FieldSchema<string, {
|
|
316
|
+
declare const RepoUrlPickerFieldSchema: _backstage_plugin_scaffolder_react.FieldSchema<string, {
|
|
316
317
|
allowedHosts?: string[] | undefined;
|
|
317
318
|
allowedOrganizations?: string[] | undefined;
|
|
318
319
|
allowedOwners?: string[] | undefined;
|
|
@@ -335,6 +336,7 @@ declare const RepoUrlPickerFieldSchema: FieldSchema<string, {
|
|
|
335
336
|
* `RepoUrlPicker` field extension.
|
|
336
337
|
*
|
|
337
338
|
* @public
|
|
339
|
+
* @deprecated this will be removed as it's no longer used
|
|
338
340
|
*/
|
|
339
341
|
type RepoUrlPickerUiOptions = typeof RepoUrlPickerFieldSchema.uiOptionsType;
|
|
340
342
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { get, set } from 'idb-keyval';
|
|
2
|
+
|
|
1
3
|
const showDirectoryPicker = window.showDirectoryPicker;
|
|
2
4
|
class WebFileAccess {
|
|
3
5
|
constructor(path, handle) {
|
|
@@ -36,11 +38,32 @@ class WebDirectoryAccess {
|
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
}
|
|
41
|
+
async createFile(options) {
|
|
42
|
+
const { name, data } = options;
|
|
43
|
+
let file;
|
|
44
|
+
if (name.includes("/")) {
|
|
45
|
+
const [dir, path] = name.split("/");
|
|
46
|
+
const handle = await this.handle.getDirectoryHandle(dir, {
|
|
47
|
+
create: true
|
|
48
|
+
});
|
|
49
|
+
file = await handle.getFileHandle(path, { create: true });
|
|
50
|
+
} else {
|
|
51
|
+
file = await this.handle.getFileHandle(name, {
|
|
52
|
+
create: true
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const writable = await file.createWritable();
|
|
56
|
+
await writable.write(data);
|
|
57
|
+
await writable.close();
|
|
58
|
+
}
|
|
39
59
|
}
|
|
40
60
|
class WebFileSystemAccess {
|
|
41
61
|
static isSupported() {
|
|
42
62
|
return Boolean(showDirectoryPicker);
|
|
43
63
|
}
|
|
64
|
+
static fromHandle(handle) {
|
|
65
|
+
return new WebDirectoryAccess(handle);
|
|
66
|
+
}
|
|
44
67
|
static async requestDirectoryAccess() {
|
|
45
68
|
if (!showDirectoryPicker) {
|
|
46
69
|
throw new Error("File system access is not supported");
|
|
@@ -51,6 +74,16 @@ class WebFileSystemAccess {
|
|
|
51
74
|
constructor() {
|
|
52
75
|
}
|
|
53
76
|
}
|
|
77
|
+
class WebFileSystemStore {
|
|
78
|
+
static key = "scalfolder-template-editor-directory";
|
|
79
|
+
static async getDirectory() {
|
|
80
|
+
const directory = await get(WebFileSystemStore.key);
|
|
81
|
+
return directory.handle;
|
|
82
|
+
}
|
|
83
|
+
static async setDirectory(directory) {
|
|
84
|
+
return set(WebFileSystemStore.key, directory);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
54
87
|
|
|
55
|
-
export { WebFileSystemAccess };
|
|
88
|
+
export { WebFileSystemAccess, WebFileSystemStore };
|
|
56
89
|
//# sourceMappingURL=WebFileSystemAccess.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebFileSystemAccess.esm.js","sources":["../../../src/lib/filesystem/WebFileSystemAccess.ts"],"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 { TemplateDirectoryAccess, TemplateFileAccess } from './types';\n\ntype WritableFileHandle = FileSystemFileHandle & {\n createWritable(): Promise<{\n write(data: string | Blob | BufferSource): Promise<void>;\n close(): Promise<void>;\n }>;\n};\n\n// A nicer type than the one from the TS lib\ninterface IterableDirectoryHandle extends FileSystemDirectoryHandle {\n values(): AsyncIterable<\n | ({ kind: 'file' } & WritableFileHandle)\n | ({ kind: 'directory' } & IterableDirectoryHandle)\n >;\n}\n\nconst showDirectoryPicker = (window as any).showDirectoryPicker as\n | (() => Promise<IterableDirectoryHandle>)\n | undefined;\n\nclass WebFileAccess implements TemplateFileAccess {\n constructor(\n readonly path: string,\n private readonly handle: WritableFileHandle,\n ) {}\n\n file(): Promise<File> {\n return this.handle.getFile();\n }\n\n async save(data: string | Blob | BufferSource): Promise<void> {\n const writable = await this.handle.createWritable();\n await writable.write(data);\n await writable.close();\n }\n}\n\nclass WebDirectoryAccess implements TemplateDirectoryAccess {\n constructor(private readonly handle: IterableDirectoryHandle) {}\n\n async listFiles(): Promise<TemplateFileAccess[]> {\n const content = [];\n for await (const entry of this.listDirectoryContents(this.handle)) {\n content.push(entry);\n }\n return content;\n }\n\n private async *listDirectoryContents(\n dirHandle: IterableDirectoryHandle,\n basePath: string[] = [],\n ): AsyncIterable<TemplateFileAccess> {\n for await (const handle of dirHandle.values()) {\n if (handle.kind === 'file') {\n yield new WebFileAccess([...basePath, handle.name].join('/'), handle);\n } else if (handle.kind === 'directory') {\n // Skip git storage directory\n if (handle.name === '.git') {\n continue;\n }\n yield* this.listDirectoryContents(handle, [...basePath, handle.name]);\n }\n }\n }\n}\n\n/** @internal */\nexport class WebFileSystemAccess {\n static isSupported(): boolean {\n return Boolean(showDirectoryPicker);\n }\n\n static async requestDirectoryAccess(): Promise<TemplateDirectoryAccess> {\n if (!showDirectoryPicker) {\n throw new Error('File system access is not supported');\n }\n const handle = await showDirectoryPicker();\n return new WebDirectoryAccess(handle);\n }\n\n private constructor() {}\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WebFileSystemAccess.esm.js","sources":["../../../src/lib/filesystem/WebFileSystemAccess.ts"],"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 { get, set } from 'idb-keyval';\nimport { TemplateDirectoryAccess, TemplateFileAccess } from './types';\n\ntype WritableFileHandle = FileSystemFileHandle & {\n createWritable(): Promise<{\n write(data: string | Blob | BufferSource): Promise<void>;\n close(): Promise<void>;\n }>;\n};\n\n// A nicer type than the one from the TS lib\ninterface IterableDirectoryHandle extends FileSystemDirectoryHandle {\n values(): AsyncIterable<\n | ({ kind: 'file' } & WritableFileHandle)\n | ({ kind: 'directory' } & IterableDirectoryHandle)\n >;\n}\n\nconst showDirectoryPicker = (window as any).showDirectoryPicker as\n | (() => Promise<IterableDirectoryHandle>)\n | undefined;\n\nclass WebFileAccess implements TemplateFileAccess {\n constructor(\n readonly path: string,\n private readonly handle: WritableFileHandle,\n ) {}\n\n file(): Promise<File> {\n return this.handle.getFile();\n }\n\n async save(data: string | Blob | BufferSource): Promise<void> {\n const writable = await this.handle.createWritable();\n await writable.write(data);\n await writable.close();\n }\n}\n\nclass WebDirectoryAccess implements TemplateDirectoryAccess {\n constructor(private readonly handle: IterableDirectoryHandle) {}\n\n async listFiles(): Promise<TemplateFileAccess[]> {\n const content = [];\n for await (const entry of this.listDirectoryContents(this.handle)) {\n content.push(entry);\n }\n return content;\n }\n\n private async *listDirectoryContents(\n dirHandle: IterableDirectoryHandle,\n basePath: string[] = [],\n ): AsyncIterable<TemplateFileAccess> {\n for await (const handle of dirHandle.values()) {\n if (handle.kind === 'file') {\n yield new WebFileAccess([...basePath, handle.name].join('/'), handle);\n } else if (handle.kind === 'directory') {\n // Skip git storage directory\n if (handle.name === '.git') {\n continue;\n }\n yield* this.listDirectoryContents(handle, [...basePath, handle.name]);\n }\n }\n }\n\n async createFile(options: { name: string; data: string }): Promise<void> {\n const { name, data } = options;\n let file: FileSystemFileHandle;\n\n // Current create template does not require support for nested directories\n if (name.includes('/')) {\n const [dir, path] = name.split('/');\n const handle = await this.handle.getDirectoryHandle(dir, {\n create: true,\n });\n file = await handle.getFileHandle(path, { create: true });\n } else {\n file = await this.handle.getFileHandle(name, {\n create: true,\n });\n }\n const writable = await file.createWritable();\n await writable.write(data);\n await writable.close();\n }\n}\n\n/** @internal */\nexport class WebFileSystemAccess {\n static isSupported(): boolean {\n return Boolean(showDirectoryPicker);\n }\n\n static fromHandle(handle: IterableDirectoryHandle) {\n return new WebDirectoryAccess(handle);\n }\n\n static async requestDirectoryAccess(): Promise<TemplateDirectoryAccess> {\n if (!showDirectoryPicker) {\n throw new Error('File system access is not supported');\n }\n const handle = await showDirectoryPicker();\n return new WebDirectoryAccess(handle);\n }\n\n private constructor() {}\n}\n\nexport class WebFileSystemStore {\n private static readonly key = 'scalfolder-template-editor-directory';\n\n static async getDirectory(): Promise<IterableDirectoryHandle | undefined> {\n const directory = await get(WebFileSystemStore.key);\n return directory.handle;\n }\n\n static async setDirectory(directory: TemplateDirectoryAccess | undefined) {\n return set(WebFileSystemStore.key, directory);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const files = {
|
|
2
|
+
"template.yaml": `
|
|
3
|
+
apiVersion: scaffolder.backstage.io/v1beta3
|
|
4
|
+
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
|
|
5
|
+
kind: Template
|
|
6
|
+
metadata:
|
|
7
|
+
name: generated-example-template
|
|
8
|
+
title: Scaffolder Example Template
|
|
9
|
+
description: An example template for the scaffolder
|
|
10
|
+
spec:
|
|
11
|
+
owner: user:guest
|
|
12
|
+
type: service
|
|
13
|
+
# These parameters are used to generate the input form in the frontend, and are
|
|
14
|
+
# used to gather input data for the execution of the template.
|
|
15
|
+
parameters:
|
|
16
|
+
- title: Fill in some steps
|
|
17
|
+
required:
|
|
18
|
+
- name
|
|
19
|
+
properties:
|
|
20
|
+
name:
|
|
21
|
+
title: Name
|
|
22
|
+
type: string
|
|
23
|
+
description: Unique name of the component
|
|
24
|
+
owner:
|
|
25
|
+
title: Owner
|
|
26
|
+
type: string
|
|
27
|
+
description: Owner of the component
|
|
28
|
+
ui:field: OwnerPicker
|
|
29
|
+
ui:options:
|
|
30
|
+
catalogFilter:
|
|
31
|
+
kind: Group
|
|
32
|
+
- title: Choose a location
|
|
33
|
+
required:
|
|
34
|
+
- repoUrl
|
|
35
|
+
properties:
|
|
36
|
+
repoUrl:
|
|
37
|
+
title: Repository Location
|
|
38
|
+
type: string
|
|
39
|
+
ui:field: RepoUrlPicker
|
|
40
|
+
ui:options:
|
|
41
|
+
allowedHosts:
|
|
42
|
+
- github.com
|
|
43
|
+
steps:
|
|
44
|
+
- id: fetch-base
|
|
45
|
+
name: Fetch Base
|
|
46
|
+
action: fetch:template
|
|
47
|
+
input:
|
|
48
|
+
url: ./skeleton
|
|
49
|
+
values:
|
|
50
|
+
name: \${{parameters.name}}
|
|
51
|
+
owner: \${{parameters.owner}}
|
|
52
|
+
destination: \${{ parameters.repoUrl | parseRepoUrl }}`,
|
|
53
|
+
"skeleton/README.md": `# This service is named \${{values.name}}!`,
|
|
54
|
+
"skeleton/catalog-info.yaml": `apiVersion: backstage.io/v1alpha1
|
|
55
|
+
kind: Component
|
|
56
|
+
metadata:
|
|
57
|
+
name: \${{values.component_id | dump}}
|
|
58
|
+
{%- if values.description %}
|
|
59
|
+
description: \${{values.description | dump}}
|
|
60
|
+
{%- endif %}
|
|
61
|
+
annotations:
|
|
62
|
+
github.com/project-slug: \${{values.destination.owner + "/" + values.destination.repo}}
|
|
63
|
+
backstage.io/techdocs-ref: dir:.
|
|
64
|
+
spec:
|
|
65
|
+
type: service
|
|
66
|
+
lifecycle: experimental
|
|
67
|
+
owner: \${{values.owner | dump}}`
|
|
68
|
+
};
|
|
69
|
+
async function createExampleTemplate(directory) {
|
|
70
|
+
for (const [name, data] of Object.entries(files)) {
|
|
71
|
+
await directory.createFile({ name, data });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { createExampleTemplate };
|
|
76
|
+
//# sourceMappingURL=createExampleTemplate.esm.js.map
|