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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/CHANGELOG.md +259 -5
  2. package/dist/alpha/blueprints/EntityCardBlueprint.esm.js +4 -8
  3. package/dist/alpha/blueprints/EntityCardBlueprint.esm.js.map +1 -1
  4. package/dist/alpha/blueprints/EntityContentBlueprint.esm.js +4 -8
  5. package/dist/alpha/blueprints/EntityContentBlueprint.esm.js.map +1 -1
  6. package/dist/alpha/blueprints/EntityContentLayoutBlueprint.esm.js +4 -8
  7. package/dist/alpha/blueprints/EntityContentLayoutBlueprint.esm.js.map +1 -1
  8. package/dist/alpha/blueprints/EntityHeaderBlueprint.esm.js +21 -0
  9. package/dist/alpha/blueprints/EntityHeaderBlueprint.esm.js.map +1 -0
  10. package/dist/alpha/blueprints/extensionData.esm.js +2 -2
  11. package/dist/alpha/blueprints/extensionData.esm.js.map +1 -1
  12. package/dist/alpha/blueprints/resolveEntityFilterData.esm.js +27 -0
  13. package/dist/alpha/blueprints/resolveEntityFilterData.esm.js.map +1 -0
  14. package/dist/alpha/converters/convertLegacyEntityCardExtension.esm.js +1 -0
  15. package/dist/alpha/converters/convertLegacyEntityCardExtension.esm.js.map +1 -1
  16. package/dist/alpha/converters/convertLegacyEntityContentExtension.esm.js +1 -0
  17. package/dist/alpha/converters/convertLegacyEntityContentExtension.esm.js.map +1 -1
  18. package/dist/alpha/predicates/createEntityPredicateSchema.esm.js +27 -0
  19. package/dist/alpha/predicates/createEntityPredicateSchema.esm.js.map +1 -0
  20. package/dist/alpha/predicates/entityPredicateToFilterFunction.esm.js +73 -0
  21. package/dist/alpha/predicates/entityPredicateToFilterFunction.esm.js.map +1 -0
  22. package/dist/alpha/predicates/valueAtPath.esm.js +31 -0
  23. package/dist/alpha/predicates/valueAtPath.esm.js.map +1 -0
  24. package/dist/alpha.d.ts +74 -26
  25. package/dist/alpha.esm.js +2 -0
  26. package/dist/alpha.esm.js.map +1 -1
  27. package/dist/index.d.ts +23 -24
  28. package/package.json +23 -22
package/CHANGELOG.md CHANGED
@@ -1,5 +1,259 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7f57365: Add support for a new entity predicate syntax when defining `filter`s related to the blueprints exported via `/alpha` for the new frontend system. For more information, see the [entity filters documentation](https://backstage.io/docs/features/software-catalog/catalog-customization#advanced-customization#entity-filters).
8
+ - ba9649a: Add a new `defaultGroup` parameter to the `EntityContentBlueprint`, here are usage examples:
9
+
10
+ Set a default group while creating the extension:
11
+
12
+ ```diff
13
+ const entityKubernetesContent = EntityContentBlueprint.make({
14
+ name: 'kubernetes',
15
+ params: {
16
+ defaultPath: '/kubernetes',
17
+ defaultTitle: 'Kubernetes',
18
+ + defaultGroup: 'deployment',
19
+ filter: 'kind:component,resource',
20
+ loader: () =>
21
+ import('./KubernetesContentPage').then(m =>
22
+ compatWrapper(<m.KubernetesContentPage />),
23
+ ),
24
+ },
25
+ });
26
+ ```
27
+
28
+ Disassociate an entity content from a default group:
29
+
30
+ ```diff
31
+ # app-config.yaml
32
+ app:
33
+ extensions:
34
+ # Entity page content
35
+ - - entity-content:kubernetes/kubernetes
36
+ + - entity-content:kubernetes/kubernetes:
37
+ + config:
38
+ + group: false
39
+ ```
40
+
41
+ Associate an entity content with a different default or custom group than the one defined in code when the extension was created:
42
+
43
+ ```diff
44
+ # app-config.yaml
45
+ app:
46
+ extensions:
47
+ # Entity page content
48
+ - - entity-content:kubernetes/kubernetes
49
+ + - entity-content:kubernetes/kubernetes:
50
+ + config:
51
+ + group: custom # associating this extension with a custom group id, the group should have previously been created via entity page configuration
52
+
53
+ ```
54
+
55
+ - 247a40b: Introduces a new `EntityHeaderBlueprint` that allows you to override the default entity page header.
56
+
57
+ ```jsx
58
+ import { EntityHeaderBlueprint } from '@backstage/plugin-catalog-react/alpha';
59
+
60
+ EntityHeaderBlueprint.make({
61
+ name: 'my-default-header',
62
+ params: {
63
+ loader: () =>
64
+ import('./MyDefaultHeader').then(m => <m.MyDefaultHeader />),
65
+ },
66
+ });
67
+ ```
68
+
69
+ - a3d93ca: Introduces a new `EntityContentLayoutBlueprint` that creates custom entity content layouts.
70
+
71
+ The layout components receive card elements and can render them as they see fit. Cards is an array of objects with the following properties:
72
+
73
+ - element: `JSx.Element`;
74
+ - type: `"peek" | "info" | "full" | undefined`;
75
+
76
+ ### Usage example
77
+
78
+ Creating a custom overview tab layout:
79
+
80
+ ```tsx
81
+ import {
82
+ EntityContentLayoutProps,
83
+ EntityContentLayoutBlueprint,
84
+ } from '@backstage/plugin-catalog-react/alpha';
85
+ // ...
86
+
87
+ function StickyEntityContentOverviewLayout(props: EntityContentLayoutProps) {
88
+ const { cards } = props;
89
+ const classes = useStyles();
90
+ return (
91
+ <Grid container spacing={3}>
92
+ <Grid
93
+ className={classes.infoArea}
94
+ xs={12}
95
+ md={4}
96
+ item
97
+ >
98
+ <Grid container spacing={3}>
99
+ {cards
100
+ .filter(card => card.type === 'info')
101
+ .map((card, index) => (
102
+ <Grid key={index} xs={12} item>
103
+ {card.element}
104
+ </Grid>
105
+ ))}
106
+ </Grid>
107
+ </Grid>
108
+ <Grid xs={12} md={8} item>
109
+ <Grid container spacing={3}>
110
+ {cards
111
+ .filter(card => card.type === 'peek')
112
+ .map((card, index) => (
113
+ <Grid key={index} className={classes.card} xs={12} md={6} item>
114
+ {card.element}
115
+ </Grid>
116
+ ))}
117
+ {cards
118
+ .filter(card => !card.type || card.type === 'full')
119
+ .map((card, index) => (
120
+ <Grid key={index} className={classes.card} xs={12} md={6} item>
121
+ {card.element}
122
+ </Grid>
123
+ ))}
124
+ </Grid>
125
+ </Grid>
126
+ </Grid>
127
+ );
128
+ }
129
+
130
+ export const customEntityContentOverviewStickyLayoutModule = createFrontendModule({
131
+ pluginId: 'app',
132
+ extensions: [
133
+ EntityContentLayoutBlueprint.make({
134
+ name: 'sticky',
135
+ params: {
136
+ // (optional) defaults the `() => false` filter function
137
+ defaultFilter: 'kind:template'
138
+ loader: async () => StickyEntityContentOverviewLayout,
139
+ },
140
+ }),
141
+ ],
142
+ ```
143
+
144
+ Disabling the custom layout:
145
+
146
+ ```yaml
147
+ # app-config.yaml
148
+ app:
149
+ extensions:
150
+ - entity-content-layout:app/sticky: false
151
+ ```
152
+
153
+ Overriding the custom layout filter:
154
+
155
+ ```yaml
156
+ # app-config.yaml
157
+ app:
158
+ extensions:
159
+ - entity-content-layout:app/sticky:
160
+ config:
161
+ # This layout will be used only with component entities
162
+ filter: 'kind:component'
163
+ ```
164
+
165
+ - d78bb71: Added `hidden` prop to `EntityTagPicker`, `EntityAutocompletePicker` and `UserListPicker`.
166
+ Added `initialFilter` prop to `EntityTagPicker` to set an initial filter for the picker.
167
+ Added `alwaysKeepFilters` prop to `UserListPicker` to prevent filters from resetting when no entities match the initial filters.
168
+ - a3d93ca: Add an optional `type` parameter to `EntityCard` extensions. A card's type determines characteristics such as its expected size and where it will be rendered by the entity content layout.
169
+
170
+ Initially the following three types are supported:
171
+
172
+ - `peek`: small vertical cards that provide information at a glance, for example recent builds, deployments, and service health.
173
+ - `info`: medium size cards with high priority and frequently used information such as common actions, entity metadata, and links.
174
+ - `full`: Large cards that are more feature rich with more information, typically used by plugins that don't quite need the full content view and want to show a card instead.
175
+
176
+ ### Usage examples
177
+
178
+ Defining a default type when creating a card:
179
+
180
+ ```diff
181
+ const myCard = EntityCardBlueprint.make({
182
+ name: 'myCard',
183
+ params: {
184
+ + type: 'info',
185
+ loader: import('./MyCard).then(m => { default: m.MyCard }),
186
+ },
187
+ });
188
+ ```
189
+
190
+ Changing the card type via `app-config.yaml` file:
191
+
192
+ ```diff
193
+ app:
194
+ extensions:
195
+ + - entity-card:myPlugin/myCard:
196
+ + config:
197
+ + type: info
198
+ ```
199
+
200
+ ### Patch Changes
201
+
202
+ - bec1e15: update EntityAutocompletePicker selected options when filter value is changed externally
203
+ - 75a3551: Export CatalogAutocomplete so it can be used externally
204
+ - Updated dependencies
205
+ - @backstage/core-components@0.17.0
206
+ - @backstage/core-plugin-api@1.10.5
207
+ - @backstage/frontend-plugin-api@0.10.0
208
+ - @backstage/frontend-test-utils@0.3.0
209
+ - @backstage/core-compat-api@0.4.0
210
+ - @backstage/integration-react@1.2.5
211
+ - @backstage/plugin-permission-react@0.4.32
212
+ - @backstage/catalog-client@1.9.1
213
+ - @backstage/catalog-model@1.7.3
214
+ - @backstage/errors@1.2.7
215
+ - @backstage/types@1.2.1
216
+ - @backstage/version-bridge@1.0.11
217
+ - @backstage/plugin-catalog-common@1.1.3
218
+ - @backstage/plugin-permission-common@0.8.4
219
+
220
+ ## 1.16.0-next.2
221
+
222
+ ### Minor Changes
223
+
224
+ - 7f57365: Add support for a new entity predicate syntax when defining `filter`s related to the blueprints exported via `/alpha` for the new frontend system. For more information, see the [entity filters documentation](https://backstage.io/docs/features/software-catalog/catalog-customization#advanced-customization#entity-filters).
225
+ - 247a40b: Introduces a new `EntityHeaderBlueprint` that allows you to override the default entity page header.
226
+
227
+ ```jsx
228
+ import { EntityHeaderBlueprint } from '@backstage/plugin-catalog-react/alpha';
229
+
230
+ EntityHeaderBlueprint.make({
231
+ name: 'my-default-header',
232
+ params: {
233
+ loader: () =>
234
+ import('./MyDefaultHeader').then(m => <m.MyDefaultHeader />),
235
+ },
236
+ });
237
+ ```
238
+
239
+ ### Patch Changes
240
+
241
+ - Updated dependencies
242
+ - @backstage/frontend-plugin-api@0.10.0-next.2
243
+ - @backstage/frontend-test-utils@0.3.0-next.2
244
+ - @backstage/core-compat-api@0.4.0-next.2
245
+ - @backstage/core-components@0.16.5-next.1
246
+ - @backstage/catalog-client@1.9.1
247
+ - @backstage/catalog-model@1.7.3
248
+ - @backstage/core-plugin-api@1.10.4
249
+ - @backstage/errors@1.2.7
250
+ - @backstage/integration-react@1.2.5-next.0
251
+ - @backstage/types@1.2.1
252
+ - @backstage/version-bridge@1.0.11
253
+ - @backstage/plugin-catalog-common@1.1.3
254
+ - @backstage/plugin-permission-common@0.8.4
255
+ - @backstage/plugin-permission-react@0.4.31
256
+
3
257
  ## 1.16.0-next.1
4
258
 
5
259
  ### Patch Changes
@@ -78,7 +332,7 @@
78
332
  The layout components receive card elements and can render them as they see fit. Cards is an array of objects with the following properties:
79
333
 
80
334
  - element: `JSx.Element`;
81
- - type: `"peek" | "info" | "full" | undefined`;
335
+ - type: `"summary" | "info" | "content" | undefined`;
82
336
 
83
337
  ### Usage example
84
338
 
@@ -115,14 +369,14 @@
115
369
  <Grid xs={12} md={8} item>
116
370
  <Grid container spacing={3}>
117
371
  {cards
118
- .filter(card => card.type === 'peek')
372
+ .filter(card => card.type === 'summary')
119
373
  .map((card, index) => (
120
374
  <Grid key={index} className={classes.card} xs={12} md={6} item>
121
375
  {card.element}
122
376
  </Grid>
123
377
  ))}
124
378
  {cards
125
- .filter(card => !card.type || card.type === 'full')
379
+ .filter(card => !card.type || card.type === 'content')
126
380
  .map((card, index) => (
127
381
  <Grid key={index} className={classes.card} xs={12} md={6} item>
128
382
  {card.element}
@@ -176,9 +430,9 @@
176
430
 
177
431
  Initially the following three types are supported:
178
432
 
179
- - `peek`: small vertical cards that provide information at a glance, for example recent builds, deployments, and service health.
433
+ - `summary`: small vertical cards that provide information at a glance, for example recent builds, deployments, and service health.
180
434
  - `info`: medium size cards with high priority and frequently used information such as common actions, entity metadata, and links.
181
- - `full`: Large cards that are more feature rich with more information, typically used by plugins that don't quite need the full content view and want to show a card instead.
435
+ - `content`: Large cards that are more feature rich with more information, typically used by plugins that don't quite need the content content view and want to show a card instead.
182
436
 
183
437
  ### Usage examples
184
438
 
@@ -1,5 +1,7 @@
1
1
  import { createExtensionBlueprint, coreExtensionData, ExtensionBoundary } from '@backstage/frontend-plugin-api';
2
2
  import { entityFilterFunctionDataRef, entityFilterExpressionDataRef, entityCardTypeDataRef, entityCardTypes } from './extensionData.esm.js';
3
+ import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema.esm.js';
4
+ import { resolveEntityFilterData } from './resolveEntityFilterData.esm.js';
3
5
 
4
6
  const EntityCardBlueprint = createExtensionBlueprint({
5
7
  kind: "entity-card",
@@ -17,7 +19,7 @@ const EntityCardBlueprint = createExtensionBlueprint({
17
19
  },
18
20
  config: {
19
21
  schema: {
20
- filter: (z) => z.string().optional(),
22
+ filter: (z) => z.union([z.string(), createEntityPredicateSchema(z)]).optional(),
21
23
  type: (z) => z.enum(entityCardTypes).optional()
22
24
  }
23
25
  },
@@ -27,13 +29,7 @@ const EntityCardBlueprint = createExtensionBlueprint({
27
29
  type
28
30
  }, { node, config }) {
29
31
  yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));
30
- if (config.filter) {
31
- yield entityFilterExpressionDataRef(config.filter);
32
- } else if (typeof filter === "string") {
33
- yield entityFilterExpressionDataRef(filter);
34
- } else if (typeof filter === "function") {
35
- yield entityFilterFunctionDataRef(filter);
36
- }
32
+ yield* resolveEntityFilterData(filter, config, node);
37
33
  const finalType = config.type ?? type;
38
34
  if (finalType) {
39
35
  yield entityCardTypeDataRef(finalType);
@@ -1 +1 @@
1
- {"version":3,"file":"EntityCardBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityCardBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ExtensionBoundary,\n coreExtensionData,\n createExtensionBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityFilterFunctionDataRef,\n entityFilterExpressionDataRef,\n entityCardTypeDataRef,\n entityCardTypes,\n EntityCardType,\n} from './extensionData';\n\n/**\n * @alpha\n * A blueprint for creating cards for the entity pages in the catalog.\n */\nexport const EntityCardBlueprint = createExtensionBlueprint({\n kind: 'entity-card',\n attachTo: { id: 'entity-content:catalog/overview', input: 'cards' },\n output: [\n coreExtensionData.reactElement,\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityCardTypeDataRef.optional(),\n ],\n dataRefs: {\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n type: entityCardTypeDataRef,\n },\n config: {\n schema: {\n filter: z => z.string().optional(),\n type: z => z.enum(entityCardTypes).optional(),\n },\n },\n *factory(\n {\n loader,\n filter,\n type,\n }: {\n loader: () => Promise<JSX.Element>;\n filter?:\n | typeof entityFilterFunctionDataRef.T\n | typeof entityFilterExpressionDataRef.T;\n type?: EntityCardType;\n },\n { node, config },\n ) {\n yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));\n\n if (config.filter) {\n yield entityFilterExpressionDataRef(config.filter);\n } else if (typeof filter === 'string') {\n yield entityFilterExpressionDataRef(filter);\n } else if (typeof filter === 'function') {\n yield entityFilterFunctionDataRef(filter);\n }\n\n const finalType = config.type ?? type;\n if (finalType) {\n yield entityCardTypeDataRef(finalType);\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Not providing type for entity cards is deprecated. Missing from '${node.spec.id}'`,\n );\n }\n },\n});\n"],"names":[],"mappings":";;;AAiCO,MAAM,sBAAsB,wBAAyB,CAAA;AAAA,EAC1D,IAAM,EAAA,aAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,iCAAA,EAAmC,OAAO,OAAQ,EAAA;AAAA,EAClE,MAAQ,EAAA;AAAA,IACN,iBAAkB,CAAA,YAAA;AAAA,IAClB,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC,sBAAsB,QAAS;AAAA,GACjC;AAAA,EACA,QAAU,EAAA;AAAA,IACR,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,IAAM,EAAA;AAAA,GACR;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,MAAQ,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACjC,MAAM,CAAK,CAAA,KAAA,CAAA,CAAE,IAAK,CAAA,eAAe,EAAE,QAAS;AAAA;AAC9C,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAQF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAA,MAAM,kBAAkB,YAAa,CAAA,iBAAA,CAAkB,IAAK,CAAA,IAAA,EAAM,MAAM,CAAC,CAAA;AAEzE,IAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,MAAM,MAAA,6BAAA,CAA8B,OAAO,MAAM,CAAA;AAAA,KACnD,MAAA,IAAW,OAAO,MAAA,KAAW,QAAU,EAAA;AACrC,MAAA,MAAM,8BAA8B,MAAM,CAAA;AAAA,KAC5C,MAAA,IAAW,OAAO,MAAA,KAAW,UAAY,EAAA;AACvC,MAAA,MAAM,4BAA4B,MAAM,CAAA;AAAA;AAG1C,IAAM,MAAA,SAAA,GAAY,OAAO,IAAQ,IAAA,IAAA;AACjC,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,MAAM,sBAAsB,SAAS,CAAA;AAAA,KAChC,MAAA;AAEL,MAAQ,OAAA,CAAA,IAAA;AAAA,QACN,CAAA,sFAAA,EAAyF,IAAK,CAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,OACvG;AAAA;AACF;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"EntityCardBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityCardBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ExtensionBoundary,\n coreExtensionData,\n createExtensionBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityFilterFunctionDataRef,\n entityFilterExpressionDataRef,\n entityCardTypeDataRef,\n entityCardTypes,\n EntityCardType,\n} from './extensionData';\nimport { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema';\nimport { EntityPredicate } from '../predicates';\nimport { resolveEntityFilterData } from './resolveEntityFilterData';\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * @alpha\n * A blueprint for creating cards for the entity pages in the catalog.\n */\nexport const EntityCardBlueprint = createExtensionBlueprint({\n kind: 'entity-card',\n attachTo: { id: 'entity-content:catalog/overview', input: 'cards' },\n output: [\n coreExtensionData.reactElement,\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityCardTypeDataRef.optional(),\n ],\n dataRefs: {\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n type: entityCardTypeDataRef,\n },\n config: {\n schema: {\n filter: z =>\n z.union([z.string(), createEntityPredicateSchema(z)]).optional(),\n type: z => z.enum(entityCardTypes).optional(),\n },\n },\n *factory(\n {\n loader,\n filter,\n type,\n }: {\n loader: () => Promise<JSX.Element>;\n filter?: string | EntityPredicate | ((entity: Entity) => boolean);\n type?: EntityCardType;\n },\n { node, config },\n ) {\n yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));\n\n yield* resolveEntityFilterData(filter, config, node);\n\n const finalType = config.type ?? type;\n if (finalType) {\n yield entityCardTypeDataRef(finalType);\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Not providing type for entity cards is deprecated. Missing from '${node.spec.id}'`,\n );\n }\n },\n});\n"],"names":[],"mappings":";;;;;AAqCO,MAAM,sBAAsB,wBAAyB,CAAA;AAAA,EAC1D,IAAM,EAAA,aAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,iCAAA,EAAmC,OAAO,OAAQ,EAAA;AAAA,EAClE,MAAQ,EAAA;AAAA,IACN,iBAAkB,CAAA,YAAA;AAAA,IAClB,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC,sBAAsB,QAAS;AAAA,GACjC;AAAA,EACA,QAAU,EAAA;AAAA,IACR,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,IAAM,EAAA;AAAA,GACR;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,MAAQ,EAAA,CAAA,CAAA,KACN,CAAE,CAAA,KAAA,CAAM,CAAC,CAAA,CAAE,MAAO,EAAA,EAAG,2BAA4B,CAAA,CAAC,CAAC,CAAC,EAAE,QAAS,EAAA;AAAA,MACjE,MAAM,CAAK,CAAA,KAAA,CAAA,CAAE,IAAK,CAAA,eAAe,EAAE,QAAS;AAAA;AAC9C,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAMF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAA,MAAM,kBAAkB,YAAa,CAAA,iBAAA,CAAkB,IAAK,CAAA,IAAA,EAAM,MAAM,CAAC,CAAA;AAEzE,IAAO,OAAA,uBAAA,CAAwB,MAAQ,EAAA,MAAA,EAAQ,IAAI,CAAA;AAEnD,IAAM,MAAA,SAAA,GAAY,OAAO,IAAQ,IAAA,IAAA;AACjC,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,MAAM,sBAAsB,SAAS,CAAA;AAAA,KAChC,MAAA;AAEL,MAAQ,OAAA,CAAA,IAAA;AAAA,QACN,CAAA,sFAAA,EAAyF,IAAK,CAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,OACvG;AAAA;AACF;AAEJ,CAAC;;;;"}
@@ -1,5 +1,7 @@
1
1
  import { createExtensionBlueprint, coreExtensionData, ExtensionBoundary } from '@backstage/frontend-plugin-api';
2
2
  import { entityContentTitleDataRef, entityFilterFunctionDataRef, entityFilterExpressionDataRef, entityContentGroupDataRef } from './extensionData.esm.js';
3
+ import { resolveEntityFilterData } from './resolveEntityFilterData.esm.js';
4
+ import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema.esm.js';
3
5
 
4
6
  const EntityContentBlueprint = createExtensionBlueprint({
5
7
  kind: "entity-content",
@@ -23,7 +25,7 @@ const EntityContentBlueprint = createExtensionBlueprint({
23
25
  schema: {
24
26
  path: (z) => z.string().optional(),
25
27
  title: (z) => z.string().optional(),
26
- filter: (z) => z.string().optional(),
28
+ filter: (z) => z.union([z.string(), createEntityPredicateSchema(z)]).optional(),
27
29
  group: (z) => z.literal(false).or(z.string()).optional()
28
30
  }
29
31
  },
@@ -44,13 +46,7 @@ const EntityContentBlueprint = createExtensionBlueprint({
44
46
  if (routeRef) {
45
47
  yield coreExtensionData.routeRef(routeRef);
46
48
  }
47
- if (config.filter) {
48
- yield entityFilterExpressionDataRef(config.filter);
49
- } else if (typeof filter === "string") {
50
- yield entityFilterExpressionDataRef(filter);
51
- } else if (typeof filter === "function") {
52
- yield entityFilterFunctionDataRef(filter);
53
- }
49
+ yield* resolveEntityFilterData(filter, config, node);
54
50
  if (group) {
55
51
  yield entityContentGroupDataRef(group);
56
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EntityContentBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityContentBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n ExtensionBoundary,\n RouteRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityContentTitleDataRef,\n entityFilterFunctionDataRef,\n entityFilterExpressionDataRef,\n entityContentGroupDataRef,\n defaultEntityContentGroups,\n} from './extensionData';\n\n/**\n * @alpha\n * Creates an EntityContent extension.\n */\nexport const EntityContentBlueprint = createExtensionBlueprint({\n kind: 'entity-content',\n attachTo: { id: 'page:catalog/entity', input: 'contents' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n entityContentTitleDataRef,\n coreExtensionData.routeRef.optional(),\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityContentGroupDataRef.optional(),\n ],\n dataRefs: {\n title: entityContentTitleDataRef,\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n group: entityContentGroupDataRef,\n },\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n filter: z => z.string().optional(),\n group: z => z.literal(false).or(z.string()).optional(),\n },\n },\n *factory(\n {\n loader,\n defaultPath,\n defaultTitle,\n defaultGroup,\n filter,\n routeRef,\n }: {\n loader: () => Promise<JSX.Element>;\n defaultPath: string;\n defaultTitle: string;\n defaultGroup?: keyof typeof defaultEntityContentGroups | (string & {});\n routeRef?: RouteRef;\n filter?:\n | typeof entityFilterFunctionDataRef.T\n | typeof entityFilterExpressionDataRef.T;\n },\n { node, config },\n ) {\n const path = config.path ?? defaultPath;\n const title = config.title ?? defaultTitle;\n const group = config.group ?? defaultGroup;\n\n yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));\n\n yield coreExtensionData.routePath(path);\n\n yield entityContentTitleDataRef(title);\n\n if (routeRef) {\n yield coreExtensionData.routeRef(routeRef);\n }\n\n if (config.filter) {\n yield entityFilterExpressionDataRef(config.filter);\n } else if (typeof filter === 'string') {\n yield entityFilterExpressionDataRef(filter);\n } else if (typeof filter === 'function') {\n yield entityFilterFunctionDataRef(filter);\n }\n\n if (group) {\n yield entityContentGroupDataRef(group);\n }\n },\n});\n"],"names":[],"mappings":";;;AAkCO,MAAM,yBAAyB,wBAAyB,CAAA;AAAA,EAC7D,IAAM,EAAA,gBAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,qBAAA,EAAuB,OAAO,UAAW,EAAA;AAAA,EACzD,MAAQ,EAAA;AAAA,IACN,iBAAkB,CAAA,YAAA;AAAA,IAClB,iBAAkB,CAAA,SAAA;AAAA,IAClB,yBAAA;AAAA,IACA,iBAAA,CAAkB,SAAS,QAAS,EAAA;AAAA,IACpC,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC,0BAA0B,QAAS;AAAA,GACrC;AAAA,EACA,QAAU,EAAA;AAAA,IACR,KAAO,EAAA,yBAAA;AAAA,IACP,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,KAAO,EAAA;AAAA,GACT;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,IAAM,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAC/B,KAAO,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAChC,MAAQ,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACjC,KAAA,EAAO,CAAK,CAAA,KAAA,CAAA,CAAE,OAAQ,CAAA,KAAK,CAAE,CAAA,EAAA,CAAG,CAAE,CAAA,MAAA,EAAQ,CAAA,CAAE,QAAS;AAAA;AACvD,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GAWF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAM,MAAA,IAAA,GAAO,OAAO,IAAQ,IAAA,WAAA;AAC5B,IAAM,MAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,YAAA;AAC9B,IAAM,MAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,YAAA;AAE9B,IAAA,MAAM,kBAAkB,YAAa,CAAA,iBAAA,CAAkB,IAAK,CAAA,IAAA,EAAM,MAAM,CAAC,CAAA;AAEzE,IAAM,MAAA,iBAAA,CAAkB,UAAU,IAAI,CAAA;AAEtC,IAAA,MAAM,0BAA0B,KAAK,CAAA;AAErC,IAAA,IAAI,QAAU,EAAA;AACZ,MAAM,MAAA,iBAAA,CAAkB,SAAS,QAAQ,CAAA;AAAA;AAG3C,IAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,MAAM,MAAA,6BAAA,CAA8B,OAAO,MAAM,CAAA;AAAA,KACnD,MAAA,IAAW,OAAO,MAAA,KAAW,QAAU,EAAA;AACrC,MAAA,MAAM,8BAA8B,MAAM,CAAA;AAAA,KAC5C,MAAA,IAAW,OAAO,MAAA,KAAW,UAAY,EAAA;AACvC,MAAA,MAAM,4BAA4B,MAAM,CAAA;AAAA;AAG1C,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,MAAM,0BAA0B,KAAK,CAAA;AAAA;AACvC;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"EntityContentBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityContentBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n ExtensionBoundary,\n RouteRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityContentTitleDataRef,\n entityFilterFunctionDataRef,\n entityFilterExpressionDataRef,\n entityContentGroupDataRef,\n defaultEntityContentGroups,\n} from './extensionData';\nimport { EntityPredicate } from '../predicates';\nimport { resolveEntityFilterData } from './resolveEntityFilterData';\nimport { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema';\nimport { Entity } from '@backstage/catalog-model';\n\n/**\n * @alpha\n * Creates an EntityContent extension.\n */\nexport const EntityContentBlueprint = createExtensionBlueprint({\n kind: 'entity-content',\n attachTo: { id: 'page:catalog/entity', input: 'contents' },\n output: [\n coreExtensionData.reactElement,\n coreExtensionData.routePath,\n entityContentTitleDataRef,\n coreExtensionData.routeRef.optional(),\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityContentGroupDataRef.optional(),\n ],\n dataRefs: {\n title: entityContentTitleDataRef,\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n group: entityContentGroupDataRef,\n },\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n filter: z =>\n z.union([z.string(), createEntityPredicateSchema(z)]).optional(),\n group: z => z.literal(false).or(z.string()).optional(),\n },\n },\n *factory(\n {\n loader,\n defaultPath,\n defaultTitle,\n defaultGroup,\n filter,\n routeRef,\n }: {\n loader: () => Promise<JSX.Element>;\n defaultPath: string;\n defaultTitle: string;\n defaultGroup?: keyof typeof defaultEntityContentGroups | (string & {});\n routeRef?: RouteRef;\n filter?: string | EntityPredicate | ((entity: Entity) => boolean);\n },\n { node, config },\n ) {\n const path = config.path ?? defaultPath;\n const title = config.title ?? defaultTitle;\n const group = config.group ?? defaultGroup;\n\n yield coreExtensionData.reactElement(ExtensionBoundary.lazy(node, loader));\n\n yield coreExtensionData.routePath(path);\n\n yield entityContentTitleDataRef(title);\n\n if (routeRef) {\n yield coreExtensionData.routeRef(routeRef);\n }\n\n yield* resolveEntityFilterData(filter, config, node);\n\n if (group) {\n yield entityContentGroupDataRef(group);\n }\n },\n});\n"],"names":[],"mappings":";;;;;AAsCO,MAAM,yBAAyB,wBAAyB,CAAA;AAAA,EAC7D,IAAM,EAAA,gBAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,qBAAA,EAAuB,OAAO,UAAW,EAAA;AAAA,EACzD,MAAQ,EAAA;AAAA,IACN,iBAAkB,CAAA,YAAA;AAAA,IAClB,iBAAkB,CAAA,SAAA;AAAA,IAClB,yBAAA;AAAA,IACA,iBAAA,CAAkB,SAAS,QAAS,EAAA;AAAA,IACpC,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC,0BAA0B,QAAS;AAAA,GACrC;AAAA,EACA,QAAU,EAAA;AAAA,IACR,KAAO,EAAA,yBAAA;AAAA,IACP,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,KAAO,EAAA;AAAA,GACT;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,IAAM,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAC/B,KAAO,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAChC,MAAQ,EAAA,CAAA,CAAA,KACN,CAAE,CAAA,KAAA,CAAM,CAAC,CAAA,CAAE,MAAO,EAAA,EAAG,2BAA4B,CAAA,CAAC,CAAC,CAAC,EAAE,QAAS,EAAA;AAAA,MACjE,KAAA,EAAO,CAAK,CAAA,KAAA,CAAA,CAAE,OAAQ,CAAA,KAAK,CAAE,CAAA,EAAA,CAAG,CAAE,CAAA,MAAA,EAAQ,CAAA,CAAE,QAAS;AAAA;AACvD,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GASF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAM,MAAA,IAAA,GAAO,OAAO,IAAQ,IAAA,WAAA;AAC5B,IAAM,MAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,YAAA;AAC9B,IAAM,MAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,YAAA;AAE9B,IAAA,MAAM,kBAAkB,YAAa,CAAA,iBAAA,CAAkB,IAAK,CAAA,IAAA,EAAM,MAAM,CAAC,CAAA;AAEzE,IAAM,MAAA,iBAAA,CAAkB,UAAU,IAAI,CAAA;AAEtC,IAAA,MAAM,0BAA0B,KAAK,CAAA;AAErC,IAAA,IAAI,QAAU,EAAA;AACZ,MAAM,MAAA,iBAAA,CAAkB,SAAS,QAAQ,CAAA;AAAA;AAG3C,IAAO,OAAA,uBAAA,CAAwB,MAAQ,EAAA,MAAA,EAAQ,IAAI,CAAA;AAEnD,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,MAAM,0BAA0B,KAAK,CAAA;AAAA;AACvC;AAEJ,CAAC;;;;"}
@@ -1,5 +1,7 @@
1
1
  import { createExtensionDataRef, createExtensionBlueprint, ExtensionBoundary } from '@backstage/frontend-plugin-api';
2
2
  import { entityFilterFunctionDataRef, entityFilterExpressionDataRef } from './extensionData.esm.js';
3
+ import { resolveEntityFilterData } from './resolveEntityFilterData.esm.js';
4
+ import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema.esm.js';
3
5
 
4
6
  const entityCardLayoutComponentDataRef = createExtensionDataRef().with({
5
7
  id: "catalog.entity-content-layout.component"
@@ -20,20 +22,14 @@ const EntityContentLayoutBlueprint = createExtensionBlueprint({
20
22
  config: {
21
23
  schema: {
22
24
  type: (z) => z.string().optional(),
23
- filter: (z) => z.string().optional()
25
+ filter: (z) => z.union([z.string(), createEntityPredicateSchema(z)]).optional()
24
26
  }
25
27
  },
26
28
  *factory({
27
29
  loader,
28
30
  filter
29
31
  }, { node, config }) {
30
- if (config.filter) {
31
- yield entityFilterExpressionDataRef(config.filter);
32
- } else if (typeof filter === "string") {
33
- yield entityFilterExpressionDataRef(filter);
34
- } else if (typeof filter === "function") {
35
- yield entityFilterFunctionDataRef(filter);
36
- }
32
+ yield* resolveEntityFilterData(filter, config, node);
37
33
  yield entityCardLayoutComponentDataRef(
38
34
  ExtensionBoundary.lazyComponent(node, loader)
39
35
  );
@@ -1 +1 @@
1
- {"version":3,"file":"EntityContentLayoutBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityContentLayoutBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 createExtensionDataRef,\n createExtensionBlueprint,\n ExtensionBoundary,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityFilterExpressionDataRef,\n entityFilterFunctionDataRef,\n EntityCardType,\n} from './extensionData';\nimport React from 'react';\n\n/** @alpha */\nexport interface EntityContentLayoutProps {\n cards: Array<{\n type?: EntityCardType;\n element: React.JSX.Element;\n }>;\n}\n\nconst entityCardLayoutComponentDataRef = createExtensionDataRef<\n (props: EntityContentLayoutProps) => React.JSX.Element\n>().with({\n id: 'catalog.entity-content-layout.component',\n});\n\n/** @alpha */\nexport const EntityContentLayoutBlueprint = createExtensionBlueprint({\n kind: 'entity-content-layout',\n attachTo: { id: 'entity-content:catalog/overview', input: 'layouts' },\n output: [\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityCardLayoutComponentDataRef,\n ],\n dataRefs: {\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n component: entityCardLayoutComponentDataRef,\n },\n config: {\n schema: {\n type: z => z.string().optional(),\n filter: z => z.string().optional(),\n },\n },\n *factory(\n {\n loader,\n filter,\n }: {\n filter?:\n | typeof entityFilterFunctionDataRef.T\n | typeof entityFilterExpressionDataRef.T;\n loader: () => Promise<\n (props: EntityContentLayoutProps) => React.JSX.Element\n >;\n },\n { node, config },\n ) {\n if (config.filter) {\n yield entityFilterExpressionDataRef(config.filter);\n } else if (typeof filter === 'string') {\n yield entityFilterExpressionDataRef(filter);\n } else if (typeof filter === 'function') {\n yield entityFilterFunctionDataRef(filter);\n }\n\n yield entityCardLayoutComponentDataRef(\n ExtensionBoundary.lazyComponent(node, loader),\n );\n },\n});\n"],"names":[],"mappings":";;;AAoCA,MAAM,gCAAA,GAAmC,sBAEvC,EAAA,CAAE,IAAK,CAAA;AAAA,EACP,EAAI,EAAA;AACN,CAAC,CAAA;AAGM,MAAM,+BAA+B,wBAAyB,CAAA;AAAA,EACnE,IAAM,EAAA,uBAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,iCAAA,EAAmC,OAAO,SAAU,EAAA;AAAA,EACpE,MAAQ,EAAA;AAAA,IACN,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC;AAAA,GACF;AAAA,EACA,QAAU,EAAA;AAAA,IACR,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,SAAW,EAAA;AAAA,GACb;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,IAAM,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAC/B,MAAQ,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS;AAAA;AACnC,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA;AAAA,GASF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,MAAM,MAAA,6BAAA,CAA8B,OAAO,MAAM,CAAA;AAAA,KACnD,MAAA,IAAW,OAAO,MAAA,KAAW,QAAU,EAAA;AACrC,MAAA,MAAM,8BAA8B,MAAM,CAAA;AAAA,KAC5C,MAAA,IAAW,OAAO,MAAA,KAAW,UAAY,EAAA;AACvC,MAAA,MAAM,4BAA4B,MAAM,CAAA;AAAA;AAG1C,IAAM,MAAA,gCAAA;AAAA,MACJ,iBAAA,CAAkB,aAAc,CAAA,IAAA,EAAM,MAAM;AAAA,KAC9C;AAAA;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"EntityContentLayoutBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityContentLayoutBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 createExtensionDataRef,\n createExtensionBlueprint,\n ExtensionBoundary,\n} from '@backstage/frontend-plugin-api';\nimport {\n entityFilterExpressionDataRef,\n entityFilterFunctionDataRef,\n EntityCardType,\n} from './extensionData';\nimport React from 'react';\nimport { EntityPredicate } from '../predicates';\nimport { resolveEntityFilterData } from './resolveEntityFilterData';\nimport { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema';\nimport { Entity } from '@backstage/catalog-model';\n\n/** @alpha */\nexport interface EntityContentLayoutProps {\n cards: Array<{\n type?: EntityCardType;\n element: React.JSX.Element;\n }>;\n}\n\nconst entityCardLayoutComponentDataRef = createExtensionDataRef<\n (props: EntityContentLayoutProps) => React.JSX.Element\n>().with({\n id: 'catalog.entity-content-layout.component',\n});\n\n/** @alpha */\nexport const EntityContentLayoutBlueprint = createExtensionBlueprint({\n kind: 'entity-content-layout',\n attachTo: { id: 'entity-content:catalog/overview', input: 'layouts' },\n output: [\n entityFilterFunctionDataRef.optional(),\n entityFilterExpressionDataRef.optional(),\n entityCardLayoutComponentDataRef,\n ],\n dataRefs: {\n filterFunction: entityFilterFunctionDataRef,\n filterExpression: entityFilterExpressionDataRef,\n component: entityCardLayoutComponentDataRef,\n },\n config: {\n schema: {\n type: z => z.string().optional(),\n filter: z =>\n z.union([z.string(), createEntityPredicateSchema(z)]).optional(),\n },\n },\n *factory(\n {\n loader,\n filter,\n }: {\n filter?: string | EntityPredicate | ((entity: Entity) => boolean);\n loader: () => Promise<\n (props: EntityContentLayoutProps) => React.JSX.Element\n >;\n },\n { node, config },\n ) {\n yield* resolveEntityFilterData(filter, config, node);\n\n yield entityCardLayoutComponentDataRef(\n ExtensionBoundary.lazyComponent(node, loader),\n );\n },\n});\n"],"names":[],"mappings":";;;;;AAwCA,MAAM,gCAAA,GAAmC,sBAEvC,EAAA,CAAE,IAAK,CAAA;AAAA,EACP,EAAI,EAAA;AACN,CAAC,CAAA;AAGM,MAAM,+BAA+B,wBAAyB,CAAA;AAAA,EACnE,IAAM,EAAA,uBAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,iCAAA,EAAmC,OAAO,SAAU,EAAA;AAAA,EACpE,MAAQ,EAAA;AAAA,IACN,4BAA4B,QAAS,EAAA;AAAA,IACrC,8BAA8B,QAAS,EAAA;AAAA,IACvC;AAAA,GACF;AAAA,EACA,QAAU,EAAA;AAAA,IACR,cAAgB,EAAA,2BAAA;AAAA,IAChB,gBAAkB,EAAA,6BAAA;AAAA,IAClB,SAAW,EAAA;AAAA,GACb;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,IAAM,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAC/B,MAAQ,EAAA,CAAA,CAAA,KACN,CAAE,CAAA,KAAA,CAAM,CAAC,CAAA,CAAE,MAAO,EAAA,EAAG,2BAA4B,CAAA,CAAC,CAAC,CAAC,EAAE,QAAS;AAAA;AACnE,GACF;AAAA,EACA,CAAC,OACC,CAAA;AAAA,IACE,MAAA;AAAA,IACA;AAAA,GAOF,EAAA,EAAE,IAAM,EAAA,MAAA,EACR,EAAA;AACA,IAAO,OAAA,uBAAA,CAAwB,MAAQ,EAAA,MAAA,EAAQ,IAAI,CAAA;AAEnD,IAAM,MAAA,gCAAA;AAAA,MACJ,iBAAA,CAAkB,aAAc,CAAA,IAAA,EAAM,MAAM;AAAA,KAC9C;AAAA;AAEJ,CAAC;;;;"}
@@ -0,0 +1,21 @@
1
+ import { createExtensionBlueprint, coreExtensionData, ExtensionBoundary } from '@backstage/frontend-plugin-api';
2
+
3
+ const EntityHeaderBlueprint = createExtensionBlueprint({
4
+ kind: "entity-header",
5
+ attachTo: { id: "page:catalog/entity", input: "header" },
6
+ dataRefs: {
7
+ element: coreExtensionData.reactElement
8
+ },
9
+ output: [coreExtensionData.reactElement.optional()],
10
+ *factory(params, { node }) {
11
+ const { loader } = params;
12
+ if (loader) {
13
+ yield coreExtensionData.reactElement(
14
+ ExtensionBoundary.lazy(node, loader)
15
+ );
16
+ }
17
+ }
18
+ });
19
+
20
+ export { EntityHeaderBlueprint };
21
+ //# sourceMappingURL=EntityHeaderBlueprint.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityHeaderBlueprint.esm.js","sources":["../../../src/alpha/blueprints/EntityHeaderBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 createExtensionBlueprint,\n coreExtensionData,\n ExtensionBoundary,\n} from '@backstage/frontend-plugin-api';\n\n/** @alpha */\nexport const EntityHeaderBlueprint = createExtensionBlueprint({\n kind: 'entity-header',\n attachTo: { id: 'page:catalog/entity', input: 'header' },\n dataRefs: {\n element: coreExtensionData.reactElement,\n },\n output: [coreExtensionData.reactElement.optional()],\n *factory(\n params: {\n loader: () => Promise<JSX.Element>;\n },\n { node },\n ) {\n const { loader } = params;\n if (loader) {\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, loader),\n );\n }\n },\n});\n"],"names":[],"mappings":";;AAuBO,MAAM,wBAAwB,wBAAyB,CAAA;AAAA,EAC5D,IAAM,EAAA,eAAA;AAAA,EACN,QAAU,EAAA,EAAE,EAAI,EAAA,qBAAA,EAAuB,OAAO,QAAS,EAAA;AAAA,EACvD,QAAU,EAAA;AAAA,IACR,SAAS,iBAAkB,CAAA;AAAA,GAC7B;AAAA,EACA,MAAQ,EAAA,CAAC,iBAAkB,CAAA,YAAA,CAAa,UAAU,CAAA;AAAA,EAClD,CAAC,OAAA,CACC,MAGA,EAAA,EAAE,MACF,EAAA;AACA,IAAM,MAAA,EAAE,QAAW,GAAA,MAAA;AACnB,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,MAAM,iBAAkB,CAAA,YAAA;AAAA,QACtB,iBAAA,CAAkB,IAAK,CAAA,IAAA,EAAM,MAAM;AAAA,OACrC;AAAA;AACF;AAEJ,CAAC;;;;"}
@@ -17,9 +17,9 @@ const entityContentGroupDataRef = createExtensionDataRef().with({
17
17
  id: "catalog.entity-content-group"
18
18
  });
19
19
  const entityCardTypes = [
20
- "peek",
20
+ "summary",
21
21
  "info",
22
- "full"
22
+ "content"
23
23
  ];
24
24
  const entityCardTypeDataRef = createExtensionDataRef().with({
25
25
  id: "catalog.entity-card-type"
@@ -1 +1 @@
1
- {"version":3,"file":"extensionData.esm.js","sources":["../../../src/alpha/blueprints/extensionData.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 { Entity } from '@backstage/catalog-model';\nimport { createExtensionDataRef } from '@backstage/frontend-plugin-api';\n\n/** @internal */\nexport const entityContentTitleDataRef = createExtensionDataRef<string>().with({\n id: 'catalog.entity-content-title',\n});\n\n/** @internal */\nexport const entityFilterFunctionDataRef = createExtensionDataRef<\n (entity: Entity) => boolean\n>().with({ id: 'catalog.entity-filter-function' });\n\n/** @internal */\nexport const entityFilterExpressionDataRef =\n createExtensionDataRef<string>().with({\n id: 'catalog.entity-filter-expression',\n });\n\n/**\n * @alpha\n * Default entity content groups.\n */\nexport const defaultEntityContentGroups = {\n documentation: 'Documentation',\n development: 'Development',\n deployment: 'Deployment',\n observability: 'Observability',\n};\n\n/** @internal */\nexport const entityContentGroupDataRef = createExtensionDataRef<string>().with({\n id: 'catalog.entity-content-group',\n});\n\n/**\n * @internal\n * Available entity card types\n */\nexport const entityCardTypes = [\n 'peek',\n 'info',\n 'full',\n] as const satisfies readonly EntityCardType[];\n\n/** @alpha */\nexport type EntityCardType = 'peek' | 'info' | 'full';\n\n/** @internal */\nexport const entityCardTypeDataRef =\n createExtensionDataRef<EntityCardType>().with({\n id: 'catalog.entity-card-type',\n });\n"],"names":[],"mappings":";;AAoBa,MAAA,yBAAA,GAA4B,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EAC7E,EAAI,EAAA;AACN,CAAC;AAGM,MAAM,8BAA8B,sBAEzC,EAAA,CAAE,KAAK,EAAE,EAAA,EAAI,kCAAkC;AAGpC,MAAA,6BAAA,GACX,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EACpC,EAAI,EAAA;AACN,CAAC;AAMI,MAAM,0BAA6B,GAAA;AAAA,EACxC,aAAe,EAAA,eAAA;AAAA,EACf,WAAa,EAAA,aAAA;AAAA,EACb,UAAY,EAAA,YAAA;AAAA,EACZ,aAAe,EAAA;AACjB;AAGa,MAAA,yBAAA,GAA4B,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EAC7E,EAAI,EAAA;AACN,CAAC;AAMM,MAAM,eAAkB,GAAA;AAAA,EAC7B,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF;AAMa,MAAA,qBAAA,GACX,sBAAuC,EAAA,CAAE,IAAK,CAAA;AAAA,EAC5C,EAAI,EAAA;AACN,CAAC;;;;"}
1
+ {"version":3,"file":"extensionData.esm.js","sources":["../../../src/alpha/blueprints/extensionData.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 { Entity } from '@backstage/catalog-model';\nimport { createExtensionDataRef } from '@backstage/frontend-plugin-api';\n\n/** @internal */\nexport const entityContentTitleDataRef = createExtensionDataRef<string>().with({\n id: 'catalog.entity-content-title',\n});\n\n/** @internal */\nexport const entityFilterFunctionDataRef = createExtensionDataRef<\n (entity: Entity) => boolean\n>().with({ id: 'catalog.entity-filter-function' });\n\n/** @internal */\nexport const entityFilterExpressionDataRef =\n createExtensionDataRef<string>().with({\n id: 'catalog.entity-filter-expression',\n });\n\n/**\n * @alpha\n * Default entity content groups.\n */\nexport const defaultEntityContentGroups = {\n documentation: 'Documentation',\n development: 'Development',\n deployment: 'Deployment',\n observability: 'Observability',\n};\n\n/** @internal */\nexport const entityContentGroupDataRef = createExtensionDataRef<string>().with({\n id: 'catalog.entity-content-group',\n});\n\n/**\n * @internal\n * Available entity card types\n */\nexport const entityCardTypes = [\n 'summary',\n 'info',\n 'content',\n] as const satisfies readonly EntityCardType[];\n\n/** @alpha */\nexport type EntityCardType = 'summary' | 'info' | 'content';\n\n/** @internal */\nexport const entityCardTypeDataRef =\n createExtensionDataRef<EntityCardType>().with({\n id: 'catalog.entity-card-type',\n });\n"],"names":[],"mappings":";;AAoBa,MAAA,yBAAA,GAA4B,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EAC7E,EAAI,EAAA;AACN,CAAC;AAGM,MAAM,8BAA8B,sBAEzC,EAAA,CAAE,KAAK,EAAE,EAAA,EAAI,kCAAkC;AAGpC,MAAA,6BAAA,GACX,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EACpC,EAAI,EAAA;AACN,CAAC;AAMI,MAAM,0BAA6B,GAAA;AAAA,EACxC,aAAe,EAAA,eAAA;AAAA,EACf,WAAa,EAAA,aAAA;AAAA,EACb,UAAY,EAAA,YAAA;AAAA,EACZ,aAAe,EAAA;AACjB;AAGa,MAAA,yBAAA,GAA4B,sBAA+B,EAAA,CAAE,IAAK,CAAA;AAAA,EAC7E,EAAI,EAAA;AACN,CAAC;AAMM,MAAM,eAAkB,GAAA;AAAA,EAC7B,SAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF;AAMa,MAAA,qBAAA,GACX,sBAAuC,EAAA,CAAE,IAAK,CAAA;AAAA,EAC5C,EAAI,EAAA;AACN,CAAC;;;;"}
@@ -0,0 +1,27 @@
1
+ import { entityFilterExpressionDataRef, entityFilterFunctionDataRef } from './extensionData.esm.js';
2
+ import { entityPredicateToFilterFunction } from '../predicates/entityPredicateToFilterFunction.esm.js';
3
+
4
+ function* resolveEntityFilterData(filter, config, node) {
5
+ if (typeof config.filter === "string") {
6
+ console.warn(
7
+ `DEPRECATION WARNING: Using a string-based filter in the configuration for '${node.spec.id}' is deprecated. Use an entity predicate object instead.`
8
+ );
9
+ yield entityFilterExpressionDataRef(config.filter);
10
+ } else if (config.filter) {
11
+ yield entityFilterFunctionDataRef(
12
+ entityPredicateToFilterFunction(config.filter)
13
+ );
14
+ } else if (typeof filter === "function") {
15
+ yield entityFilterFunctionDataRef(filter);
16
+ } else if (typeof filter === "string") {
17
+ console.warn(
18
+ `DEPRECATION WARNING: Using a string as the default filter for '${node.spec.id}' is deprecated. Use an entity predicate object instead.`
19
+ );
20
+ yield entityFilterExpressionDataRef(filter);
21
+ } else if (filter) {
22
+ yield entityFilterFunctionDataRef(entityPredicateToFilterFunction(filter));
23
+ }
24
+ }
25
+
26
+ export { resolveEntityFilterData };
27
+ //# sourceMappingURL=resolveEntityFilterData.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveEntityFilterData.esm.js","sources":["../../../src/alpha/blueprints/resolveEntityFilterData.ts"],"sourcesContent":["/*\n * Copyright 2025 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 entityFilterExpressionDataRef,\n entityFilterFunctionDataRef,\n} from './extensionData';\nimport {\n EntityPredicate,\n entityPredicateToFilterFunction,\n} from '../predicates';\nimport { Entity } from '@backstage/catalog-model';\nimport { AppNode } from '@backstage/frontend-plugin-api';\n\nexport function* resolveEntityFilterData(\n filter: ((entity: Entity) => boolean) | EntityPredicate | string | undefined,\n config: { filter?: EntityPredicate | string },\n node: AppNode,\n) {\n if (typeof config.filter === 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Using a string-based filter in the configuration for '${node.spec.id}' is deprecated. Use an entity predicate object instead.`,\n );\n yield entityFilterExpressionDataRef(config.filter);\n } else if (config.filter) {\n yield entityFilterFunctionDataRef(\n entityPredicateToFilterFunction(config.filter),\n );\n } else if (typeof filter === 'function') {\n yield entityFilterFunctionDataRef(filter);\n } else if (typeof filter === 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: Using a string as the default filter for '${node.spec.id}' is deprecated. Use an entity predicate object instead.`,\n );\n yield entityFilterExpressionDataRef(filter);\n } else if (filter) {\n yield entityFilterFunctionDataRef(entityPredicateToFilterFunction(filter));\n }\n}\n"],"names":[],"mappings":";;;AA2BiB,UAAA,uBAAA,CACf,MACA,EAAA,MAAA,EACA,IACA,EAAA;AACA,EAAI,IAAA,OAAO,MAAO,CAAA,MAAA,KAAW,QAAU,EAAA;AAErC,IAAQ,OAAA,CAAA,IAAA;AAAA,MACN,CAAA,2EAAA,EAA8E,IAAK,CAAA,IAAA,CAAK,EAAE,CAAA,wDAAA;AAAA,KAC5F;AACA,IAAM,MAAA,6BAAA,CAA8B,OAAO,MAAM,CAAA;AAAA,GACnD,MAAA,IAAW,OAAO,MAAQ,EAAA;AACxB,IAAM,MAAA,2BAAA;AAAA,MACJ,+BAAA,CAAgC,OAAO,MAAM;AAAA,KAC/C;AAAA,GACF,MAAA,IAAW,OAAO,MAAA,KAAW,UAAY,EAAA;AACvC,IAAA,MAAM,4BAA4B,MAAM,CAAA;AAAA,GAC1C,MAAA,IAAW,OAAO,MAAA,KAAW,QAAU,EAAA;AAErC,IAAQ,OAAA,CAAA,IAAA;AAAA,MACN,CAAA,+DAAA,EAAkE,IAAK,CAAA,IAAA,CAAK,EAAE,CAAA,wDAAA;AAAA,KAChF;AACA,IAAA,MAAM,8BAA8B,MAAM,CAAA;AAAA,aACjC,MAAQ,EAAA;AACjB,IAAM,MAAA,2BAAA,CAA4B,+BAAgC,CAAA,MAAM,CAAC,CAAA;AAAA;AAE7E;;;;"}
@@ -4,6 +4,7 @@ import React from 'react';
4
4
  import { EntityCardBlueprint } from '../blueprints/EntityCardBlueprint.esm.js';
5
5
  import '../blueprints/EntityContentBlueprint.esm.js';
6
6
  import '../blueprints/EntityContentLayoutBlueprint.esm.js';
7
+ import '../blueprints/EntityHeaderBlueprint.esm.js';
7
8
  import '../blueprints/extensionData.esm.js';
8
9
  import kebabCase from 'lodash/kebabCase';
9
10
 
@@ -1 +1 @@
1
- {"version":3,"file":"convertLegacyEntityCardExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityCardExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport React, { ComponentType } from 'react';\nimport { EntityCardBlueprint } from '../blueprints';\nimport kebabCase from 'lodash/kebabCase';\n\n/** @alpha */\nexport function convertLegacyEntityCardExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?:\n | typeof EntityCardBlueprint.dataRefs.filterFunction.T\n | typeof EntityCardBlueprint.dataRefs.filterExpression.T;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Card$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityCardBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;AAwBgB,SAAA,gCAAA,CACd,iBACA,SAMqB,EAAA;AACrB,EAAM,MAAA,OAAA,uCAAW,eAAgB,EAAA,IAAA,CAAA;AAEjC,EAAM,MAAA,OAAA,GAAU,gBAAyB,CAAA,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAM,MAAA,IAAI,MAAM,uBAAuB,CAAA;AAAA;AAGzC,EAAM,MAAA,MAAA,GAAS,gBAAkC,CAAA,OAAA,EAAS,aAAa,CAAA;AACvE,EAAM,MAAA,QAAA,GAAW,QAAQ,KAAM,EAAA;AAE/B,EAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,kBAAkB,CAAA;AAC9C,EAAM,MAAA,KAAA,GAAQ,KAAQ,GAAA,CAAC,CAAK,IAAA,OAAA;AAE5B,EAAA,IAAI,IAA2B,GAAA,KAAA;AAC/B,EACE,IAAA,QAAA,IACA,IACG,CAAA,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAS,CAAA,iBAAA,CAAkB,OAAO,CAAC,CACjD,EAAA;AACA,IAAO,IAAA,GAAA,IAAA,CAAK,KAAM,CAAA,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAO,IAAA,GAAA,KAAA,CAAA;AAAA;AACT;AAEF,EAAO,IAAA,GAAA,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,oBAAoB,IAAK,CAAA;AAAA,IAC9B,IAAA,EAAM,WAAW,IAAQ,IAAA,IAAA;AAAA,IACzB,MAAQ,EAAA;AAAA,MACN,QAAQ,SAAW,EAAA,MAAA;AAAA,MACnB,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"convertLegacyEntityCardExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityCardExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { BackstagePlugin, getComponentData } from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport React, { ComponentType } from 'react';\nimport { EntityCardBlueprint } from '../blueprints';\nimport kebabCase from 'lodash/kebabCase';\nimport { EntityPredicate } from '../predicates';\nimport { Entity } from '@backstage/catalog-model';\n\n/** @alpha */\nexport function convertLegacyEntityCardExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | EntityPredicate | ((entity: Entity) => boolean);\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Card$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityCardBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;AA0BgB,SAAA,gCAAA,CACd,iBACA,SAIqB,EAAA;AACrB,EAAM,MAAA,OAAA,uCAAW,eAAgB,EAAA,IAAA,CAAA;AAEjC,EAAM,MAAA,OAAA,GAAU,gBAAyB,CAAA,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAM,MAAA,IAAI,MAAM,uBAAuB,CAAA;AAAA;AAGzC,EAAM,MAAA,MAAA,GAAS,gBAAkC,CAAA,OAAA,EAAS,aAAa,CAAA;AACvE,EAAM,MAAA,QAAA,GAAW,QAAQ,KAAM,EAAA;AAE/B,EAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,kBAAkB,CAAA;AAC9C,EAAM,MAAA,KAAA,GAAQ,KAAQ,GAAA,CAAC,CAAK,IAAA,OAAA;AAE5B,EAAA,IAAI,IAA2B,GAAA,KAAA;AAC/B,EACE,IAAA,QAAA,IACA,IACG,CAAA,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAS,CAAA,iBAAA,CAAkB,OAAO,CAAC,CACjD,EAAA;AACA,IAAO,IAAA,GAAA,IAAA,CAAK,KAAM,CAAA,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAO,IAAA,GAAA,KAAA,CAAA;AAAA;AACT;AAEF,EAAO,IAAA,GAAA,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,oBAAoB,IAAK,CAAA;AAAA,IAC9B,IAAA,EAAM,WAAW,IAAQ,IAAA,IAAA;AAAA,IACzB,MAAQ,EAAA;AAAA,MACN,QAAQ,SAAW,EAAA,MAAA;AAAA,MACnB,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
@@ -6,6 +6,7 @@ import React from 'react';
6
6
  import '../blueprints/EntityCardBlueprint.esm.js';
7
7
  import { EntityContentBlueprint } from '../blueprints/EntityContentBlueprint.esm.js';
8
8
  import '../blueprints/EntityContentLayoutBlueprint.esm.js';
9
+ import '../blueprints/EntityHeaderBlueprint.esm.js';
9
10
  import '../blueprints/extensionData.esm.js';
10
11
 
11
12
  function convertLegacyEntityContentExtension(LegacyExtension, overrides) {
@@ -1 +1 @@
1
- {"version":3,"file":"convertLegacyEntityContentExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityContentExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n BackstagePlugin,\n getComponentData,\n RouteRef as LegacyRouteRef,\n} from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport kebabCase from 'lodash/kebabCase';\nimport startCase from 'lodash/startCase';\nimport React, { ComponentType } from 'react';\nimport { EntityContentBlueprint } from '../blueprints';\n\n/** @alpha */\nexport function convertLegacyEntityContentExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?:\n | typeof EntityContentBlueprint.dataRefs.filterFunction.T\n | typeof EntityContentBlueprint.dataRefs.filterExpression.T;\n defaultPath?: string;\n defaultTitle?: string;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const mountPoint = getComponentData<LegacyRouteRef>(\n element,\n 'core.mountPoint',\n );\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Content$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityContentBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n defaultPath: overrides?.defaultPath ?? `/${kebabCase(infix)}`,\n defaultTitle: overrides?.defaultTitle ?? startCase(infix),\n routeRef: mountPoint && convertLegacyRouteRef(mountPoint),\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;AAgCgB,SAAA,mCAAA,CACd,iBACA,SAQqB,EAAA;AACrB,EAAM,MAAA,OAAA,uCAAW,eAAgB,EAAA,IAAA,CAAA;AAEjC,EAAM,MAAA,OAAA,GAAU,gBAAyB,CAAA,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAM,MAAA,IAAI,MAAM,uBAAuB,CAAA;AAAA;AAGzC,EAAA,MAAM,UAAa,GAAA,gBAAA;AAAA,IACjB,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAM,MAAA,MAAA,GAAS,gBAAkC,CAAA,OAAA,EAAS,aAAa,CAAA;AACvE,EAAM,MAAA,QAAA,GAAW,QAAQ,KAAM,EAAA;AAE/B,EAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,qBAAqB,CAAA;AACjD,EAAM,MAAA,KAAA,GAAQ,KAAQ,GAAA,CAAC,CAAK,IAAA,OAAA;AAE5B,EAAA,IAAI,IAA2B,GAAA,KAAA;AAC/B,EACE,IAAA,QAAA,IACA,IACG,CAAA,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAS,CAAA,iBAAA,CAAkB,OAAO,CAAC,CACjD,EAAA;AACA,IAAO,IAAA,GAAA,IAAA,CAAK,KAAM,CAAA,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAO,IAAA,GAAA,KAAA,CAAA;AAAA;AACT;AAEF,EAAO,IAAA,GAAA,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,uBAAuB,IAAK,CAAA;AAAA,IACjC,IAAA,EAAM,WAAW,IAAQ,IAAA,IAAA;AAAA,IACzB,MAAQ,EAAA;AAAA,MACN,QAAQ,SAAW,EAAA,MAAA;AAAA,MACnB,aAAa,SAAW,EAAA,WAAA,IAAe,CAAI,CAAA,EAAA,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,MAC3D,YAAc,EAAA,SAAA,EAAW,YAAgB,IAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACxD,QAAA,EAAU,UAAc,IAAA,qBAAA,CAAsB,UAAU,CAAA;AAAA,MACxD,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"convertLegacyEntityContentExtension.esm.js","sources":["../../../src/alpha/converters/convertLegacyEntityContentExtension.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n BackstagePlugin,\n getComponentData,\n RouteRef as LegacyRouteRef,\n} from '@backstage/core-plugin-api';\nimport { ExtensionDefinition } from '@backstage/frontend-plugin-api';\nimport kebabCase from 'lodash/kebabCase';\nimport startCase from 'lodash/startCase';\nimport React, { ComponentType } from 'react';\nimport { EntityContentBlueprint } from '../blueprints';\nimport { EntityPredicate } from '../predicates';\nimport { Entity } from '@backstage/catalog-model';\n\n/** @alpha */\nexport function convertLegacyEntityContentExtension(\n LegacyExtension: ComponentType<{}>,\n overrides?: {\n name?: string;\n filter?: string | EntityPredicate | ((entity: Entity) => boolean);\n defaultPath?: string;\n defaultTitle?: string;\n },\n): ExtensionDefinition {\n const element = <LegacyExtension />;\n\n const extName = getComponentData<string>(element, 'core.extensionName');\n if (!extName) {\n throw new Error('Extension has no name');\n }\n\n const mountPoint = getComponentData<LegacyRouteRef>(\n element,\n 'core.mountPoint',\n );\n\n const plugin = getComponentData<BackstagePlugin>(element, 'core.plugin');\n const pluginId = plugin?.getId();\n\n const match = extName.match(/^Entity(.*)Content$/);\n const infix = match?.[1] ?? extName;\n\n let name: string | undefined = infix;\n if (\n pluginId &&\n name\n .toLocaleLowerCase('en-US')\n .startsWith(pluginId.toLocaleLowerCase('en-US'))\n ) {\n name = name.slice(pluginId.length);\n if (!name) {\n name = undefined;\n }\n }\n name = name && kebabCase(name);\n\n return EntityContentBlueprint.make({\n name: overrides?.name ?? name,\n params: {\n filter: overrides?.filter,\n defaultPath: overrides?.defaultPath ?? `/${kebabCase(infix)}`,\n defaultTitle: overrides?.defaultTitle ?? startCase(infix),\n routeRef: mountPoint && convertLegacyRouteRef(mountPoint),\n loader: async () => compatWrapper(element),\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAkCgB,SAAA,mCAAA,CACd,iBACA,SAMqB,EAAA;AACrB,EAAM,MAAA,OAAA,uCAAW,eAAgB,EAAA,IAAA,CAAA;AAEjC,EAAM,MAAA,OAAA,GAAU,gBAAyB,CAAA,OAAA,EAAS,oBAAoB,CAAA;AACtE,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAM,MAAA,IAAI,MAAM,uBAAuB,CAAA;AAAA;AAGzC,EAAA,MAAM,UAAa,GAAA,gBAAA;AAAA,IACjB,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAM,MAAA,MAAA,GAAS,gBAAkC,CAAA,OAAA,EAAS,aAAa,CAAA;AACvE,EAAM,MAAA,QAAA,GAAW,QAAQ,KAAM,EAAA;AAE/B,EAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,qBAAqB,CAAA;AACjD,EAAM,MAAA,KAAA,GAAQ,KAAQ,GAAA,CAAC,CAAK,IAAA,OAAA;AAE5B,EAAA,IAAI,IAA2B,GAAA,KAAA;AAC/B,EACE,IAAA,QAAA,IACA,IACG,CAAA,iBAAA,CAAkB,OAAO,CAAA,CACzB,WAAW,QAAS,CAAA,iBAAA,CAAkB,OAAO,CAAC,CACjD,EAAA;AACA,IAAO,IAAA,GAAA,IAAA,CAAK,KAAM,CAAA,QAAA,CAAS,MAAM,CAAA;AACjC,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAO,IAAA,GAAA,KAAA,CAAA;AAAA;AACT;AAEF,EAAO,IAAA,GAAA,IAAA,IAAQ,UAAU,IAAI,CAAA;AAE7B,EAAA,OAAO,uBAAuB,IAAK,CAAA;AAAA,IACjC,IAAA,EAAM,WAAW,IAAQ,IAAA,IAAA;AAAA,IACzB,MAAQ,EAAA;AAAA,MACN,QAAQ,SAAW,EAAA,MAAA;AAAA,MACnB,aAAa,SAAW,EAAA,WAAA,IAAe,CAAI,CAAA,EAAA,SAAA,CAAU,KAAK,CAAC,CAAA,CAAA;AAAA,MAC3D,YAAc,EAAA,SAAA,EAAW,YAAgB,IAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACxD,QAAA,EAAU,UAAc,IAAA,qBAAA,CAAsB,UAAU,CAAA;AAAA,MACxD,MAAA,EAAQ,YAAY,aAAA,CAAc,OAAO;AAAA;AAC3C,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,27 @@
1
+ function createEntityPredicateSchema(z) {
2
+ const primitiveSchema = z.union([z.string(), z.number(), z.boolean()]);
3
+ const comparableValueSchema = z.union([
4
+ primitiveSchema,
5
+ z.array(primitiveSchema)
6
+ ]);
7
+ let valuePredicateSchema;
8
+ const predicateSchema = z.lazy(
9
+ () => z.union([
10
+ comparableValueSchema,
11
+ z.object({ $all: z.array(predicateSchema) }),
12
+ z.object({ $any: z.array(predicateSchema) }),
13
+ z.object({ $not: predicateSchema }),
14
+ z.record(z.string().regex(/^(?!\$).*$/), valuePredicateSchema)
15
+ ])
16
+ );
17
+ valuePredicateSchema = z.union([
18
+ comparableValueSchema,
19
+ z.object({ $exists: z.boolean() }),
20
+ z.object({ $in: z.array(primitiveSchema) }),
21
+ z.object({ $contains: predicateSchema })
22
+ ]);
23
+ return predicateSchema;
24
+ }
25
+
26
+ export { createEntityPredicateSchema };
27
+ //# sourceMappingURL=createEntityPredicateSchema.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createEntityPredicateSchema.esm.js","sources":["../../../src/alpha/predicates/createEntityPredicateSchema.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { EntityPredicate, EntityPredicateValue } from '.';\nimport type { z as zImpl, ZodType } from 'zod';\n\n/** @internal */\nexport function createEntityPredicateSchema(z: typeof zImpl) {\n const primitiveSchema = z.union([z.string(), z.number(), z.boolean()]);\n\n const comparableValueSchema = z.union([\n primitiveSchema,\n z.array(primitiveSchema),\n ]);\n\n // eslint-disable-next-line prefer-const\n let valuePredicateSchema: ZodType<EntityPredicateValue>;\n\n const predicateSchema = z.lazy(() =>\n z.union([\n comparableValueSchema,\n z.object({ $all: z.array(predicateSchema) }),\n z.object({ $any: z.array(predicateSchema) }),\n z.object({ $not: predicateSchema }),\n z.record(z.string().regex(/^(?!\\$).*$/), valuePredicateSchema),\n ]),\n ) as ZodType<EntityPredicate>;\n\n valuePredicateSchema = z.union([\n comparableValueSchema,\n z.object({ $exists: z.boolean() }),\n z.object({ $in: z.array(primitiveSchema) }),\n z.object({ $contains: predicateSchema }),\n ]) as ZodType<EntityPredicateValue>;\n\n return predicateSchema;\n}\n"],"names":[],"mappings":"AAoBO,SAAS,4BAA4B,CAAiB,EAAA;AAC3D,EAAA,MAAM,eAAkB,GAAA,CAAA,CAAE,KAAM,CAAA,CAAC,CAAE,CAAA,MAAA,EAAU,EAAA,CAAA,CAAE,MAAO,EAAA,EAAG,CAAE,CAAA,OAAA,EAAS,CAAC,CAAA;AAErE,EAAM,MAAA,qBAAA,GAAwB,EAAE,KAAM,CAAA;AAAA,IACpC,eAAA;AAAA,IACA,CAAA,CAAE,MAAM,eAAe;AAAA,GACxB,CAAA;AAGD,EAAI,IAAA,oBAAA;AAEJ,EAAA,MAAM,kBAAkB,CAAE,CAAA,IAAA;AAAA,IAAK,MAC7B,EAAE,KAAM,CAAA;AAAA,MACN,qBAAA;AAAA,MACA,CAAA,CAAE,OAAO,EAAE,IAAA,EAAM,EAAE,KAAM,CAAA,eAAe,GAAG,CAAA;AAAA,MAC3C,CAAA,CAAE,OAAO,EAAE,IAAA,EAAM,EAAE,KAAM,CAAA,eAAe,GAAG,CAAA;AAAA,MAC3C,CAAE,CAAA,MAAA,CAAO,EAAE,IAAA,EAAM,iBAAiB,CAAA;AAAA,MAClC,CAAA,CAAE,OAAO,CAAE,CAAA,MAAA,GAAS,KAAM,CAAA,YAAY,GAAG,oBAAoB;AAAA,KAC9D;AAAA,GACH;AAEA,EAAA,oBAAA,GAAuB,EAAE,KAAM,CAAA;AAAA,IAC7B,qBAAA;AAAA,IACA,EAAE,MAAO,CAAA,EAAE,SAAS,CAAE,CAAA,OAAA,IAAW,CAAA;AAAA,IACjC,CAAA,CAAE,OAAO,EAAE,GAAA,EAAK,EAAE,KAAM,CAAA,eAAe,GAAG,CAAA;AAAA,IAC1C,CAAE,CAAA,MAAA,CAAO,EAAE,SAAA,EAAW,iBAAiB;AAAA,GACxC,CAAA;AAED,EAAO,OAAA,eAAA;AACT;;;;"}
@@ -0,0 +1,73 @@
1
+ import { valueAtPath } from './valueAtPath.esm.js';
2
+
3
+ function entityPredicateToFilterFunction(entityPredicate) {
4
+ return (value) => evaluateEntityPredicate(entityPredicate, value);
5
+ }
6
+ function evaluateEntityPredicate(filter, value) {
7
+ if (typeof filter !== "object" || filter === null || Array.isArray(filter)) {
8
+ return valuesAreEqual(value, filter);
9
+ }
10
+ if ("$all" in filter) {
11
+ return filter.$all.every((f) => evaluateEntityPredicate(f, value));
12
+ }
13
+ if ("$any" in filter) {
14
+ return filter.$any.some((f) => evaluateEntityPredicate(f, value));
15
+ }
16
+ if ("$not" in filter) {
17
+ return !evaluateEntityPredicate(filter.$not, value);
18
+ }
19
+ for (const filterKey in filter) {
20
+ if (!Object.hasOwn(filter, filterKey)) {
21
+ continue;
22
+ }
23
+ if (filterKey.startsWith("$")) {
24
+ return false;
25
+ }
26
+ if (!evaluatePredicateValue(filter[filterKey], valueAtPath(value, filterKey))) {
27
+ return false;
28
+ }
29
+ }
30
+ return true;
31
+ }
32
+ function evaluatePredicateValue(filter, value) {
33
+ if (typeof filter !== "object" || filter === null || Array.isArray(filter)) {
34
+ return valuesAreEqual(value, filter);
35
+ }
36
+ if ("$contains" in filter) {
37
+ if (!Array.isArray(value)) {
38
+ return false;
39
+ }
40
+ return value.some((v) => evaluateEntityPredicate(filter.$contains, v));
41
+ }
42
+ if ("$in" in filter) {
43
+ return filter.$in.includes(value);
44
+ }
45
+ if ("$exists" in filter) {
46
+ if (filter.$exists === true) {
47
+ return value !== void 0;
48
+ }
49
+ return value === void 0;
50
+ }
51
+ return false;
52
+ }
53
+ function valuesAreEqual(a, b) {
54
+ if (a === null || b === null) {
55
+ return false;
56
+ }
57
+ if (a === b) {
58
+ return true;
59
+ }
60
+ if (typeof a === "string" && typeof b === "string") {
61
+ return a.toLocaleUpperCase("en-US") === b.toLocaleUpperCase("en-US");
62
+ }
63
+ if (typeof a === "number" || typeof b === "number") {
64
+ return String(a) === String(b);
65
+ }
66
+ if (Array.isArray(a) && Array.isArray(b)) {
67
+ return a.length === b.length && a.every((v, i) => valuesAreEqual(v, b[i]));
68
+ }
69
+ return false;
70
+ }
71
+
72
+ export { entityPredicateToFilterFunction };
73
+ //# sourceMappingURL=entityPredicateToFilterFunction.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityPredicateToFilterFunction.esm.js","sources":["../../../src/alpha/predicates/entityPredicateToFilterFunction.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { JsonValue } from '@backstage/types';\nimport {\n EntityPredicate,\n EntityPredicatePrimitive,\n EntityPredicateValue,\n} from './types';\nimport { valueAtPath } from './valueAtPath';\n\n/**\n * Convert an entity predicate to a filter function that can be used to filter entities.\n * @alpha\n */\nexport function entityPredicateToFilterFunction<T extends JsonValue>(\n entityPredicate: EntityPredicate,\n): (value: T) => boolean {\n return value => evaluateEntityPredicate(entityPredicate, value);\n}\n\n/**\n * Evaluate a entity predicate against a value, typically an entity.\n *\n * @internal\n */\nfunction evaluateEntityPredicate(\n filter: EntityPredicate,\n value: JsonValue,\n): boolean {\n if (typeof filter !== 'object' || filter === null || Array.isArray(filter)) {\n return valuesAreEqual(value, filter);\n }\n\n if ('$all' in filter) {\n return filter.$all.every(f => evaluateEntityPredicate(f, value));\n }\n if ('$any' in filter) {\n return filter.$any.some(f => evaluateEntityPredicate(f, value));\n }\n if ('$not' in filter) {\n return !evaluateEntityPredicate(filter.$not, value);\n }\n\n for (const filterKey in filter) {\n if (!Object.hasOwn(filter, filterKey)) {\n continue;\n }\n if (filterKey.startsWith('$')) {\n return false;\n }\n if (\n !evaluatePredicateValue(filter[filterKey], valueAtPath(value, filterKey))\n ) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Evaluate a single value against a predicate value.\n *\n * @internal\n */\nfunction evaluatePredicateValue(\n filter: EntityPredicateValue,\n value: JsonValue | undefined,\n): boolean {\n if (typeof filter !== 'object' || filter === null || Array.isArray(filter)) {\n return valuesAreEqual(value, filter);\n }\n\n if ('$contains' in filter) {\n if (!Array.isArray(value)) {\n return false;\n }\n return value.some(v => evaluateEntityPredicate(filter.$contains, v));\n }\n if ('$in' in filter) {\n return filter.$in.includes(value as EntityPredicatePrimitive);\n }\n if ('$exists' in filter) {\n if (filter.$exists === true) {\n return value !== undefined;\n }\n return value === undefined;\n }\n\n return false;\n}\n\nfunction valuesAreEqual(\n a: JsonValue | undefined,\n b: JsonValue | undefined,\n): boolean {\n if (a === null || b === null) {\n return false;\n }\n if (a === b) {\n return true;\n }\n if (typeof a === 'string' && typeof b === 'string') {\n return a.toLocaleUpperCase('en-US') === b.toLocaleUpperCase('en-US');\n }\n if (typeof a === 'number' || typeof b === 'number') {\n return String(a) === String(b);\n }\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => valuesAreEqual(v, b[i]));\n }\n return false;\n}\n"],"names":[],"mappings":";;AA4BO,SAAS,gCACd,eACuB,EAAA;AACvB,EAAO,OAAA,CAAA,KAAA,KAAS,uBAAwB,CAAA,eAAA,EAAiB,KAAK,CAAA;AAChE;AAOA,SAAS,uBAAA,CACP,QACA,KACS,EAAA;AACT,EAAI,IAAA,OAAO,WAAW,QAAY,IAAA,MAAA,KAAW,QAAQ,KAAM,CAAA,OAAA,CAAQ,MAAM,CAAG,EAAA;AAC1E,IAAO,OAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA;AAGrC,EAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,IAAA,OAAO,OAAO,IAAK,CAAA,KAAA,CAAM,OAAK,uBAAwB,CAAA,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA;AAEjE,EAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,IAAA,OAAO,OAAO,IAAK,CAAA,IAAA,CAAK,OAAK,uBAAwB,CAAA,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA;AAEhE,EAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,IAAA,OAAO,CAAC,uBAAA,CAAwB,MAAO,CAAA,IAAA,EAAM,KAAK,CAAA;AAAA;AAGpD,EAAA,KAAA,MAAW,aAAa,MAAQ,EAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,CAAO,MAAO,CAAA,MAAA,EAAQ,SAAS,CAAG,EAAA;AACrC,MAAA;AAAA;AAEF,IAAI,IAAA,SAAA,CAAU,UAAW,CAAA,GAAG,CAAG,EAAA;AAC7B,MAAO,OAAA,KAAA;AAAA;AAET,IACE,IAAA,CAAC,uBAAuB,MAAO,CAAA,SAAS,GAAG,WAAY,CAAA,KAAA,EAAO,SAAS,CAAC,CACxE,EAAA;AACA,MAAO,OAAA,KAAA;AAAA;AACT;AAGF,EAAO,OAAA,IAAA;AACT;AAOA,SAAS,sBAAA,CACP,QACA,KACS,EAAA;AACT,EAAI,IAAA,OAAO,WAAW,QAAY,IAAA,MAAA,KAAW,QAAQ,KAAM,CAAA,OAAA,CAAQ,MAAM,CAAG,EAAA;AAC1E,IAAO,OAAA,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA;AAGrC,EAAA,IAAI,eAAe,MAAQ,EAAA;AACzB,IAAA,IAAI,CAAC,KAAA,CAAM,OAAQ,CAAA,KAAK,CAAG,EAAA;AACzB,MAAO,OAAA,KAAA;AAAA;AAET,IAAA,OAAO,MAAM,IAAK,CAAA,CAAA,CAAA,KAAK,wBAAwB,MAAO,CAAA,SAAA,EAAW,CAAC,CAAC,CAAA;AAAA;AAErE,EAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,IAAO,OAAA,MAAA,CAAO,GAAI,CAAA,QAAA,CAAS,KAAiC,CAAA;AAAA;AAE9D,EAAA,IAAI,aAAa,MAAQ,EAAA;AACvB,IAAI,IAAA,MAAA,CAAO,YAAY,IAAM,EAAA;AAC3B,MAAA,OAAO,KAAU,KAAA,KAAA,CAAA;AAAA;AAEnB,IAAA,OAAO,KAAU,KAAA,KAAA,CAAA;AAAA;AAGnB,EAAO,OAAA,KAAA;AACT;AAEA,SAAS,cAAA,CACP,GACA,CACS,EAAA;AACT,EAAI,IAAA,CAAA,KAAM,IAAQ,IAAA,CAAA,KAAM,IAAM,EAAA;AAC5B,IAAO,OAAA,KAAA;AAAA;AAET,EAAA,IAAI,MAAM,CAAG,EAAA;AACX,IAAO,OAAA,IAAA;AAAA;AAET,EAAA,IAAI,OAAO,CAAA,KAAM,QAAY,IAAA,OAAO,MAAM,QAAU,EAAA;AAClD,IAAA,OAAO,EAAE,iBAAkB,CAAA,OAAO,CAAM,KAAA,CAAA,CAAE,kBAAkB,OAAO,CAAA;AAAA;AAErE,EAAA,IAAI,OAAO,CAAA,KAAM,QAAY,IAAA,OAAO,MAAM,QAAU,EAAA;AAClD,IAAA,OAAO,MAAO,CAAA,CAAC,CAAM,KAAA,MAAA,CAAO,CAAC,CAAA;AAAA;AAE/B,EAAA,IAAI,MAAM,OAAQ,CAAA,CAAC,KAAK,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAG,EAAA;AACxC,IAAA,OAAO,CAAE,CAAA,MAAA,KAAW,CAAE,CAAA,MAAA,IAAU,EAAE,KAAM,CAAA,CAAC,CAAG,EAAA,CAAA,KAAM,cAAe,CAAA,CAAA,EAAG,CAAE,CAAA,CAAC,CAAC,CAAC,CAAA;AAAA;AAE3E,EAAO,OAAA,KAAA;AACT;;;;"}
@@ -0,0 +1,31 @@
1
+ function valueAtPath(value, path) {
2
+ if (!path) {
3
+ return void 0;
4
+ }
5
+ if (value === void 0 || value === null || typeof value !== "object" || Array.isArray(value)) {
6
+ return void 0;
7
+ }
8
+ for (const valueKey in value) {
9
+ if (!Object.hasOwn(value, valueKey)) {
10
+ continue;
11
+ }
12
+ if (valueKey === path) {
13
+ if (value[valueKey] !== void 0) {
14
+ return value[valueKey];
15
+ }
16
+ }
17
+ if (path.startsWith(`${valueKey}.`)) {
18
+ const found = valueAtPath(
19
+ value[valueKey],
20
+ path.slice(valueKey.length + 1)
21
+ );
22
+ if (found !== void 0) {
23
+ return found;
24
+ }
25
+ }
26
+ }
27
+ return void 0;
28
+ }
29
+
30
+ export { valueAtPath };
31
+ //# sourceMappingURL=valueAtPath.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valueAtPath.esm.js","sources":["../../../src/alpha/predicates/valueAtPath.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { JsonValue } from '@backstage/types';\n\n/**\n * Looks up a value by path in a nested object structure.\n *\n * @remarks\n *\n * The path should be a dot-separated string of keys to traverse. The traversal\n * will tolerate object keys containing dots, and will keep searching until a\n * value has been found or all matching keys have been traversed.\n *\n * This lookup does not traverse into arrays, returning `undefined` instead.\n *\n * @internal\n */\nexport function valueAtPath(\n value: JsonValue | undefined,\n path: string,\n): JsonValue | undefined {\n if (!path) {\n return undefined;\n }\n if (\n value === undefined ||\n value === null ||\n typeof value !== 'object' ||\n Array.isArray(value)\n ) {\n return undefined;\n }\n\n for (const valueKey in value) {\n if (!Object.hasOwn(value, valueKey)) {\n continue;\n }\n if (valueKey === path) {\n if (value[valueKey] !== undefined) {\n return value[valueKey];\n }\n }\n if (path.startsWith(`${valueKey}.`)) {\n const found = valueAtPath(\n value[valueKey],\n path.slice(valueKey.length + 1),\n );\n if (found !== undefined) {\n return found;\n }\n }\n }\n\n return undefined;\n}\n"],"names":[],"mappings":"AA+BgB,SAAA,WAAA,CACd,OACA,IACuB,EAAA;AACvB,EAAA,IAAI,CAAC,IAAM,EAAA;AACT,IAAO,OAAA,KAAA,CAAA;AAAA;AAET,EACE,IAAA,KAAA,KAAU,KACV,CAAA,IAAA,KAAA,KAAU,IACV,IAAA,OAAO,UAAU,QACjB,IAAA,KAAA,CAAM,OAAQ,CAAA,KAAK,CACnB,EAAA;AACA,IAAO,OAAA,KAAA,CAAA;AAAA;AAGT,EAAA,KAAA,MAAW,YAAY,KAAO,EAAA;AAC5B,IAAA,IAAI,CAAC,MAAA,CAAO,MAAO,CAAA,KAAA,EAAO,QAAQ,CAAG,EAAA;AACnC,MAAA;AAAA;AAEF,IAAA,IAAI,aAAa,IAAM,EAAA;AACrB,MAAI,IAAA,KAAA,CAAM,QAAQ,CAAA,KAAM,KAAW,CAAA,EAAA;AACjC,QAAA,OAAO,MAAM,QAAQ,CAAA;AAAA;AACvB;AAEF,IAAA,IAAI,IAAK,CAAA,UAAA,CAAW,CAAG,EAAA,QAAQ,GAAG,CAAG,EAAA;AACnC,MAAA,MAAM,KAAQ,GAAA,WAAA;AAAA,QACZ,MAAM,QAAQ,CAAA;AAAA,QACd,IAAK,CAAA,KAAA,CAAM,QAAS,CAAA,MAAA,GAAS,CAAC;AAAA,OAChC;AACA,MAAA,IAAI,UAAU,KAAW,CAAA,EAAA;AACvB,QAAO,OAAA,KAAA;AAAA;AACT;AACF;AAGF,EAAO,OAAA,KAAA,CAAA;AACT;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,10 +1,9 @@
1
- /// <reference types="react" />
2
1
  import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
3
2
  import { RouteRef, ExtensionDefinition } from '@backstage/frontend-plugin-api';
4
3
  import * as React from 'react';
5
4
  import React__default, { ComponentType } from 'react';
6
- import * as _backstage_catalog_model from '@backstage/catalog-model';
7
5
  import { Entity } from '@backstage/catalog-model';
6
+ import { JsonValue } from '@backstage/types';
8
7
  import * as _backstage_core_plugin_api_alpha from '@backstage/core-plugin-api/alpha';
9
8
  import { ResourcePermission } from '@backstage/plugin-permission-common';
10
9
 
@@ -30,7 +29,38 @@ declare const defaultEntityContentGroups: {
30
29
  observability: string;
31
30
  };
32
31
  /** @alpha */
33
- type EntityCardType = 'peek' | 'info' | 'full';
32
+ type EntityCardType = 'summary' | 'info' | 'content';
33
+
34
+ /** @alpha */
35
+ type EntityPredicate = EntityPredicateExpression | EntityPredicatePrimitive | {
36
+ $all: EntityPredicate[];
37
+ } | {
38
+ $any: EntityPredicate[];
39
+ } | {
40
+ $not: EntityPredicate;
41
+ };
42
+ /** @alpha */
43
+ type EntityPredicateExpression = {
44
+ [KPath in string]: EntityPredicateValue;
45
+ } & {
46
+ [KPath in `$${string}`]: never;
47
+ };
48
+ /** @alpha */
49
+ type EntityPredicateValue = EntityPredicatePrimitive | {
50
+ $exists: boolean;
51
+ } | {
52
+ $in: EntityPredicatePrimitive[];
53
+ } | {
54
+ $contains: EntityPredicateExpression;
55
+ };
56
+ /** @alpha */
57
+ type EntityPredicatePrimitive = string | number | boolean;
58
+
59
+ /**
60
+ * Convert an entity predicate to a filter function that can be used to filter entities.
61
+ * @alpha
62
+ */
63
+ declare function entityPredicateToFilterFunction<T extends JsonValue>(entityPredicate: EntityPredicate): (value: T) => boolean;
34
64
 
35
65
  /**
36
66
  * @alpha
@@ -41,10 +71,10 @@ declare const EntityCardBlueprint: _backstage_frontend_plugin_api.ExtensionBluep
41
71
  name: undefined;
42
72
  params: {
43
73
  loader: () => Promise<JSX.Element>;
44
- filter?: string | ((entity: _backstage_catalog_model.Entity) => boolean) | undefined;
45
- type?: EntityCardType | undefined;
74
+ filter?: string | EntityPredicate | ((entity: Entity) => boolean);
75
+ type?: EntityCardType;
46
76
  };
47
- output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
77
+ output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {
48
78
  optional: true;
49
79
  }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {
50
80
  optional: true;
@@ -53,15 +83,15 @@ declare const EntityCardBlueprint: _backstage_frontend_plugin_api.ExtensionBluep
53
83
  }>;
54
84
  inputs: {};
55
85
  config: {
56
- filter: string | undefined;
57
- type: "full" | "info" | "peek" | undefined;
86
+ filter: EntityPredicate | undefined;
87
+ type: "content" | "summary" | "info" | undefined;
58
88
  };
59
89
  configInput: {
60
- filter?: string | undefined;
61
- type?: "full" | "info" | "peek" | undefined;
90
+ filter?: EntityPredicate | undefined;
91
+ type?: "content" | "summary" | "info" | undefined;
62
92
  };
63
93
  dataRefs: {
64
- filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {}>;
94
+ filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {}>;
65
95
  filterExpression: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {}>;
66
96
  type: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<EntityCardType, "catalog.entity-card-type", {}>;
67
97
  };
@@ -78,13 +108,13 @@ declare const EntityContentBlueprint: _backstage_frontend_plugin_api.ExtensionBl
78
108
  loader: () => Promise<JSX.Element>;
79
109
  defaultPath: string;
80
110
  defaultTitle: string;
81
- defaultGroup?: (string & {}) | "documentation" | "development" | "deployment" | "observability" | undefined;
82
- routeRef?: RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams> | undefined;
83
- filter?: string | ((entity: _backstage_catalog_model.Entity) => boolean) | undefined;
111
+ defaultGroup?: keyof typeof defaultEntityContentGroups | (string & {});
112
+ routeRef?: RouteRef;
113
+ filter?: string | EntityPredicate | ((entity: Entity) => boolean);
84
114
  };
85
115
  output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
86
116
  optional: true;
87
- }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-content-title", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
117
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-content-title", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {
88
118
  optional: true;
89
119
  }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {
90
120
  optional: true;
@@ -95,18 +125,18 @@ declare const EntityContentBlueprint: _backstage_frontend_plugin_api.ExtensionBl
95
125
  config: {
96
126
  path: string | undefined;
97
127
  title: string | undefined;
98
- filter: string | undefined;
128
+ filter: EntityPredicate | undefined;
99
129
  group: string | false | undefined;
100
130
  };
101
131
  configInput: {
102
- filter?: string | undefined;
132
+ filter?: EntityPredicate | undefined;
103
133
  title?: string | undefined;
104
134
  path?: string | undefined;
105
135
  group?: string | false | undefined;
106
136
  };
107
137
  dataRefs: {
108
138
  title: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-content-title", {}>;
109
- filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {}>;
139
+ filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {}>;
110
140
  filterExpression: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {}>;
111
141
  group: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-content-group", {}>;
112
142
  };
@@ -124,10 +154,10 @@ declare const EntityContentLayoutBlueprint: _backstage_frontend_plugin_api.Exten
124
154
  kind: "entity-content-layout";
125
155
  name: undefined;
126
156
  params: {
127
- filter?: string | ((entity: _backstage_catalog_model.Entity) => boolean) | undefined;
157
+ filter?: string | EntityPredicate | ((entity: Entity) => boolean);
128
158
  loader: () => Promise<(props: EntityContentLayoutProps) => React__default.JSX.Element>;
129
159
  };
130
- output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
160
+ output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {
131
161
  optional: true;
132
162
  }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {
133
163
  optional: true;
@@ -135,29 +165,47 @@ declare const EntityContentLayoutBlueprint: _backstage_frontend_plugin_api.Exten
135
165
  inputs: {};
136
166
  config: {
137
167
  type: string | undefined;
138
- filter: string | undefined;
168
+ filter: EntityPredicate | undefined;
139
169
  };
140
170
  configInput: {
141
- filter?: string | undefined;
171
+ filter?: EntityPredicate | undefined;
142
172
  type?: string | undefined;
143
173
  };
144
174
  dataRefs: {
145
- filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {}>;
175
+ filterFunction: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(entity: Entity) => boolean, "catalog.entity-filter-function", {}>;
146
176
  filterExpression: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "catalog.entity-filter-expression", {}>;
147
177
  component: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<(props: EntityContentLayoutProps) => React__default.JSX.Element, "catalog.entity-content-layout.component", {}>;
148
178
  };
149
179
  }>;
150
180
 
181
+ /** @alpha */
182
+ declare const EntityHeaderBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
183
+ kind: "entity-header";
184
+ name: undefined;
185
+ params: {
186
+ loader: () => Promise<JSX.Element>;
187
+ };
188
+ output: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {
189
+ optional: true;
190
+ }>;
191
+ inputs: {};
192
+ config: {};
193
+ configInput: {};
194
+ dataRefs: {
195
+ element: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<React.JSX.Element, "core.reactElement", {}>;
196
+ };
197
+ }>;
198
+
151
199
  /** @alpha */
152
200
  declare function convertLegacyEntityCardExtension(LegacyExtension: ComponentType<{}>, overrides?: {
153
201
  name?: string;
154
- filter?: typeof EntityCardBlueprint.dataRefs.filterFunction.T | typeof EntityCardBlueprint.dataRefs.filterExpression.T;
202
+ filter?: string | EntityPredicate | ((entity: Entity) => boolean);
155
203
  }): ExtensionDefinition;
156
204
 
157
205
  /** @alpha */
158
206
  declare function convertLegacyEntityContentExtension(LegacyExtension: ComponentType<{}>, overrides?: {
159
207
  name?: string;
160
- filter?: typeof EntityContentBlueprint.dataRefs.filterFunction.T | typeof EntityContentBlueprint.dataRefs.filterExpression.T;
208
+ filter?: string | EntityPredicate | ((entity: Entity) => boolean);
161
209
  defaultPath?: string;
162
210
  defaultTitle?: string;
163
211
  }): ExtensionDefinition;
@@ -234,4 +282,4 @@ declare function useEntityPermission(permission: ResourcePermission<'catalog-ent
234
282
  error?: Error;
235
283
  };
236
284
 
237
- export { EntityCardBlueprint, type EntityCardType, EntityContentBlueprint, EntityContentLayoutBlueprint, type EntityContentLayoutProps, catalogReactTranslationRef, convertLegacyEntityCardExtension, convertLegacyEntityContentExtension, defaultEntityContentGroups, isOwnerOf, useEntityPermission };
285
+ export { EntityCardBlueprint, type EntityCardType, EntityContentBlueprint, EntityContentLayoutBlueprint, type EntityContentLayoutProps, EntityHeaderBlueprint, type EntityPredicate, type EntityPredicateExpression, type EntityPredicatePrimitive, type EntityPredicateValue, catalogReactTranslationRef, convertLegacyEntityCardExtension, convertLegacyEntityContentExtension, defaultEntityContentGroups, entityPredicateToFilterFunction, isOwnerOf, useEntityPermission };
package/dist/alpha.esm.js CHANGED
@@ -1,9 +1,11 @@
1
1
  export { EntityCardBlueprint } from './alpha/blueprints/EntityCardBlueprint.esm.js';
2
2
  export { EntityContentBlueprint } from './alpha/blueprints/EntityContentBlueprint.esm.js';
3
3
  export { EntityContentLayoutBlueprint } from './alpha/blueprints/EntityContentLayoutBlueprint.esm.js';
4
+ export { EntityHeaderBlueprint } from './alpha/blueprints/EntityHeaderBlueprint.esm.js';
4
5
  export { defaultEntityContentGroups } from './alpha/blueprints/extensionData.esm.js';
5
6
  export { convertLegacyEntityCardExtension } from './alpha/converters/convertLegacyEntityCardExtension.esm.js';
6
7
  export { convertLegacyEntityContentExtension } from './alpha/converters/convertLegacyEntityContentExtension.esm.js';
8
+ export { entityPredicateToFilterFunction } from './alpha/predicates/entityPredicateToFilterFunction.esm.js';
7
9
  export { catalogReactTranslationRef } from './translation.esm.js';
8
10
  export { isOwnerOf } from './utils/isOwnerOf.esm.js';
9
11
  export { useEntityPermission } from './hooks/useEntityPermission.esm.js';
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
1
+ {"version":3,"file":"alpha.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { CatalogApi } from '@backstage/catalog-client';
3
2
  export { CATALOG_FILTER_EXISTS, CatalogApi } from '@backstage/catalog-client';
4
3
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
@@ -223,8 +222,8 @@ declare const CatalogFilterLayout: {
223
222
  Filters: (props: {
224
223
  children: React__default.ReactNode;
225
224
  options?: {
226
- drawerBreakpoint?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number;
227
- drawerAnchor?: 'left' | 'right' | 'top' | 'bottom';
225
+ drawerBreakpoint?: "xs" | "sm" | "md" | "lg" | "xl" | number;
226
+ drawerAnchor?: "left" | "right" | "top" | "bottom";
228
227
  };
229
228
  }) => React__default.JSX.Element;
230
229
  Content: (props: {
@@ -443,23 +442,23 @@ interface EntityTableProps<T extends Entity> {
443
442
  declare const EntityTable: {
444
443
  <T extends Entity>(props: EntityTableProps<T>): React__default.JSX.Element;
445
444
  columns: Readonly<{
446
- createEntityRefColumn<T_1 extends Entity>(options: {
447
- defaultKind?: string | undefined;
448
- }): TableColumn<T_1>;
449
- createEntityRelationColumn<T_2 extends Entity>(options: {
445
+ createEntityRefColumn<T extends Entity>(options: {
446
+ defaultKind?: string;
447
+ }): TableColumn<T>;
448
+ createEntityRelationColumn<T extends Entity>(options: {
450
449
  title: string;
451
450
  relation: string;
452
- defaultKind?: string | undefined;
451
+ defaultKind?: string;
453
452
  filter?: {
454
453
  kind: string;
455
- } | undefined;
456
- }): TableColumn<T_2>;
457
- createOwnerColumn<T_3 extends Entity>(): TableColumn<T_3>;
458
- createDomainColumn<T_4 extends Entity>(): TableColumn<T_4>;
459
- createSystemColumn<T_5 extends Entity>(): TableColumn<T_5>;
460
- createMetadataDescriptionColumn<T_6 extends Entity>(): TableColumn<T_6>;
461
- createSpecLifecycleColumn<T_7 extends Entity>(): TableColumn<T_7>;
462
- createSpecTypeColumn<T_8 extends Entity>(): TableColumn<T_8>;
454
+ };
455
+ }): TableColumn<T>;
456
+ createOwnerColumn<T extends Entity>(): TableColumn<T>;
457
+ createDomainColumn<T extends Entity>(): TableColumn<T>;
458
+ createSystemColumn<T extends Entity>(): TableColumn<T>;
459
+ createMetadataDescriptionColumn<T extends Entity>(): TableColumn<T>;
460
+ createSpecLifecycleColumn<T extends Entity>(): TableColumn<T>;
461
+ createSpecTypeColumn<T extends Entity>(): TableColumn<T>;
463
462
  }>;
464
463
  systemEntityColumns: TableColumn<_backstage_catalog_model.SystemEntity>[];
465
464
  componentEntityColumns: TableColumn<_backstage_catalog_model.ComponentEntity>[];
@@ -470,20 +469,20 @@ declare const columnFactories: Readonly<{
470
469
  createEntityRefColumn<T extends Entity>(options: {
471
470
  defaultKind?: string;
472
471
  }): TableColumn<T>;
473
- createEntityRelationColumn<T_1 extends Entity>(options: {
472
+ createEntityRelationColumn<T extends Entity>(options: {
474
473
  title: string;
475
474
  relation: string;
476
475
  defaultKind?: string;
477
476
  filter?: {
478
477
  kind: string;
479
478
  };
480
- }): TableColumn<T_1>;
481
- createOwnerColumn<T_2 extends Entity>(): TableColumn<T_2>;
482
- createDomainColumn<T_3 extends Entity>(): TableColumn<T_3>;
483
- createSystemColumn<T_4 extends Entity>(): TableColumn<T_4>;
484
- createMetadataDescriptionColumn<T_5 extends Entity>(): TableColumn<T_5>;
485
- createSpecLifecycleColumn<T_6 extends Entity>(): TableColumn<T_6>;
486
- createSpecTypeColumn<T_7 extends Entity>(): TableColumn<T_7>;
479
+ }): TableColumn<T>;
480
+ createOwnerColumn<T extends Entity>(): TableColumn<T>;
481
+ createDomainColumn<T extends Entity>(): TableColumn<T>;
482
+ createSystemColumn<T extends Entity>(): TableColumn<T>;
483
+ createMetadataDescriptionColumn<T extends Entity>(): TableColumn<T>;
484
+ createSpecLifecycleColumn<T extends Entity>(): TableColumn<T>;
485
+ createSpecTypeColumn<T extends Entity>(): TableColumn<T>;
487
486
  }>;
488
487
 
489
488
  /** @public */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.16.0-next.1",
3
+ "version": "1.16.0",
4
4
  "description": "A frontend library that helps other Backstage plugins interact with the catalog",
5
5
  "backstage": {
6
6
  "role": "web-library",
@@ -49,7 +49,7 @@
49
49
  "types": "./dist/index.d.ts",
50
50
  "typesVersions": {
51
51
  "*": {
52
- "index": [
52
+ "*": [
53
53
  "dist/index.d.ts"
54
54
  ],
55
55
  "alpha": [
@@ -73,20 +73,20 @@
73
73
  "test": "backstage-cli package test"
74
74
  },
75
75
  "dependencies": {
76
- "@backstage/catalog-client": "1.9.1",
77
- "@backstage/catalog-model": "1.7.3",
78
- "@backstage/core-compat-api": "0.3.7-next.1",
79
- "@backstage/core-components": "0.16.5-next.0",
80
- "@backstage/core-plugin-api": "1.10.4",
81
- "@backstage/errors": "1.2.7",
82
- "@backstage/frontend-plugin-api": "0.9.6-next.1",
83
- "@backstage/frontend-test-utils": "0.2.7-next.1",
84
- "@backstage/integration-react": "1.2.4",
85
- "@backstage/plugin-catalog-common": "1.1.3",
86
- "@backstage/plugin-permission-common": "0.8.4",
87
- "@backstage/plugin-permission-react": "0.4.31",
88
- "@backstage/types": "1.2.1",
89
- "@backstage/version-bridge": "1.0.11",
76
+ "@backstage/catalog-client": "^1.9.1",
77
+ "@backstage/catalog-model": "^1.7.3",
78
+ "@backstage/core-compat-api": "^0.4.0",
79
+ "@backstage/core-components": "^0.17.0",
80
+ "@backstage/core-plugin-api": "^1.10.5",
81
+ "@backstage/errors": "^1.2.7",
82
+ "@backstage/frontend-plugin-api": "^0.10.0",
83
+ "@backstage/frontend-test-utils": "^0.3.0",
84
+ "@backstage/integration-react": "^1.2.5",
85
+ "@backstage/plugin-catalog-common": "^1.1.3",
86
+ "@backstage/plugin-permission-common": "^0.8.4",
87
+ "@backstage/plugin-permission-react": "^0.4.32",
88
+ "@backstage/types": "^1.2.1",
89
+ "@backstage/version-bridge": "^1.0.11",
90
90
  "@material-ui/core": "^4.12.2",
91
91
  "@material-ui/icons": "^4.9.1",
92
92
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -100,11 +100,11 @@
100
100
  "zen-observable": "^0.10.0"
101
101
  },
102
102
  "devDependencies": {
103
- "@backstage/cli": "0.30.1-next.0",
104
- "@backstage/core-app-api": "1.15.5",
105
- "@backstage/plugin-catalog-common": "1.1.3",
106
- "@backstage/plugin-scaffolder-common": "1.5.10-next.0",
107
- "@backstage/test-utils": "1.7.5",
103
+ "@backstage/cli": "^0.31.0",
104
+ "@backstage/core-app-api": "^1.16.0",
105
+ "@backstage/plugin-catalog-common": "^1.1.3",
106
+ "@backstage/plugin-scaffolder-common": "^1.5.10",
107
+ "@backstage/test-utils": "^1.7.6",
108
108
  "@testing-library/dom": "^10.0.0",
109
109
  "@testing-library/jest-dom": "^6.0.0",
110
110
  "@testing-library/react": "^16.0.0",
@@ -114,7 +114,8 @@
114
114
  "react": "^18.0.2",
115
115
  "react-dom": "^18.0.2",
116
116
  "react-router-dom": "^6.3.0",
117
- "react-test-renderer": "^16.13.1"
117
+ "react-test-renderer": "^16.13.1",
118
+ "zod": "^3.22.4"
118
119
  },
119
120
  "peerDependencies": {
120
121
  "@types/react": "^17.0.0 || ^18.0.0",