@backstage/plugin-catalog-react 1.7.0-next.0 → 1.7.0-next.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,25 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.7.0-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 429319d080cd: `EntityAutocompletePicker` add `initialSelectedOptions` prop
8
+ - 429319d080cd: `EntityLifecycleFilter` loads data using the facets endpoint
9
+ - Updated dependencies
10
+ - @backstage/integration@1.5.0-next.0
11
+ - @backstage/errors@1.2.0-next.0
12
+ - @backstage/core-components@0.13.2-next.1
13
+ - @backstage/catalog-model@1.4.0-next.0
14
+ - @backstage/core-plugin-api@1.5.2-next.0
15
+ - @backstage/catalog-client@1.4.2-next.1
16
+ - @backstage/plugin-permission-common@0.7.6-next.0
17
+ - @backstage/plugin-catalog-common@1.0.14-next.0
18
+ - @backstage/theme@0.4.0-next.0
19
+ - @backstage/types@1.0.2
20
+ - @backstage/version-bridge@1.0.4
21
+ - @backstage/plugin-permission-react@0.4.13-next.0
22
+
3
23
  ## 1.7.0-next.0
4
24
 
5
25
  ### 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.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
@@ -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';
package/dist/index.esm.js CHANGED
@@ -1,8 +1,8 @@
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';
@@ -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,7 +34,6 @@ 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';
@@ -726,91 +726,143 @@ const EntityKindPicker = (props) => {
726
726
  ));
727
727
  };
728
728
 
729
+ const icon$2 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
730
+ const checkedIcon$2 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
731
+ function OptionCheckbox({ selected }) {
732
+ return /* @__PURE__ */ React.createElement(Checkbox, { icon: icon$2, checkedIcon: checkedIcon$2, checked: selected });
733
+ }
734
+ const EntityAutocompletePickerOption = memo((props) => {
735
+ const { selected, value, availableOptions, showCounts } = props;
736
+ const label = showCounts ? `${value} (${availableOptions == null ? void 0 : availableOptions[value]})` : value;
737
+ return /* @__PURE__ */ React.createElement(
738
+ FormControlLabel,
739
+ {
740
+ control: /* @__PURE__ */ React.createElement(OptionCheckbox, { selected }),
741
+ label,
742
+ onClick: (event) => event.preventDefault()
743
+ }
744
+ );
745
+ });
746
+
729
747
  const useStyles$f = makeStyles(
730
748
  {
731
749
  input: {}
732
750
  },
733
751
  {
734
- name: "CatalogReactEntityLifecyclePicker"
752
+ name: "CatalogReactEntityAutocompletePickerInput"
735
753
  }
736
754
  );
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;
755
+ function EntityAutocompletePickerInput(params) {
742
756
  const classes = useStyles$f();
757
+ return /* @__PURE__ */ React.createElement(
758
+ TextField,
759
+ {
760
+ variant: "outlined",
761
+ ...params,
762
+ className: classNames(classes.input, params.className)
763
+ }
764
+ );
765
+ }
766
+
767
+ function EntityAutocompletePicker(props) {
768
+ var _a, _b;
769
+ const {
770
+ label,
771
+ name,
772
+ path,
773
+ showCounts,
774
+ Filter,
775
+ InputProps,
776
+ initialSelectedOptions = []
777
+ } = props;
743
778
  const {
744
779
  updateFilters,
745
- backendEntities,
746
780
  filters,
747
- queryParameters: { lifecycles: lifecyclesParameter }
781
+ queryParameters: { [name]: queryParameter }
748
782
  } = useEntityList();
749
- const queryParamLifecycles = useMemo(
750
- () => [lifecyclesParameter].flat().filter(Boolean),
751
- [lifecyclesParameter]
783
+ const catalogApi = useApi(catalogApiRef);
784
+ const { value: availableValues } = useAsync(async () => {
785
+ var _a2;
786
+ const facet = path;
787
+ const { facets } = await catalogApi.getEntityFacets({
788
+ facets: [facet],
789
+ filter: (_a2 = filters.kind) == null ? void 0 : _a2.getCatalogFilters()
790
+ });
791
+ return Object.fromEntries(
792
+ facets[facet].map(({ value, count }) => [value, count])
793
+ );
794
+ }, [filters.kind]);
795
+ const queryParameters = useMemo(
796
+ () => [queryParameter].flat().filter(Boolean),
797
+ [queryParameter]
752
798
  );
753
- const [selectedLifecycles, setSelectedLifecycles] = useState(
754
- queryParamLifecycles.length ? queryParamLifecycles : (_b = (_a = filters.lifecycles) == null ? void 0 : _a.values) != null ? _b : initialFilter
799
+ const [selectedOptions, setSelectedOptions] = useState(
800
+ queryParameters.length ? queryParameters : (_b = (_a = filters[name]) == null ? void 0 : _a.values) != null ? _b : initialSelectedOptions
755
801
  );
756
802
  useEffect(() => {
757
- if (queryParamLifecycles.length) {
758
- setSelectedLifecycles(queryParamLifecycles);
803
+ if (queryParameters.length) {
804
+ setSelectedOptions(queryParameters);
759
805
  }
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
- );
806
+ }, [queryParameters]);
807
+ const availableOptions = Object.keys(availableValues != null ? availableValues : {});
808
+ const shouldAddFilter = selectedOptions.length && availableOptions.length;
772
809
  useEffect(() => {
773
810
  updateFilters({
774
- lifecycles: selectedLifecycles.length && availableLifecycles.length ? new EntityLifecycleFilter(selectedLifecycles) : void 0
811
+ [name]: shouldAddFilter ? new Filter(selectedOptions) : void 0
775
812
  });
776
- }, [selectedLifecycles, updateFilters, availableLifecycles]);
777
- if (!availableLifecycles.length)
813
+ }, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);
814
+ const filter = filters[name];
815
+ if (filter && typeof filter === "object" && !("values" in filter) || !availableOptions.length) {
816
+ return null;
817
+ }
818
+ if (availableOptions.length <= 1)
778
819
  return null;
779
- return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button", component: "label" }, "Lifecycle", /* @__PURE__ */ React.createElement(
820
+ return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button", component: "label" }, label, /* @__PURE__ */ React.createElement(
780
821
  Autocomplete,
781
822
  {
782
823
  multiple: true,
783
824
  disableCloseOnSelect: true,
784
- options: availableLifecycles,
785
- value: selectedLifecycles,
786
- onChange: (_, value) => setSelectedLifecycles(value),
825
+ options: availableOptions,
826
+ value: selectedOptions,
827
+ onChange: (_event, options) => setSelectedOptions(options),
787
828
  renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
788
- FormControlLabel,
829
+ EntityAutocompletePickerOption,
789
830
  {
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
831
+ selected,
832
+ value: option,
833
+ availableOptions: availableValues,
834
+ showCounts: !!showCounts
800
835
  }
801
836
  ),
802
837
  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
- )
838
+ popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, { "data-testid": `${String(name)}-picker-expand` }),
839
+ renderInput: (params) => /* @__PURE__ */ React.createElement(EntityAutocompletePickerInput, { ...params, ...InputProps })
812
840
  }
813
841
  )));
842
+ }
843
+
844
+ const useStyles$e = makeStyles(
845
+ {
846
+ input: {}
847
+ },
848
+ {
849
+ name: "CatalogReactEntityLifecyclePicker"
850
+ }
851
+ );
852
+ const EntityLifecyclePicker = (props) => {
853
+ const { initialFilter = [] } = props;
854
+ const classes = useStyles$e();
855
+ return /* @__PURE__ */ React.createElement(
856
+ EntityAutocompletePicker,
857
+ {
858
+ label: "Lifecycle",
859
+ name: "lifecycles",
860
+ path: "spec.lifecycle",
861
+ Filter: EntityLifecycleFilter,
862
+ InputProps: { className: classes.input },
863
+ initialSelectedOptions: initialFilter
864
+ }
865
+ );
814
866
  };
815
867
 
816
868
  function humanizeEntityRef(entityRef, opts) {
@@ -851,7 +903,7 @@ function humanizeEntity(entity, defaultName) {
851
903
  return defaultName;
852
904
  }
853
905
 
854
- const useStyles$e = makeStyles(
906
+ const useStyles$d = makeStyles(
855
907
  {
856
908
  input: {}
857
909
  },
@@ -859,11 +911,11 @@ const useStyles$e = makeStyles(
859
911
  name: "CatalogReactEntityOwnerPicker"
860
912
  }
861
913
  );
862
- const icon$2 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
863
- const checkedIcon$2 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
914
+ const icon$1 = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
915
+ const checkedIcon$1 = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
864
916
  const EntityOwnerPicker = () => {
865
917
  var _a, _b, _c;
866
- const classes = useStyles$e();
918
+ const classes = useStyles$d();
867
919
  const {
868
920
  updateFilters,
869
921
  filters,
@@ -968,8 +1020,8 @@ const EntityOwnerPicker = () => {
968
1020
  control: /* @__PURE__ */ React.createElement(
969
1021
  Checkbox,
970
1022
  {
971
- icon: icon$2,
972
- checkedIcon: checkedIcon$2,
1023
+ icon: icon$1,
1024
+ checkedIcon: checkedIcon$1,
973
1025
  checked: selected
974
1026
  }
975
1027
  ),
@@ -1195,7 +1247,7 @@ const UserCardActions = (props) => {
1195
1247
  return email ? /* @__PURE__ */ React.createElement(EmailCardAction, { email }) : null;
1196
1248
  };
1197
1249
 
1198
- const useStyles$d = makeStyles(() => {
1250
+ const useStyles$c = makeStyles(() => {
1199
1251
  return {
1200
1252
  popoverPaper: {
1201
1253
  width: "30em"
@@ -1213,7 +1265,7 @@ const maxTagChips = 4;
1213
1265
  const EntityPeekAheadPopover = (props) => {
1214
1266
  var _a, _b, _c;
1215
1267
  const { entityRef, children, delayTime = 500 } = props;
1216
- const classes = useStyles$d();
1268
+ const classes = useStyles$c();
1217
1269
  const apiHolder = useApiHolder();
1218
1270
  const popupState = usePopupState({
1219
1271
  variant: "popover",
@@ -1282,7 +1334,7 @@ const EntityPeekAheadPopover = (props) => {
1282
1334
  ));
1283
1335
  };
1284
1336
 
1285
- const useStyles$c = makeStyles(
1337
+ const useStyles$b = makeStyles(
1286
1338
  (_theme) => ({
1287
1339
  searchToolbar: {
1288
1340
  paddingLeft: 0,
@@ -1296,7 +1348,7 @@ const useStyles$c = makeStyles(
1296
1348
  );
1297
1349
  const EntitySearchBar = () => {
1298
1350
  var _a, _b;
1299
- const classes = useStyles$c();
1351
+ const classes = useStyles$b();
1300
1352
  const { filters, updateFilters } = useEntityList();
1301
1353
  const [search, setSearch] = useState((_b = (_a = filters.text) == null ? void 0 : _a.value) != null ? _b : "");
1302
1354
  useDebounce(
@@ -1461,7 +1513,7 @@ const componentEntityColumns = [
1461
1513
  columnFactories.createMetadataDescriptionColumn()
1462
1514
  ];
1463
1515
 
1464
- const useStyles$b = makeStyles((theme) => ({
1516
+ const useStyles$a = makeStyles((theme) => ({
1465
1517
  empty: {
1466
1518
  padding: theme.spacing(2),
1467
1519
  display: "flex",
@@ -1476,7 +1528,7 @@ const EntityTable = (props) => {
1476
1528
  variant = "gridItem",
1477
1529
  columns
1478
1530
  } = props;
1479
- const classes = useStyles$b();
1531
+ const classes = useStyles$a();
1480
1532
  const tableStyle = {
1481
1533
  minWidth: "0",
1482
1534
  width: "100%"
@@ -1507,113 +1559,6 @@ EntityTable.columns = columnFactories;
1507
1559
  EntityTable.systemEntityColumns = systemEntityColumns;
1508
1560
  EntityTable.componentEntityColumns = componentEntityColumns;
1509
1561
 
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
1562
  const useStyles$9 = makeStyles(
1618
1563
  { input: {} },
1619
1564
  { name: "CatalogReactEntityTagPicker" }