@backstage/plugin-catalog-react 1.9.0-next.2 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ceebf2ca4ba7: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended.
8
+ - Updated dependencies
9
+ - @backstage/integration-react@1.1.21
10
+
11
+ ## 1.9.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 1e5b7d993a: Added an `EntityPresentationApi` and associated `entityPresentationApiRef`. This
16
+ API lets you control how references to entities (e.g. in links, headings,
17
+ iconography etc) are represented in the user interface.
18
+
19
+ Usage of this API is initially added to the `EntityRefLink` and `EntityRefLinks`
20
+ components, so that they can render richer, more correct representation of
21
+ entity refs. There's also a new `EntityDisplayName` component, which works just like
22
+ the `EntityRefLink` but without the link.
23
+
24
+ Along with that change, the `fetchEntities` and `getTitle` props of
25
+ `EntityRefLinksProps` are deprecated and no longer used, since the same need
26
+ instead is fulfilled (and by default always enabled) by the
27
+ `entityPresentationApiRef`.
28
+
29
+ - 1fd53fa0c6: The `UserListPicker` component has undergone improvements to enhance its performance.
30
+
31
+ 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.
32
+
33
+ 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.
34
+
35
+ ### Patch Changes
36
+
37
+ - 2ad1bacef7: Add EntityRef to Entity Inspector UI
38
+ - 6c2b872153: Add official support for React 18.
39
+ - 69ee8d75f4: Remove `button` prop from used MaterialUI `MenuItem` component fixing incompatibility with MaterialUI v5.
40
+ - 0bf6ebda88: Added new APIs at the `/alpha` subpath for creating entity page cards and content for the new frontend system.
41
+ - 77f009b35d: Internal updates to match changes in the experimental `@backstage/frontend-plugin-api`.
42
+ - 71c97e7d73: The `spec.type` field in entities will now always be rendered as a string.
43
+ - 69c14904b6: Move the `EntityRefLink` icon to the left hand side as per Material-UI guidelines
44
+ - 000dcd01af: Removed unnecessary `@backstage/integration` dependency, replaced by `@backstage/integration-react`.
45
+ - 6c357184e2: Export `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react`
46
+ - Updated dependencies
47
+ - @backstage/core-components@0.13.8
48
+ - @backstage/frontend-plugin-api@0.3.0
49
+ - @backstage/integration-react@1.1.21
50
+ - @backstage/core-plugin-api@1.8.0
51
+ - @backstage/plugin-permission-react@0.4.17
52
+ - @backstage/version-bridge@1.0.7
53
+ - @backstage/theme@0.4.4
54
+ - @backstage/catalog-client@1.4.6
55
+ - @backstage/plugin-permission-common@0.7.10
56
+ - @backstage/catalog-model@1.4.3
57
+ - @backstage/errors@1.2.3
58
+ - @backstage/types@1.1.1
59
+ - @backstage/plugin-catalog-common@1.0.18
60
+
3
61
  ## 1.9.0-next.2
4
62
 
5
63
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.9.0-next.2",
3
+ "version": "1.9.1",
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
@@ -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 */
package/dist/index.esm.js CHANGED
@@ -13,9 +13,9 @@ 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, EmptyState } from '@backstage/core-components';
18
+ import { Select, Link, ResponseErrorPanel, Progress, OverflowTooltip, Table, DependencyGraph, DependencyGraphTypes, CodeSnippet, CopyTextButton, EmptyState } from '@backstage/core-components';
19
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';
@@ -52,6 +52,7 @@ 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 useDeepCompareEffect from 'react-use/lib/useDeepCompareEffect';
55
56
  import Box$1 from '@material-ui/core/Box';
56
57
  import Button$1 from '@material-ui/core/Button';
57
58
  import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
@@ -1431,7 +1432,7 @@ const useStyles$e = makeStyles(
1431
1432
  alignItems: "center"
1432
1433
  },
1433
1434
  icon: {
1434
- marginLeft: theme.spacing(0.5),
1435
+ marginRight: theme.spacing(0.5),
1435
1436
  color: theme.palette.text.secondary,
1436
1437
  lineHeight: 0
1437
1438
  }
@@ -1439,15 +1440,15 @@ const useStyles$e = makeStyles(
1439
1440
  { name: "CatalogReactEntityDisplayName" }
1440
1441
  );
1441
1442
  const EntityDisplayName = (props) => {
1442
- const { entityRef, noIcon, noTooltip, defaultKind, defaultNamespace } = props;
1443
+ const { entityRef, hideIcon, disableTooltip, defaultKind, defaultNamespace } = props;
1443
1444
  const classes = useStyles$e();
1444
1445
  const { primaryTitle, secondaryTitle, Icon } = useEntityPresentation(
1445
1446
  entityRef,
1446
1447
  { defaultKind, defaultNamespace }
1447
1448
  );
1448
1449
  let content = /* @__PURE__ */ React.createElement(React.Fragment, null, primaryTitle);
1449
- 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);
1450
- if (secondaryTitle && !noTooltip) {
1450
+ 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);
1451
+ if (secondaryTitle && !disableTooltip) {
1451
1452
  content = /* @__PURE__ */ React.createElement(Tooltip, { enterDelay: 1500, title: secondaryTitle }, content);
1452
1453
  }
1453
1454
  return content;
@@ -1478,6 +1479,7 @@ const EntityRefLink = forwardRef(
1478
1479
  defaultNamespace,
1479
1480
  title,
1480
1481
  children,
1482
+ hideIcon,
1481
1483
  ...linkProps
1482
1484
  } = props;
1483
1485
  const entityRoute = useEntityRoute(props.entityRef);
@@ -1486,7 +1488,8 @@ const EntityRefLink = forwardRef(
1486
1488
  {
1487
1489
  entityRef,
1488
1490
  defaultKind,
1489
- defaultNamespace
1491
+ defaultNamespace,
1492
+ hideIcon
1490
1493
  }
1491
1494
  );
1492
1495
  return /* @__PURE__ */ React.createElement(Link, { ...linkProps, ref, to: entityRoute }, content);
@@ -1523,10 +1526,10 @@ function useEntityRoute(entityRef) {
1523
1526
  }
1524
1527
 
1525
1528
  function EntityRefLinks(props) {
1526
- const { entityRefs, ...linkProps } = props;
1529
+ const { entityRefs, hideIcons, ...linkProps } = props;
1527
1530
  return /* @__PURE__ */ React.createElement(React.Fragment, null, entityRefs.map((r, i) => {
1528
1531
  const entityRefString = typeof r === "string" ? r : stringifyEntityRef(r);
1529
- return /* @__PURE__ */ React.createElement(React.Fragment, { key: `${i}.${entityRefString}` }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, { ...linkProps, entityRef: r }));
1532
+ return /* @__PURE__ */ React.createElement(React.Fragment, { key: `${i}.${entityRefString}` }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, { ...linkProps, entityRef: r, hideIcon: hideIcons }));
1530
1533
  }));
1531
1534
  }
1532
1535
 
@@ -2324,13 +2327,14 @@ function OverviewPage(props) {
2324
2327
  sortBy(relations, (r) => r.targetRef),
2325
2328
  "type"
2326
2329
  );
2330
+ const entityRef = stringifyEntityRef(props.entity);
2327
2331
  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(
2328
2332
  ListItemText,
2329
2333
  {
2330
2334
  primary: "spec.type",
2331
2335
  secondary: (_a = spec.type) == null ? void 0 : _a.toString()
2332
2336
  }
2333
- )), 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(
2337
+ )), 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(
2334
2338
  List,
2335
2339
  {
2336
2340
  dense: true,
@@ -2668,58 +2672,48 @@ function useOwnedEntitiesCount() {
2668
2672
  // load only on mount
2669
2673
  []
2670
2674
  );
2671
- const prevRequest = useRef();
2672
- const request = useMemo(() => {
2673
- const { user, owners, ...allFilters } = filters;
2674
- const compacted = compact(Object.values(allFilters));
2675
- const allFilter = reduceCatalogFilters(compacted);
2676
- const { ["metadata.name"]: metadata, ...filter2 } = allFilter;
2677
- const countFilter = getOwnedCountClaims(owners, ownershipEntityRefs);
2678
- if ((ownershipEntityRefs == null ? void 0 : ownershipEntityRefs.length) === 0 || countFilter === void 0 || Object.keys(filter2).length === 0) {
2679
- prevRequest.current = void 0;
2680
- return void 0;
2681
- }
2682
- const newRequest = {
2683
- filter: {
2684
- ...filter2,
2685
- "relations.ownedBy": countFilter
2686
- },
2687
- limit: 0
2688
- };
2689
- if (isEqual(newRequest, prevRequest.current)) {
2690
- return prevRequest.current;
2691
- }
2692
- prevRequest.current = newRequest;
2693
- return newRequest;
2694
- }, [filters, ownershipEntityRefs]);
2675
+ const { user, owners, ...allFilters } = filters;
2676
+ const { ["metadata.name"]: metadata, ...filter } = reduceCatalogFilters(
2677
+ compact(Object.values(allFilters))
2678
+ );
2695
2679
  const [{ value: count, loading: loadingEntityOwnership }, fetchEntities] = useAsyncFn(
2696
- async (req, ownershipEntityRefsParam) => {
2697
- if (ownershipEntityRefsParam && !req) {
2680
+ async (req) => {
2681
+ const ownedClaims = getOwnedCountClaims(
2682
+ req.owners,
2683
+ req.ownershipEntityRefs
2684
+ );
2685
+ if (ownedClaims === void 0) {
2698
2686
  return 0;
2699
2687
  }
2700
- const { totalItems } = await catalogApi.queryEntities(req);
2688
+ const { totalItems } = await catalogApi.queryEntities({
2689
+ filter: {
2690
+ ...req.filter,
2691
+ "relations.ownedBy": ownedClaims
2692
+ },
2693
+ limit: 0
2694
+ });
2701
2695
  return totalItems;
2702
2696
  },
2703
2697
  [],
2704
2698
  { loading: true }
2705
2699
  );
2706
- useEffect(() => {
2707
- if (ownershipEntityRefs) {
2708
- if (request && Object.keys(request).length === 0) {
2709
- return;
2710
- }
2711
- fetchEntities(request, ownershipEntityRefs);
2700
+ useDeepCompareEffect(() => {
2701
+ if (Object.keys(filter).length === 0) {
2702
+ return;
2712
2703
  }
2713
- }, [fetchEntities, request, ownershipEntityRefs]);
2704
+ if (ownershipEntityRefs === void 0) {
2705
+ return;
2706
+ }
2707
+ fetchEntities({ ownershipEntityRefs, owners, filter });
2708
+ }, [ownershipEntityRefs, owners, filter]);
2714
2709
  const loading = loadingEntityRefs || loadingEntityOwnership;
2715
- const filter = useMemo(
2716
- () => EntityUserFilter.owned(ownershipEntityRefs != null ? ownershipEntityRefs : []),
2717
- [ownershipEntityRefs]
2718
- );
2719
2710
  return {
2720
2711
  count,
2721
2712
  loading,
2722
- filter,
2713
+ filter: useMemo(
2714
+ () => EntityUserFilter.owned(ownershipEntityRefs != null ? ownershipEntityRefs : []),
2715
+ [ownershipEntityRefs]
2716
+ ),
2723
2717
  ownershipEntityRefs
2724
2718
  };
2725
2719
  }
@@ -2975,7 +2969,6 @@ const UserListPicker = (props) => {
2975
2969
  {
2976
2970
  role: "none presentation",
2977
2971
  key: item.id,
2978
- button: true,
2979
2972
  divider: true,
2980
2973
  onClick: () => setSelectedUserFilter(item.id),
2981
2974
  selected: item.id === ((_a2 = filters.user) == null ? void 0 : _a2.value),