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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,68 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1e5b7d993a: Added an `EntityPresentationApi` and associated `entityPresentationApiRef`. This
8
+ API lets you control how references to entities (e.g. in links, headings,
9
+ iconography etc) are represented in the user interface.
10
+
11
+ Usage of this API is initially added to the `EntityRefLink` and `EntityRefLinks`
12
+ components, so that they can render richer, more correct representation of
13
+ entity refs. There's also a new `EntityDisplayName` component, which works just like
14
+ the `EntityRefLink` but without the link.
15
+
16
+ Along with that change, the `fetchEntities` and `getTitle` props of
17
+ `EntityRefLinksProps` are deprecated and no longer used, since the same need
18
+ instead is fulfilled (and by default always enabled) by the
19
+ `entityPresentationApiRef`.
20
+
21
+ - 1fd53fa0c6: The `UserListPicker` component has undergone improvements to enhance its performance.
22
+
23
+ The previous implementation inferred the number of owned and starred entities based on the entities available in the `EntityListContext`. The updated version no longer relies on the `EntityListContext` for inference, allowing for better decoupling.
24
+
25
+ The component now loads the entities' count asynchronously, resulting in improved performance and responsiveness. For this purpose, some of the exported filters such as `EntityTagFilter`, `EntityOwnerFilter`, `EntityLifecycleFilter` and `EntityNamespaceFilter` have now the `getCatalogFilters` method implemented.
26
+
27
+ ### Patch Changes
28
+
29
+ - 2ad1bacef7: Add EntityRef to Entity Inspector UI
30
+ - 6c2b872153: Add official support for React 18.
31
+ - 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5.
32
+ - 0bf6ebda88: Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system.
33
+ - 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`.
34
+ - 71c97e7d73: The `spec.type` field in entities will now always be rendered as a string.
35
+ - 69c14904b6: Move the `EntityRefLink` icon to the left hand side as per Material-UI guidelines
36
+ - 000dcd01af: Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`.
37
+ - 6c357184e2: Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react`
38
+ - Updated dependencies
39
+ - @backstage/core-components@0.13.8
40
+ - @backstage/frontend-plugin-api@0.3.0
41
+ - @backstage/integration-react@1.1.21
42
+ - @backstage/core-plugin-api@1.8.0
43
+ - @backstage/plugin-permission-react@0.4.17
44
+ - @backstage/version-bridge@1.0.7
45
+ - @backstage/theme@0.4.4
46
+ - @backstage/catalog-client@1.4.6
47
+ - @backstage/plugin-permission-common@0.7.10
48
+ - @backstage/catalog-model@1.4.3
49
+ - @backstage/errors@1.2.3
50
+ - @backstage/types@1.1.1
51
+ - @backstage/plugin-catalog-common@1.0.18
52
+
53
+ ## 1.9.0-next.2
54
+
55
+ ### Patch Changes
56
+
57
+ - [#20962](https://github.com/backstage/backstage/pull/20962) [`000dcd01af`](https://github.com/backstage/backstage/commit/000dcd01afaa4a06b67da20c3590a7753af4f532) Thanks [@Rugvip](https://github.com/Rugvip)! - Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`.
58
+
59
+ - [#20842](https://github.com/backstage/backstage/pull/20842) [`6c357184e2`](https://github.com/backstage/backstage/commit/6c357184e27d86796fac6005ec6a597f994aa19d) Thanks [@benjdlambert](https://github.com/benjdlambert)! - Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react`
60
+
61
+ - Updated dependencies
62
+ - @backstage/core-components@0.13.8-next.2
63
+ - @backstage/frontend-plugin-api@0.3.0-next.2
64
+ - @backstage/integration-react@1.1.21-next.1
65
+
3
66
  ## 1.9.0-next.1
4
67
 
5
68
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.9.0-next.1",
3
+ "version": "1.9.0",
4
4
  "main": "../dist/alpha.esm.js",
5
5
  "module": "../dist/alpha.esm.js",
6
6
  "types": "../dist/alpha.d.ts"
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ import { LinkProps, InfoCardVariants, TableColumn, TableOptions } from '@backsta
11
11
  import { IconButton, TextFieldProps } from '@material-ui/core';
12
12
  import { Overrides } from '@material-ui/core/styles/overrides';
13
13
  import { StyleRules } from '@material-ui/core/styles/withStyles';
14
- import { ScmIntegrationRegistry } from '@backstage/integration';
14
+ import { scmIntegrationsApiRef } from '@backstage/integration-react';
15
15
 
16
16
  /**
17
17
  * The API reference for the {@link @backstage/catalog-client#CatalogApi}.
@@ -259,8 +259,8 @@ type CatalogReactEntityDisplayNameClassKey = 'root' | 'icon';
259
259
  */
260
260
  type EntityDisplayNameProps = {
261
261
  entityRef: Entity | CompoundEntityRef | string;
262
- noIcon?: boolean;
263
- noTooltip?: boolean;
262
+ hideIcon?: boolean;
263
+ disableTooltip?: boolean;
264
264
  defaultKind?: string;
265
265
  defaultNamespace?: string;
266
266
  };
@@ -283,6 +283,7 @@ type EntityRefLinkProps = {
283
283
  /** @deprecated This option should no longer be used; presentation is requested through the {@link entityPresentationApiRef} instead */
284
284
  title?: string;
285
285
  children?: React.ReactNode;
286
+ hideIcon?: boolean;
286
287
  } & Omit<LinkProps, 'to'>;
287
288
  /**
288
289
  * Shows a clickable link to an entity.
@@ -299,6 +300,7 @@ declare const EntityRefLink: (props: EntityRefLinkProps) => JSX.Element;
299
300
  type EntityRefLinksProps<TRef extends string | CompoundEntityRef | Entity> = {
300
301
  defaultKind?: string;
301
302
  entityRefs: TRef[];
303
+ hideIcons?: boolean;
302
304
  /** @deprecated This option is no longer used; presentation is handled by entityPresentationApiRef instead */
303
305
  fetchEntities?: boolean;
304
306
  /** @deprecated This option is no longer used; presentation is handled by entityPresentationApiRef instead */
@@ -714,6 +716,17 @@ type EntityAutocompletePickerProps<T extends DefaultEntityFilters = DefaultEntit
714
716
  /** @public */
715
717
  declare function EntityAutocompletePicker<T extends DefaultEntityFilters = DefaultEntityFilters, Name extends AllowedEntityFilters<T> = AllowedEntityFilters<T>>(props: EntityAutocompletePickerProps<T, Name>): React.JSX.Element | null;
716
718
 
719
+ /** @public */
720
+ type MissingAnnotationEmptyStateClassKey = 'code';
721
+ /**
722
+ * @public
723
+ * Renders an empty state when an annotation is missing from an entity.
724
+ */
725
+ declare function MissingAnnotationEmptyState(props: {
726
+ annotation: string | string[];
727
+ readMoreUrl?: string;
728
+ }): React.JSX.Element;
729
+
717
730
  /** @public */
718
731
  type EntityLoadingStatus<TEntity extends Entity = Entity> = {
719
732
  entity?: TEntity;
@@ -886,6 +899,6 @@ type EntitySourceLocation = {
886
899
  integrationType?: string;
887
900
  };
888
901
  /** @public */
889
- declare function getEntitySourceLocation(entity: Entity, scmIntegrationsApi: ScmIntegrationRegistry): EntitySourceLocation | undefined;
902
+ declare function getEntitySourceLocation(entity: Entity, scmIntegrationsApi: typeof scmIntegrationsApiRef.T): EntitySourceLocation | undefined;
890
903
 
891
- export { AllowedEntityFilters, AsyncEntityProvider, AsyncEntityProviderProps, BackstageOverrides, CatalogFilterLayout, CatalogReactComponentsNameToClassKey, CatalogReactEntityDisplayNameClassKey, CatalogReactEntityLifecyclePickerClassKey, CatalogReactEntityNamespacePickerClassKey, CatalogReactEntityOwnerPickerClassKey, CatalogReactEntityProcessingStatusPickerClassKey, CatalogReactEntitySearchBarClassKey, CatalogReactEntityTagPickerClassKey, CatalogReactUserListPickerClassKey, DefaultEntityFilters, EntityAutocompletePicker, EntityAutocompletePickerProps, EntityDisplayName, EntityDisplayNameProps, EntityErrorFilter, EntityFilter, EntityKindFilter, EntityKindPicker, EntityKindPickerProps, EntityLifecycleFilter, EntityLifecyclePicker, EntityListContext, EntityListContextProps, EntityListProvider, EntityLoadingStatus, EntityNamespaceFilter, EntityNamespacePicker, EntityOrphanFilter, EntityOwnerFilter, EntityOwnerPicker, EntityOwnerPickerProps, EntityPeekAheadPopover, EntityPeekAheadPopoverProps, EntityPresentationApi, EntityProcessingStatusPicker, EntityProvider, EntityProviderProps, EntityRefLink, EntityRefLinkProps, EntityRefLinks, EntityRefLinksProps, EntityRefPresentation, EntityRefPresentationSnapshot, EntitySearchBar, EntitySourceLocation, EntityTable, EntityTableProps, EntityTagFilter, EntityTagPicker, EntityTagPickerProps, EntityTextFilter, EntityTypeFilter, EntityTypePicker, EntityTypePickerProps, EntityUserFilter, FavoriteEntity, FavoriteEntityProps, InspectEntityDialog, MockEntityListContextProvider, MockStarredEntitiesApi, StarredEntitiesApi, UnregisterEntityDialog, UnregisterEntityDialogProps, UserListFilter, UserListFilterKind, UserListPicker, UserListPickerProps, catalogApiRef, columnFactories, defaultEntityPresentation, entityPresentationApiRef, entityRouteParams, entityRouteRef, getEntityRelations, getEntitySourceLocation, humanizeEntityRef, starredEntitiesApiRef, useAsyncEntity, useEntity, useEntityList, useEntityOwnership, useEntityPresentation, useEntityTypeFilter, useRelatedEntities, useStarredEntities, useStarredEntity };
904
+ export { AllowedEntityFilters, AsyncEntityProvider, AsyncEntityProviderProps, BackstageOverrides, CatalogFilterLayout, CatalogReactComponentsNameToClassKey, CatalogReactEntityDisplayNameClassKey, CatalogReactEntityLifecyclePickerClassKey, CatalogReactEntityNamespacePickerClassKey, CatalogReactEntityOwnerPickerClassKey, CatalogReactEntityProcessingStatusPickerClassKey, CatalogReactEntitySearchBarClassKey, CatalogReactEntityTagPickerClassKey, CatalogReactUserListPickerClassKey, DefaultEntityFilters, EntityAutocompletePicker, EntityAutocompletePickerProps, EntityDisplayName, EntityDisplayNameProps, EntityErrorFilter, EntityFilter, EntityKindFilter, EntityKindPicker, EntityKindPickerProps, EntityLifecycleFilter, EntityLifecyclePicker, EntityListContext, EntityListContextProps, EntityListProvider, EntityLoadingStatus, EntityNamespaceFilter, EntityNamespacePicker, EntityOrphanFilter, EntityOwnerFilter, EntityOwnerPicker, EntityOwnerPickerProps, EntityPeekAheadPopover, EntityPeekAheadPopoverProps, EntityPresentationApi, EntityProcessingStatusPicker, EntityProvider, EntityProviderProps, EntityRefLink, EntityRefLinkProps, EntityRefLinks, EntityRefLinksProps, EntityRefPresentation, EntityRefPresentationSnapshot, EntitySearchBar, EntitySourceLocation, EntityTable, EntityTableProps, EntityTagFilter, EntityTagPicker, EntityTagPickerProps, EntityTextFilter, EntityTypeFilter, EntityTypePicker, EntityTypePickerProps, EntityUserFilter, FavoriteEntity, FavoriteEntityProps, InspectEntityDialog, MissingAnnotationEmptyState, MissingAnnotationEmptyStateClassKey, MockEntityListContextProvider, MockStarredEntitiesApi, StarredEntitiesApi, UnregisterEntityDialog, UnregisterEntityDialogProps, UserListFilter, UserListFilterKind, UserListPicker, UserListPickerProps, catalogApiRef, columnFactories, defaultEntityPresentation, entityPresentationApiRef, entityRouteParams, entityRouteRef, getEntityRelations, getEntitySourceLocation, humanizeEntityRef, starredEntitiesApiRef, useAsyncEntity, useEntity, useEntityList, useEntityOwnership, useEntityPresentation, useEntityTypeFilter, useRelatedEntities, useStarredEntities, useStarredEntity };
package/dist/index.esm.js CHANGED
@@ -13,10 +13,10 @@ import PersonIcon from '@material-ui/icons/Person';
13
13
  import get from 'lodash/get';
14
14
  import React, { useState, useEffect, useMemo, createContext, useCallback, useContext, useRef, memo, forwardRef, useLayoutEffect, Fragment } from 'react';
15
15
  import ObservableImpl from 'zen-observable';
16
- import { Grid, useMediaQuery, useTheme, Button, Drawer, Box, Typography, FormControlLabel, Checkbox, makeStyles, TextField, Tooltip, IconButton, Card, CardContent, Chip, CardActions, Toolbar, FormControl, Input, InputAdornment, withStyles, DialogContentText, ListItemText as ListItemText$1, ListSubheader as ListSubheader$1, ListItem, ListItemIcon, List, Dialog, DialogTitle, DialogContent, Tabs, Tab, DialogActions, Divider, MenuItem, ListItemSecondaryAction } from '@material-ui/core';
16
+ import { Grid, useMediaQuery, useTheme, Button, Drawer, Box, Typography, FormControlLabel, Checkbox, makeStyles, TextField, Tooltip, IconButton, Card, CardContent, Chip, CardActions, Toolbar, FormControl, Input, InputAdornment, withStyles, DialogContentText, ListItemText as ListItemText$1, ListSubheader as ListSubheader$1, ListItem, ListItemIcon, List, ListItemSecondaryAction, Dialog, DialogTitle, DialogContent, Tabs, Tab, DialogActions, Divider, MenuItem } from '@material-ui/core';
17
17
  import FilterListIcon from '@material-ui/icons/FilterList';
18
- import { Select, Link, ResponseErrorPanel, Progress, OverflowTooltip, Table, DependencyGraph, DependencyGraphTypes, CodeSnippet } from '@backstage/core-components';
19
- import { g as getEntityRelations } from './esm/useEntity-de64059a.esm.js';
18
+ import { Select, Link, ResponseErrorPanel, Progress, OverflowTooltip, Table, DependencyGraph, DependencyGraphTypes, CodeSnippet, CopyTextButton, EmptyState } from '@backstage/core-components';
19
+ import { g as getEntityRelations, u as useEntity } from './esm/useEntity-de64059a.esm.js';
20
20
  export { A as AsyncEntityProvider, E as EntityProvider, g as getEntityRelations, a as useAsyncEntity, u as useEntity } from './esm/useEntity-de64059a.esm.js';
21
21
  import { compact, isEqual, debounce, intersection } from 'lodash';
22
22
  import qs from 'qs';
@@ -52,6 +52,10 @@ import YAML from 'yaml';
52
52
  import Alert$1 from '@material-ui/lab/Alert';
53
53
  import { assertError } from '@backstage/errors';
54
54
  import SettingsIcon from '@material-ui/icons/Settings';
55
+ import Box$1 from '@material-ui/core/Box';
56
+ import Button$1 from '@material-ui/core/Button';
57
+ import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
58
+ import Typography$1 from '@material-ui/core/Typography';
55
59
 
56
60
  const catalogApiRef = createApiRef({
57
61
  id: "plugin.catalog.service"
@@ -958,7 +962,7 @@ const EntityAutocompletePickerOption = memo((props) => {
958
962
  );
959
963
  });
960
964
 
961
- const useStyles$g = makeStyles(
965
+ const useStyles$h = makeStyles(
962
966
  {
963
967
  input: {}
964
968
  },
@@ -967,7 +971,7 @@ const useStyles$g = makeStyles(
967
971
  }
968
972
  );
969
973
  function EntityAutocompletePickerInput(params) {
970
- const classes = useStyles$g();
974
+ const classes = useStyles$h();
971
975
  return /* @__PURE__ */ React.createElement(
972
976
  TextField,
973
977
  {
@@ -1055,7 +1059,7 @@ function EntityAutocompletePicker(props) {
1055
1059
  )));
1056
1060
  }
1057
1061
 
1058
- const useStyles$f = makeStyles(
1062
+ const useStyles$g = makeStyles(
1059
1063
  {
1060
1064
  input: {}
1061
1065
  },
@@ -1065,7 +1069,7 @@ const useStyles$f = makeStyles(
1065
1069
  );
1066
1070
  const EntityLifecyclePicker = (props) => {
1067
1071
  const { initialFilter = [] } = props;
1068
- const classes = useStyles$f();
1072
+ const classes = useStyles$g();
1069
1073
  return /* @__PURE__ */ React.createElement(
1070
1074
  EntityAutocompletePicker,
1071
1075
  {
@@ -1287,7 +1291,7 @@ function useSelectedOwners({
1287
1291
  };
1288
1292
  }
1289
1293
 
1290
- const useStyles$e = makeStyles(
1294
+ const useStyles$f = makeStyles(
1291
1295
  {
1292
1296
  input: {}
1293
1297
  },
@@ -1299,7 +1303,7 @@ const icon$1 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { f
1299
1303
  const checkedIcon$1 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
1300
1304
  const EntityOwnerPicker = (props) => {
1301
1305
  var _a, _b, _c;
1302
- const classes = useStyles$e();
1306
+ const classes = useStyles$f();
1303
1307
  const { mode = "owners-only" } = props || {};
1304
1308
  const {
1305
1309
  updateFilters,
@@ -1420,14 +1424,14 @@ const EntityOwnerPicker = (props) => {
1420
1424
  )));
1421
1425
  };
1422
1426
 
1423
- const useStyles$d = makeStyles(
1427
+ const useStyles$e = makeStyles(
1424
1428
  (theme) => ({
1425
1429
  root: {
1426
1430
  display: "inline-flex",
1427
1431
  alignItems: "center"
1428
1432
  },
1429
1433
  icon: {
1430
- marginLeft: theme.spacing(0.5),
1434
+ marginRight: theme.spacing(0.5),
1431
1435
  color: theme.palette.text.secondary,
1432
1436
  lineHeight: 0
1433
1437
  }
@@ -1435,15 +1439,15 @@ const useStyles$d = makeStyles(
1435
1439
  { name: "CatalogReactEntityDisplayName" }
1436
1440
  );
1437
1441
  const EntityDisplayName = (props) => {
1438
- const { entityRef, noIcon, noTooltip, defaultKind, defaultNamespace } = props;
1439
- const classes = useStyles$d();
1442
+ const { entityRef, hideIcon, disableTooltip, defaultKind, defaultNamespace } = props;
1443
+ const classes = useStyles$e();
1440
1444
  const { primaryTitle, secondaryTitle, Icon } = useEntityPresentation(
1441
1445
  entityRef,
1442
1446
  { defaultKind, defaultNamespace }
1443
1447
  );
1444
1448
  let content = /* @__PURE__ */ React.createElement(React.Fragment, null, primaryTitle);
1445
- content = /* @__PURE__ */ React.createElement(Box, { component: "span", className: classes.root }, content, Icon && !noIcon ? /* @__PURE__ */ React.createElement(Box, { component: "span", className: classes.icon }, /* @__PURE__ */ React.createElement(Icon, { fontSize: "inherit" })) : null);
1446
- if (secondaryTitle && !noTooltip) {
1449
+ content = /* @__PURE__ */ React.createElement(Box, { component: "span", className: classes.root }, Icon && !hideIcon ? /* @__PURE__ */ React.createElement(Box, { component: "span", className: classes.icon }, /* @__PURE__ */ React.createElement(Icon, { fontSize: "inherit" })) : null, content);
1450
+ if (secondaryTitle && !disableTooltip) {
1447
1451
  content = /* @__PURE__ */ React.createElement(Tooltip, { enterDelay: 1500, title: secondaryTitle }, content);
1448
1452
  }
1449
1453
  return content;
@@ -1474,6 +1478,7 @@ const EntityRefLink = forwardRef(
1474
1478
  defaultNamespace,
1475
1479
  title,
1476
1480
  children,
1481
+ hideIcon,
1477
1482
  ...linkProps
1478
1483
  } = props;
1479
1484
  const entityRoute = useEntityRoute(props.entityRef);
@@ -1482,7 +1487,8 @@ const EntityRefLink = forwardRef(
1482
1487
  {
1483
1488
  entityRef,
1484
1489
  defaultKind,
1485
- defaultNamespace
1490
+ defaultNamespace,
1491
+ hideIcon
1486
1492
  }
1487
1493
  );
1488
1494
  return /* @__PURE__ */ React.createElement(Link, { ...linkProps, ref, to: entityRoute }, content);
@@ -1519,10 +1525,10 @@ function useEntityRoute(entityRef) {
1519
1525
  }
1520
1526
 
1521
1527
  function EntityRefLinks(props) {
1522
- const { entityRefs, ...linkProps } = props;
1528
+ const { entityRefs, hideIcons, ...linkProps } = props;
1523
1529
  return /* @__PURE__ */ React.createElement(React.Fragment, null, entityRefs.map((r, i) => {
1524
1530
  const entityRefString = typeof r === "string" ? r : stringifyEntityRef(r);
1525
- return /* @__PURE__ */ React.createElement(React.Fragment, { key: `${i}.${entityRefString}` }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, { ...linkProps, entityRef: r }));
1531
+ return /* @__PURE__ */ React.createElement(React.Fragment, { key: `${i}.${entityRefString}` }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, { ...linkProps, entityRef: r, hideIcon: hideIcons }));
1526
1532
  }));
1527
1533
  }
1528
1534
 
@@ -1565,7 +1571,7 @@ const UserCardActions = (props) => {
1565
1571
  return email ? /* @__PURE__ */ React.createElement(EmailCardAction, { email }) : null;
1566
1572
  };
1567
1573
 
1568
- const useStyles$c = makeStyles(() => {
1574
+ const useStyles$d = makeStyles(() => {
1569
1575
  return {
1570
1576
  popoverPaper: {
1571
1577
  width: "30em"
@@ -1583,7 +1589,7 @@ const maxTagChips = 4;
1583
1589
  const EntityPeekAheadPopover = (props) => {
1584
1590
  var _a, _b, _c, _d;
1585
1591
  const { entityRef, children, delayTime = 500 } = props;
1586
- const classes = useStyles$c();
1592
+ const classes = useStyles$d();
1587
1593
  const apiHolder = useApiHolder();
1588
1594
  const popupState = usePopupState({
1589
1595
  variant: "popover",
@@ -1652,7 +1658,7 @@ const EntityPeekAheadPopover = (props) => {
1652
1658
  ));
1653
1659
  };
1654
1660
 
1655
- const useStyles$b = makeStyles(
1661
+ const useStyles$c = makeStyles(
1656
1662
  (_theme) => ({
1657
1663
  searchToolbar: {
1658
1664
  paddingLeft: 0,
@@ -1666,7 +1672,7 @@ const useStyles$b = makeStyles(
1666
1672
  );
1667
1673
  const EntitySearchBar = () => {
1668
1674
  var _a, _b;
1669
- const classes = useStyles$b();
1675
+ const classes = useStyles$c();
1670
1676
  const { filters, updateFilters } = useEntityList();
1671
1677
  const [search, setSearch] = useState((_b = (_a = filters.text) == null ? void 0 : _a.value) != null ? _b : "");
1672
1678
  useDebounce(
@@ -1831,7 +1837,7 @@ const componentEntityColumns = [
1831
1837
  columnFactories.createMetadataDescriptionColumn()
1832
1838
  ];
1833
1839
 
1834
- const useStyles$a = makeStyles((theme) => ({
1840
+ const useStyles$b = makeStyles((theme) => ({
1835
1841
  empty: {
1836
1842
  padding: theme.spacing(2),
1837
1843
  display: "flex",
@@ -1847,7 +1853,7 @@ const EntityTable = (props) => {
1847
1853
  columns,
1848
1854
  tableOptions = {}
1849
1855
  } = props;
1850
- const classes = useStyles$a();
1856
+ const classes = useStyles$b();
1851
1857
  const tableStyle = {
1852
1858
  minWidth: "0",
1853
1859
  width: "100%"
@@ -1879,12 +1885,12 @@ EntityTable.columns = columnFactories;
1879
1885
  EntityTable.systemEntityColumns = systemEntityColumns;
1880
1886
  EntityTable.componentEntityColumns = componentEntityColumns;
1881
1887
 
1882
- const useStyles$9 = makeStyles(
1888
+ const useStyles$a = makeStyles(
1883
1889
  { input: {} },
1884
1890
  { name: "CatalogReactEntityTagPicker" }
1885
1891
  );
1886
1892
  const EntityTagPicker = (props) => {
1887
- const classes = useStyles$9();
1893
+ const classes = useStyles$a();
1888
1894
  return /* @__PURE__ */ React.createElement(
1889
1895
  EntityAutocompletePicker,
1890
1896
  {
@@ -1990,7 +1996,7 @@ function EntityKindIcon(props) {
1990
1996
  return /* @__PURE__ */ React.createElement(Icon, { ...otherProps });
1991
1997
  }
1992
1998
 
1993
- const useStyles$8 = makeStyles((theme) => ({
1999
+ const useStyles$9 = makeStyles((theme) => ({
1994
2000
  node: {
1995
2001
  fill: theme.palette.grey[300],
1996
2002
  stroke: theme.palette.grey[300],
@@ -2044,7 +2050,7 @@ function useAncestry(root) {
2044
2050
  };
2045
2051
  }
2046
2052
  function CustomNode({ node }) {
2047
- const classes = useStyles$8();
2053
+ const classes = useStyles$9();
2048
2054
  const navigate = useNavigate();
2049
2055
  const entityRoute = useRouteRef(entityRouteRef);
2050
2056
  const [width, setWidth] = useState(0);
@@ -2139,7 +2145,7 @@ function AncestryPage(props) {
2139
2145
  )));
2140
2146
  }
2141
2147
 
2142
- const useStyles$7 = makeStyles((theme) => ({
2148
+ const useStyles$8 = makeStyles((theme) => ({
2143
2149
  root: {
2144
2150
  display: "flex",
2145
2151
  flexDirection: "column"
@@ -2156,7 +2162,7 @@ const useStyles$7 = makeStyles((theme) => ({
2156
2162
  }
2157
2163
  }));
2158
2164
  function ListItemText(props) {
2159
- const classes = useStyles$7();
2165
+ const classes = useStyles$8();
2160
2166
  return /* @__PURE__ */ React.createElement(
2161
2167
  ListItemText$1,
2162
2168
  {
@@ -2167,7 +2173,7 @@ function ListItemText(props) {
2167
2173
  );
2168
2174
  }
2169
2175
  function ListSubheader(props) {
2170
- const classes = useStyles$7();
2176
+ const classes = useStyles$8();
2171
2177
  return /* @__PURE__ */ React.createElement(ListSubheader$1, { className: classes.monospace }, props.children);
2172
2178
  }
2173
2179
  function Container(props) {
@@ -2194,11 +2200,11 @@ function KeyValueListItem(props) {
2194
2200
  ));
2195
2201
  }
2196
2202
  function HelpIcon(props) {
2197
- const classes = useStyles$7();
2203
+ const classes = useStyles$8();
2198
2204
  return /* @__PURE__ */ React.createElement(Link, { to: props.to, className: classes.helpIcon }, /* @__PURE__ */ React.createElement(HelpOutlineIcon, { fontSize: "inherit" }));
2199
2205
  }
2200
2206
 
2201
- const useStyles$6 = makeStyles({
2207
+ const useStyles$7 = makeStyles({
2202
2208
  root: {
2203
2209
  display: "flex",
2204
2210
  flexDirection: "column"
@@ -2278,7 +2284,7 @@ function Contents$1(props) {
2278
2284
  ));
2279
2285
  }
2280
2286
  function ColocatedPage(props) {
2281
- const classes = useStyles$6();
2287
+ const classes = useStyles$7();
2282
2288
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DialogContentText, { variant: "h2" }, "Colocated"), /* @__PURE__ */ React.createElement(DialogContentText, null, "These are the entities that are colocated with this entity - as in, they originated from the same data source (e.g. came from the same YAML file), or from the same origin (e.g. the originally registered URL)."), /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Contents$1, { entity: props.entity })));
2283
2289
  }
2284
2290
 
@@ -2299,7 +2305,7 @@ function JsonPage(props) {
2299
2305
  ))));
2300
2306
  }
2301
2307
 
2302
- const useStyles$5 = makeStyles({
2308
+ const useStyles$6 = makeStyles({
2303
2309
  root: {
2304
2310
  display: "flex",
2305
2311
  flexDirection: "column"
@@ -2307,7 +2313,7 @@ const useStyles$5 = makeStyles({
2307
2313
  });
2308
2314
  function OverviewPage(props) {
2309
2315
  var _a, _b, _c;
2310
- const classes = useStyles$5();
2316
+ const classes = useStyles$6();
2311
2317
  const {
2312
2318
  apiVersion,
2313
2319
  kind,
@@ -2320,13 +2326,14 @@ function OverviewPage(props) {
2320
2326
  sortBy(relations, (r) => r.targetRef),
2321
2327
  "type"
2322
2328
  );
2329
+ const entityRef = stringifyEntityRef(props.entity);
2323
2330
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DialogContentText, { variant: "h2" }, "Overview"), /* @__PURE__ */ React.createElement("div", { className: classes.root }, /* @__PURE__ */ React.createElement(Container, { title: "Identity" }, /* @__PURE__ */ React.createElement(List, { dense: true }, /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "apiVersion", secondary: apiVersion })), /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "kind", secondary: kind })), (spec == null ? void 0 : spec.type) && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(
2324
2331
  ListItemText,
2325
2332
  {
2326
2333
  primary: "spec.type",
2327
2334
  secondary: (_a = spec.type) == null ? void 0 : _a.toString()
2328
2335
  }
2329
- )), metadata.uid && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "uid", secondary: metadata.uid })), metadata.etag && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "etag", secondary: metadata.etag })))), /* @__PURE__ */ React.createElement(Container, { title: "Metadata" }, !!Object.keys(metadata.annotations || {}).length && /* @__PURE__ */ React.createElement(
2336
+ )), metadata.uid && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "uid", secondary: metadata.uid }), /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(CopyTextButton, { text: metadata.uid }))), metadata.etag && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "etag", secondary: metadata.etag }), /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(CopyTextButton, { text: metadata.etag }))), /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemText, { primary: "entityRef", secondary: entityRef }), /* @__PURE__ */ React.createElement(ListItemSecondaryAction, null, /* @__PURE__ */ React.createElement(CopyTextButton, { text: entityRef }))))), /* @__PURE__ */ React.createElement(Container, { title: "Metadata" }, !!Object.keys(metadata.annotations || {}).length && /* @__PURE__ */ React.createElement(
2330
2337
  List,
2331
2338
  {
2332
2339
  dense: true,
@@ -2368,7 +2375,7 @@ function YamlPage(props) {
2368
2375
  ))));
2369
2376
  }
2370
2377
 
2371
- const useStyles$4 = makeStyles((theme) => ({
2378
+ const useStyles$5 = makeStyles((theme) => ({
2372
2379
  fullHeightDialog: {
2373
2380
  height: "calc(100% - 64px)"
2374
2381
  },
@@ -2389,7 +2396,7 @@ const useStyles$4 = makeStyles((theme) => ({
2389
2396
  }));
2390
2397
  function TabPanel(props) {
2391
2398
  const { children, value, index, ...other } = props;
2392
- const classes = useStyles$4();
2399
+ const classes = useStyles$5();
2393
2400
  return /* @__PURE__ */ React.createElement(
2394
2401
  "div",
2395
2402
  {
@@ -2410,7 +2417,7 @@ function a11yProps(index) {
2410
2417
  };
2411
2418
  }
2412
2419
  function InspectEntityDialog(props) {
2413
- const classes = useStyles$4();
2420
+ const classes = useStyles$5();
2414
2421
  const [activeTab, setActiveTab] = React.useState(0);
2415
2422
  useEffect(() => {
2416
2423
  setActiveTab(0);
@@ -2514,7 +2521,7 @@ function useUnregisterEntityDialogState(entity) {
2514
2521
  };
2515
2522
  }
2516
2523
 
2517
- const useStyles$3 = makeStyles({
2524
+ const useStyles$4 = makeStyles({
2518
2525
  advancedButton: {
2519
2526
  fontSize: "0.7em"
2520
2527
  },
@@ -2530,7 +2537,7 @@ const Contents = ({
2530
2537
  var _a;
2531
2538
  const alertApi = useApi(alertApiRef);
2532
2539
  const configApi = useApi(configApiRef);
2533
- const classes = useStyles$3();
2540
+ const classes = useStyles$4();
2534
2541
  const state = useUnregisterEntityDialogState(entity);
2535
2542
  const [showDelete, setShowDelete] = useState(false);
2536
2543
  const [busy, setBusy] = useState(false);
@@ -2819,7 +2826,7 @@ function useStarredEntitiesCount() {
2819
2826
  return { count, loading, filter };
2820
2827
  }
2821
2828
 
2822
- const useStyles$2 = makeStyles(
2829
+ const useStyles$3 = makeStyles(
2823
2830
  (theme) => ({
2824
2831
  root: {
2825
2832
  backgroundColor: "rgba(0, 0, 0, .11)",
@@ -2878,7 +2885,7 @@ function getFilterGroups(orgName) {
2878
2885
  const UserListPicker = (props) => {
2879
2886
  var _a;
2880
2887
  const { initialFilter, availableFilters } = props;
2881
- const classes = useStyles$2();
2888
+ const classes = useStyles$3();
2882
2889
  const configApi = useApi(configApiRef);
2883
2890
  const orgName = (_a = configApi.getOptionalString("organization.name")) != null ? _a : "Company";
2884
2891
  const {
@@ -2971,7 +2978,6 @@ const UserListPicker = (props) => {
2971
2978
  {
2972
2979
  role: "none presentation",
2973
2980
  key: item.id,
2974
- button: true,
2975
2981
  divider: true,
2976
2982
  onClick: () => setSelectedUserFilter(item.id),
2977
2983
  selected: item.id === ((_a2 = filters.user) == null ? void 0 : _a2.value),
@@ -2988,7 +2994,7 @@ const UserListPicker = (props) => {
2988
2994
  }))))));
2989
2995
  };
2990
2996
 
2991
- const useStyles$1 = makeStyles(
2997
+ const useStyles$2 = makeStyles(
2992
2998
  {
2993
2999
  input: {}
2994
3000
  },
@@ -2999,7 +3005,7 @@ const useStyles$1 = makeStyles(
2999
3005
  const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
3000
3006
  const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
3001
3007
  const EntityProcessingStatusPicker = () => {
3002
- const classes = useStyles$1();
3008
+ const classes = useStyles$2();
3003
3009
  const { updateFilters } = useEntityList();
3004
3010
  const [selectedAdvancedItems, setSelectedAdvancedItems] = useState(
3005
3011
  []
@@ -3056,7 +3062,7 @@ const EntityProcessingStatusPicker = () => {
3056
3062
  )));
3057
3063
  };
3058
3064
 
3059
- const useStyles = makeStyles(
3065
+ const useStyles$1 = makeStyles(
3060
3066
  {
3061
3067
  input: {}
3062
3068
  },
@@ -3065,7 +3071,7 @@ const useStyles = makeStyles(
3065
3071
  }
3066
3072
  );
3067
3073
  const EntityNamespacePicker = () => {
3068
- const classes = useStyles();
3074
+ const classes = useStyles$1();
3069
3075
  return /* @__PURE__ */ React.createElement(
3070
3076
  EntityAutocompletePicker,
3071
3077
  {
@@ -3078,6 +3084,79 @@ const EntityNamespacePicker = () => {
3078
3084
  );
3079
3085
  };
3080
3086
 
3087
+ const useStyles = makeStyles$1(
3088
+ (theme) => ({
3089
+ code: {
3090
+ borderRadius: 6,
3091
+ margin: theme.spacing(2, 0),
3092
+ background: theme.palette.type === "dark" ? "#444" : theme.palette.common.white
3093
+ }
3094
+ }),
3095
+ { name: "BackstageMissingAnnotationEmptyState" }
3096
+ );
3097
+ function generateYamlExample(annotations, entity) {
3098
+ var _a, _b;
3099
+ const kind = (entity == null ? void 0 : entity.kind) || "Component";
3100
+ const name = (entity == null ? void 0 : entity.metadata.name) || "example";
3101
+ const type = ((_a = entity == null ? void 0 : entity.spec) == null ? void 0 : _a.type) || "website";
3102
+ const owner = ((_b = entity == null ? void 0 : entity.spec) == null ? void 0 : _b.owner) || "user:default/guest";
3103
+ const yamlText = `apiVersion: backstage.io/v1alpha1
3104
+ kind: ${kind}
3105
+ metadata:
3106
+ name: ${name}
3107
+ annotations:${annotations.map((ann) => `
3108
+ ${ann}: value`).join("")}
3109
+ spec:
3110
+ type: ${type}
3111
+ owner: ${owner}`;
3112
+ let line = 6;
3113
+ const lineNumbers = [];
3114
+ annotations.forEach(() => {
3115
+ lineNumbers.push(line);
3116
+ line++;
3117
+ });
3118
+ return {
3119
+ yamlText,
3120
+ lineNumbers
3121
+ };
3122
+ }
3123
+ function generateDescription(annotations, entityKind = "Component") {
3124
+ const isSingular = annotations.length <= 1;
3125
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, "The ", isSingular ? "annotation" : "annotations", " ", annotations.map((ann) => /* @__PURE__ */ React.createElement("code", null, ann)).reduce((prev, curr) => /* @__PURE__ */ React.createElement(React.Fragment, null, prev, ", ", curr)), " ", isSingular ? "is" : "are", " missing. You need to add the", " ", isSingular ? "annotation" : "annotations", " to your ", entityKind, " if you want to enable this tool.");
3126
+ }
3127
+ function MissingAnnotationEmptyState(props) {
3128
+ let entity;
3129
+ try {
3130
+ const entityContext = useEntity();
3131
+ entity = entityContext.entity;
3132
+ } catch (err) {
3133
+ }
3134
+ const { annotation, readMoreUrl } = props;
3135
+ const annotations = Array.isArray(annotation) ? annotation : [annotation];
3136
+ const url = readMoreUrl || "https://backstage.io/docs/features/software-catalog/well-known-annotations";
3137
+ const classes = useStyles();
3138
+ const entityKind = (entity == null ? void 0 : entity.kind) || "Component";
3139
+ const { yamlText, lineNumbers } = generateYamlExample(annotations, entity);
3140
+ return /* @__PURE__ */ React.createElement(
3141
+ EmptyState,
3142
+ {
3143
+ missing: "field",
3144
+ title: "Missing Annotation",
3145
+ description: generateDescription(annotations, entityKind),
3146
+ action: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography$1, { variant: "body1" }, "Add the annotation to your ", entityKind, " YAML as shown in the highlighted example below:"), /* @__PURE__ */ React.createElement(Box$1, { className: classes.code }, /* @__PURE__ */ React.createElement(
3147
+ CodeSnippet,
3148
+ {
3149
+ text: yamlText,
3150
+ language: "yaml",
3151
+ showLineNumbers: true,
3152
+ highlightedNumbers: lineNumbers,
3153
+ customStyle: { background: "inherit", fontSize: "115%" }
3154
+ }
3155
+ )), /* @__PURE__ */ React.createElement(Button$1, { color: "primary", component: Link, to: url }, "Read more"))
3156
+ }
3157
+ );
3158
+ }
3159
+
3081
3160
  function MockEntityListContextProvider(props) {
3082
3161
  var _a;
3083
3162
  const { children, value } = props;
@@ -3117,5 +3196,5 @@ function MockEntityListContextProvider(props) {
3117
3196
  return /* @__PURE__ */ React.createElement(EntityListContext.Provider, { value: resolvedValue }, children);
3118
3197
  }
3119
3198
 
3120
- export { CatalogFilterLayout, EntityAutocompletePicker, EntityDisplayName, EntityErrorFilter, EntityKindFilter, EntityKindPicker, EntityLifecycleFilter, EntityLifecyclePicker, EntityListContext, EntityListProvider, EntityNamespaceFilter, EntityNamespacePicker, EntityOrphanFilter, EntityOwnerFilter, EntityOwnerPicker, EntityPeekAheadPopover, EntityProcessingStatusPicker, EntityRefLink, EntityRefLinks, EntitySearchBar, EntityTable, EntityTagFilter, EntityTagPicker, EntityTextFilter, EntityTypeFilter, EntityTypePicker, EntityUserFilter, FavoriteEntity, InspectEntityDialog, MockEntityListContextProvider, MockStarredEntitiesApi, UnregisterEntityDialog, UserListFilter, UserListPicker, catalogApiRef, columnFactories, defaultEntityPresentation, entityPresentationApiRef, entityRouteParams, entityRouteRef, getEntitySourceLocation, humanizeEntityRef, starredEntitiesApiRef, useEntityList, useEntityOwnership, useEntityPresentation, useEntityTypeFilter, useRelatedEntities, useStarredEntities, useStarredEntity };
3199
+ export { CatalogFilterLayout, EntityAutocompletePicker, EntityDisplayName, EntityErrorFilter, EntityKindFilter, EntityKindPicker, EntityLifecycleFilter, EntityLifecyclePicker, EntityListContext, EntityListProvider, EntityNamespaceFilter, EntityNamespacePicker, EntityOrphanFilter, EntityOwnerFilter, EntityOwnerPicker, EntityPeekAheadPopover, EntityProcessingStatusPicker, EntityRefLink, EntityRefLinks, EntitySearchBar, EntityTable, EntityTagFilter, EntityTagPicker, EntityTextFilter, EntityTypeFilter, EntityTypePicker, EntityUserFilter, FavoriteEntity, InspectEntityDialog, MissingAnnotationEmptyState, MockEntityListContextProvider, MockStarredEntitiesApi, UnregisterEntityDialog, UserListFilter, UserListPicker, catalogApiRef, columnFactories, defaultEntityPresentation, entityPresentationApiRef, entityRouteParams, entityRouteRef, getEntitySourceLocation, humanizeEntityRef, starredEntitiesApiRef, useEntityList, useEntityOwnership, useEntityPresentation, useEntityTypeFilter, useRelatedEntities, useStarredEntities, useStarredEntity };
3121
3200
  //# sourceMappingURL=index.esm.js.map