@backstage/plugin-catalog-react 1.7.0-next.0 → 1.7.0-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,36 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.7.0-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d68692aee97e: Make `useRelatedEntities` use `getEntitiesByRefs` under the hood
8
+ - Updated dependencies
9
+ - @backstage/theme@0.4.0-next.1
10
+ - @backstage/core-components@0.13.2-next.2
11
+ - @backstage/core-plugin-api@1.5.2-next.0
12
+ - @backstage/plugin-permission-react@0.4.13-next.0
13
+
14
+ ## 1.7.0-next.1
15
+
16
+ ### Patch Changes
17
+
18
+ - 429319d080cd: `EntityAutocompletePicker` add `initialSelectedOptions` prop
19
+ - 429319d080cd: `EntityLifecycleFilter` loads data using the facets endpoint
20
+ - Updated dependencies
21
+ - @backstage/integration@1.5.0-next.0
22
+ - @backstage/errors@1.2.0-next.0
23
+ - @backstage/core-components@0.13.2-next.1
24
+ - @backstage/catalog-model@1.4.0-next.0
25
+ - @backstage/core-plugin-api@1.5.2-next.0
26
+ - @backstage/catalog-client@1.4.2-next.1
27
+ - @backstage/plugin-permission-common@0.7.6-next.0
28
+ - @backstage/plugin-catalog-common@1.0.14-next.0
29
+ - @backstage/theme@0.4.0-next.0
30
+ - @backstage/types@1.0.2
31
+ - @backstage/version-bridge@1.0.4
32
+ - @backstage/plugin-permission-react@0.4.13-next.0
33
+
3
34
  ## 1.7.0-next.0
4
35
 
5
36
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.7.0-next.0",
3
+ "version": "1.7.0-next.2",
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
@@ -91,7 +91,7 @@ type CatalogReactEntityLifecyclePickerClassKey = 'input';
91
91
  /** @public */
92
92
  declare const EntityLifecyclePicker: (props: {
93
93
  initialFilter?: string[];
94
- }) => JSX.Element | null;
94
+ }) => JSX.Element;
95
95
 
96
96
  /** @public */
97
97
  type CatalogReactEntityOwnerPickerClassKey = 'input';
@@ -569,7 +569,12 @@ declare function useEntityTypeFilter(): {
569
569
  setSelectedTypes: (types: string[]) => void;
570
570
  };
571
571
 
572
- /** @public */
572
+ /**
573
+ * Fetches all entities that appear in the entity's relations, optionally
574
+ * filtered by relation type and kind.
575
+ *
576
+ * @public
577
+ */
573
578
  declare function useRelatedEntities(entity: Entity, relationFilter: {
574
579
  type?: string;
575
580
  kind?: string;
package/dist/index.esm.js CHANGED
@@ -1,14 +1,14 @@
1
1
  export { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client';
2
2
  import { createApiRef, useApi, identityApiRef, alertApiRef, createRouteRef, useRouteRef, useApiHolder, useApp, configApiRef } from '@backstage/core-plugin-api';
3
3
  import ObservableImpl from 'zen-observable';
4
- import React, { useState, createContext, useMemo, useCallback, useContext, useEffect, useRef, forwardRef, memo, useLayoutEffect, Fragment } from 'react';
5
- import { Grid, useMediaQuery, useTheme, Button, Drawer, Box, Typography, makeStyles, FormControlLabel, Checkbox, 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';
4
+ import React, { useState, createContext, useMemo, useCallback, useContext, useEffect, useRef, memo, forwardRef, useLayoutEffect, Fragment } from 'react';
5
+ 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';
6
6
  import FilterListIcon from '@material-ui/icons/FilterList';
7
7
  import { Select, Link, Progress, ErrorPanel, ResponseErrorPanel, OverflowTooltip, Table, DependencyGraph, DependencyGraphTypes, CodeSnippet } from '@backstage/core-components';
8
8
  import { ANNOTATION_SOURCE_LOCATION, parseLocationRef, stringifyEntityRef, parseEntityRef, RELATION_OWNED_BY, DEFAULT_NAMESPACE, getCompoundEntityRef, isUserEntity, isGroupEntity, RELATION_PART_OF, ANNOTATION_LOCATION, ANNOTATION_ORIGIN_LOCATION } from '@backstage/catalog-model';
9
9
  import { g as getEntityRelations } from './esm/useEntity-de64059a.esm.js';
10
10
  export { A as AsyncEntityProvider, E as EntityProvider, g as getEntityRelations, a as useAsyncEntity, u as useEntity } from './esm/useEntity-de64059a.esm.js';
11
- import { compact, isEqual, groupBy, chunk, debounce } from 'lodash';
11
+ import { compact, isEqual, debounce } from 'lodash';
12
12
  import qs from 'qs';
13
13
  import { useLocation, useNavigate } from 'react-router-dom';
14
14
  import useAsyncFn from 'react-use/lib/useAsyncFn';
@@ -18,10 +18,11 @@ import useAsync from 'react-use/lib/useAsync';
18
18
  import isEqual$1 from 'lodash/isEqual';
19
19
  import sortBy from 'lodash/sortBy';
20
20
  import useObservable from 'react-use/lib/useObservable';
21
- import CheckBoxIcon from '@material-ui/icons/CheckBox';
22
- import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
23
21
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
24
22
  import { Autocomplete, Alert } from '@material-ui/lab';
23
+ import CheckBoxIcon from '@material-ui/icons/CheckBox';
24
+ import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
25
+ import classNames from 'classnames';
25
26
  import { useDebouncedEffect } from '@react-hookz/web';
26
27
  import PersonIcon from '@material-ui/icons/Person';
27
28
  import GroupIcon from '@material-ui/icons/Group';
@@ -33,12 +34,11 @@ import InfoIcon from '@material-ui/icons/Info';
33
34
  import EmailIcon from '@material-ui/icons/Email';
34
35
  import Clear from '@material-ui/icons/Clear';
35
36
  import Search from '@material-ui/icons/Search';
36
- import classNames from 'classnames';
37
37
  import Star from '@material-ui/icons/Star';
38
38
  import StarBorder from '@material-ui/icons/StarBorder';
39
39
  import WorkIcon from '@material-ui/icons/Work';
40
40
  import HelpOutlineIcon from '@material-ui/icons/HelpOutline';
41
- import groupBy$1 from 'lodash/groupBy';
41
+ import groupBy from 'lodash/groupBy';
42
42
  import DialogContentText$1 from '@material-ui/core/DialogContentText';
43
43
  import YAML from 'yaml';
44
44
  import Alert$1 from '@material-ui/lab/Alert';
@@ -489,7 +489,6 @@ function useEntityTypeFilter() {
489
489
  };
490
490
  }
491
491
 
492
- const BATCH_SIZE = 20;
493
492
  function useRelatedEntities(entity, relationFilter) {
494
493
  var _a, _b;
495
494
  const filterByTypeLower = (_a = relationFilter == null ? void 0 : relationFilter.type) == null ? void 0 : _a.toLocaleLowerCase("en-US");
@@ -501,43 +500,16 @@ function useRelatedEntities(entity, relationFilter) {
501
500
  error
502
501
  } = useAsync(async () => {
503
502
  var _a2;
504
- const relations = (_a2 = entity.relations) == null ? void 0 : _a2.map((r) => ({ type: r.type, target: parseEntityRef(r.targetRef) })).filter(
505
- (r) => (!filterByTypeLower || r.type.toLocaleLowerCase("en-US") === filterByTypeLower) && (!filterByKindLower || r.target.kind === filterByKindLower)
503
+ const relations = (_a2 = entity.relations) == null ? void 0 : _a2.filter(
504
+ (r) => (!filterByTypeLower || r.type.toLocaleLowerCase("en-US") === filterByTypeLower) && (!filterByKindLower || parseEntityRef(r.targetRef).kind === filterByKindLower)
506
505
  );
507
- if (!relations) {
506
+ if (!(relations == null ? void 0 : relations.length)) {
508
507
  return [];
509
508
  }
510
- const relationsByKindAndNamespace = Object.values(
511
- groupBy(relations, ({ target }) => {
512
- return `${target.kind}:${target.namespace}`.toLocaleLowerCase("en-US");
513
- })
514
- );
515
- const batchedRelationsByKindAndNamespace = [];
516
- for (const rs of relationsByKindAndNamespace) {
517
- batchedRelationsByKindAndNamespace.push({
518
- // All relations in a group have the same kind and namespace, so its arbitrary which we pick
519
- kind: rs[0].target.kind,
520
- namespace: rs[0].target.namespace,
521
- nameBatches: chunk(
522
- rs.map((r) => r.target.name),
523
- BATCH_SIZE
524
- )
525
- });
526
- }
527
- const results = await Promise.all(
528
- batchedRelationsByKindAndNamespace.flatMap((rs) => {
529
- return rs.nameBatches.map((names) => {
530
- return catalogApi.getEntities({
531
- filter: {
532
- kind: rs.kind,
533
- "metadata.namespace": rs.namespace,
534
- "metadata.name": names
535
- }
536
- });
537
- });
538
- })
539
- );
540
- return results.flatMap((r) => r.items);
509
+ const { items } = await catalogApi.getEntitiesByRefs({
510
+ entityRefs: relations.map((r) => r.targetRef)
511
+ });
512
+ return items.filter((x) => Boolean(x));
541
513
  }, [entity, filterByTypeLower, filterByKindLower]);
542
514
  return {
543
515
  entities,
@@ -726,91 +698,143 @@ const EntityKindPicker = (props) => {
726
698
  ));
727
699
  };
728
700
 
701
+ const icon$2 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
702
+ const checkedIcon$2 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
703
+ function OptionCheckbox({ selected }) {
704
+ return /* @__PURE__ */ React.createElement(Checkbox, { icon: icon$2, checkedIcon: checkedIcon$2, checked: selected });
705
+ }
706
+ const EntityAutocompletePickerOption = memo((props) => {
707
+ const { selected, value, availableOptions, showCounts } = props;
708
+ const label = showCounts ? `${value} (${availableOptions == null ? void 0 : availableOptions[value]})` : value;
709
+ return /* @__PURE__ */ React.createElement(
710
+ FormControlLabel,
711
+ {
712
+ control: /* @__PURE__ */ React.createElement(OptionCheckbox, { selected }),
713
+ label,
714
+ onClick: (event) => event.preventDefault()
715
+ }
716
+ );
717
+ });
718
+
729
719
  const useStyles$f = makeStyles(
730
720
  {
731
721
  input: {}
732
722
  },
733
723
  {
734
- name: "CatalogReactEntityLifecyclePicker"
724
+ name: "CatalogReactEntityAutocompletePickerInput"
735
725
  }
736
726
  );
737
- const icon$3 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
738
- const checkedIcon$3 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
739
- const EntityLifecyclePicker = (props) => {
740
- var _a, _b;
741
- const { initialFilter = [] } = props;
727
+ function EntityAutocompletePickerInput(params) {
742
728
  const classes = useStyles$f();
729
+ return /* @__PURE__ */ React.createElement(
730
+ TextField,
731
+ {
732
+ variant: "outlined",
733
+ ...params,
734
+ className: classNames(classes.input, params.className)
735
+ }
736
+ );
737
+ }
738
+
739
+ function EntityAutocompletePicker(props) {
740
+ var _a, _b;
741
+ const {
742
+ label,
743
+ name,
744
+ path,
745
+ showCounts,
746
+ Filter,
747
+ InputProps,
748
+ initialSelectedOptions = []
749
+ } = props;
743
750
  const {
744
751
  updateFilters,
745
- backendEntities,
746
752
  filters,
747
- queryParameters: { lifecycles: lifecyclesParameter }
753
+ queryParameters: { [name]: queryParameter }
748
754
  } = useEntityList();
749
- const queryParamLifecycles = useMemo(
750
- () => [lifecyclesParameter].flat().filter(Boolean),
751
- [lifecyclesParameter]
755
+ const catalogApi = useApi(catalogApiRef);
756
+ const { value: availableValues } = useAsync(async () => {
757
+ var _a2;
758
+ const facet = path;
759
+ const { facets } = await catalogApi.getEntityFacets({
760
+ facets: [facet],
761
+ filter: (_a2 = filters.kind) == null ? void 0 : _a2.getCatalogFilters()
762
+ });
763
+ return Object.fromEntries(
764
+ facets[facet].map(({ value, count }) => [value, count])
765
+ );
766
+ }, [filters.kind]);
767
+ const queryParameters = useMemo(
768
+ () => [queryParameter].flat().filter(Boolean),
769
+ [queryParameter]
752
770
  );
753
- const [selectedLifecycles, setSelectedLifecycles] = useState(
754
- queryParamLifecycles.length ? queryParamLifecycles : (_b = (_a = filters.lifecycles) == null ? void 0 : _a.values) != null ? _b : initialFilter
771
+ const [selectedOptions, setSelectedOptions] = useState(
772
+ queryParameters.length ? queryParameters : (_b = (_a = filters[name]) == null ? void 0 : _a.values) != null ? _b : initialSelectedOptions
755
773
  );
756
774
  useEffect(() => {
757
- if (queryParamLifecycles.length) {
758
- setSelectedLifecycles(queryParamLifecycles);
775
+ if (queryParameters.length) {
776
+ setSelectedOptions(queryParameters);
759
777
  }
760
- }, [queryParamLifecycles]);
761
- const availableLifecycles = useMemo(
762
- () => [
763
- ...new Set(
764
- backendEntities.map((e) => {
765
- var _a2;
766
- return (_a2 = e.spec) == null ? void 0 : _a2.lifecycle;
767
- }).filter(Boolean)
768
- )
769
- ].sort(),
770
- [backendEntities]
771
- );
778
+ }, [queryParameters]);
779
+ const availableOptions = Object.keys(availableValues != null ? availableValues : {});
780
+ const shouldAddFilter = selectedOptions.length && availableOptions.length;
772
781
  useEffect(() => {
773
782
  updateFilters({
774
- lifecycles: selectedLifecycles.length && availableLifecycles.length ? new EntityLifecycleFilter(selectedLifecycles) : void 0
783
+ [name]: shouldAddFilter ? new Filter(selectedOptions) : void 0
775
784
  });
776
- }, [selectedLifecycles, updateFilters, availableLifecycles]);
777
- if (!availableLifecycles.length)
785
+ }, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);
786
+ const filter = filters[name];
787
+ if (filter && typeof filter === "object" && !("values" in filter) || !availableOptions.length) {
788
+ return null;
789
+ }
790
+ if (availableOptions.length <= 1)
778
791
  return null;
779
- return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button", component: "label" }, "Lifecycle", /* @__PURE__ */ React.createElement(
792
+ return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button", component: "label" }, label, /* @__PURE__ */ React.createElement(
780
793
  Autocomplete,
781
794
  {
782
795
  multiple: true,
783
796
  disableCloseOnSelect: true,
784
- options: availableLifecycles,
785
- value: selectedLifecycles,
786
- onChange: (_, value) => setSelectedLifecycles(value),
797
+ options: availableOptions,
798
+ value: selectedOptions,
799
+ onChange: (_event, options) => setSelectedOptions(options),
787
800
  renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
788
- FormControlLabel,
801
+ EntityAutocompletePickerOption,
789
802
  {
790
- control: /* @__PURE__ */ React.createElement(
791
- Checkbox,
792
- {
793
- icon: icon$3,
794
- checkedIcon: checkedIcon$3,
795
- checked: selected
796
- }
797
- ),
798
- onClick: (event) => event.preventDefault(),
799
- label: option
803
+ selected,
804
+ value: option,
805
+ availableOptions: availableValues,
806
+ showCounts: !!showCounts
800
807
  }
801
808
  ),
802
809
  size: "small",
803
- popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { "data-testid": "lifecycle-picker-expand" }),
804
- renderInput: (params) => /* @__PURE__ */ React.createElement(
805
- TextField,
806
- {
807
- ...params,
808
- className: classes.input,
809
- variant: "outlined"
810
- }
811
- )
810
+ popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { "data-testid": `${String(name)}-picker-expand` }),
811
+ renderInput: (params) => /* @__PURE__ */ React.createElement(EntityAutocompletePickerInput, { ...params, ...InputProps })
812
812
  }
813
813
  )));
814
+ }
815
+
816
+ const useStyles$e = makeStyles(
817
+ {
818
+ input: {}
819
+ },
820
+ {
821
+ name: "CatalogReactEntityLifecyclePicker"
822
+ }
823
+ );
824
+ const EntityLifecyclePicker = (props) => {
825
+ const { initialFilter = [] } = props;
826
+ const classes = useStyles$e();
827
+ return /* @__PURE__ */ React.createElement(
828
+ EntityAutocompletePicker,
829
+ {
830
+ label: "Lifecycle",
831
+ name: "lifecycles",
832
+ path: "spec.lifecycle",
833
+ Filter: EntityLifecycleFilter,
834
+ InputProps: { className: classes.input },
835
+ initialSelectedOptions: initialFilter
836
+ }
837
+ );
814
838
  };
815
839
 
816
840
  function humanizeEntityRef(entityRef, opts) {
@@ -851,7 +875,7 @@ function humanizeEntity(entity, defaultName) {
851
875
  return defaultName;
852
876
  }
853
877
 
854
- const useStyles$e = makeStyles(
878
+ const useStyles$d = makeStyles(
855
879
  {
856
880
  input: {}
857
881
  },
@@ -859,11 +883,11 @@ const useStyles$e = makeStyles(
859
883
  name: "CatalogReactEntityOwnerPicker"
860
884
  }
861
885
  );
862
- const icon$2 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
863
- const checkedIcon$2 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
886
+ const icon$1 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
887
+ const checkedIcon$1 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
864
888
  const EntityOwnerPicker = () => {
865
889
  var _a, _b, _c;
866
- const classes = useStyles$e();
890
+ const classes = useStyles$d();
867
891
  const {
868
892
  updateFilters,
869
893
  filters,
@@ -968,8 +992,8 @@ const EntityOwnerPicker = () => {
968
992
  control: /* @__PURE__ */ React.createElement(
969
993
  Checkbox,
970
994
  {
971
- icon: icon$2,
972
- checkedIcon: checkedIcon$2,
995
+ icon: icon$1,
996
+ checkedIcon: checkedIcon$1,
973
997
  checked: selected
974
998
  }
975
999
  ),
@@ -1195,7 +1219,7 @@ const UserCardActions = (props) => {
1195
1219
  return email ? /* @__PURE__ */ React.createElement(EmailCardAction, { email }) : null;
1196
1220
  };
1197
1221
 
1198
- const useStyles$d = makeStyles(() => {
1222
+ const useStyles$c = makeStyles(() => {
1199
1223
  return {
1200
1224
  popoverPaper: {
1201
1225
  width: "30em"
@@ -1213,7 +1237,7 @@ const maxTagChips = 4;
1213
1237
  const EntityPeekAheadPopover = (props) => {
1214
1238
  var _a, _b, _c;
1215
1239
  const { entityRef, children, delayTime = 500 } = props;
1216
- const classes = useStyles$d();
1240
+ const classes = useStyles$c();
1217
1241
  const apiHolder = useApiHolder();
1218
1242
  const popupState = usePopupState({
1219
1243
  variant: "popover",
@@ -1282,7 +1306,7 @@ const EntityPeekAheadPopover = (props) => {
1282
1306
  ));
1283
1307
  };
1284
1308
 
1285
- const useStyles$c = makeStyles(
1309
+ const useStyles$b = makeStyles(
1286
1310
  (_theme) => ({
1287
1311
  searchToolbar: {
1288
1312
  paddingLeft: 0,
@@ -1296,7 +1320,7 @@ const useStyles$c = makeStyles(
1296
1320
  );
1297
1321
  const EntitySearchBar = () => {
1298
1322
  var _a, _b;
1299
- const classes = useStyles$c();
1323
+ const classes = useStyles$b();
1300
1324
  const { filters, updateFilters } = useEntityList();
1301
1325
  const [search, setSearch] = useState((_b = (_a = filters.text) == null ? void 0 : _a.value) != null ? _b : "");
1302
1326
  useDebounce(
@@ -1461,7 +1485,7 @@ const componentEntityColumns = [
1461
1485
  columnFactories.createMetadataDescriptionColumn()
1462
1486
  ];
1463
1487
 
1464
- const useStyles$b = makeStyles((theme) => ({
1488
+ const useStyles$a = makeStyles((theme) => ({
1465
1489
  empty: {
1466
1490
  padding: theme.spacing(2),
1467
1491
  display: "flex",
@@ -1476,7 +1500,7 @@ const EntityTable = (props) => {
1476
1500
  variant = "gridItem",
1477
1501
  columns
1478
1502
  } = props;
1479
- const classes = useStyles$b();
1503
+ const classes = useStyles$a();
1480
1504
  const tableStyle = {
1481
1505
  minWidth: "0",
1482
1506
  width: "100%"
@@ -1507,113 +1531,6 @@ EntityTable.columns = columnFactories;
1507
1531
  EntityTable.systemEntityColumns = systemEntityColumns;
1508
1532
  EntityTable.componentEntityColumns = componentEntityColumns;
1509
1533
 
1510
- const icon$1 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
1511
- const checkedIcon$1 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
1512
- function OptionCheckbox({ selected }) {
1513
- return /* @__PURE__ */ React.createElement(Checkbox, { icon: icon$1, checkedIcon: checkedIcon$1, checked: selected });
1514
- }
1515
- const EntityAutocompletePickerOption = memo((props) => {
1516
- const { selected, value, availableOptions, showCounts } = props;
1517
- const label = showCounts ? `${value} (${availableOptions == null ? void 0 : availableOptions[value]})` : value;
1518
- return /* @__PURE__ */ React.createElement(
1519
- FormControlLabel,
1520
- {
1521
- control: /* @__PURE__ */ React.createElement(OptionCheckbox, { selected }),
1522
- label,
1523
- onClick: (event) => event.preventDefault()
1524
- }
1525
- );
1526
- });
1527
-
1528
- const useStyles$a = makeStyles(
1529
- {
1530
- input: {}
1531
- },
1532
- {
1533
- name: "CatalogReactEntityAutocompletePickerInput"
1534
- }
1535
- );
1536
- function EntityAutocompletePickerInput(params) {
1537
- const classes = useStyles$a();
1538
- return /* @__PURE__ */ React.createElement(
1539
- TextField,
1540
- {
1541
- variant: "outlined",
1542
- ...params,
1543
- className: classNames(classes.input, params.className)
1544
- }
1545
- );
1546
- }
1547
-
1548
- function EntityAutocompletePicker(props) {
1549
- var _a, _b;
1550
- const { label, name, path, showCounts, Filter, InputProps } = props;
1551
- const {
1552
- updateFilters,
1553
- filters,
1554
- queryParameters: { [name]: queryParameter }
1555
- } = useEntityList();
1556
- const catalogApi = useApi(catalogApiRef);
1557
- const { value: availableValues } = useAsync(async () => {
1558
- var _a2;
1559
- const facet = path;
1560
- const { facets } = await catalogApi.getEntityFacets({
1561
- facets: [facet],
1562
- filter: (_a2 = filters.kind) == null ? void 0 : _a2.getCatalogFilters()
1563
- });
1564
- return Object.fromEntries(
1565
- facets[facet].map(({ value, count }) => [value, count])
1566
- );
1567
- }, [filters.kind]);
1568
- const queryParameters = useMemo(
1569
- () => [queryParameter].flat().filter(Boolean),
1570
- [queryParameter]
1571
- );
1572
- const [selectedOptions, setSelectedOptions] = useState(
1573
- queryParameters.length ? queryParameters : (_b = (_a = filters[name]) == null ? void 0 : _a.values) != null ? _b : []
1574
- );
1575
- useEffect(() => {
1576
- if (queryParameters.length) {
1577
- setSelectedOptions(queryParameters);
1578
- }
1579
- }, [queryParameters]);
1580
- const availableOptions = Object.keys(availableValues != null ? availableValues : {});
1581
- const shouldAddFilter = selectedOptions.length && availableOptions.length;
1582
- useEffect(() => {
1583
- updateFilters({
1584
- [name]: shouldAddFilter ? new Filter(selectedOptions) : void 0
1585
- });
1586
- }, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);
1587
- const filter = filters[name];
1588
- if (filter && typeof filter === "object" && !("values" in filter) || !availableOptions.length) {
1589
- return null;
1590
- }
1591
- if (availableOptions.length <= 1)
1592
- return null;
1593
- return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button", component: "label" }, label, /* @__PURE__ */ React.createElement(
1594
- Autocomplete,
1595
- {
1596
- multiple: true,
1597
- disableCloseOnSelect: true,
1598
- options: availableOptions,
1599
- value: selectedOptions,
1600
- onChange: (_event, options) => setSelectedOptions(options),
1601
- renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
1602
- EntityAutocompletePickerOption,
1603
- {
1604
- selected,
1605
- value: option,
1606
- availableOptions: availableValues,
1607
- showCounts: !!showCounts
1608
- }
1609
- ),
1610
- size: "small",
1611
- popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { "data-testid": `${String(name)}-picker-expand` }),
1612
- renderInput: (params) => /* @__PURE__ */ React.createElement(EntityAutocompletePickerInput, { ...params, ...InputProps })
1613
- }
1614
- )));
1615
- }
1616
-
1617
1534
  const useStyles$9 = makeStyles(
1618
1535
  { input: {} },
1619
1536
  { name: "CatalogReactEntityTagPicker" }
@@ -2051,7 +1968,7 @@ function OverviewPage(props) {
2051
1968
  relations = [],
2052
1969
  status = {}
2053
1970
  } = props.entity;
2054
- const groupedRelations = groupBy$1(
1971
+ const groupedRelations = groupBy(
2055
1972
  sortBy(relations, (r) => r.targetRef),
2056
1973
  "type"
2057
1974
  );