@backstage/plugin-scaffolder 1.28.0 → 1.29.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunContext.esm.js +4 -3
- package/dist/alpha/components/TemplateEditorPage/DryRunContext.esm.js.map +1 -1
- package/dist/alpha/extensions.esm.js +20 -6
- package/dist/alpha/extensions.esm.js.map +1 -1
- package/dist/alpha.d.ts +8 -3
- package/dist/components/Router/Router.esm.js +20 -2
- package/dist/components/Router/Router.esm.js.map +1 -1
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js +3 -1
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -1
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js +3 -0
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js.map +1 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +3 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.esm.js +11 -1
- package/dist/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.esm.js +2 -0
- package/dist/components/fields/RepoBranchPicker/DefaultRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/GitHubRepoBranchPicker.esm.js +11 -1
- package/dist/components/fields/RepoBranchPicker/GitHubRepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoBranchPicker/RepoBranchPicker.esm.js +3 -0
- package/dist/components/fields/RepoBranchPicker/RepoBranchPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js +6 -3
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js +8 -3
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js +3 -1
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js +3 -2
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js +11 -2
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js +11 -2
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js +14 -2
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js +2 -2
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js +11 -3
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js.map +1 -1
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js +3 -1
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -1
- package/package.json +22 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 1.29.0-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/core-components@0.16.5-next.0
|
|
9
|
+
- @backstage/plugin-scaffolder-react@1.14.6-next.1
|
|
10
|
+
- @backstage/plugin-scaffolder-common@1.5.10-next.0
|
|
11
|
+
- @backstage/plugin-catalog-react@1.16.0-next.1
|
|
12
|
+
- @backstage/core-compat-api@0.3.7-next.1
|
|
13
|
+
- @backstage/catalog-client@1.9.1
|
|
14
|
+
- @backstage/catalog-model@1.7.3
|
|
15
|
+
- @backstage/core-plugin-api@1.10.4
|
|
16
|
+
- @backstage/errors@1.2.7
|
|
17
|
+
- @backstage/frontend-plugin-api@0.9.6-next.1
|
|
18
|
+
- @backstage/integration@1.16.1
|
|
19
|
+
- @backstage/integration-react@1.2.4
|
|
20
|
+
- @backstage/types@1.2.1
|
|
21
|
+
- @backstage/plugin-catalog-common@1.1.3
|
|
22
|
+
- @backstage/plugin-permission-react@0.4.31
|
|
23
|
+
|
|
24
|
+
## 1.29.0-next.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- 9d864ff: Allowed passing `ui:disabled` for disabling the input field of all the pickers.
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 6a3fa48: Fixes DryRunContext not forwarding the correct Scaffolder Secrets to the DryRun API
|
|
33
|
+
- b3b7c9c: Updated the alpha `page:scaffolder` extension to accept `formFields` input, matching the updated `FormFieldBlueprint`.
|
|
34
|
+
- Updated dependencies
|
|
35
|
+
- @backstage/plugin-catalog-react@1.16.0-next.0
|
|
36
|
+
- @backstage/plugin-scaffolder-react@1.14.6-next.0
|
|
37
|
+
- @backstage/frontend-plugin-api@0.9.6-next.0
|
|
38
|
+
- @backstage/core-compat-api@0.3.7-next.0
|
|
39
|
+
- @backstage/integration-react@1.2.4
|
|
40
|
+
|
|
3
41
|
## 1.28.0
|
|
4
42
|
|
|
5
43
|
### Minor Changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import yaml from 'yaml';
|
|
2
2
|
import { useApi } from '@backstage/core-plugin-api';
|
|
3
3
|
import React, { createContext, useState, useRef, useCallback, useMemo, useContext } from 'react';
|
|
4
|
-
import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
|
|
4
|
+
import { scaffolderApiRef, useTemplateSecrets } from '@backstage/plugin-scaffolder-react';
|
|
5
5
|
import { useFormDecorators } from '../../hooks/useFormDecorators.esm.js';
|
|
6
6
|
|
|
7
7
|
const MAX_CONTENT_SIZE = 64 * 1024;
|
|
@@ -28,6 +28,7 @@ function base64EncodeContent(content) {
|
|
|
28
28
|
function DryRunProvider(props) {
|
|
29
29
|
const decorators = useFormDecorators();
|
|
30
30
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
31
|
+
const { secrets: contextSecrets } = useTemplateSecrets();
|
|
31
32
|
const [state, setState] = useState({
|
|
32
33
|
results: [],
|
|
33
34
|
selectedResult: void 0
|
|
@@ -67,7 +68,7 @@ function DryRunProvider(props) {
|
|
|
67
68
|
const parsed = yaml.parse(options.templateContent);
|
|
68
69
|
const { formState: values, secrets } = await decorators.run({
|
|
69
70
|
formState: options.values,
|
|
70
|
-
secrets:
|
|
71
|
+
secrets: contextSecrets,
|
|
71
72
|
manifest: parsed?.spec
|
|
72
73
|
});
|
|
73
74
|
const response = await scaffolderApi.dryRun({
|
|
@@ -88,7 +89,7 @@ function DryRunProvider(props) {
|
|
|
88
89
|
selectedResult: prevState.selectedResult ?? result
|
|
89
90
|
}));
|
|
90
91
|
},
|
|
91
|
-
[scaffolderApi, decorators]
|
|
92
|
+
[scaffolderApi, decorators, contextSecrets]
|
|
92
93
|
);
|
|
93
94
|
const dryRun = useMemo(
|
|
94
95
|
() => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DryRunContext.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/DryRunContext.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 yaml from 'yaml';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport React, {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n scaffolderApiRef,\n ScaffolderDryRunResponse,\n} from '@backstage/plugin-scaffolder-react';\nimport { useFormDecorators } from '../../hooks/useFormDecorators';\n\nconst MAX_CONTENT_SIZE = 64 * 1024;\nconst CHUNK_SIZE = 32 * 1024;\n\ninterface DryRunOptions {\n templateContent: string;\n values: JsonObject;\n files: Array<{ path: string; content: string }>;\n}\n\nexport interface DryRunResult extends ScaffolderDryRunResponse {\n id: number;\n}\n\ninterface DryRun {\n results: DryRunResult[];\n selectedResult: DryRunResult | undefined;\n\n selectResult(id: number): void;\n deleteResult(id: number): void;\n execute(options: DryRunOptions): Promise<void>;\n}\n\nconst DryRunContext = createContext<DryRun | undefined>(undefined);\n\ninterface DryRunProviderProps {\n children: ReactNode;\n}\n\nexport function base64EncodeContent(content: string): string {\n if (content.length > MAX_CONTENT_SIZE) {\n return window.btoa('<file too large>');\n }\n\n try {\n return window.btoa(content);\n } catch {\n const decoder = new TextEncoder();\n const buffer = decoder.encode(content);\n\n const chunks = new Array<string>();\n for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {\n chunks.push(\n String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE)),\n );\n }\n return window.btoa(chunks.join(''));\n }\n}\n\nexport function DryRunProvider(props: DryRunProviderProps) {\n const decorators = useFormDecorators();\n const scaffolderApi = useApi(scaffolderApiRef);\n
|
|
1
|
+
{"version":3,"file":"DryRunContext.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/DryRunContext.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 yaml from 'yaml';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport React, {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n scaffolderApiRef,\n ScaffolderDryRunResponse,\n useTemplateSecrets,\n} from '@backstage/plugin-scaffolder-react';\nimport { useFormDecorators } from '../../hooks/useFormDecorators';\n\nconst MAX_CONTENT_SIZE = 64 * 1024;\nconst CHUNK_SIZE = 32 * 1024;\n\ninterface DryRunOptions {\n templateContent: string;\n values: JsonObject;\n files: Array<{ path: string; content: string }>;\n}\n\nexport interface DryRunResult extends ScaffolderDryRunResponse {\n id: number;\n}\n\ninterface DryRun {\n results: DryRunResult[];\n selectedResult: DryRunResult | undefined;\n\n selectResult(id: number): void;\n deleteResult(id: number): void;\n execute(options: DryRunOptions): Promise<void>;\n}\n\nconst DryRunContext = createContext<DryRun | undefined>(undefined);\n\ninterface DryRunProviderProps {\n children: ReactNode;\n}\n\nexport function base64EncodeContent(content: string): string {\n if (content.length > MAX_CONTENT_SIZE) {\n return window.btoa('<file too large>');\n }\n\n try {\n return window.btoa(content);\n } catch {\n const decoder = new TextEncoder();\n const buffer = decoder.encode(content);\n\n const chunks = new Array<string>();\n for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {\n chunks.push(\n String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE)),\n );\n }\n return window.btoa(chunks.join(''));\n }\n}\n\nexport function DryRunProvider(props: DryRunProviderProps) {\n const decorators = useFormDecorators();\n const scaffolderApi = useApi(scaffolderApiRef);\n const { secrets: contextSecrets } = useTemplateSecrets();\n const [state, setState] = useState<\n Pick<DryRun, 'results' | 'selectedResult'>\n >({\n results: [],\n selectedResult: undefined,\n });\n const idRef = useRef(1);\n\n const selectResult = useCallback((id: number) => {\n setState(prevState => {\n const result = prevState.results.find(r => r.id === id);\n if (result === prevState.selectedResult) {\n return prevState;\n }\n return {\n results: prevState.results,\n selectedResult: result,\n };\n });\n }, []);\n\n const deleteResult = useCallback((id: number) => {\n setState(prevState => {\n const index = prevState.results.findIndex(r => r.id === id);\n if (index === -1) {\n return prevState;\n }\n const newResults = prevState.results.slice();\n const [deleted] = newResults.splice(index, 1);\n return {\n results: newResults,\n selectedResult:\n prevState.selectedResult?.id === deleted.id\n ? newResults[0]\n : prevState.selectedResult,\n };\n });\n }, []);\n\n const execute = useCallback(\n async (options: DryRunOptions) => {\n if (!scaffolderApi.dryRun) {\n throw new Error('Scaffolder API does not support dry-run');\n }\n\n const parsed = yaml.parse(options.templateContent);\n\n const { formState: values, secrets } = await decorators.run({\n formState: options.values as Record<string, JsonValue>,\n secrets: contextSecrets,\n manifest: parsed?.spec,\n });\n\n const response = await scaffolderApi.dryRun({\n template: parsed,\n values,\n secrets,\n directoryContents: options.files.map(file => ({\n path: file.path,\n base64Content: base64EncodeContent(file.content),\n })),\n });\n\n const result = {\n ...response,\n id: idRef.current++,\n };\n\n setState(prevState => ({\n results: [...prevState.results, result],\n selectedResult: prevState.selectedResult ?? result,\n }));\n },\n [scaffolderApi, decorators, contextSecrets],\n );\n\n const dryRun = useMemo(\n () => ({\n ...state,\n selectResult,\n deleteResult,\n execute,\n }),\n [state, selectResult, deleteResult, execute],\n );\n\n return (\n <DryRunContext.Provider value={dryRun}>\n {props.children}\n </DryRunContext.Provider>\n );\n}\n\nexport function useDryRun(): DryRun {\n const value = useContext(DryRunContext);\n if (!value) {\n throw new Error('must be used within a DryRunProvider');\n }\n return value;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { convertLegacyRouteRef, compatWrapper } from '@backstage/core-compat-api';
|
|
2
|
-
import { PageBlueprint, NavItemBlueprint, ApiBlueprint, createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { PageBlueprint, createExtensionInput, NavItemBlueprint, ApiBlueprint, createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef } from '@backstage/frontend-plugin-api';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { rootRouteRef } from '../routes.esm.js';
|
|
5
5
|
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
|
|
@@ -8,11 +8,25 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
|
|
8
8
|
import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
|
|
9
9
|
import { ScaffolderClient } from '../api.esm.js';
|
|
10
10
|
|
|
11
|
-
const scaffolderPage = PageBlueprint.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const scaffolderPage = PageBlueprint.makeWithOverrides({
|
|
12
|
+
inputs: {
|
|
13
|
+
formFields: createExtensionInput([
|
|
14
|
+
FormFieldBlueprint.dataRefs.formFieldLoader
|
|
15
|
+
])
|
|
16
|
+
},
|
|
17
|
+
factory(originalFactory, { inputs }) {
|
|
18
|
+
const formFieldLoaders = inputs.formFields.map(
|
|
19
|
+
(i) => i.get(FormFieldBlueprint.dataRefs.formFieldLoader)
|
|
20
|
+
);
|
|
21
|
+
return originalFactory({
|
|
22
|
+
routeRef: convertLegacyRouteRef(rootRouteRef),
|
|
23
|
+
defaultPath: "/create",
|
|
24
|
+
loader: () => import('../components/Router/Router.esm.js').then(
|
|
25
|
+
(m) => compatWrapper(
|
|
26
|
+
/* @__PURE__ */ React.createElement(m.InternalRouter, { formFieldLoaders })
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
});
|
|
16
30
|
}
|
|
17
31
|
});
|
|
18
32
|
const scaffolderNavItem = NavItemBlueprint.make({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.esm.js","sources":["../../src/alpha/extensions.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n NavItemBlueprint,\n PageBlueprint,\n ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n} from '@backstage/frontend-plugin-api';\nimport React from 'react';\nimport { rootRouteRef } from '../routes';\nimport CreateComponentIcon from '@material-ui/icons/AddCircleOutline';\nimport { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderClient } from '../api';\n\nexport const scaffolderPage = PageBlueprint.
|
|
1
|
+
{"version":3,"file":"extensions.esm.js","sources":["../../src/alpha/extensions.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n NavItemBlueprint,\n PageBlueprint,\n ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport React from 'react';\nimport { rootRouteRef } from '../routes';\nimport CreateComponentIcon from '@material-ui/icons/AddCircleOutline';\nimport { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderClient } from '../api';\n\nexport const scaffolderPage = PageBlueprint.makeWithOverrides({\n inputs: {\n formFields: createExtensionInput([\n FormFieldBlueprint.dataRefs.formFieldLoader,\n ]),\n },\n factory(originalFactory, { inputs }) {\n const formFieldLoaders = inputs.formFields.map(i =>\n i.get(FormFieldBlueprint.dataRefs.formFieldLoader),\n );\n return originalFactory({\n routeRef: convertLegacyRouteRef(rootRouteRef),\n defaultPath: '/create',\n loader: () =>\n import('../components/Router/Router').then(m =>\n compatWrapper(\n <m.InternalRouter formFieldLoaders={formFieldLoaders} />,\n ),\n ),\n });\n },\n});\n\nexport const scaffolderNavItem = NavItemBlueprint.make({\n params: {\n routeRef: convertLegacyRouteRef(rootRouteRef),\n title: 'Create...',\n icon: CreateComponentIcon,\n },\n});\n\nexport const repoUrlPickerFormField = FormFieldBlueprint.make({\n name: 'repo-url-picker',\n params: {\n field: () => import('./fields/RepoUrlPicker').then(m => m.RepoUrlPicker),\n },\n});\n\nexport const scaffolderApi = ApiBlueprint.make({\n params: {\n factory: createApiFactory({\n api: scaffolderApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n scmIntegrationsApi: scmIntegrationsApiRef,\n fetchApi: fetchApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) =>\n new ScaffolderClient({\n discoveryApi,\n scmIntegrationsApi,\n fetchApi,\n identityApi,\n }),\n }),\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;AAsCa,MAAA,cAAA,GAAiB,cAAc,iBAAkB,CAAA;AAAA,EAC5D,MAAQ,EAAA;AAAA,IACN,YAAY,oBAAqB,CAAA;AAAA,MAC/B,mBAAmB,QAAS,CAAA;AAAA,KAC7B;AAAA,GACH;AAAA,EACA,OAAQ,CAAA,eAAA,EAAiB,EAAE,MAAA,EAAU,EAAA;AACnC,IAAM,MAAA,gBAAA,GAAmB,OAAO,UAAW,CAAA,GAAA;AAAA,MAAI,CAC7C,CAAA,KAAA,CAAA,CAAE,GAAI,CAAA,kBAAA,CAAmB,SAAS,eAAe;AAAA,KACnD;AACA,IAAA,OAAO,eAAgB,CAAA;AAAA,MACrB,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,MAC5C,WAAa,EAAA,SAAA;AAAA,MACb,MAAQ,EAAA,MACN,OAAO,oCAA6B,CAAE,CAAA,IAAA;AAAA,QAAK,CACzC,CAAA,KAAA,aAAA;AAAA,0BACG,KAAA,CAAA,aAAA,CAAA,CAAA,CAAE,cAAF,EAAA,EAAiB,gBAAoC,EAAA;AAAA;AACxD;AACF,KACH,CAAA;AAAA;AAEL,CAAC;AAEY,MAAA,iBAAA,GAAoB,iBAAiB,IAAK,CAAA;AAAA,EACrD,MAAQ,EAAA;AAAA,IACN,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,KAAO,EAAA,WAAA;AAAA,IACP,IAAM,EAAA;AAAA;AAEV,CAAC;AAEY,MAAA,sBAAA,GAAyB,mBAAmB,IAAK,CAAA;AAAA,EAC5D,IAAM,EAAA,iBAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,KAAA,EAAO,MAAM,OAAO,+BAAwB,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,aAAa;AAAA;AAE3E,CAAC;AAEY,MAAA,aAAA,GAAgB,aAAa,IAAK,CAAA;AAAA,EAC7C,MAAQ,EAAA;AAAA,IACN,SAAS,gBAAiB,CAAA;AAAA,MACxB,GAAK,EAAA,gBAAA;AAAA,MACL,IAAM,EAAA;AAAA,QACJ,YAAc,EAAA,eAAA;AAAA,QACd,kBAAoB,EAAA,qBAAA;AAAA,QACpB,QAAU,EAAA,WAAA;AAAA,QACV,WAAa,EAAA;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,oBAAoB,QAAU,EAAA,WAAA,EACtD,KAAA,IAAI,gBAAiB,CAAA;AAAA,QACnB,YAAA;AAAA,QACA,kBAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA,OACD;AAAA,KACJ;AAAA;AAEL,CAAC;;;;"}
|
package/dist/alpha.d.ts
CHANGED
|
@@ -334,8 +334,6 @@ declare const _default: _backstage_frontend_plugin_api.FrontendPlugin<{
|
|
|
334
334
|
};
|
|
335
335
|
}>;
|
|
336
336
|
"page:scaffolder": _backstage_frontend_plugin_api.ExtensionDefinition<{
|
|
337
|
-
kind: "page";
|
|
338
|
-
name: undefined;
|
|
339
337
|
config: {
|
|
340
338
|
path: string | undefined;
|
|
341
339
|
};
|
|
@@ -345,7 +343,14 @@ declare const _default: _backstage_frontend_plugin_api.FrontendPlugin<{
|
|
|
345
343
|
output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
|
|
346
344
|
optional: true;
|
|
347
345
|
}>;
|
|
348
|
-
inputs: {
|
|
346
|
+
inputs: {
|
|
347
|
+
formFields: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<() => Promise<FormField>, "scaffolder.form-field-loader", {}>, {
|
|
348
|
+
singleton: false;
|
|
349
|
+
optional: false;
|
|
350
|
+
}>;
|
|
351
|
+
};
|
|
352
|
+
kind: "page";
|
|
353
|
+
name: undefined;
|
|
349
354
|
params: {
|
|
350
355
|
defaultPath: string;
|
|
351
356
|
loader: () => Promise<JSX.Element>;
|
|
@@ -15,8 +15,11 @@ import { CustomFieldsPage } from '../../alpha/components/TemplateEditorPage/Cust
|
|
|
15
15
|
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
16
16
|
import { taskReadPermission, templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha';
|
|
17
17
|
import { useApp } from '@backstage/core-plugin-api';
|
|
18
|
+
import { useAsync, useMountEffect } from '@react-hookz/web';
|
|
19
|
+
import { OpaqueFormField } from '../../packages/scaffolder-internal/src/wiring/InternalFormField.esm.js';
|
|
20
|
+
import '../../packages/scaffolder-internal/src/wiring/InternalFormDecorator.esm.js';
|
|
18
21
|
|
|
19
|
-
const
|
|
22
|
+
const InternalRouter = (props) => {
|
|
20
23
|
const {
|
|
21
24
|
components: {
|
|
22
25
|
TemplateCardComponent,
|
|
@@ -29,10 +32,12 @@ const Router = (props) => {
|
|
|
29
32
|
} = props;
|
|
30
33
|
const outlet = useOutlet() || props.children;
|
|
31
34
|
const customFieldExtensions = useCustomFieldExtensions(outlet);
|
|
35
|
+
const loadedFieldExtensions = useFormFieldLoaders(props.formFieldLoaders);
|
|
32
36
|
const app = useApp();
|
|
33
37
|
const { NotFoundErrorPage } = app.getComponents();
|
|
34
38
|
const fieldExtensions = [
|
|
35
39
|
...customFieldExtensions,
|
|
40
|
+
...loadedFieldExtensions,
|
|
36
41
|
...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(
|
|
37
42
|
({ name }) => !customFieldExtensions.some(
|
|
38
43
|
(customFieldExtension) => customFieldExtension.name === name
|
|
@@ -133,6 +138,19 @@ const Router = (props) => {
|
|
|
133
138
|
}
|
|
134
139
|
), /* @__PURE__ */ React.createElement(Route, { path: "*", element: /* @__PURE__ */ React.createElement(NotFoundErrorPage, null) }));
|
|
135
140
|
};
|
|
141
|
+
const Router = (props) => {
|
|
142
|
+
return /* @__PURE__ */ React.createElement(InternalRouter, { ...props });
|
|
143
|
+
};
|
|
144
|
+
function useFormFieldLoaders(formFieldLoaders) {
|
|
145
|
+
const [{ result: loadedFieldExtensions }, { execute }] = useAsync(async () => {
|
|
146
|
+
const loaded = await Promise.all(
|
|
147
|
+
(formFieldLoaders ?? []).map((loader) => loader())
|
|
148
|
+
);
|
|
149
|
+
return loaded.map((f) => OpaqueFormField.toInternal(f));
|
|
150
|
+
}, []);
|
|
151
|
+
useMountEffect(execute);
|
|
152
|
+
return loadedFieldExtensions;
|
|
153
|
+
}
|
|
136
154
|
|
|
137
|
-
export { Router };
|
|
155
|
+
export { InternalRouter, Router };
|
|
138
156
|
//# sourceMappingURL=Router.esm.js.map
|
|
@@ -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 editorRouteRef,\n customFieldsRouteRef,\n editRouteRef,\n scaffolderListTaskRouteRef,\n scaffolderTaskRouteRef,\n selectedTemplateRouteRef,\n templateFormRouteRef,\n} from '../../routes';\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 TemplateFormPage,\n TemplateIntroPage,\n TemplateEditorPage,\n CustomFieldsPage,\n} from '../../alpha/components/TemplateEditorPage';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport {\n taskReadPermission,\n templateManagementPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { useApp } from '@backstage/core-plugin-api';\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 /** Whether to show a link to the create page (on /create subroutes) */\n create?: 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 const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\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 <RequirePermission permission={taskReadPermission}>\n <TaskPageComponent\n TemplateOutputsComponent={TemplateOutputsComponent}\n />\n </RequirePermission>\n }\n />\n <Route\n path={editRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateIntroPage />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route\n path={customFieldsRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <CustomFieldsPage fieldExtensions={fieldExtensions} />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route\n path={templateFormRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateFormPage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n\n <Route\n path={actionsRouteRef.path}\n element={<ActionsPage contextMenu={props.contextMenu} />}\n />\n <Route\n path={scaffolderListTaskRouteRef.path}\n element={\n <RequirePermission permission={taskReadPermission}>\n <ListTasksPage contextMenu={props.contextMenu} />\n </RequirePermission>\n }\n />\n <Route\n path={editorRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateEditorPage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route path=\"*\" element={<NotFoundErrorPage />} />\n </Routes>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
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';\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 TemplateFormPage,\n TemplateIntroPage,\n TemplateEditorPage,\n CustomFieldsPage,\n} from '../../alpha/components/TemplateEditorPage';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport {\n taskReadPermission,\n templateManagementPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { useApp } from '@backstage/core-plugin-api';\nimport { FormField, OpaqueFormField } from '@internal/scaffolder';\nimport { useAsync, useMountEffect } from '@react-hookz/web';\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 /** Whether to show a link to the create page (on /create subroutes) */\n create?: boolean;\n };\n};\n\n/**\n * Internal router with additional props that aren't available in the public API\n * for the old frontend system.\n *\n * @internal\n */\nexport const InternalRouter = (\n props: PropsWithChildren<\n RouterProps & { formFieldLoaders?: Array<() => Promise<FormField>> }\n >,\n) => {\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 = useCustomFieldExtensions(outlet);\n const loadedFieldExtensions = useFormFieldLoaders(props.formFieldLoaders);\n\n const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\n\n const fieldExtensions = [\n ...customFieldExtensions,\n ...loadedFieldExtensions,\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 <RequirePermission permission={taskReadPermission}>\n <TaskPageComponent\n TemplateOutputsComponent={TemplateOutputsComponent}\n />\n </RequirePermission>\n }\n />\n <Route\n path={editRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateIntroPage />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route\n path={customFieldsRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <CustomFieldsPage fieldExtensions={fieldExtensions} />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route\n path={templateFormRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateFormPage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n\n <Route\n path={actionsRouteRef.path}\n element={<ActionsPage contextMenu={props.contextMenu} />}\n />\n <Route\n path={scaffolderListTaskRouteRef.path}\n element={\n <RequirePermission permission={taskReadPermission}>\n <ListTasksPage contextMenu={props.contextMenu} />\n </RequirePermission>\n }\n />\n <Route\n path={editorRouteRef.path}\n element={\n <RequirePermission permission={templateManagementPermission}>\n <SecretsContextProvider>\n <TemplateEditorPage\n layouts={customLayouts}\n formProps={props.formProps}\n fieldExtensions={fieldExtensions}\n />\n </SecretsContextProvider>\n </RequirePermission>\n }\n />\n <Route path=\"*\" element={<NotFoundErrorPage />} />\n </Routes>\n );\n};\n\n/**\n * The Scaffolder Router\n *\n * @public\n */\nexport const Router = (props: PropsWithChildren<RouterProps>) => {\n return <InternalRouter {...props} />;\n};\n\nfunction useFormFieldLoaders(\n formFieldLoaders?: Array<() => Promise<FormField>>,\n) {\n const [{ result: loadedFieldExtensions }, { execute }] =\n useAsync(async () => {\n const loaded = await Promise.all(\n (formFieldLoaders ?? []).map(loader => loader()),\n );\n return loaded.map(f => OpaqueFormField.toInternal(f));\n }, []);\n useMountEffect(execute);\n return loadedFieldExtensions;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,7 @@ const EntityPicker = (props) => {
|
|
|
29
29
|
const catalogFilter = buildCatalogFilter(uiSchema);
|
|
30
30
|
const defaultKind = uiSchema["ui:options"]?.defaultKind;
|
|
31
31
|
const defaultNamespace = uiSchema["ui:options"]?.defaultNamespace || void 0;
|
|
32
|
+
const isDisabled = uiSchema?.["ui:disabled"] ?? false;
|
|
32
33
|
const catalogApi = useApi(catalogApiRef);
|
|
33
34
|
const entityPresentationApi = useApi(entityPresentationApiRef);
|
|
34
35
|
const { value: entities, loading } = useAsync(async () => {
|
|
@@ -106,7 +107,7 @@ const EntityPicker = (props) => {
|
|
|
106
107
|
/* @__PURE__ */ React.createElement(
|
|
107
108
|
Autocomplete,
|
|
108
109
|
{
|
|
109
|
-
disabled: required && !allowArbitraryValues && entities?.catalogEntities.length === 1,
|
|
110
|
+
disabled: isDisabled || required && !allowArbitraryValues && entities?.catalogEntities.length === 1,
|
|
110
111
|
id: idSchema?.$id,
|
|
111
112
|
value: selectedEntity,
|
|
112
113
|
loading,
|
|
@@ -128,6 +129,7 @@ const EntityPicker = (props) => {
|
|
|
128
129
|
FormHelperTextProps: { margin: "dense", style: { marginLeft: 0 } },
|
|
129
130
|
variant: "outlined",
|
|
130
131
|
required,
|
|
132
|
+
disabled: isDisabled,
|
|
131
133
|
InputProps: params.InputProps
|
|
132
134
|
}
|
|
133
135
|
),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityPicker.esm.js","sources":["../../../../src/components/fields/EntityPicker/EntityPicker.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 EntityDisplayName,\n EntityRefPresentationSnapshot,\n catalogApiRef,\n entityPresentationApiRef,\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 createFilterOptions,\n} from '@material-ui/lab/Autocomplete';\nimport React, { useCallback, useEffect } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n EntityPickerFilterQueryValue,\n EntityPickerProps,\n EntityPickerUiOptions,\n EntityPickerFilterQuery,\n} from './schema';\nimport { VirtualizedListbox } from '../VirtualizedListbox';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nexport { EntityPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `EntityPicker`\n * field extension.\n *\n * @public\n */\nexport const EntityPicker = (props: EntityPickerProps) => {\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const {\n onChange,\n schema: {\n title = t('fields.entityPicker.title'),\n description = t('fields.entityPicker.description'),\n },\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\n const { value: entities, loading } = useAsync(async () => {\n const fields = [\n 'metadata.name',\n 'metadata.namespace',\n 'metadata.title',\n 'kind',\n ];\n const { items } = await catalogApi.getEntities(\n catalogFilter\n ? { filter: catalogFilter, fields }\n : { filter: undefined, fields },\n );\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\n return { catalogEntities: items, entityRefToPresentation };\n });\n\n const allowArbitraryValues =\n uiSchema['ui:options']?.allowArbitraryValues ?? true;\n\n const getLabel = useCallback(\n (freeSoloValue: string) => {\n try {\n // Will throw if defaultKind or defaultNamespace are not set\n const parsedRef = parseEntityRef(freeSoloValue, {\n defaultKind,\n defaultNamespace,\n });\n\n return stringifyEntityRef(parsedRef);\n } catch (err) {\n return freeSoloValue;\n }\n },\n [defaultKind, defaultNamespace],\n );\n\n const onSelect = useCallback(\n (_: any, ref: string | Entity | null, reason: AutocompleteChangeReason) => {\n // ref can either be a string from free solo entry or\n if (typeof ref !== 'string') {\n // if ref does not exist: pass 'undefined' to trigger validation for required value\n onChange(ref ? stringifyEntityRef(ref as Entity) : undefined);\n } else {\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 // We need to check against formData here as that's the previous value for this field.\n if (formData !== ref || allowArbitraryValues) {\n onChange(entityRef);\n }\n }\n }\n },\n [onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues],\n );\n\n // Since free solo can be enabled, attempt to parse as a full entity ref first, then fall\n // back to the given value.\n const selectedEntity =\n entities?.catalogEntities.find(e => stringifyEntityRef(e) === formData) ??\n (allowArbitraryValues && formData ? getLabel(formData) : '');\n\n useEffect(() => {\n if (\n required &&\n !allowArbitraryValues &&\n entities?.catalogEntities.length === 1 &&\n selectedEntity === ''\n ) {\n onChange(stringifyEntityRef(entities.catalogEntities[0]));\n }\n }, [entities, onChange, selectedEntity, required, allowArbitraryValues]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n disabled={\n required &&\n !allowArbitraryValues &&\n entities?.catalogEntities.length === 1\n }\n id={idSchema?.$id}\n value={selectedEntity}\n loading={loading}\n onChange={onSelect}\n options={entities?.catalogEntities || []}\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={{ margin: 'dense', style: { marginLeft: 0 } }}\n variant=\"outlined\"\n required={required}\n InputProps={params.InputProps}\n />\n )}\n renderOption={option => <EntityDisplayName entityRef={option} />}\n filterOptions={createFilterOptions<Entity>({\n stringify: option =>\n entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.primaryTitle!,\n })}\n ListboxComponent={VirtualizedListbox}\n />\n </FormControl>\n );\n};\n\n/**\n * Converts a especial `{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<EntityPickerFilterQueryValue, 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: EntityPickerFilterQuery,\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 * If `allowedKinds` is specified in the `uiSchema` will support the legacy `allowedKinds` option.\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: EntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds;\n\n const catalogFilter: EntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter ||\n (allowedKinds && { kind: allowedKinds });\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":"EntityPicker.esm.js","sources":["../../../../src/components/fields/EntityPicker/EntityPicker.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 EntityDisplayName,\n EntityRefPresentationSnapshot,\n catalogApiRef,\n entityPresentationApiRef,\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 createFilterOptions,\n} from '@material-ui/lab/Autocomplete';\nimport React, { useCallback, useEffect } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n EntityPickerFilterQueryValue,\n EntityPickerProps,\n EntityPickerUiOptions,\n EntityPickerFilterQuery,\n} from './schema';\nimport { VirtualizedListbox } from '../VirtualizedListbox';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nexport { EntityPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `EntityPicker`\n * field extension.\n *\n * @public\n */\nexport const EntityPicker = (props: EntityPickerProps) => {\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const {\n onChange,\n schema: {\n title = t('fields.entityPicker.title'),\n description = t('fields.entityPicker.description'),\n },\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 isDisabled = uiSchema?.['ui:disabled'] ?? false;\n\n const catalogApi = useApi(catalogApiRef);\n const entityPresentationApi = useApi(entityPresentationApiRef);\n\n const { value: entities, loading } = useAsync(async () => {\n const fields = [\n 'metadata.name',\n 'metadata.namespace',\n 'metadata.title',\n 'kind',\n ];\n const { items } = await catalogApi.getEntities(\n catalogFilter\n ? { filter: catalogFilter, fields }\n : { filter: undefined, fields },\n );\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\n return { catalogEntities: items, entityRefToPresentation };\n });\n\n const allowArbitraryValues =\n uiSchema['ui:options']?.allowArbitraryValues ?? true;\n\n const getLabel = useCallback(\n (freeSoloValue: string) => {\n try {\n // Will throw if defaultKind or defaultNamespace are not set\n const parsedRef = parseEntityRef(freeSoloValue, {\n defaultKind,\n defaultNamespace,\n });\n\n return stringifyEntityRef(parsedRef);\n } catch (err) {\n return freeSoloValue;\n }\n },\n [defaultKind, defaultNamespace],\n );\n\n const onSelect = useCallback(\n (_: any, ref: string | Entity | null, reason: AutocompleteChangeReason) => {\n // ref can either be a string from free solo entry or\n if (typeof ref !== 'string') {\n // if ref does not exist: pass 'undefined' to trigger validation for required value\n onChange(ref ? stringifyEntityRef(ref as Entity) : undefined);\n } else {\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 // We need to check against formData here as that's the previous value for this field.\n if (formData !== ref || allowArbitraryValues) {\n onChange(entityRef);\n }\n }\n }\n },\n [onChange, formData, defaultKind, defaultNamespace, allowArbitraryValues],\n );\n\n // Since free solo can be enabled, attempt to parse as a full entity ref first, then fall\n // back to the given value.\n const selectedEntity =\n entities?.catalogEntities.find(e => stringifyEntityRef(e) === formData) ??\n (allowArbitraryValues && formData ? getLabel(formData) : '');\n\n useEffect(() => {\n if (\n required &&\n !allowArbitraryValues &&\n entities?.catalogEntities.length === 1 &&\n selectedEntity === ''\n ) {\n onChange(stringifyEntityRef(entities.catalogEntities[0]));\n }\n }, [entities, onChange, selectedEntity, required, allowArbitraryValues]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n disabled={\n isDisabled ||\n (required &&\n !allowArbitraryValues &&\n entities?.catalogEntities.length === 1)\n }\n id={idSchema?.$id}\n value={selectedEntity}\n loading={loading}\n onChange={onSelect}\n options={entities?.catalogEntities || []}\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={{ margin: 'dense', style: { marginLeft: 0 } }}\n variant=\"outlined\"\n required={required}\n disabled={isDisabled}\n InputProps={params.InputProps}\n />\n )}\n renderOption={option => <EntityDisplayName entityRef={option} />}\n filterOptions={createFilterOptions<Entity>({\n stringify: option =>\n entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.primaryTitle!,\n })}\n ListboxComponent={VirtualizedListbox}\n />\n </FormControl>\n );\n};\n\n/**\n * Converts a especial `{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<EntityPickerFilterQueryValue, 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: EntityPickerFilterQuery,\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 * If `allowedKinds` is specified in the `uiSchema` will support the legacy `allowedKinds` option.\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: EntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds;\n\n const catalogFilter: EntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter ||\n (allowedKinds && { kind: allowedKinds });\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":";;;;;;;;;;;;;;AAyDa,MAAA,YAAA,GAAe,CAAC,KAA6B,KAAA;AACxD,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,wBAAwB,CAAA;AACxD,EAAM,MAAA;AAAA,IACJ,QAAA;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,KAAA,GAAQ,EAAE,2BAA2B,CAAA;AAAA,MACrC,WAAA,GAAc,EAAE,iCAAiC;AAAA,KACnD;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AACJ,EAAM,MAAA,aAAA,GAAgB,mBAAmB,QAAQ,CAAA;AACjD,EAAM,MAAA,WAAA,GAAc,QAAS,CAAA,YAAY,CAAG,EAAA,WAAA;AAC5C,EAAA,MAAM,gBACJ,GAAA,QAAA,CAAS,YAAY,CAAA,EAAG,gBAAoB,IAAA,KAAA,CAAA;AAC9C,EAAM,MAAA,UAAA,GAAa,QAAW,GAAA,aAAa,CAAK,IAAA,KAAA;AAEhD,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,qBAAA,GAAwB,OAAO,wBAAwB,CAAA;AAE7D,EAAA,MAAM,EAAE,KAAO,EAAA,QAAA,EAAU,OAAQ,EAAA,GAAI,SAAS,YAAY;AACxD,IAAA,MAAM,MAAS,GAAA;AAAA,MACb,eAAA;AAAA,MACA,oBAAA;AAAA,MACA,gBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,UAAW,CAAA,WAAA;AAAA,MACjC,aAAA,GACI,EAAE,MAAQ,EAAA,aAAA,EAAe,QACzB,GAAA,EAAE,MAAQ,EAAA,KAAA,CAAA,EAAW,MAAO;AAAA,KAClC;AAEA,IAAA,MAAM,0BAA0B,IAAI,GAAA;AAAA,MAIlC,MAAM,OAAQ,CAAA,GAAA;AAAA,QACZ,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,UAAA,MAAM,YAAe,GAAA,MAAM,qBAAsB,CAAA,SAAA,CAAU,IAAI,CAC5D,CAAA,OAAA;AACH,UAAA,OAAO,CAAC,kBAAA,CAAmB,IAAI,CAAA,EAAG,YAAY,CAAA;AAAA,SAI/C;AAAA;AACH,KACF;AAEA,IAAO,OAAA,EAAE,eAAiB,EAAA,KAAA,EAAO,uBAAwB,EAAA;AAAA,GAC1D,CAAA;AAED,EAAA,MAAM,oBACJ,GAAA,QAAA,CAAS,YAAY,CAAA,EAAG,oBAAwB,IAAA,IAAA;AAElD,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,aAA0B,KAAA;AACzB,MAAI,IAAA;AAEF,QAAM,MAAA,SAAA,GAAY,eAAe,aAAe,EAAA;AAAA,UAC9C,WAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAA,OAAO,mBAAmB,SAAS,CAAA;AAAA,eAC5B,GAAK,EAAA;AACZ,QAAO,OAAA,aAAA;AAAA;AACT,KACF;AAAA,IACA,CAAC,aAAa,gBAAgB;AAAA,GAChC;AAEA,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,CAAQ,EAAA,GAAA,EAA6B,MAAqC,KAAA;AAEzE,MAAI,IAAA,OAAO,QAAQ,QAAU,EAAA;AAE3B,QAAA,QAAA,CAAS,GAAM,GAAA,kBAAA,CAAmB,GAAa,CAAA,GAAI,KAAS,CAAA,CAAA;AAAA,OACvD,MAAA;AACL,QAAI,IAAA,MAAA,KAAW,MAAU,IAAA,MAAA,KAAW,eAAiB,EAAA;AAEnD,UAAA,IAAI,SAAY,GAAA,GAAA;AAChB,UAAI,IAAA;AAEF,YAAY,SAAA,GAAA,kBAAA;AAAA,cACV,eAAe,GAAe,EAAA;AAAA,gBAC5B,WAAA;AAAA,gBACA;AAAA,eACD;AAAA,aACH;AAAA,mBACO,GAAK,EAAA;AAAA;AAId,UAAI,IAAA,QAAA,KAAa,OAAO,oBAAsB,EAAA;AAC5C,YAAA,QAAA,CAAS,SAAS,CAAA;AAAA;AACpB;AACF;AACF,KACF;AAAA,IACA,CAAC,QAAA,EAAU,QAAU,EAAA,WAAA,EAAa,kBAAkB,oBAAoB;AAAA,GAC1E;AAIA,EAAA,MAAM,cACJ,GAAA,QAAA,EAAU,eAAgB,CAAA,IAAA,CAAK,OAAK,kBAAmB,CAAA,CAAC,CAAM,KAAA,QAAQ,CACrE,KAAA,oBAAA,IAAwB,QAAW,GAAA,QAAA,CAAS,QAAQ,CAAI,GAAA,EAAA,CAAA;AAE3D,EAAA,SAAA,CAAU,MAAM;AACd,IACE,IAAA,QAAA,IACA,CAAC,oBACD,IAAA,QAAA,EAAU,gBAAgB,MAAW,KAAA,CAAA,IACrC,mBAAmB,EACnB,EAAA;AACA,MAAA,QAAA,CAAS,kBAAmB,CAAA,QAAA,CAAS,eAAgB,CAAA,CAAC,CAAC,CAAC,CAAA;AAAA;AAC1D,KACC,CAAC,QAAA,EAAU,UAAU,cAAgB,EAAA,QAAA,EAAU,oBAAoB,CAAC,CAAA;AAEvE,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,QAAA;AAAA,MACP,QAAA;AAAA,MACA,KAAO,EAAA,SAAA,EAAW,MAAS,GAAA,CAAA,IAAK,CAAC;AAAA,KAAA;AAAA,oBAEjC,KAAA,CAAA,aAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,UACE,UACC,IAAA,QAAA,IACC,CAAC,oBACD,IAAA,QAAA,EAAU,gBAAgB,MAAW,KAAA,CAAA;AAAA,QAEzC,IAAI,QAAU,EAAA,GAAA;AAAA,QACd,KAAO,EAAA,cAAA;AAAA,QACP,OAAA;AAAA,QACA,QAAU,EAAA,QAAA;AAAA,QACV,OAAA,EAAS,QAAU,EAAA,eAAA,IAAmB,EAAC;AAAA,QACvC,cAAgB,EAAA,CAAA,MAAA;AAAA;AAAA,UAEd,OAAO,MAAW,KAAA,QAAA,GACd,MACA,GAAA,QAAA,EAAU,wBAAwB,GAAI,CAAA,kBAAA,CAAmB,MAAM,CAAC,CAC5D,EAAA;AAAA,SAAA;AAAA,QAEV,UAAU,EAAA,IAAA;AAAA,QACV,QAAU,EAAA,oBAAA;AAAA,QACV,aAAa,CACX,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YACE,GAAG,MAAA;AAAA,YACJ,KAAO,EAAA,KAAA;AAAA,YACP,MAAO,EAAA,OAAA;AAAA,YACP,UAAY,EAAA,WAAA;AAAA,YACZ,mBAAA,EAAqB,EAAE,MAAQ,EAAA,OAAA,EAAS,OAAO,EAAE,UAAA,EAAY,GAAI,EAAA;AAAA,YACjE,OAAQ,EAAA,UAAA;AAAA,YACR,QAAA;AAAA,YACA,QAAU,EAAA,UAAA;AAAA,YACV,YAAY,MAAO,CAAA;AAAA;AAAA,SACrB;AAAA,QAEF,YAAc,EAAA,CAAA,MAAA,qBAAW,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,WAAW,MAAQ,EAAA,CAAA;AAAA,QAC9D,eAAe,mBAA4B,CAAA;AAAA,UACzC,SAAA,EAAW,YACT,QAAU,EAAA,uBAAA,CAAwB,IAAI,kBAAmB,CAAA,MAAM,CAAC,CAC5D,EAAA;AAAA,SACP,CAAA;AAAA,QACD,gBAAkB,EAAA;AAAA;AAAA;AACpB,GACF;AAEJ;AAQA,SAAS,iBACP,KACiB,EAAA;AACjB,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,KAAA,CAAM,MAAQ,EAAA;AAC7C,IAAO,OAAA,qBAAA;AAAA;AAET,EAAA,OAAO,OAAO,QAAS,EAAA;AACzB;AAWA,SAAS,4BACP,aACwC,EAAA;AACxC,EAAA,MAAM,QAA2B,EAAC;AAElC,EAAA,KAAA,MAAW,CAAC,GAAK,EAAA,KAAK,KAAK,MAAO,CAAA,OAAA,CAAQ,aAAa,CAAG,EAAA;AACxD,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,KAAK,CAAG,EAAA;AACxB,MAAA,KAAA,CAAM,GAAG,CAAI,GAAA,KAAA;AAAA,KACR,MAAA;AACL,MAAM,KAAA,CAAA,GAAG,CAAI,GAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA;AACrC;AAGF,EAAO,OAAA,KAAA;AACT;AAUA,SAAS,mBACP,QAC+B,EAAA;AAC/B,EAAM,MAAA,YAAA,GAAe,QAAS,CAAA,YAAY,CAAG,EAAA,YAAA;AAE7C,EAAM,MAAA,aAAA,GACJ,SAAS,YAAY,CAAA,EAAG,iBACvB,YAAgB,IAAA,EAAE,MAAM,YAAa,EAAA;AAExC,EAAA,IAAI,CAAC,aAAe,EAAA;AAClB,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,aAAa,CAAG,EAAA;AAChC,IAAO,OAAA,aAAA,CAAc,IAAI,2BAA2B,CAAA;AAAA;AAGtD,EAAA,OAAO,4BAA4B,aAAa,CAAA;AAClD;;;;"}
|
|
@@ -21,6 +21,7 @@ const EntityTagsPicker = (props) => {
|
|
|
21
21
|
const kinds = uiSchema["ui:options"]?.kinds;
|
|
22
22
|
const showCounts = uiSchema["ui:options"]?.showCounts;
|
|
23
23
|
const helperText = uiSchema["ui:options"]?.helperText;
|
|
24
|
+
const isDisabled = uiSchema?.["ui:disabled"] ?? false;
|
|
24
25
|
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
25
26
|
const { loading, value: existingTags } = useAsync(async () => {
|
|
26
27
|
const facet = "metadata.tags";
|
|
@@ -62,6 +63,7 @@ const EntityTagsPicker = (props) => {
|
|
|
62
63
|
freeSolo: true,
|
|
63
64
|
filterSelectedOptions: true,
|
|
64
65
|
onChange: setTags,
|
|
66
|
+
disabled: isDisabled,
|
|
65
67
|
value: formData || [],
|
|
66
68
|
inputValue,
|
|
67
69
|
loading,
|
|
@@ -73,6 +75,7 @@ const EntityTagsPicker = (props) => {
|
|
|
73
75
|
{
|
|
74
76
|
...params,
|
|
75
77
|
label: t("fields.entityTagsPicker.title"),
|
|
78
|
+
disabled: isDisabled,
|
|
76
79
|
onChange: (e) => setInputValue(e.target.value),
|
|
77
80
|
error: inputError,
|
|
78
81
|
helperText: helperText ?? t("fields.entityTagsPicker.description"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityTagsPicker.esm.js","sources":["../../../../src/components/fields/EntityTagsPicker/EntityTagsPicker.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 React, { useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport useEffectOnce from 'react-use/esm/useEffectOnce';\nimport { GetEntityFacetsRequest } from '@backstage/catalog-client';\nimport { makeValidator } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport FormControl from '@material-ui/core/FormControl';\nimport TextField from '@material-ui/core/TextField';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { EntityTagsPickerProps } from './schema';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nexport { EntityTagsPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `EntityTagsPicker`\n * field extension.\n *\n * @public\n */\nexport const EntityTagsPicker = (props: EntityTagsPickerProps) => {\n const { formData, onChange, uiSchema } = props;\n const catalogApi = useApi(catalogApiRef);\n const [tagOptions, setTagOptions] = useState<string[]>([]);\n const [inputValue, setInputValue] = useState('');\n const [inputError, setInputError] = useState(false);\n const tagValidator = makeValidator().isValidTag;\n const kinds = uiSchema['ui:options']?.kinds;\n const showCounts = uiSchema['ui:options']?.showCounts;\n const helperText = uiSchema['ui:options']?.helperText;\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const { loading, value: existingTags } = useAsync(async () => {\n const facet = 'metadata.tags';\n const tagsRequest: GetEntityFacetsRequest = { facets: [facet] };\n if (kinds) {\n tagsRequest.filter = { kind: kinds };\n }\n\n const { facets } = await catalogApi.getEntityFacets(tagsRequest);\n\n const tagFacets = Object.fromEntries(\n facets[facet].map(({ value, count }) => [value, count]),\n );\n\n setTagOptions(\n Object.keys(tagFacets).sort((a, b) =>\n showCounts ? tagFacets[b] - tagFacets[a] : a.localeCompare(b),\n ),\n );\n\n return tagFacets;\n });\n\n const setTags = (_: React.ChangeEvent<{}>, values: string[] | null) => {\n // Reset error state in case all tags were removed\n let hasError = false;\n let addDuplicate = false;\n const currentTags = formData || [];\n\n // If adding a new tag\n if (values?.length && currentTags.length < values.length) {\n const newTag = (values[values.length - 1] = values[values.length - 1]\n .toLocaleLowerCase('en-US')\n .trim());\n hasError = !tagValidator(newTag);\n addDuplicate = currentTags.indexOf(newTag) !== -1;\n }\n\n setInputError(hasError);\n setInputValue(!hasError ? '' : inputValue);\n if (!hasError && !addDuplicate) {\n onChange(values || []);\n }\n };\n\n // Initialize field to always return an array\n useEffectOnce(() => onChange(formData || []));\n\n return (\n <FormControl margin=\"normal\">\n <Autocomplete\n multiple\n freeSolo\n filterSelectedOptions\n onChange={setTags}\n value={formData || []}\n inputValue={inputValue}\n loading={loading}\n options={tagOptions}\n ChipProps={{ size: 'small' }}\n renderOption={option =>\n showCounts ? `${option} (${existingTags?.[option]})` : option\n }\n renderInput={params => (\n <TextField\n {...params}\n label={t('fields.entityTagsPicker.title')}\n onChange={e => setInputValue(e.target.value)}\n error={inputError}\n helperText={helperText ?? t('fields.entityTagsPicker.description')}\n FormHelperTextProps={{ margin: 'dense', style: { marginLeft: 0 } }}\n />\n )}\n />\n </FormControl>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EntityTagsPicker.esm.js","sources":["../../../../src/components/fields/EntityTagsPicker/EntityTagsPicker.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 React, { useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport useEffectOnce from 'react-use/esm/useEffectOnce';\nimport { GetEntityFacetsRequest } from '@backstage/catalog-client';\nimport { makeValidator } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport FormControl from '@material-ui/core/FormControl';\nimport TextField from '@material-ui/core/TextField';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { EntityTagsPickerProps } from './schema';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nexport { EntityTagsPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `EntityTagsPicker`\n * field extension.\n *\n * @public\n */\nexport const EntityTagsPicker = (props: EntityTagsPickerProps) => {\n const { formData, onChange, uiSchema } = props;\n const catalogApi = useApi(catalogApiRef);\n const [tagOptions, setTagOptions] = useState<string[]>([]);\n const [inputValue, setInputValue] = useState('');\n const [inputError, setInputError] = useState(false);\n const tagValidator = makeValidator().isValidTag;\n const kinds = uiSchema['ui:options']?.kinds;\n const showCounts = uiSchema['ui:options']?.showCounts;\n const helperText = uiSchema['ui:options']?.helperText;\n const isDisabled = uiSchema?.['ui:disabled'] ?? false;\n\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const { loading, value: existingTags } = useAsync(async () => {\n const facet = 'metadata.tags';\n const tagsRequest: GetEntityFacetsRequest = { facets: [facet] };\n if (kinds) {\n tagsRequest.filter = { kind: kinds };\n }\n\n const { facets } = await catalogApi.getEntityFacets(tagsRequest);\n\n const tagFacets = Object.fromEntries(\n facets[facet].map(({ value, count }) => [value, count]),\n );\n\n setTagOptions(\n Object.keys(tagFacets).sort((a, b) =>\n showCounts ? tagFacets[b] - tagFacets[a] : a.localeCompare(b),\n ),\n );\n\n return tagFacets;\n });\n\n const setTags = (_: React.ChangeEvent<{}>, values: string[] | null) => {\n // Reset error state in case all tags were removed\n let hasError = false;\n let addDuplicate = false;\n const currentTags = formData || [];\n\n // If adding a new tag\n if (values?.length && currentTags.length < values.length) {\n const newTag = (values[values.length - 1] = values[values.length - 1]\n .toLocaleLowerCase('en-US')\n .trim());\n hasError = !tagValidator(newTag);\n addDuplicate = currentTags.indexOf(newTag) !== -1;\n }\n\n setInputError(hasError);\n setInputValue(!hasError ? '' : inputValue);\n if (!hasError && !addDuplicate) {\n onChange(values || []);\n }\n };\n\n // Initialize field to always return an array\n useEffectOnce(() => onChange(formData || []));\n\n return (\n <FormControl margin=\"normal\">\n <Autocomplete\n multiple\n freeSolo\n filterSelectedOptions\n onChange={setTags}\n disabled={isDisabled}\n value={formData || []}\n inputValue={inputValue}\n loading={loading}\n options={tagOptions}\n ChipProps={{ size: 'small' }}\n renderOption={option =>\n showCounts ? `${option} (${existingTags?.[option]})` : option\n }\n renderInput={params => (\n <TextField\n {...params}\n label={t('fields.entityTagsPicker.title')}\n disabled={isDisabled}\n onChange={e => setInputValue(e.target.value)}\n error={inputError}\n helperText={helperText ?? t('fields.entityTagsPicker.description')}\n FormHelperTextProps={{ margin: 'dense', style: { marginLeft: 0 } }}\n />\n )}\n />\n </FormControl>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -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 isDisabled = uiSchema?.["ui:disabled"] ?? false;
|
|
26
27
|
const [noOfItemsSelected, setNoOfItemsSelected] = useState(0);
|
|
27
28
|
const catalogApi = useApi(catalogApiRef);
|
|
28
29
|
const entityPresentationApi = useApi(entityPresentationApiRef);
|
|
@@ -87,7 +88,7 @@ const MultiEntityPicker = (props) => {
|
|
|
87
88
|
{
|
|
88
89
|
multiple: true,
|
|
89
90
|
filterSelectedOptions: true,
|
|
90
|
-
disabled: required && !allowArbitraryValues && entities?.entities?.length === 1,
|
|
91
|
+
disabled: isDisabled || required && !allowArbitraryValues && entities?.entities?.length === 1,
|
|
91
92
|
id: idSchema?.$id,
|
|
92
93
|
defaultValue: formData,
|
|
93
94
|
loading,
|
|
@@ -106,6 +107,7 @@ const MultiEntityPicker = (props) => {
|
|
|
106
107
|
{
|
|
107
108
|
...params,
|
|
108
109
|
label: title,
|
|
110
|
+
disabled: isDisabled,
|
|
109
111
|
margin: "dense",
|
|
110
112
|
helperText: description,
|
|
111
113
|
FormHelperTextProps: {
|
|
@@ -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, 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 (required && !allowArbitraryValues && entities?.entities?.length === 1) {\n onChange([stringifyEntityRef(entities?.entities[0])]);\n }\n }, [entities, onChange, required, allowArbitraryValues]);\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={\n required && !allowArbitraryValues && entities?.entities?.length === 1\n }\n id={idSchema?.$id}\n defaultValue={formData}\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":";;;;;;;;;;;;AAqDa,MAAA,iBAAA,GAAoB,CAAC,KAAkC,KAAA;AAClE,EAAM,MAAA;AAAA,IACJ,QAAA;AAAA,IACA,MAAQ,EAAA,EAAE,KAAQ,GAAA,QAAA,EAAU,cAAc,4BAA6B,EAAA;AAAA,IACvE,QAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AACJ,EAAM,MAAA,aAAA,GAAgB,mBAAmB,QAAQ,CAAA;AACjD,EAAM,MAAA,WAAA,GAAc,QAAS,CAAA,YAAY,CAAG,EAAA,WAAA;AAC5C,EAAA,MAAM,gBACJ,GAAA,QAAA,CAAS,YAAY,CAAA,EAAG,gBAAoB,IAAA,KAAA,CAAA;AAC9C,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,CAAC,CAAA;AAE5D,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAM,MAAA,qBAAA,GAAwB,OAAO,wBAAwB,CAAA;AAC7D,EAAA,MAAM,EAAE,KAAO,EAAA,QAAA,EAAU,OAAQ,EAAA,GAAI,SAAS,YAAY;AACxD,IAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,UAAW,CAAA,WAAA;AAAA,MACjC,aAAgB,GAAA,EAAE,MAAQ,EAAA,aAAA,EAAkB,GAAA,KAAA;AAAA,KAC9C;AACA,IAAA,MAAM,0BAA0B,IAAI,GAAA;AAAA,MAIlC,MAAM,OAAQ,CAAA,GAAA;AAAA,QACZ,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,UAAA,MAAM,YAAe,GAAA,MAAM,qBAAsB,CAAA,SAAA,CAAU,IAAI,CAC5D,CAAA,OAAA;AACH,UAAA,OAAO,CAAC,kBAAA,CAAmB,IAAI,CAAA,EAAG,YAAY,CAAA;AAAA,SAI/C;AAAA;AACH,KACF;AACA,IAAO,OAAA,EAAE,QAAU,EAAA,KAAA,EAAO,uBAAwB,EAAA;AAAA,GACnD,CAAA;AACD,EAAA,MAAM,oBACJ,GAAA,QAAA,CAAS,YAAY,CAAA,EAAG,oBAAwB,IAAA,IAAA;AAGlD,EAAM,MAAA,QAAA,GAAW,MAAM,MAAO,CAAA,QAAA;AAE9B,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,CAAQ,EAAA,IAAA,EAA2B,MAAqC,KAAA;AACvE,MAAM,MAAA,MAAA,GAAS,IACZ,CAAA,GAAA,CAAI,CAAO,GAAA,KAAA;AACV,QAAI,IAAA,OAAO,QAAQ,QAAU,EAAA;AAE3B,UAAO,OAAA,GAAA,GAAM,kBAAmB,CAAA,GAAa,CAAI,GAAA,KAAA,CAAA;AAAA;AAEnD,QAAI,IAAA,MAAA,KAAW,MAAU,IAAA,MAAA,KAAW,eAAiB,EAAA;AAEnD,UAAA,IAAI,SAAY,GAAA,GAAA;AAChB,UAAI,IAAA;AAEF,YAAY,SAAA,GAAA,kBAAA;AAAA,cACV,eAAe,GAAe,EAAA;AAAA,gBAC5B,WAAA;AAAA,gBACA;AAAA,eACD;AAAA,aACH;AAAA,mBACO,GAAK,EAAA;AAAA;AAKd,UAAA,IAAI,QAAU,EAAA,QAAA,CAAS,GAAG,CAAA,IAAK,oBAAsB,EAAA;AACnD,YAAO,OAAA,SAAA;AAAA;AACT;AAGF,QAAO,OAAA,KAAA,CAAA;AAAA,OACR,CAAA,CACA,MAAO,CAAA,CAAA,GAAA,KAAO,QAAQ,KAAS,CAAA,CAAA;AAElC,MAAA,oBAAA,CAAqB,OAAO,MAAM,CAAA;AAClC,MAAA,QAAA,CAAS,MAAM,CAAA;AAAA,KACjB;AAAA,IACA,CAAC,QAAA,EAAU,QAAU,EAAA,WAAA,EAAa,kBAAkB,oBAAoB;AAAA,GAC1E;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAY,CAAC,oBAAA,IAAwB,QAAU,EAAA,QAAA,EAAU,WAAW,CAAG,EAAA;AACzE,MAAA,QAAA,CAAS,CAAC,kBAAmB,CAAA,QAAA,EAAU,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA;AACtD,KACC,CAAC,QAAA,EAAU,QAAU,EAAA,QAAA,EAAU,oBAAoB,CAAC,CAAA;AAEvD,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,QAAA;AAAA,MACP,QAAA;AAAA,MACA,KAAO,EAAA,SAAA,EAAW,MAAS,GAAA,CAAA,IAAK,CAAC;AAAA,KAAA;AAAA,oBAEjC,KAAA,CAAA,aAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,QAAQ,EAAA,IAAA;AAAA,QACR,qBAAqB,EAAA,IAAA;AAAA,QACrB,UACE,QAAY,IAAA,CAAC,oBAAwB,IAAA,QAAA,EAAU,UAAU,MAAW,KAAA,CAAA;AAAA,QAEtE,IAAI,QAAU,EAAA,GAAA;AAAA,QACd,YAAc,EAAA,QAAA;AAAA,QACd,OAAA;AAAA,QACA,QAAU,EAAA,QAAA;AAAA,QACV,OAAA,EAAS,QAAU,EAAA,QAAA,IAAY,EAAC;AAAA,QAChC,YAAc,EAAA,CAAA,MAAA,qBAAW,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,WAAW,MAAQ,EAAA,CAAA;AAAA,QAC9D,cAAgB,EAAA,CAAA,MAAA;AAAA;AAAA,UAEd,OAAO,MAAW,KAAA,QAAA,GACd,MACA,GAAA,QAAA,EAAU,wBAAwB,GAAI,CAAA,kBAAA,CAAmB,MAAM,CAAC,CAC5D,EAAA;AAAA,SAAA;AAAA,QAEV,iBAAmB,EAAA,CAAA,QAAA,KACjB,QAAW,GAAA,iBAAA,IAAqB,QAAW,GAAA,KAAA;AAAA,QAE7C,UAAU,EAAA,IAAA;AAAA,QACV,QAAU,EAAA,oBAAA;AAAA,QACV,aAAa,CACX,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YACE,GAAG,MAAA;AAAA,YACJ,KAAO,EAAA,KAAA;AAAA,YACP,MAAO,EAAA,OAAA;AAAA,YACP,UAAY,EAAA,WAAA;AAAA,YACZ,mBAAqB,EAAA;AAAA,cACnB,MAAQ,EAAA,OAAA;AAAA,cACR,KAAA,EAAO,EAAE,UAAA,EAAY,CAAE;AAAA,aACzB;AAAA,YACA,OAAQ,EAAA,UAAA;AAAA,YACR,QAAA;AAAA,YACA,UAAY,EAAA;AAAA,cACV,GAAG,MAAO,CAAA,UAAA;AAAA,cACV,QAAA,EAAU,QAAU,EAAA,MAAA,KAAW,CAAK,IAAA;AAAA;AACtC;AAAA,SACF;AAAA,QAEF,gBAAkB,EAAA;AAAA;AAAA;AACpB,GACF;AAEJ;AAEa,MAAA,mCAAA,GAAsC,CACjD,MAAA,EACA,UACG,KAAA;AACH,EAAA,MAAA,CAAO,QAAQ,CAAS,KAAA,KAAA;AACtB,IAAI,IAAA;AACF,MAAA,cAAA,CAAe,KAAK,CAAA;AAAA,KACd,CAAA,MAAA;AACN,MAAW,UAAA,CAAA,QAAA,CAAS,CAAG,EAAA,KAAK,CAA4B,0BAAA,CAAA,CAAA;AAAA;AAC1D,GACD,CAAA;AACH;AAQA,SAAS,iBACP,KACiB,EAAA;AACjB,EAAA,IAAI,OAAO,KAAA,KAAU,QAAY,IAAA,KAAA,CAAM,MAAQ,EAAA;AAC7C,IAAO,OAAA,qBAAA;AAAA;AAET,EAAA,OAAO,OAAO,QAAS,EAAA;AACzB;AAWA,SAAS,4BACP,aACwC,EAAA;AACxC,EAAA,MAAM,QAA2B,EAAC;AAElC,EAAA,KAAA,MAAW,CAAC,GAAK,EAAA,KAAK,KAAK,MAAO,CAAA,OAAA,CAAQ,aAAa,CAAG,EAAA;AACxD,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,KAAK,CAAG,EAAA;AACxB,MAAA,KAAA,CAAM,GAAG,CAAI,GAAA,KAAA;AAAA,KACR,MAAA;AACL,MAAM,KAAA,CAAA,GAAG,CAAI,GAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA;AACrC;AAGF,EAAO,OAAA,KAAA;AACT;AASA,SAAS,mBACP,QAC+B,EAAA;AAC/B,EAAM,MAAA,aAAA,GACJ,QAAS,CAAA,YAAY,CAAG,EAAA,aAAA;AAE1B,EAAA,IAAI,CAAC,aAAe,EAAA;AAClB,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,aAAa,CAAG,EAAA;AAChC,IAAO,OAAA,aAAA,CAAc,IAAI,2BAA2B,CAAA;AAAA;AAGtD,EAAA,OAAO,4BAA4B,aAAa,CAAA;AAClD;;;;"}
|
|
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\n const catalogFilter = buildCatalogFilter(uiSchema);\n const defaultKind = uiSchema['ui:options']?.defaultKind;\n const defaultNamespace =\n uiSchema['ui:options']?.defaultNamespace || undefined;\n const isDisabled = uiSchema?.['ui:disabled'] ?? false;\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 (required && !allowArbitraryValues && entities?.entities?.length === 1) {\n onChange([stringifyEntityRef(entities?.entities[0])]);\n }\n }, [entities, onChange, required, allowArbitraryValues]);\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={\n isDisabled ||\n (required &&\n !allowArbitraryValues &&\n entities?.entities?.length === 1)\n }\n id={idSchema?.$id}\n defaultValue={formData}\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 disabled={isDisabled}\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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"}
|
|
@@ -12,6 +12,7 @@ const BitbucketRepoBranchPicker = ({
|
|
|
12
12
|
state,
|
|
13
13
|
rawErrors,
|
|
14
14
|
accessToken,
|
|
15
|
+
isDisabled,
|
|
15
16
|
required
|
|
16
17
|
}) => {
|
|
17
18
|
const { host, workspace, repository, branch } = state;
|
|
@@ -48,8 +49,17 @@ const BitbucketRepoBranchPicker = ({
|
|
|
48
49
|
onChange: (_, newValue) => {
|
|
49
50
|
onChange({ branch: newValue || "" });
|
|
50
51
|
},
|
|
52
|
+
disabled: isDisabled,
|
|
51
53
|
options: availableBranches,
|
|
52
|
-
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
54
|
+
renderInput: (params) => /* @__PURE__ */ React.createElement(
|
|
55
|
+
TextField,
|
|
56
|
+
{
|
|
57
|
+
...params,
|
|
58
|
+
label: "Branch",
|
|
59
|
+
disabled: isDisabled,
|
|
60
|
+
required
|
|
61
|
+
}
|
|
62
|
+
),
|
|
53
63
|
freeSolo: true,
|
|
54
64
|
autoSelect: true
|
|
55
65
|
}
|