@backstage/plugin-catalog-react 1.9.0 → 1.9.2-next.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,28 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.9.2-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 8587f067d2: Added pagination support to `EntityListProvider`.
8
+ - aaa6fb3bc9: Minor updates for TypeScript 5.2.2+ compatibility
9
+ - 4d9e3b39e4: Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`.
10
+ - eee0ff2946: Fixed a issue where `CatalogPage` wasn't using the chosen `initiallySelectedFilter` as intended.
11
+ - Updated dependencies
12
+ - @backstage/core-plugin-api@1.8.1-next.0
13
+ - @backstage/core-components@0.13.9-next.0
14
+ - @backstage/theme@0.5.0-next.0
15
+ - @backstage/frontend-plugin-api@0.3.1-next.0
16
+ - @backstage/integration-react@1.1.22-next.0
17
+ - @backstage/plugin-permission-react@0.4.18-next.0
18
+ - @backstage/catalog-client@1.4.6
19
+ - @backstage/catalog-model@1.4.3
20
+ - @backstage/errors@1.2.3
21
+ - @backstage/types@1.1.1
22
+ - @backstage/version-bridge@1.0.7
23
+ - @backstage/plugin-catalog-common@1.0.18
24
+ - @backstage/plugin-permission-common@0.7.10
25
+
3
26
  ## 1.9.0
4
27
 
5
28
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.9.0",
3
+ "version": "1.9.2-next.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
@@ -678,17 +678,29 @@ type EntityListContextProps<EntityFilters extends DefaultEntityFilters = Default
678
678
  queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;
679
679
  loading: boolean;
680
680
  error?: Error;
681
+ pageInfo?: {
682
+ next?: () => void;
683
+ prev?: () => void;
684
+ };
681
685
  };
682
686
  /**
683
687
  * Creates new context for entity listing and filtering.
684
688
  * @public
685
689
  */
686
690
  declare const EntityListContext: React.Context<EntityListContextProps<any> | undefined>;
691
+ /**
692
+ * @public
693
+ */
694
+ type EntityListProviderProps = PropsWithChildren<{
695
+ pagination?: boolean | {
696
+ limit?: number;
697
+ };
698
+ }>;
687
699
  /**
688
700
  * Provides entities and filters for a catalog listing.
689
701
  * @public
690
702
  */
691
- declare const EntityListProvider: <EntityFilters extends DefaultEntityFilters>(props: PropsWithChildren<{}>) => React.JSX.Element;
703
+ declare const EntityListProvider: <EntityFilters extends DefaultEntityFilters>(props: EntityListProviderProps) => React.JSX.Element;
692
704
  /**
693
705
  * Hook for interacting with the entity list context provided by the {@link EntityListProvider}.
694
706
  * @public
@@ -883,6 +895,10 @@ type CatalogReactComponentsNameToClassKey = {
883
895
  type BackstageOverrides = Overrides & {
884
896
  [Name in keyof CatalogReactComponentsNameToClassKey]?: Partial<StyleRules<CatalogReactComponentsNameToClassKey[Name]>>;
885
897
  };
898
+ declare module '@backstage/theme' {
899
+ interface OverrideComponentNameToClassKeys extends CatalogReactComponentsNameToClassKey {
900
+ }
901
+ }
886
902
 
887
903
  /**
888
904
  * Get the related entity references.
@@ -901,4 +917,4 @@ type EntitySourceLocation = {
901
917
  /** @public */
902
918
  declare function getEntitySourceLocation(entity: Entity, scmIntegrationsApi: typeof scmIntegrationsApiRef.T): EntitySourceLocation | undefined;
903
919
 
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 };
920
+ 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, EntityListProviderProps, 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
@@ -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';
@@ -560,21 +561,26 @@ const EntityListProvider = (props) => {
560
561
  {}
561
562
  );
562
563
  const location = useLocation();
563
- const queryParameters = useMemo(
564
- () => {
565
- var _a;
566
- return (_a = qs.parse(location.search, {
567
- ignoreQueryPrefix: true
568
- }).filters) != null ? _a : {};
569
- },
570
- [location]
571
- );
564
+ const enablePagination = props.pagination === true || typeof props.pagination === "object";
565
+ const limit = props.pagination && typeof props.pagination === "object" && typeof props.pagination.limit === "number" ? props.pagination.limit : 20;
566
+ const { queryParameters, cursor: initialCursor } = useMemo(() => {
567
+ var _a;
568
+ const parsed = qs.parse(location.search, {
569
+ ignoreQueryPrefix: true
570
+ });
571
+ return {
572
+ queryParameters: (_a = parsed.filters) != null ? _a : {},
573
+ cursor: typeof parsed.cursor === "string" ? parsed.cursor : void 0
574
+ };
575
+ }, [location]);
576
+ const [cursor, setCursor] = useState(initialCursor);
572
577
  const [outputState, setOutputState] = useState(
573
578
  () => {
574
579
  return {
575
580
  appliedFilters: {},
576
581
  entities: [],
577
- backendEntities: []
582
+ backendEntities: [],
583
+ pageInfo: enablePagination ? {} : void 0
578
584
  };
579
585
  }
580
586
  );
@@ -582,11 +588,6 @@ const EntityListProvider = (props) => {
582
588
  async () => {
583
589
  var _a;
584
590
  const compacted = compact(Object.values(requestedFilters));
585
- const entityFilter = reduceEntityFilters(compacted);
586
- const backendFilter = reduceBackendCatalogFilters(compacted);
587
- const previousBackendFilter = reduceBackendCatalogFilters(
588
- compact(Object.values(outputState.appliedFilters))
589
- );
590
591
  const queryParams = Object.keys(requestedFilters).reduce(
591
592
  (params, key) => {
592
593
  const filter = requestedFilters[key];
@@ -597,40 +598,91 @@ const EntityListProvider = (props) => {
597
598
  },
598
599
  {}
599
600
  );
600
- if (!isEqual(previousBackendFilter, backendFilter)) {
601
- const response = await catalogApi.getEntities({
602
- filter: backendFilter
603
- });
604
- setOutputState({
605
- appliedFilters: requestedFilters,
606
- backendEntities: response.items,
607
- entities: response.items.filter(entityFilter)
608
- });
601
+ if (enablePagination) {
602
+ if (cursor) {
603
+ if (cursor !== outputState.appliedCursor) {
604
+ const entityFilter = reduceEntityFilters(compacted);
605
+ const response = await catalogApi.queryEntities({
606
+ cursor,
607
+ limit
608
+ });
609
+ setOutputState({
610
+ appliedFilters: requestedFilters,
611
+ appliedCursor: cursor,
612
+ backendEntities: response.items,
613
+ entities: response.items.filter(entityFilter),
614
+ pageInfo: response.pageInfo
615
+ });
616
+ }
617
+ } else {
618
+ const entityFilter = reduceEntityFilters(compacted);
619
+ const backendFilter = reduceCatalogFilters(compacted);
620
+ const previousBackendFilter = reduceCatalogFilters(
621
+ compact(Object.values(outputState.appliedFilters))
622
+ );
623
+ if (!isEqual(previousBackendFilter, backendFilter)) {
624
+ const response = await catalogApi.queryEntities({
625
+ filter: backendFilter,
626
+ limit,
627
+ orderFields: [{ field: "metadata.name", order: "asc" }]
628
+ });
629
+ setOutputState({
630
+ appliedFilters: requestedFilters,
631
+ backendEntities: response.items,
632
+ entities: response.items.filter(entityFilter),
633
+ pageInfo: response.pageInfo
634
+ });
635
+ }
636
+ }
609
637
  } else {
610
- setOutputState({
611
- appliedFilters: requestedFilters,
612
- backendEntities: outputState.backendEntities,
613
- entities: outputState.backendEntities.filter(entityFilter)
614
- });
638
+ const entityFilter = reduceEntityFilters(compacted);
639
+ const backendFilter = reduceBackendCatalogFilters(compacted);
640
+ const previousBackendFilter = reduceBackendCatalogFilters(
641
+ compact(Object.values(outputState.appliedFilters))
642
+ );
643
+ if (!isEqual(previousBackendFilter, backendFilter)) {
644
+ const response = await catalogApi.getEntities({
645
+ filter: backendFilter
646
+ });
647
+ setOutputState({
648
+ appliedFilters: requestedFilters,
649
+ backendEntities: response.items,
650
+ entities: response.items.filter(entityFilter)
651
+ });
652
+ } else {
653
+ setOutputState({
654
+ appliedFilters: requestedFilters,
655
+ backendEntities: outputState.backendEntities,
656
+ entities: outputState.backendEntities.filter(entityFilter)
657
+ });
658
+ }
615
659
  }
616
660
  if (isMounted()) {
617
661
  const oldParams = qs.parse(location.search, {
618
662
  ignoreQueryPrefix: true
619
663
  });
620
664
  const newParams = qs.stringify(
621
- { ...oldParams, filters: queryParams },
665
+ { ...oldParams, filters: queryParams, cursor },
622
666
  { addQueryPrefix: true, arrayFormat: "repeat" }
623
667
  );
624
668
  const newUrl = `${window.location.pathname}${newParams}`;
625
669
  (_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
626
670
  }
627
671
  },
628
- [catalogApi, queryParameters, requestedFilters, outputState],
672
+ [
673
+ catalogApi,
674
+ queryParameters,
675
+ requestedFilters,
676
+ outputState,
677
+ cursor,
678
+ enablePagination
679
+ ],
629
680
  { loading: true }
630
681
  );
631
- useDebounce(refresh, 10, [requestedFilters]);
682
+ useDebounce(refresh, 10, [requestedFilters, cursor]);
632
683
  const updateFilters = useCallback(
633
684
  (update) => {
685
+ setCursor(void 0);
634
686
  setRequestedFilters((prevFilters) => {
635
687
  const newFilters = typeof update === "function" ? update(prevFilters) : update;
636
688
  return { ...prevFilters, ...newFilters };
@@ -638,6 +690,18 @@ const EntityListProvider = (props) => {
638
690
  },
639
691
  []
640
692
  );
693
+ const pageInfo = useMemo(() => {
694
+ var _a, _b;
695
+ if (!enablePagination) {
696
+ return void 0;
697
+ }
698
+ const prevCursor = (_a = outputState.pageInfo) == null ? void 0 : _a.prevCursor;
699
+ const nextCursor = (_b = outputState.pageInfo) == null ? void 0 : _b.nextCursor;
700
+ return {
701
+ prev: prevCursor ? () => setCursor(prevCursor) : void 0,
702
+ next: nextCursor ? () => setCursor(nextCursor) : void 0
703
+ };
704
+ }, [enablePagination, outputState.pageInfo]);
641
705
  const value = useMemo(
642
706
  () => ({
643
707
  filters: outputState.appliedFilters,
@@ -646,9 +710,10 @@ const EntityListProvider = (props) => {
646
710
  updateFilters,
647
711
  queryParameters,
648
712
  loading,
649
- error
713
+ error,
714
+ pageInfo
650
715
  }),
651
- [outputState, updateFilters, queryParameters, loading, error]
716
+ [outputState, updateFilters, queryParameters, loading, error, pageInfo]
652
717
  );
653
718
  return /* @__PURE__ */ React.createElement(EntityListContext.Provider, { value }, props.children);
654
719
  };
@@ -2671,58 +2736,48 @@ function useOwnedEntitiesCount() {
2671
2736
  // load only on mount
2672
2737
  []
2673
2738
  );
2674
- const prevRequest = useRef();
2675
- const request = useMemo(() => {
2676
- const { user, owners, ...allFilters } = filters;
2677
- const compacted = compact(Object.values(allFilters));
2678
- const allFilter = reduceCatalogFilters(compacted);
2679
- const { ["metadata.name"]: metadata, ...filter2 } = allFilter;
2680
- const countFilter = getOwnedCountClaims(owners, ownershipEntityRefs);
2681
- if ((ownershipEntityRefs == null ? void 0 : ownershipEntityRefs.length) === 0 || countFilter === void 0 || Object.keys(filter2).length === 0) {
2682
- prevRequest.current = void 0;
2683
- return void 0;
2684
- }
2685
- const newRequest = {
2686
- filter: {
2687
- ...filter2,
2688
- "relations.ownedBy": countFilter
2689
- },
2690
- limit: 0
2691
- };
2692
- if (isEqual(newRequest, prevRequest.current)) {
2693
- return prevRequest.current;
2694
- }
2695
- prevRequest.current = newRequest;
2696
- return newRequest;
2697
- }, [filters, ownershipEntityRefs]);
2739
+ const { user, owners, ...allFilters } = filters;
2740
+ const { ["metadata.name"]: metadata, ...filter } = reduceCatalogFilters(
2741
+ compact(Object.values(allFilters))
2742
+ );
2698
2743
  const [{ value: count, loading: loadingEntityOwnership }, fetchEntities] = useAsyncFn(
2699
- async (req, ownershipEntityRefsParam) => {
2700
- if (ownershipEntityRefsParam && !req) {
2744
+ async (req) => {
2745
+ const ownedClaims = getOwnedCountClaims(
2746
+ req.owners,
2747
+ req.ownershipEntityRefs
2748
+ );
2749
+ if (ownedClaims === void 0) {
2701
2750
  return 0;
2702
2751
  }
2703
- const { totalItems } = await catalogApi.queryEntities(req);
2752
+ const { totalItems } = await catalogApi.queryEntities({
2753
+ filter: {
2754
+ ...req.filter,
2755
+ "relations.ownedBy": ownedClaims
2756
+ },
2757
+ limit: 0
2758
+ });
2704
2759
  return totalItems;
2705
2760
  },
2706
2761
  [],
2707
2762
  { loading: true }
2708
2763
  );
2709
- useEffect(() => {
2710
- if (ownershipEntityRefs) {
2711
- if (request && Object.keys(request).length === 0) {
2712
- return;
2713
- }
2714
- fetchEntities(request, ownershipEntityRefs);
2764
+ useDeepCompareEffect(() => {
2765
+ if (Object.keys(filter).length === 0) {
2766
+ return;
2715
2767
  }
2716
- }, [fetchEntities, request, ownershipEntityRefs]);
2768
+ if (ownershipEntityRefs === void 0) {
2769
+ return;
2770
+ }
2771
+ fetchEntities({ ownershipEntityRefs, owners, filter });
2772
+ }, [ownershipEntityRefs, owners, filter]);
2717
2773
  const loading = loadingEntityRefs || loadingEntityOwnership;
2718
- const filter = useMemo(
2719
- () => EntityUserFilter.owned(ownershipEntityRefs != null ? ownershipEntityRefs : []),
2720
- [ownershipEntityRefs]
2721
- );
2722
2774
  return {
2723
2775
  count,
2724
2776
  loading,
2725
- filter,
2777
+ filter: useMemo(
2778
+ () => EntityUserFilter.owned(ownershipEntityRefs != null ? ownershipEntityRefs : []),
2779
+ [ownershipEntityRefs]
2780
+ ),
2726
2781
  ownershipEntityRefs
2727
2782
  };
2728
2783
  }