@backstage/plugin-catalog-react 2.1.2-next.1 → 2.1.2-next.2

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 (40) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/alpha.d.ts +7 -0
  3. package/dist/apis/EntityPresentationApi/EntityPresentationApi.esm.js.map +1 -1
  4. package/dist/apis/EntityPresentationApi/defaultEntityPresentation.esm.js.map +1 -1
  5. package/dist/apis/EntityPresentationApi/entityPresentationSnapshot.esm.js +13 -0
  6. package/dist/apis/EntityPresentationApi/entityPresentationSnapshot.esm.js.map +1 -0
  7. package/dist/apis/EntityPresentationApi/useEntityPresentation.esm.js.map +1 -1
  8. package/dist/components/EntityDataTable/columnFactories.esm.js +14 -3
  9. package/dist/components/EntityDataTable/columnFactories.esm.js.map +1 -1
  10. package/dist/components/EntityDisplayName/EntityDisplayName.esm.js.map +1 -1
  11. package/dist/components/EntityOwnerPicker/EntityOwnerPicker.esm.js +11 -4
  12. package/dist/components/EntityOwnerPicker/EntityOwnerPicker.esm.js.map +1 -1
  13. package/dist/components/EntityRefLink/humanize.esm.js +2 -11
  14. package/dist/components/EntityRefLink/humanize.esm.js.map +1 -1
  15. package/dist/components/EntityRelationCard/EntityRelationCard.esm.js +1 -0
  16. package/dist/components/EntityRelationCard/EntityRelationCard.esm.js.map +1 -1
  17. package/dist/components/EntityTable/columns.esm.js +27 -7
  18. package/dist/components/EntityTable/columns.esm.js.map +1 -1
  19. package/dist/components/InspectEntityDialog/InspectEntityDialog.esm.js +50 -98
  20. package/dist/components/InspectEntityDialog/InspectEntityDialog.esm.js.map +1 -1
  21. package/dist/components/InspectEntityDialog/components/AncestryPage.esm.js +10 -13
  22. package/dist/components/InspectEntityDialog/components/AncestryPage.esm.js.map +1 -1
  23. package/dist/components/InspectEntityDialog/components/ColocatedPage.esm.js +63 -19
  24. package/dist/components/InspectEntityDialog/components/ColocatedPage.esm.js.map +1 -1
  25. package/dist/components/InspectEntityDialog/components/JsonPage.esm.js +4 -5
  26. package/dist/components/InspectEntityDialog/components/JsonPage.esm.js.map +1 -1
  27. package/dist/components/InspectEntityDialog/components/OverviewPage.esm.js +243 -94
  28. package/dist/components/InspectEntityDialog/components/OverviewPage.esm.js.map +1 -1
  29. package/dist/components/InspectEntityDialog/components/YamlPage.esm.js +4 -5
  30. package/dist/components/InspectEntityDialog/components/YamlPage.esm.js.map +1 -1
  31. package/dist/components/InspectEntityDialog/components/common.esm.js +32 -68
  32. package/dist/components/InspectEntityDialog/components/common.esm.js.map +1 -1
  33. package/dist/components/UnregisterEntityDialog/UnregisterEntityDialog.esm.js +3 -5
  34. package/dist/components/UnregisterEntityDialog/UnregisterEntityDialog.esm.js.map +1 -1
  35. package/dist/index.d.ts +117 -5
  36. package/dist/index.esm.js +1 -0
  37. package/dist/index.esm.js.map +1 -1
  38. package/dist/translation.esm.js +6 -2
  39. package/dist/translation.esm.js.map +1 -1
  40. package/package.json +22 -21
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 2.1.2-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 482ceed: Migrated from `assertError` to `toError` for error handling.
8
+ - 5f9a531: Deprecated `humanizeEntityRef` and `humanizeEntity` in favor of the Catalog Presentation API. Use `useEntityPresentation`, `EntityDisplayName`, or `entityPresentationApiRef` instead.
9
+ - fa232da: Migrated `InspectEntityDialog` from Material UI to Backstage UI components. Added new translation keys: `inspectEntityDialog.overviewPage.copyAriaLabel`, `inspectEntityDialog.overviewPage.copiedStatus`, `inspectEntityDialog.overviewPage.helpLinkAriaLabel`, and `inspectEntityDialog.colocatedPage.entityListAriaLabel`.
10
+ - Updated dependencies
11
+ - @backstage/ui@0.14.0-next.2
12
+ - @backstage/errors@1.3.0-next.0
13
+ - @backstage/core-components@0.18.9-next.1
14
+ - @backstage/catalog-client@1.14.1-next.0
15
+ - @backstage/catalog-model@1.7.8-next.0
16
+ - @backstage/core-compat-api@0.5.10-next.2
17
+ - @backstage/core-plugin-api@1.12.5-next.2
18
+ - @backstage/filter-predicates@0.1.2-next.0
19
+ - @backstage/frontend-plugin-api@0.16.0-next.2
20
+ - @backstage/plugin-permission-common@0.9.8-next.0
21
+ - @backstage/integration-react@1.2.17-next.1
22
+ - @backstage/plugin-catalog-common@1.1.9-next.0
23
+ - @backstage/frontend-test-utils@0.5.2-next.2
24
+ - @backstage/plugin-permission-react@0.4.42-next.1
25
+
3
26
  ## 2.1.2-next.1
4
27
 
5
28
  ### Patch Changes
package/dist/alpha.d.ts CHANGED
@@ -8,6 +8,7 @@ import { IconLinkVerticalProps } from '@backstage/core-components';
8
8
  import { ResourcePermission } from '@backstage/plugin-permission-common';
9
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
10
10
  import { ColumnConfig, TableItem } from '@backstage/ui';
11
+ import { EntityPresentationApi } from '@backstage/plugin-catalog-react';
11
12
 
12
13
  /**
13
14
  * Returns true if the `owner` argument is a direct owner on the `entity` argument.
@@ -364,6 +365,7 @@ declare const columnFactories: Readonly<{
364
365
  createEntityRefColumn(options: {
365
366
  defaultKind?: string;
366
367
  isRowHeader?: boolean;
368
+ entityPresentationApi?: EntityPresentationApi;
367
369
  }): EntityColumnConfig;
368
370
  createEntityRelationColumn(options: {
369
371
  id: string;
@@ -373,6 +375,7 @@ declare const columnFactories: Readonly<{
373
375
  filter?: {
374
376
  kind: string;
375
377
  };
378
+ entityPresentationApi?: EntityPresentationApi;
376
379
  }): EntityColumnConfig;
377
380
  createOwnerColumn(): EntityColumnConfig;
378
381
  createSystemColumn(): EntityColumnConfig;
@@ -466,6 +469,7 @@ declare const catalogReactTranslationRef: _backstage_frontend_plugin_api.Transla
466
469
  readonly "inspectEntityDialog.colocatedPage.alertNoEntity": "There were no other entities on this location.";
467
470
  readonly "inspectEntityDialog.colocatedPage.locationHeader": "At the same location";
468
471
  readonly "inspectEntityDialog.colocatedPage.originHeader": "At the same origin";
472
+ readonly "inspectEntityDialog.colocatedPage.entityListAriaLabel": "Colocated entities";
469
473
  readonly "inspectEntityDialog.jsonPage.title": "Entity as JSON";
470
474
  readonly "inspectEntityDialog.jsonPage.description": "This is the raw entity data as received from the catalog, on JSON form.";
471
475
  readonly "inspectEntityDialog.overviewPage.title": "Overview";
@@ -475,6 +479,9 @@ declare const catalogReactTranslationRef: _backstage_frontend_plugin_api.Transla
475
479
  readonly "inspectEntityDialog.overviewPage.identity.title": "Identity";
476
480
  readonly "inspectEntityDialog.overviewPage.annotations": "Annotations";
477
481
  readonly "inspectEntityDialog.overviewPage.tags": "Tags";
482
+ readonly "inspectEntityDialog.overviewPage.copyAriaLabel": "Copy {{label}}";
483
+ readonly "inspectEntityDialog.overviewPage.copiedStatus": "Copied";
484
+ readonly "inspectEntityDialog.overviewPage.helpLinkAriaLabel": "Learn more";
478
485
  readonly "inspectEntityDialog.overviewPage.relation.title": "Relations";
479
486
  readonly "inspectEntityDialog.yamlPage.title": "Entity as YAML";
480
487
  readonly "inspectEntityDialog.yamlPage.description": "This is the raw entity data as received from the catalog, on YAML form.";
@@ -1 +1 @@
1
- {"version":3,"file":"EntityPresentationApi.esm.js","sources":["../../../src/apis/EntityPresentationApi/EntityPresentationApi.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 { Entity } from '@backstage/catalog-model';\nimport {\n ApiRef,\n IconComponent,\n createApiRef,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\n\n/**\n * An API that handles how to represent entities in the interface.\n *\n * @public\n */\nexport const entityPresentationApiRef: ApiRef<EntityPresentationApi> =\n createApiRef({\n id: 'plugin.catalog.entity-presentation',\n });\n\n/**\n * The visual presentation of an entity reference at some point in time.\n *\n * @public\n */\nexport interface EntityRefPresentationSnapshot {\n /**\n * The ref to the entity that this snapshot represents.\n *\n * @remarks\n *\n * Note that when the input data was broken or had missing vital pieces of\n * information, this string may contain placeholders such as \"unknown\". You\n * can therefore not necessarily assume that the ref is completely valid and\n * usable for example for forming a clickable link to the entity.\n */\n entityRef: string;\n /**\n * A string that can be used as a plain representation of the entity, for\n * example in a header or a link.\n *\n * @remarks\n *\n * The title may be short and not contain all of the information that the\n * entity holds. When rendering the primary title, you may also want to\n * make sure to add more contextual information nearby such as the icon or\n * secondary title, since the primary could for example just be the\n * `metadata.name` of the entity which might be ambiguous to the reader.\n */\n primaryTitle: string;\n /**\n * Optionally, some additional textual information about the entity, to be\n * used as a clarification on top of the primary title.\n *\n * @remarks\n *\n * This text can for example be rendered in a tooltip or be used as a\n * subtitle. It may not be sufficient to display on its own; it should\n * typically be used in conjunction with the primary title. It can contain\n * such information as the entity ref and/or a `spec.type` etc.\n */\n secondaryTitle?: string;\n /**\n * Optionally, an icon that represents the kind/type of entity.\n *\n * @remarks\n *\n * This icon should ideally be easily recognizable as the kind of entity, and\n * be used consistently throughout the Backstage interface. It can be rendered\n * both in larger formats such as in a header, or in smaller formats such as\n * inline with regular text, so bear in mind that the legibility should be\n * high in both cases.\n *\n * A value of `false` here indicates the desire to not have an icon present\n * for the given implementation. A value of `undefined` leaves it at the\n * discretion of the display layer to choose what to do (such as for example\n * showing a fallback icon).\n */\n Icon?: IconComponent | undefined | false;\n}\n\n/**\n * The visual presentation of an entity reference.\n *\n * @public\n */\nexport interface EntityRefPresentation {\n /**\n * The representation that's suitable to use for this entity right now.\n */\n snapshot: EntityRefPresentationSnapshot;\n /**\n * Some presentation implementations support emitting updated snapshots over\n * time, for example after retrieving additional data from the catalog or\n * elsewhere.\n */\n update$?: Observable<EntityRefPresentationSnapshot>;\n /**\n * A promise that resolves to a usable entity presentation.\n */\n promise: Promise<EntityRefPresentationSnapshot>;\n}\n\n/**\n * An API that decides how to visually represent entities in the interface.\n *\n * @remarks\n *\n * Most consumers will want to use the {@link useEntityPresentation} hook\n * instead of this interface directly.\n *\n * @public\n */\nexport interface EntityPresentationApi {\n /**\n * Fetches the presentation for an entity.\n *\n * @param entityOrRef - Either an entity, or a string ref to it. If you pass\n * in an entity, it is assumed that it is not a partial one - i.e. only pass\n * in an entity if you know that it was fetched in such a way that it\n * contains all of the fields that the representation renderer needs.\n * @param context - Contextual information that may affect the presentation.\n */\n forEntity(\n entityOrRef: Entity | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n ): EntityRefPresentation;\n}\n"],"names":[],"mappings":";;AA6BO,MAAM,2BACX,YAAA,CAAa;AAAA,EACX,EAAA,EAAI;AACN,CAAC;;;;"}
1
+ {"version":3,"file":"EntityPresentationApi.esm.js","sources":["../../../src/apis/EntityPresentationApi/EntityPresentationApi.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 { Entity } from '@backstage/catalog-model';\nimport {\n ApiRef,\n IconComponent,\n createApiRef,\n} from '@backstage/core-plugin-api';\nimport { Observable } from '@backstage/types';\n\n/**\n * An API that handles how to represent entities in the interface.\n *\n * @remarks\n *\n * There are several ways to consume this API depending on context:\n *\n * - In React components, use the {@link useEntityPresentation} hook to get a\n * reactive presentation snapshot that updates over time.\n *\n * - For simple inline rendering, use the {@link EntityDisplayName} component\n * which wraps the hook and renders a styled entity name with optional icon\n * and tooltip.\n *\n * - In non-React contexts such as sort comparators or data mappers, use the\n * {@link entityPresentationSnapshot} helper for synchronous access, or\n * the API directly via `forEntity().promise` in async loaders.\n *\n * @public\n */\nexport const entityPresentationApiRef: ApiRef<EntityPresentationApi> =\n createApiRef({\n id: 'plugin.catalog.entity-presentation',\n });\n\n/**\n * The visual presentation of an entity reference at some point in time.\n *\n * @public\n */\nexport interface EntityRefPresentationSnapshot {\n /**\n * The ref to the entity that this snapshot represents.\n *\n * @remarks\n *\n * Note that when the input data was broken or had missing vital pieces of\n * information, this string may contain placeholders such as \"unknown\". You\n * can therefore not necessarily assume that the ref is completely valid and\n * usable for example for forming a clickable link to the entity.\n */\n entityRef: string;\n /**\n * A string that can be used as a plain representation of the entity, for\n * example in a header or a link.\n *\n * @remarks\n *\n * The title may be short and not contain all of the information that the\n * entity holds. When rendering the primary title, you may also want to\n * make sure to add more contextual information nearby such as the icon or\n * secondary title, since the primary could for example just be the\n * `metadata.name` of the entity which might be ambiguous to the reader.\n */\n primaryTitle: string;\n /**\n * Optionally, some additional textual information about the entity, to be\n * used as a clarification on top of the primary title.\n *\n * @remarks\n *\n * This text can for example be rendered in a tooltip or be used as a\n * subtitle. It may not be sufficient to display on its own; it should\n * typically be used in conjunction with the primary title. It can contain\n * such information as the entity ref and/or a `spec.type` etc.\n */\n secondaryTitle?: string;\n /**\n * Optionally, an icon that represents the kind/type of entity.\n *\n * @remarks\n *\n * This icon should ideally be easily recognizable as the kind of entity, and\n * be used consistently throughout the Backstage interface. It can be rendered\n * both in larger formats such as in a header, or in smaller formats such as\n * inline with regular text, so bear in mind that the legibility should be\n * high in both cases.\n *\n * A value of `false` here indicates the desire to not have an icon present\n * for the given implementation. A value of `undefined` leaves it at the\n * discretion of the display layer to choose what to do (such as for example\n * showing a fallback icon).\n */\n Icon?: IconComponent | undefined | false;\n}\n\n/**\n * The visual presentation of an entity reference.\n *\n * @public\n */\nexport interface EntityRefPresentation {\n /**\n * The representation that's suitable to use for this entity right now.\n */\n snapshot: EntityRefPresentationSnapshot;\n /**\n * Some presentation implementations support emitting updated snapshots over\n * time, for example after retrieving additional data from the catalog or\n * elsewhere.\n */\n update$?: Observable<EntityRefPresentationSnapshot>;\n /**\n * A promise that resolves to a usable entity presentation.\n */\n promise: Promise<EntityRefPresentationSnapshot>;\n}\n\n/**\n * An API that decides how to visually represent entities in the interface.\n *\n * @remarks\n *\n * Most consumers will not need to interact with this interface directly.\n * Instead, use one of the following:\n *\n * - {@link useEntityPresentation} — React hook for reactive presentation data.\n *\n * - {@link EntityDisplayName} — React component that renders an entity name\n * with optional icon and tooltip.\n *\n * For non-React contexts, use the {@link entityPresentationSnapshot} helper\n * for synchronous access, or the API directly via `forEntity().promise`\n * for async contexts.\n *\n * Implement this interface to customize how entities are displayed throughout\n * the Backstage interface.\n *\n * @public\n */\nexport interface EntityPresentationApi {\n /**\n * Fetches the presentation for an entity.\n *\n * @param entityOrRef - Either an entity, or a string ref to it. If you pass\n * in an entity, it is assumed that it is not a partial one - i.e. only pass\n * in an entity if you know that it was fetched in such a way that it\n * contains all of the fields that the representation renderer needs.\n * @param context - Contextual information that may affect the presentation.\n */\n forEntity(\n entityOrRef: Entity | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n ): EntityRefPresentation;\n}\n"],"names":[],"mappings":";;AA4CO,MAAM,2BACX,YAAA,CAAa;AAAA,EACX,EAAA,EAAI;AACN,CAAC;;;;"}
@@ -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 * This returns the default representation of an entity.\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?.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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"}
@@ -0,0 +1,13 @@
1
+ import { stringifyEntityRef } from '@backstage/catalog-model';
2
+ import { defaultEntityPresentation } from './defaultEntityPresentation.esm.js';
3
+
4
+ function entityPresentationSnapshot(entityOrRef, context, entityPresentationApi) {
5
+ if (entityPresentationApi) {
6
+ const ref = typeof entityOrRef === "string" || "metadata" in entityOrRef ? entityOrRef : stringifyEntityRef(entityOrRef);
7
+ return entityPresentationApi.forEntity(ref, context).snapshot;
8
+ }
9
+ return defaultEntityPresentation(entityOrRef, context);
10
+ }
11
+
12
+ export { entityPresentationSnapshot };
13
+ //# sourceMappingURL=entityPresentationSnapshot.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityPresentationSnapshot.esm.js","sources":["../../../src/apis/EntityPresentationApi/entityPresentationSnapshot.ts"],"sourcesContent":["/*\n * Copyright 2026 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 Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n EntityPresentationApi,\n EntityRefPresentationSnapshot,\n} from './EntityPresentationApi';\nimport { defaultEntityPresentation } from './defaultEntityPresentation';\n\n/**\n * Returns a synchronous presentation snapshot for an entity in non-React\n * contexts.\n *\n * @remarks\n *\n * This is the synchronous, non-React counterpart to\n * {@link useEntityPresentation}. It handles `Entity`, `CompoundEntityRef`,\n * and string ref inputs uniformly, using the provided\n * {@link EntityPresentationApi} when available and falling back to\n * {@link defaultEntityPresentation} otherwise.\n *\n * Because this function is synchronous, it uses cached data from the\n * presentation API (via `.snapshot`). If the entity has been seen before,\n * the snapshot will contain the full resolved title; otherwise it falls\n * back to what can be extracted from the ref alone. This is the correct\n * trade-off for sort comparators, column factories, filter callbacks, and\n * data mappers where a synchronous return value is required.\n *\n * In async contexts such as data loaders where you can `await`, prefer\n * using the {@link EntityPresentationApi} directly via\n * `forEntity().promise` for the richest possible presentation.\n *\n * @public\n * @param entityOrRef - An entity, a compound entity ref, or a string entity ref.\n * @param context - Optional context that may affect the presentation.\n * @param entityPresentationApi - Optional presentation API instance. When not\n * provided, falls back to {@link defaultEntityPresentation}.\n */\nexport function entityPresentationSnapshot(\n entityOrRef: Entity | CompoundEntityRef | string,\n context?: { defaultKind?: string; defaultNamespace?: string },\n entityPresentationApi?: EntityPresentationApi,\n): EntityRefPresentationSnapshot {\n if (entityPresentationApi) {\n const ref =\n typeof entityOrRef === 'string' || 'metadata' in entityOrRef\n ? entityOrRef\n : stringifyEntityRef(entityOrRef);\n return entityPresentationApi.forEntity(ref, context).snapshot;\n }\n return defaultEntityPresentation(entityOrRef, context);\n}\n"],"names":[],"mappings":";;;AAwDO,SAAS,0BAAA,CACd,WAAA,EACA,OAAA,EACA,qBAAA,EAC+B;AAC/B,EAAA,IAAI,qBAAA,EAAuB;AACzB,IAAA,MAAM,GAAA,GACJ,OAAO,WAAA,KAAgB,QAAA,IAAY,cAAc,WAAA,GAC7C,WAAA,GACA,mBAAmB,WAAW,CAAA;AACpC,IAAA,OAAO,qBAAA,CAAsB,SAAA,CAAU,GAAA,EAAK,OAAO,CAAA,CAAE,QAAA;AAAA,EACvD;AACA,EAAA,OAAO,yBAAA,CAA0B,aAAa,OAAO,CAAA;AACvD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEntityPresentation.esm.js","sources":["../../../src/apis/EntityPresentationApi/useEntityPresentation.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 Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApiHolder } from '@backstage/core-plugin-api';\nimport { useMemo } from 'react';\nimport {\n EntityRefPresentation,\n EntityRefPresentationSnapshot,\n entityPresentationApiRef,\n} from './EntityPresentationApi';\nimport { defaultEntityPresentation } from './defaultEntityPresentation';\nimport { useUpdatingObservable } from './useUpdatingObservable';\n\n/**\n * Returns information about how to represent an entity in the interface.\n *\n * @public\n * @param entityOrRef - The entity to represent, or an entity ref to it. If you\n * pass in an entity, it is assumed that it is NOT a partial one - i.e. only\n * pass in an entity if you know that it was fetched in such a way that it\n * contains all of the fields that the representation renderer needs.\n * @param context - Optional context that control details of the presentation.\n * @returns A snapshot of the entity presentation, which may change over time\n */\nexport function useEntityPresentation(\n entityOrRef: Entity | CompoundEntityRef | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n): EntityRefPresentationSnapshot {\n // Defensively allow for a missing presentation API, which makes this hook\n // safe to use in tests.\n const apis = useApiHolder();\n const entityPresentationApi = apis.get(entityPresentationApiRef);\n\n const deps = [\n entityPresentationApi,\n JSON.stringify(entityOrRef),\n JSON.stringify(context || null),\n ];\n\n const presentation = useMemo<EntityRefPresentation>(\n () => {\n if (!entityPresentationApi) {\n const fallback = defaultEntityPresentation(entityOrRef, context);\n return { snapshot: fallback, promise: Promise.resolve(fallback) };\n }\n\n return entityPresentationApi.forEntity(\n typeof entityOrRef === 'string' || 'metadata' in entityOrRef\n ? entityOrRef\n : stringifyEntityRef(entityOrRef),\n context,\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n deps,\n );\n\n // NOTE(freben): We intentionally do not use the plain useObservable from the\n // react-use library here. That hook does not support a dependencies array,\n // and also it only subscribes once to the initially passed in observable and\n // won't properly react when either initial value or the actual observable\n // changes.\n return useUpdatingObservable(presentation.snapshot, presentation.update$, [\n presentation,\n ]);\n}\n"],"names":[],"mappings":";;;;;;;AA0CO,SAAS,qBAAA,CACd,aACA,OAAA,EAI+B;AAG/B,EAAA,MAAM,OAAO,YAAA,EAAa;AAC1B,EAAA,MAAM,qBAAA,GAAwB,IAAA,CAAK,GAAA,CAAI,wBAAwB,CAAA;AAE/D,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,qBAAA;AAAA,IACA,IAAA,CAAK,UAAU,WAAW,CAAA;AAAA,IAC1B,IAAA,CAAK,SAAA,CAAU,OAAA,IAAW,IAAI;AAAA,GAChC;AAEA,EAAA,MAAM,YAAA,GAAe,OAAA;AAAA,IACnB,MAAM;AACJ,MAAA,IAAI,CAAC,qBAAA,EAAuB;AAC1B,QAAA,MAAM,QAAA,GAAW,yBAAA,CAA0B,WAAA,EAAa,OAAO,CAAA;AAC/D,QAAA,OAAO,EAAE,QAAA,EAAU,QAAA,EAAU,SAAS,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA,EAAE;AAAA,MAClE;AAEA,MAAA,OAAO,qBAAA,CAAsB,SAAA;AAAA,QAC3B,OAAO,WAAA,KAAgB,QAAA,IAAY,cAAc,WAAA,GAC7C,WAAA,GACA,mBAAmB,WAAW,CAAA;AAAA,QAClC;AAAA,OACF;AAAA,IACF,CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAOA,EAAA,OAAO,qBAAA,CAAsB,YAAA,CAAa,QAAA,EAAU,YAAA,CAAa,OAAA,EAAS;AAAA,IACxE;AAAA,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"useEntityPresentation.esm.js","sources":["../../../src/apis/EntityPresentationApi/useEntityPresentation.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 Entity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { useApiHolder } from '@backstage/core-plugin-api';\nimport { useMemo } from 'react';\nimport {\n EntityRefPresentation,\n EntityRefPresentationSnapshot,\n entityPresentationApiRef,\n} from './EntityPresentationApi';\nimport { defaultEntityPresentation } from './defaultEntityPresentation';\nimport { useUpdatingObservable } from './useUpdatingObservable';\n\n/**\n * Returns information about how to represent an entity in the interface.\n *\n * @remarks\n *\n * This hook subscribes to the {@link EntityPresentationApi} and returns a\n * snapshot that may update over time as richer data is fetched (for example,\n * resolving `metadata.title` from a string entity ref). If no presentation\n * API is registered, it falls back to {@link defaultEntityPresentation}.\n *\n * For simple inline rendering, consider using the {@link EntityDisplayName}\n * component instead, which wraps this hook with icon and tooltip support.\n *\n * For non-React contexts such as sort comparators or data mappers, use\n * {@link entityPresentationSnapshot}.\n *\n * @public\n * @param entityOrRef - The entity to represent, or an entity ref to it. If you\n * pass in an entity, it is assumed that it is NOT a partial one - i.e. only\n * pass in an entity if you know that it was fetched in such a way that it\n * contains all of the fields that the representation renderer needs.\n * @param context - Optional context that control details of the presentation.\n * @returns A snapshot of the entity presentation, which may change over time\n */\nexport function useEntityPresentation(\n entityOrRef: Entity | CompoundEntityRef | string,\n context?: {\n defaultKind?: string;\n defaultNamespace?: string;\n },\n): EntityRefPresentationSnapshot {\n // Defensively allow for a missing presentation API, which makes this hook\n // safe to use in tests.\n const apis = useApiHolder();\n const entityPresentationApi = apis.get(entityPresentationApiRef);\n\n const deps = [\n entityPresentationApi,\n JSON.stringify(entityOrRef),\n JSON.stringify(context || null),\n ];\n\n const presentation = useMemo<EntityRefPresentation>(\n () => {\n if (!entityPresentationApi) {\n const fallback = defaultEntityPresentation(entityOrRef, context);\n return { snapshot: fallback, promise: Promise.resolve(fallback) };\n }\n\n return entityPresentationApi.forEntity(\n typeof entityOrRef === 'string' || 'metadata' in entityOrRef\n ? entityOrRef\n : stringifyEntityRef(entityOrRef),\n context,\n );\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n deps,\n );\n\n // NOTE(freben): We intentionally do not use the plain useObservable from the\n // react-use library here. That hook does not support a dependencies array,\n // and also it only subscribes once to the initially passed in observable and\n // won't properly react when either initial value or the actual observable\n // changes.\n return useUpdatingObservable(presentation.snapshot, presentation.update$, [\n presentation,\n ]);\n}\n"],"names":[],"mappings":";;;;;;;AAuDO,SAAS,qBAAA,CACd,aACA,OAAA,EAI+B;AAG/B,EAAA,MAAM,OAAO,YAAA,EAAa;AAC1B,EAAA,MAAM,qBAAA,GAAwB,IAAA,CAAK,GAAA,CAAI,wBAAwB,CAAA;AAE/D,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,qBAAA;AAAA,IACA,IAAA,CAAK,UAAU,WAAW,CAAA;AAAA,IAC1B,IAAA,CAAK,SAAA,CAAU,OAAA,IAAW,IAAI;AAAA,GAChC;AAEA,EAAA,MAAM,YAAA,GAAe,OAAA;AAAA,IACnB,MAAM;AACJ,MAAA,IAAI,CAAC,qBAAA,EAAuB;AAC1B,QAAA,MAAM,QAAA,GAAW,yBAAA,CAA0B,WAAA,EAAa,OAAO,CAAA;AAC/D,QAAA,OAAO,EAAE,QAAA,EAAU,QAAA,EAAU,SAAS,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA,EAAE;AAAA,MAClE;AAEA,MAAA,OAAO,qBAAA,CAAsB,SAAA;AAAA,QAC3B,OAAO,WAAA,KAAgB,QAAA,IAAY,cAAc,WAAA,GAC7C,WAAA,GACA,mBAAmB,WAAW,CAAA;AAAA,QAClC;AAAA,OACF;AAAA,IACF,CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAOA,EAAA,OAAO,qBAAA,CAAsB,YAAA,CAAa,QAAA,EAAU,YAAA,CAAa,OAAA,EAAS;AAAA,IACxE;AAAA,GACD,CAAA;AACH;;;;"}
@@ -3,7 +3,8 @@ import { RELATION_PART_OF, RELATION_OWNED_BY } from '@backstage/catalog-model';
3
3
  import { CellText, Column, Cell } from '@backstage/ui';
4
4
  import { EntityRefLink } from '../EntityRefLink/EntityRefLink.esm.js';
5
5
  import { EntityRefLinks } from '../EntityRefLink/EntityRefLinks.esm.js';
6
- import { humanizeEntityRef } from '../EntityRefLink/humanize.esm.js';
6
+ import 'lodash/get';
7
+ import { entityPresentationSnapshot } from '@backstage/plugin-catalog-react';
7
8
  import { EntityTableColumnTitle } from '../EntityTable/TitleColumn.esm.js';
8
9
  import { getEntityRelations } from '../../utils/getEntityRelations.esm.js';
9
10
 
@@ -24,7 +25,11 @@ const columnFactories = Object.freeze({
24
25
  title: entity.metadata?.title
25
26
  }
26
27
  ) }),
27
- sortValue: (entity) => entity.metadata?.title || humanizeEntityRef(entity, { defaultKind: options.defaultKind })
28
+ sortValue: (entity) => entityPresentationSnapshot(
29
+ entity,
30
+ { defaultKind: options.defaultKind },
31
+ options.entityPresentationApi
32
+ ).primaryTitle
28
33
  };
29
34
  },
30
35
  createEntityRelationColumn(options) {
@@ -44,7 +49,13 @@ const columnFactories = Object.freeze({
44
49
  defaultKind: options.defaultKind
45
50
  }
46
51
  ) }),
47
- sortValue: (entity) => getEntityRelations(entity, options.relation, options.filter).map((r) => humanizeEntityRef(r, { defaultKind: options.defaultKind })).join(", ")
52
+ sortValue: (entity) => getEntityRelations(entity, options.relation, options.filter).map(
53
+ (r) => entityPresentationSnapshot(
54
+ r,
55
+ { defaultKind: options.defaultKind },
56
+ options.entityPresentationApi
57
+ ).primaryTitle
58
+ ).join(", ")
48
59
  };
49
60
  },
50
61
  createOwnerColumn() {
@@ -1 +1 @@
1
- {"version":3,"file":"columnFactories.esm.js","sources":["../../../src/components/EntityDataTable/columnFactories.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport { Cell, CellText, Column, ColumnConfig, TableItem } from '@backstage/ui';\nimport {\n EntityRefLink,\n EntityRefLinks,\n humanizeEntityRef,\n} from '../EntityRefLink';\nimport { EntityTableColumnTitle } from '../EntityTable/TitleColumn';\nimport { getEntityRelations } from '../../utils';\n\n/** @public */\nexport type EntityRow = Entity & TableItem;\n\n/** @public */\nexport interface EntityColumnConfig extends ColumnConfig<EntityRow> {\n sortValue?: (entity: EntityRow) => string;\n}\n\n/** @public */\nexport const columnFactories = Object.freeze({\n createEntityRefColumn(options: {\n defaultKind?: string;\n isRowHeader?: boolean;\n }): EntityColumnConfig {\n const isRowHeader = options.isRowHeader ?? true;\n return {\n id: 'name',\n label: 'Name',\n header: () => (\n <Column id=\"name\" isRowHeader={isRowHeader} allowsSorting>\n <EntityTableColumnTitle translationKey=\"name\" />\n </Column>\n ),\n isRowHeader,\n isSortable: true,\n cell: entity => (\n <Cell>\n <EntityRefLink\n entityRef={entity}\n defaultKind={options.defaultKind}\n title={entity.metadata?.title}\n />\n </Cell>\n ),\n sortValue: entity =>\n entity.metadata?.title ||\n humanizeEntityRef(entity, { defaultKind: options.defaultKind }),\n };\n },\n\n createEntityRelationColumn(options: {\n id: string;\n translationKey: 'owner' | 'system' | 'domain';\n relation: string;\n defaultKind?: string;\n filter?: { kind: string };\n }): EntityColumnConfig {\n return {\n id: options.id,\n label: options.id.charAt(0).toUpperCase() + options.id.slice(1),\n header: () => (\n <Column id={options.id} allowsSorting>\n <EntityTableColumnTitle translationKey={options.translationKey} />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <Cell>\n <EntityRefLinks\n entityRefs={getEntityRelations(\n entity,\n options.relation,\n options.filter,\n )}\n defaultKind={options.defaultKind}\n />\n </Cell>\n ),\n sortValue: entity =>\n getEntityRelations(entity, options.relation, options.filter)\n .map(r => humanizeEntityRef(r, { defaultKind: options.defaultKind }))\n .join(', '),\n };\n },\n\n createOwnerColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'owner',\n translationKey: 'owner',\n relation: RELATION_OWNED_BY,\n defaultKind: 'group',\n });\n },\n\n createSystemColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'system',\n translationKey: 'system',\n relation: RELATION_PART_OF,\n defaultKind: 'system',\n filter: { kind: 'system' },\n });\n },\n\n createDomainColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'domain',\n translationKey: 'domain',\n relation: RELATION_PART_OF,\n defaultKind: 'domain',\n filter: { kind: 'domain' },\n });\n },\n\n createMetadataDescriptionColumn(): EntityColumnConfig {\n return {\n id: 'description',\n label: 'Description',\n header: () => (\n <Column id=\"description\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"description\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => <CellText title={entity.metadata.description ?? ''} />,\n sortValue: entity => entity.metadata.description ?? '',\n };\n },\n\n createSpecTypeColumn(): EntityColumnConfig {\n return {\n id: 'type',\n label: 'Type',\n header: () => (\n <Column id=\"type\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"type\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <CellText\n title={\n (entity.spec as Record<string, string> | undefined)?.type ?? ''\n }\n />\n ),\n sortValue: entity =>\n (entity.spec as Record<string, string> | undefined)?.type ?? '',\n };\n },\n\n createSpecLifecycleColumn(): EntityColumnConfig {\n return {\n id: 'lifecycle',\n label: 'Lifecycle',\n header: () => (\n <Column id=\"lifecycle\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"lifecycle\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <CellText\n title={\n (entity.spec as Record<string, string> | undefined)?.lifecycle ?? ''\n }\n />\n ),\n sortValue: entity =>\n (entity.spec as Record<string, string> | undefined)?.lifecycle ?? '',\n };\n },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"columnFactories.esm.js","sources":["../../../src/components/EntityDataTable/columnFactories.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport { Cell, CellText, Column, ColumnConfig, TableItem } from '@backstage/ui';\nimport { EntityRefLink, EntityRefLinks } from '../EntityRefLink';\nimport {\n entityPresentationSnapshot,\n EntityPresentationApi,\n} from '@backstage/plugin-catalog-react';\nimport { EntityTableColumnTitle } from '../EntityTable/TitleColumn';\nimport { getEntityRelations } from '../../utils';\n\n/** @public */\nexport type EntityRow = Entity & TableItem;\n\n/** @public */\nexport interface EntityColumnConfig extends ColumnConfig<EntityRow> {\n sortValue?: (entity: EntityRow) => string;\n}\n\n/** @public */\nexport const columnFactories = Object.freeze({\n createEntityRefColumn(options: {\n defaultKind?: string;\n isRowHeader?: boolean;\n entityPresentationApi?: EntityPresentationApi;\n }): EntityColumnConfig {\n const isRowHeader = options.isRowHeader ?? true;\n return {\n id: 'name',\n label: 'Name',\n header: () => (\n <Column id=\"name\" isRowHeader={isRowHeader} allowsSorting>\n <EntityTableColumnTitle translationKey=\"name\" />\n </Column>\n ),\n isRowHeader,\n isSortable: true,\n cell: entity => (\n <Cell>\n <EntityRefLink\n entityRef={entity}\n defaultKind={options.defaultKind}\n title={entity.metadata?.title}\n />\n </Cell>\n ),\n sortValue: entity =>\n entityPresentationSnapshot(\n entity,\n { defaultKind: options.defaultKind },\n options.entityPresentationApi,\n ).primaryTitle,\n };\n },\n\n createEntityRelationColumn(options: {\n id: string;\n translationKey: 'owner' | 'system' | 'domain';\n relation: string;\n defaultKind?: string;\n filter?: { kind: string };\n entityPresentationApi?: EntityPresentationApi;\n }): EntityColumnConfig {\n return {\n id: options.id,\n label: options.id.charAt(0).toUpperCase() + options.id.slice(1),\n header: () => (\n <Column id={options.id} allowsSorting>\n <EntityTableColumnTitle translationKey={options.translationKey} />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <Cell>\n <EntityRefLinks\n entityRefs={getEntityRelations(\n entity,\n options.relation,\n options.filter,\n )}\n defaultKind={options.defaultKind}\n />\n </Cell>\n ),\n sortValue: entity =>\n getEntityRelations(entity, options.relation, options.filter)\n .map(\n r =>\n entityPresentationSnapshot(\n r,\n { defaultKind: options.defaultKind },\n options.entityPresentationApi,\n ).primaryTitle,\n )\n .join(', '),\n };\n },\n\n createOwnerColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'owner',\n translationKey: 'owner',\n relation: RELATION_OWNED_BY,\n defaultKind: 'group',\n });\n },\n\n createSystemColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'system',\n translationKey: 'system',\n relation: RELATION_PART_OF,\n defaultKind: 'system',\n filter: { kind: 'system' },\n });\n },\n\n createDomainColumn(): EntityColumnConfig {\n return columnFactories.createEntityRelationColumn({\n id: 'domain',\n translationKey: 'domain',\n relation: RELATION_PART_OF,\n defaultKind: 'domain',\n filter: { kind: 'domain' },\n });\n },\n\n createMetadataDescriptionColumn(): EntityColumnConfig {\n return {\n id: 'description',\n label: 'Description',\n header: () => (\n <Column id=\"description\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"description\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => <CellText title={entity.metadata.description ?? ''} />,\n sortValue: entity => entity.metadata.description ?? '',\n };\n },\n\n createSpecTypeColumn(): EntityColumnConfig {\n return {\n id: 'type',\n label: 'Type',\n header: () => (\n <Column id=\"type\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"type\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <CellText\n title={\n (entity.spec as Record<string, string> | undefined)?.type ?? ''\n }\n />\n ),\n sortValue: entity =>\n (entity.spec as Record<string, string> | undefined)?.type ?? '',\n };\n },\n\n createSpecLifecycleColumn(): EntityColumnConfig {\n return {\n id: 'lifecycle',\n label: 'Lifecycle',\n header: () => (\n <Column id=\"lifecycle\" allowsSorting>\n <EntityTableColumnTitle translationKey=\"lifecycle\" />\n </Column>\n ),\n isSortable: true,\n cell: entity => (\n <CellText\n title={\n (entity.spec as Record<string, string> | undefined)?.lifecycle ?? ''\n }\n />\n ),\n sortValue: entity =>\n (entity.spec as Record<string, string> | undefined)?.lifecycle ?? '',\n };\n },\n});\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityDisplayName.esm.js","sources":["../../../src/components/EntityDisplayName/EntityDisplayName.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CompoundEntityRef, Entity } from '@backstage/catalog-model';\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport { Theme, makeStyles } from '@material-ui/core/styles';\nimport { useEntityPresentation } from '../../apis';\n\n/**\n * The available style class keys for {@link EntityDisplayName}, under the name\n * \"CatalogReactEntityDisplayName\".\n *\n * @public\n */\nexport type CatalogReactEntityDisplayNameClassKey = 'root' | 'icon';\n\nconst useStyles = makeStyles(\n (theme: Theme) => ({\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n textDecoration: 'inherit',\n },\n icon: {\n marginRight: theme.spacing(0.5),\n color: theme.palette.text.secondary,\n '& svg': {\n verticalAlign: 'middle',\n },\n },\n }),\n { name: 'CatalogReactEntityDisplayName' },\n);\n\n/**\n * Props for {@link EntityDisplayName}.\n *\n * @public\n */\nexport type EntityDisplayNameProps = {\n entityRef: Entity | CompoundEntityRef | string;\n hideIcon?: boolean;\n disableTooltip?: boolean;\n defaultKind?: string;\n defaultNamespace?: string;\n};\n\n/**\n * Shows a nice representation of a reference to an entity.\n *\n * @public\n */\nexport const EntityDisplayName = (\n props: EntityDisplayNameProps,\n): JSX.Element => {\n const { entityRef, hideIcon, disableTooltip, defaultKind, defaultNamespace } =\n props;\n\n const classes = useStyles();\n const { primaryTitle, secondaryTitle, Icon } = useEntityPresentation(\n entityRef,\n { defaultKind, defaultNamespace },\n );\n\n // The innermost \"body\" content\n let content = <>{primaryTitle}</>;\n // Optionally an icon, and wrapper around them both\n content = (\n <Box component=\"span\" className={classes.root}>\n {Icon && !hideIcon ? (\n <Box component=\"span\" className={classes.icon}>\n <Icon fontSize=\"inherit\" />\n </Box>\n ) : null}\n {content}\n </Box>\n );\n\n // Optionally, a tooltip as the outermost layer\n if (secondaryTitle && !disableTooltip) {\n content = (\n <Tooltip enterDelay={1500} title={secondaryTitle}>\n {content}\n </Tooltip>\n );\n }\n\n return content;\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA8BA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAC,KAAA,MAAkB;AAAA,IACjB,IAAA,EAAM;AAAA,MACJ,OAAA,EAAS,aAAA;AAAA,MACT,UAAA,EAAY,QAAA;AAAA,MACZ,cAAA,EAAgB;AAAA,KAClB;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,WAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,MAC9B,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,SAAA;AAAA,MAC1B,OAAA,EAAS;AAAA,QACP,aAAA,EAAe;AAAA;AACjB;AACF,GACF,CAAA;AAAA,EACA,EAAE,MAAM,+BAAA;AACV,CAAA;AAoBO,MAAM,iBAAA,GAAoB,CAC/B,KAAA,KACgB;AAChB,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,cAAA,EAAgB,WAAA,EAAa,kBAAiB,GACzE,KAAA;AAEF,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,EAAE,YAAA,EAAc,cAAA,EAAgB,IAAA,EAAK,GAAI,qBAAA;AAAA,IAC7C,SAAA;AAAA,IACA,EAAE,aAAa,gBAAA;AAAiB,GAClC;AAGA,EAAA,IAAI,OAAA,mCAAa,QAAA,EAAA,YAAA,EAAa,CAAA;AAE9B,EAAA,OAAA,wBACG,GAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EAAO,SAAA,EAAW,QAAQ,IAAA,EACtC,QAAA,EAAA;AAAA,IAAA,IAAA,IAAQ,CAAC,QAAA,mBACR,GAAA,CAAC,GAAA,EAAA,EAAI,WAAU,MAAA,EAAO,SAAA,EAAW,OAAA,CAAQ,IAAA,EACvC,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,QAAA,EAAS,SAAA,EAAU,GAC3B,CAAA,GACE,IAAA;AAAA,IACH;AAAA,GAAA,EACH,CAAA;AAIF,EAAA,IAAI,cAAA,IAAkB,CAAC,cAAA,EAAgB;AACrC,IAAA,OAAA,uBACG,OAAA,EAAA,EAAQ,UAAA,EAAY,IAAA,EAAM,KAAA,EAAO,gBAC/B,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,OAAO,OAAA;AACT;;;;"}
1
+ {"version":3,"file":"EntityDisplayName.esm.js","sources":["../../../src/components/EntityDisplayName/EntityDisplayName.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CompoundEntityRef, Entity } from '@backstage/catalog-model';\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport { Theme, makeStyles } from '@material-ui/core/styles';\nimport { useEntityPresentation } from '../../apis';\n\n/**\n * The available style class keys for {@link EntityDisplayName}, under the name\n * \"CatalogReactEntityDisplayName\".\n *\n * @public\n */\nexport type CatalogReactEntityDisplayNameClassKey = 'root' | 'icon';\n\nconst useStyles = makeStyles(\n (theme: Theme) => ({\n root: {\n display: 'inline-flex',\n alignItems: 'center',\n textDecoration: 'inherit',\n },\n icon: {\n marginRight: theme.spacing(0.5),\n color: theme.palette.text.secondary,\n '& svg': {\n verticalAlign: 'middle',\n },\n },\n }),\n { name: 'CatalogReactEntityDisplayName' },\n);\n\n/**\n * Props for {@link EntityDisplayName}.\n *\n * @public\n */\nexport type EntityDisplayNameProps = {\n entityRef: Entity | CompoundEntityRef | string;\n hideIcon?: boolean;\n disableTooltip?: boolean;\n defaultKind?: string;\n defaultNamespace?: string;\n};\n\n/**\n * Shows a nice representation of a reference to an entity.\n *\n * @remarks\n *\n * This component uses the {@link useEntityPresentation} hook internally and\n * renders the entity's primary title with optional icon and tooltip. It is\n * the simplest way to display an entity name in JSX.\n *\n * For more control over the presentation data, use the\n * {@link useEntityPresentation} hook directly. For non-React contexts, use\n * {@link entityPresentationSnapshot}.\n *\n * @public\n */\nexport const EntityDisplayName = (\n props: EntityDisplayNameProps,\n): JSX.Element => {\n const { entityRef, hideIcon, disableTooltip, defaultKind, defaultNamespace } =\n props;\n\n const classes = useStyles();\n const { primaryTitle, secondaryTitle, Icon } = useEntityPresentation(\n entityRef,\n { defaultKind, defaultNamespace },\n );\n\n // The innermost \"body\" content\n let content = <>{primaryTitle}</>;\n // Optionally an icon, and wrapper around them both\n content = (\n <Box component=\"span\" className={classes.root}>\n {Icon && !hideIcon ? (\n <Box component=\"span\" className={classes.icon}>\n <Icon fontSize=\"inherit\" />\n </Box>\n ) : null}\n {content}\n </Box>\n );\n\n // Optionally, a tooltip as the outermost layer\n if (secondaryTitle && !disableTooltip) {\n content = (\n <Tooltip enterDelay={1500} title={secondaryTitle}>\n {content}\n </Tooltip>\n );\n }\n\n return content;\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA8BA,MAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAC,KAAA,MAAkB;AAAA,IACjB,IAAA,EAAM;AAAA,MACJ,OAAA,EAAS,aAAA;AAAA,MACT,UAAA,EAAY,QAAA;AAAA,MACZ,cAAA,EAAgB;AAAA,KAClB;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,WAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,MAC9B,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,SAAA;AAAA,MAC1B,OAAA,EAAS;AAAA,QACP,aAAA,EAAe;AAAA;AACjB;AACF,GACF,CAAA;AAAA,EACA,EAAE,MAAM,+BAAA;AACV,CAAA;AA8BO,MAAM,iBAAA,GAAoB,CAC/B,KAAA,KACgB;AAChB,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,cAAA,EAAgB,WAAA,EAAa,kBAAiB,GACzE,KAAA;AAEF,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,EAAE,YAAA,EAAc,cAAA,EAAgB,IAAA,EAAK,GAAI,qBAAA;AAAA,IAC7C,SAAA;AAAA,IACA,EAAE,aAAa,gBAAA;AAAiB,GAClC;AAGA,EAAA,IAAI,OAAA,mCAAa,QAAA,EAAA,YAAA,EAAa,CAAA;AAE9B,EAAA,OAAA,wBACG,GAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EAAO,SAAA,EAAW,QAAQ,IAAA,EACtC,QAAA,EAAA;AAAA,IAAA,IAAA,IAAQ,CAAC,QAAA,mBACR,GAAA,CAAC,GAAA,EAAA,EAAI,WAAU,MAAA,EAAO,SAAA,EAAW,OAAA,CAAQ,IAAA,EACvC,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,QAAA,EAAS,SAAA,EAAU,GAC3B,CAAA,GACE,IAAA;AAAA,IACH;AAAA,GAAA,EACH,CAAA;AAIF,EAAA,IAAI,cAAA,IAAkB,CAAC,cAAA,EAAgB;AACrC,IAAA,OAAA,uBACG,OAAA,EAAA,EAAQ,UAAA,EAAY,IAAA,EAAM,KAAA,EAAO,gBAC/B,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,OAAO,OAAA;AACT;;;;"}
@@ -14,14 +14,15 @@ import { EntityOwnerFilter } from '../../filters.esm.js';
14
14
  import { useDebouncedEffect } from '@react-hookz/web';
15
15
  import PersonIcon from '@material-ui/icons/Person';
16
16
  import GroupIcon from '@material-ui/icons/Group';
17
- import { humanizeEntity, humanizeEntityRef } from '../EntityRefLink/humanize.esm.js';
18
- import { useFetchEntities } from './useFetchEntities.esm.js';
19
- import '../../apis/EntityPresentationApi/EntityPresentationApi.esm.js';
17
+ import { entityPresentationApiRef } from '../../apis/EntityPresentationApi/EntityPresentationApi.esm.js';
20
18
  import 'lodash/get';
19
+ import { entityPresentationSnapshot } from '../../apis/EntityPresentationApi/entityPresentationSnapshot.esm.js';
21
20
  import { useEntityPresentation } from '../../apis/EntityPresentationApi/useEntityPresentation.esm.js';
22
21
  import '../../apis/StarredEntitiesApi/StarredEntitiesApi.esm.js';
23
22
  import 'zen-observable';
23
+ import { useFetchEntities } from './useFetchEntities.esm.js';
24
24
  import { catalogReactTranslationRef } from '../../translation.esm.js';
25
+ import { useApiHolder } from '@backstage/core-plugin-api';
25
26
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
26
27
  import { CatalogAutocomplete } from '../CatalogAutocomplete/CatalogAutocomplete.esm.js';
27
28
 
@@ -80,6 +81,8 @@ function RenderOptionLabel(props) {
80
81
  const EntityOwnerPicker = (props) => {
81
82
  const classes = useStyles();
82
83
  const { mode = "owners-only" } = props || {};
84
+ const apis = useApiHolder();
85
+ const entityPresentationApi = apis.get(entityPresentationApiRef);
83
86
  const {
84
87
  updateFilters,
85
88
  filters,
@@ -140,7 +143,11 @@ const EntityOwnerPicker = (props) => {
140
143
  defaultKind: "group",
141
144
  defaultNamespace: "default"
142
145
  }) : o;
143
- return humanizeEntity(entity, humanizeEntityRef(entity));
146
+ return entityPresentationSnapshot(
147
+ entity,
148
+ void 0,
149
+ entityPresentationApi
150
+ ).primaryTitle;
144
151
  },
145
152
  onChange: (_, owners) => {
146
153
  setText("");
@@ -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 { humanizeEntity, humanizeEntityRef } from '../EntityRefLink/humanize';\nimport { useFetchEntities } from './useFetchEntities';\nimport { withStyles } from '@material-ui/core/styles';\nimport { useEntityPresentation } from '../../apis';\nimport { catalogReactTranslationRef } from '../../translation';\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: { entity: Entity; isSelected: boolean }) {\n const classes = useStyles();\n const isGroup = props.entity.kind.toLocaleLowerCase('en-US') === 'group';\n const { primaryTitle: title } = useEntityPresentation(props.entity);\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 {\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 const [selectedOwners, setSelectedOwners] = useState<string[]>(\n queryParamOwners.length ? queryParamOwners : 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 const entity =\n typeof o === 'string'\n ? cache.getEntity(o) ||\n parseEntityRef(o, {\n defaultKind: 'group',\n defaultNamespace: 'default',\n })\n : o;\n return humanizeEntity(entity, humanizeEntityRef(entity));\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 <RenderOptionLabel entity={entity} isSelected={selected} />;\n }}\n name=\"owner-picker\"\n onInputChange={(_e, inputValue) => {\n setText(inputValue);\n }}\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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"}
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 { 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: { entity: Entity; isSelected: boolean }) {\n const classes = useStyles();\n const isGroup = props.entity.kind.toLocaleLowerCase('en-US') === 'group';\n const { primaryTitle: title } = useEntityPresentation(props.entity);\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 const [selectedOwners, setSelectedOwners] = useState<string[]>(\n queryParamOwners.length ? queryParamOwners : 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 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 <RenderOptionLabel entity={entity} isSelected={selected} />;\n }}\n name=\"owner-picker\"\n onInputChange={(_e, inputValue) => {\n setText(inputValue);\n }}\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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"}
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_NAMESPACE } from '@backstage/catalog-model';
2
- import get from 'lodash/get';
2
+ import 'lodash/get';
3
3
 
4
4
  function humanizeEntityRef(entityRef, opts) {
5
5
  const defaultKind = opts?.defaultKind;
@@ -29,15 +29,6 @@ function humanizeEntityRef(entityRef, opts) {
29
29
  kind = defaultKind && defaultKind.toLocaleLowerCase("en-US") === kind ? void 0 : kind;
30
30
  return `${kind ? `${kind}:` : ""}${namespace ? `${namespace}/` : ""}${name}`;
31
31
  }
32
- function humanizeEntity(entity, defaultName) {
33
- for (const path of ["spec.profile.displayName", "metadata.title"]) {
34
- const value = get(entity, path);
35
- if (value && typeof value === "string") {
36
- return value;
37
- }
38
- }
39
- return defaultName;
40
- }
41
32
 
42
- export { humanizeEntity, humanizeEntityRef };
33
+ export { humanizeEntityRef };
43
34
  //# sourceMappingURL=humanize.esm.js.map
@@ -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 * @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 * @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":";;;AA6BO,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;AAeO,SAAS,cAAA,CAAe,QAAgB,WAAA,EAAqB;AAClE,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,0BAAA,EAA4B,gBAAgB,CAAA,EAAG;AACjE,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAC9B,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,WAAA;AACT;;;;"}
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;;;;"}
@@ -7,6 +7,7 @@ import '@backstage/catalog-model';
7
7
  import '../EntityRefLink/EntityRefLink.esm.js';
8
8
  import 'react';
9
9
  import 'lodash/get';
10
+ import '@backstage/plugin-catalog-react';
10
11
  import { catalogReactTranslationRef } from '../../translation.esm.js';
11
12
  import '../EntityDataTable/presets.esm.js';
12
13
  import { useEntity } from '../../hooks/useEntity.esm.js';
@@ -1 +1 @@
1
- {"version":3,"file":"EntityRelationCard.esm.js","sources":["../../../src/components/EntityRelationCard/EntityRelationCard.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { Alert, Link, Text } from '@backstage/ui';\nimport { useTranslationRef } from '@backstage/frontend-plugin-api';\nimport { EntityInfoCard } from '../EntityInfoCard';\nimport { EntityDataTable } from '../EntityDataTable';\nimport { EntityColumnConfig } from '../EntityDataTable/columnFactories';\nimport { useEntity, useRelatedEntities } from '../../hooks';\nimport { catalogReactTranslationRef } from '../../translation';\n\n/** @public */\nexport interface EntityRelationCardProps {\n title: string;\n relationType: string;\n entityKind?: string;\n columnConfig: EntityColumnConfig[];\n emptyState?: {\n message: string;\n helpLink?: string;\n };\n className?: string;\n}\n\n/** @public */\nexport function EntityRelationCard(props: EntityRelationCardProps) {\n const {\n title,\n relationType,\n entityKind,\n columnConfig,\n emptyState,\n className,\n } = props;\n const { t } = useTranslationRef(catalogReactTranslationRef);\n const { entity } = useEntity();\n const { entities, loading, error } = useRelatedEntities(entity, {\n type: relationType,\n kind: entityKind,\n });\n\n return (\n <EntityInfoCard title={title} className={className}>\n {error ? (\n <Alert status=\"warning\" icon title={error.message} role=\"status\" />\n ) : (\n <EntityDataTable\n columnConfig={columnConfig}\n data={entities ?? []}\n loading={loading}\n emptyState={\n emptyState && (\n <Text as=\"p\">\n {emptyState.message}{' '}\n {emptyState.helpLink && (\n <Link\n href={emptyState.helpLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n variant=\"body-medium\"\n >\n {t('entityRelationCard.emptyHelpLinkTitle')}\n </Link>\n )}\n </Text>\n )\n }\n />\n )}\n </EntityInfoCard>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCO,SAAS,mBAAmB,KAAA,EAAgC;AACjE,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AACJ,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,0BAA0B,CAAA;AAC1D,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAM,GAAI,mBAAmB,MAAA,EAAQ;AAAA,IAC9D,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,2BACG,cAAA,EAAA,EAAe,KAAA,EAAc,SAAA,EAC3B,QAAA,EAAA,KAAA,uBACE,KAAA,EAAA,EAAM,MAAA,EAAO,SAAA,EAAU,IAAA,EAAI,MAAC,KAAA,EAAO,KAAA,CAAM,OAAA,EAAS,IAAA,EAAK,UAAS,CAAA,mBAEjE,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,YAAA;AAAA,MACA,IAAA,EAAM,YAAY,EAAC;AAAA,MACnB,OAAA;AAAA,MACA,UAAA,EACE,UAAA,oBACE,IAAA,CAAC,IAAA,EAAA,EAAK,IAAG,GAAA,EACN,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,OAAA;AAAA,QAAS,GAAA;AAAA,QACpB,WAAW,QAAA,oBACV,GAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YACC,MAAM,UAAA,CAAW,QAAA;AAAA,YACjB,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YACJ,OAAA,EAAQ,aAAA;AAAA,YAEP,YAAE,uCAAuC;AAAA;AAAA;AAC5C,OAAA,EAEJ;AAAA;AAAA,GAGN,EAEJ,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityRelationCard.esm.js","sources":["../../../src/components/EntityRelationCard/EntityRelationCard.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { Alert, Link, Text } from '@backstage/ui';\nimport { useTranslationRef } from '@backstage/frontend-plugin-api';\nimport { EntityInfoCard } from '../EntityInfoCard';\nimport { EntityDataTable } from '../EntityDataTable';\nimport { EntityColumnConfig } from '../EntityDataTable/columnFactories';\nimport { useEntity, useRelatedEntities } from '../../hooks';\nimport { catalogReactTranslationRef } from '../../translation';\n\n/** @public */\nexport interface EntityRelationCardProps {\n title: string;\n relationType: string;\n entityKind?: string;\n columnConfig: EntityColumnConfig[];\n emptyState?: {\n message: string;\n helpLink?: string;\n };\n className?: string;\n}\n\n/** @public */\nexport function EntityRelationCard(props: EntityRelationCardProps) {\n const {\n title,\n relationType,\n entityKind,\n columnConfig,\n emptyState,\n className,\n } = props;\n const { t } = useTranslationRef(catalogReactTranslationRef);\n const { entity } = useEntity();\n const { entities, loading, error } = useRelatedEntities(entity, {\n type: relationType,\n kind: entityKind,\n });\n\n return (\n <EntityInfoCard title={title} className={className}>\n {error ? (\n <Alert status=\"warning\" icon title={error.message} role=\"status\" />\n ) : (\n <EntityDataTable\n columnConfig={columnConfig}\n data={entities ?? []}\n loading={loading}\n emptyState={\n emptyState && (\n <Text as=\"p\">\n {emptyState.message}{' '}\n {emptyState.helpLink && (\n <Link\n href={emptyState.helpLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n variant=\"body-medium\"\n >\n {t('entityRelationCard.emptyHelpLinkTitle')}\n </Link>\n )}\n </Text>\n )\n }\n />\n )}\n </EntityInfoCard>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAsCO,SAAS,mBAAmB,KAAA,EAAgC;AACjE,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AACJ,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,iBAAA,CAAkB,0BAA0B,CAAA;AAC1D,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAC7B,EAAA,MAAM,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAM,GAAI,mBAAmB,MAAA,EAAQ;AAAA,IAC9D,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,2BACG,cAAA,EAAA,EAAe,KAAA,EAAc,SAAA,EAC3B,QAAA,EAAA,KAAA,uBACE,KAAA,EAAA,EAAM,MAAA,EAAO,SAAA,EAAU,IAAA,EAAI,MAAC,KAAA,EAAO,KAAA,CAAM,OAAA,EAAS,IAAA,EAAK,UAAS,CAAA,mBAEjE,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,YAAA;AAAA,MACA,IAAA,EAAM,YAAY,EAAC;AAAA,MACnB,OAAA;AAAA,MACA,UAAA,EACE,UAAA,oBACE,IAAA,CAAC,IAAA,EAAA,EAAK,IAAG,GAAA,EACN,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,OAAA;AAAA,QAAS,GAAA;AAAA,QACpB,WAAW,QAAA,oBACV,GAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YACC,MAAM,UAAA,CAAW,QAAA;AAAA,YACjB,MAAA,EAAO,QAAA;AAAA,YACP,GAAA,EAAI,qBAAA;AAAA,YACJ,OAAA,EAAQ,aAAA;AAAA,YAEP,YAAE,uCAAuC;AAAA;AAAA;AAC5C,OAAA,EAEJ;AAAA;AAAA,GAGN,EAEJ,CAAA;AAEJ;;;;"}
@@ -4,16 +4,24 @@ import { OverflowTooltip } from '@backstage/core-components';
4
4
  import { getEntityRelations } from '../../utils/getEntityRelations.esm.js';
5
5
  import { EntityRefLink } from '../EntityRefLink/EntityRefLink.esm.js';
6
6
  import { EntityRefLinks } from '../EntityRefLink/EntityRefLinks.esm.js';
7
- import { humanizeEntityRef } from '../EntityRefLink/humanize.esm.js';
7
+ import 'lodash/get';
8
+ import '../../apis/EntityPresentationApi/EntityPresentationApi.esm.js';
9
+ import { entityPresentationSnapshot } from '../../apis/EntityPresentationApi/entityPresentationSnapshot.esm.js';
10
+ import '@backstage/core-plugin-api';
11
+ import 'react';
12
+ import '../../apis/StarredEntitiesApi/StarredEntitiesApi.esm.js';
13
+ import 'zen-observable';
8
14
  import { EntityTableColumnTitle } from './TitleColumn.esm.js';
9
15
 
10
16
  const columnFactories = Object.freeze({
11
17
  createEntityRefColumn(options) {
12
- const { defaultKind } = options;
18
+ const { defaultKind, entityPresentationApi } = options;
13
19
  function formatContent(entity) {
14
- return entity.metadata?.title || humanizeEntityRef(entity, {
15
- defaultKind
16
- });
20
+ return entityPresentationSnapshot(
21
+ entity,
22
+ { defaultKind },
23
+ entityPresentationApi
24
+ ).primaryTitle;
17
25
  }
18
26
  return {
19
27
  title: /* @__PURE__ */ jsx(EntityTableColumnTitle, { translationKey: "name" }),
@@ -35,12 +43,24 @@ const columnFactories = Object.freeze({
35
43
  };
36
44
  },
37
45
  createEntityRelationColumn(options) {
38
- const { title, relation, defaultKind, filter: entityFilter } = options;
46
+ const {
47
+ title,
48
+ relation,
49
+ defaultKind,
50
+ filter: entityFilter,
51
+ entityPresentationApi
52
+ } = options;
39
53
  function getRelations(entity) {
40
54
  return getEntityRelations(entity, relation, entityFilter);
41
55
  }
42
56
  function formatContent(entity) {
43
- return getRelations(entity).map((r) => humanizeEntityRef(r, { defaultKind })).join(", ");
57
+ return getRelations(entity).map(
58
+ (r) => entityPresentationSnapshot(
59
+ r,
60
+ { defaultKind },
61
+ entityPresentationApi
62
+ ).primaryTitle
63
+ ).join(", ");
44
64
  }
45
65
  return {
46
66
  title,