@backstage/plugin-scaffolder 1.34.1-next.1 → 1.34.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 CHANGED
@@ -1,5 +1,38 @@
1
1
  # @backstage/plugin-scaffolder
2
2
 
3
+ ## 1.34.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0d415ae: Render a TechDocs link on the Scaffolder Template List page when templates include either `backstage.io/techdocs-ref` or `backstage.io/techdocs-entity` annotations, using the shared `buildTechDocsURL` helper. Also adds tests to verify both annotations and optional `backstage.io/techdocs-entity-path` are respected.
8
+ - 7151260: Prevent the MultiEntityPicker from removing options present in form state when new options are selected
9
+ - Updated dependencies
10
+ - @backstage/plugin-catalog-react@1.21.0
11
+ - @backstage/plugin-techdocs-react@1.3.3
12
+ - @backstage/frontend-plugin-api@0.12.0
13
+ - @backstage/core-plugin-api@1.11.0
14
+ - @backstage/catalog-client@1.12.0
15
+ - @backstage/integration@1.18.0
16
+ - @backstage/core-components@0.18.0
17
+ - @backstage/types@1.2.2
18
+ - @backstage/core-compat-api@0.5.2
19
+ - @backstage/plugin-scaffolder-react@1.19.1
20
+ - @backstage/integration-react@1.2.10
21
+ - @backstage/plugin-scaffolder-common@1.7.1
22
+
23
+ ## 1.34.1-next.2
24
+
25
+ ### Patch Changes
26
+
27
+ - 0d415ae: Render a TechDocs link on the Scaffolder Template List page when templates include either `backstage.io/techdocs-ref` or `backstage.io/techdocs-entity` annotations, using the shared `buildTechDocsURL` helper. Also adds tests to verify both annotations and optional `backstage.io/techdocs-entity-path` are respected.
28
+ - Updated dependencies
29
+ - @backstage/catalog-client@1.12.0-next.0
30
+ - @backstage/plugin-catalog-react@1.21.0-next.2
31
+ - @backstage/core-components@0.17.6-next.1
32
+ - @backstage/plugin-scaffolder-react@1.19.1-next.2
33
+ - @backstage/integration@1.18.0-next.0
34
+ - @backstage/core-compat-api@0.5.2-next.2
35
+
3
36
  ## 1.34.1-next.1
4
37
 
5
38
  ### Patch Changes
@@ -10,6 +10,8 @@ import { registerComponentRouteRef, editRouteRef, actionsRouteRef, scaffolderLis
10
10
  import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
11
11
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
12
12
  import { scaffolderTranslationRef } from '../../../translation.esm.js';
13
+ import { buildTechDocsURL } from '@backstage/plugin-techdocs-react';
14
+ import { TECHDOCS_ANNOTATION, TECHDOCS_EXTERNAL_ANNOTATION } from '@backstage/plugin-techdocs-common';
13
15
 
14
16
  const createGroupsWithOther = (groups, t) => [
15
17
  ...groups,
@@ -49,16 +51,17 @@ const TemplateListPage = (props) => {
49
51
  };
50
52
  const additionalLinksForEntity = useCallback(
51
53
  (template) => {
52
- const { kind, namespace, name } = parseEntityRef(
53
- stringifyEntityRef(template)
54
- );
55
- return template.metadata.annotations?.["backstage.io/techdocs-ref"] && viewTechDocsLink ? [
54
+ if (!(template.metadata.annotations?.[TECHDOCS_ANNOTATION] || template.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) || !viewTechDocsLink) {
55
+ return [];
56
+ }
57
+ const url = buildTechDocsURL(template, viewTechDocsLink);
58
+ return url ? [
56
59
  {
57
60
  icon: app.getSystemIcon("docs") ?? DocsIcon,
58
61
  text: t(
59
62
  "templateListPage.additionalLinksForEntity.viewTechDocsTitle"
60
63
  ),
61
- url: viewTechDocsLink({ kind, namespace, name })
64
+ url
62
65
  }
63
66
  ] : [];
64
67
  },
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateListPage.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/TemplateListPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ComponentType, useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n Header,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n ScaffolderPageContextMenu,\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\n\nimport { RegisterExistingButton } from './RegisterExistingButton';\nimport {\n actionsRouteRef,\n editRouteRef,\n registerComponentRouteRef,\n scaffolderListTaskRouteRef,\n selectedTemplateRouteRef,\n templatingExtensionsRouteRef,\n viewTechDocRouteRef,\n} from '../../../routes';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';\nimport {\n TranslationFunction,\n useTranslationRef,\n} from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\n/**\n * @alpha\n */\nexport type TemplateListPageProps = {\n TemplateCardComponent?: ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n contextMenu?: {\n editor?: boolean;\n actions?: boolean;\n tasks?: boolean;\n templatingExtensions?: boolean;\n };\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\nconst createGroupsWithOther = (\n groups: TemplateGroupFilter[],\n t: TranslationFunction<typeof scaffolderTranslationRef.T>,\n): TemplateGroupFilter[] => [\n ...groups,\n {\n title: t('templateListPage.templateGroups.otherTitle'),\n filter: e => ![...groups].some(({ filter }) => filter(e)),\n },\n];\n\n/**\n * @alpha\n */\nexport const TemplateListPage = (props: TemplateListPageProps) => {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const {\n TemplateCardComponent,\n groups: givenGroups = [],\n templateFilter,\n headerOptions,\n } = props;\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = givenGroups.length\n ? createGroupsWithOther(givenGroups, t)\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ];\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked:\n props?.contextMenu?.editor !== false\n ? () => navigate(editorLink())\n : undefined,\n onActionsClicked:\n props?.contextMenu?.actions !== false\n ? () => navigate(actionsLink())\n : undefined,\n onTasksClicked:\n props?.contextMenu?.tasks !== false\n ? () => navigate(tasksLink())\n : undefined,\n onTemplatingExtensionsClicked:\n props?.contextMenu?.templatingExtensions !== false\n ? () => navigate(templatingExtensionsLink())\n : undefined,\n };\n\n const additionalLinksForEntity = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { kind, namespace, name } = parseEntityRef(\n stringifyEntityRef(template),\n );\n return template.metadata.annotations?.['backstage.io/techdocs-ref'] &&\n viewTechDocsLink\n ? [\n {\n icon: app.getSystemIcon('docs') ?? DocsIcon,\n text: t(\n 'templateListPage.additionalLinksForEntity.viewTechDocsTitle',\n ),\n url: viewTechDocsLink({ kind, namespace, name }),\n },\n ]\n : [];\n },\n [app, viewTechDocsLink, t],\n );\n\n const onTemplateSelected = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { namespace, name } = parseEntityRef(stringifyEntityRef(template));\n\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templateListPage.pageTitle')}\n title={t('templateListPage.title')}\n subtitle={t('templateListPage.subtitle')}\n {...headerOptions}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n <Content>\n <ContentHeader>\n <RegisterExistingButton\n title={t(\n 'templateListPage.contentHeader.registerExistingButtonTitle',\n )}\n to={registerComponentLink && registerComponentLink()}\n />\n <SupportButton>\n {t('templateListPage.contentHeader.supportButtonTitle')}\n </SupportButton>\n </ContentHeader>\n\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <EntitySearchBar />\n <EntityKindPicker initialFilter=\"template\" hidden />\n <UserListPicker\n initialFilter=\"all\"\n availableFilters={['all', 'starred']}\n />\n <TemplateCategoryPicker />\n <EntityTagPicker />\n <EntityOwnerPicker />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n <TemplateGroups\n groups={groups}\n templateFilter={templateFilter}\n TemplateCardComponent={TemplateCardComponent}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </Page>\n </EntityListProvider>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TemplateListPage.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/TemplateListPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ComponentType, useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n Header,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n ScaffolderPageContextMenu,\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\n\nimport { RegisterExistingButton } from './RegisterExistingButton';\nimport {\n actionsRouteRef,\n editRouteRef,\n registerComponentRouteRef,\n scaffolderListTaskRouteRef,\n selectedTemplateRouteRef,\n templatingExtensionsRouteRef,\n viewTechDocRouteRef,\n} from '../../../routes';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';\nimport {\n TranslationFunction,\n useTranslationRef,\n} from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { buildTechDocsURL } from '@backstage/plugin-techdocs-react';\nimport {\n TECHDOCS_ANNOTATION,\n TECHDOCS_EXTERNAL_ANNOTATION,\n} from '@backstage/plugin-techdocs-common';\n\n/**\n * @alpha\n */\nexport type TemplateListPageProps = {\n TemplateCardComponent?: ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n contextMenu?: {\n editor?: boolean;\n actions?: boolean;\n tasks?: boolean;\n templatingExtensions?: boolean;\n };\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\nconst createGroupsWithOther = (\n groups: TemplateGroupFilter[],\n t: TranslationFunction<typeof scaffolderTranslationRef.T>,\n): TemplateGroupFilter[] => [\n ...groups,\n {\n title: t('templateListPage.templateGroups.otherTitle'),\n filter: e => ![...groups].some(({ filter }) => filter(e)),\n },\n];\n\n/**\n * @alpha\n */\nexport const TemplateListPage = (props: TemplateListPageProps) => {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const {\n TemplateCardComponent,\n groups: givenGroups = [],\n templateFilter,\n headerOptions,\n } = props;\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = givenGroups.length\n ? createGroupsWithOther(givenGroups, t)\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ];\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked:\n props?.contextMenu?.editor !== false\n ? () => navigate(editorLink())\n : undefined,\n onActionsClicked:\n props?.contextMenu?.actions !== false\n ? () => navigate(actionsLink())\n : undefined,\n onTasksClicked:\n props?.contextMenu?.tasks !== false\n ? () => navigate(tasksLink())\n : undefined,\n onTemplatingExtensionsClicked:\n props?.contextMenu?.templatingExtensions !== false\n ? () => navigate(templatingExtensionsLink())\n : undefined,\n };\n\n const additionalLinksForEntity = useCallback(\n (template: TemplateEntityV1beta3) => {\n if (\n !(\n template.metadata.annotations?.[TECHDOCS_ANNOTATION] ||\n template.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]\n ) ||\n !viewTechDocsLink\n ) {\n return [];\n }\n\n const url = buildTechDocsURL(template, viewTechDocsLink);\n return url\n ? [\n {\n icon: app.getSystemIcon('docs') ?? DocsIcon,\n text: t(\n 'templateListPage.additionalLinksForEntity.viewTechDocsTitle',\n ),\n url,\n },\n ]\n : [];\n },\n [app, viewTechDocsLink, t],\n );\n\n const onTemplateSelected = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { namespace, name } = parseEntityRef(stringifyEntityRef(template));\n\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templateListPage.pageTitle')}\n title={t('templateListPage.title')}\n subtitle={t('templateListPage.subtitle')}\n {...headerOptions}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n <Content>\n <ContentHeader>\n <RegisterExistingButton\n title={t(\n 'templateListPage.contentHeader.registerExistingButtonTitle',\n )}\n to={registerComponentLink && registerComponentLink()}\n />\n <SupportButton>\n {t('templateListPage.contentHeader.supportButtonTitle')}\n </SupportButton>\n </ContentHeader>\n\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <EntitySearchBar />\n <EntityKindPicker initialFilter=\"template\" hidden />\n <UserListPicker\n initialFilter=\"all\"\n availableFilters={['all', 'starred']}\n />\n <TemplateCategoryPicker />\n <EntityTagPicker />\n <EntityOwnerPicker />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n <TemplateGroups\n groups={groups}\n templateFilter={templateFilter}\n TemplateCardComponent={TemplateCardComponent}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </Page>\n </EntityListProvider>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -13,6 +13,10 @@ import { useTranslationRef } from '@backstage/frontend-plugin-api';
13
13
  import { scaffolderTranslationRef } from '../../../translation.esm.js';
14
14
  export { MultiEntityPickerSchema } from './schema.esm.js';
15
15
 
16
+ const FREE_SOLO_EVENTS = [
17
+ "blur",
18
+ "create-option"
19
+ ];
16
20
  const MultiEntityPicker = (props) => {
17
21
  const { t } = useTranslationRef(scaffolderTranslationRef);
18
22
  const {
@@ -57,20 +61,22 @@ const MultiEntityPicker = (props) => {
57
61
  if (typeof ref !== "string") {
58
62
  return ref ? stringifyEntityRef(ref) : void 0;
59
63
  }
60
- if (reason === "blur" || reason === "create-option") {
61
- let entityRef = ref;
62
- try {
63
- entityRef = stringifyEntityRef(
64
- parseEntityRef(ref, {
65
- defaultKind,
66
- defaultNamespace
67
- })
68
- );
69
- } catch (err) {
70
- }
71
- if (formData?.includes(ref) || allowArbitraryValues) {
72
- return entityRef;
73
- }
64
+ let entityRef = ref;
65
+ try {
66
+ entityRef = stringifyEntityRef(
67
+ parseEntityRef(ref, {
68
+ defaultKind,
69
+ defaultNamespace
70
+ })
71
+ );
72
+ } catch (err) {
73
+ }
74
+ if (
75
+ // If value already matches what exists in form data, allow it
76
+ formData?.includes(ref) || // If arbitrary values are allowed and the reason is a free solo event, allow it
77
+ allowArbitraryValues && FREE_SOLO_EVENTS.includes(reason)
78
+ ) {
79
+ return entityRef;
74
80
  }
75
81
  return void 0;
76
82
  }).filter((ref) => ref !== void 0);
@@ -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 Autocomplete, {\n AutocompleteChangeReason,\n createFilterOptions,\n} from '@material-ui/lab/Autocomplete';\nimport { 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';\nimport { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';\nimport { useTranslationRef } from '@backstage/frontend-plugin-api';\nimport { scaffolderTranslationRef } from '../../../translation';\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 { t } = useTranslationRef(scaffolderTranslationRef);\n const {\n onChange,\n schema: {\n title = t('fields.multiEntityPicker.title'),\n description = t('fields.multiEntityPicker.description'),\n },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n errors,\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 <ScaffolderField\n rawErrors={rawErrors}\n rawDescription={uiSchema['ui:description'] ?? description}\n required={required}\n disabled={isDisabled}\n errors={errors}\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 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 filterOptions={createFilterOptions<Entity>({\n stringify: option =>\n entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.primaryTitle!,\n })}\n ListboxComponent={VirtualizedListbox}\n />\n </ScaffolderField>\n );\n};\n\nexport const validateMultiEntityPickerValidation = (\n values: string[],\n validation: FieldValidation,\n) => {\n values.forEach(value => {\n try {\n parseEntityRef(value);\n } catch {\n validation.addError(`${value} is not a valid entity ref`);\n }\n });\n};\n\n/**\n * Converts a special `{exists: true}` value to the `CATALOG_FILTER_EXISTS` symbol.\n *\n * @param value - The value to convert.\n * @returns The converted value.\n */\nfunction convertOpsValues(\n value: Exclude<MultiEntityPickerFilterQueryValue, Array<any>>,\n): string | symbol {\n if (typeof value === 'object' && value.exists) {\n return CATALOG_FILTER_EXISTS;\n }\n return value?.toString();\n}\n\n/**\n * Converts schema filters to entity filter query, replacing `{exists:true}` values\n * with the constant `CATALOG_FILTER_EXISTS`.\n *\n * @param schemaFilters - An object containing schema filters with keys as filter names\n * and values as filter values.\n * @returns An object with the same keys as the input object, but with `{exists:true}` values\n * transformed to `CATALOG_FILTER_EXISTS` symbol.\n */\nfunction convertSchemaFiltersToQuery(\n schemaFilters: MultiEntityPickerFilterQuery,\n): Exclude<EntityFilterQuery, Array<any>> {\n const query: EntityFilterQuery = {};\n\n for (const [key, value] of Object.entries(schemaFilters)) {\n if (Array.isArray(value)) {\n query[key] = value;\n } else {\n query[key] = convertOpsValues(value);\n }\n }\n\n return query;\n}\n\n/**\n * Builds an `EntityFilterQuery` based on the `uiSchema` passed in.\n * If `catalogFilter` is specified in the `uiSchema`, it is converted to a `EntityFilterQuery`.\n *\n * @param uiSchema The `uiSchema` of an `EntityPicker` component.\n * @returns An `EntityFilterQuery` based on the `uiSchema`, or `undefined` if `catalogFilter` is not specified in the `uiSchema`.\n */\nfunction buildCatalogFilter(\n uiSchema: MultiEntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const catalogFilter: MultiEntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter;\n\n if (!catalogFilter) {\n return undefined;\n }\n\n if (Array.isArray(catalogFilter)) {\n return catalogFilter.map(convertSchemaFiltersToQuery);\n }\n\n return convertSchemaFiltersToQuery(catalogFilter);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MultiEntityPicker.esm.js","sources":["../../../../src/components/fields/MultiEntityPicker/MultiEntityPicker.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n type EntityFilterQuery,\n CATALOG_FILTER_EXISTS,\n} from '@backstage/catalog-client';\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n entityPresentationApiRef,\n EntityDisplayName,\n EntityRefPresentationSnapshot,\n} from '@backstage/plugin-catalog-react';\nimport TextField from '@material-ui/core/TextField';\nimport Autocomplete, {\n AutocompleteChangeReason,\n createFilterOptions,\n} from '@material-ui/lab/Autocomplete';\nimport { 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';\nimport { ScaffolderField } from '@backstage/plugin-scaffolder-react/alpha';\nimport { useTranslationRef } from '@backstage/frontend-plugin-api';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nexport { MultiEntityPickerSchema } from './schema';\n\n// AutocompleteChangeReason events that can be triggered when a user inputs a freeSolo option\nconst FREE_SOLO_EVENTS: readonly AutocompleteChangeReason[] = [\n 'blur',\n 'create-option',\n];\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 { t } = useTranslationRef(scaffolderTranslationRef);\n const {\n onChange,\n schema: {\n title = t('fields.multiEntityPicker.title'),\n description = t('fields.multiEntityPicker.description'),\n },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n errors,\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 the ref is not a string, then it was a selected option in the picker\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\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 (\n // If value already matches what exists in form data, allow it\n formData?.includes(ref) ||\n // If arbitrary values are allowed and the reason is a free solo event, allow it\n (allowArbitraryValues && FREE_SOLO_EVENTS.includes(reason))\n ) {\n return entityRef;\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 <ScaffolderField\n rawErrors={rawErrors}\n rawDescription={uiSchema['ui:description'] ?? description}\n required={required}\n disabled={isDisabled}\n errors={errors}\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 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 filterOptions={createFilterOptions<Entity>({\n stringify: option =>\n entities?.entityRefToPresentation.get(stringifyEntityRef(option))\n ?.primaryTitle!,\n })}\n ListboxComponent={VirtualizedListbox}\n />\n </ScaffolderField>\n );\n};\n\nexport const validateMultiEntityPickerValidation = (\n values: string[],\n validation: FieldValidation,\n) => {\n values.forEach(value => {\n try {\n parseEntityRef(value);\n } catch {\n validation.addError(`${value} is not a valid entity ref`);\n }\n });\n};\n\n/**\n * Converts a special `{exists: true}` value to the `CATALOG_FILTER_EXISTS` symbol.\n *\n * @param value - The value to convert.\n * @returns The converted value.\n */\nfunction convertOpsValues(\n value: Exclude<MultiEntityPickerFilterQueryValue, Array<any>>,\n): string | symbol {\n if (typeof value === 'object' && value.exists) {\n return CATALOG_FILTER_EXISTS;\n }\n return value?.toString();\n}\n\n/**\n * Converts schema filters to entity filter query, replacing `{exists:true}` values\n * with the constant `CATALOG_FILTER_EXISTS`.\n *\n * @param schemaFilters - An object containing schema filters with keys as filter names\n * and values as filter values.\n * @returns An object with the same keys as the input object, but with `{exists:true}` values\n * transformed to `CATALOG_FILTER_EXISTS` symbol.\n */\nfunction convertSchemaFiltersToQuery(\n schemaFilters: MultiEntityPickerFilterQuery,\n): Exclude<EntityFilterQuery, Array<any>> {\n const query: EntityFilterQuery = {};\n\n for (const [key, value] of Object.entries(schemaFilters)) {\n if (Array.isArray(value)) {\n query[key] = value;\n } else {\n query[key] = convertOpsValues(value);\n }\n }\n\n return query;\n}\n\n/**\n * Builds an `EntityFilterQuery` based on the `uiSchema` passed in.\n * If `catalogFilter` is specified in the `uiSchema`, it is converted to a `EntityFilterQuery`.\n *\n * @param uiSchema The `uiSchema` of an `EntityPicker` component.\n * @returns An `EntityFilterQuery` based on the `uiSchema`, or `undefined` if `catalogFilter` is not specified in the `uiSchema`.\n */\nfunction buildCatalogFilter(\n uiSchema: MultiEntityPickerProps['uiSchema'],\n): EntityFilterQuery | undefined {\n const catalogFilter: MultiEntityPickerUiOptions['catalogFilter'] | undefined =\n uiSchema['ui:options']?.catalogFilter;\n\n if (!catalogFilter) {\n return undefined;\n }\n\n if (Array.isArray(catalogFilter)) {\n return catalogFilter.map(convertSchemaFiltersToQuery);\n }\n\n return convertSchemaFiltersToQuery(catalogFilter);\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  var name = "@backstage/plugin-scaffolder";
2
- var version = "1.34.1-next.1";
2
+ var version = "1.34.1";
3
3
  var description = "The Backstage plugin that helps you create new things";
4
4
  var backstage = {
5
5
  role: "frontend-plugin",
@@ -71,6 +71,8 @@ var dependencies = {
71
71
  "@backstage/plugin-permission-react": "workspace:^",
72
72
  "@backstage/plugin-scaffolder-common": "workspace:^",
73
73
  "@backstage/plugin-scaffolder-react": "workspace:^",
74
+ "@backstage/plugin-techdocs-common": "workspace:^",
75
+ "@backstage/plugin-techdocs-react": "workspace:^",
74
76
  "@backstage/types": "workspace:^",
75
77
  "@codemirror/language": "^6.0.0",
76
78
  "@codemirror/legacy-modes": "^6.1.0",
@@ -108,6 +110,7 @@ var devDependencies = {
108
110
  "@backstage/dev-utils": "workspace:^",
109
111
  "@backstage/plugin-catalog": "workspace:^",
110
112
  "@backstage/plugin-permission-common": "workspace:^",
113
+ "@backstage/plugin-techdocs": "workspace:^",
111
114
  "@backstage/test-utils": "workspace:^",
112
115
  "@testing-library/dom": "^10.0.0",
113
116
  "@testing-library/jest-dom": "^6.0.0",
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder",
3
- "version": "1.34.1-next.1",
3
+ "version": "1.34.1",
4
4
  "description": "The Backstage plugin that helps you create new things",
5
5
  "backstage": {
6
6
  "role": "frontend-plugin",
@@ -70,21 +70,23 @@
70
70
  "test": "backstage-cli package test"
71
71
  },
72
72
  "dependencies": {
73
- "@backstage/catalog-client": "1.11.0",
74
- "@backstage/catalog-model": "1.7.5",
75
- "@backstage/core-compat-api": "0.5.2-next.1",
76
- "@backstage/core-components": "0.17.6-next.0",
77
- "@backstage/core-plugin-api": "1.10.9",
78
- "@backstage/errors": "1.2.7",
79
- "@backstage/frontend-plugin-api": "0.11.1-next.0",
80
- "@backstage/integration": "1.18.0-next.0",
81
- "@backstage/integration-react": "1.2.10-next.0",
82
- "@backstage/plugin-catalog-common": "1.1.5",
83
- "@backstage/plugin-catalog-react": "1.20.2-next.1",
84
- "@backstage/plugin-permission-react": "0.4.36",
85
- "@backstage/plugin-scaffolder-common": "1.7.1-next.0",
86
- "@backstage/plugin-scaffolder-react": "1.19.1-next.1",
87
- "@backstage/types": "1.2.1",
73
+ "@backstage/catalog-client": "^1.12.0",
74
+ "@backstage/catalog-model": "^1.7.5",
75
+ "@backstage/core-compat-api": "^0.5.2",
76
+ "@backstage/core-components": "^0.18.0",
77
+ "@backstage/core-plugin-api": "^1.11.0",
78
+ "@backstage/errors": "^1.2.7",
79
+ "@backstage/frontend-plugin-api": "^0.12.0",
80
+ "@backstage/integration": "^1.18.0",
81
+ "@backstage/integration-react": "^1.2.10",
82
+ "@backstage/plugin-catalog-common": "^1.1.5",
83
+ "@backstage/plugin-catalog-react": "^1.21.0",
84
+ "@backstage/plugin-permission-react": "^0.4.36",
85
+ "@backstage/plugin-scaffolder-common": "^1.7.1",
86
+ "@backstage/plugin-scaffolder-react": "^1.19.1",
87
+ "@backstage/plugin-techdocs-common": "^0.1.1",
88
+ "@backstage/plugin-techdocs-react": "^1.3.3",
89
+ "@backstage/types": "^1.2.2",
88
90
  "@codemirror/language": "^6.0.0",
89
91
  "@codemirror/legacy-modes": "^6.1.0",
90
92
  "@codemirror/view": "^6.0.0",
@@ -116,12 +118,13 @@
116
118
  "zod-to-json-schema": "^3.20.4"
117
119
  },
118
120
  "devDependencies": {
119
- "@backstage/cli": "0.34.2-next.1",
120
- "@backstage/core-app-api": "1.18.0",
121
- "@backstage/dev-utils": "1.1.14-next.1",
122
- "@backstage/plugin-catalog": "1.31.3-next.1",
123
- "@backstage/plugin-permission-common": "0.9.1",
124
- "@backstage/test-utils": "1.7.11",
121
+ "@backstage/cli": "^0.34.2",
122
+ "@backstage/core-app-api": "^1.19.0",
123
+ "@backstage/dev-utils": "^1.1.14",
124
+ "@backstage/plugin-catalog": "^1.31.3",
125
+ "@backstage/plugin-permission-common": "^0.9.1",
126
+ "@backstage/plugin-techdocs": "^1.15.0",
127
+ "@backstage/test-utils": "^1.7.11",
125
128
  "@testing-library/dom": "^10.0.0",
126
129
  "@testing-library/jest-dom": "^6.0.0",
127
130
  "@testing-library/react": "^16.0.0",