@backstage/plugin-catalog-react 1.0.0 → 1.0.1-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.0.1-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 4be0d1e777: Changed catalog filter components to only pay attention to query parameters relevant to the component.
8
+ - 5d5fdbe541: Columns in CatalogTable now change depending on the entity kind, ensuring only relevant columns are displayed.
9
+ - 99063c39ae: Minor API report cleanup
10
+ - Updated dependencies
11
+ - @backstage/core-components@0.9.3-next.1
12
+ - @backstage/catalog-model@1.0.1-next.1
13
+
14
+ ## 1.0.1-next.1
15
+
16
+ ### Patch Changes
17
+
18
+ - 0ffd88a90e: Prevent permissions with types other than `ResourcePermission<'catalog-entity'>` from being used with the `useEntityPermission` hook.
19
+ - 4af82967f4: Decouple tags picker from backend entities
20
+
21
+ `EntityTagPicker` fetches all the tags independently and it doesn't require all the entities to be available client side.
22
+
23
+ - 37b04b5a5e: Removed broken link from Labels section of entity inspector.
24
+ - 4431873583: Update `usePermission` usage.
25
+ - Updated dependencies
26
+ - @backstage/integration@1.1.0-next.1
27
+ - @backstage/plugin-permission-react@0.4.0-next.0
28
+ - @backstage/plugin-permission-common@0.6.0-next.0
29
+ - @backstage/plugin-catalog-common@1.0.1-next.1
30
+
31
+ ## 1.0.1-next.0
32
+
33
+ ### Patch Changes
34
+
35
+ - a496cee4d1: Add support for string refs to the `EntityRefLinks` component
36
+ - d34900af81: Added a new `NextScaffolderRouter` which will eventually replace the exiting router
37
+ - Updated dependencies
38
+ - @backstage/catalog-model@1.0.1-next.0
39
+ - @backstage/integration@1.0.1-next.0
40
+ - @backstage/core-components@0.9.3-next.0
41
+ - @backstage/catalog-client@1.0.1-next.0
42
+
3
43
  ## 1.0.0
4
44
 
5
45
  ### Major Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.0.0",
3
+ "version": "1.0.1-next.2",
4
4
  "main": "../dist/index.esm.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -17,10 +17,10 @@ import { IconButton } from '@material-ui/core';
17
17
  import { LinkProps } from '@backstage/core-components';
18
18
  import { Observable } from '@backstage/types';
19
19
  import { Overrides } from '@material-ui/core/styles/overrides';
20
- import { Permission } from '@backstage/plugin-permission-common';
21
20
  import { PropsWithChildren } from 'react';
22
21
  import { default as React_2 } from 'react';
23
22
  import { ReactNode } from 'react';
23
+ import { ResourcePermission } from '@backstage/plugin-permission-common';
24
24
  import { RouteRef } from '@backstage/core-plugin-api';
25
25
  import { ScmIntegrationRegistry } from '@backstage/integration';
26
26
  import { StyleRules } from '@material-ui/core/styles/withStyles';
@@ -259,7 +259,7 @@ export declare const EntityOwnerPicker: () => JSX.Element | null;
259
259
  *
260
260
  * @public
261
261
  */
262
- export declare const EntityProvider: ({ entity, children }: EntityProviderProps) => JSX.Element;
262
+ export declare const EntityProvider: (props: EntityProviderProps) => JSX.Element;
263
263
 
264
264
  /**
265
265
  * Properties for the EntityProvider component.
@@ -295,7 +295,7 @@ export declare type EntityRefLinkProps = {
295
295
  *
296
296
  * @public
297
297
  */
298
- export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }: EntityRefLinksProps) => JSX.Element;
298
+ export declare function EntityRefLinks(props: EntityRefLinksProps): JSX.Element;
299
299
 
300
300
  /**
301
301
  * Props for {@link EntityRefLink}.
@@ -303,7 +303,7 @@ export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }:
303
303
  * @public
304
304
  */
305
305
  export declare type EntityRefLinksProps = {
306
- entityRefs: (Entity | CompoundEntityRef)[];
306
+ entityRefs: (string | Entity | CompoundEntityRef)[];
307
307
  defaultKind?: string;
308
308
  } & Omit<LinkProps, 'to'>;
309
309
 
@@ -585,14 +585,14 @@ export declare function useEntityOwnership(): {
585
585
  * A thin wrapper around the
586
586
  * {@link @backstage/plugin-permission-react#usePermission} hook which uses the
587
587
  * current entity in context to make an authorization request for the given
588
- * permission.
588
+ * {@link @backstage/plugin-catalog-common#CatalogEntityPermission}.
589
589
  *
590
590
  * Note: this hook blocks the permission request until the entity has loaded in
591
591
  * context. If you have the entityRef and need concurrent requests, use the
592
592
  * `usePermission` hook directly.
593
593
  * @alpha
594
594
  */
595
- export declare function useEntityPermission(permission: Permission): {
595
+ export declare function useEntityPermission(permission: ResourcePermission<'catalog-entity'>): {
596
596
  loading: boolean;
597
597
  allowed: boolean;
598
598
  error?: Error;
@@ -17,10 +17,10 @@ import { IconButton } from '@material-ui/core';
17
17
  import { LinkProps } from '@backstage/core-components';
18
18
  import { Observable } from '@backstage/types';
19
19
  import { Overrides } from '@material-ui/core/styles/overrides';
20
- import { Permission } from '@backstage/plugin-permission-common';
21
20
  import { PropsWithChildren } from 'react';
22
21
  import { default as React_2 } from 'react';
23
22
  import { ReactNode } from 'react';
23
+ import { ResourcePermission } from '@backstage/plugin-permission-common';
24
24
  import { RouteRef } from '@backstage/core-plugin-api';
25
25
  import { ScmIntegrationRegistry } from '@backstage/integration';
26
26
  import { StyleRules } from '@material-ui/core/styles/withStyles';
@@ -259,7 +259,7 @@ export declare const EntityOwnerPicker: () => JSX.Element | null;
259
259
  *
260
260
  * @public
261
261
  */
262
- export declare const EntityProvider: ({ entity, children }: EntityProviderProps) => JSX.Element;
262
+ export declare const EntityProvider: (props: EntityProviderProps) => JSX.Element;
263
263
 
264
264
  /**
265
265
  * Properties for the EntityProvider component.
@@ -295,7 +295,7 @@ export declare type EntityRefLinkProps = {
295
295
  *
296
296
  * @public
297
297
  */
298
- export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }: EntityRefLinksProps) => JSX.Element;
298
+ export declare function EntityRefLinks(props: EntityRefLinksProps): JSX.Element;
299
299
 
300
300
  /**
301
301
  * Props for {@link EntityRefLink}.
@@ -303,7 +303,7 @@ export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }:
303
303
  * @public
304
304
  */
305
305
  export declare type EntityRefLinksProps = {
306
- entityRefs: (Entity | CompoundEntityRef)[];
306
+ entityRefs: (string | Entity | CompoundEntityRef)[];
307
307
  defaultKind?: string;
308
308
  } & Omit<LinkProps, 'to'>;
309
309
 
package/dist/index.d.ts CHANGED
@@ -17,10 +17,10 @@ import { IconButton } from '@material-ui/core';
17
17
  import { LinkProps } from '@backstage/core-components';
18
18
  import { Observable } from '@backstage/types';
19
19
  import { Overrides } from '@material-ui/core/styles/overrides';
20
- import { Permission } from '@backstage/plugin-permission-common';
21
20
  import { PropsWithChildren } from 'react';
22
21
  import { default as React_2 } from 'react';
23
22
  import { ReactNode } from 'react';
23
+ import { ResourcePermission } from '@backstage/plugin-permission-common';
24
24
  import { RouteRef } from '@backstage/core-plugin-api';
25
25
  import { ScmIntegrationRegistry } from '@backstage/integration';
26
26
  import { StyleRules } from '@material-ui/core/styles/withStyles';
@@ -259,7 +259,7 @@ export declare const EntityOwnerPicker: () => JSX.Element | null;
259
259
  *
260
260
  * @public
261
261
  */
262
- export declare const EntityProvider: ({ entity, children }: EntityProviderProps) => JSX.Element;
262
+ export declare const EntityProvider: (props: EntityProviderProps) => JSX.Element;
263
263
 
264
264
  /**
265
265
  * Properties for the EntityProvider component.
@@ -295,7 +295,7 @@ export declare type EntityRefLinkProps = {
295
295
  *
296
296
  * @public
297
297
  */
298
- export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }: EntityRefLinksProps) => JSX.Element;
298
+ export declare function EntityRefLinks(props: EntityRefLinksProps): JSX.Element;
299
299
 
300
300
  /**
301
301
  * Props for {@link EntityRefLink}.
@@ -303,7 +303,7 @@ export declare const EntityRefLinks: ({ entityRefs, defaultKind, ...linkProps }:
303
303
  * @public
304
304
  */
305
305
  export declare type EntityRefLinksProps = {
306
- entityRefs: (Entity | CompoundEntityRef)[];
306
+ entityRefs: (string | Entity | CompoundEntityRef)[];
307
307
  defaultKind?: string;
308
308
  } & Omit<LinkProps, 'to'>;
309
309
 
package/dist/index.esm.js CHANGED
@@ -125,12 +125,12 @@ const AsyncEntityProvider = ({
125
125
  value: createVersionedValueMap({ 1: value })
126
126
  }, children);
127
127
  };
128
- const EntityProvider = ({ entity, children }) => /* @__PURE__ */ React.createElement(AsyncEntityProvider, {
129
- entity,
130
- loading: !Boolean(entity),
128
+ const EntityProvider = (props) => /* @__PURE__ */ React.createElement(AsyncEntityProvider, {
129
+ entity: props.entity,
130
+ loading: !Boolean(props.entity),
131
131
  error: void 0,
132
132
  refresh: void 0,
133
- children
133
+ children: props.children
134
134
  });
135
135
  function useEntity() {
136
136
  const versionedHolder = useVersionedContext("entity-context");
@@ -368,17 +368,16 @@ const EntityRefLink = forwardRef((props, ref) => {
368
368
  }, link) : link;
369
369
  });
370
370
 
371
- const EntityRefLinks = ({
372
- entityRefs,
373
- defaultKind,
374
- ...linkProps
375
- }) => /* @__PURE__ */ React.createElement(React.Fragment, null, entityRefs.map((r, i) => /* @__PURE__ */ React.createElement(React.Fragment, {
376
- key: i
377
- }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, {
378
- ...linkProps,
379
- entityRef: r,
380
- defaultKind
381
- }))));
371
+ function EntityRefLinks(props) {
372
+ const { entityRefs, defaultKind, ...linkProps } = props;
373
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, entityRefs.map((r, i) => /* @__PURE__ */ React.createElement(React.Fragment, {
374
+ key: i
375
+ }, i > 0 && ", ", /* @__PURE__ */ React.createElement(EntityRefLink, {
376
+ ...linkProps,
377
+ entityRef: r,
378
+ defaultKind
379
+ }))));
380
+ }
382
381
 
383
382
  class EntityKindFilter {
384
383
  constructor(value) {
@@ -480,16 +479,16 @@ function useEntityTypeFilter() {
480
479
  const catalogApi = useApi(catalogApiRef);
481
480
  const {
482
481
  filters: { kind: kindFilter, type: typeFilter },
483
- queryParameters,
482
+ queryParameters: { type: typeParameter },
484
483
  updateFilters
485
484
  } = useEntityList();
486
- const queryParamTypes = useMemo(() => [queryParameters.type].flat().filter(Boolean), [queryParameters]);
487
- const [selectedTypes, setSelectedTypes] = useState(queryParamTypes.length ? queryParamTypes : (_a = typeFilter == null ? void 0 : typeFilter.getTypes()) != null ? _a : []);
485
+ const flattenedQueryTypes = useMemo(() => [typeParameter].flat().filter(Boolean), [typeParameter]);
486
+ const [selectedTypes, setSelectedTypes] = useState(flattenedQueryTypes.length ? flattenedQueryTypes : (_a = typeFilter == null ? void 0 : typeFilter.getTypes()) != null ? _a : []);
488
487
  useEffect(() => {
489
- if (queryParamTypes.length) {
490
- setSelectedTypes(queryParamTypes);
488
+ if (flattenedQueryTypes.length) {
489
+ setSelectedTypes(flattenedQueryTypes);
491
490
  }
492
- }, [queryParamTypes]);
491
+ }, [flattenedQueryTypes]);
493
492
  const [availableTypes, setAvailableTypes] = useState([]);
494
493
  const kind = useMemo(() => kindFilter == null ? void 0 : kindFilter.value, [kindFilter]);
495
494
  const {
@@ -650,7 +649,10 @@ function useEntityPermission(permission) {
650
649
  allowed,
651
650
  loading: loadingPermission,
652
651
  error: permissionError
653
- } = usePermission(permission, entity ? stringifyEntityRef(entity) : void 0);
652
+ } = usePermission({
653
+ permission,
654
+ resourceRef: entity ? stringifyEntityRef(entity) : void 0
655
+ });
654
656
  if (loadingEntity || loadingPermission) {
655
657
  return { loading: true, allowed: false };
656
658
  }
@@ -663,8 +665,11 @@ function useEntityPermission(permission) {
663
665
  const EntityKindPicker = (props) => {
664
666
  var _a;
665
667
  const { initialFilter, hidden } = props;
666
- const { updateFilters, queryParameters } = useEntityList();
667
- const [selectedKind] = useState((_a = [queryParameters.kind].flat()[0]) != null ? _a : initialFilter);
668
+ const {
669
+ updateFilters,
670
+ queryParameters: { kind: kindParameter }
671
+ } = useEntityList();
672
+ const [selectedKind] = useState((_a = [kindParameter].flat()[0]) != null ? _a : initialFilter);
668
673
  useEffect(() => {
669
674
  updateFilters({
670
675
  kind: selectedKind ? new EntityKindFilter(selectedKind) : void 0
@@ -691,8 +696,13 @@ const checkedIcon$2 = /* @__PURE__ */ React.createElement(CheckBoxIcon, {
691
696
  const EntityLifecyclePicker = () => {
692
697
  var _a, _b;
693
698
  const classes = useStyles$b();
694
- const { updateFilters, backendEntities, filters, queryParameters } = useEntityList();
695
- const queryParamLifecycles = useMemo(() => [queryParameters.lifecycles].flat().filter(Boolean), [queryParameters]);
699
+ const {
700
+ updateFilters,
701
+ backendEntities,
702
+ filters,
703
+ queryParameters: { lifecycles: lifecyclesParameter }
704
+ } = useEntityList();
705
+ const queryParamLifecycles = useMemo(() => [lifecyclesParameter].flat().filter(Boolean), [lifecyclesParameter]);
696
706
  const [selectedLifecycles, setSelectedLifecycles] = useState(queryParamLifecycles.length ? queryParamLifecycles : (_b = (_a = filters.lifecycles) == null ? void 0 : _a.values) != null ? _b : []);
697
707
  useEffect(() => {
698
708
  if (queryParamLifecycles.length) {
@@ -757,8 +767,13 @@ const checkedIcon$1 = /* @__PURE__ */ React.createElement(CheckBoxIcon, {
757
767
  const EntityOwnerPicker = () => {
758
768
  var _a, _b;
759
769
  const classes = useStyles$a();
760
- const { updateFilters, backendEntities, filters, queryParameters } = useEntityList();
761
- const queryParamOwners = useMemo(() => [queryParameters.owners].flat().filter(Boolean), [queryParameters]);
770
+ const {
771
+ updateFilters,
772
+ backendEntities,
773
+ filters,
774
+ queryParameters: { owners: ownersParameter }
775
+ } = useEntityList();
776
+ const queryParamOwners = useMemo(() => [ownersParameter].flat().filter(Boolean), [ownersParameter]);
762
777
  const [selectedOwners, setSelectedOwners] = useState(queryParamOwners.length ? queryParamOwners : (_b = (_a = filters.owners) == null ? void 0 : _a.values) != null ? _b : []);
763
778
  useEffect(() => {
764
779
  if (queryParamOwners.length) {
@@ -828,6 +843,7 @@ const EntitySearchBar = () => {
828
843
  return /* @__PURE__ */ React.createElement(Toolbar, {
829
844
  className: classes.searchToolbar
830
845
  }, /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(Input, {
846
+ "aria-label": "search",
831
847
  id: "input-with-icon-adornment",
832
848
  className: classes.input,
833
849
  placeholder: "Search",
@@ -1029,8 +1045,22 @@ const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, {
1029
1045
  const EntityTagPicker = () => {
1030
1046
  var _a, _b;
1031
1047
  const classes = useStyles$7();
1032
- const { updateFilters, backendEntities, filters, queryParameters } = useEntityList();
1033
- const queryParamTags = useMemo(() => [queryParameters.tags].flat().filter(Boolean), [queryParameters]);
1048
+ const {
1049
+ updateFilters,
1050
+ filters,
1051
+ queryParameters: { tags: tagsParameter }
1052
+ } = useEntityList();
1053
+ const catalogApi = useApi(catalogApiRef);
1054
+ const { value: availableTags } = useAsync(async () => {
1055
+ var _a2;
1056
+ const facet = "metadata.tags";
1057
+ const { facets } = await catalogApi.getEntityFacets({
1058
+ facets: [facet],
1059
+ filter: (_a2 = filters.kind) == null ? void 0 : _a2.getCatalogFilters()
1060
+ });
1061
+ return facets[facet].map(({ value }) => value);
1062
+ }, [filters.kind]);
1063
+ const queryParamTags = useMemo(() => [tagsParameter].flat().filter(Boolean), [tagsParameter]);
1034
1064
  const [selectedTags, setSelectedTags] = useState(queryParamTags.length ? queryParamTags : (_b = (_a = filters.tags) == null ? void 0 : _a.values) != null ? _b : []);
1035
1065
  useEffect(() => {
1036
1066
  if (queryParamTags.length) {
@@ -1042,10 +1072,7 @@ const EntityTagPicker = () => {
1042
1072
  tags: selectedTags.length ? new EntityTagFilter(selectedTags) : void 0
1043
1073
  });
1044
1074
  }, [selectedTags, updateFilters]);
1045
- const availableTags = useMemo(() => [
1046
- ...new Set(backendEntities.flatMap((e) => e.metadata.tags).filter(Boolean))
1047
- ].sort(), [backendEntities]);
1048
- if (!availableTags.length)
1075
+ if (!(availableTags == null ? void 0 : availableTags.length))
1049
1076
  return null;
1050
1077
  return /* @__PURE__ */ React.createElement(Box, {
1051
1078
  pb: 1,
@@ -1122,6 +1149,7 @@ const YellowStar = withStyles({
1122
1149
  const FavoriteEntity = (props) => {
1123
1150
  const { toggleStarredEntity, isStarredEntity } = useStarredEntity(props.entity);
1124
1151
  return /* @__PURE__ */ React.createElement(IconButton, {
1152
+ "aria-label": "favorite",
1125
1153
  color: "inherit",
1126
1154
  ...props,
1127
1155
  onClick: () => toggleStarredEntity()
@@ -1530,9 +1558,7 @@ function OverviewPage(props) {
1530
1558
  entry
1531
1559
  }))), !!Object.keys(metadata.labels || {}).length && /* @__PURE__ */ React.createElement(List, {
1532
1560
  dense: true,
1533
- subheader: /* @__PURE__ */ React.createElement(ListSubheader, null, "Labels", /* @__PURE__ */ React.createElement(HelpIcon, {
1534
- to: "https://backstage.io/docs/features/software-catalog/well-known-labels"
1535
- }))
1561
+ subheader: /* @__PURE__ */ React.createElement(ListSubheader, null, "Labels")
1536
1562
  }, Object.entries(metadata.labels).map((entry) => /* @__PURE__ */ React.createElement(KeyValueListItem, {
1537
1563
  key: entry[0],
1538
1564
  indent: true,
@@ -1953,20 +1979,20 @@ const UserListPicker = (props) => {
1953
1979
  filters,
1954
1980
  updateFilters,
1955
1981
  backendEntities,
1956
- queryParameters,
1982
+ queryParameters: { kind: kindParameter, user: userParameter },
1957
1983
  loading: loadingBackendEntities
1958
1984
  } = useEntityList();
1959
1985
  const userAndGroupFilterIds = ["starred", "all"];
1960
1986
  const filterGroups = getFilterGroups(orgName).map((filterGroup) => ({
1961
1987
  ...filterGroup,
1962
- items: filterGroup.items.filter(({ id }) => ["group", "user"].some((kind) => kind === queryParameters.kind) ? userAndGroupFilterIds.includes(id) : !availableFilters || availableFilters.includes(id))
1988
+ items: filterGroup.items.filter(({ id }) => ["group", "user"].some((kind) => kind === kindParameter) ? userAndGroupFilterIds.includes(id) : !availableFilters || availableFilters.includes(id))
1963
1989
  })).filter(({ items }) => !!items.length);
1964
1990
  const { isStarredEntity } = useStarredEntities();
1965
1991
  const { isOwnedEntity, loading: loadingEntityOwnership } = useEntityOwnership();
1966
1992
  const loading = loadingBackendEntities || loadingEntityOwnership;
1967
1993
  const ownedFilter = useMemo(() => new UserListFilter("owned", isOwnedEntity, isStarredEntity), [isOwnedEntity, isStarredEntity]);
1968
1994
  const starredFilter = useMemo(() => new UserListFilter("starred", isOwnedEntity, isStarredEntity), [isOwnedEntity, isStarredEntity]);
1969
- const queryParamUserFilter = useMemo(() => [queryParameters.user].flat()[0], [queryParameters]);
1995
+ const queryParamUserFilter = useMemo(() => [userParameter].flat()[0], [userParameter]);
1970
1996
  const [selectedUserFilter, setSelectedUserFilter] = useState(queryParamUserFilter != null ? queryParamUserFilter : initialFilter);
1971
1997
  const entitiesWithoutUserFilter = useMemo(() => backendEntities.filter(reduceEntityFilters(compact(Object.values({ ...filters, user: void 0 })))), [filters, backendEntities]);
1972
1998
  const filterCounts = useMemo(() => ({