@backstage/plugin-catalog-react 0.6.11 → 0.6.13-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 +60 -0
- package/dist/index.cjs.js +51 -62
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +41 -4
- package/dist/index.esm.js +52 -63
- package/dist/index.esm.js.map +1 -1
- package/package.json +13 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-react
|
|
2
2
|
|
|
3
|
+
## 0.6.13-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f7257dff6f: The `<Link />` component now accepts a `noTrack` prop, which prevents the `click` event from being captured by the Analytics API. This can be used if tracking is explicitly not warranted, or in order to use custom link tracking in specific situations.
|
|
8
|
+
- 300f8cdaee: Fix bug: previously the filter would be set to "all" on page load, even if the
|
|
9
|
+
`initiallySelectedFilter` on the `DefaultCatalogPage` was set to something else,
|
|
10
|
+
or a different query parameter was supplied. Now, the prop and query parameters
|
|
11
|
+
control the filter as expected. Additionally, after this change any filters
|
|
12
|
+
which match 0 items will be disabled, and the filter will be reverted to 'all'
|
|
13
|
+
if they're set on page load.
|
|
14
|
+
- 6acc8f7db7: Add caching to the useEntityPermission hook
|
|
15
|
+
|
|
16
|
+
The hook now caches the authorization decision based on the permission + the entity, and returns the cache match value as the default `allowed` value while loading. This helps avoid flicker in UI elements that would be conditionally rendered based on the `allowed` result of this hook.
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @backstage/core-components@0.8.7-next.1
|
|
20
|
+
|
|
21
|
+
## 0.6.13-next.0
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- @backstage/core-components@0.8.7-next.0
|
|
27
|
+
|
|
28
|
+
## 0.6.12
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 3d87019269: The `entityRouteRef` is now a well-known route that should be imported directly from `@backstage/plugin-catalog-react`. It is guaranteed to be globally unique across duplicate installations of the `@backstage/plugin-catalog-react`, starting at this version.
|
|
33
|
+
|
|
34
|
+
Deprecated `entityRoute` in favor of `entityRouteRef`.
|
|
35
|
+
|
|
36
|
+
Deprecated `rootRoute` and `catalogRouteRef`. If you want to refer to the catalog index page from a public plugin you now need to use an `ExternalRouteRef` instead. For private plugins it is possible to take the shortcut of referring directly to `catalogPlugin.routes.indexPage` instead.
|
|
37
|
+
|
|
38
|
+
- 2916a83b9c: Deprecated `loadIdentityOwnerRefs`, since they can now be retrieved as `ownershipEntityRefs` from `identityApi.getBackstageIdentity()` instead.
|
|
39
|
+
- 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
|
|
40
|
+
- c54c0d9d10: Add useEntityPermission hook
|
|
41
|
+
- Updated dependencies
|
|
42
|
+
- @backstage/plugin-permission-react@0.3.0
|
|
43
|
+
- @backstage/core-components@0.8.5
|
|
44
|
+
- @backstage/integration@0.7.2
|
|
45
|
+
- @backstage/plugin-permission-common@0.4.0
|
|
46
|
+
- @backstage/core-plugin-api@0.6.0
|
|
47
|
+
- @backstage/catalog-model@0.9.10
|
|
48
|
+
- @backstage/catalog-client@0.5.5
|
|
49
|
+
|
|
50
|
+
## 0.6.12-next.0
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- 2916a83b9c: Deprecated `loadIdentityOwnerRefs`, since they can now be retrieved as `ownershipEntityRefs` from `identityApi.getBackstageIdentity()` instead.
|
|
55
|
+
- 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
|
|
56
|
+
- Updated dependencies
|
|
57
|
+
- @backstage/core-components@0.8.5-next.0
|
|
58
|
+
- @backstage/core-plugin-api@0.6.0-next.0
|
|
59
|
+
- @backstage/catalog-model@0.9.10-next.0
|
|
60
|
+
- @backstage/catalog-client@0.5.5-next.0
|
|
61
|
+
- @backstage/integration@0.7.2-next.0
|
|
62
|
+
|
|
3
63
|
## 0.6.11
|
|
4
64
|
|
|
5
65
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -21,7 +21,7 @@ var isEqual = require('lodash/isEqual');
|
|
|
21
21
|
var coreComponents = require('@backstage/core-components');
|
|
22
22
|
var core = require('@material-ui/core');
|
|
23
23
|
var useObservable = require('react-use/lib/useObservable');
|
|
24
|
-
var
|
|
24
|
+
var pluginPermissionReact = require('@backstage/plugin-permission-react');
|
|
25
25
|
var CheckBoxIcon = require('@material-ui/icons/CheckBox');
|
|
26
26
|
var CheckBoxOutlineBlankIcon = require('@material-ui/icons/CheckBoxOutlineBlank');
|
|
27
27
|
var ExpandMoreIcon = require('@material-ui/icons/ExpandMore');
|
|
@@ -46,7 +46,6 @@ var useMountedState__default = /*#__PURE__*/_interopDefaultLegacy(useMountedStat
|
|
|
46
46
|
var useAsync__default = /*#__PURE__*/_interopDefaultLegacy(useAsync);
|
|
47
47
|
var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
|
|
48
48
|
var useObservable__default = /*#__PURE__*/_interopDefaultLegacy(useObservable);
|
|
49
|
-
var jwtDecoder__default = /*#__PURE__*/_interopDefaultLegacy(jwtDecoder);
|
|
50
49
|
var CheckBoxIcon__default = /*#__PURE__*/_interopDefaultLegacy(CheckBoxIcon);
|
|
51
50
|
var CheckBoxOutlineBlankIcon__default = /*#__PURE__*/_interopDefaultLegacy(CheckBoxOutlineBlankIcon);
|
|
52
51
|
var ExpandMoreIcon__default = /*#__PURE__*/_interopDefaultLegacy(ExpandMoreIcon);
|
|
@@ -129,11 +128,11 @@ const rootRoute = corePluginApi.createRouteRef({
|
|
|
129
128
|
id: "catalog"
|
|
130
129
|
});
|
|
131
130
|
const catalogRouteRef = rootRoute;
|
|
132
|
-
const
|
|
131
|
+
const entityRouteRef = versionBridge.getOrCreateGlobalSingleton("catalog:entity-route-ref", () => corePluginApi.createRouteRef({
|
|
133
132
|
id: "catalog:entity",
|
|
134
133
|
params: ["namespace", "kind", "name"]
|
|
135
|
-
});
|
|
136
|
-
const
|
|
134
|
+
}));
|
|
135
|
+
const entityRoute = entityRouteRef;
|
|
137
136
|
function entityRouteParams(entity) {
|
|
138
137
|
var _a, _b;
|
|
139
138
|
return {
|
|
@@ -624,11 +623,13 @@ function useEntityKinds() {
|
|
|
624
623
|
function useOwnUser() {
|
|
625
624
|
const catalogApi = corePluginApi.useApi(catalogApiRef);
|
|
626
625
|
const identityApi = corePluginApi.useApi(corePluginApi.identityApiRef);
|
|
627
|
-
return useAsync__default["default"](() =>
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
626
|
+
return useAsync__default["default"](async () => {
|
|
627
|
+
const identity = await identityApi.getBackstageIdentity();
|
|
628
|
+
return catalogApi.getEntityByName(catalogModel.parseEntityRef(identity.userEntityRef, {
|
|
629
|
+
defaultKind: "User",
|
|
630
|
+
defaultNamespace: catalogModel.ENTITY_DEFAULT_NAMESPACE
|
|
631
|
+
}));
|
|
632
|
+
}, [catalogApi, identityApi]);
|
|
632
633
|
}
|
|
633
634
|
|
|
634
635
|
const BATCH_SIZE = 20;
|
|
@@ -712,34 +713,9 @@ function useStarredEntity(entityOrRef) {
|
|
|
712
713
|
};
|
|
713
714
|
}
|
|
714
715
|
|
|
715
|
-
function extendUserId(id) {
|
|
716
|
-
try {
|
|
717
|
-
const ref = catalogModel.parseEntityRef(id, {
|
|
718
|
-
defaultKind: "User",
|
|
719
|
-
defaultNamespace: "default"
|
|
720
|
-
});
|
|
721
|
-
return catalogModel.stringifyEntityRef(ref);
|
|
722
|
-
} catch {
|
|
723
|
-
return id;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
716
|
async function loadIdentityOwnerRefs(identityApi) {
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
const result = [];
|
|
730
|
-
if (id) {
|
|
731
|
-
result.push(extendUserId(id));
|
|
732
|
-
}
|
|
733
|
-
if (token) {
|
|
734
|
-
try {
|
|
735
|
-
const decoded = jwtDecoder__default["default"](token);
|
|
736
|
-
if (decoded == null ? void 0 : decoded.ent) {
|
|
737
|
-
[decoded.ent].flat().filter((x) => typeof x === "string").map((x) => x.toLocaleLowerCase("en-US")).forEach((x) => result.push(x));
|
|
738
|
-
}
|
|
739
|
-
} catch {
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
return result;
|
|
717
|
+
const identity = await identityApi.getBackstageIdentity();
|
|
718
|
+
return identity.ownershipEntityRefs;
|
|
743
719
|
}
|
|
744
720
|
async function loadCatalogOwnerRefs(catalogApi, identityOwnerRefs) {
|
|
745
721
|
const result = new Array();
|
|
@@ -761,9 +737,9 @@ function useEntityOwnership() {
|
|
|
761
737
|
const identityApi = corePluginApi.useApi(corePluginApi.identityApiRef);
|
|
762
738
|
const catalogApi = corePluginApi.useApi(catalogApiRef);
|
|
763
739
|
const { loading, value: refs } = useAsync__default["default"](async () => {
|
|
764
|
-
const
|
|
765
|
-
const catalogRefs = await loadCatalogOwnerRefs(catalogApi,
|
|
766
|
-
return /* @__PURE__ */ new Set([...
|
|
740
|
+
const { ownershipEntityRefs } = await identityApi.getBackstageIdentity();
|
|
741
|
+
const catalogRefs = await loadCatalogOwnerRefs(catalogApi, ownershipEntityRefs);
|
|
742
|
+
return /* @__PURE__ */ new Set([...ownershipEntityRefs, ...catalogRefs]);
|
|
767
743
|
}, []);
|
|
768
744
|
const isOwnedEntity = React.useMemo(() => {
|
|
769
745
|
const myOwnerRefs = new Set(refs != null ? refs : []);
|
|
@@ -804,6 +780,22 @@ function useOwnedEntities(allowedKinds) {
|
|
|
804
780
|
return React.useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]);
|
|
805
781
|
}
|
|
806
782
|
|
|
783
|
+
function useEntityPermission(permission) {
|
|
784
|
+
const { entity, loading: loadingEntity, error: entityError } = useEntity();
|
|
785
|
+
const {
|
|
786
|
+
allowed,
|
|
787
|
+
loading: loadingPermission,
|
|
788
|
+
error: permissionError
|
|
789
|
+
} = pluginPermissionReact.usePermission(permission, entity ? catalogModel.stringifyEntityRef(entity) : void 0);
|
|
790
|
+
if (loadingEntity || loadingPermission) {
|
|
791
|
+
return { loading: true, allowed: false };
|
|
792
|
+
}
|
|
793
|
+
if (entityError) {
|
|
794
|
+
return { loading: false, allowed: false, error: entityError };
|
|
795
|
+
}
|
|
796
|
+
return { loading: false, allowed, error: permissionError };
|
|
797
|
+
}
|
|
798
|
+
|
|
807
799
|
const EntityKindPicker = ({
|
|
808
800
|
initialFilter,
|
|
809
801
|
hidden
|
|
@@ -1528,7 +1520,7 @@ const UserListPicker = ({
|
|
|
1528
1520
|
const classes = useStyles();
|
|
1529
1521
|
const configApi = corePluginApi.useApi(corePluginApi.configApiRef);
|
|
1530
1522
|
const orgName = (_a = configApi.getOptionalString("organization.name")) != null ? _a : "Company";
|
|
1531
|
-
const { filters, updateFilters, backendEntities, queryParameters } = useEntityListProvider();
|
|
1523
|
+
const { filters, updateFilters, backendEntities, queryParameters, loading } = useEntityListProvider();
|
|
1532
1524
|
const userAndGroupFilterIds = ["starred", "all"];
|
|
1533
1525
|
const filterGroups = getFilterGroups(orgName).map((filterGroup) => ({
|
|
1534
1526
|
...filterGroup,
|
|
@@ -1538,28 +1530,23 @@ const UserListPicker = ({
|
|
|
1538
1530
|
const { isOwnedEntity } = useEntityOwnership();
|
|
1539
1531
|
const ownedFilter = React.useMemo(() => new UserListFilter("owned", isOwnedEntity, isStarredEntity), [isOwnedEntity, isStarredEntity]);
|
|
1540
1532
|
const starredFilter = React.useMemo(() => new UserListFilter("starred", isOwnedEntity, isStarredEntity), [isOwnedEntity, isStarredEntity]);
|
|
1541
|
-
const [
|
|
1542
|
-
const
|
|
1543
|
-
const
|
|
1533
|
+
const [selectedUserFilter, setSelectedUserFilter] = React.useState((_b = [queryParameters.user].flat()[0]) != null ? _b : initialFilter);
|
|
1534
|
+
const entitiesWithoutUserFilter = React.useMemo(() => backendEntities.filter(reduceEntityFilters(lodash.compact(Object.values({ ...filters, user: void 0 })))), [filters, backendEntities]);
|
|
1535
|
+
const filterCounts = React.useMemo(() => ({
|
|
1536
|
+
all: entitiesWithoutUserFilter.length,
|
|
1537
|
+
starred: entitiesWithoutUserFilter.filter((entity) => starredFilter.filterEntity(entity)).length,
|
|
1538
|
+
owned: entitiesWithoutUserFilter.filter((entity) => ownedFilter.filterEntity(entity)).length
|
|
1539
|
+
}), [entitiesWithoutUserFilter, starredFilter, ownedFilter]);
|
|
1540
|
+
React.useEffect(() => {
|
|
1541
|
+
if (!loading && !!selectedUserFilter && selectedUserFilter !== "all" && filterCounts[selectedUserFilter] === 0) {
|
|
1542
|
+
setSelectedUserFilter("all");
|
|
1543
|
+
}
|
|
1544
|
+
}, [loading, filterCounts, selectedUserFilter, setSelectedUserFilter]);
|
|
1544
1545
|
React.useEffect(() => {
|
|
1545
1546
|
updateFilters({
|
|
1546
1547
|
user: selectedUserFilter ? new UserListFilter(selectedUserFilter, isOwnedEntity, isStarredEntity) : void 0
|
|
1547
1548
|
});
|
|
1548
1549
|
}, [selectedUserFilter, isOwnedEntity, isStarredEntity, updateFilters]);
|
|
1549
|
-
React.useEffect(() => {
|
|
1550
|
-
const filterFn = reduceEntityFilters(lodash.compact(Object.values({ ...filters, user: void 0 })));
|
|
1551
|
-
setEntitiesWithoutUserFilter(backendEntities.filter(filterFn));
|
|
1552
|
-
}, [filters, backendEntities]);
|
|
1553
|
-
function getFilterCount(id) {
|
|
1554
|
-
switch (id) {
|
|
1555
|
-
case "owned":
|
|
1556
|
-
return totalOwnedUserEntities;
|
|
1557
|
-
case "starred":
|
|
1558
|
-
return entitiesWithoutUserFilter.filter((entity) => starredFilter.filterEntity(entity)).length;
|
|
1559
|
-
default:
|
|
1560
|
-
return entitiesWithoutUserFilter.length;
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
1550
|
return /* @__PURE__ */ React__default["default"].createElement(core.Card, {
|
|
1564
1551
|
className: classes.root
|
|
1565
1552
|
}, filterGroups.map((group) => /* @__PURE__ */ React__default["default"].createElement(React.Fragment, {
|
|
@@ -1580,15 +1567,16 @@ const UserListPicker = ({
|
|
|
1580
1567
|
divider: true,
|
|
1581
1568
|
onClick: () => setSelectedUserFilter(item.id),
|
|
1582
1569
|
selected: item.id === ((_a2 = filters.user) == null ? void 0 : _a2.value),
|
|
1583
|
-
className: classes.menuItem
|
|
1570
|
+
className: classes.menuItem,
|
|
1571
|
+
disabled: filterCounts[item.id] === 0,
|
|
1572
|
+
"data-testid": `user-picker-${item.id}`
|
|
1584
1573
|
}, item.icon && /* @__PURE__ */ React__default["default"].createElement(core.ListItemIcon, {
|
|
1585
1574
|
className: classes.listIcon
|
|
1586
1575
|
}, /* @__PURE__ */ React__default["default"].createElement(item.icon, {
|
|
1587
1576
|
fontSize: "small"
|
|
1588
1577
|
})), /* @__PURE__ */ React__default["default"].createElement(core.ListItemText, null, /* @__PURE__ */ React__default["default"].createElement(core.Typography, {
|
|
1589
|
-
variant: "body1"
|
|
1590
|
-
|
|
1591
|
-
}, item.label)), /* @__PURE__ */ React__default["default"].createElement(core.ListItemSecondaryAction, null, (_b2 = getFilterCount(item.id)) != null ? _b2 : "-"));
|
|
1578
|
+
variant: "body1"
|
|
1579
|
+
}, item.label)), /* @__PURE__ */ React__default["default"].createElement(core.ListItemSecondaryAction, null, (_b2 = filterCounts[item.id]) != null ? _b2 : "-"));
|
|
1592
1580
|
}))))));
|
|
1593
1581
|
};
|
|
1594
1582
|
|
|
@@ -1673,6 +1661,7 @@ exports.useEntityFromUrl = useEntityFromUrl;
|
|
|
1673
1661
|
exports.useEntityKinds = useEntityKinds;
|
|
1674
1662
|
exports.useEntityListProvider = useEntityListProvider;
|
|
1675
1663
|
exports.useEntityOwnership = useEntityOwnership;
|
|
1664
|
+
exports.useEntityPermission = useEntityPermission;
|
|
1676
1665
|
exports.useEntityTypeFilter = useEntityTypeFilter;
|
|
1677
1666
|
exports.useOwnUser = useOwnUser;
|
|
1678
1667
|
exports.useOwnedEntities = useOwnedEntities;
|