@backstage/plugin-catalog-react 3.2.3-next.1 → 3.2.3

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/alpha/converters/convertLegacyEntityCardExtension.esm.js +1 -1
  3. package/dist/alpha/converters/convertLegacyEntityCardExtension.esm.js.map +1 -1
  4. package/dist/alpha/converters/convertLegacyEntityContentExtension.esm.js +1 -1
  5. package/dist/alpha/converters/convertLegacyEntityContentExtension.esm.js.map +1 -1
  6. package/dist/apis/EntityPresentationApi/defaultEntityPresentation.esm.js +5 -5
  7. package/dist/apis/EntityPresentationApi/defaultEntityPresentation.esm.js.map +1 -1
  8. package/dist/components/EntityKindPicker/EntityKindPicker.esm.js +1 -1
  9. package/dist/components/EntityKindPicker/EntityKindPicker.esm.js.map +1 -1
  10. package/dist/components/EntityKindPicker/kindFilterUtils.esm.js +3 -5
  11. package/dist/components/EntityKindPicker/kindFilterUtils.esm.js.map +1 -1
  12. package/dist/components/EntityOwnerPicker/EntityOwnerPicker.esm.js +3 -5
  13. package/dist/components/EntityOwnerPicker/EntityOwnerPicker.esm.js.map +1 -1
  14. package/dist/components/EntityRefLink/humanize.esm.js +2 -2
  15. package/dist/components/EntityRefLink/humanize.esm.js.map +1 -1
  16. package/dist/components/EntityTypePicker/EntityTypePicker.esm.js +1 -3
  17. package/dist/components/EntityTypePicker/EntityTypePicker.esm.js.map +1 -1
  18. package/dist/components/InspectEntityDialog/components/AncestryPage.esm.js +1 -3
  19. package/dist/components/InspectEntityDialog/components/AncestryPage.esm.js.map +1 -1
  20. package/dist/components/InspectEntityDialog/components/EntityKindIcon.esm.js +2 -2
  21. package/dist/components/InspectEntityDialog/components/EntityKindIcon.esm.js.map +1 -1
  22. package/dist/filters.esm.js +1 -1
  23. package/dist/filters.esm.js.map +1 -1
  24. package/dist/hooks/useEntityListProvider.esm.js +1 -1
  25. package/dist/hooks/useEntityListProvider.esm.js.map +1 -1
  26. package/dist/hooks/useEntityTypeFilter.esm.js +1 -5
  27. package/dist/hooks/useEntityTypeFilter.esm.js.map +1 -1
  28. package/dist/hooks/useRelatedEntities.esm.js +3 -3
  29. package/dist/hooks/useRelatedEntities.esm.js.map +1 -1
  30. package/dist/routes.esm.js +2 -2
  31. package/dist/routes.esm.js.map +1 -1
  32. package/dist/utils/getEntityRelations.esm.js +1 -1
  33. package/dist/utils/getEntityRelations.esm.js.map +1 -1
  34. package/package.json +22 -22
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 3.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 736d84e: Use locale-insensitive Unicode casing for consistent string handling across environments.
8
+ - a7b14b5: Fixed `EntityOwnerPicker` crashing with `Entity reference "<name>" had missing or empty kind` when the `owners` query parameter contains humanized entity refs, as produced by the `OwnershipCard` links in `@backstage/plugin-org`.
9
+
10
+ Query parameters were stored as-is in the initial state and only converted to full entity refs by an effect, which runs after the first render. That first render passed the raw value to the entity presentation API, whose `parseEntityRef` call rejects a ref without a kind. The same raw value was also sent to `catalogApi.getEntitiesByRefs` on mount, and made the option checkboxes render unselected until the effect ran.
11
+
12
+ The query parameters are now normalized through `EntityOwnerFilter` when the state is initialized, matching what the existing effect already did and what the `filters` code path already produced.
13
+
14
+ - bf7e890: Added the missing Material UI dependency used by catalog popovers.
15
+ - Updated dependencies
16
+ - @backstage/core-components@0.18.14
17
+ - @backstage/ui@0.18.0
18
+ - @backstage/catalog-client@1.16.2
19
+ - @backstage/catalog-model@1.10.1
20
+ - @backstage/filter-predicates@0.1.5
21
+ - @backstage/frontend-plugin-api@0.18.1
22
+ - @backstage/core-compat-api@0.5.15
23
+ - @backstage/core-plugin-api@1.12.10
24
+ - @backstage/integration-react@1.2.22
25
+ - @backstage/plugin-permission-common@0.9.11
26
+ - @backstage/plugin-permission-react@0.5.5
27
+
28
+ ## 3.2.3-next.2
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies
33
+ - @backstage/ui@0.18.0-next.2
34
+ - @backstage/catalog-client@1.16.2-next.1
35
+ - @backstage/core-components@0.18.14-next.2
36
+ - @backstage/core-plugin-api@1.12.10-next.1
37
+ - @backstage/filter-predicates@0.1.5-next.1
38
+ - @backstage/frontend-plugin-api@0.18.1-next.1
39
+ - @backstage/integration-react@1.2.22-next.1
40
+ - @backstage/plugin-permission-common@0.9.11-next.0
41
+ - @backstage/plugin-permission-react@0.5.5-next.1
42
+
3
43
  ## 3.2.3-next.1
4
44
 
5
45
  ### Patch Changes
@@ -15,7 +15,7 @@ function convertLegacyEntityCardExtension(LegacyExtension, overrides) {
15
15
  const match = extName.match(/^Entity(.*)Card$/);
16
16
  const infix = match?.[1] ?? extName;
17
17
  let name = infix;
18
- if (pluginId && name.toLocaleLowerCase("en-US").startsWith(pluginId.toLocaleLowerCase("en-US"))) {
18
+ if (pluginId && name.toLowerCase().startsWith(pluginId.toLowerCase())) {
19
19
  name = name.slice(pluginId.length);
20
20
  if (!name) {
21
21
  name = void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"convertLegacyEntityCardExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityCardExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport { ComponentType } from 'react';\nimport { EntityCardBlueprint } from '../blueprints/EntityCardBlueprint';\nimport kebabCase from 'lodash/kebabCase';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { Entity } from '@backstage/catalog-model';\nimport { EntityCardType } from '../blueprints/extensionData';\n\n/** @alpha */\nexport function convertLegacyEntityCardExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | FilterPredicate | ((entity: Entity) => boolean);\n type?: EntityCardType;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Card$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityCardBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n loader: async () => compatWrapper(element),\n type: overrides?.type,\n },\n });\n}\n"],"names":[],"mappings":";;;;;;AA2BO,SAAS,gCAAA,CACd,iBACA,SAAA,EAKqB;AACrB,EAAA,MAAM,OAAA,uBAAW,eAAA,EAAA,EAAgB,CAAA;AAEjC,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAyB,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAkC,OAAA,EAAS,aAAa,CAAA;AACvE,EAAA,MAAM,QAAA,GAAW,QAAQ,KAAA,EAAM;AAE/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,kBAAkB,CAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,CAAC,CAAA,IAAK,OAAA;AAE5B,EAAA,IAAI,IAAA,GAA2B,KAAA;AAC/B,EAAA,IACE,QAAA,IACA,IAAA,CACG,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAA,CAAS,iBAAA,CAAkB,OAAO,CAAC,CAAA,EACjD;AACA,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,MAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAA,GAAO,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,oBAAoB,IAAA,CAAK;AAAA,IAC9B,IAAA,EAAM,WAAW,IAAA,IAAQ,IAAA;AAAA,IACzB,MAAA,EAAQ;AAAA,MACN,QAAQ,SAAA,EAAW,MAAA;AAAA,MACnB,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO,CAAA;AAAA,MACzC,MAAM,SAAA,EAAW;AAAA;AACnB,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"convertLegacyEntityCardExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityCardExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport { ComponentType } from 'react';\nimport { EntityCardBlueprint } from '../blueprints/EntityCardBlueprint';\nimport kebabCase from 'lodash/kebabCase';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { Entity } from '@backstage/catalog-model';\nimport { EntityCardType } from '../blueprints/extensionData';\n\n/** @alpha */\nexport function convertLegacyEntityCardExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | FilterPredicate | ((entity: Entity) => boolean);\n type?: EntityCardType;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Card$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (pluginId && name.toLowerCase().startsWith(pluginId.toLowerCase())) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityCardBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n loader: async () => compatWrapper(element),\n type: overrides?.type,\n },\n });\n}\n"],"names":[],"mappings":";;;;;;AA2BO,SAAS,gCAAA,CACd,iBACA,SAAA,EAKqB;AACrB,EAAA,MAAM,OAAA,uBAAW,eAAA,EAAA,EAAgB,CAAA;AAEjC,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAyB,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAkC,OAAA,EAAS,aAAa,CAAA;AACvE,EAAA,MAAM,QAAA,GAAW,QAAQ,KAAA,EAAM;AAE/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,kBAAkB,CAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,CAAC,CAAA,IAAK,OAAA;AAE5B,EAAA,IAAI,IAAA,GAA2B,KAAA;AAC/B,EAAA,IAAI,QAAA,IAAY,KAAK,WAAA,EAAY,CAAE,WAAW,QAAA,CAAS,WAAA,EAAa,CAAA,EAAG;AACrE,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,MAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAA,GAAO,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,oBAAoB,IAAA,CAAK;AAAA,IAC9B,IAAA,EAAM,WAAW,IAAA,IAAQ,IAAA;AAAA,IACzB,MAAA,EAAQ;AAAA,MACN,QAAQ,SAAA,EAAW,MAAA;AAAA,MACnB,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO,CAAA;AAAA,MACzC,MAAM,SAAA,EAAW;AAAA;AACnB,GACD,CAAA;AACH;;;;"}
@@ -20,7 +20,7 @@ function convertLegacyEntityContentExtension(LegacyExtension, overrides) {
20
20
  const match = extName.match(/^Entity(.*)Content$/);
21
21
  const infix = match?.[1] ?? extName;
22
22
  let name = infix;
23
- if (pluginId && name.toLocaleLowerCase("en-US").startsWith(pluginId.toLocaleLowerCase("en-US"))) {
23
+ if (pluginId && name.toLowerCase().startsWith(pluginId.toLowerCase())) {
24
24
  name = name.slice(pluginId.length);
25
25
  if (!name) {
26
26
  name = void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"convertLegacyEntityContentExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityContentExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n BackstagePlugin,\n getComponentData,\n RouteRef as LegacyRouteRef,\n} from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport kebabCase from 'lodash/kebabCase';\nimport startCase from 'lodash/startCase';\nimport { ComponentType, ReactElement } from 'react';\nimport { EntityContentBlueprint } from '../blueprints/EntityContentBlueprint';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { Entity } from '@backstage/catalog-model';\n\n/** @alpha */\nexport function convertLegacyEntityContentExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | FilterPredicate | ((entity: Entity) => boolean);\n path?: string;\n title?: string;\n icon?: string | ReactElement;\n\n /**\n * @deprecated Use the `path` param instead.\n */\n defaultPath?: [Error: `Use the 'path' override instead`];\n\n /**\n * @deprecated Use the `path` param instead.\n */\n defaultTitle?: [Error: `Use the 'title' override instead`];\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const mountPoint = getComponentData<LegacyRouteRef>(\n element,\n 'core.mountPoint',\n );\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Content$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n // TODO(blam): Remove support for all the `default*` props in the future, this breaks backwards compatibility without it\n // As this is marked as BREAKING ALPHA, it doesn't affect the public API so it falls in range and gets picked\n // up by packages that depend on `catalog-react`.\n return EntityContentBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n path: (overrides?.path ??\n overrides?.defaultPath ??\n `/${kebabCase(infix)}`) as string,\n title: (overrides?.title ??\n overrides?.defaultTitle ??\n startCase(infix)) as string,\n icon: overrides?.icon,\n routeRef: mountPoint && convertLegacyRouteRef(mountPoint),\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;AAkCO,SAAS,mCAAA,CACd,iBACA,SAAA,EAiBqB;AACrB,EAAA,MAAM,OAAA,uBAAW,eAAA,EAAA,EAAgB,CAAA;AAEjC,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAyB,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,UAAA,GAAa,gBAAA;AAAA,IACjB,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAkC,OAAA,EAAS,aAAa,CAAA;AACvE,EAAA,MAAM,QAAA,GAAW,QAAQ,KAAA,EAAM;AAE/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,qBAAqB,CAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,CAAC,CAAA,IAAK,OAAA;AAE5B,EAAA,IAAI,IAAA,GAA2B,KAAA;AAC/B,EAAA,IACE,QAAA,IACA,IAAA,CACG,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAA,CAAS,iBAAA,CAAkB,OAAO,CAAC,CAAA,EACjD;AACA,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,MAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAA,GAAO,IAAA,IAAQ,UAAU,IAAI,CAAA;AAI7B,EAAA,OAAO,uBAAuB,IAAA,CAAK;AAAA,IACjC,IAAA,EAAM,WAAW,IAAA,IAAQ,IAAA;AAAA,IACzB,MAAA,EAAQ;AAAA,MACN,QAAQ,SAAA,EAAW,MAAA;AAAA,MACnB,IAAA,EAAO,WAAW,IAAA,IAChB,SAAA,EAAW,eACX,CAAA,CAAA,EAAI,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,MACtB,OAAQ,SAAA,EAAW,KAAA,IACjB,SAAA,EAAW,YAAA,IACX,UAAU,KAAK,CAAA;AAAA,MACjB,MAAM,SAAA,EAAW,IAAA;AAAA,MACjB,QAAA,EAAU,UAAA,IAAc,qBAAA,CAAsB,UAAU,CAAA;AAAA,MACxD,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"convertLegacyEntityContentExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityContentExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n BackstagePlugin,\n getComponentData,\n RouteRef as LegacyRouteRef,\n} from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport kebabCase from 'lodash/kebabCase';\nimport startCase from 'lodash/startCase';\nimport { ComponentType, ReactElement } from 'react';\nimport { EntityContentBlueprint } from '../blueprints/EntityContentBlueprint';\nimport { FilterPredicate } from '@backstage/filter-predicates';\nimport { Entity } from '@backstage/catalog-model';\n\n/** @alpha */\nexport function convertLegacyEntityContentExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | FilterPredicate | ((entity: Entity) => boolean);\n path?: string;\n title?: string;\n icon?: string | ReactElement;\n\n /**\n * @deprecated Use the `path` param instead.\n */\n defaultPath?: [Error: `Use the 'path' override instead`];\n\n /**\n * @deprecated Use the `path` param instead.\n */\n defaultTitle?: [Error: `Use the 'title' override instead`];\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const mountPoint = getComponentData<LegacyRouteRef>(\n element,\n 'core.mountPoint',\n );\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Content$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (pluginId && name.toLowerCase().startsWith(pluginId.toLowerCase())) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n // TODO(blam): Remove support for all the `default*` props in the future, this breaks backwards compatibility without it\n // As this is marked as BREAKING ALPHA, it doesn't affect the public API so it falls in range and gets picked\n // up by packages that depend on `catalog-react`.\n return EntityContentBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n path: (overrides?.path ??\n overrides?.defaultPath ??\n `/${kebabCase(infix)}`) as string,\n title: (overrides?.title ??\n overrides?.defaultTitle ??\n startCase(infix)) as string,\n icon: overrides?.icon,\n routeRef: mountPoint && convertLegacyRouteRef(mountPoint),\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;AAkCO,SAAS,mCAAA,CACd,iBACA,SAAA,EAiBqB;AACrB,EAAA,MAAM,OAAA,uBAAW,eAAA,EAAA,EAAgB,CAAA;AAEjC,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAyB,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,UAAA,GAAa,gBAAA;AAAA,IACjB,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAkC,OAAA,EAAS,aAAa,CAAA;AACvE,EAAA,MAAM,QAAA,GAAW,QAAQ,KAAA,EAAM;AAE/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,qBAAqB,CAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,KAAA,GAAQ,CAAC,CAAA,IAAK,OAAA;AAE5B,EAAA,IAAI,IAAA,GAA2B,KAAA;AAC/B,EAAA,IAAI,QAAA,IAAY,KAAK,WAAA,EAAY,CAAE,WAAW,QAAA,CAAS,WAAA,EAAa,CAAA,EAAG;AACrE,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,IAAA,GAAO,MAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAA,GAAO,IAAA,IAAQ,UAAU,IAAI,CAAA;AAI7B,EAAA,OAAO,uBAAuB,IAAA,CAAK;AAAA,IACjC,IAAA,EAAM,WAAW,IAAA,IAAQ,IAAA;AAAA,IACzB,MAAA,EAAQ;AAAA,MACN,QAAQ,SAAA,EAAW,MAAA;AAAA,MACnB,IAAA,EAAO,WAAW,IAAA,IAChB,SAAA,EAAW,eACX,CAAA,CAAA,EAAI,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,MACtB,OAAQ,SAAA,EAAW,KAAA,IACjB,SAAA,EAAW,YAAA,IACX,UAAU,KAAK,CAAA;AAAA,MACjB,MAAM,SAAA,EAAW,IAAA;AAAA,MACjB,QAAA,EAAU,UAAA,IAAc,qBAAA,CAAsB,UAAU,CAAA;AAAA,MACxD,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
@@ -61,16 +61,16 @@ function getParts(entityOrRef) {
61
61
  return {};
62
62
  }
63
63
  function getShortRef(options) {
64
- const kind = options.kind?.toLocaleLowerCase("en-US") || "unknown";
64
+ const kind = options.kind?.toLowerCase() || "unknown";
65
65
  const namespace = options.namespace || DEFAULT_NAMESPACE;
66
66
  const name = options.name || "unknown";
67
- const defaultKindLower = options.context?.defaultKind?.toLocaleLowerCase("en-US");
68
- const defaultNamespaceLower = options.context?.defaultNamespace?.toLocaleLowerCase("en-US");
67
+ const defaultKindLower = options.context?.defaultKind?.toLowerCase();
68
+ const defaultNamespaceLower = options.context?.defaultNamespace?.toLowerCase();
69
69
  let result = name;
70
- if (defaultNamespaceLower && namespace.toLocaleLowerCase("en-US") !== defaultNamespaceLower || namespace !== DEFAULT_NAMESPACE) {
70
+ if (defaultNamespaceLower && namespace.toLowerCase() !== defaultNamespaceLower || namespace !== DEFAULT_NAMESPACE) {
71
71
  result = `${namespace}/${result}`;
72
72
  }
73
- if (defaultKindLower && kind.toLocaleLowerCase("en-US") !== defaultKindLower) {
73
+ if (defaultKindLower && kind.toLowerCase() !== defaultKindLower) {
74
74
  result = `${kind}:${result}`;
75
75
  }
76
76
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"defaultEntityPresentation.esm.js","sources":["../../../src/apis/EntityPresentationApi/defaultEntityPresentation.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CompoundEntityRef,\n DEFAULT_NAMESPACE,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport get from 'lodash/get';\nimport { EntityRefPresentationSnapshot } from './EntityPresentationApi';\n\n/**\n * Returns the default representation of an entity.\n *\n * @remarks\n *\n * This is a synchronous helper that extracts a display name from an\n * already-loaded entity or entity ref. It resolves `primaryTitle` as the\n * first available value among `spec.profile.displayName`, `metadata.title`,\n * and a shortened entity ref string.\n *\n * This function is primarily used as the internal fallback within the\n * {@link EntityPresentationApi} when no custom implementation is registered.\n * In React components, use the {@link useEntityPresentation} hook or the\n * {@link EntityDisplayName} component. In non-React contexts, use\n * {@link entityPresentationSnapshot} which respects custom presentation\n * overrides and falls back to this function when no API is registered.\n *\n * @public\n * @param entityOrRef - Either an entity, or a ref to it.\n * @param context - Contextual information that may affect the presentation.\n */\nexport function defaultEntityPresentation(\n entityOrRef: Entity | CompoundEntityRef | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n): EntityRefPresentationSnapshot {\n // NOTE(freben): This code may look convoluted, but it tries its very best to\n // be defensive and handling any type of malformed input and still producing\n // some form of result without crashing.\n const { kind, namespace, name, title, description, displayName, type } =\n getParts(entityOrRef);\n\n const entityRef: string = stringifyEntityRef({\n kind: kind || 'unknown',\n namespace: namespace || DEFAULT_NAMESPACE,\n name: name || 'unknown',\n });\n\n const shortRef = getShortRef({ kind, namespace, name, context });\n\n const primary = [displayName, title, shortRef].find(\n candidate => candidate && typeof candidate === 'string',\n )!;\n\n const secondary = [\n primary !== entityRef ? entityRef : undefined,\n type,\n description,\n ]\n .filter(candidate => candidate && typeof candidate === 'string')\n .join(' | ');\n\n return {\n entityRef,\n primaryTitle: primary,\n secondaryTitle: secondary || undefined,\n Icon: undefined, // leave it up to the presentation API to handle\n };\n}\n\nconst isString = (value: unknown): value is string =>\n Boolean(value) && typeof value === 'string';\n\n// Try to extract display-worthy parts of an entity or ref as best we can, without throwing\nfunction getParts(entityOrRef: Entity | CompoundEntityRef | string): {\n kind?: string;\n namespace?: string;\n name?: string;\n title?: string;\n description?: string;\n displayName?: string;\n type?: string;\n} {\n if (typeof entityOrRef === 'string') {\n let colonI = entityOrRef.indexOf(':');\n const slashI = entityOrRef.indexOf('/');\n\n // If the / is ahead of the :, treat the rest as the name\n if (slashI !== -1 && slashI < colonI) {\n colonI = -1;\n }\n\n const kind = colonI === -1 ? undefined : entityOrRef.slice(0, colonI);\n const namespace =\n slashI === -1 ? undefined : entityOrRef.slice(colonI + 1, slashI);\n const name = entityOrRef.slice(Math.max(colonI + 1, slashI + 1));\n\n return { kind, namespace, name };\n }\n\n if (typeof entityOrRef === 'object' && entityOrRef !== null) {\n const kind = [get(entityOrRef, 'kind')].find(isString);\n\n const namespace = [\n get(entityOrRef, 'metadata.namespace'),\n get(entityOrRef, 'namespace'),\n ].find(isString);\n\n const name = [\n get(entityOrRef, 'metadata.name'),\n get(entityOrRef, 'name'),\n ].find(isString);\n\n const title = [get(entityOrRef, 'metadata.title')].find(isString);\n\n const description = [get(entityOrRef, 'metadata.description')].find(\n isString,\n );\n\n const displayName = [get(entityOrRef, 'spec.profile.displayName')].find(\n isString,\n );\n\n const type = [get(entityOrRef, 'spec.type')].find(isString);\n\n return { kind, namespace, name, title, description, displayName, type };\n }\n\n return {};\n}\n\nfunction getShortRef(options: {\n kind?: string;\n namespace?: string;\n name?: string;\n context?: { defaultKind?: string; defaultNamespace?: string };\n}): string {\n const kind = options.kind?.toLocaleLowerCase('en-US') || 'unknown';\n const namespace = options.namespace || DEFAULT_NAMESPACE;\n const name = options.name || 'unknown';\n const defaultKindLower =\n options.context?.defaultKind?.toLocaleLowerCase('en-US');\n const defaultNamespaceLower =\n options.context?.defaultNamespace?.toLocaleLowerCase('en-US');\n\n let result = name;\n\n if (\n (defaultNamespaceLower &&\n namespace.toLocaleLowerCase('en-US') !== defaultNamespaceLower) ||\n namespace !== DEFAULT_NAMESPACE\n ) {\n result = `${namespace}/${result}`;\n }\n\n if (\n defaultKindLower &&\n kind.toLocaleLowerCase('en-US') !== defaultKindLower\n ) {\n result = `${kind}:${result}`;\n }\n\n return result;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"defaultEntityPresentation.esm.js","sources":["../../../src/apis/EntityPresentationApi/defaultEntityPresentation.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n CompoundEntityRef,\n DEFAULT_NAMESPACE,\n Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport get from 'lodash/get';\nimport { EntityRefPresentationSnapshot } from './EntityPresentationApi';\n\n/**\n * Returns the default representation of an entity.\n *\n * @remarks\n *\n * This is a synchronous helper that extracts a display name from an\n * already-loaded entity or entity ref. It resolves `primaryTitle` as the\n * first available value among `spec.profile.displayName`, `metadata.title`,\n * and a shortened entity ref string.\n *\n * This function is primarily used as the internal fallback within the\n * {@link EntityPresentationApi} when no custom implementation is registered.\n * In React components, use the {@link useEntityPresentation} hook or the\n * {@link EntityDisplayName} component. In non-React contexts, use\n * {@link entityPresentationSnapshot} which respects custom presentation\n * overrides and falls back to this function when no API is registered.\n *\n * @public\n * @param entityOrRef - Either an entity, or a ref to it.\n * @param context - Contextual information that may affect the presentation.\n */\nexport function defaultEntityPresentation(\n entityOrRef: Entity | CompoundEntityRef | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n): EntityRefPresentationSnapshot {\n // NOTE(freben): This code may look convoluted, but it tries its very best to\n // be defensive and handling any type of malformed input and still producing\n // some form of result without crashing.\n const { kind, namespace, name, title, description, displayName, type } =\n getParts(entityOrRef);\n\n const entityRef: string = stringifyEntityRef({\n kind: kind || 'unknown',\n namespace: namespace || DEFAULT_NAMESPACE,\n name: name || 'unknown',\n });\n\n const shortRef = getShortRef({ kind, namespace, name, context });\n\n const primary = [displayName, title, shortRef].find(\n candidate => candidate && typeof candidate === 'string',\n )!;\n\n const secondary = [\n primary !== entityRef ? entityRef : undefined,\n type,\n description,\n ]\n .filter(candidate => candidate && typeof candidate === 'string')\n .join(' | ');\n\n return {\n entityRef,\n primaryTitle: primary,\n secondaryTitle: secondary || undefined,\n Icon: undefined, // leave it up to the presentation API to handle\n };\n}\n\nconst isString = (value: unknown): value is string =>\n Boolean(value) && typeof value === 'string';\n\n// Try to extract display-worthy parts of an entity or ref as best we can, without throwing\nfunction getParts(entityOrRef: Entity | CompoundEntityRef | string): {\n kind?: string;\n namespace?: string;\n name?: string;\n title?: string;\n description?: string;\n displayName?: string;\n type?: string;\n} {\n if (typeof entityOrRef === 'string') {\n let colonI = entityOrRef.indexOf(':');\n const slashI = entityOrRef.indexOf('/');\n\n // If the / is ahead of the :, treat the rest as the name\n if (slashI !== -1 && slashI < colonI) {\n colonI = -1;\n }\n\n const kind = colonI === -1 ? undefined : entityOrRef.slice(0, colonI);\n const namespace =\n slashI === -1 ? undefined : entityOrRef.slice(colonI + 1, slashI);\n const name = entityOrRef.slice(Math.max(colonI + 1, slashI + 1));\n\n return { kind, namespace, name };\n }\n\n if (typeof entityOrRef === 'object' && entityOrRef !== null) {\n const kind = [get(entityOrRef, 'kind')].find(isString);\n\n const namespace = [\n get(entityOrRef, 'metadata.namespace'),\n get(entityOrRef, 'namespace'),\n ].find(isString);\n\n const name = [\n get(entityOrRef, 'metadata.name'),\n get(entityOrRef, 'name'),\n ].find(isString);\n\n const title = [get(entityOrRef, 'metadata.title')].find(isString);\n\n const description = [get(entityOrRef, 'metadata.description')].find(\n isString,\n );\n\n const displayName = [get(entityOrRef, 'spec.profile.displayName')].find(\n isString,\n );\n\n const type = [get(entityOrRef, 'spec.type')].find(isString);\n\n return { kind, namespace, name, title, description, displayName, type };\n }\n\n return {};\n}\n\nfunction getShortRef(options: {\n kind?: string;\n namespace?: string;\n name?: string;\n context?: { defaultKind?: string; defaultNamespace?: string };\n}): string {\n const kind = options.kind?.toLowerCase() || 'unknown';\n const namespace = options.namespace || DEFAULT_NAMESPACE;\n const name = options.name || 'unknown';\n const defaultKindLower = options.context?.defaultKind?.toLowerCase();\n const defaultNamespaceLower =\n options.context?.defaultNamespace?.toLowerCase();\n\n let result = name;\n\n if (\n (defaultNamespaceLower &&\n namespace.toLowerCase() !== defaultNamespaceLower) ||\n namespace !== DEFAULT_NAMESPACE\n ) {\n result = `${namespace}/${result}`;\n }\n\n if (defaultKindLower && kind.toLowerCase() !== defaultKindLower) {\n result = `${kind}:${result}`;\n }\n\n return result;\n}\n"],"names":[],"mappings":"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"}
@@ -84,7 +84,7 @@ const EntityKindPicker = (props) => {
84
84
  {
85
85
  label: t("entityKindPicker.title"),
86
86
  items,
87
- selected: selectedKind.toLocaleLowerCase("en-US"),
87
+ selected: selectedKind.toLowerCase(),
88
88
  onChange: (value) => setSelectedKind(String(value))
89
89
  }
90
90
  ) });
@@ -1 +1 @@
1
- {"version":3,"file":"EntityKindPicker.esm.js","sources":["../../../src/components/EntityKindPicker/EntityKindPicker.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 */\n\nimport { Select } from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport Box from '@material-ui/core/Box';\nimport { useEffect, useMemo, useState } from 'react';\nimport { EntityKindFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { filterKinds, useAllKinds } from './kindFilterUtils';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nfunction useEntityKindFilter(opts: { initialFilter: string }): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n selectedKind: string;\n setSelectedKind: (kind: string) => void;\n} {\n const {\n filters,\n queryParameters: { kind: kindParameter },\n updateFilters,\n } = useEntityList();\n\n const queryParamKind = useMemo(\n () => [kindParameter].flat()[0],\n [kindParameter],\n );\n\n const [selectedKind, setSelectedKind] = useState(\n queryParamKind ?? filters.kind?.value ?? opts.initialFilter,\n );\n\n // Set selected kinds on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamKind) {\n setSelectedKind(queryParamKind);\n }\n }, [queryParamKind]);\n\n // Set selected kind from filters; this happens when the kind filter is\n // updated from another component\n useEffect(() => {\n if (filters.kind?.value) {\n setSelectedKind(filters.kind?.value);\n }\n }, [filters.kind]);\n\n const { allKinds, loading, error } = useAllKinds();\n const selectedKindLabel = allKinds.get(selectedKind) || selectedKind;\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind\n ? new EntityKindFilter(selectedKind, selectedKindLabel)\n : undefined,\n });\n }, [selectedKind, selectedKindLabel, updateFilters]);\n\n return {\n loading,\n error,\n allKinds,\n selectedKind,\n setSelectedKind,\n };\n}\n\n/**\n * Props for {@link EntityKindPicker}.\n *\n * @public\n */\nexport interface EntityKindPickerProps {\n /**\n * Entity kinds to show in the dropdown; by default all kinds are fetched from the catalog and\n * displayed.\n */\n allowedKinds?: string[];\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityKindPicker = (props: EntityKindPickerProps) => {\n const { allowedKinds, hidden, initialFilter = 'component' } = props;\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n const alertApi = useApi(alertApiRef);\n\n const { error, allKinds, selectedKind, setSelectedKind } =\n useEntityKindFilter({\n initialFilter: initialFilter,\n });\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityKindPicker.errorMessage'),\n severity: 'error',\n });\n }\n }, [error, alertApi, t]);\n\n if (error) return null;\n\n const options = filterKinds(allKinds, allowedKinds, selectedKind);\n\n const items = [...options.entries()].map(([key, value]) => ({\n label: value,\n value: key,\n }));\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityKindPicker.title')}\n items={items}\n selected={selectedKind.toLocaleLowerCase('en-US')}\n onChange={value => setSelectedKind(String(value))}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"EntityKindPicker.esm.js","sources":["../../../src/components/EntityKindPicker/EntityKindPicker.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 */\n\nimport { Select } from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport Box from '@material-ui/core/Box';\nimport { useEffect, useMemo, useState } from 'react';\nimport { EntityKindFilter } from '../../filters';\nimport { useEntityList } from '../../hooks';\nimport { filterKinds, useAllKinds } from './kindFilterUtils';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nfunction useEntityKindFilter(opts: { initialFilter: string }): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n selectedKind: string;\n setSelectedKind: (kind: string) => void;\n} {\n const {\n filters,\n queryParameters: { kind: kindParameter },\n updateFilters,\n } = useEntityList();\n\n const queryParamKind = useMemo(\n () => [kindParameter].flat()[0],\n [kindParameter],\n );\n\n const [selectedKind, setSelectedKind] = useState(\n queryParamKind ?? filters.kind?.value ?? opts.initialFilter,\n );\n\n // Set selected kinds on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamKind) {\n setSelectedKind(queryParamKind);\n }\n }, [queryParamKind]);\n\n // Set selected kind from filters; this happens when the kind filter is\n // updated from another component\n useEffect(() => {\n if (filters.kind?.value) {\n setSelectedKind(filters.kind?.value);\n }\n }, [filters.kind]);\n\n const { allKinds, loading, error } = useAllKinds();\n const selectedKindLabel = allKinds.get(selectedKind) || selectedKind;\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind\n ? new EntityKindFilter(selectedKind, selectedKindLabel)\n : undefined,\n });\n }, [selectedKind, selectedKindLabel, updateFilters]);\n\n return {\n loading,\n error,\n allKinds,\n selectedKind,\n setSelectedKind,\n };\n}\n\n/**\n * Props for {@link EntityKindPicker}.\n *\n * @public\n */\nexport interface EntityKindPickerProps {\n /**\n * Entity kinds to show in the dropdown; by default all kinds are fetched from the catalog and\n * displayed.\n */\n allowedKinds?: string[];\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityKindPicker = (props: EntityKindPickerProps) => {\n const { allowedKinds, hidden, initialFilter = 'component' } = props;\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n const alertApi = useApi(alertApiRef);\n\n const { error, allKinds, selectedKind, setSelectedKind } =\n useEntityKindFilter({\n initialFilter: initialFilter,\n });\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityKindPicker.errorMessage'),\n severity: 'error',\n });\n }\n }, [error, alertApi, t]);\n\n if (error) return null;\n\n const options = filterKinds(allKinds, allowedKinds, selectedKind);\n\n const items = [...options.entries()].map(([key, value]) => ({\n label: value,\n value: key,\n }));\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityKindPicker.title')}\n items={items}\n selected={selectedKind.toLowerCase()}\n onChange={value => setSelectedKind(String(value))}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -11,22 +11,20 @@ function useAllKinds() {
11
11
  } = useAsync(async () => {
12
12
  const { facets } = await catalogApi.getEntityFacets({ facets: ["kind"] });
13
13
  const kindFacets = (facets.kind ?? []).map((f) => f.value);
14
- return new Map(
15
- kindFacets.map((kind) => [kind.toLocaleLowerCase("en-US"), kind])
16
- );
14
+ return new Map(kindFacets.map((kind) => [kind.toLowerCase(), kind]));
17
15
  }, [catalogApi]);
18
16
  return { loading, error, allKinds: allKinds ?? /* @__PURE__ */ new Map() };
19
17
  }
20
18
  function filterKinds(allKinds, allowedKinds, forcedKinds) {
21
19
  let availableKinds = Array.from(allKinds.keys());
22
20
  if (allowedKinds) {
23
- availableKinds = allowedKinds.map((k) => k.toLocaleLowerCase("en-US")).filter((k) => allKinds.has(k));
21
+ availableKinds = allowedKinds.map((k) => k.toLowerCase()).filter((k) => allKinds.has(k));
24
22
  }
25
23
  const kindsMap = new Map(
26
24
  availableKinds.map((kind) => [kind, allKinds.get(kind) || kind])
27
25
  );
28
26
  if (forcedKinds && !kindsMap.has(forcedKinds)) {
29
- kindsMap.set(forcedKinds.toLocaleLowerCase("en-US"), forcedKinds);
27
+ kindsMap.set(forcedKinds.toLowerCase(), forcedKinds);
30
28
  }
31
29
  return kindsMap;
32
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"kindFilterUtils.esm.js","sources":["../../../src/components/EntityKindPicker/kindFilterUtils.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\n\n/**\n * Fetch and return all available kinds.\n */\nexport function useAllKinds(): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n} {\n const catalogApi = useApi(catalogApiRef);\n\n const {\n error,\n loading,\n value: allKinds,\n } = useAsync(async () => {\n const { facets } = await catalogApi.getEntityFacets({ facets: ['kind'] });\n const kindFacets = (facets.kind ?? []).map(f => f.value);\n return new Map(\n kindFacets.map(kind => [kind.toLocaleLowerCase('en-US'), kind]),\n );\n }, [catalogApi]);\n\n return { loading, error, allKinds: allKinds ?? new Map() };\n}\n\n/**\n * Filter and capitalize accessible kinds.\n */\nexport function filterKinds(\n allKinds: Map<string, string>,\n allowedKinds?: string[],\n forcedKinds?: string,\n): Map<string, string> {\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n let availableKinds = Array.from(allKinds.keys());\n if (allowedKinds) {\n availableKinds = allowedKinds\n .map(k => k.toLocaleLowerCase('en-US'))\n .filter(k => allKinds.has(k));\n }\n\n const kindsMap = new Map(\n availableKinds.map(kind => [kind, allKinds.get(kind) || kind]),\n );\n\n if (forcedKinds && !kindsMap.has(forcedKinds)) {\n // this is the only time we set a label for a kind which is not properly capitalized\n kindsMap.set(forcedKinds.toLocaleLowerCase('en-US'), forcedKinds);\n }\n\n return kindsMap;\n}\n"],"names":[],"mappings":";;;;AAuBO,SAAS,WAAA,GAId;AACA,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA,EAAO;AAAA,GACT,GAAI,SAAS,YAAY;AACvB,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,UAAA,CAAW,eAAA,CAAgB,EAAE,MAAA,EAAQ,CAAC,MAAM,CAAA,EAAG,CAAA;AACxE,IAAA,MAAM,UAAA,GAAA,CAAc,OAAO,IAAA,IAAQ,IAAI,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,KAAK,CAAA;AACvD,IAAA,OAAO,IAAI,GAAA;AAAA,MACT,UAAA,CAAW,IAAI,CAAA,IAAA,KAAQ,CAAC,KAAK,iBAAA,CAAkB,OAAO,CAAA,EAAG,IAAI,CAAC;AAAA,KAChE;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,UAAU,QAAA,oBAAY,IAAI,KAAI,EAAE;AAC3D;AAKO,SAAS,WAAA,CACd,QAAA,EACA,YAAA,EACA,WAAA,EACqB;AAMrB,EAAA,IAAI,cAAA,GAAiB,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA;AAC/C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,cAAA,GAAiB,YAAA,CACd,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,iBAAA,CAAkB,OAAO,CAAC,CAAA,CACrC,MAAA,CAAO,CAAA,CAAA,KAAK,QAAA,CAAS,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA,EAChC;AAEA,EAAA,MAAM,WAAW,IAAI,GAAA;AAAA,IACnB,cAAA,CAAe,GAAA,CAAI,CAAA,IAAA,KAAQ,CAAC,IAAA,EAAM,SAAS,GAAA,CAAI,IAAI,CAAA,IAAK,IAAI,CAAC;AAAA,GAC/D;AAEA,EAAA,IAAI,WAAA,IAAe,CAAC,QAAA,CAAS,GAAA,CAAI,WAAW,CAAA,EAAG;AAE7C,IAAA,QAAA,CAAS,GAAA,CAAI,WAAA,CAAY,iBAAA,CAAkB,OAAO,GAAG,WAAW,CAAA;AAAA,EAClE;AAEA,EAAA,OAAO,QAAA;AACT;;;;"}
1
+ {"version":3,"file":"kindFilterUtils.esm.js","sources":["../../../src/components/EntityKindPicker/kindFilterUtils.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../api';\n\n/**\n * Fetch and return all available kinds.\n */\nexport function useAllKinds(): {\n loading: boolean;\n error?: Error;\n allKinds: Map<string, string>;\n} {\n const catalogApi = useApi(catalogApiRef);\n\n const {\n error,\n loading,\n value: allKinds,\n } = useAsync(async () => {\n const { facets } = await catalogApi.getEntityFacets({ facets: ['kind'] });\n const kindFacets = (facets.kind ?? []).map(f => f.value);\n return new Map(kindFacets.map(kind => [kind.toLowerCase(), kind]));\n }, [catalogApi]);\n\n return { loading, error, allKinds: allKinds ?? new Map() };\n}\n\n/**\n * Filter and capitalize accessible kinds.\n */\nexport function filterKinds(\n allKinds: Map<string, string>,\n allowedKinds?: string[],\n forcedKinds?: string,\n): Map<string, string> {\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n let availableKinds = Array.from(allKinds.keys());\n if (allowedKinds) {\n availableKinds = allowedKinds\n .map(k => k.toLowerCase())\n .filter(k => allKinds.has(k));\n }\n\n const kindsMap = new Map(\n availableKinds.map(kind => [kind, allKinds.get(kind) || kind]),\n );\n\n if (forcedKinds && !kindsMap.has(forcedKinds)) {\n // this is the only time we set a label for a kind which is not properly capitalized\n kindsMap.set(forcedKinds.toLowerCase(), forcedKinds);\n }\n\n return kindsMap;\n}\n"],"names":[],"mappings":";;;;AAuBO,SAAS,WAAA,GAId;AACA,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA,EAAO;AAAA,GACT,GAAI,SAAS,YAAY;AACvB,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,UAAA,CAAW,eAAA,CAAgB,EAAE,MAAA,EAAQ,CAAC,MAAM,CAAA,EAAG,CAAA;AACxE,IAAA,MAAM,UAAA,GAAA,CAAc,OAAO,IAAA,IAAQ,IAAI,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,KAAK,CAAA;AACvD,IAAA,OAAO,IAAI,GAAA,CAAI,UAAA,CAAW,GAAA,CAAI,CAAA,IAAA,KAAQ,CAAC,IAAA,CAAK,WAAA,EAAY,EAAG,IAAI,CAAC,CAAC,CAAA;AAAA,EACnE,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,UAAU,QAAA,oBAAY,IAAI,KAAI,EAAE;AAC3D;AAKO,SAAS,WAAA,CACd,QAAA,EACA,YAAA,EACA,WAAA,EACqB;AAMrB,EAAA,IAAI,cAAA,GAAiB,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA;AAC/C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,cAAA,GAAiB,YAAA,CACd,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,WAAA,EAAa,CAAA,CACxB,MAAA,CAAO,CAAA,CAAA,KAAK,QAAA,CAAS,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA,EAChC;AAEA,EAAA,MAAM,WAAW,IAAI,GAAA;AAAA,IACnB,cAAA,CAAe,GAAA,CAAI,CAAA,IAAA,KAAQ,CAAC,IAAA,EAAM,SAAS,GAAA,CAAI,IAAI,CAAA,IAAK,IAAI,CAAC;AAAA,GAC/D;AAEA,EAAA,IAAI,WAAA,IAAe,CAAC,QAAA,CAAS,GAAA,CAAI,WAAW,CAAA,EAAG;AAE7C,IAAA,QAAA,CAAS,GAAA,CAAI,WAAA,CAAY,WAAA,EAAY,EAAG,WAAW,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,QAAA;AACT;;;;"}
@@ -56,7 +56,7 @@ const icon = /* @__PURE__ */ jsx(CheckBoxOutlineBlankIcon, { fontSize: "small" }
56
56
  const checkedIcon = /* @__PURE__ */ jsx(CheckBoxIcon, { fontSize: "small" });
57
57
  function RenderOptionLabel(props) {
58
58
  const classes = useStyles();
59
- const isGroup = props.entity.kind.toLocaleLowerCase("en-US") === "group";
59
+ const isGroup = props.entity.kind.toLowerCase() === "group";
60
60
  const entityOrRef = props.mode === "owners-only" ? stringifyEntityRef(props.entity) : props.entity;
61
61
  const { primaryTitle: title } = useEntityPresentation(entityOrRef);
62
62
  return /* @__PURE__ */ jsx(Box, { className: classes.fullWidth, children: /* @__PURE__ */ jsx(
@@ -104,7 +104,7 @@ const EntityOwnerPicker = (props) => {
104
104
  initialSelectedOwnersRefs: selectedOwners
105
105
  });
106
106
  useDebouncedEffect(
107
- () => handleFetch({ text: text.toLocaleLowerCase("en-US") }),
107
+ () => handleFetch({ text: text.toLowerCase() }),
108
108
  [text, handleFetch],
109
109
  250
110
110
  );
@@ -120,9 +120,7 @@ const EntityOwnerPicker = (props) => {
120
120
  owners: selectedOwners.length ? new EntityOwnerFilter(selectedOwners) : void 0
121
121
  });
122
122
  }, [selectedOwners, updateFilters]);
123
- if (["user", "group"].includes(
124
- filters.kind?.value.toLocaleLowerCase("en-US") || ""
125
- )) {
123
+ if (["user", "group"].includes(filters.kind?.value.toLowerCase() || "")) {
126
124
  return null;
127
125
  }
128
126
  return /* @__PURE__ */ jsx(Box, { className: classes.root, pb: 1, pt: 1, children: /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"EntityOwnerPicker.esm.js","sources":["../../../src/components/EntityOwnerPicker/EntityOwnerPicker.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 */\n\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport Box from '@material-ui/core/Box';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Typography from '@material-ui/core/Typography';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport { MouseEvent, useEffect, useMemo, useState } from 'react';\nimport { useEntityList } from '../../hooks/useEntityListProvider';\nimport { EntityOwnerFilter } from '../../filters';\nimport { useDebouncedEffect } from '@react-hookz/web';\nimport PersonIcon from '@material-ui/icons/Person';\nimport GroupIcon from '@material-ui/icons/Group';\nimport {\n entityPresentationApiRef,\n entityPresentationSnapshot,\n} from '../../apis';\nimport { useFetchEntities } from './useFetchEntities';\nimport { VirtualizedListbox } from './VirtualizedListbox';\nimport { withStyles } from '@material-ui/core/styles';\nimport { useEntityPresentation } from '../../apis';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useApiHolder } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { CatalogAutocomplete } from '../CatalogAutocomplete';\n\n/** @public */\nexport type CatalogReactEntityOwnerPickerClassKey = 'input';\n\nconst useStyles = makeStyles(\n {\n root: {},\n label: {},\n input: {},\n fullWidth: { width: '100%' },\n boxLabel: {\n width: '100%',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n },\n },\n { name: 'CatalogReactEntityOwnerPicker' },\n);\n\n/** @public */\nexport type FixedWidthFormControlLabelClassKey = 'label' | 'root';\n\nconst FixedWidthFormControlLabel = withStyles(\n _theme => ({\n label: {\n width: '100%',\n },\n root: {\n width: '90%',\n },\n }),\n { name: 'FixedWidthFormControlLabel' },\n)(FormControlLabel);\n\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\n/**\n * @public\n */\nexport type EntityOwnerPickerProps = {\n mode?: 'owners-only' | 'all';\n};\n\nfunction RenderOptionLabel(props: {\n entity: Entity;\n isSelected: boolean;\n mode: 'owners-only' | 'all';\n}) {\n const classes = useStyles();\n const isGroup = props.entity.kind.toLocaleLowerCase('en-US') === 'group';\n // owners-only stubs lack title/displayName; pass ref string so the presentation API fetches the full entity.\n const entityOrRef: Entity | string =\n props.mode === 'owners-only'\n ? stringifyEntityRef(props.entity)\n : props.entity;\n const { primaryTitle: title } = useEntityPresentation(entityOrRef);\n return (\n <Box className={classes.fullWidth}>\n <FixedWidthFormControlLabel\n className={classes.fullWidth}\n control={\n <Checkbox\n icon={icon}\n checkedIcon={checkedIcon}\n checked={props.isSelected}\n />\n }\n onClick={event => event.preventDefault()}\n label={\n <Tooltip title={title}>\n <Box display=\"flex\" alignItems=\"center\">\n {isGroup ? (\n <GroupIcon fontSize=\"small\" />\n ) : (\n <PersonIcon fontSize=\"small\" />\n )}\n &nbsp;\n <Box className={classes.boxLabel}>\n <Typography noWrap>{title}</Typography>\n </Box>\n </Box>\n </Tooltip>\n }\n />\n </Box>\n );\n}\n\n/** @public */\nexport const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => {\n const classes = useStyles();\n const { mode = 'owners-only' } = props || {};\n const apis = useApiHolder();\n const entityPresentationApi = apis.get(entityPresentationApiRef);\n const {\n updateFilters,\n filters,\n queryParameters: { owners: ownersParameter },\n } = useEntityList();\n\n const [text, setText] = useState('');\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n const queryParamOwners = useMemo(\n () => [ownersParameter].flat().filter(Boolean) as string[],\n [ownersParameter],\n );\n\n // Query parameters may contain humanized refs (e.g. `guests` rather than\n // `group:default/guests`), so they are normalized before being stored.\n const [selectedOwners, setSelectedOwners] = useState<string[]>(\n queryParamOwners.length\n ? new EntityOwnerFilter(queryParamOwners).values\n : filters.owners?.values ?? [],\n );\n\n const [{ value, loading }, handleFetch, cache] = useFetchEntities({\n mode,\n initialSelectedOwnersRefs: selectedOwners,\n });\n useDebouncedEffect(\n () => handleFetch({ text: text.toLocaleLowerCase('en-US') }),\n [text, handleFetch],\n 250,\n );\n\n const availableOwners = value?.items || [];\n\n // Set selected owners on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamOwners.length) {\n const filter = new EntityOwnerFilter(queryParamOwners);\n setSelectedOwners(filter.values);\n }\n }, [queryParamOwners]);\n\n useEffect(() => {\n updateFilters({\n owners: selectedOwners.length\n ? new EntityOwnerFilter(selectedOwners)\n : undefined,\n });\n }, [selectedOwners, updateFilters]);\n\n if (\n ['user', 'group'].includes(\n filters.kind?.value.toLocaleLowerCase('en-US') || '',\n )\n ) {\n return null;\n }\n\n return (\n <Box className={classes.root} pb={1} pt={1}>\n <CatalogAutocomplete<Entity, true>\n label={t('entityOwnerPicker.title')}\n multiple\n disableCloseOnSelect\n loading={loading}\n options={availableOwners}\n value={selectedOwners as unknown as Entity[]}\n getOptionSelected={(o, v) => {\n if (typeof v === 'string') {\n return stringifyEntityRef(o) === v;\n }\n return o === v;\n }}\n getOptionLabel={o => {\n if (mode === 'owners-only') {\n // Stubs have no title; use string ref so entityPresentationSnapshot hits the API cache.\n const ref = typeof o === 'string' ? o : stringifyEntityRef(o);\n return entityPresentationSnapshot(\n ref,\n undefined,\n entityPresentationApi,\n ).primaryTitle;\n }\n const entity =\n typeof o === 'string'\n ? cache.getEntity(o) ||\n parseEntityRef(o, {\n defaultKind: 'group',\n defaultNamespace: 'default',\n })\n : o;\n return entityPresentationSnapshot(\n entity,\n undefined,\n entityPresentationApi,\n ).primaryTitle;\n }}\n onChange={(_: object, owners) => {\n setText('');\n setSelectedOwners(\n owners.map(e => {\n const entityRef =\n typeof e === 'string' ? e : stringifyEntityRef(e);\n\n if (typeof e !== 'string') {\n cache.setEntity(e);\n }\n return entityRef;\n }),\n );\n }}\n filterOptions={x => x}\n renderOption={(entity, { selected }) => {\n return (\n <RenderOptionLabel\n entity={entity}\n isSelected={selected}\n mode={mode}\n />\n );\n }}\n name=\"owner-picker\"\n onInputChange={(_e, inputValue) => {\n setText(inputValue);\n }}\n ListboxComponent={VirtualizedListbox}\n ListboxProps={{\n onScroll: (e: MouseEvent) => {\n const element = e.currentTarget;\n const hasReachedEnd =\n Math.abs(\n element.scrollHeight - element.clientHeight - element.scrollTop,\n ) < 1;\n\n if (hasReachedEnd && value?.cursor) {\n handleFetch({ items: value.items, cursor: value.cursor });\n }\n },\n 'data-testid': 'owner-picker-listbox',\n }}\n LabelProps={{ className: classes.label }}\n TextFieldProps={{ className: classes.input }}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB;AAAA,IACE,MAAM,EAAC;AAAA,IACP,OAAO,EAAC;AAAA,IACR,OAAO,EAAC;AAAA,IACR,SAAA,EAAW,EAAE,KAAA,EAAO,MAAA,EAAO;AAAA,IAC3B,QAAA,EAAU;AAAA,MACR,KAAA,EAAO,MAAA;AAAA,MACP,YAAA,EAAc,UAAA;AAAA,MACd,QAAA,EAAU;AAAA;AACZ,GACF;AAAA,EACA,EAAE,MAAM,+BAAA;AACV,CAAA;AAKA,MAAM,0BAAA,GAA6B,UAAA;AAAA,EACjC,CAAA,MAAA,MAAW;AAAA,IACT,KAAA,EAAO;AAAA,MACL,KAAA,EAAO;AAAA,KACT;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,KAAA,EAAO;AAAA;AACT,GACF,CAAA;AAAA,EACA,EAAE,MAAM,4BAAA;AACV,CAAA,CAAE,gBAAgB,CAAA;AAElB,MAAM,IAAA,mBAAO,GAAA,CAAC,wBAAA,EAAA,EAAyB,QAAA,EAAS,OAAA,EAAQ,CAAA;AACxD,MAAM,WAAA,mBAAc,GAAA,CAAC,YAAA,EAAA,EAAa,QAAA,EAAS,OAAA,EAAQ,CAAA;AASnD,SAAS,kBAAkB,KAAA,EAIxB;AACD,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,UAAU,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO,CAAA,KAAM,OAAA;AAEjE,EAAA,MAAM,WAAA,GACJ,MAAM,IAAA,KAAS,aAAA,GACX,mBAAmB,KAAA,CAAM,MAAM,IAC/B,KAAA,CAAM,MAAA;AACZ,EAAA,MAAM,EAAE,YAAA,EAAc,KAAA,EAAM,GAAI,sBAAsB,WAAW,CAAA;AACjE,EAAA,uBACE,GAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,SAAA,EACtB,QAAA,kBAAA,GAAA;AAAA,IAAC,0BAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAA,CAAQ,SAAA;AAAA,MACnB,OAAA,kBACE,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA;AAAA,UACA,WAAA;AAAA,UACA,SAAS,KAAA,CAAM;AAAA;AAAA,OACjB;AAAA,MAEF,OAAA,EAAS,CAAA,KAAA,KAAS,KAAA,CAAM,cAAA,EAAe;AAAA,MACvC,KAAA,sBACG,OAAA,EAAA,EAAQ,KAAA,EACP,+BAAC,GAAA,EAAA,EAAI,OAAA,EAAQ,MAAA,EAAO,UAAA,EAAW,QAAA,EAC5B,QAAA,EAAA;AAAA,QAAA,OAAA,mBACC,GAAA,CAAC,aAAU,QAAA,EAAS,OAAA,EAAQ,oBAE5B,GAAA,CAAC,UAAA,EAAA,EAAW,UAAS,OAAA,EAAQ,CAAA;AAAA,QAC7B,MAAA;AAAA,wBAEF,GAAA,CAAC,GAAA,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,QAAA,EACtB,8BAAC,UAAA,EAAA,EAAW,MAAA,EAAM,IAAA,EAAE,QAAA,EAAA,KAAA,EAAM,CAAA,EAC5B;AAAA,OAAA,EACF,CAAA,EACF;AAAA;AAAA,GAEJ,EACF,CAAA;AAEJ;AAGO,MAAM,iBAAA,GAAoB,CAAC,KAAA,KAAmC;AACnE,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,EAAE,IAAA,GAAO,aAAA,EAAc,GAAI,SAAS,EAAC;AAC3C,EAAA,MAAM,OAAO,YAAA,EAAa;AAC1B,EAAA,MAAM,qBAAA,GAAwB,IAAA,CAAK,GAAA,CAAI,wBAAwB,CAAA;AAC/D,EAAA,MAAM;AAAA,IACJ,aAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA,EAAiB,EAAE,MAAA,EAAQ,eAAA;AAAgB,MACzC,aAAA,EAAc;AAElB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,EAAE,CAAA;AACnC,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAA,MAAM,gBAAA,GAAmB,OAAA;AAAA,IACvB,MAAM,CAAC,eAAe,EAAE,IAAA,EAAK,CAAE,OAAO,OAAO,CAAA;AAAA,IAC7C,CAAC,eAAe;AAAA,GAClB;AAIA,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA;AAAA,IAC1C,gBAAA,CAAiB,MAAA,GACb,IAAI,iBAAA,CAAkB,gBAAgB,EAAE,MAAA,GACxC,OAAA,CAAQ,MAAA,EAAQ,MAAA,IAAU;AAAC,GACjC;AAEA,EAAA,MAAM,CAAC,EAAE,KAAA,EAAO,OAAA,IAAW,WAAA,EAAa,KAAK,IAAI,gBAAA,CAAiB;AAAA,IAChE,IAAA;AAAA,IACA,yBAAA,EAA2B;AAAA,GAC5B,CAAA;AACD,EAAA,kBAAA;AAAA,IACE,MAAM,YAAY,EAAE,IAAA,EAAM,KAAK,iBAAA,CAAkB,OAAO,GAAG,CAAA;AAAA,IAC3D,CAAC,MAAM,WAAW,CAAA;AAAA,IAClB;AAAA,GACF;AAEA,EAAA,MAAM,eAAA,GAAkB,KAAA,EAAO,KAAA,IAAS,EAAC;AAIzC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,iBAAiB,MAAA,EAAQ;AAC3B,MAAA,MAAM,MAAA,GAAS,IAAI,iBAAA,CAAkB,gBAAgB,CAAA;AACrD,MAAA,iBAAA,CAAkB,OAAO,MAAM,CAAA;AAAA,IACjC;AAAA,EACF,CAAA,EAAG,CAAC,gBAAgB,CAAC,CAAA;AAErB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,aAAA,CAAc;AAAA,MACZ,QAAQ,cAAA,CAAe,MAAA,GACnB,IAAI,iBAAA,CAAkB,cAAc,CAAA,GACpC;AAAA,KACL,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,cAAA,EAAgB,aAAa,CAAC,CAAA;AAElC,EAAA,IACE,CAAC,MAAA,EAAQ,OAAO,CAAA,CAAE,QAAA;AAAA,IAChB,OAAA,CAAQ,IAAA,EAAM,KAAA,CAAM,iBAAA,CAAkB,OAAO,CAAA,IAAK;AAAA,GACpD,EACA;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAC,OAAI,SAAA,EAAW,OAAA,CAAQ,MAAM,EAAA,EAAI,CAAA,EAAG,IAAI,CAAA,EACvC,QAAA,kBAAA,GAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,MAClC,QAAA,EAAQ,IAAA;AAAA,MACR,oBAAA,EAAoB,IAAA;AAAA,MACpB,OAAA;AAAA,MACA,OAAA,EAAS,eAAA;AAAA,MACT,KAAA,EAAO,cAAA;AAAA,MACP,iBAAA,EAAmB,CAAC,CAAA,EAAG,CAAA,KAAM;AAC3B,QAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,UAAA,OAAO,kBAAA,CAAmB,CAAC,CAAA,KAAM,CAAA;AAAA,QACnC;AACA,QAAA,OAAO,CAAA,KAAM,CAAA;AAAA,MACf,CAAA;AAAA,MACA,gBAAgB,CAAA,CAAA,KAAK;AACnB,QAAA,IAAI,SAAS,aAAA,EAAe;AAE1B,UAAA,MAAM,MAAM,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,mBAAmB,CAAC,CAAA;AAC5D,UAAA,OAAO,0BAAA;AAAA,YACL,GAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WACF,CAAE,YAAA;AAAA,QACJ;AACA,QAAA,MAAM,MAAA,GACJ,OAAO,CAAA,KAAM,QAAA,GACT,MAAM,SAAA,CAAU,CAAC,CAAA,IACjB,cAAA,CAAe,CAAA,EAAG;AAAA,UAChB,WAAA,EAAa,OAAA;AAAA,UACb,gBAAA,EAAkB;AAAA,SACnB,CAAA,GACD,CAAA;AACN,QAAA,OAAO,0BAAA;AAAA,UACL,MAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACF,CAAE,YAAA;AAAA,MACJ,CAAA;AAAA,MACA,QAAA,EAAU,CAAC,CAAA,EAAW,MAAA,KAAW;AAC/B,QAAA,OAAA,CAAQ,EAAE,CAAA;AACV,QAAA,iBAAA;AAAA,UACE,MAAA,CAAO,IAAI,CAAA,CAAA,KAAK;AACd,YAAA,MAAM,YACJ,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,mBAAmB,CAAC,CAAA;AAElD,YAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,cAAA,KAAA,CAAM,UAAU,CAAC,CAAA;AAAA,YACnB;AACA,YAAA,OAAO,SAAA;AAAA,UACT,CAAC;AAAA,SACH;AAAA,MACF,CAAA;AAAA,MACA,eAAe,CAAA,CAAA,KAAK,CAAA;AAAA,MACpB,YAAA,EAAc,CAAC,MAAA,EAAQ,EAAE,UAAS,KAAM;AACtC,QAAA,uBACE,GAAA;AAAA,UAAC,iBAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,UAAA,EAAY,QAAA;AAAA,YACZ;AAAA;AAAA,SACF;AAAA,MAEJ,CAAA;AAAA,MACA,IAAA,EAAK,cAAA;AAAA,MACL,aAAA,EAAe,CAAC,EAAA,EAAI,UAAA,KAAe;AACjC,QAAA,OAAA,CAAQ,UAAU,CAAA;AAAA,MACpB,CAAA;AAAA,MACA,gBAAA,EAAkB,kBAAA;AAAA,MAClB,YAAA,EAAc;AAAA,QACZ,QAAA,EAAU,CAAC,CAAA,KAAkB;AAC3B,UAAA,MAAM,UAAU,CAAA,CAAE,aAAA;AAClB,UAAA,MAAM,gBACJ,IAAA,CAAK,GAAA;AAAA,YACH,OAAA,CAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA,GAAe,OAAA,CAAQ;AAAA,WACxD,GAAI,CAAA;AAEN,UAAA,IAAI,aAAA,IAAiB,OAAO,MAAA,EAAQ;AAClC,YAAA,WAAA,CAAY,EAAE,KAAA,EAAO,KAAA,CAAM,OAAO,MAAA,EAAQ,KAAA,CAAM,QAAQ,CAAA;AAAA,UAC1D;AAAA,QACF,CAAA;AAAA,QACA,aAAA,EAAe;AAAA,OACjB;AAAA,MACA,UAAA,EAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,KAAA,EAAM;AAAA,MACvC,cAAA,EAAgB,EAAE,SAAA,EAAW,OAAA,CAAQ,KAAA;AAAM;AAAA,GAC7C,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityOwnerPicker.esm.js","sources":["../../../src/components/EntityOwnerPicker/EntityOwnerPicker.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 */\n\nimport {\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport Box from '@material-ui/core/Box';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Typography from '@material-ui/core/Typography';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport { MouseEvent, useEffect, useMemo, useState } from 'react';\nimport { useEntityList } from '../../hooks/useEntityListProvider';\nimport { EntityOwnerFilter } from '../../filters';\nimport { useDebouncedEffect } from '@react-hookz/web';\nimport PersonIcon from '@material-ui/icons/Person';\nimport GroupIcon from '@material-ui/icons/Group';\nimport {\n entityPresentationApiRef,\n entityPresentationSnapshot,\n} from '../../apis';\nimport { useFetchEntities } from './useFetchEntities';\nimport { VirtualizedListbox } from './VirtualizedListbox';\nimport { withStyles } from '@material-ui/core/styles';\nimport { useEntityPresentation } from '../../apis';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useApiHolder } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { CatalogAutocomplete } from '../CatalogAutocomplete';\n\n/** @public */\nexport type CatalogReactEntityOwnerPickerClassKey = 'input';\n\nconst useStyles = makeStyles(\n {\n root: {},\n label: {},\n input: {},\n fullWidth: { width: '100%' },\n boxLabel: {\n width: '100%',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n },\n },\n { name: 'CatalogReactEntityOwnerPicker' },\n);\n\n/** @public */\nexport type FixedWidthFormControlLabelClassKey = 'label' | 'root';\n\nconst FixedWidthFormControlLabel = withStyles(\n _theme => ({\n label: {\n width: '100%',\n },\n root: {\n width: '90%',\n },\n }),\n { name: 'FixedWidthFormControlLabel' },\n)(FormControlLabel);\n\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\n/**\n * @public\n */\nexport type EntityOwnerPickerProps = {\n mode?: 'owners-only' | 'all';\n};\n\nfunction RenderOptionLabel(props: {\n entity: Entity;\n isSelected: boolean;\n mode: 'owners-only' | 'all';\n}) {\n const classes = useStyles();\n const isGroup = props.entity.kind.toLowerCase() === 'group';\n // owners-only stubs lack title/displayName; pass ref string so the presentation API fetches the full entity.\n const entityOrRef: Entity | string =\n props.mode === 'owners-only'\n ? stringifyEntityRef(props.entity)\n : props.entity;\n const { primaryTitle: title } = useEntityPresentation(entityOrRef);\n return (\n <Box className={classes.fullWidth}>\n <FixedWidthFormControlLabel\n className={classes.fullWidth}\n control={\n <Checkbox\n icon={icon}\n checkedIcon={checkedIcon}\n checked={props.isSelected}\n />\n }\n onClick={event => event.preventDefault()}\n label={\n <Tooltip title={title}>\n <Box display=\"flex\" alignItems=\"center\">\n {isGroup ? (\n <GroupIcon fontSize=\"small\" />\n ) : (\n <PersonIcon fontSize=\"small\" />\n )}\n &nbsp;\n <Box className={classes.boxLabel}>\n <Typography noWrap>{title}</Typography>\n </Box>\n </Box>\n </Tooltip>\n }\n />\n </Box>\n );\n}\n\n/** @public */\nexport const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => {\n const classes = useStyles();\n const { mode = 'owners-only' } = props || {};\n const apis = useApiHolder();\n const entityPresentationApi = apis.get(entityPresentationApiRef);\n const {\n updateFilters,\n filters,\n queryParameters: { owners: ownersParameter },\n } = useEntityList();\n\n const [text, setText] = useState('');\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n const queryParamOwners = useMemo(\n () => [ownersParameter].flat().filter(Boolean) as string[],\n [ownersParameter],\n );\n\n // Query parameters may contain humanized refs (e.g. `guests` rather than\n // `group:default/guests`), so they are normalized before being stored.\n const [selectedOwners, setSelectedOwners] = useState<string[]>(\n queryParamOwners.length\n ? new EntityOwnerFilter(queryParamOwners).values\n : filters.owners?.values ?? [],\n );\n\n const [{ value, loading }, handleFetch, cache] = useFetchEntities({\n mode,\n initialSelectedOwnersRefs: selectedOwners,\n });\n useDebouncedEffect(\n () => handleFetch({ text: text.toLowerCase() }),\n [text, handleFetch],\n 250,\n );\n\n const availableOwners = value?.items || [];\n\n // Set selected owners on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (queryParamOwners.length) {\n const filter = new EntityOwnerFilter(queryParamOwners);\n setSelectedOwners(filter.values);\n }\n }, [queryParamOwners]);\n\n useEffect(() => {\n updateFilters({\n owners: selectedOwners.length\n ? new EntityOwnerFilter(selectedOwners)\n : undefined,\n });\n }, [selectedOwners, updateFilters]);\n\n if (['user', 'group'].includes(filters.kind?.value.toLowerCase() || '')) {\n return null;\n }\n\n return (\n <Box className={classes.root} pb={1} pt={1}>\n <CatalogAutocomplete<Entity, true>\n label={t('entityOwnerPicker.title')}\n multiple\n disableCloseOnSelect\n loading={loading}\n options={availableOwners}\n value={selectedOwners as unknown as Entity[]}\n getOptionSelected={(o, v) => {\n if (typeof v === 'string') {\n return stringifyEntityRef(o) === v;\n }\n return o === v;\n }}\n getOptionLabel={o => {\n if (mode === 'owners-only') {\n // Stubs have no title; use string ref so entityPresentationSnapshot hits the API cache.\n const ref = typeof o === 'string' ? o : stringifyEntityRef(o);\n return entityPresentationSnapshot(\n ref,\n undefined,\n entityPresentationApi,\n ).primaryTitle;\n }\n const entity =\n typeof o === 'string'\n ? cache.getEntity(o) ||\n parseEntityRef(o, {\n defaultKind: 'group',\n defaultNamespace: 'default',\n })\n : o;\n return entityPresentationSnapshot(\n entity,\n undefined,\n entityPresentationApi,\n ).primaryTitle;\n }}\n onChange={(_: object, owners) => {\n setText('');\n setSelectedOwners(\n owners.map(e => {\n const entityRef =\n typeof e === 'string' ? e : stringifyEntityRef(e);\n\n if (typeof e !== 'string') {\n cache.setEntity(e);\n }\n return entityRef;\n }),\n );\n }}\n filterOptions={x => x}\n renderOption={(entity, { selected }) => {\n return (\n <RenderOptionLabel\n entity={entity}\n isSelected={selected}\n mode={mode}\n />\n );\n }}\n name=\"owner-picker\"\n onInputChange={(_e, inputValue) => {\n setText(inputValue);\n }}\n ListboxComponent={VirtualizedListbox}\n ListboxProps={{\n onScroll: (e: MouseEvent) => {\n const element = e.currentTarget;\n const hasReachedEnd =\n Math.abs(\n element.scrollHeight - element.clientHeight - element.scrollTop,\n ) < 1;\n\n if (hasReachedEnd && value?.cursor) {\n handleFetch({ items: value.items, cursor: value.cursor });\n }\n },\n 'data-testid': 'owner-picker-listbox',\n }}\n LabelProps={{ className: classes.label }}\n TextFieldProps={{ className: classes.input }}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -25,8 +25,8 @@ function humanizeEntityRef(entityRef, opts) {
25
25
  } else if (namespace === DEFAULT_NAMESPACE) {
26
26
  namespace = void 0;
27
27
  }
28
- kind = kind.toLocaleLowerCase("en-US");
29
- kind = defaultKind && defaultKind.toLocaleLowerCase("en-US") === kind ? void 0 : kind;
28
+ kind = kind.toLowerCase();
29
+ kind = defaultKind && defaultKind.toLowerCase() === kind ? void 0 : kind;
30
30
  return `${kind ? `${kind}:` : ""}${namespace ? `${namespace}/` : ""}${name}`;
31
31
  }
32
32
 
@@ -1 +1 @@
1
- {"version":3,"file":"humanize.esm.js","sources":["../../../src/components/EntityRefLink/humanize.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n CompoundEntityRef,\n DEFAULT_NAMESPACE,\n} from '@backstage/catalog-model';\nimport get from 'lodash/get';\n\n/**\n * @param defaultNamespace - if set to false then namespace is never omitted,\n * if set to string which matches namespace of entity then omitted\n *\n * @deprecated Use {@link useEntityPresentation} or {@link EntityDisplayName}\n * in React components. In non-React contexts such as sort comparators or\n * data mappers, use {@link entityPresentationSnapshot}. These provide richer\n * display names using `metadata.title` and `spec.profile.displayName` in\n * addition to the entity ref.\n *\n * @public\n **/\nexport function humanizeEntityRef(\n entityRef: Entity | CompoundEntityRef,\n opts?: {\n defaultKind?: string;\n defaultNamespace?: string | false;\n },\n) {\n const defaultKind = opts?.defaultKind;\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in entityRef) {\n kind = entityRef.kind;\n namespace = entityRef.metadata.namespace;\n name = entityRef.metadata.name;\n } else {\n kind = entityRef.kind;\n namespace = entityRef.namespace;\n name = entityRef.name;\n }\n\n if (namespace === undefined || namespace === '') {\n namespace = DEFAULT_NAMESPACE;\n }\n if (opts?.defaultNamespace !== undefined) {\n if (opts?.defaultNamespace === namespace) {\n namespace = undefined;\n }\n } else if (namespace === DEFAULT_NAMESPACE) {\n namespace = undefined;\n }\n\n kind = kind.toLocaleLowerCase('en-US');\n kind =\n defaultKind && defaultKind.toLocaleLowerCase('en-US') === kind\n ? undefined\n : kind;\n return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`;\n}\n\n/**\n * Convert an entity to its more readable name if available.\n *\n * If an entity is either User or Group, this will be its `spec.profile.displayName`.\n * Otherwise, this is `metadata.title`.\n *\n * If neither of those are found or populated, fallback to `defaultName`.\n *\n * @deprecated Use {@link useEntityPresentation} or {@link EntityDisplayName}\n * in React components. In non-React contexts, use\n * {@link entityPresentationSnapshot}.\n *\n * @param entity - Entity to convert.\n * @param defaultName - If entity readable name is not available, `defaultName` will be returned.\n * @returns Readable name, defaults to `defaultName`.\n *\n */\nexport function humanizeEntity(entity: Entity, defaultName: string) {\n for (const path of ['spec.profile.displayName', 'metadata.title']) {\n const value = get(entity, path);\n if (value && typeof value === 'string') {\n return value;\n }\n }\n return defaultName;\n}\n"],"names":[],"mappings":";;;AAmCO,SAAS,iBAAA,CACd,WACA,IAAA,EAIA;AACA,EAAA,MAAM,cAAc,IAAA,EAAM,WAAA;AAC1B,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,cAAc,SAAA,EAAW;AAC3B,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AACjB,IAAA,SAAA,GAAY,UAAU,QAAA,CAAS,SAAA;AAC/B,IAAA,IAAA,GAAO,UAAU,QAAA,CAAS,IAAA;AAAA,EAC5B,CAAA,MAAO;AACL,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AACjB,IAAA,SAAA,GAAY,SAAA,CAAU,SAAA;AACtB,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AAAA,EACnB;AAEA,EAAA,IAAI,SAAA,KAAc,MAAA,IAAa,SAAA,KAAc,EAAA,EAAI;AAC/C,IAAA,SAAA,GAAY,iBAAA;AAAA,EACd;AACA,EAAA,IAAI,IAAA,EAAM,qBAAqB,MAAA,EAAW;AACxC,IAAA,IAAI,IAAA,EAAM,qBAAqB,SAAA,EAAW;AACxC,MAAA,SAAA,GAAY,MAAA;AAAA,IACd;AAAA,EACF,CAAA,MAAA,IAAW,cAAc,iBAAA,EAAmB;AAC1C,IAAA,SAAA,GAAY,MAAA;AAAA,EACd;AAEA,EAAA,IAAA,GAAO,IAAA,CAAK,kBAAkB,OAAO,CAAA;AACrC,EAAA,IAAA,GACE,eAAe,WAAA,CAAY,iBAAA,CAAkB,OAAO,CAAA,KAAM,OACtD,MAAA,GACA,IAAA;AACN,EAAA,OAAO,CAAA,EAAG,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,EAAG,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,CAAA,GAAM,EAAE,GAAG,IAAI,CAAA,CAAA;AAC5E;;;;"}
1
+ {"version":3,"file":"humanize.esm.js","sources":["../../../src/components/EntityRefLink/humanize.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n CompoundEntityRef,\n DEFAULT_NAMESPACE,\n} from '@backstage/catalog-model';\nimport get from 'lodash/get';\n\n/**\n * @param defaultNamespace - if set to false then namespace is never omitted,\n * if set to string which matches namespace of entity then omitted\n *\n * @deprecated Use {@link useEntityPresentation} or {@link EntityDisplayName}\n * in React components. In non-React contexts such as sort comparators or\n * data mappers, use {@link entityPresentationSnapshot}. These provide richer\n * display names using `metadata.title` and `spec.profile.displayName` in\n * addition to the entity ref.\n *\n * @public\n **/\nexport function humanizeEntityRef(\n entityRef: Entity | CompoundEntityRef,\n opts?: {\n defaultKind?: string;\n defaultNamespace?: string | false;\n },\n) {\n const defaultKind = opts?.defaultKind;\n let kind;\n let namespace;\n let name;\n\n if ('metadata' in entityRef) {\n kind = entityRef.kind;\n namespace = entityRef.metadata.namespace;\n name = entityRef.metadata.name;\n } else {\n kind = entityRef.kind;\n namespace = entityRef.namespace;\n name = entityRef.name;\n }\n\n if (namespace === undefined || namespace === '') {\n namespace = DEFAULT_NAMESPACE;\n }\n if (opts?.defaultNamespace !== undefined) {\n if (opts?.defaultNamespace === namespace) {\n namespace = undefined;\n }\n } else if (namespace === DEFAULT_NAMESPACE) {\n namespace = undefined;\n }\n\n kind = kind.toLowerCase();\n kind = defaultKind && defaultKind.toLowerCase() === kind ? undefined : kind;\n return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`;\n}\n\n/**\n * Convert an entity to its more readable name if available.\n *\n * If an entity is either User or Group, this will be its `spec.profile.displayName`.\n * Otherwise, this is `metadata.title`.\n *\n * If neither of those are found or populated, fallback to `defaultName`.\n *\n * @deprecated Use {@link useEntityPresentation} or {@link EntityDisplayName}\n * in React components. In non-React contexts, use\n * {@link entityPresentationSnapshot}.\n *\n * @param entity - Entity to convert.\n * @param defaultName - If entity readable name is not available, `defaultName` will be returned.\n * @returns Readable name, defaults to `defaultName`.\n *\n */\nexport function humanizeEntity(entity: Entity, defaultName: string) {\n for (const path of ['spec.profile.displayName', 'metadata.title']) {\n const value = get(entity, path);\n if (value && typeof value === 'string') {\n return value;\n }\n }\n return defaultName;\n}\n"],"names":[],"mappings":";;;AAmCO,SAAS,iBAAA,CACd,WACA,IAAA,EAIA;AACA,EAAA,MAAM,cAAc,IAAA,EAAM,WAAA;AAC1B,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,cAAc,SAAA,EAAW;AAC3B,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AACjB,IAAA,SAAA,GAAY,UAAU,QAAA,CAAS,SAAA;AAC/B,IAAA,IAAA,GAAO,UAAU,QAAA,CAAS,IAAA;AAAA,EAC5B,CAAA,MAAO;AACL,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AACjB,IAAA,SAAA,GAAY,SAAA,CAAU,SAAA;AACtB,IAAA,IAAA,GAAO,SAAA,CAAU,IAAA;AAAA,EACnB;AAEA,EAAA,IAAI,SAAA,KAAc,MAAA,IAAa,SAAA,KAAc,EAAA,EAAI;AAC/C,IAAA,SAAA,GAAY,iBAAA;AAAA,EACd;AACA,EAAA,IAAI,IAAA,EAAM,qBAAqB,MAAA,EAAW;AACxC,IAAA,IAAI,IAAA,EAAM,qBAAqB,SAAA,EAAW;AACxC,MAAA,SAAA,GAAY,MAAA;AAAA,IACd;AAAA,EACF,CAAA,MAAA,IAAW,cAAc,iBAAA,EAAmB;AAC1C,IAAA,SAAA,GAAY,MAAA;AAAA,EACd;AAEA,EAAA,IAAA,GAAO,KAAK,WAAA,EAAY;AACxB,EAAA,IAAA,GAAO,WAAA,IAAe,WAAA,CAAY,WAAA,EAAY,KAAM,OAAO,MAAA,GAAY,IAAA;AACvE,EAAA,OAAO,CAAA,EAAG,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,EAAG,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,CAAA,CAAA,GAAM,EAAE,GAAG,IAAI,CAAA,CAAA;AAC5E;;;;"}
@@ -24,9 +24,7 @@ const EntityTypePicker = (props) => {
24
24
  }
25
25
  }, [error, alertApi, initialFilter, setSelectedTypes, t]);
26
26
  if (availableTypes.length === 0 || error) return null;
27
- availableTypes.sort(
28
- (a, b) => a.toLocaleLowerCase("en-US").localeCompare(b.toLocaleLowerCase("en-US"))
29
- );
27
+ availableTypes.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
30
28
  const items = [
31
29
  { value: "all", label: t("entityTypePicker.optionAllTitle") },
32
30
  ...availableTypes.map((type) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"EntityTypePicker.esm.js","sources":["../../../src/components/EntityTypePicker/EntityTypePicker.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 */\n\nimport { useEffect } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';\n\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Select } from '@backstage/core-components';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Props for {@link EntityTypePicker}.\n *\n * @public\n */\nexport interface EntityTypePickerProps {\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityTypePicker = (props: EntityTypePickerProps) => {\n const { hidden, initialFilter } = props;\n const alertApi = useApi(alertApiRef);\n const { error, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityTypePicker.errorMessage'),\n severity: 'error',\n });\n }\n if (initialFilter) {\n setSelectedTypes([initialFilter]);\n }\n }, [error, alertApi, initialFilter, setSelectedTypes, t]);\n\n if (availableTypes.length === 0 || error) return null;\n\n availableTypes.sort((a, b) =>\n a.toLocaleLowerCase('en-US').localeCompare(b.toLocaleLowerCase('en-US')),\n );\n\n const items = [\n { value: 'all', label: t('entityTypePicker.optionAllTitle') },\n ...availableTypes.map((type: string) => ({\n value: type,\n label: type,\n })),\n ];\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityTypePicker.title')}\n items={items}\n selected={(items.length > 1 ? selectedTypes[0] : undefined) ?? 'all'}\n onChange={value =>\n setSelectedTypes(value === 'all' ? [] : [String(value)])\n }\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAoCO,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAiC;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAc,GAAI,KAAA;AAClC,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,EAAE,KAAA,EAAO,cAAA,EAAgB,aAAA,EAAe,gBAAA,KAC5C,mBAAA,EAAoB;AACtB,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,OAAA,EAAS,EAAE,+BAA+B,CAAA;AAAA,QAC1C,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH;AACA,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,gBAAA,CAAiB,CAAC,aAAa,CAAC,CAAA;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,KAAA,EAAO,UAAU,aAAA,EAAe,gBAAA,EAAkB,CAAC,CAAC,CAAA;AAExD,EAAA,IAAI,cAAA,CAAe,MAAA,KAAW,CAAA,IAAK,KAAA,EAAO,OAAO,IAAA;AAEjD,EAAA,cAAA,CAAe,IAAA;AAAA,IAAK,CAAC,CAAA,EAAG,CAAA,KACtB,CAAA,CAAE,iBAAA,CAAkB,OAAO,CAAA,CAAE,aAAA,CAAc,CAAA,CAAE,iBAAA,CAAkB,OAAO,CAAC;AAAA,GACzE;AAEA,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,CAAE,iCAAiC,CAAA,EAAE;AAAA,IAC5D,GAAG,cAAA,CAAe,GAAA,CAAI,CAAC,IAAA,MAAkB;AAAA,MACvC,KAAA,EAAO,IAAA;AAAA,MACP,KAAA,EAAO;AAAA,KACT,CAAE;AAAA,GACJ;AAEA,EAAA,OAAO,SAAS,IAAA,mBACd,GAAA,CAAC,OAAI,EAAA,EAAI,CAAA,EAAG,IAAI,CAAA,EACd,QAAA,kBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,KAAA;AAAA,MACA,WAAW,KAAA,CAAM,MAAA,GAAS,IAAI,aAAA,CAAc,CAAC,IAAI,MAAA,KAAc,KAAA;AAAA,MAC/D,QAAA,EAAU,CAAA,KAAA,KACR,gBAAA,CAAiB,KAAA,KAAU,KAAA,GAAQ,EAAC,GAAI,CAAC,MAAA,CAAO,KAAK,CAAC,CAAC;AAAA;AAAA,GAE3D,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityTypePicker.esm.js","sources":["../../../src/components/EntityTypePicker/EntityTypePicker.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 */\n\nimport { useEffect } from 'react';\nimport Box from '@material-ui/core/Box';\nimport { useEntityTypeFilter } from '../../hooks/useEntityTypeFilter';\n\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Select } from '@backstage/core-components';\nimport { catalogReactTranslationRef } from '../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\n/**\n * Props for {@link EntityTypePicker}.\n *\n * @public\n */\nexport interface EntityTypePickerProps {\n initialFilter?: string;\n hidden?: boolean;\n}\n\n/** @public */\nexport const EntityTypePicker = (props: EntityTypePickerProps) => {\n const { hidden, initialFilter } = props;\n const alertApi = useApi(alertApiRef);\n const { error, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n const { t } = useTranslationRef(catalogReactTranslationRef);\n\n useEffect(() => {\n if (error) {\n alertApi.post({\n message: t('entityTypePicker.errorMessage'),\n severity: 'error',\n });\n }\n if (initialFilter) {\n setSelectedTypes([initialFilter]);\n }\n }, [error, alertApi, initialFilter, setSelectedTypes, t]);\n\n if (availableTypes.length === 0 || error) return null;\n\n availableTypes.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\n const items = [\n { value: 'all', label: t('entityTypePicker.optionAllTitle') },\n ...availableTypes.map((type: string) => ({\n value: type,\n label: type,\n })),\n ];\n\n return hidden ? null : (\n <Box pb={1} pt={1}>\n <Select\n label={t('entityTypePicker.title')}\n items={items}\n selected={(items.length > 1 ? selectedTypes[0] : undefined) ?? 'all'}\n onChange={value =>\n setSelectedTypes(value === 'all' ? [] : [String(value)])\n }\n />\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAoCO,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAiC;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAc,GAAI,KAAA;AAClC,EAAA,MAAM,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAA,MAAM,EAAE,KAAA,EAAO,cAAA,EAAgB,aAAA,EAAe,gBAAA,KAC5C,mBAAA,EAAoB;AACtB,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,0BAA0B,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,IAAA,CAAK;AAAA,QACZ,OAAA,EAAS,EAAE,+BAA+B,CAAA;AAAA,QAC1C,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH;AACA,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,gBAAA,CAAiB,CAAC,aAAa,CAAC,CAAA;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,KAAA,EAAO,UAAU,aAAA,EAAe,gBAAA,EAAkB,CAAC,CAAC,CAAA;AAExD,EAAA,IAAI,cAAA,CAAe,MAAA,KAAW,CAAA,IAAK,KAAA,EAAO,OAAO,IAAA;AAEjD,EAAA,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,WAAA,EAAY,CAAE,aAAA,CAAc,CAAA,CAAE,WAAA,EAAa,CAAC,CAAA;AAE5E,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA,CAAE,iCAAiC,CAAA,EAAE;AAAA,IAC5D,GAAG,cAAA,CAAe,GAAA,CAAI,CAAC,IAAA,MAAkB;AAAA,MACvC,KAAA,EAAO,IAAA;AAAA,MACP,KAAA,EAAO;AAAA,KACT,CAAE;AAAA,GACJ;AAEA,EAAA,OAAO,SAAS,IAAA,mBACd,GAAA,CAAC,OAAI,EAAA,EAAI,CAAA,EAAG,IAAI,CAAA,EACd,QAAA,kBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,KAAA;AAAA,MACA,WAAW,KAAA,CAAM,MAAA,GAAS,IAAI,aAAA,CAAc,CAAC,IAAI,MAAA,KAAc,KAAA;AAAA,MAC/D,QAAA,EAAU,CAAA,KAAA,KACR,gBAAA,CAAiB,KAAA,KAAU,KAAA,GAAQ,EAAC,GAAI,CAAC,MAAA,CAAO,KAAK,CAAC,CAAC;AAAA;AAAA,GAE3D,EACF,CAAA;AAEJ;;;;"}
@@ -91,9 +91,7 @@ function CustomNode({ node }) {
91
91
  }
92
92
  }
93
93
  }, [width, height]);
94
- const hasKindIcon = app.getSystemIcon(
95
- `kind:${node.kind.toLocaleLowerCase("en-US")}`
96
- );
94
+ const hasKindIcon = app.getSystemIcon(`kind:${node.kind.toLowerCase()}`);
97
95
  const padding = 10;
98
96
  const iconSize = height;
99
97
  const paddedIconWidth = hasKindIcon ? iconSize + padding : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"AncestryPage.esm.js","sources":["../../../../src/components/InspectEntityDialog/components/AncestryPage.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 {\n Entity,\n DEFAULT_NAMESPACE,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n Link,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { useApi, useApp, useRouteRef } from '@backstage/core-plugin-api';\nimport { Text, Box } from '@backstage/ui';\nimport { makeStyles } from '@material-ui/core/styles';\nimport classNames from 'classnames';\nimport { useLayoutEffect, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../../api';\nimport { entityRouteRef } from '../../../routes';\nimport { useEntityPresentation } from '../../../apis';\nimport { EntityKindIcon } from './EntityKindIcon';\nimport { catalogReactTranslationRef } from '../../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nconst useStyles = makeStyles(theme => ({\n node: {\n fill: theme.palette.grey[300],\n stroke: theme.palette.grey[300],\n '&.primary': {\n fill: theme.palette.primary.light,\n stroke: theme.palette.primary.light,\n },\n '&.secondary': {\n fill: theme.palette.secondary.light,\n stroke: theme.palette.secondary.light,\n },\n },\n text: {\n fill: theme.palette.getContrastText(theme.palette.grey[300]),\n '&.primary': {\n fill: theme.palette.primary.contrastText,\n },\n '&.secondary': {\n fill: theme.palette.secondary.contrastText,\n },\n '&.focused': {\n fontWeight: 'bold',\n },\n },\n clickable: {\n cursor: 'pointer',\n },\n}));\n\ntype NodeType = Entity & { root: boolean };\n\nfunction useAncestry(root: Entity): {\n loading: boolean;\n error?: Error;\n nodes: DependencyGraphTypes.DependencyNode<NodeType>[];\n edges: DependencyGraphTypes.DependencyEdge[];\n} {\n const catalogClient = useApi(catalogApiRef);\n const entityRef = stringifyEntityRef(root);\n\n const { loading, error, value } = useAsync(async () => {\n const response = await catalogClient.getEntityAncestors({ entityRef });\n const nodes = new Array<DependencyGraphTypes.DependencyNode<NodeType>>();\n const edges = new Array<DependencyGraphTypes.DependencyEdge>();\n for (const current of response.items) {\n const currentRef = stringifyEntityRef(current.entity);\n const isRootNode = currentRef === response.rootEntityRef;\n nodes.push({ id: currentRef, root: isRootNode, ...current.entity });\n for (const parentRef of current.parentEntityRefs) {\n edges.push({ from: currentRef, to: parentRef });\n }\n }\n return { nodes, edges };\n }, [entityRef]);\n\n return {\n loading,\n error,\n nodes: value?.nodes || [],\n edges: value?.edges || [],\n };\n}\n\nfunction CustomNode({ node }: DependencyGraphTypes.RenderNodeProps<NodeType>) {\n const classes = useStyles();\n const navigate = useNavigate();\n const entityRoute = useRouteRef(entityRouteRef);\n const [width, setWidth] = useState(0);\n const [height, setHeight] = useState(0);\n const app = useApp();\n const idRef = useRef<SVGTextElement | null>(null);\n\n useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const hasKindIcon = app.getSystemIcon(\n `kind:${node.kind.toLocaleLowerCase('en-US')}`,\n );\n const padding = 10;\n const iconSize = height;\n const paddedIconWidth = hasKindIcon ? iconSize + padding : 0;\n const paddedWidth = paddedIconWidth + width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n const { primaryTitle: displayTitle } = useEntityPresentation(node);\n\n const onClick = () => {\n navigate(\n entityRoute({\n kind: node.kind,\n namespace: node.metadata.namespace || DEFAULT_NAMESPACE,\n name: node.metadata.name,\n }),\n );\n };\n\n return (\n <g onClick={onClick} className={classes.clickable}>\n <rect\n className={classNames(\n classes.node,\n node.root ? 'secondary' : 'primary',\n )}\n width={paddedWidth}\n height={paddedHeight}\n rx={10}\n />\n {hasKindIcon && (\n <EntityKindIcon\n kind={node.kind}\n y={padding}\n x={padding}\n width={iconSize}\n height={iconSize}\n className={classNames(\n classes.text,\n node.root ? 'secondary' : 'primary',\n )}\n />\n )}\n <text\n ref={idRef}\n className={classNames(\n classes.text,\n node.root ? 'secondary' : 'primary',\n )}\n y={paddedHeight / 2}\n x={paddedIconWidth + (width + padding * 2) / 2}\n textAnchor=\"middle\"\n alignmentBaseline=\"middle\"\n >\n {displayTitle}\n </text>\n </g>\n );\n}\n\nexport function AncestryPage(props: { entity: Entity }) {\n const { loading, error, nodes, edges } = useAncestry(props.entity);\n const { t } = useTranslationRef(catalogReactTranslationRef);\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <>\n <Box mb=\"2\">\n <Text as=\"p\">\n {t('inspectEntityDialog.ancestryPage.description', {\n processorsLink: (\n <Link to=\"https://backstage.io/docs/features/software-catalog/life-of-an-entity\">\n {t('inspectEntityDialog.ancestryPage.processorsLink')}\n </Link>\n ),\n })}\n </Text>\n </Box>\n <Box mt=\"8\">\n <DependencyGraph\n nodes={nodes}\n edges={edges}\n renderNode={CustomNode}\n direction={DependencyGraphTypes.Direction.BOTTOM_TOP}\n zoom=\"enable-on-click\"\n />\n </Box>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AncestryPage.esm.js","sources":["../../../../src/components/InspectEntityDialog/components/AncestryPage.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 {\n Entity,\n DEFAULT_NAMESPACE,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n Link,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { useApi, useApp, useRouteRef } from '@backstage/core-plugin-api';\nimport { Text, Box } from '@backstage/ui';\nimport { makeStyles } from '@material-ui/core/styles';\nimport classNames from 'classnames';\nimport { useLayoutEffect, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../../../api';\nimport { entityRouteRef } from '../../../routes';\nimport { useEntityPresentation } from '../../../apis';\nimport { EntityKindIcon } from './EntityKindIcon';\nimport { catalogReactTranslationRef } from '../../../translation';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\n\nconst useStyles = makeStyles(theme => ({\n node: {\n fill: theme.palette.grey[300],\n stroke: theme.palette.grey[300],\n '&.primary': {\n fill: theme.palette.primary.light,\n stroke: theme.palette.primary.light,\n },\n '&.secondary': {\n fill: theme.palette.secondary.light,\n stroke: theme.palette.secondary.light,\n },\n },\n text: {\n fill: theme.palette.getContrastText(theme.palette.grey[300]),\n '&.primary': {\n fill: theme.palette.primary.contrastText,\n },\n '&.secondary': {\n fill: theme.palette.secondary.contrastText,\n },\n '&.focused': {\n fontWeight: 'bold',\n },\n },\n clickable: {\n cursor: 'pointer',\n },\n}));\n\ntype NodeType = Entity & { root: boolean };\n\nfunction useAncestry(root: Entity): {\n loading: boolean;\n error?: Error;\n nodes: DependencyGraphTypes.DependencyNode<NodeType>[];\n edges: DependencyGraphTypes.DependencyEdge[];\n} {\n const catalogClient = useApi(catalogApiRef);\n const entityRef = stringifyEntityRef(root);\n\n const { loading, error, value } = useAsync(async () => {\n const response = await catalogClient.getEntityAncestors({ entityRef });\n const nodes = new Array<DependencyGraphTypes.DependencyNode<NodeType>>();\n const edges = new Array<DependencyGraphTypes.DependencyEdge>();\n for (const current of response.items) {\n const currentRef = stringifyEntityRef(current.entity);\n const isRootNode = currentRef === response.rootEntityRef;\n nodes.push({ id: currentRef, root: isRootNode, ...current.entity });\n for (const parentRef of current.parentEntityRefs) {\n edges.push({ from: currentRef, to: parentRef });\n }\n }\n return { nodes, edges };\n }, [entityRef]);\n\n return {\n loading,\n error,\n nodes: value?.nodes || [],\n edges: value?.edges || [],\n };\n}\n\nfunction CustomNode({ node }: DependencyGraphTypes.RenderNodeProps<NodeType>) {\n const classes = useStyles();\n const navigate = useNavigate();\n const entityRoute = useRouteRef(entityRouteRef);\n const [width, setWidth] = useState(0);\n const [height, setHeight] = useState(0);\n const app = useApp();\n const idRef = useRef<SVGTextElement | null>(null);\n\n useLayoutEffect(() => {\n // set the width to the length of the ID\n if (idRef.current) {\n let { height: renderedHeight, width: renderedWidth } =\n idRef.current.getBBox();\n renderedHeight = Math.round(renderedHeight);\n renderedWidth = Math.round(renderedWidth);\n if (renderedHeight !== height || renderedWidth !== width) {\n setWidth(renderedWidth);\n setHeight(renderedHeight);\n }\n }\n }, [width, height]);\n\n const hasKindIcon = app.getSystemIcon(`kind:${node.kind.toLowerCase()}`);\n const padding = 10;\n const iconSize = height;\n const paddedIconWidth = hasKindIcon ? iconSize + padding : 0;\n const paddedWidth = paddedIconWidth + width + padding * 2;\n const paddedHeight = height + padding * 2;\n\n const { primaryTitle: displayTitle } = useEntityPresentation(node);\n\n const onClick = () => {\n navigate(\n entityRoute({\n kind: node.kind,\n namespace: node.metadata.namespace || DEFAULT_NAMESPACE,\n name: node.metadata.name,\n }),\n );\n };\n\n return (\n <g onClick={onClick} className={classes.clickable}>\n <rect\n className={classNames(\n classes.node,\n node.root ? 'secondary' : 'primary',\n )}\n width={paddedWidth}\n height={paddedHeight}\n rx={10}\n />\n {hasKindIcon && (\n <EntityKindIcon\n kind={node.kind}\n y={padding}\n x={padding}\n width={iconSize}\n height={iconSize}\n className={classNames(\n classes.text,\n node.root ? 'secondary' : 'primary',\n )}\n />\n )}\n <text\n ref={idRef}\n className={classNames(\n classes.text,\n node.root ? 'secondary' : 'primary',\n )}\n y={paddedHeight / 2}\n x={paddedIconWidth + (width + padding * 2) / 2}\n textAnchor=\"middle\"\n alignmentBaseline=\"middle\"\n >\n {displayTitle}\n </text>\n </g>\n );\n}\n\nexport function AncestryPage(props: { entity: Entity }) {\n const { loading, error, nodes, edges } = useAncestry(props.entity);\n const { t } = useTranslationRef(catalogReactTranslationRef);\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <>\n <Box mb=\"2\">\n <Text as=\"p\">\n {t('inspectEntityDialog.ancestryPage.description', {\n processorsLink: (\n <Link to=\"https://backstage.io/docs/features/software-catalog/life-of-an-entity\">\n {t('inspectEntityDialog.ancestryPage.processorsLink')}\n </Link>\n ),\n })}\n </Text>\n </Box>\n <Box mt=\"8\">\n <DependencyGraph\n nodes={nodes}\n edges={edges}\n renderNode={CustomNode}\n direction={DependencyGraphTypes.Direction.BOTTOM_TOP}\n zoom=\"enable-on-click\"\n />\n </Box>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -6,11 +6,11 @@ import SvgIcon from '@material-ui/core/SvgIcon';
6
6
  const DEFAULT_ICON = SvgIcon;
7
7
  function getKind(kind, entityRef) {
8
8
  if (kind) {
9
- return kind.toLocaleLowerCase("en-US");
9
+ return kind.toLowerCase();
10
10
  }
11
11
  if (entityRef) {
12
12
  try {
13
- return parseEntityRef(entityRef).kind.toLocaleLowerCase("en-US");
13
+ return parseEntityRef(entityRef).kind.toLowerCase();
14
14
  } catch {
15
15
  return void 0;
16
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityKindIcon.esm.js","sources":["../../../../src/components/InspectEntityDialog/components/EntityKindIcon.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 { parseEntityRef } from '@backstage/catalog-model';\nimport { useApp } from '@backstage/core-plugin-api';\nimport SvgIcon from '@material-ui/core/SvgIcon';\n\nconst DEFAULT_ICON = SvgIcon;\n\nfunction getKind(\n kind: string | undefined,\n entityRef: string | undefined,\n): string | undefined {\n if (kind) {\n return kind.toLocaleLowerCase('en-US');\n }\n\n if (entityRef) {\n try {\n return parseEntityRef(entityRef).kind.toLocaleLowerCase('en-US');\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nfunction useIcon(kind: string | undefined, entityRef: string | undefined) {\n const app = useApp();\n\n const actualKind = getKind(kind, entityRef);\n if (!actualKind) {\n return DEFAULT_ICON;\n }\n\n const icon = app.getSystemIcon(`kind:${actualKind}`);\n return icon || DEFAULT_ICON;\n}\n\nexport function EntityKindIcon(props: {\n kind?: string;\n entityRef?: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n className?: string;\n}) {\n const { kind, entityRef, ...otherProps } = props;\n const Icon = useIcon(kind, entityRef);\n return <Icon {...otherProps} />;\n}\n"],"names":[],"mappings":";;;;;AAoBA,MAAM,YAAA,GAAe,OAAA;AAErB,SAAS,OAAA,CACP,MACA,SAAA,EACoB;AACpB,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,OAAO,IAAA,CAAK,kBAAkB,OAAO,CAAA;AAAA,EACvC;AAEA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,IAAI;AACF,MAAA,OAAO,cAAA,CAAe,SAAS,CAAA,CAAE,IAAA,CAAK,kBAAkB,OAAO,CAAA;AAAA,IACjE,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,OAAA,CAAQ,MAA0B,SAAA,EAA+B;AACxE,EAAA,MAAM,MAAM,MAAA,EAAO;AAEnB,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,IAAA,EAAM,SAAS,CAAA;AAC1C,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,aAAA,CAAc,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAE,CAAA;AACnD,EAAA,OAAO,IAAA,IAAQ,YAAA;AACjB;AAEO,SAAS,eAAe,KAAA,EAQ5B;AACD,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,GAAG,YAAW,GAAI,KAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,EAAM,SAAS,CAAA;AACpC,EAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAM,GAAG,UAAA,EAAY,CAAA;AAC/B;;;;"}
1
+ {"version":3,"file":"EntityKindIcon.esm.js","sources":["../../../../src/components/InspectEntityDialog/components/EntityKindIcon.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 { parseEntityRef } from '@backstage/catalog-model';\nimport { useApp } from '@backstage/core-plugin-api';\nimport SvgIcon from '@material-ui/core/SvgIcon';\n\nconst DEFAULT_ICON = SvgIcon;\n\nfunction getKind(\n kind: string | undefined,\n entityRef: string | undefined,\n): string | undefined {\n if (kind) {\n return kind.toLowerCase();\n }\n\n if (entityRef) {\n try {\n return parseEntityRef(entityRef).kind.toLowerCase();\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nfunction useIcon(kind: string | undefined, entityRef: string | undefined) {\n const app = useApp();\n\n const actualKind = getKind(kind, entityRef);\n if (!actualKind) {\n return DEFAULT_ICON;\n }\n\n const icon = app.getSystemIcon(`kind:${actualKind}`);\n return icon || DEFAULT_ICON;\n}\n\nexport function EntityKindIcon(props: {\n kind?: string;\n entityRef?: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n className?: string;\n}) {\n const { kind, entityRef, ...otherProps } = props;\n const Icon = useIcon(kind, entityRef);\n return <Icon {...otherProps} />;\n}\n"],"names":[],"mappings":";;;;;AAoBA,MAAM,YAAA,GAAe,OAAA;AAErB,SAAS,OAAA,CACP,MACA,SAAA,EACoB;AACpB,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,OAAO,KAAK,WAAA,EAAY;AAAA,EAC1B;AAEA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,IAAI;AACF,MAAA,OAAO,cAAA,CAAe,SAAS,CAAA,CAAE,IAAA,CAAK,WAAA,EAAY;AAAA,IACpD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,OAAA,CAAQ,MAA0B,SAAA,EAA+B;AACxE,EAAA,MAAM,MAAM,MAAA,EAAO;AAEnB,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,IAAA,EAAM,SAAS,CAAA;AAC1C,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,aAAA,CAAc,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAE,CAAA;AACnD,EAAA,OAAO,IAAA,IAAQ,YAAA;AACjB;AAEO,SAAS,eAAe,KAAA,EAQ5B;AACD,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,GAAG,YAAW,GAAI,KAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,EAAM,SAAS,CAAA;AACpC,EAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAM,GAAG,UAAA,EAAY,CAAA;AAC/B;;;;"}
@@ -86,7 +86,7 @@ class EntityTextFilter {
86
86
  return this.value;
87
87
  }
88
88
  toUpperArray(value) {
89
- return value.flat().filter((m) => Boolean(m) && typeof m === "string").map((m) => m.toLocaleUpperCase("en-US"));
89
+ return value.flat().filter((m) => Boolean(m) && typeof m === "string").map((m) => m.toUpperCase());
90
90
  }
91
91
  }
92
92
  class EntityOwnerFilter {
@@ -1 +1 @@
1
- {"version":3,"file":"filters.esm.js","sources":["../src/filters.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 {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AlphaEntity } from '@backstage/catalog-model/alpha';\nimport { EntityFilter, UserListFilterKind } from './types';\nimport { getEntityRelations } from './utils/getEntityRelations';\nimport { EntityOrderQuery } from '@backstage/catalog-client';\n\n/**\n * Filter entities based on Kind.\n * @public\n */\nexport class EntityKindFilter implements EntityFilter {\n readonly value: string;\n readonly label: string;\n\n constructor(value: string, label: string) {\n this.value = value;\n this.label = label;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { kind: this.value };\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on type\n * @public\n */\nexport class EntityTypeFilter implements EntityFilter {\n readonly value: string | string[];\n\n constructor(value: string | string[]) {\n this.value = value;\n }\n\n // Simplify `string | string[]` for consumers, always returns an array\n getTypes(): string[] {\n return Array.isArray(this.value) ? this.value : [this.value];\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.type': this.getTypes() };\n }\n\n toQueryValue(): string[] {\n return this.getTypes();\n }\n}\n\n/**\n * Filters entities based on tag.\n * @public\n */\nexport class EntityTagFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.every(v => (entity.metadata.tags ?? []).includes(v));\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.tags': this.values };\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities where the text matches spec, title or tags.\n * @public\n */\nexport class EntityTextFilter implements EntityFilter {\n readonly value: string;\n\n constructor(value: string) {\n this.value = value;\n }\n\n filterEntity(entity: Entity): boolean {\n const words = this.toUpperArray(this.value.split(/\\s/));\n const exactMatch = this.toUpperArray([entity.metadata.tags]);\n const targets = (entity.spec as { targets?: unknown })?.targets;\n const partialMatch = this.toUpperArray([\n entity.metadata.name,\n entity.metadata.title,\n (entity.spec?.profile as { displayName?: string })?.displayName,\n (entity.spec as { target?: string })?.target,\n ...(Array.isArray(targets) ? targets : []),\n ]);\n\n for (const word of words) {\n if (\n exactMatch.every(m => m !== word) &&\n partialMatch.every(m => !m.includes(word))\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n getFullTextFilters() {\n return {\n term: this.value,\n // Update this to be more dynamic based on table columns.\n fields: [\n 'metadata.name',\n 'metadata.title',\n 'spec.profile.displayName',\n 'spec.target',\n 'spec.targets',\n ],\n };\n }\n\n toQueryValue() {\n return this.value;\n }\n\n private toUpperArray(\n value: Array<string | string[] | undefined>,\n ): Array<string> {\n return value\n .flat()\n .filter((m): m is string => Boolean(m) && typeof m === 'string')\n .map(m => m.toLocaleUpperCase('en-US'));\n }\n}\n\n/**\n * Filter matching entities that are owned by group.\n * @public\n *\n * CAUTION: This class may contain both full and partial entity refs.\n */\nexport class EntityOwnerFilter implements EntityFilter {\n readonly values: string[];\n constructor(values: string[]) {\n this.values = values.reduce((fullRefs, ref) => {\n // Attempt to remove bad entity references here.\n try {\n fullRefs.push(\n stringifyEntityRef(parseEntityRef(ref, { defaultKind: 'Group' })),\n );\n return fullRefs;\n } catch (err) {\n return fullRefs;\n }\n }, [] as string[]);\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'relations.ownedBy': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v =>\n getEntityRelations(entity, RELATION_OWNED_BY).some(\n o => stringifyEntityRef(o) === v,\n ),\n );\n }\n\n /**\n * Get the URL query parameter value. May be a mix of full and humanized entity refs.\n * @returns list of entity refs.\n */\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities on lifecycle.\n * @public\n */\nexport class EntityLifecycleFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.lifecycle': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.spec?.lifecycle === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities to those within the given namespace(s).\n * @public\n */\nexport class EntityNamespaceFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.namespace': this.values };\n }\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.metadata.namespace === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * @public\n */\nexport class EntityUserFilter implements EntityFilter {\n readonly value: UserListFilterKind;\n readonly refs?: string[];\n\n private constructor(value: UserListFilterKind, refs?: string[]) {\n this.value = value;\n this.refs = refs;\n }\n\n static owned(ownershipEntityRefs: string[]) {\n return new EntityUserFilter('owned', ownershipEntityRefs);\n }\n\n static all() {\n return new EntityUserFilter('all');\n }\n\n static starred(starredEntityRefs: string[]) {\n return new EntityUserFilter('starred', starredEntityRefs);\n }\n\n getCatalogFilters(): Record<string, string[]> {\n if (this.value === 'owned') {\n return { 'relations.ownedBy': this.refs ?? [] };\n }\n if (this.value === 'starred') {\n return {\n 'metadata.name': this.refs?.map(e => parseEntityRef(e).name) ?? [],\n };\n }\n return {};\n }\n\n filterEntity(entity: Entity) {\n if (this.value === 'starred') {\n return this.refs?.includes(stringifyEntityRef(entity)) ?? true;\n }\n // used only for retro-compatibility with non paginated data.\n // This is supposed to return always true for paginated\n // owned entities, since the filters are applied server side.\n if (this.value === 'owned') {\n const relations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n this.refs?.some(v =>\n relations.some(o => stringifyEntityRef(o) === v),\n ) ?? false\n );\n }\n return true;\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on whatever the user has starred or owns them.\n * @deprecated use EntityUserFilter\n * @public\n */\nexport class UserListFilter implements EntityFilter {\n readonly value: UserListFilterKind;\n readonly isOwnedEntity: (entity: Entity) => boolean;\n readonly isStarredEntity: (entity: Entity) => boolean;\n\n constructor(\n value: UserListFilterKind,\n isOwnedEntity: (entity: Entity) => boolean,\n isStarredEntity: (entity: Entity) => boolean,\n ) {\n this.value = value;\n this.isOwnedEntity = isOwnedEntity;\n this.isStarredEntity = isStarredEntity;\n }\n\n filterEntity(entity: Entity): boolean {\n switch (this.value) {\n case 'owned':\n return this.isOwnedEntity(entity);\n case 'starred':\n return this.isStarredEntity(entity);\n default:\n return true;\n }\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based if it is an orphan or not.\n * @public\n */\nexport class EntityOrphanFilter implements EntityFilter {\n readonly value: boolean;\n\n constructor(value: boolean) {\n this.value = value;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n if (this.value) {\n return { 'metadata.annotations.backstage.io/orphan': String(this.value) };\n }\n return {};\n }\n\n filterEntity(entity: Entity): boolean {\n const orphan = entity.metadata.annotations?.['backstage.io/orphan'];\n return orphan !== undefined && this.value.toString() === orphan;\n }\n}\n\n/**\n * Filters entities based on if it has errors or not.\n * @public\n */\nexport class EntityErrorFilter implements EntityFilter {\n readonly value: boolean;\n\n constructor(value: boolean) {\n this.value = value;\n }\n\n filterEntity(entity: Entity): boolean {\n const error =\n ((entity as AlphaEntity)?.status?.items?.length as number) > 0;\n return error !== undefined && this.value === error;\n }\n}\n\n/**\n * Sort entities by a given field/column.\n * @public\n */\nexport class EntityOrderFilter implements EntityFilter {\n readonly values: [string, 'asc' | 'desc'][];\n\n constructor(values: [string, 'asc' | 'desc'][]) {\n this.values = values;\n }\n\n getOrderFilters(): EntityOrderQuery {\n return this.values.map(([field, order]) => ({ field, order }));\n }\n\n toQueryValue(): string[] {\n return this.values.flat();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filters.esm.js","sources":["../src/filters.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 {\n Entity,\n parseEntityRef,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { AlphaEntity } from '@backstage/catalog-model/alpha';\nimport { EntityFilter, UserListFilterKind } from './types';\nimport { getEntityRelations } from './utils/getEntityRelations';\nimport { EntityOrderQuery } from '@backstage/catalog-client';\n\n/**\n * Filter entities based on Kind.\n * @public\n */\nexport class EntityKindFilter implements EntityFilter {\n readonly value: string;\n readonly label: string;\n\n constructor(value: string, label: string) {\n this.value = value;\n this.label = label;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { kind: this.value };\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on type\n * @public\n */\nexport class EntityTypeFilter implements EntityFilter {\n readonly value: string | string[];\n\n constructor(value: string | string[]) {\n this.value = value;\n }\n\n // Simplify `string | string[]` for consumers, always returns an array\n getTypes(): string[] {\n return Array.isArray(this.value) ? this.value : [this.value];\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.type': this.getTypes() };\n }\n\n toQueryValue(): string[] {\n return this.getTypes();\n }\n}\n\n/**\n * Filters entities based on tag.\n * @public\n */\nexport class EntityTagFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.every(v => (entity.metadata.tags ?? []).includes(v));\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.tags': this.values };\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities where the text matches spec, title or tags.\n * @public\n */\nexport class EntityTextFilter implements EntityFilter {\n readonly value: string;\n\n constructor(value: string) {\n this.value = value;\n }\n\n filterEntity(entity: Entity): boolean {\n const words = this.toUpperArray(this.value.split(/\\s/));\n const exactMatch = this.toUpperArray([entity.metadata.tags]);\n const targets = (entity.spec as { targets?: unknown })?.targets;\n const partialMatch = this.toUpperArray([\n entity.metadata.name,\n entity.metadata.title,\n (entity.spec?.profile as { displayName?: string })?.displayName,\n (entity.spec as { target?: string })?.target,\n ...(Array.isArray(targets) ? targets : []),\n ]);\n\n for (const word of words) {\n if (\n exactMatch.every(m => m !== word) &&\n partialMatch.every(m => !m.includes(word))\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n getFullTextFilters() {\n return {\n term: this.value,\n // Update this to be more dynamic based on table columns.\n fields: [\n 'metadata.name',\n 'metadata.title',\n 'spec.profile.displayName',\n 'spec.target',\n 'spec.targets',\n ],\n };\n }\n\n toQueryValue() {\n return this.value;\n }\n\n private toUpperArray(\n value: Array<string | string[] | undefined>,\n ): Array<string> {\n return value\n .flat()\n .filter((m): m is string => Boolean(m) && typeof m === 'string')\n .map(m => m.toUpperCase());\n }\n}\n\n/**\n * Filter matching entities that are owned by group.\n * @public\n *\n * CAUTION: This class may contain both full and partial entity refs.\n */\nexport class EntityOwnerFilter implements EntityFilter {\n readonly values: string[];\n constructor(values: string[]) {\n this.values = values.reduce((fullRefs, ref) => {\n // Attempt to remove bad entity references here.\n try {\n fullRefs.push(\n stringifyEntityRef(parseEntityRef(ref, { defaultKind: 'Group' })),\n );\n return fullRefs;\n } catch (err) {\n return fullRefs;\n }\n }, [] as string[]);\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'relations.ownedBy': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v =>\n getEntityRelations(entity, RELATION_OWNED_BY).some(\n o => stringifyEntityRef(o) === v,\n ),\n );\n }\n\n /**\n * Get the URL query parameter value. May be a mix of full and humanized entity refs.\n * @returns list of entity refs.\n */\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities on lifecycle.\n * @public\n */\nexport class EntityLifecycleFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'spec.lifecycle': this.values };\n }\n\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.spec?.lifecycle === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * Filters entities to those within the given namespace(s).\n * @public\n */\nexport class EntityNamespaceFilter implements EntityFilter {\n readonly values: string[];\n\n constructor(values: string[]) {\n this.values = values;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n return { 'metadata.namespace': this.values };\n }\n filterEntity(entity: Entity): boolean {\n return this.values.some(v => entity.metadata.namespace === v);\n }\n\n toQueryValue(): string[] {\n return this.values;\n }\n}\n\n/**\n * @public\n */\nexport class EntityUserFilter implements EntityFilter {\n readonly value: UserListFilterKind;\n readonly refs?: string[];\n\n private constructor(value: UserListFilterKind, refs?: string[]) {\n this.value = value;\n this.refs = refs;\n }\n\n static owned(ownershipEntityRefs: string[]) {\n return new EntityUserFilter('owned', ownershipEntityRefs);\n }\n\n static all() {\n return new EntityUserFilter('all');\n }\n\n static starred(starredEntityRefs: string[]) {\n return new EntityUserFilter('starred', starredEntityRefs);\n }\n\n getCatalogFilters(): Record<string, string[]> {\n if (this.value === 'owned') {\n return { 'relations.ownedBy': this.refs ?? [] };\n }\n if (this.value === 'starred') {\n return {\n 'metadata.name': this.refs?.map(e => parseEntityRef(e).name) ?? [],\n };\n }\n return {};\n }\n\n filterEntity(entity: Entity) {\n if (this.value === 'starred') {\n return this.refs?.includes(stringifyEntityRef(entity)) ?? true;\n }\n // used only for retro-compatibility with non paginated data.\n // This is supposed to return always true for paginated\n // owned entities, since the filters are applied server side.\n if (this.value === 'owned') {\n const relations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n this.refs?.some(v =>\n relations.some(o => stringifyEntityRef(o) === v),\n ) ?? false\n );\n }\n return true;\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based on whatever the user has starred or owns them.\n * @deprecated use EntityUserFilter\n * @public\n */\nexport class UserListFilter implements EntityFilter {\n readonly value: UserListFilterKind;\n readonly isOwnedEntity: (entity: Entity) => boolean;\n readonly isStarredEntity: (entity: Entity) => boolean;\n\n constructor(\n value: UserListFilterKind,\n isOwnedEntity: (entity: Entity) => boolean,\n isStarredEntity: (entity: Entity) => boolean,\n ) {\n this.value = value;\n this.isOwnedEntity = isOwnedEntity;\n this.isStarredEntity = isStarredEntity;\n }\n\n filterEntity(entity: Entity): boolean {\n switch (this.value) {\n case 'owned':\n return this.isOwnedEntity(entity);\n case 'starred':\n return this.isStarredEntity(entity);\n default:\n return true;\n }\n }\n\n toQueryValue(): string {\n return this.value;\n }\n}\n\n/**\n * Filters entities based if it is an orphan or not.\n * @public\n */\nexport class EntityOrphanFilter implements EntityFilter {\n readonly value: boolean;\n\n constructor(value: boolean) {\n this.value = value;\n }\n\n getCatalogFilters(): Record<string, string | string[]> {\n if (this.value) {\n return { 'metadata.annotations.backstage.io/orphan': String(this.value) };\n }\n return {};\n }\n\n filterEntity(entity: Entity): boolean {\n const orphan = entity.metadata.annotations?.['backstage.io/orphan'];\n return orphan !== undefined && this.value.toString() === orphan;\n }\n}\n\n/**\n * Filters entities based on if it has errors or not.\n * @public\n */\nexport class EntityErrorFilter implements EntityFilter {\n readonly value: boolean;\n\n constructor(value: boolean) {\n this.value = value;\n }\n\n filterEntity(entity: Entity): boolean {\n const error =\n ((entity as AlphaEntity)?.status?.items?.length as number) > 0;\n return error !== undefined && this.value === error;\n }\n}\n\n/**\n * Sort entities by a given field/column.\n * @public\n */\nexport class EntityOrderFilter implements EntityFilter {\n readonly values: [string, 'asc' | 'desc'][];\n\n constructor(values: [string, 'asc' | 'desc'][]) {\n this.values = values;\n }\n\n getOrderFilters(): EntityOrderQuery {\n return this.values.map(([field, order]) => ({ field, order }));\n }\n\n toQueryValue(): string[] {\n return this.values.flat();\n }\n}\n"],"names":[],"mappings":"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"}
@@ -64,7 +64,7 @@ const EntityListProvider = (props) => {
64
64
  const lastFetchParamsRef = useRef(void 0);
65
65
  const fetchGenRef = useRef(0);
66
66
  const adjustedFilters = useMemo(() => {
67
- const kindValue = requestedFilters.kind?.value?.toLocaleLowerCase("en-US");
67
+ const kindValue = requestedFilters.kind?.value?.toLowerCase();
68
68
  return kindValue === "user" || kindValue === "group" ? { ...requestedFilters, owners: void 0 } : requestedFilters;
69
69
  }, [requestedFilters]);
70
70
  const refresh = async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityListProvider.esm.js","sources":["../../src/hooks/useEntityListProvider.tsx"],"sourcesContent":["/*\n * Copyright 2020 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 { QueryEntitiesResponse } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n useVersionedContext,\n} from '@backstage/version-bridge';\nimport { compact, isEqual } from 'lodash';\nimport qs from 'qs';\nimport {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useLocation } from 'react-router-dom';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport useMountedState from 'react-use/esm/useMountedState';\nimport { catalogApiRef } from '../api';\nimport {\n EntityErrorFilter,\n EntityKindFilter,\n EntityLifecycleFilter,\n EntityNamespaceFilter,\n EntityOrderFilter,\n EntityOrphanFilter,\n EntityOwnerFilter,\n EntityTagFilter,\n EntityTextFilter,\n EntityTypeFilter,\n EntityUserFilter,\n UserListFilter,\n} from '../filters';\nimport { EntityFilter, EntityListPagination } from '../types';\nimport {\n reduceBackendCatalogFilters,\n reduceCatalogFilters,\n reduceEntityFilters,\n} from '../utils/filters';\n\n/** @public */\nexport type DefaultEntityFilters = {\n kind?: EntityKindFilter;\n type?: EntityTypeFilter;\n user?: UserListFilter | EntityUserFilter;\n owners?: EntityOwnerFilter;\n lifecycles?: EntityLifecycleFilter;\n tags?: EntityTagFilter;\n text?: EntityTextFilter;\n orphan?: EntityOrphanFilter;\n error?: EntityErrorFilter;\n namespace?: EntityNamespaceFilter;\n order?: EntityOrderFilter;\n};\n\n/** @public */\nexport type PaginationMode = 'cursor' | 'offset' | 'none';\n\n/** @public */\nexport type EntityListContextProps<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n> = {\n /**\n * The currently registered filters, adhering to the shape of DefaultEntityFilters or an extension\n * of that default (to add custom filter types).\n */\n filters: EntityFilters;\n\n /**\n * The resolved list of catalog entities, after all filters are applied.\n */\n entities: Entity[];\n\n /**\n * The resolved list of catalog entities, after _only catalog-backend_ filters are applied.\n */\n backendEntities: Entity[];\n\n /**\n * Update one or more of the registered filters. Optional filters can be set to `undefined` to\n * reset the filter.\n */\n updateFilters: (\n filters:\n | Partial<EntityFilters>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => void;\n\n /**\n * Filter values from query parameters.\n */\n queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;\n\n loading: boolean;\n error?: Error;\n\n pageInfo?: {\n next?: () => void;\n prev?: () => void;\n };\n totalItems?: number;\n totalItemsLoading: boolean;\n limit: number;\n offset?: number;\n setLimit: (limit: number) => void;\n setOffset?: (offset: number) => void;\n paginationMode: PaginationMode;\n\n /**\n * Trigger refresh of entities and entity totals.\n */\n refresh?: () => void;\n};\n\n// This context has support for multiple concurrent versions of this package.\n// It is currently used in parallel with the old context in order to provide\n// a smooth transition, but will eventually be the only context we use.\nexport const NewEntityListContext = createVersionedContext<{\n 1: EntityListContextProps<any>;\n}>('entity-list-context');\n\n/**\n * Creates new context for entity listing and filtering.\n */\nexport const OldEntityListContext = createContext<\n EntityListContextProps<any> | undefined\n>(undefined);\n\ntype BackendState = {\n backendEntities: Entity[];\n pageInfo?: QueryEntitiesResponse['pageInfo'];\n totalItems?: number;\n};\n\n/**\n * @public\n */\nexport type EntityListProviderProps = PropsWithChildren<{\n pagination?: EntityListPagination;\n}>;\n\n/**\n * Provides entities and filters for a catalog listing.\n * @public\n */\nexport const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(\n props: EntityListProviderProps,\n) => {\n const isMounted = useMountedState();\n const catalogApi = useApi(catalogApiRef);\n const [requestedFilters, setRequestedFilters] = useState<EntityFilters>(\n {} as EntityFilters,\n );\n\n // We use react-router's useLocation hook so updates from external sources trigger an update to\n // the queryParameters in outputState. Updates from this hook use replaceState below and won't\n // trigger a useLocation change; this would instead come from an external source, such as a manual\n // update of the URL or two catalog sidebar links with different catalog filters.\n const location = useLocation();\n\n let paginationMode: PaginationMode = 'none';\n if (props.pagination === true) {\n paginationMode = 'cursor';\n } else if (typeof props.pagination === 'object') {\n paginationMode = props.pagination.mode ?? 'cursor';\n }\n const paginationLimit =\n typeof props.pagination === 'object' ? props.pagination.limit ?? 20 : 20;\n\n const {\n queryParameters,\n cursor: initialCursor,\n offset: initialOffset,\n limit: initialLimit,\n } = useMemo(() => {\n const parsed = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n arrayLimit: 10000,\n });\n\n let limit = paginationLimit;\n if (typeof parsed.limit === 'string') {\n const queryLimit = Number.parseInt(parsed.limit, 10);\n if (!isNaN(queryLimit)) {\n limit = queryLimit;\n }\n }\n\n const offset =\n typeof parsed.offset === 'string' && paginationMode === 'offset'\n ? Number.parseInt(parsed.offset, 10)\n : undefined;\n\n return {\n queryParameters: (parsed.filters ?? {}) as Record<\n string,\n string | string[]\n >,\n cursor:\n typeof parsed.cursor === 'string' && paginationMode === 'cursor'\n ? parsed.cursor\n : undefined,\n offset:\n paginationMode === 'offset' && offset && !isNaN(offset)\n ? offset\n : undefined,\n limit,\n };\n }, [paginationMode, location.search, paginationLimit]);\n\n const [cursor, setCursor] = useState(initialCursor);\n const [offset, setOffset] = useState<number | undefined>(initialOffset);\n const [limit, setLimit] = useState(initialLimit);\n\n const [backendState, setBackendState] = useState<BackendState>({\n backendEntities: [],\n });\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>();\n const [refreshToken, setRefreshToken] = useState(0);\n\n // Tracks the params of the last API call so identical requests are\n // skipped even when requestedFilters changes (e.g. a label change\n // or a frontend-only filter addition).\n const lastFetchParamsRef = useRef<unknown>(undefined);\n // Generation counter — only the most recent fetch updates state,\n // so out-of-order responses from overlapping requests are discarded.\n const fetchGenRef = useRef(0);\n\n // Adjusted filters remove the owners filter for user/group kinds,\n // since ownership is not meaningful for those entity types.\n const adjustedFilters = useMemo(() => {\n const kindValue = requestedFilters.kind?.value?.toLocaleLowerCase('en-US');\n return kindValue === 'user' || kindValue === 'group'\n ? { ...requestedFilters, owners: undefined }\n : requestedFilters;\n }, [requestedFilters]);\n\n const refresh = async () => {\n const compacted = compact(Object.values(adjustedFilters));\n\n let fetchParams: unknown;\n let doFetch: () => Promise<BackendState>;\n\n if (paginationMode !== 'none') {\n if (cursor) {\n fetchParams = { cursor, limit };\n doFetch = async () => {\n const response = await catalogApi.queryEntities({\n cursor,\n limit,\n totalItems: 'exclude',\n });\n return {\n backendEntities: response.items,\n pageInfo: response.pageInfo,\n };\n };\n } else {\n const backendFilter = reduceCatalogFilters(compacted);\n fetchParams = { ...backendFilter, limit, offset };\n doFetch = async () => {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit,\n offset,\n totalItems: 'exclude',\n });\n return {\n backendEntities: response.items,\n pageInfo: response.pageInfo,\n };\n };\n }\n } else {\n const backendFilter = reduceBackendCatalogFilters(compacted);\n const { orderFields } = reduceCatalogFilters(compacted);\n fetchParams = { filter: backendFilter, order: orderFields };\n doFetch = async () => {\n const response = await catalogApi.getEntities({\n filter: backendFilter,\n order: orderFields,\n });\n return { backendEntities: response.items };\n };\n }\n\n // No filters registered yet — wait for filter components to\n // call updateFilters before making the first request.\n // Exception: a cursor in the URL is a self-contained page reference\n // that doesn't need filter state to be valid.\n if (\n compacted.length === 0 &&\n lastFetchParamsRef.current === undefined &&\n !cursor\n ) {\n setLoading(false);\n return;\n }\n\n if (isEqual(fetchParams, lastFetchParamsRef.current)) {\n return;\n }\n lastFetchParamsRef.current = fetchParams;\n\n const gen = ++fetchGenRef.current;\n setLoading(true);\n setError(undefined);\n\n try {\n const result = await doFetch();\n if (gen === fetchGenRef.current) {\n setBackendState(result);\n }\n } catch (e) {\n if (gen === fetchGenRef.current) {\n // Clear the ref so the same params can be retried, and so\n // a response discarded due to a concurrent request (gen mismatch)\n // doesn't permanently block fetching those params again.\n lastFetchParamsRef.current = undefined;\n setError(e as Error);\n }\n } finally {\n if (gen === fetchGenRef.current) {\n setLoading(false);\n }\n }\n };\n\n // Slight debounce on the refresh, since (especially on page load)\n // several filters will be calling updateFilters in rapid succession.\n useDebounce(refresh, 10, [\n adjustedFilters,\n cursor,\n limit,\n offset,\n refreshToken,\n ]);\n\n // Fetch the total count separately, only when filters change. This is\n // decoupled from the main list fetch so that page navigation doesn't\n // re-run the expensive count query, and so that the count can arrive\n // asynchronously without blocking the list response.\n const [{ value: totalItems, loading: totalItemsLoading }, refreshCount] =\n useAsyncFn(async () => {\n if (paginationMode === 'none') {\n return undefined;\n }\n const compacted = compact(Object.values(adjustedFilters));\n if (compacted.length === 0) {\n return undefined;\n }\n const backendFilter = reduceCatalogFilters(compacted);\n try {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit: 0,\n });\n return response.totalItems;\n } catch {\n return undefined;\n }\n }, [catalogApi, paginationMode, adjustedFilters]);\n\n useDebounce(refreshCount, 10, [adjustedFilters, refreshToken]);\n\n // Frontend filtering — synchronous, no debounce needed. Updates\n // instantly when requestedFilters or backendEntities change.\n const entities = useMemo(() => {\n const compacted = compact(Object.values(adjustedFilters));\n const entityFilter = reduceEntityFilters(compacted);\n return backendState.backendEntities.filter(entityFilter);\n }, [adjustedFilters, backendState.backendEntities]);\n\n // Sync filter state to URL query parameters. We use direct history\n // manipulation since useSearchParams and useNavigate in\n // react-router-dom cause unnecessary extra rerenders. Also make sure\n // to replace the state rather than pushing, since we don't want\n // there to be back/forward slots for every single filter change.\n useEffect(() => {\n if (!isMounted() || Object.keys(requestedFilters).length === 0) {\n return;\n }\n const queryParams = Object.keys(requestedFilters).reduce((params, key) => {\n const filter = requestedFilters[key as keyof EntityFilters] as\n | EntityFilter\n | undefined;\n if (filter?.toQueryValue) {\n params[key] = filter.toQueryValue();\n }\n return params;\n }, {} as Record<string, string | string[]>);\n\n const oldParams = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n arrayLimit: 10000,\n });\n const newParams = qs.stringify(\n {\n ...oldParams,\n filters: queryParams,\n ...(paginationMode === 'none' ? {} : { cursor, limit, offset }),\n },\n { addQueryPrefix: true, arrayFormat: 'repeat' },\n );\n const newUrl = `${window.location.pathname}${newParams}`;\n window.history?.replaceState(null, document.title, newUrl);\n }, [\n cursor,\n isMounted,\n limit,\n location.search,\n offset,\n requestedFilters,\n paginationMode,\n ]);\n\n const updateFilters = useCallback(\n (\n update:\n | Partial<EntityFilter>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => {\n // changing filters will affect pagination, so we need to reset\n // the cursor and start from the first page.\n // TODO(vinzscam): this is currently causing issues at page reload\n // where the state is not kept. Unfortunately we need to rethink\n // the way filters work in order to fix this.\n if (paginationMode === 'cursor') {\n setCursor(undefined);\n } else if (paginationMode === 'offset') {\n // Same thing with offset\n setOffset(0);\n }\n setRequestedFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [paginationMode],\n );\n\n const triggerRefresh = useCallback(() => {\n // Clear the ref to allow refetching with the same params.\n lastFetchParamsRef.current = undefined;\n setRefreshToken(t => t + 1);\n }, []);\n\n const pageInfo = useMemo(() => {\n if (paginationMode !== 'cursor') {\n return undefined;\n }\n\n const prevCursor = backendState.pageInfo?.prevCursor;\n const nextCursor = backendState.pageInfo?.nextCursor;\n return {\n prev: prevCursor ? () => setCursor(prevCursor) : undefined,\n next: nextCursor ? () => setCursor(nextCursor) : undefined,\n };\n }, [paginationMode, backendState.pageInfo]);\n\n const value = useMemo(\n () => ({\n filters: requestedFilters,\n entities,\n backendEntities: backendState.backendEntities,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n totalItems:\n paginationMode === 'none'\n ? entities.length\n : totalItems ?? backendState.totalItems,\n totalItemsLoading: paginationMode !== 'none' && totalItemsLoading,\n limit,\n offset,\n setLimit,\n setOffset,\n paginationMode,\n refresh: triggerRefresh,\n }),\n [\n requestedFilters,\n entities,\n backendState,\n totalItems,\n totalItemsLoading,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n paginationMode,\n limit,\n offset,\n setLimit,\n setOffset,\n triggerRefresh,\n ],\n );\n\n return (\n <OldEntityListContext.Provider value={value}>\n <NewEntityListContext.Provider\n value={createVersionedValueMap({ 1: value })}\n >\n {props.children}\n </NewEntityListContext.Provider>\n </OldEntityListContext.Provider>\n );\n};\n\n/**\n * Hook for interacting with the entity list context provided by the {@link EntityListProvider}.\n * @public\n */\nexport function useEntityList<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n>(): EntityListContextProps<EntityFilters> {\n const versionedHolder = useVersionedContext<{\n 1: EntityListContextProps<any>;\n }>('entity-list-context');\n const oldContext = useContext(OldEntityListContext);\n\n if (versionedHolder) {\n const value = versionedHolder.atVersion(1);\n if (!value) {\n throw new Error('EntityListContext v1 not available');\n }\n return value;\n }\n\n if (oldContext) {\n return oldContext;\n }\n\n throw new Error('useEntityList must be used within EntityListProvider');\n}\n"],"names":["limit","offset"],"mappings":"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"}
1
+ {"version":3,"file":"useEntityListProvider.esm.js","sources":["../../src/hooks/useEntityListProvider.tsx"],"sourcesContent":["/*\n * Copyright 2020 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 { QueryEntitiesResponse } from '@backstage/catalog-client';\nimport { Entity } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n useVersionedContext,\n} from '@backstage/version-bridge';\nimport { compact, isEqual } from 'lodash';\nimport qs from 'qs';\nimport {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useLocation } from 'react-router-dom';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport useMountedState from 'react-use/esm/useMountedState';\nimport { catalogApiRef } from '../api';\nimport {\n EntityErrorFilter,\n EntityKindFilter,\n EntityLifecycleFilter,\n EntityNamespaceFilter,\n EntityOrderFilter,\n EntityOrphanFilter,\n EntityOwnerFilter,\n EntityTagFilter,\n EntityTextFilter,\n EntityTypeFilter,\n EntityUserFilter,\n UserListFilter,\n} from '../filters';\nimport { EntityFilter, EntityListPagination } from '../types';\nimport {\n reduceBackendCatalogFilters,\n reduceCatalogFilters,\n reduceEntityFilters,\n} from '../utils/filters';\n\n/** @public */\nexport type DefaultEntityFilters = {\n kind?: EntityKindFilter;\n type?: EntityTypeFilter;\n user?: UserListFilter | EntityUserFilter;\n owners?: EntityOwnerFilter;\n lifecycles?: EntityLifecycleFilter;\n tags?: EntityTagFilter;\n text?: EntityTextFilter;\n orphan?: EntityOrphanFilter;\n error?: EntityErrorFilter;\n namespace?: EntityNamespaceFilter;\n order?: EntityOrderFilter;\n};\n\n/** @public */\nexport type PaginationMode = 'cursor' | 'offset' | 'none';\n\n/** @public */\nexport type EntityListContextProps<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n> = {\n /**\n * The currently registered filters, adhering to the shape of DefaultEntityFilters or an extension\n * of that default (to add custom filter types).\n */\n filters: EntityFilters;\n\n /**\n * The resolved list of catalog entities, after all filters are applied.\n */\n entities: Entity[];\n\n /**\n * The resolved list of catalog entities, after _only catalog-backend_ filters are applied.\n */\n backendEntities: Entity[];\n\n /**\n * Update one or more of the registered filters. Optional filters can be set to `undefined` to\n * reset the filter.\n */\n updateFilters: (\n filters:\n | Partial<EntityFilters>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => void;\n\n /**\n * Filter values from query parameters.\n */\n queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;\n\n loading: boolean;\n error?: Error;\n\n pageInfo?: {\n next?: () => void;\n prev?: () => void;\n };\n totalItems?: number;\n totalItemsLoading: boolean;\n limit: number;\n offset?: number;\n setLimit: (limit: number) => void;\n setOffset?: (offset: number) => void;\n paginationMode: PaginationMode;\n\n /**\n * Trigger refresh of entities and entity totals.\n */\n refresh?: () => void;\n};\n\n// This context has support for multiple concurrent versions of this package.\n// It is currently used in parallel with the old context in order to provide\n// a smooth transition, but will eventually be the only context we use.\nexport const NewEntityListContext = createVersionedContext<{\n 1: EntityListContextProps<any>;\n}>('entity-list-context');\n\n/**\n * Creates new context for entity listing and filtering.\n */\nexport const OldEntityListContext = createContext<\n EntityListContextProps<any> | undefined\n>(undefined);\n\ntype BackendState = {\n backendEntities: Entity[];\n pageInfo?: QueryEntitiesResponse['pageInfo'];\n totalItems?: number;\n};\n\n/**\n * @public\n */\nexport type EntityListProviderProps = PropsWithChildren<{\n pagination?: EntityListPagination;\n}>;\n\n/**\n * Provides entities and filters for a catalog listing.\n * @public\n */\nexport const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(\n props: EntityListProviderProps,\n) => {\n const isMounted = useMountedState();\n const catalogApi = useApi(catalogApiRef);\n const [requestedFilters, setRequestedFilters] = useState<EntityFilters>(\n {} as EntityFilters,\n );\n\n // We use react-router's useLocation hook so updates from external sources trigger an update to\n // the queryParameters in outputState. Updates from this hook use replaceState below and won't\n // trigger a useLocation change; this would instead come from an external source, such as a manual\n // update of the URL or two catalog sidebar links with different catalog filters.\n const location = useLocation();\n\n let paginationMode: PaginationMode = 'none';\n if (props.pagination === true) {\n paginationMode = 'cursor';\n } else if (typeof props.pagination === 'object') {\n paginationMode = props.pagination.mode ?? 'cursor';\n }\n const paginationLimit =\n typeof props.pagination === 'object' ? props.pagination.limit ?? 20 : 20;\n\n const {\n queryParameters,\n cursor: initialCursor,\n offset: initialOffset,\n limit: initialLimit,\n } = useMemo(() => {\n const parsed = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n arrayLimit: 10000,\n });\n\n let limit = paginationLimit;\n if (typeof parsed.limit === 'string') {\n const queryLimit = Number.parseInt(parsed.limit, 10);\n if (!isNaN(queryLimit)) {\n limit = queryLimit;\n }\n }\n\n const offset =\n typeof parsed.offset === 'string' && paginationMode === 'offset'\n ? Number.parseInt(parsed.offset, 10)\n : undefined;\n\n return {\n queryParameters: (parsed.filters ?? {}) as Record<\n string,\n string | string[]\n >,\n cursor:\n typeof parsed.cursor === 'string' && paginationMode === 'cursor'\n ? parsed.cursor\n : undefined,\n offset:\n paginationMode === 'offset' && offset && !isNaN(offset)\n ? offset\n : undefined,\n limit,\n };\n }, [paginationMode, location.search, paginationLimit]);\n\n const [cursor, setCursor] = useState(initialCursor);\n const [offset, setOffset] = useState<number | undefined>(initialOffset);\n const [limit, setLimit] = useState(initialLimit);\n\n const [backendState, setBackendState] = useState<BackendState>({\n backendEntities: [],\n });\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>();\n const [refreshToken, setRefreshToken] = useState(0);\n\n // Tracks the params of the last API call so identical requests are\n // skipped even when requestedFilters changes (e.g. a label change\n // or a frontend-only filter addition).\n const lastFetchParamsRef = useRef<unknown>(undefined);\n // Generation counter — only the most recent fetch updates state,\n // so out-of-order responses from overlapping requests are discarded.\n const fetchGenRef = useRef(0);\n\n // Adjusted filters remove the owners filter for user/group kinds,\n // since ownership is not meaningful for those entity types.\n const adjustedFilters = useMemo(() => {\n const kindValue = requestedFilters.kind?.value?.toLowerCase();\n return kindValue === 'user' || kindValue === 'group'\n ? { ...requestedFilters, owners: undefined }\n : requestedFilters;\n }, [requestedFilters]);\n\n const refresh = async () => {\n const compacted = compact(Object.values(adjustedFilters));\n\n let fetchParams: unknown;\n let doFetch: () => Promise<BackendState>;\n\n if (paginationMode !== 'none') {\n if (cursor) {\n fetchParams = { cursor, limit };\n doFetch = async () => {\n const response = await catalogApi.queryEntities({\n cursor,\n limit,\n totalItems: 'exclude',\n });\n return {\n backendEntities: response.items,\n pageInfo: response.pageInfo,\n };\n };\n } else {\n const backendFilter = reduceCatalogFilters(compacted);\n fetchParams = { ...backendFilter, limit, offset };\n doFetch = async () => {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit,\n offset,\n totalItems: 'exclude',\n });\n return {\n backendEntities: response.items,\n pageInfo: response.pageInfo,\n };\n };\n }\n } else {\n const backendFilter = reduceBackendCatalogFilters(compacted);\n const { orderFields } = reduceCatalogFilters(compacted);\n fetchParams = { filter: backendFilter, order: orderFields };\n doFetch = async () => {\n const response = await catalogApi.getEntities({\n filter: backendFilter,\n order: orderFields,\n });\n return { backendEntities: response.items };\n };\n }\n\n // No filters registered yet — wait for filter components to\n // call updateFilters before making the first request.\n // Exception: a cursor in the URL is a self-contained page reference\n // that doesn't need filter state to be valid.\n if (\n compacted.length === 0 &&\n lastFetchParamsRef.current === undefined &&\n !cursor\n ) {\n setLoading(false);\n return;\n }\n\n if (isEqual(fetchParams, lastFetchParamsRef.current)) {\n return;\n }\n lastFetchParamsRef.current = fetchParams;\n\n const gen = ++fetchGenRef.current;\n setLoading(true);\n setError(undefined);\n\n try {\n const result = await doFetch();\n if (gen === fetchGenRef.current) {\n setBackendState(result);\n }\n } catch (e) {\n if (gen === fetchGenRef.current) {\n // Clear the ref so the same params can be retried, and so\n // a response discarded due to a concurrent request (gen mismatch)\n // doesn't permanently block fetching those params again.\n lastFetchParamsRef.current = undefined;\n setError(e as Error);\n }\n } finally {\n if (gen === fetchGenRef.current) {\n setLoading(false);\n }\n }\n };\n\n // Slight debounce on the refresh, since (especially on page load)\n // several filters will be calling updateFilters in rapid succession.\n useDebounce(refresh, 10, [\n adjustedFilters,\n cursor,\n limit,\n offset,\n refreshToken,\n ]);\n\n // Fetch the total count separately, only when filters change. This is\n // decoupled from the main list fetch so that page navigation doesn't\n // re-run the expensive count query, and so that the count can arrive\n // asynchronously without blocking the list response.\n const [{ value: totalItems, loading: totalItemsLoading }, refreshCount] =\n useAsyncFn(async () => {\n if (paginationMode === 'none') {\n return undefined;\n }\n const compacted = compact(Object.values(adjustedFilters));\n if (compacted.length === 0) {\n return undefined;\n }\n const backendFilter = reduceCatalogFilters(compacted);\n try {\n const response = await catalogApi.queryEntities({\n ...backendFilter,\n limit: 0,\n });\n return response.totalItems;\n } catch {\n return undefined;\n }\n }, [catalogApi, paginationMode, adjustedFilters]);\n\n useDebounce(refreshCount, 10, [adjustedFilters, refreshToken]);\n\n // Frontend filtering — synchronous, no debounce needed. Updates\n // instantly when requestedFilters or backendEntities change.\n const entities = useMemo(() => {\n const compacted = compact(Object.values(adjustedFilters));\n const entityFilter = reduceEntityFilters(compacted);\n return backendState.backendEntities.filter(entityFilter);\n }, [adjustedFilters, backendState.backendEntities]);\n\n // Sync filter state to URL query parameters. We use direct history\n // manipulation since useSearchParams and useNavigate in\n // react-router-dom cause unnecessary extra rerenders. Also make sure\n // to replace the state rather than pushing, since we don't want\n // there to be back/forward slots for every single filter change.\n useEffect(() => {\n if (!isMounted() || Object.keys(requestedFilters).length === 0) {\n return;\n }\n const queryParams = Object.keys(requestedFilters).reduce((params, key) => {\n const filter = requestedFilters[key as keyof EntityFilters] as\n | EntityFilter\n | undefined;\n if (filter?.toQueryValue) {\n params[key] = filter.toQueryValue();\n }\n return params;\n }, {} as Record<string, string | string[]>);\n\n const oldParams = qs.parse(location.search, {\n ignoreQueryPrefix: true,\n arrayLimit: 10000,\n });\n const newParams = qs.stringify(\n {\n ...oldParams,\n filters: queryParams,\n ...(paginationMode === 'none' ? {} : { cursor, limit, offset }),\n },\n { addQueryPrefix: true, arrayFormat: 'repeat' },\n );\n const newUrl = `${window.location.pathname}${newParams}`;\n window.history?.replaceState(null, document.title, newUrl);\n }, [\n cursor,\n isMounted,\n limit,\n location.search,\n offset,\n requestedFilters,\n paginationMode,\n ]);\n\n const updateFilters = useCallback(\n (\n update:\n | Partial<EntityFilter>\n | ((prevFilters: EntityFilters) => Partial<EntityFilters>),\n ) => {\n // changing filters will affect pagination, so we need to reset\n // the cursor and start from the first page.\n // TODO(vinzscam): this is currently causing issues at page reload\n // where the state is not kept. Unfortunately we need to rethink\n // the way filters work in order to fix this.\n if (paginationMode === 'cursor') {\n setCursor(undefined);\n } else if (paginationMode === 'offset') {\n // Same thing with offset\n setOffset(0);\n }\n setRequestedFilters(prevFilters => {\n const newFilters =\n typeof update === 'function' ? update(prevFilters) : update;\n return { ...prevFilters, ...newFilters };\n });\n },\n [paginationMode],\n );\n\n const triggerRefresh = useCallback(() => {\n // Clear the ref to allow refetching with the same params.\n lastFetchParamsRef.current = undefined;\n setRefreshToken(t => t + 1);\n }, []);\n\n const pageInfo = useMemo(() => {\n if (paginationMode !== 'cursor') {\n return undefined;\n }\n\n const prevCursor = backendState.pageInfo?.prevCursor;\n const nextCursor = backendState.pageInfo?.nextCursor;\n return {\n prev: prevCursor ? () => setCursor(prevCursor) : undefined,\n next: nextCursor ? () => setCursor(nextCursor) : undefined,\n };\n }, [paginationMode, backendState.pageInfo]);\n\n const value = useMemo(\n () => ({\n filters: requestedFilters,\n entities,\n backendEntities: backendState.backendEntities,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n totalItems:\n paginationMode === 'none'\n ? entities.length\n : totalItems ?? backendState.totalItems,\n totalItemsLoading: paginationMode !== 'none' && totalItemsLoading,\n limit,\n offset,\n setLimit,\n setOffset,\n paginationMode,\n refresh: triggerRefresh,\n }),\n [\n requestedFilters,\n entities,\n backendState,\n totalItems,\n totalItemsLoading,\n updateFilters,\n queryParameters,\n loading,\n error,\n pageInfo,\n paginationMode,\n limit,\n offset,\n setLimit,\n setOffset,\n triggerRefresh,\n ],\n );\n\n return (\n <OldEntityListContext.Provider value={value}>\n <NewEntityListContext.Provider\n value={createVersionedValueMap({ 1: value })}\n >\n {props.children}\n </NewEntityListContext.Provider>\n </OldEntityListContext.Provider>\n );\n};\n\n/**\n * Hook for interacting with the entity list context provided by the {@link EntityListProvider}.\n * @public\n */\nexport function useEntityList<\n EntityFilters extends DefaultEntityFilters = DefaultEntityFilters,\n>(): EntityListContextProps<EntityFilters> {\n const versionedHolder = useVersionedContext<{\n 1: EntityListContextProps<any>;\n }>('entity-list-context');\n const oldContext = useContext(OldEntityListContext);\n\n if (versionedHolder) {\n const value = versionedHolder.atVersion(1);\n if (!value) {\n throw new Error('EntityListContext v1 not available');\n }\n return value;\n }\n\n if (oldContext) {\n return oldContext;\n }\n\n throw new Error('useEntityList must be used within EntityListProvider');\n}\n"],"names":["limit","offset"],"mappings":"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"}
@@ -50,11 +50,7 @@ function useEntityTypeFilter() {
50
50
  return;
51
51
  }
52
52
  const newTypes = [
53
- ...new Set(
54
- sortBy(facets, (f) => -f.count).map(
55
- (f) => f.value.toLocaleLowerCase("en-US")
56
- )
57
- )
53
+ ...new Set(sortBy(facets, (f) => -f.count).map((f) => f.value.toLowerCase()))
58
54
  ];
59
55
  setAvailableTypes(newTypes);
60
56
  const stillValidTypes = selectedTypes.filter(
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityTypeFilter.esm.js","sources":["../../src/hooks/useEntityTypeFilter.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 */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport isEqual from 'lodash/isEqual';\nimport sortBy from 'lodash/sortBy';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '../api';\nimport { useEntityList } from './useEntityListProvider';\nimport { EntityTypeFilter } from '../filters';\n\n/**\n * A hook built on top of `useEntityList` for enabling selection of valid `spec.type` values\n * based on the selected EntityKindFilter.\n * @public\n */\nexport function useEntityTypeFilter(): {\n loading: boolean;\n error?: Error;\n availableTypes: string[];\n selectedTypes: string[];\n setSelectedTypes: (types: string[]) => void;\n} {\n const catalogApi = useApi(catalogApiRef);\n const {\n filters: { kind: kindFilter, type: typeFilter },\n queryParameters: { type: typeParameter },\n updateFilters,\n } = useEntityList();\n\n const flattenedQueryTypes = useMemo(\n () => [typeParameter].flat().filter(Boolean) as string[],\n [typeParameter],\n );\n\n const [selectedTypes, setSelectedTypes] = useState(\n flattenedQueryTypes.length\n ? flattenedQueryTypes\n : typeFilter?.getTypes() ?? [],\n );\n\n // Set selected types on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (flattenedQueryTypes.length) {\n setSelectedTypes(flattenedQueryTypes);\n }\n }, [flattenedQueryTypes]);\n\n const [availableTypes, setAvailableTypes] = useState<string[]>([]);\n const kind = useMemo(() => kindFilter?.value, [kindFilter]);\n\n // Load all valid spec.type values straight from the catalogApi, paying attention to only the\n // kind filter for a complete list.\n const {\n error,\n loading,\n value: facets,\n } = useAsync(async () => {\n if (kind) {\n const items = await catalogApi\n .getEntityFacets({\n filter: { kind },\n facets: ['spec.type'],\n })\n .then(response => response.facets['spec.type'] || []);\n return items;\n }\n return undefined;\n }, [kind, catalogApi]);\n\n const facetsRef = useRef(facets);\n useEffect(() => {\n const oldFacets = facetsRef.current;\n facetsRef.current = facets;\n // Delay processing hook until kind and facets load updates have settled to generate list of types;\n // This prevents resetting the type filter due to saved type value from query params not matching the\n // empty set of type values while values are still being loaded; also only run this hook on changes\n // to facets\n if (loading || !kind || oldFacets === facets || !facets) {\n return;\n }\n\n // Sort by facet count descending, so the most common types appear on top\n const newTypes = [\n ...new Set(\n sortBy(facets, f => -f.count).map(f =>\n f.value.toLocaleLowerCase('en-US'),\n ),\n ),\n ];\n setAvailableTypes(newTypes);\n\n // Update type filter to only valid values when the list of available types has changed\n const stillValidTypes = selectedTypes.filter(value =>\n newTypes.includes(value),\n );\n if (!isEqual(selectedTypes, stillValidTypes)) {\n setSelectedTypes(stillValidTypes);\n }\n }, [loading, kind, selectedTypes, setSelectedTypes, facets]);\n\n useEffect(() => {\n updateFilters({\n type: selectedTypes.length\n ? new EntityTypeFilter(selectedTypes)\n : undefined,\n });\n }, [selectedTypes, updateFilters]);\n\n return {\n loading,\n error,\n availableTypes,\n selectedTypes,\n setSelectedTypes,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useEntityTypeFilter.esm.js","sources":["../../src/hooks/useEntityTypeFilter.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 */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport isEqual from 'lodash/isEqual';\nimport sortBy from 'lodash/sortBy';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '../api';\nimport { useEntityList } from './useEntityListProvider';\nimport { EntityTypeFilter } from '../filters';\n\n/**\n * A hook built on top of `useEntityList` for enabling selection of valid `spec.type` values\n * based on the selected EntityKindFilter.\n * @public\n */\nexport function useEntityTypeFilter(): {\n loading: boolean;\n error?: Error;\n availableTypes: string[];\n selectedTypes: string[];\n setSelectedTypes: (types: string[]) => void;\n} {\n const catalogApi = useApi(catalogApiRef);\n const {\n filters: { kind: kindFilter, type: typeFilter },\n queryParameters: { type: typeParameter },\n updateFilters,\n } = useEntityList();\n\n const flattenedQueryTypes = useMemo(\n () => [typeParameter].flat().filter(Boolean) as string[],\n [typeParameter],\n );\n\n const [selectedTypes, setSelectedTypes] = useState(\n flattenedQueryTypes.length\n ? flattenedQueryTypes\n : typeFilter?.getTypes() ?? [],\n );\n\n // Set selected types on query parameter updates; this happens at initial page load and from\n // external updates to the page location.\n useEffect(() => {\n if (flattenedQueryTypes.length) {\n setSelectedTypes(flattenedQueryTypes);\n }\n }, [flattenedQueryTypes]);\n\n const [availableTypes, setAvailableTypes] = useState<string[]>([]);\n const kind = useMemo(() => kindFilter?.value, [kindFilter]);\n\n // Load all valid spec.type values straight from the catalogApi, paying attention to only the\n // kind filter for a complete list.\n const {\n error,\n loading,\n value: facets,\n } = useAsync(async () => {\n if (kind) {\n const items = await catalogApi\n .getEntityFacets({\n filter: { kind },\n facets: ['spec.type'],\n })\n .then(response => response.facets['spec.type'] || []);\n return items;\n }\n return undefined;\n }, [kind, catalogApi]);\n\n const facetsRef = useRef(facets);\n useEffect(() => {\n const oldFacets = facetsRef.current;\n facetsRef.current = facets;\n // Delay processing hook until kind and facets load updates have settled to generate list of types;\n // This prevents resetting the type filter due to saved type value from query params not matching the\n // empty set of type values while values are still being loaded; also only run this hook on changes\n // to facets\n if (loading || !kind || oldFacets === facets || !facets) {\n return;\n }\n\n // Sort by facet count descending, so the most common types appear on top\n const newTypes = [\n ...new Set(sortBy(facets, f => -f.count).map(f => f.value.toLowerCase())),\n ];\n setAvailableTypes(newTypes);\n\n // Update type filter to only valid values when the list of available types has changed\n const stillValidTypes = selectedTypes.filter(value =>\n newTypes.includes(value),\n );\n if (!isEqual(selectedTypes, stillValidTypes)) {\n setSelectedTypes(stillValidTypes);\n }\n }, [loading, kind, selectedTypes, setSelectedTypes, facets]);\n\n useEffect(() => {\n updateFilters({\n type: selectedTypes.length\n ? new EntityTypeFilter(selectedTypes)\n : undefined,\n });\n }, [selectedTypes, updateFilters]);\n\n return {\n loading,\n error,\n availableTypes,\n selectedTypes,\n setSelectedTypes,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;AA8BO,SAAS,mBAAA,GAMd;AACA,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAA,MAAM;AAAA,IACJ,OAAA,EAAS,EAAE,IAAA,EAAM,UAAA,EAAY,MAAM,UAAA,EAAW;AAAA,IAC9C,eAAA,EAAiB,EAAE,IAAA,EAAM,aAAA,EAAc;AAAA,IACvC;AAAA,MACE,aAAA,EAAc;AAElB,EAAA,MAAM,mBAAA,GAAsB,OAAA;AAAA,IAC1B,MAAM,CAAC,aAAa,EAAE,IAAA,EAAK,CAAE,OAAO,OAAO,CAAA;AAAA,IAC3C,CAAC,aAAa;AAAA,GAChB;AAEA,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,QAAA;AAAA,IACxC,oBAAoB,MAAA,GAChB,mBAAA,GACA,UAAA,EAAY,QAAA,MAAc;AAAC,GACjC;AAIA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,oBAAoB,MAAA,EAAQ;AAC9B,MAAA,gBAAA,CAAiB,mBAAmB,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,CAAC,mBAAmB,CAAC,CAAA;AAExB,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA,CAAmB,EAAE,CAAA;AACjE,EAAA,MAAM,OAAO,OAAA,CAAQ,MAAM,YAAY,KAAA,EAAO,CAAC,UAAU,CAAC,CAAA;AAI1D,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA,EAAO;AAAA,GACT,GAAI,SAAS,YAAY;AACvB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,KAAA,GAAQ,MAAM,UAAA,CACjB,eAAA,CAAgB;AAAA,QACf,MAAA,EAAQ,EAAE,IAAA,EAAK;AAAA,QACf,MAAA,EAAQ,CAAC,WAAW;AAAA,OACrB,EACA,IAAA,CAAK,CAAA,QAAA,KAAY,SAAS,MAAA,CAAO,WAAW,CAAA,IAAK,EAAE,CAAA;AACtD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,EAAG,CAAC,IAAA,EAAM,UAAU,CAAC,CAAA;AAErB,EAAA,MAAM,SAAA,GAAY,OAAO,MAAM,CAAA;AAC/B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAY,SAAA,CAAU,OAAA;AAC5B,IAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAKpB,IAAA,IAAI,WAAW,CAAC,IAAA,IAAQ,SAAA,KAAc,MAAA,IAAU,CAAC,MAAA,EAAQ;AACvD,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,QAAA,GAAW;AAAA,MACf,GAAG,IAAI,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQ,OAAK,CAAC,CAAA,CAAE,KAAK,CAAA,CAAE,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,KAAA,CAAM,WAAA,EAAa,CAAC;AAAA,KAC1E;AACA,IAAA,iBAAA,CAAkB,QAAQ,CAAA;AAG1B,IAAA,MAAM,kBAAkB,aAAA,CAAc,MAAA;AAAA,MAAO,CAAA,KAAA,KAC3C,QAAA,CAAS,QAAA,CAAS,KAAK;AAAA,KACzB;AACA,IAAA,IAAI,CAAC,OAAA,CAAQ,aAAA,EAAe,eAAe,CAAA,EAAG;AAC5C,MAAA,gBAAA,CAAiB,eAAe,CAAA;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,OAAA,EAAS,MAAM,aAAA,EAAe,gBAAA,EAAkB,MAAM,CAAC,CAAA;AAE3D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,aAAA,CAAc;AAAA,MACZ,MAAM,aAAA,CAAc,MAAA,GAChB,IAAI,gBAAA,CAAiB,aAAa,CAAA,GAClC;AAAA,KACL,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,aAAA,EAAe,aAAa,CAAC,CAAA;AAEjC,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,KAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -4,8 +4,8 @@ import useAsync from 'react-use/esm/useAsync';
4
4
  import { catalogApiRef } from '../api.esm.js';
5
5
 
6
6
  function useRelatedEntities(entity, relationFilter) {
7
- const filterByTypeLower = relationFilter?.type?.toLocaleLowerCase("en-US");
8
- const filterByKindLower = relationFilter?.kind?.toLocaleLowerCase("en-US");
7
+ const filterByTypeLower = relationFilter?.type?.toLowerCase();
8
+ const filterByKindLower = relationFilter?.kind?.toLowerCase();
9
9
  const catalogApi = useApi(catalogApiRef);
10
10
  const {
11
11
  loading,
@@ -13,7 +13,7 @@ function useRelatedEntities(entity, relationFilter) {
13
13
  error
14
14
  } = useAsync(async () => {
15
15
  const relations = entity.relations?.filter(
16
- (r) => (!filterByTypeLower || r.type.toLocaleLowerCase("en-US") === filterByTypeLower) && (!filterByKindLower || parseEntityRef(r.targetRef).kind === filterByKindLower)
16
+ (r) => (!filterByTypeLower || r.type.toLowerCase() === filterByTypeLower) && (!filterByKindLower || parseEntityRef(r.targetRef).kind === filterByKindLower)
17
17
  );
18
18
  if (!relations?.length) {
19
19
  return [];
@@ -1 +1 @@
1
- {"version":3,"file":"useRelatedEntities.esm.js","sources":["../../src/hooks/useRelatedEntities.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { Entity, parseEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../api';\n\n/**\n * Fetches all entities that appear in the entity's relations, optionally\n * filtered by relation type and kind.\n *\n * @public\n */\nexport function useRelatedEntities(\n entity: Entity,\n relationFilter: { type?: string; kind?: string },\n): {\n entities: Entity[] | undefined;\n loading: boolean;\n error: Error | undefined;\n} {\n const filterByTypeLower = relationFilter?.type?.toLocaleLowerCase('en-US');\n const filterByKindLower = relationFilter?.kind?.toLocaleLowerCase('en-US');\n const catalogApi = useApi(catalogApiRef);\n\n const {\n loading,\n value: entities,\n error,\n } = useAsync(async () => {\n const relations = entity.relations?.filter(\n r =>\n (!filterByTypeLower ||\n r.type.toLocaleLowerCase('en-US') === filterByTypeLower) &&\n (!filterByKindLower ||\n parseEntityRef(r.targetRef).kind === filterByKindLower),\n );\n\n if (!relations?.length) {\n return [];\n }\n\n const { items } = await catalogApi.getEntitiesByRefs({\n entityRefs: relations.map(r => r.targetRef),\n });\n\n return items.filter((x): x is Entity => Boolean(x));\n }, [entity, filterByTypeLower, filterByKindLower]);\n\n return {\n entities,\n loading,\n error,\n };\n}\n"],"names":[],"mappings":";;;;;AA2BO,SAAS,kBAAA,CACd,QACA,cAAA,EAKA;AACA,EAAA,MAAM,iBAAA,GAAoB,cAAA,EAAgB,IAAA,EAAM,iBAAA,CAAkB,OAAO,CAAA;AACzE,EAAA,MAAM,iBAAA,GAAoB,cAAA,EAAgB,IAAA,EAAM,iBAAA,CAAkB,OAAO,CAAA;AACzE,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,KAAA,EAAO,QAAA;AAAA,IACP;AAAA,GACF,GAAI,SAAS,YAAY;AACvB,IAAA,MAAM,SAAA,GAAY,OAAO,SAAA,EAAW,MAAA;AAAA,MAClC,CAAA,CAAA,KAAA,CACG,CAAC,iBAAA,IACA,CAAA,CAAE,KAAK,iBAAA,CAAkB,OAAO,CAAA,KAAM,iBAAA,MACvC,CAAC,iBAAA,IACA,cAAA,CAAe,CAAA,CAAE,SAAS,EAAE,IAAA,KAAS,iBAAA;AAAA,KAC3C;AAEA,IAAA,IAAI,CAAC,WAAW,MAAA,EAAQ;AACtB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,WAAW,iBAAA,CAAkB;AAAA,MACnD,UAAA,EAAY,SAAA,CAAU,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,SAAS;AAAA,KAC3C,CAAA;AAED,IAAA,OAAO,MAAM,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,EACpD,CAAA,EAAG,CAAC,MAAA,EAAQ,iBAAA,EAAmB,iBAAiB,CAAC,CAAA;AAEjD,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"useRelatedEntities.esm.js","sources":["../../src/hooks/useRelatedEntities.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { Entity, parseEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { catalogApiRef } from '../api';\n\n/**\n * Fetches all entities that appear in the entity's relations, optionally\n * filtered by relation type and kind.\n *\n * @public\n */\nexport function useRelatedEntities(\n entity: Entity,\n relationFilter: { type?: string; kind?: string },\n): {\n entities: Entity[] | undefined;\n loading: boolean;\n error: Error | undefined;\n} {\n const filterByTypeLower = relationFilter?.type?.toLowerCase();\n const filterByKindLower = relationFilter?.kind?.toLowerCase();\n const catalogApi = useApi(catalogApiRef);\n\n const {\n loading,\n value: entities,\n error,\n } = useAsync(async () => {\n const relations = entity.relations?.filter(\n r =>\n (!filterByTypeLower || r.type.toLowerCase() === filterByTypeLower) &&\n (!filterByKindLower ||\n parseEntityRef(r.targetRef).kind === filterByKindLower),\n );\n\n if (!relations?.length) {\n return [];\n }\n\n const { items } = await catalogApi.getEntitiesByRefs({\n entityRefs: relations.map(r => r.targetRef),\n });\n\n return items.filter((x): x is Entity => Boolean(x));\n }, [entity, filterByTypeLower, filterByKindLower]);\n\n return {\n entities,\n loading,\n error,\n };\n}\n"],"names":[],"mappings":";;;;;AA2BO,SAAS,kBAAA,CACd,QACA,cAAA,EAKA;AACA,EAAA,MAAM,iBAAA,GAAoB,cAAA,EAAgB,IAAA,EAAM,WAAA,EAAY;AAC5D,EAAA,MAAM,iBAAA,GAAoB,cAAA,EAAgB,IAAA,EAAM,WAAA,EAAY;AAC5D,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,KAAA,EAAO,QAAA;AAAA,IACP;AAAA,GACF,GAAI,SAAS,YAAY;AACvB,IAAA,MAAM,SAAA,GAAY,OAAO,SAAA,EAAW,MAAA;AAAA,MAClC,CAAA,CAAA,KAAA,CACG,CAAC,iBAAA,IAAqB,CAAA,CAAE,KAAK,WAAA,EAAY,KAAM,iBAAA,MAC/C,CAAC,iBAAA,IACA,cAAA,CAAe,CAAA,CAAE,SAAS,EAAE,IAAA,KAAS,iBAAA;AAAA,KAC3C;AAEA,IAAA,IAAI,CAAC,WAAW,MAAA,EAAQ;AACtB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,WAAW,iBAAA,CAAkB;AAAA,MACnD,UAAA,EAAY,SAAA,CAAU,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,SAAS;AAAA,KAC3C,CAAA;AAED,IAAA,OAAO,MAAM,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,EACpD,CAAA,EAAG,CAAC,MAAA,EAAQ,iBAAA,EAAmB,iBAAiB,CAAC,CAAA;AAEjD,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -27,8 +27,8 @@ function entityRouteParams(entityOrRef, options) {
27
27
  namespace = entityOrRef.namespace;
28
28
  name = entityOrRef.name;
29
29
  }
30
- kind = kind.toLocaleLowerCase("en-US");
31
- namespace = namespace?.toLocaleLowerCase("en-US") ?? DEFAULT_NAMESPACE;
30
+ kind = kind.toLowerCase();
31
+ namespace = namespace?.toLowerCase() ?? DEFAULT_NAMESPACE;
32
32
  const { encodeParams = false } = options || {};
33
33
  if (encodeParams) {
34
34
  kind = encodeURIComponent(kind);
@@ -1 +1 @@
1
- {"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n DEFAULT_NAMESPACE,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport { createRouteRef } from '@backstage/core-plugin-api';\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n/**\n * A stable route ref that points to the catalog page for an individual entity.\n *\n * This `RouteRef` can be imported and used directly, and does not need to be referenced\n * via an `ExternalRouteRef`.\n *\n * If you want to replace the `EntityPage` from `@backstage/catalog-plugin` in your app,\n * you need to use the `entityRouteRef` as the mount point instead of your own.\n * @public\n */\nexport const entityRouteRef = getOrCreateGlobalSingleton(\n 'catalog:entity-route-ref',\n () =>\n createRouteRef({\n id: 'catalog:entity',\n params: ['namespace', 'kind', 'name'],\n }),\n);\n\n/**\n * Configurable options for `entityRouteParams`\n * @public\n */\nexport type EntityRouteParamsOptions = {\n encodeParams?: boolean;\n};\n\n/**\n * Utility function to get suitable route params for entityRoute, given an\n * @public\n */\nexport function entityRouteParams(\n entityOrRef: Entity | CompoundEntityRef | string,\n options?: EntityRouteParamsOptions,\n) {\n let kind;\n let namespace;\n let name;\n\n if (typeof entityOrRef === 'string') {\n const parsed = parseEntityRef(entityOrRef);\n kind = parsed.kind;\n namespace = parsed.namespace;\n name = parsed.name;\n } else if ('metadata' in entityOrRef) {\n kind = entityOrRef.kind;\n namespace = entityOrRef.metadata.namespace;\n name = entityOrRef.metadata.name;\n } else {\n kind = entityOrRef.kind;\n namespace = entityOrRef.namespace;\n name = entityOrRef.name;\n }\n\n kind = kind.toLocaleLowerCase('en-US');\n namespace = namespace?.toLocaleLowerCase('en-US') ?? DEFAULT_NAMESPACE;\n\n const { encodeParams = false } = options || {};\n if (encodeParams) {\n kind = encodeURIComponent(kind);\n namespace = encodeURIComponent(namespace);\n name = encodeURIComponent(name);\n }\n\n return {\n kind,\n namespace,\n name,\n } as const;\n}\n"],"names":[],"mappings":";;;;AAmCO,MAAM,cAAA,GAAiB,0BAAA;AAAA,EAC5B,0BAAA;AAAA,EACA,MACE,cAAA,CAAe;AAAA,IACb,EAAA,EAAI,gBAAA;AAAA,IACJ,MAAA,EAAQ,CAAC,WAAA,EAAa,MAAA,EAAQ,MAAM;AAAA,GACrC;AACL;AAcO,SAAS,iBAAA,CACd,aACA,OAAA,EACA;AACA,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,OAAO,gBAAgB,QAAA,EAAU;AACnC,IAAA,MAAM,MAAA,GAAS,eAAe,WAAW,CAAA;AACzC,IAAA,IAAA,GAAO,MAAA,CAAO,IAAA;AACd,IAAA,SAAA,GAAY,MAAA,CAAO,SAAA;AACnB,IAAA,IAAA,GAAO,MAAA,CAAO,IAAA;AAAA,EAChB,CAAA,MAAA,IAAW,cAAc,WAAA,EAAa;AACpC,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AACnB,IAAA,SAAA,GAAY,YAAY,QAAA,CAAS,SAAA;AACjC,IAAA,IAAA,GAAO,YAAY,QAAA,CAAS,IAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AACnB,IAAA,SAAA,GAAY,WAAA,CAAY,SAAA;AACxB,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AAAA,EACrB;AAEA,EAAA,IAAA,GAAO,IAAA,CAAK,kBAAkB,OAAO,CAAA;AACrC,EAAA,SAAA,GAAY,SAAA,EAAW,iBAAA,CAAkB,OAAO,CAAA,IAAK,iBAAA;AAErD,EAAA,MAAM,EAAE,YAAA,GAAe,KAAA,EAAM,GAAI,WAAW,EAAC;AAC7C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,IAAA,GAAO,mBAAmB,IAAI,CAAA;AAC9B,IAAA,SAAA,GAAY,mBAAmB,SAAS,CAAA;AACxC,IAAA,IAAA,GAAO,mBAAmB,IAAI,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n DEFAULT_NAMESPACE,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport { createRouteRef } from '@backstage/core-plugin-api';\nimport { getOrCreateGlobalSingleton } from '@backstage/version-bridge';\n\n/**\n * A stable route ref that points to the catalog page for an individual entity.\n *\n * This `RouteRef` can be imported and used directly, and does not need to be referenced\n * via an `ExternalRouteRef`.\n *\n * If you want to replace the `EntityPage` from `@backstage/catalog-plugin` in your app,\n * you need to use the `entityRouteRef` as the mount point instead of your own.\n * @public\n */\nexport const entityRouteRef = getOrCreateGlobalSingleton(\n 'catalog:entity-route-ref',\n () =>\n createRouteRef({\n id: 'catalog:entity',\n params: ['namespace', 'kind', 'name'],\n }),\n);\n\n/**\n * Configurable options for `entityRouteParams`\n * @public\n */\nexport type EntityRouteParamsOptions = {\n encodeParams?: boolean;\n};\n\n/**\n * Utility function to get suitable route params for entityRoute, given an\n * @public\n */\nexport function entityRouteParams(\n entityOrRef: Entity | CompoundEntityRef | string,\n options?: EntityRouteParamsOptions,\n) {\n let kind;\n let namespace;\n let name;\n\n if (typeof entityOrRef === 'string') {\n const parsed = parseEntityRef(entityOrRef);\n kind = parsed.kind;\n namespace = parsed.namespace;\n name = parsed.name;\n } else if ('metadata' in entityOrRef) {\n kind = entityOrRef.kind;\n namespace = entityOrRef.metadata.namespace;\n name = entityOrRef.metadata.name;\n } else {\n kind = entityOrRef.kind;\n namespace = entityOrRef.namespace;\n name = entityOrRef.name;\n }\n\n kind = kind.toLowerCase();\n namespace = namespace?.toLowerCase() ?? DEFAULT_NAMESPACE;\n\n const { encodeParams = false } = options || {};\n if (encodeParams) {\n kind = encodeURIComponent(kind);\n namespace = encodeURIComponent(namespace);\n name = encodeURIComponent(name);\n }\n\n return {\n kind,\n namespace,\n name,\n } as const;\n}\n"],"names":[],"mappings":";;;;AAmCO,MAAM,cAAA,GAAiB,0BAAA;AAAA,EAC5B,0BAAA;AAAA,EACA,MACE,cAAA,CAAe;AAAA,IACb,EAAA,EAAI,gBAAA;AAAA,IACJ,MAAA,EAAQ,CAAC,WAAA,EAAa,MAAA,EAAQ,MAAM;AAAA,GACrC;AACL;AAcO,SAAS,iBAAA,CACd,aACA,OAAA,EACA;AACA,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI,OAAO,gBAAgB,QAAA,EAAU;AACnC,IAAA,MAAM,MAAA,GAAS,eAAe,WAAW,CAAA;AACzC,IAAA,IAAA,GAAO,MAAA,CAAO,IAAA;AACd,IAAA,SAAA,GAAY,MAAA,CAAO,SAAA;AACnB,IAAA,IAAA,GAAO,MAAA,CAAO,IAAA;AAAA,EAChB,CAAA,MAAA,IAAW,cAAc,WAAA,EAAa;AACpC,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AACnB,IAAA,SAAA,GAAY,YAAY,QAAA,CAAS,SAAA;AACjC,IAAA,IAAA,GAAO,YAAY,QAAA,CAAS,IAAA;AAAA,EAC9B,CAAA,MAAO;AACL,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AACnB,IAAA,SAAA,GAAY,WAAA,CAAY,SAAA;AACxB,IAAA,IAAA,GAAO,WAAA,CAAY,IAAA;AAAA,EACrB;AAEA,EAAA,IAAA,GAAO,KAAK,WAAA,EAAY;AACxB,EAAA,SAAA,GAAY,SAAA,EAAW,aAAY,IAAK,iBAAA;AAExC,EAAA,MAAM,EAAE,YAAA,GAAe,KAAA,EAAM,GAAI,WAAW,EAAC;AAC7C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,IAAA,GAAO,mBAAmB,IAAI,CAAA;AAC9B,IAAA,SAAA,GAAY,mBAAmB,SAAS,CAAA;AACxC,IAAA,IAAA,GAAO,mBAAmB,IAAI,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -4,7 +4,7 @@ function getEntityRelations(entity, relationType, filter) {
4
4
  let entityNames = entity?.relations?.filter((r) => r.type === relationType).map((r) => parseEntityRef(r.targetRef)) || [];
5
5
  if (filter?.kind) {
6
6
  entityNames = entityNames.filter(
7
- (e) => e.kind.toLocaleLowerCase("en-US") === filter.kind.toLocaleLowerCase("en-US")
7
+ (e) => e.kind.toLowerCase() === filter.kind.toLowerCase()
8
8
  );
9
9
  }
10
10
  return entityNames;
@@ -1 +1 @@
1
- {"version":3,"file":"getEntityRelations.esm.js","sources":["../../src/utils/getEntityRelations.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\n\n// TODO(freben): This should be returning entity refs instead\n/**\n * Get the related entity references.\n *\n * @public\n */\nexport function getEntityRelations(\n entity: Entity | undefined,\n relationType: string,\n filter?: { kind: string },\n): CompoundEntityRef[] {\n let entityNames =\n entity?.relations\n ?.filter(r => r.type === relationType)\n .map(r => parseEntityRef(r.targetRef)) || [];\n\n if (filter?.kind) {\n entityNames = entityNames.filter(\n e =>\n e.kind.toLocaleLowerCase('en-US') ===\n filter.kind.toLocaleLowerCase('en-US'),\n );\n }\n\n return entityNames;\n}\n"],"names":[],"mappings":";;AA4BO,SAAS,kBAAA,CACd,MAAA,EACA,YAAA,EACA,MAAA,EACqB;AACrB,EAAA,IAAI,cACF,MAAA,EAAQ,SAAA,EACJ,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,YAAY,CAAA,CACpC,GAAA,CAAI,OAAK,cAAA,CAAe,CAAA,CAAE,SAAS,CAAC,KAAK,EAAC;AAE/C,EAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,IAAA,WAAA,GAAc,WAAA,CAAY,MAAA;AAAA,MACxB,CAAA,CAAA,KACE,EAAE,IAAA,CAAK,iBAAA,CAAkB,OAAO,CAAA,KAChC,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO;AAAA,KACzC;AAAA,EACF;AAEA,EAAA,OAAO,WAAA;AACT;;;;"}
1
+ {"version":3,"file":"getEntityRelations.esm.js","sources":["../../src/utils/getEntityRelations.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Entity,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\n\n// TODO(freben): This should be returning entity refs instead\n/**\n * Get the related entity references.\n *\n * @public\n */\nexport function getEntityRelations(\n entity: Entity | undefined,\n relationType: string,\n filter?: { kind: string },\n): CompoundEntityRef[] {\n let entityNames =\n entity?.relations\n ?.filter(r => r.type === relationType)\n .map(r => parseEntityRef(r.targetRef)) || [];\n\n if (filter?.kind) {\n entityNames = entityNames.filter(\n e => e.kind.toLowerCase() === filter.kind.toLowerCase(),\n );\n }\n\n return entityNames;\n}\n"],"names":[],"mappings":";;AA4BO,SAAS,kBAAA,CACd,MAAA,EACA,YAAA,EACA,MAAA,EACqB;AACrB,EAAA,IAAI,cACF,MAAA,EAAQ,SAAA,EACJ,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,YAAY,CAAA,CACpC,GAAA,CAAI,OAAK,cAAA,CAAe,CAAA,CAAE,SAAS,CAAC,KAAK,EAAC;AAE/C,EAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,IAAA,WAAA,GAAc,WAAA,CAAY,MAAA;AAAA,MACxB,OAAK,CAAA,CAAE,IAAA,CAAK,aAAY,KAAM,MAAA,CAAO,KAAK,WAAA;AAAY,KACxD;AAAA,EACF;AAEA,EAAA,OAAO,WAAA;AACT;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "3.2.3-next.1",
3
+ "version": "3.2.3",
4
4
  "description": "A frontend library that helps other Backstage plugins interact with the catalog",
5
5
  "backstage": {
6
6
  "role": "web-library",
@@ -73,20 +73,20 @@
73
73
  "test": "backstage-cli package test"
74
74
  },
75
75
  "dependencies": {
76
- "@backstage/catalog-client": "1.16.2-next.0",
77
- "@backstage/catalog-model": "1.10.0",
78
- "@backstage/core-compat-api": "0.5.15-next.1",
79
- "@backstage/core-components": "0.18.14-next.1",
80
- "@backstage/core-plugin-api": "1.12.10-next.0",
81
- "@backstage/errors": "1.3.1",
82
- "@backstage/filter-predicates": "0.1.5-next.0",
83
- "@backstage/frontend-plugin-api": "0.18.1-next.0",
84
- "@backstage/integration-react": "1.2.22-next.0",
85
- "@backstage/plugin-permission-common": "0.9.10",
86
- "@backstage/plugin-permission-react": "0.5.5-next.0",
87
- "@backstage/types": "1.2.2",
88
- "@backstage/ui": "0.18.0-next.1",
89
- "@backstage/version-bridge": "1.0.12",
76
+ "@backstage/catalog-client": "^1.16.2",
77
+ "@backstage/catalog-model": "^1.10.1",
78
+ "@backstage/core-compat-api": "^0.5.15",
79
+ "@backstage/core-components": "^0.18.14",
80
+ "@backstage/core-plugin-api": "^1.12.10",
81
+ "@backstage/errors": "^1.3.1",
82
+ "@backstage/filter-predicates": "^0.1.5",
83
+ "@backstage/frontend-plugin-api": "^0.18.1",
84
+ "@backstage/integration-react": "^1.2.22",
85
+ "@backstage/plugin-permission-common": "^0.9.11",
86
+ "@backstage/plugin-permission-react": "^0.5.5",
87
+ "@backstage/types": "^1.2.2",
88
+ "@backstage/ui": "^0.18.0",
89
+ "@backstage/version-bridge": "^1.0.12",
90
90
  "@material-ui/core": "^4.12.2",
91
91
  "@material-ui/icons": "^4.9.1",
92
92
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -104,12 +104,12 @@
104
104
  "zod": "^4.0.0"
105
105
  },
106
106
  "devDependencies": {
107
- "@backstage/cli": "0.36.6-next.0",
108
- "@backstage/core-app-api": "1.20.5-next.1",
109
- "@backstage/frontend-test-utils": "0.6.4-next.1",
110
- "@backstage/plugin-catalog-common": "1.1.10",
111
- "@backstage/plugin-scaffolder-common": "2.3.0-next.1",
112
- "@backstage/test-utils": "1.7.22-next.1",
107
+ "@backstage/cli": "^0.36.6",
108
+ "@backstage/core-app-api": "^1.20.5",
109
+ "@backstage/frontend-test-utils": "^0.6.4",
110
+ "@backstage/plugin-catalog-common": "^1.2.0",
111
+ "@backstage/plugin-scaffolder-common": "^2.3.0",
112
+ "@backstage/test-utils": "^1.7.22",
113
113
  "@testing-library/dom": "^10.0.0",
114
114
  "@testing-library/jest-dom": "^6.0.0",
115
115
  "@testing-library/react": "^16.0.0",
@@ -123,7 +123,7 @@
123
123
  "react-test-renderer": "^16.13.1"
124
124
  },
125
125
  "peerDependencies": {
126
- "@backstage/frontend-test-utils": "0.6.4-next.1",
126
+ "@backstage/frontend-test-utils": "^0.6.4",
127
127
  "@types/react": "^17.0.0 || ^18.0.0",
128
128
  "react": "^17.0.0 || ^18.0.0",
129
129
  "react-dom": "^17.0.0 || ^18.0.0",