@backstage/plugin-scaffolder 1.20.0 → 1.20.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/alpha/package.json +1 -1
- package/dist/api.esm.js +9 -17
- package/dist/api.esm.js.map +1 -1
- package/dist/components/ActionsPage/ActionsPage.esm.js +10 -13
- package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -1
- package/dist/components/FileBrowser/FileBrowser.esm.js +1 -1
- package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -1
- package/dist/components/ListTasksPage/ListTasksPage.esm.js +9 -17
- package/dist/components/ListTasksPage/ListTasksPage.esm.js.map +1 -1
- package/dist/components/ListTasksPage/columns/OwnerEntityColumn.esm.js +1 -2
- package/dist/components/ListTasksPage/columns/OwnerEntityColumn.esm.js.map +1 -1
- package/dist/components/ListTasksPage/columns/TemplateTitleColumn.esm.js +1 -1
- package/dist/components/ListTasksPage/columns/TemplateTitleColumn.esm.js.map +1 -1
- package/dist/components/OngoingTask/ContextMenu.esm.js +1 -1
- package/dist/components/OngoingTask/ContextMenu.esm.js.map +1 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js +10 -18
- package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -1
- package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js +3 -3
- package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js.map +1 -1
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js +11 -13
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -1
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js +6 -7
- package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js.map +1 -1
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +15 -21
- package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js +7 -11
- package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js.map +1 -1
- package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js +1 -1
- package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js.map +1 -1
- package/dist/components/fields/OwnerPicker/OwnerPicker.esm.js +4 -5
- package/dist/components/fields/OwnerPicker/OwnerPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js +16 -16
- package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js +6 -6
- package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js +2 -2
- package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js +2 -2
- package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js +2 -2
- package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js +2 -2
- package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js +8 -25
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js +6 -6
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js +3 -3
- package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/validation.esm.js +2 -3
- package/dist/components/fields/RepoUrlPicker/validation.esm.js.map +1 -1
- package/dist/components/fields/SecretInput/SecretInput.esm.js +3 -5
- package/dist/components/fields/SecretInput/SecretInput.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js +14 -18
- package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js +55 -91
- package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/DryRunContext.esm.js +5 -9
- package/dist/next/TemplateEditorPage/DryRunContext.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js +1 -2
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js +8 -12
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js +2 -5
- package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js +1 -2
- package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js +4 -13
- package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js +3 -12
- package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js +3 -3
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js +5 -15
- package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +1 -1
- package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js +4 -7
- package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -1
- package/dist/next/TemplateListPage/TemplateListPage.esm.js +5 -7
- package/dist/next/TemplateListPage/TemplateListPage.esm.js.map +1 -1
- package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js +1 -2
- package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepoUrlPicker.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n scmIntegrationsApiRef,\n scmAuthApiRef,\n} from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GiteaRepoPicker } from './GiteaRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { GerritRepoPicker } from './GerritRepoPicker';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerProps } from './schema';\nimport { RepoUrlPickerState } from './types';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport Typography from '@material-ui/core/Typography';\n\nexport { RepoUrlPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `RepoUrlPicker`\n * field extension.\n *\n * @public\n */\nexport const RepoUrlPicker = (props: RepoUrlPickerProps) => {\n const { uiSchema, onChange, rawErrors, formData, schema } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n const scmAuthApi = useApi(scmAuthApiRef);\n const { secrets, setSecrets } = useTemplateSecrets();\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOrganizations = useMemo(\n () => uiSchema?.['ui:options']?.allowedOrganizations ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n const allowedProjects = useMemo(\n () => uiSchema?.['ui:options']?.allowedProjects ?? [],\n [uiSchema],\n );\n const allowedRepos = useMemo(\n () => uiSchema?.['ui:options']?.allowedRepos ?? [],\n [uiSchema],\n );\n\n const { owner, organization, project, repoName } = state;\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOrganizations.length > 0 && !organization) {\n setState(prevState => ({\n ...prevState,\n organization: allowedOrganizations[0],\n }));\n }\n }, [setState, allowedOrganizations, organization]);\n\n useEffect(() => {\n if (allowedOwners.length > 0 && !owner) {\n setState(prevState => ({\n ...prevState,\n owner: allowedOwners[0],\n }));\n }\n }, [setState, allowedOwners, owner]);\n\n useEffect(() => {\n if (allowedProjects.length > 0 && !project) {\n setState(prevState => ({\n ...prevState,\n project: allowedProjects[0],\n }));\n }\n }, [setState, allowedProjects, project]);\n\n useEffect(() => {\n if (allowedRepos.length > 0 && !repoName) {\n setState(prevState => ({ ...prevState, repoName: allowedRepos[0] }));\n }\n }, [setState, allowedRepos, repoName]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n useDebounce(\n async () => {\n const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {};\n\n const workspace = state.owner ? state.owner : state.project;\n if (\n !requestUserCredentials ||\n !(state.host && workspace && state.repoName)\n ) {\n return;\n }\n\n // don't show login prompt if secret value is already in state\n if (secrets[requestUserCredentials.secretsKey]) {\n return;\n }\n\n // previously, we were encodeURI for state.host, workspace and state.repoName separately.\n // That created an issue where GitLab workspace can be nested like groupA/subgroupB\n // when we encodeURi separately and then join, the URL will be malformed and\n // resulting in 400 request error from GitLab API\n const [encodedHost, encodedRepoName] = [state.host, state.repoName].map(\n encodeURIComponent,\n );\n\n // user has requested that we use the users credentials\n // so lets grab them using the scmAuthApi and pass through\n // any additional scopes from the ui:options\n const { token } = await scmAuthApi.getCredentials({\n url: `https://${encodedHost}/${workspace}/${encodedRepoName}`,\n additionalScope: {\n repoWrite: true,\n customScopes: requestUserCredentials.additionalScopes,\n },\n });\n\n // set the secret using the key provided in the ui:options for use\n // in the templating the manifest with ${{ secrets[secretsKey] }}\n setSecrets({ [requestUserCredentials.secretsKey]: token });\n },\n 500,\n [state, uiSchema],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n return (\n <>\n {schema.title && (\n <Box my={1}>\n <Typography variant=\"h5\">{schema.title}</Typography>\n <Divider />\n </Box>\n )}\n {schema.description && (\n <Typography variant=\"body1\">{schema.description}</Typography>\n )}\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n onChange={updateLocalState}\n rawErrors={rawErrors}\n state={state}\n />\n )}\n {hostType === 'gitea' && (\n <GiteaRepoPicker\n allowedOwners={allowedOwners}\n allowedRepos={allowedRepos}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n allowedOwners={allowedOwners}\n allowedProjects={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n allowedOrganizations={allowedOrganizations}\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gerrit' && (\n <GerritRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n <RepoUrlPickerRepoName\n repoName={state.repoName}\n allowedRepos={allowedRepos}\n onChange={repo =>\n setState(prevState => ({ ...prevState, repoName: repo }))\n }\n rawErrors={rawErrors}\n />\n </>\n );\n};\n"],"names":["_a","_b"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RepoUrlPicker.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n scmIntegrationsApiRef,\n scmAuthApiRef,\n} from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GiteaRepoPicker } from './GiteaRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { GerritRepoPicker } from './GerritRepoPicker';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerProps } from './schema';\nimport { RepoUrlPickerState } from './types';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport Box from '@material-ui/core/Box';\nimport Divider from '@material-ui/core/Divider';\nimport Typography from '@material-ui/core/Typography';\n\nexport { RepoUrlPickerSchema } from './schema';\n\n/**\n * The underlying component that is rendered in the form for the `RepoUrlPicker`\n * field extension.\n *\n * @public\n */\nexport const RepoUrlPicker = (props: RepoUrlPickerProps) => {\n const { uiSchema, onChange, rawErrors, formData, schema } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n const scmAuthApi = useApi(scmAuthApiRef);\n const { secrets, setSecrets } = useTemplateSecrets();\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOrganizations = useMemo(\n () => uiSchema?.['ui:options']?.allowedOrganizations ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n const allowedProjects = useMemo(\n () => uiSchema?.['ui:options']?.allowedProjects ?? [],\n [uiSchema],\n );\n const allowedRepos = useMemo(\n () => uiSchema?.['ui:options']?.allowedRepos ?? [],\n [uiSchema],\n );\n\n const { owner, organization, project, repoName } = state;\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOrganizations.length > 0 && !organization) {\n setState(prevState => ({\n ...prevState,\n organization: allowedOrganizations[0],\n }));\n }\n }, [setState, allowedOrganizations, organization]);\n\n useEffect(() => {\n if (allowedOwners.length > 0 && !owner) {\n setState(prevState => ({\n ...prevState,\n owner: allowedOwners[0],\n }));\n }\n }, [setState, allowedOwners, owner]);\n\n useEffect(() => {\n if (allowedProjects.length > 0 && !project) {\n setState(prevState => ({\n ...prevState,\n project: allowedProjects[0],\n }));\n }\n }, [setState, allowedProjects, project]);\n\n useEffect(() => {\n if (allowedRepos.length > 0 && !repoName) {\n setState(prevState => ({ ...prevState, repoName: allowedRepos[0] }));\n }\n }, [setState, allowedRepos, repoName]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n useDebounce(\n async () => {\n const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {};\n\n const workspace = state.owner ? state.owner : state.project;\n if (\n !requestUserCredentials ||\n !(state.host && workspace && state.repoName)\n ) {\n return;\n }\n\n // don't show login prompt if secret value is already in state\n if (secrets[requestUserCredentials.secretsKey]) {\n return;\n }\n\n // previously, we were encodeURI for state.host, workspace and state.repoName separately.\n // That created an issue where GitLab workspace can be nested like groupA/subgroupB\n // when we encodeURi separately and then join, the URL will be malformed and\n // resulting in 400 request error from GitLab API\n const [encodedHost, encodedRepoName] = [state.host, state.repoName].map(\n encodeURIComponent,\n );\n\n // user has requested that we use the users credentials\n // so lets grab them using the scmAuthApi and pass through\n // any additional scopes from the ui:options\n const { token } = await scmAuthApi.getCredentials({\n url: `https://${encodedHost}/${workspace}/${encodedRepoName}`,\n additionalScope: {\n repoWrite: true,\n customScopes: requestUserCredentials.additionalScopes,\n },\n });\n\n // set the secret using the key provided in the ui:options for use\n // in the templating the manifest with ${{ secrets[secretsKey] }}\n setSecrets({ [requestUserCredentials.secretsKey]: token });\n },\n 500,\n [state, uiSchema],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n return (\n <>\n {schema.title && (\n <Box my={1}>\n <Typography variant=\"h5\">{schema.title}</Typography>\n <Divider />\n </Box>\n )}\n {schema.description && (\n <Typography variant=\"body1\">{schema.description}</Typography>\n )}\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n onChange={updateLocalState}\n rawErrors={rawErrors}\n state={state}\n />\n )}\n {hostType === 'gitea' && (\n <GiteaRepoPicker\n allowedOwners={allowedOwners}\n allowedRepos={allowedRepos}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n allowedOwners={allowedOwners}\n allowedProjects={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n allowedOrganizations={allowedOrganizations}\n allowedProject={allowedProjects}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gerrit' && (\n <GerritRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n <RepoUrlPickerRepoName\n repoName={state.repoName}\n allowedRepos={allowedRepos}\n onChange={repo =>\n setState(prevState => ({ ...prevState, repoName: repo }))\n }\n rawErrors={rawErrors}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -12,20 +12,20 @@ const RepoUrlPickerHost = (props) => {
|
|
|
12
12
|
const { value: { integrations } = { integrations: [] }, loading } = useAsync(
|
|
13
13
|
async () => {
|
|
14
14
|
return await scaffolderApi.getIntegrationsList({
|
|
15
|
-
allowedHosts: hosts
|
|
15
|
+
allowedHosts: hosts ?? []
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
);
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
if (!host) {
|
|
21
|
-
if (hosts
|
|
21
|
+
if (hosts?.length) {
|
|
22
22
|
onChange(hosts[0]);
|
|
23
|
-
} else if (integrations
|
|
23
|
+
} else if (integrations?.length) {
|
|
24
24
|
onChange(integrations[0].host);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
}, [hosts, host, onChange, integrations]);
|
|
28
|
-
const hostsOptions = integrations ? integrations.filter((i) =>
|
|
28
|
+
const hostsOptions = integrations ? integrations.filter((i) => hosts?.length ? hosts?.includes(i.host) : true).map((i) => ({ label: i.title, value: i.host })) : [{ label: "Loading...", value: "loading" }];
|
|
29
29
|
if (loading) {
|
|
30
30
|
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
31
31
|
}
|
|
@@ -34,13 +34,13 @@ const RepoUrlPickerHost = (props) => {
|
|
|
34
34
|
{
|
|
35
35
|
margin: "normal",
|
|
36
36
|
required: true,
|
|
37
|
-
error:
|
|
37
|
+
error: rawErrors?.length > 0 && !host
|
|
38
38
|
},
|
|
39
39
|
/* @__PURE__ */ React.createElement(
|
|
40
40
|
Select,
|
|
41
41
|
{
|
|
42
42
|
native: true,
|
|
43
|
-
disabled:
|
|
43
|
+
disabled: hosts?.length === 1,
|
|
44
44
|
label: "Host",
|
|
45
45
|
onChange: (s) => onChange(String(Array.isArray(s) ? s[0] : s)),
|
|
46
46
|
selected: host,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepoUrlPickerHost.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPickerHost.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, { useEffect } from 'react';\nimport { Progress, Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport useAsync from 'react-use/esm/useAsync';\n\nexport const RepoUrlPickerHost = (props: {\n host?: string;\n hosts?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { host, hosts, onChange, rawErrors } = props;\n const scaffolderApi = useApi(scaffolderApiRef);\n\n const { value: { integrations } = { integrations: [] }, loading } = useAsync(\n async () => {\n return await scaffolderApi.getIntegrationsList({\n allowedHosts: hosts ?? [],\n });\n },\n );\n\n useEffect(() => {\n // If there is no host chosen currently\n if (!host) {\n // Set the first of the allowedHosts option if that available\n if (hosts?.length) {\n onChange(hosts[0]);\n // if there's no hosts provided, fallback to using the first integration\n } else if (integrations?.length) {\n onChange(integrations[0].host);\n }\n }\n }, [hosts, host, onChange, integrations]);\n\n // If there are no allowedHosts provided, then show all integrations. Otherwise, only show integrations\n // that are provided in the dropdown for the user to choose from.\n const hostsOptions: SelectItem[] = integrations\n ? integrations\n .filter(i => (hosts?.length ? hosts?.includes(i.host) : true))\n .map(i => ({ label: i.title, value: i.host }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n if (loading) {\n return <Progress />;\n }\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !host}\n >\n <Select\n native\n disabled={hosts?.length === 1}\n label=\"Host\"\n onChange={s => onChange(String(Array.isArray(s) ? s[0] : s))}\n selected={host}\n items={hostsOptions}\n data-testid=\"host-select\"\n />\n\n <FormHelperText>\n The host where the repository will be created\n </FormHelperText>\n </FormControl>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAuBa,MAAA,iBAAA,GAAoB,CAAC,KAK5B,KAAA;AACJ,EAAA,MAAM,EAAE,IAAA,EAAM,KAAO,EAAA,QAAA,EAAU,WAAc,GAAA,KAAA,CAAA;AAC7C,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA,CAAA;AAE7C,EAAM,MAAA,EAAE,KAAO,EAAA,EAAE,YAAa,EAAA,GAAI,EAAE,YAAA,EAAc,EAAC,EAAK,EAAA,OAAA,EAAY,GAAA,QAAA;AAAA,IAClE,YAAY;AACV,MAAO,OAAA,MAAM,cAAc,mBAAoB,CAAA;AAAA,QAC7C,YAAA,EAAc,
|
|
1
|
+
{"version":3,"file":"RepoUrlPickerHost.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPickerHost.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, { useEffect } from 'react';\nimport { Progress, Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport useAsync from 'react-use/esm/useAsync';\n\nexport const RepoUrlPickerHost = (props: {\n host?: string;\n hosts?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { host, hosts, onChange, rawErrors } = props;\n const scaffolderApi = useApi(scaffolderApiRef);\n\n const { value: { integrations } = { integrations: [] }, loading } = useAsync(\n async () => {\n return await scaffolderApi.getIntegrationsList({\n allowedHosts: hosts ?? [],\n });\n },\n );\n\n useEffect(() => {\n // If there is no host chosen currently\n if (!host) {\n // Set the first of the allowedHosts option if that available\n if (hosts?.length) {\n onChange(hosts[0]);\n // if there's no hosts provided, fallback to using the first integration\n } else if (integrations?.length) {\n onChange(integrations[0].host);\n }\n }\n }, [hosts, host, onChange, integrations]);\n\n // If there are no allowedHosts provided, then show all integrations. Otherwise, only show integrations\n // that are provided in the dropdown for the user to choose from.\n const hostsOptions: SelectItem[] = integrations\n ? integrations\n .filter(i => (hosts?.length ? hosts?.includes(i.host) : true))\n .map(i => ({ label: i.title, value: i.host }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n if (loading) {\n return <Progress />;\n }\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !host}\n >\n <Select\n native\n disabled={hosts?.length === 1}\n label=\"Host\"\n onChange={s => onChange(String(Array.isArray(s) ? s[0] : s))}\n selected={host}\n items={hostsOptions}\n data-testid=\"host-select\"\n />\n\n <FormHelperText>\n The host where the repository will be created\n </FormHelperText>\n </FormControl>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAuBa,MAAA,iBAAA,GAAoB,CAAC,KAK5B,KAAA;AACJ,EAAA,MAAM,EAAE,IAAA,EAAM,KAAO,EAAA,QAAA,EAAU,WAAc,GAAA,KAAA,CAAA;AAC7C,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA,CAAA;AAE7C,EAAM,MAAA,EAAE,KAAO,EAAA,EAAE,YAAa,EAAA,GAAI,EAAE,YAAA,EAAc,EAAC,EAAK,EAAA,OAAA,EAAY,GAAA,QAAA;AAAA,IAClE,YAAY;AACV,MAAO,OAAA,MAAM,cAAc,mBAAoB,CAAA;AAAA,QAC7C,YAAA,EAAc,SAAS,EAAC;AAAA,OACzB,CAAA,CAAA;AAAA,KACH;AAAA,GACF,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,CAAC,IAAM,EAAA;AAET,MAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,QAAS,QAAA,CAAA,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAAA,OAEnB,MAAA,IAAW,cAAc,MAAQ,EAAA;AAC/B,QAAS,QAAA,CAAA,YAAA,CAAa,CAAC,CAAA,CAAE,IAAI,CAAA,CAAA;AAAA,OAC/B;AAAA,KACF;AAAA,KACC,CAAC,KAAA,EAAO,IAAM,EAAA,QAAA,EAAU,YAAY,CAAC,CAAA,CAAA;AAIxC,EAAA,MAAM,YAA6B,GAAA,YAAA,GAC/B,YACG,CAAA,MAAA,CAAO,CAAM,CAAA,KAAA,KAAA,EAAO,MAAS,GAAA,KAAA,EAAO,QAAS,CAAA,CAAA,CAAE,IAAI,CAAA,GAAI,IAAK,CAC5D,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA,EAAE,KAAO,EAAA,CAAA,CAAE,KAAO,EAAA,KAAA,EAAO,EAAE,IAAK,EAAA,CAAE,CAC/C,GAAA,CAAC,EAAE,KAAA,EAAO,YAAc,EAAA,KAAA,EAAO,WAAW,CAAA,CAAA;AAE9C,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA,CAAA;AAAA,GACnB;AAEA,EAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,QAAA;AAAA,MACP,QAAQ,EAAA,IAAA;AAAA,MACR,KAAO,EAAA,SAAA,EAAW,MAAS,GAAA,CAAA,IAAK,CAAC,IAAA;AAAA,KAAA;AAAA,oBAEjC,KAAA,CAAA,aAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,MAAM,EAAA,IAAA;AAAA,QACN,QAAA,EAAU,OAAO,MAAW,KAAA,CAAA;AAAA,QAC5B,KAAM,EAAA,MAAA;AAAA,QACN,QAAU,EAAA,CAAA,CAAA,KAAK,QAAS,CAAA,MAAA,CAAO,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAE,CAAA,CAAC,CAAI,GAAA,CAAC,CAAC,CAAA;AAAA,QAC3D,QAAU,EAAA,IAAA;AAAA,QACV,KAAO,EAAA,YAAA;AAAA,QACP,aAAY,EAAA,aAAA;AAAA,OAAA;AAAA,KACd;AAAA,oBAEA,KAAA,CAAA,aAAA,CAAC,sBAAe,+CAEhB,CAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -9,7 +9,7 @@ const RepoUrlPickerRepoName = (props) => {
|
|
|
9
9
|
const { repoName, allowedRepos, onChange, rawErrors } = props;
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
if (!repoName) {
|
|
12
|
-
if (allowedRepos
|
|
12
|
+
if (allowedRepos?.length) {
|
|
13
13
|
onChange(allowedRepos[0]);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -20,9 +20,9 @@ const RepoUrlPickerRepoName = (props) => {
|
|
|
20
20
|
{
|
|
21
21
|
margin: "normal",
|
|
22
22
|
required: true,
|
|
23
|
-
error:
|
|
23
|
+
error: rawErrors?.length > 0 && !repoName
|
|
24
24
|
},
|
|
25
|
-
|
|
25
|
+
allowedRepos?.length ? /* @__PURE__ */ React.createElement(
|
|
26
26
|
Select,
|
|
27
27
|
{
|
|
28
28
|
native: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepoUrlPickerRepoName.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.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, { useEffect } from 'react';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\n\nexport const RepoUrlPickerRepoName = (props: {\n repoName?: string;\n allowedRepos?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { repoName, allowedRepos, onChange, rawErrors } = props;\n\n useEffect(() => {\n // If there is no repoName chosen currently\n if (!repoName) {\n // Set the first of the allowedRepos option if that available\n if (allowedRepos?.length) {\n onChange(allowedRepos[0]);\n }\n }\n }, [allowedRepos, repoName, onChange]);\n\n const repoItems: SelectItem[] = allowedRepos\n ? allowedRepos.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n {allowedRepos?.length ? (\n <Select\n native\n label=\"Repositories Available\"\n onChange={selected =>\n onChange(String(Array.isArray(selected) ? selected[0] : selected))\n }\n disabled={allowedRepos.length === 1}\n selected={repoName}\n items={repoItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange(String(e.target.value))}\n value={repoName}\n />\n </>\n )}\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBa,MAAA,qBAAA,GAAwB,CAAC,KAKhC,KAAA;AACJ,EAAA,MAAM,EAAE,QAAA,EAAU,YAAc,EAAA,QAAA,EAAU,WAAc,GAAA,KAAA,CAAA;AAExD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,CAAC,QAAU,EAAA;AAEb,MAAA,IAAI,
|
|
1
|
+
{"version":3,"file":"RepoUrlPickerRepoName.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.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, { useEffect } from 'react';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\n\nexport const RepoUrlPickerRepoName = (props: {\n repoName?: string;\n allowedRepos?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { repoName, allowedRepos, onChange, rawErrors } = props;\n\n useEffect(() => {\n // If there is no repoName chosen currently\n if (!repoName) {\n // Set the first of the allowedRepos option if that available\n if (allowedRepos?.length) {\n onChange(allowedRepos[0]);\n }\n }\n }, [allowedRepos, repoName, onChange]);\n\n const repoItems: SelectItem[] = allowedRepos\n ? allowedRepos.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n {allowedRepos?.length ? (\n <Select\n native\n label=\"Repositories Available\"\n onChange={selected =>\n onChange(String(Array.isArray(selected) ? selected[0] : selected))\n }\n disabled={allowedRepos.length === 1}\n selected={repoName}\n items={repoItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange(String(e.target.value))}\n value={repoName}\n />\n </>\n )}\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBa,MAAA,qBAAA,GAAwB,CAAC,KAKhC,KAAA;AACJ,EAAA,MAAM,EAAE,QAAA,EAAU,YAAc,EAAA,QAAA,EAAU,WAAc,GAAA,KAAA,CAAA;AAExD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,CAAC,QAAU,EAAA;AAEb,MAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,QAAS,QAAA,CAAA,YAAA,CAAa,CAAC,CAAC,CAAA,CAAA;AAAA,OAC1B;AAAA,KACF;AAAA,GACC,EAAA,CAAC,YAAc,EAAA,QAAA,EAAU,QAAQ,CAAC,CAAA,CAAA;AAErC,EAAA,MAAM,YAA0B,YAC5B,GAAA,YAAA,CAAa,IAAI,CAAM,CAAA,MAAA,EAAE,OAAO,CAAG,EAAA,KAAA,EAAO,CAAE,EAAA,CAAE,IAC9C,CAAC,EAAE,OAAO,YAAc,EAAA,KAAA,EAAO,WAAW,CAAA,CAAA;AAE9C,EAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,MAAO,EAAA,QAAA;AAAA,MACP,QAAQ,EAAA,IAAA;AAAA,MACR,KAAO,EAAA,SAAA,EAAW,MAAS,GAAA,CAAA,IAAK,CAAC,QAAA;AAAA,KAAA;AAAA,IAEhC,cAAc,MACb,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,MAAM,EAAA,IAAA;AAAA,QACN,KAAM,EAAA,wBAAA;AAAA,QACN,QAAU,EAAA,CAAA,QAAA,KACR,QAAS,CAAA,MAAA,CAAO,KAAM,CAAA,OAAA,CAAQ,QAAQ,CAAA,GAAI,QAAS,CAAA,CAAC,CAAI,GAAA,QAAQ,CAAC,CAAA;AAAA,QAEnE,QAAA,EAAU,aAAa,MAAW,KAAA,CAAA;AAAA,QAClC,QAAU,EAAA,QAAA;AAAA,QACV,KAAO,EAAA,SAAA;AAAA,OAAA;AAAA,wBAIP,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,OAAQ,EAAA,eAAA,EAAA,EAAgB,YAAU,CAC9C,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,EAAG,EAAA,eAAA;AAAA,QACH,UAAU,CAAK,CAAA,KAAA,QAAA,CAAS,OAAO,CAAE,CAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QAC9C,KAAO,EAAA,QAAA;AAAA,OAAA;AAAA,KAEX,CAAA;AAAA,oBAEF,KAAA,CAAA,aAAA,CAAC,sBAAe,4BAA0B,CAAA;AAAA,GAE9C,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
|
2
2
|
|
|
3
3
|
const repoPickerValidation = (value, validation, context) => {
|
|
4
|
-
var _a, _b;
|
|
5
4
|
try {
|
|
6
5
|
const { host, searchParams } = new URL(`https://${value}`);
|
|
7
6
|
const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);
|
|
@@ -10,7 +9,7 @@ const repoPickerValidation = (value, validation, context) => {
|
|
|
10
9
|
"Incomplete repository location provided, host not provided"
|
|
11
10
|
);
|
|
12
11
|
} else {
|
|
13
|
-
if (
|
|
12
|
+
if (integrationApi?.byHost(host)?.type === "bitbucket") {
|
|
14
13
|
if (host === "bitbucket.org" && !searchParams.get("workspace")) {
|
|
15
14
|
validation.addError(
|
|
16
15
|
"Incomplete repository location provided, workspace not provided"
|
|
@@ -21,7 +20,7 @@ const repoPickerValidation = (value, validation, context) => {
|
|
|
21
20
|
"Incomplete repository location provided, project not provided"
|
|
22
21
|
);
|
|
23
22
|
}
|
|
24
|
-
} else if (
|
|
23
|
+
} else if (integrationApi?.byHost(host)?.type !== "gerrit") {
|
|
25
24
|
if (!searchParams.get("owner")) {
|
|
26
25
|
validation.addError(
|
|
27
26
|
"Incomplete repository location provided, owner not provided"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/validation.ts"],"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 */\n\nimport { FieldValidation } from '@rjsf/utils';\nimport { ApiHolder } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\n/**\n * The validation function for the `repoUrl` that is returned from the\n * field extension. Ensures that you have all the required fields filled for\n * the different providers that exist.\n *\n * @public\n */\nexport const repoPickerValidation = (\n value: string,\n validation: FieldValidation,\n context: { apiHolder: ApiHolder },\n) => {\n try {\n const { host, searchParams } = new URL(`https://${value}`);\n\n const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);\n\n if (!host) {\n validation.addError(\n 'Incomplete repository location provided, host not provided',\n );\n } else {\n if (integrationApi?.byHost(host)?.type === 'bitbucket') {\n // workspace is only applicable for bitbucket cloud\n if (host === 'bitbucket.org' && !searchParams.get('workspace')) {\n validation.addError(\n 'Incomplete repository location provided, workspace not provided',\n );\n }\n\n if (!searchParams.get('project')) {\n validation.addError(\n 'Incomplete repository location provided, project not provided',\n );\n }\n }\n // For anything other than bitbucket and gerrit\n else if (integrationApi?.byHost(host)?.type !== 'gerrit') {\n if (!searchParams.get('owner')) {\n validation.addError(\n 'Incomplete repository location provided, owner not provided',\n );\n }\n }\n\n // Do this for all hosts\n if (!searchParams.get('repo')) {\n validation.addError(\n 'Incomplete repository location provided, repo not provided',\n );\n }\n }\n } catch {\n validation.addError('Unable to parse the Repository URL');\n }\n};\n"],"names":[],"mappings":";;AA2BO,MAAM,oBAAuB,GAAA,CAClC,KACA,EAAA,UAAA,EACA,OACG,KAAA;
|
|
1
|
+
{"version":3,"file":"validation.esm.js","sources":["../../../../src/components/fields/RepoUrlPicker/validation.ts"],"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 */\n\nimport { FieldValidation } from '@rjsf/utils';\nimport { ApiHolder } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\n/**\n * The validation function for the `repoUrl` that is returned from the\n * field extension. Ensures that you have all the required fields filled for\n * the different providers that exist.\n *\n * @public\n */\nexport const repoPickerValidation = (\n value: string,\n validation: FieldValidation,\n context: { apiHolder: ApiHolder },\n) => {\n try {\n const { host, searchParams } = new URL(`https://${value}`);\n\n const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);\n\n if (!host) {\n validation.addError(\n 'Incomplete repository location provided, host not provided',\n );\n } else {\n if (integrationApi?.byHost(host)?.type === 'bitbucket') {\n // workspace is only applicable for bitbucket cloud\n if (host === 'bitbucket.org' && !searchParams.get('workspace')) {\n validation.addError(\n 'Incomplete repository location provided, workspace not provided',\n );\n }\n\n if (!searchParams.get('project')) {\n validation.addError(\n 'Incomplete repository location provided, project not provided',\n );\n }\n }\n // For anything other than bitbucket and gerrit\n else if (integrationApi?.byHost(host)?.type !== 'gerrit') {\n if (!searchParams.get('owner')) {\n validation.addError(\n 'Incomplete repository location provided, owner not provided',\n );\n }\n }\n\n // Do this for all hosts\n if (!searchParams.get('repo')) {\n validation.addError(\n 'Incomplete repository location provided, repo not provided',\n );\n }\n }\n } catch {\n validation.addError('Unable to parse the Repository URL');\n }\n};\n"],"names":[],"mappings":";;AA2BO,MAAM,oBAAuB,GAAA,CAClC,KACA,EAAA,UAAA,EACA,OACG,KAAA;AACH,EAAI,IAAA;AACF,IAAM,MAAA,EAAE,MAAM,YAAa,EAAA,GAAI,IAAI,GAAI,CAAA,CAAA,QAAA,EAAW,KAAK,CAAE,CAAA,CAAA,CAAA;AAEzD,IAAA,MAAM,cAAiB,GAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,qBAAqB,CAAA,CAAA;AAElE,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAW,UAAA,CAAA,QAAA;AAAA,QACT,4DAAA;AAAA,OACF,CAAA;AAAA,KACK,MAAA;AACL,MAAA,IAAI,cAAgB,EAAA,MAAA,CAAO,IAAI,CAAA,EAAG,SAAS,WAAa,EAAA;AAEtD,QAAA,IAAI,SAAS,eAAmB,IAAA,CAAC,YAAa,CAAA,GAAA,CAAI,WAAW,CAAG,EAAA;AAC9D,UAAW,UAAA,CAAA,QAAA;AAAA,YACT,iEAAA;AAAA,WACF,CAAA;AAAA,SACF;AAEA,QAAA,IAAI,CAAC,YAAA,CAAa,GAAI,CAAA,SAAS,CAAG,EAAA;AAChC,UAAW,UAAA,CAAA,QAAA;AAAA,YACT,+DAAA;AAAA,WACF,CAAA;AAAA,SACF;AAAA,iBAGO,cAAgB,EAAA,MAAA,CAAO,IAAI,CAAA,EAAG,SAAS,QAAU,EAAA;AACxD,QAAA,IAAI,CAAC,YAAA,CAAa,GAAI,CAAA,OAAO,CAAG,EAAA;AAC9B,UAAW,UAAA,CAAA,QAAA;AAAA,YACT,6DAAA;AAAA,WACF,CAAA;AAAA,SACF;AAAA,OACF;AAGA,MAAA,IAAI,CAAC,YAAA,CAAa,GAAI,CAAA,MAAM,CAAG,EAAA;AAC7B,QAAW,UAAA,CAAA,QAAA;AAAA,UACT,4DAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,KACF;AAAA,GACM,CAAA,MAAA;AACN,IAAA,UAAA,CAAW,SAAS,oCAAoC,CAAA,CAAA;AAAA,GAC1D;AACF;;;;"}
|
|
@@ -5,7 +5,6 @@ import Input from '@material-ui/core/Input';
|
|
|
5
5
|
import InputLabel from '@material-ui/core/InputLabel';
|
|
6
6
|
|
|
7
7
|
const SecretInput = (props) => {
|
|
8
|
-
var _a;
|
|
9
8
|
const { setSecrets, secrets } = useTemplateSecrets();
|
|
10
9
|
const {
|
|
11
10
|
name,
|
|
@@ -32,11 +31,10 @@ const SecretInput = (props) => {
|
|
|
32
31
|
id: title,
|
|
33
32
|
"aria-describedby": title,
|
|
34
33
|
onChange: (e) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
setSecrets({ [name]: (_b = e.target) == null ? void 0 : _b.value });
|
|
34
|
+
onChange(Array(e.target?.value.length).fill("*").join(""));
|
|
35
|
+
setSecrets({ [name]: e.target?.value });
|
|
38
36
|
},
|
|
39
|
-
value:
|
|
37
|
+
value: secrets[name] ?? "",
|
|
40
38
|
type: "password",
|
|
41
39
|
autoComplete: "off"
|
|
42
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecretInput.esm.js","sources":["../../../../src/components/fields/SecretInput/SecretInput.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 */\nimport React from 'react';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderRJSFFieldProps } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\n\nexport const SecretInput = (props: ScaffolderRJSFFieldProps) => {\n const { setSecrets, secrets } = useTemplateSecrets();\n const {\n name,\n onChange,\n schema: { title, description },\n rawErrors,\n disabled,\n errors,\n required,\n } = props;\n\n return (\n <ScaffolderField\n rawErrors={rawErrors}\n rawDescription={description}\n disabled={disabled}\n errors={errors}\n required={required}\n >\n <InputLabel htmlFor={title}>{title}</InputLabel>\n <Input\n id={title}\n aria-describedby={title}\n onChange={e => {\n onChange(Array(e.target?.value.length).fill('*').join(''));\n setSecrets({ [name]: e.target?.value });\n }}\n value={secrets[name] ?? ''}\n type=\"password\"\n autoComplete=\"off\"\n />\n </ScaffolderField>\n );\n};\n"],"names":[
|
|
1
|
+
{"version":3,"file":"SecretInput.esm.js","sources":["../../../../src/components/fields/SecretInput/SecretInput.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 */\nimport React from 'react';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderRJSFFieldProps } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\n\nexport const SecretInput = (props: ScaffolderRJSFFieldProps) => {\n const { setSecrets, secrets } = useTemplateSecrets();\n const {\n name,\n onChange,\n schema: { title, description },\n rawErrors,\n disabled,\n errors,\n required,\n } = props;\n\n return (\n <ScaffolderField\n rawErrors={rawErrors}\n rawDescription={description}\n disabled={disabled}\n errors={errors}\n required={required}\n >\n <InputLabel htmlFor={title}>{title}</InputLabel>\n <Input\n id={title}\n aria-describedby={title}\n onChange={e => {\n onChange(Array(e.target?.value.length).fill('*').join(''));\n setSecrets({ [name]: e.target?.value });\n }}\n value={secrets[name] ?? ''}\n type=\"password\"\n autoComplete=\"off\"\n />\n </ScaffolderField>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsBa,MAAA,WAAA,GAAc,CAAC,KAAoC,KAAA;AAC9D,EAAA,MAAM,EAAE,UAAA,EAAY,OAAQ,EAAA,GAAI,kBAAmB,EAAA,CAAA;AACnD,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,EAAQ,EAAE,KAAA,EAAO,WAAY,EAAA;AAAA,IAC7B,SAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,GACE,GAAA,KAAA,CAAA;AAEJ,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,cAAgB,EAAA,WAAA;AAAA,MAChB,QAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,KAAA;AAAA,oBAEC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAS,EAAA,KAAA,EAAA,EAAQ,KAAM,CAAA;AAAA,oBACnC,KAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,EAAI,EAAA,KAAA;AAAA,QACJ,kBAAkB,EAAA,KAAA;AAAA,QAClB,UAAU,CAAK,CAAA,KAAA;AACb,UAAS,QAAA,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,EAAQ,KAAM,CAAA,MAAM,CAAE,CAAA,IAAA,CAAK,GAAG,CAAA,CAAE,IAAK,CAAA,EAAE,CAAC,CAAA,CAAA;AACzD,UAAA,UAAA,CAAW,EAAE,CAAC,IAAI,GAAG,CAAE,CAAA,MAAA,EAAQ,OAAO,CAAA,CAAA;AAAA,SACxC;AAAA,QACA,KAAA,EAAO,OAAQ,CAAA,IAAI,CAAK,IAAA,EAAA;AAAA,QACxB,IAAK,EAAA,UAAA;AAAA,QACL,YAAa,EAAA,KAAA;AAAA,OAAA;AAAA,KACf;AAAA,GACF,CAAA;AAEJ;;;;"}
|
|
@@ -47,30 +47,26 @@ const CustomFieldExplorer = ({
|
|
|
47
47
|
customFieldExtensions = [],
|
|
48
48
|
onClose
|
|
49
49
|
}) => {
|
|
50
|
-
var _a, _b;
|
|
51
50
|
const classes = useStyles();
|
|
52
51
|
const fieldOptions = customFieldExtensions.filter((field) => !!field.schema);
|
|
53
52
|
const [selectedField, setSelectedField] = useState(fieldOptions[0]);
|
|
54
53
|
const [fieldFormState, setFieldFormState] = useState({});
|
|
55
54
|
const [refreshKey, setRefreshKey] = useState(Date.now());
|
|
56
55
|
const sampleFieldTemplate = useMemo(
|
|
57
|
-
() => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"ui:field": selectedField.name,
|
|
67
|
-
"ui:options": fieldFormState
|
|
68
|
-
}
|
|
56
|
+
() => yaml.stringify({
|
|
57
|
+
parameters: [
|
|
58
|
+
{
|
|
59
|
+
title: `${selectedField.name} Example`,
|
|
60
|
+
properties: {
|
|
61
|
+
[selectedField.name]: {
|
|
62
|
+
type: selectedField.schema?.returnValue?.type,
|
|
63
|
+
"ui:field": selectedField.name,
|
|
64
|
+
"ui:options": fieldFormState
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}),
|
|
74
70
|
[fieldFormState, selectedField]
|
|
75
71
|
);
|
|
76
72
|
const fieldComponents = useMemo(() => {
|
|
@@ -111,7 +107,7 @@ const CustomFieldExplorer = ({
|
|
|
111
107
|
formContext: { fieldFormState },
|
|
112
108
|
onSubmit: (e) => handleFieldConfigChange(e.formData),
|
|
113
109
|
validator,
|
|
114
|
-
schema:
|
|
110
|
+
schema: selectedField.schema?.uiOptions || {},
|
|
115
111
|
experimental_defaultFormStateBehavior: {
|
|
116
112
|
allOf: "populateDefaults"
|
|
117
113
|
}
|
|
@@ -122,7 +118,7 @@ const CustomFieldExplorer = ({
|
|
|
122
118
|
variant: "contained",
|
|
123
119
|
color: "primary",
|
|
124
120
|
type: "submit",
|
|
125
|
-
disabled: !
|
|
121
|
+
disabled: !selectedField.schema?.uiOptions
|
|
126
122
|
},
|
|
127
123
|
"Apply"
|
|
128
124
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomFieldExplorer.esm.js","sources":["../../../src/next/TemplateEditorPage/CustomFieldExplorer.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport Button from '@material-ui/core/Button';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport FormControl from '@material-ui/core/FormControl';\nimport IconButton from '@material-ui/core/IconButton';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CloseIcon from '@material-ui/icons/Close';\nimport CodeMirror from '@uiw/react-codemirror';\nimport React, { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport validator from '@rjsf/validator-ajv8';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateAreas: `\n \"controls controls\"\n \"fieldForm preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n controls: {\n gridArea: 'controls',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n margin: theme.spacing(1),\n },\n fieldForm: {\n gridArea: 'fieldForm',\n },\n preview: {\n gridArea: 'preview',\n },\n}));\n\nexport const CustomFieldExplorer = ({\n customFieldExtensions = [],\n onClose,\n}: {\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n onClose?: () => void;\n}) => {\n const classes = useStyles();\n const fieldOptions = customFieldExtensions.filter(field => !!field.schema);\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const [fieldFormState, setFieldFormState] = useState({});\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const sampleFieldTemplate = useMemo(\n () =>\n yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n }),\n [fieldFormState, selectedField],\n );\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [customFieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <FormControl variant=\"outlined\" size=\"small\" fullWidth>\n <InputLabel id=\"select-field-label\">\n Choose Custom Field Extension\n </InputLabel>\n <Select\n value={selectedField}\n label=\"Choose Custom Field Extension\"\n labelId=\"select-field-label\"\n onChange={e =>\n handleSelectionChange(e.target.value as FieldExtensionOptions)\n }\n >\n {fieldOptions.map((option, idx) => (\n <MenuItem key={idx} value={option as any}>\n {option.name}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n\n <IconButton size=\"medium\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </IconButton>\n </div>\n <div className={classes.fieldForm}>\n <Card>\n <CardHeader title=\"Field Options\" />\n <CardContent>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField.schema?.uiOptions}\n >\n Apply\n </Button>\n </Form>\n </CardContent>\n </Card>\n </div>\n <div className={classes.preview}>\n <Card>\n <CardHeader title=\"Example Template Spec\" />\n <CardContent>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </CardContent>\n </Card>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={() => null}\n />\n </div>\n </main>\n );\n};\n"],"names":["_a","_b","yamlSupport"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CustomFieldExplorer.esm.js","sources":["../../../src/next/TemplateEditorPage/CustomFieldExplorer.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport Button from '@material-ui/core/Button';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport FormControl from '@material-ui/core/FormControl';\nimport IconButton from '@material-ui/core/IconButton';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CloseIcon from '@material-ui/icons/Close';\nimport CodeMirror from '@uiw/react-codemirror';\nimport React, { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport validator from '@rjsf/validator-ajv8';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateAreas: `\n \"controls controls\"\n \"fieldForm preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n controls: {\n gridArea: 'controls',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n margin: theme.spacing(1),\n },\n fieldForm: {\n gridArea: 'fieldForm',\n },\n preview: {\n gridArea: 'preview',\n },\n}));\n\nexport const CustomFieldExplorer = ({\n customFieldExtensions = [],\n onClose,\n}: {\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n onClose?: () => void;\n}) => {\n const classes = useStyles();\n const fieldOptions = customFieldExtensions.filter(field => !!field.schema);\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const [fieldFormState, setFieldFormState] = useState({});\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const sampleFieldTemplate = useMemo(\n () =>\n yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n }),\n [fieldFormState, selectedField],\n );\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [customFieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <FormControl variant=\"outlined\" size=\"small\" fullWidth>\n <InputLabel id=\"select-field-label\">\n Choose Custom Field Extension\n </InputLabel>\n <Select\n value={selectedField}\n label=\"Choose Custom Field Extension\"\n labelId=\"select-field-label\"\n onChange={e =>\n handleSelectionChange(e.target.value as FieldExtensionOptions)\n }\n >\n {fieldOptions.map((option, idx) => (\n <MenuItem key={idx} value={option as any}>\n {option.name}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n\n <IconButton size=\"medium\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </IconButton>\n </div>\n <div className={classes.fieldForm}>\n <Card>\n <CardHeader title=\"Field Options\" />\n <CardContent>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField.schema?.uiOptions}\n >\n Apply\n </Button>\n </Form>\n </CardContent>\n </Card>\n </div>\n <div className={classes.preview}>\n <Card>\n <CardHeader title=\"Example Template Spec\" />\n <CardContent>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </CardContent>\n </Card>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={() => null}\n />\n </div>\n </main>\n );\n};\n"],"names":["yamlSupport"],"mappings":"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"}
|
|
@@ -2,157 +2,121 @@ import { ErrorPanel, Progress } from '@backstage/core-components';
|
|
|
2
2
|
import { useAsync, useRerender } from '@react-hookz/web';
|
|
3
3
|
import React, { createContext, useEffect, useContext } from 'react';
|
|
4
4
|
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
-
var __publicField = (obj, key, value) => {
|
|
8
|
-
__defNormalProp(obj, key + "" , value);
|
|
9
|
-
return value;
|
|
10
|
-
};
|
|
11
|
-
var __accessCheck = (obj, member, msg) => {
|
|
12
|
-
if (!member.has(obj))
|
|
13
|
-
throw TypeError("Cannot " + msg);
|
|
14
|
-
};
|
|
15
|
-
var __privateGet = (obj, member, getter) => {
|
|
16
|
-
__accessCheck(obj, member, "read from private field");
|
|
17
|
-
return member.get(obj);
|
|
18
|
-
};
|
|
19
|
-
var __privateAdd = (obj, member, value) => {
|
|
20
|
-
if (member.has(obj))
|
|
21
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
22
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
23
|
-
};
|
|
24
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
25
|
-
__accessCheck(obj, member, "write to private field");
|
|
26
|
-
member.set(obj, value);
|
|
27
|
-
return value;
|
|
28
|
-
};
|
|
29
|
-
var _access, _signalUpdate, _content, _savedContent, _access2, _listeners, _files, _selectedFile, _signalUpdate2;
|
|
30
5
|
const MAX_SIZE = 1024 * 1024;
|
|
31
6
|
const MAX_SIZE_MESSAGE = "This file is too large to be displayed";
|
|
32
7
|
class DirectoryEditorFileManager {
|
|
8
|
+
#access;
|
|
9
|
+
#signalUpdate;
|
|
10
|
+
#content;
|
|
11
|
+
#savedContent;
|
|
33
12
|
constructor(access, signalUpdate) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
__privateAdd(this, _content, void 0);
|
|
37
|
-
__privateAdd(this, _savedContent, void 0);
|
|
38
|
-
__privateSet(this, _access, access);
|
|
39
|
-
__privateSet(this, _signalUpdate, signalUpdate);
|
|
13
|
+
this.#access = access;
|
|
14
|
+
this.#signalUpdate = signalUpdate;
|
|
40
15
|
}
|
|
41
16
|
get path() {
|
|
42
|
-
return
|
|
17
|
+
return this.#access.path;
|
|
43
18
|
}
|
|
44
19
|
get content() {
|
|
45
|
-
|
|
46
|
-
return (_a = __privateGet(this, _content)) != null ? _a : MAX_SIZE_MESSAGE;
|
|
20
|
+
return this.#content ?? MAX_SIZE_MESSAGE;
|
|
47
21
|
}
|
|
48
22
|
updateContent(content) {
|
|
49
|
-
if (
|
|
23
|
+
if (this.#content === void 0) {
|
|
50
24
|
return;
|
|
51
25
|
}
|
|
52
|
-
|
|
53
|
-
|
|
26
|
+
this.#content = content;
|
|
27
|
+
this.#signalUpdate();
|
|
54
28
|
}
|
|
55
29
|
get dirty() {
|
|
56
|
-
return
|
|
30
|
+
return this.#content !== this.#savedContent;
|
|
57
31
|
}
|
|
58
32
|
async save() {
|
|
59
|
-
if (
|
|
60
|
-
await
|
|
61
|
-
|
|
62
|
-
|
|
33
|
+
if (this.#content !== void 0) {
|
|
34
|
+
await this.#access.save(this.#content);
|
|
35
|
+
this.#savedContent = this.#content;
|
|
36
|
+
this.#signalUpdate();
|
|
63
37
|
}
|
|
64
38
|
}
|
|
65
39
|
async reload() {
|
|
66
|
-
const file = await
|
|
40
|
+
const file = await this.#access.file();
|
|
67
41
|
if (file.size > MAX_SIZE) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
42
|
+
if (this.#content !== void 0) {
|
|
43
|
+
this.#content = void 0;
|
|
44
|
+
this.#savedContent = void 0;
|
|
45
|
+
this.#signalUpdate();
|
|
72
46
|
}
|
|
73
47
|
return;
|
|
74
48
|
}
|
|
75
49
|
const content = await file.text();
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
50
|
+
if (this.#content !== content) {
|
|
51
|
+
this.#content = content;
|
|
52
|
+
this.#savedContent = content;
|
|
53
|
+
this.#signalUpdate();
|
|
80
54
|
}
|
|
81
55
|
}
|
|
82
56
|
}
|
|
83
|
-
_access = new WeakMap();
|
|
84
|
-
_signalUpdate = new WeakMap();
|
|
85
|
-
_content = new WeakMap();
|
|
86
|
-
_savedContent = new WeakMap();
|
|
87
57
|
class DirectoryEditorManager {
|
|
58
|
+
#access;
|
|
59
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
60
|
+
#files = [];
|
|
61
|
+
#selectedFile;
|
|
88
62
|
constructor(access) {
|
|
89
|
-
|
|
90
|
-
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
91
|
-
__privateAdd(this, _files, []);
|
|
92
|
-
__privateAdd(this, _selectedFile, void 0);
|
|
93
|
-
__publicField(this, "setSelectedFile", (path) => {
|
|
94
|
-
const prev = __privateGet(this, _selectedFile);
|
|
95
|
-
const next = __privateGet(this, _files).find((file) => file.path === path);
|
|
96
|
-
if (prev !== next) {
|
|
97
|
-
__privateSet(this, _selectedFile, next);
|
|
98
|
-
__privateGet(this, _signalUpdate2).call(this);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
__privateAdd(this, _signalUpdate2, () => {
|
|
102
|
-
__privateGet(this, _listeners).forEach((listener) => listener());
|
|
103
|
-
});
|
|
104
|
-
__privateSet(this, _access2, access);
|
|
63
|
+
this.#access = access;
|
|
105
64
|
}
|
|
106
65
|
get files() {
|
|
107
|
-
return
|
|
66
|
+
return this.#files;
|
|
108
67
|
}
|
|
109
68
|
get selectedFile() {
|
|
110
|
-
return
|
|
111
|
-
}
|
|
69
|
+
return this.#selectedFile;
|
|
70
|
+
}
|
|
71
|
+
setSelectedFile = (path) => {
|
|
72
|
+
const prev = this.#selectedFile;
|
|
73
|
+
const next = this.#files.find((file) => file.path === path);
|
|
74
|
+
if (prev !== next) {
|
|
75
|
+
this.#selectedFile = next;
|
|
76
|
+
this.#signalUpdate();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
112
79
|
get dirty() {
|
|
113
|
-
return
|
|
80
|
+
return this.#files.some((file) => file.dirty);
|
|
114
81
|
}
|
|
115
82
|
async save() {
|
|
116
|
-
await Promise.all(
|
|
83
|
+
await Promise.all(this.#files.map((file) => file.save()));
|
|
117
84
|
}
|
|
118
85
|
async reload() {
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
const files = await __privateGet(this, _access2).listFiles();
|
|
86
|
+
const selectedPath = this.#selectedFile?.path;
|
|
87
|
+
const files = await this.#access.listFiles();
|
|
122
88
|
const fileManagers = await Promise.all(
|
|
123
89
|
files.map(async (file) => {
|
|
124
90
|
const manager = new DirectoryEditorFileManager(
|
|
125
91
|
file,
|
|
126
|
-
|
|
92
|
+
this.#signalUpdate
|
|
127
93
|
);
|
|
128
94
|
await manager.reload();
|
|
129
95
|
return manager;
|
|
130
96
|
})
|
|
131
97
|
);
|
|
132
|
-
|
|
133
|
-
|
|
98
|
+
this.#files.length = 0;
|
|
99
|
+
this.#files.push(...fileManagers);
|
|
134
100
|
this.setSelectedFile(selectedPath);
|
|
135
|
-
|
|
101
|
+
this.#signalUpdate();
|
|
136
102
|
}
|
|
137
103
|
subscribe(listener) {
|
|
138
|
-
|
|
104
|
+
this.#listeners.add(listener);
|
|
139
105
|
return () => {
|
|
140
|
-
|
|
106
|
+
this.#listeners.delete(listener);
|
|
141
107
|
};
|
|
142
108
|
}
|
|
109
|
+
#signalUpdate = () => {
|
|
110
|
+
this.#listeners.forEach((listener) => listener());
|
|
111
|
+
};
|
|
143
112
|
}
|
|
144
|
-
_access2 = new WeakMap();
|
|
145
|
-
_listeners = new WeakMap();
|
|
146
|
-
_files = new WeakMap();
|
|
147
|
-
_selectedFile = new WeakMap();
|
|
148
|
-
_signalUpdate2 = new WeakMap();
|
|
149
113
|
const DirectoryEditorContext = createContext(
|
|
150
114
|
void 0
|
|
151
115
|
);
|
|
152
116
|
function useDirectoryEditor() {
|
|
153
117
|
const value = useContext(DirectoryEditorContext);
|
|
154
118
|
const rerender = useRerender();
|
|
155
|
-
useEffect(() => value
|
|
119
|
+
useEffect(() => value?.subscribe(rerender), [value, rerender]);
|
|
156
120
|
if (!value) {
|
|
157
121
|
throw new Error("must be used within a DirectoryEditorProvider");
|
|
158
122
|
}
|