@backstage/plugin-org 0.6.20-next.1 → 0.6.20-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/dist/index.esm.js CHANGED
@@ -1,29 +1,31 @@
1
- import { createExternalRouteRef, createPlugin, createComponentExtension, useApi, useApp, alertApiRef, useRouteRef, identityApiRef } from '@backstage/core-plugin-api';
2
- import { stringifyEntityRef, DEFAULT_NAMESPACE, RELATION_PARENT_OF, RELATION_CHILD_OF, ANNOTATION_LOCATION, ANNOTATION_EDIT_URL, RELATION_MEMBER_OF, parseEntityRef, getCompoundEntityRef } from '@backstage/catalog-model';
3
- import { getEntityRelations, useEntity, catalogApiRef, EntityRefLink, EntityRefLinks, humanizeEntityRef, entityRouteRef } from '@backstage/plugin-catalog-react';
4
- import { makeStyles, createStyles, Box, Typography, Grid, Switch, Divider, ListItem, ListItemIcon, ListItemText, IconButton, List, Tooltip, ListItemSecondaryAction } from '@material-ui/core';
5
- import Pagination from '@material-ui/lab/Pagination';
6
- import React, { useState, useCallback, useEffect } from 'react';
1
+ import { createPlugin, createComponentExtension, useApi, identityApiRef, useRouteRef } from '@backstage/core-plugin-api';
2
+ import { c as catalogIndexRouteRef } from './esm/routes-e3daad75.esm.js';
3
+ export { MembersListCard } from './esm/MembersListCard-cb148b44.esm.js';
4
+ export { GroupProfileCard } from './esm/GroupProfileCard-d9207fd9.esm.js';
5
+ export { UserProfileCard } from './esm/UserProfileCard-d467b6e5.esm.js';
6
+ export { OwnershipCard } from './esm/OwnershipCard-9f8835e6.esm.js';
7
+ import React from 'react';
8
+ import { getCompoundEntityRef, DEFAULT_NAMESPACE, stringifyEntityRef } from '@backstage/catalog-model';
9
+ import { SidebarItem, SidebarSubmenu, SidebarSubmenuItem } from '@backstage/core-components';
7
10
  import useAsync from 'react-use/lib/useAsync';
8
- import { Progress, ResponseErrorPanel, InfoCard, Avatar, Link, OverflowTooltip, SidebarItem, SidebarSubmenu, SidebarSubmenuItem } from '@backstage/core-components';
9
- import AccountTreeIcon from '@material-ui/icons/AccountTree';
10
- import Alert from '@material-ui/lab/Alert';
11
- import CachedIcon from '@material-ui/icons/Cached';
12
- import EditIcon from '@material-ui/icons/Edit';
13
- import EmailIcon from '@material-ui/icons/Email';
14
- import GroupIcon from '@material-ui/icons/Group';
15
- import LanguageIcon from '@material-ui/icons/Language';
16
- import { useEntityPermission } from '@backstage/plugin-catalog-react/alpha';
17
- import { catalogEntityRefreshPermission } from '@backstage/plugin-catalog-common/alpha';
18
- import PersonIcon from '@material-ui/icons/Person';
19
- import pluralize from 'pluralize';
20
- import limiterFactory from 'p-limit';
21
- import qs from 'qs';
22
- import { uniq } from 'lodash';
23
-
24
- const catalogIndexRouteRef = createExternalRouteRef({
25
- id: "catalog-index"
26
- });
11
+ import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react';
12
+ import '@material-ui/core';
13
+ import '@material-ui/lab/Pagination';
14
+ import '@material-ui/icons/AccountTree';
15
+ import '@material-ui/lab/Alert';
16
+ import '@material-ui/icons/Cached';
17
+ import '@material-ui/icons/Edit';
18
+ import '@material-ui/icons/Email';
19
+ import '@material-ui/icons/Group';
20
+ import './esm/LinksGroup-9fefd100.esm.js';
21
+ import '@material-ui/icons/Language';
22
+ import '@backstage/plugin-catalog-react/alpha';
23
+ import '@backstage/plugin-catalog-common/alpha';
24
+ import '@material-ui/icons/Person';
25
+ import 'pluralize';
26
+ import 'p-limit';
27
+ import 'qs';
28
+ import 'lodash';
27
29
 
28
30
  const orgPlugin = createPlugin({
29
31
  id: "org",
@@ -35,7 +37,7 @@ const EntityGroupProfileCard = orgPlugin.provide(
35
37
  createComponentExtension({
36
38
  name: "EntityGroupProfileCard",
37
39
  component: {
38
- lazy: () => import('./esm/index-9172d7e6.esm.js').then((m) => m.GroupProfileCard)
40
+ lazy: () => import('./esm/index-ad2d9b29.esm.js').then((m) => m.GroupProfileCard)
39
41
  }
40
42
  })
41
43
  );
@@ -43,7 +45,7 @@ const EntityMembersListCard = orgPlugin.provide(
43
45
  createComponentExtension({
44
46
  name: "EntityMembersListCard",
45
47
  component: {
46
- lazy: () => import('./esm/index-9172d7e6.esm.js').then((m) => m.MembersListCard)
48
+ lazy: () => import('./esm/index-ad2d9b29.esm.js').then((m) => m.MembersListCard)
47
49
  }
48
50
  })
49
51
  );
@@ -51,7 +53,7 @@ const EntityOwnershipCard = orgPlugin.provide(
51
53
  createComponentExtension({
52
54
  name: "EntityOwnershipCard",
53
55
  component: {
54
- lazy: () => import('./esm/index-9172d7e6.esm.js').then((m) => m.OwnershipCard)
56
+ lazy: () => import('./esm/index-ad2d9b29.esm.js').then((m) => m.OwnershipCard)
55
57
  }
56
58
  })
57
59
  );
@@ -59,733 +61,10 @@ const EntityUserProfileCard = orgPlugin.provide(
59
61
  createComponentExtension({
60
62
  name: "EntityUserProfileCard",
61
63
  component: {
62
- lazy: () => import('./esm/index-9172d7e6.esm.js').then((m) => m.UserProfileCard)
63
- }
64
- })
65
- );
66
-
67
- const getMembersFromGroups = async (groups, catalogApi) => {
68
- const membersList = groups.length === 0 ? { items: [] } : await catalogApi.getEntities({
69
- filter: {
70
- kind: "User",
71
- "relations.memberof": groups.map(
72
- (group) => stringifyEntityRef({
73
- kind: "group",
74
- namespace: group.namespace.toLocaleLowerCase("en-US"),
75
- name: group.name.toLocaleLowerCase("en-US")
76
- })
77
- )
78
- }
79
- });
80
- return membersList.items;
81
- };
82
- const getDescendantGroupsFromGroup = async (group, catalogApi) => {
83
- var _a;
84
- const alreadyQueuedOrExpandedGroupNames = /* @__PURE__ */ new Map();
85
- const groupRef = {
86
- kind: group.kind,
87
- namespace: (_a = group.metadata.namespace) != null ? _a : DEFAULT_NAMESPACE,
88
- name: group.metadata.name
89
- };
90
- const groupQueue = [groupRef];
91
- const resultantGroupRefs = [];
92
- while (groupQueue.length > 0) {
93
- const activeGroupRef = groupQueue.shift();
94
- const activeGroup = await catalogApi.getEntityByRef(activeGroupRef);
95
- alreadyQueuedOrExpandedGroupNames.set(
96
- stringifyEntityRef(activeGroupRef),
97
- true
98
- );
99
- const childGroups = getEntityRelations(activeGroup, RELATION_PARENT_OF, {
100
- kind: "Group"
101
- }).filter(
102
- (currentGroup) => !alreadyQueuedOrExpandedGroupNames.has(
103
- stringifyEntityRef(currentGroup)
104
- )
105
- );
106
- childGroups.forEach(
107
- (childGroup) => alreadyQueuedOrExpandedGroupNames.set(
108
- stringifyEntityRef(childGroup),
109
- true
110
- )
111
- );
112
- groupQueue.push(...childGroups);
113
- resultantGroupRefs.push(...childGroups);
114
- }
115
- return resultantGroupRefs;
116
- };
117
- const getAllDesendantMembersForGroupEntity = async (groupEntity, catalogApi) => getMembersFromGroups(
118
- await getDescendantGroupsFromGroup(groupEntity, catalogApi),
119
- catalogApi
120
- );
121
- const removeDuplicateEntitiesFrom = (entityArray) => {
122
- const seenEntities = /* @__PURE__ */ new Map();
123
- return entityArray.filter((entity) => {
124
- const stringifiedEntity = stringifyEntityRef(entity);
125
- const isDuplicate = seenEntities.has(stringifiedEntity);
126
- seenEntities.set(stringifiedEntity, true);
127
- return !isDuplicate;
128
- });
129
- };
130
-
131
- const useStyles$2 = makeStyles(
132
- (theme) => createStyles({
133
- card: {
134
- border: `1px solid ${theme.palette.divider}`,
135
- boxShadow: theme.shadows[2],
136
- borderRadius: "4px",
137
- overflow: "visible",
138
- position: "relative",
139
- margin: theme.spacing(4, 1, 1),
140
- flex: "1",
141
- minWidth: "0px"
64
+ lazy: () => import('./esm/index-ad2d9b29.esm.js').then((m) => m.UserProfileCard)
142
65
  }
143
66
  })
144
67
  );
145
- const MemberComponent = (props) => {
146
- var _a;
147
- const classes = useStyles$2();
148
- const {
149
- metadata: { name: metaName, description },
150
- spec: { profile }
151
- } = props.member;
152
- const displayName = (_a = profile == null ? void 0 : profile.displayName) != null ? _a : metaName;
153
- return /* @__PURE__ */ React.createElement(Box, { className: classes.card }, /* @__PURE__ */ React.createElement(
154
- Box,
155
- {
156
- display: "flex",
157
- flexDirection: "column",
158
- m: 3,
159
- alignItems: "center",
160
- justifyContent: "center"
161
- },
162
- /* @__PURE__ */ React.createElement(
163
- Avatar,
164
- {
165
- displayName,
166
- picture: profile == null ? void 0 : profile.picture,
167
- customStyles: {
168
- position: "absolute",
169
- top: "-2rem"
170
- }
171
- }
172
- ),
173
- /* @__PURE__ */ React.createElement(
174
- Box,
175
- {
176
- pt: 2,
177
- sx: {
178
- width: "100%"
179
- },
180
- textAlign: "center"
181
- },
182
- /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, /* @__PURE__ */ React.createElement(
183
- EntityRefLink,
184
- {
185
- "data-testid": "user-link",
186
- entityRef: props.member,
187
- title: displayName
188
- }
189
- )),
190
- (profile == null ? void 0 : profile.email) && /* @__PURE__ */ React.createElement(Link, { to: `mailto:${profile.email}` }, /* @__PURE__ */ React.createElement(OverflowTooltip, { text: profile.email })),
191
- description && /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2" }, description)
192
- )
193
- ));
194
- };
195
- const useListStyles = makeStyles((theme) => ({
196
- root: {
197
- height: "100%"
198
- },
199
- cardContent: {
200
- overflow: "auto"
201
- },
202
- memberList: {
203
- display: "grid",
204
- gap: theme.spacing(1.5),
205
- gridTemplateColumns: `repeat(auto-fit, minmax(auto, ${theme.spacing(
206
- 34
207
- )}px))`
208
- }
209
- }));
210
- const MembersListCard = (props) => {
211
- var _a;
212
- const {
213
- memberDisplayTitle = "Members",
214
- pageSize = 50,
215
- showAggregateMembersToggle
216
- } = props;
217
- const classes = useListStyles();
218
- const { entity: groupEntity } = useEntity();
219
- const {
220
- metadata: { name: groupName, namespace: grpNamespace },
221
- spec: { profile }
222
- } = groupEntity;
223
- const catalogApi = useApi(catalogApiRef);
224
- const displayName = (_a = profile == null ? void 0 : profile.displayName) != null ? _a : groupName;
225
- const groupNamespace = grpNamespace || DEFAULT_NAMESPACE;
226
- const [page, setPage] = React.useState(1);
227
- const pageChange = (_, pageIndex) => {
228
- setPage(pageIndex);
229
- };
230
- const [showAggregateMembers, setShowAggregateMembers] = useState(false);
231
- const { loading: loadingDescendantMembers, value: descendantMembers } = useAsync(async () => {
232
- if (!showAggregateMembersToggle) {
233
- return [];
234
- }
235
- return await getAllDesendantMembersForGroupEntity(
236
- groupEntity,
237
- catalogApi
238
- );
239
- }, [catalogApi, groupEntity, showAggregateMembersToggle]);
240
- const {
241
- loading,
242
- error,
243
- value: directMembers
244
- } = useAsync(async () => {
245
- const membersList = await catalogApi.getEntities({
246
- filter: {
247
- kind: "User",
248
- "relations.memberof": [
249
- stringifyEntityRef({
250
- kind: "group",
251
- namespace: groupNamespace.toLocaleLowerCase("en-US"),
252
- name: groupName.toLocaleLowerCase("en-US")
253
- })
254
- ]
255
- }
256
- });
257
- return membersList.items;
258
- }, [catalogApi, groupEntity]);
259
- const members = removeDuplicateEntitiesFrom(
260
- [
261
- ...directMembers != null ? directMembers : [],
262
- ...descendantMembers && showAggregateMembers ? descendantMembers : []
263
- ].sort(
264
- (a, b) => stringifyEntityRef(a).localeCompare(stringifyEntityRef(b))
265
- )
266
- );
267
- if (loading) {
268
- return /* @__PURE__ */ React.createElement(Progress, null);
269
- } else if (error) {
270
- return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
271
- }
272
- const nbPages = Math.ceil(((members == null ? void 0 : members.length) || 0) / pageSize);
273
- const paginationLabel = nbPages < 2 ? "" : `, page ${page} of ${nbPages}`;
274
- const pagination = /* @__PURE__ */ React.createElement(
275
- Pagination,
276
- {
277
- count: nbPages,
278
- page,
279
- onChange: pageChange,
280
- showFirstButton: true,
281
- showLastButton: true
282
- }
283
- );
284
- let memberList;
285
- if (members && members.length > 0) {
286
- memberList = /* @__PURE__ */ React.createElement(Box, { className: classes.memberList }, members.slice(pageSize * (page - 1), pageSize * page).map((member) => /* @__PURE__ */ React.createElement(MemberComponent, { member, key: member.metadata.uid })));
287
- } else {
288
- memberList = /* @__PURE__ */ React.createElement(Box, { p: 2 }, /* @__PURE__ */ React.createElement(Typography, null, "This group has no ", memberDisplayTitle.toLocaleLowerCase(), "."));
289
- }
290
- return /* @__PURE__ */ React.createElement(Grid, { item: true, className: classes.root }, /* @__PURE__ */ React.createElement(
291
- InfoCard,
292
- {
293
- title: `${memberDisplayTitle} (${(members == null ? void 0 : members.length) || 0}${paginationLabel})`,
294
- subheader: `of ${displayName}`,
295
- ...nbPages <= 1 ? {} : { actions: pagination },
296
- className: classes.root,
297
- cardClassName: classes.cardContent
298
- },
299
- showAggregateMembersToggle && /* @__PURE__ */ React.createElement(React.Fragment, null, "Direct Members", /* @__PURE__ */ React.createElement(
300
- Switch,
301
- {
302
- color: "primary",
303
- checked: showAggregateMembers,
304
- onChange: () => {
305
- setShowAggregateMembers(!showAggregateMembers);
306
- },
307
- inputProps: { "aria-label": "Users Type Switch" }
308
- }
309
- ), "Aggregated Members"),
310
- showAggregateMembers && loadingDescendantMembers ? /* @__PURE__ */ React.createElement(Progress, null) : memberList
311
- ));
312
- };
313
-
314
- const WebLink = ({
315
- href,
316
- Icon,
317
- text
318
- }) => /* @__PURE__ */ React.createElement(ListItem, { key: href }, /* @__PURE__ */ React.createElement(ListItemIcon, null, Icon ? /* @__PURE__ */ React.createElement(Icon, null) : /* @__PURE__ */ React.createElement(LanguageIcon, null)), /* @__PURE__ */ React.createElement(ListItemText, null, /* @__PURE__ */ React.createElement(Link, { to: href }, text)));
319
- const LinksGroup = ({ links }) => {
320
- const app = useApp();
321
- const iconResolver = (key) => {
322
- var _a;
323
- return key ? (_a = app.getSystemIcon(key)) != null ? _a : LanguageIcon : LanguageIcon;
324
- };
325
- if (links === void 0) {
326
- return null;
327
- }
328
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Divider, null), links.map((link) => {
329
- return /* @__PURE__ */ React.createElement(
330
- WebLink,
331
- {
332
- key: link.url,
333
- href: link.url,
334
- text: link.title,
335
- Icon: iconResolver(link.icon)
336
- }
337
- );
338
- }));
339
- };
340
-
341
- const CardTitle$1 = (props) => /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(GroupIcon, { fontSize: "inherit" }), /* @__PURE__ */ React.createElement(Box, { ml: 1 }, props.title));
342
- const GroupProfileCard = (props) => {
343
- var _a, _b, _c;
344
- const catalogApi = useApi(catalogApiRef);
345
- const alertApi = useApi(alertApiRef);
346
- const { entity: group } = useEntity();
347
- const { allowed: canRefresh } = useEntityPermission(
348
- catalogEntityRefreshPermission
349
- );
350
- const refreshEntity = useCallback(async () => {
351
- await catalogApi.refreshEntity(stringifyEntityRef(group));
352
- alertApi.post({
353
- message: "Refresh scheduled",
354
- severity: "info",
355
- display: "transient"
356
- });
357
- }, [catalogApi, alertApi, group]);
358
- if (!group) {
359
- return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, "Group not found");
360
- }
361
- const {
362
- metadata: { name, description, title, annotations, links },
363
- spec: { profile }
364
- } = group;
365
- const childRelations = getEntityRelations(group, RELATION_PARENT_OF, {
366
- kind: "Group"
367
- });
368
- const parentRelations = getEntityRelations(group, RELATION_CHILD_OF, {
369
- kind: "group"
370
- });
371
- const entityLocation = annotations == null ? void 0 : annotations[ANNOTATION_LOCATION];
372
- const allowRefresh = (entityLocation == null ? void 0 : entityLocation.startsWith("url:")) || (entityLocation == null ? void 0 : entityLocation.startsWith("file:"));
373
- const entityMetadataEditUrl = (_a = group.metadata.annotations) == null ? void 0 : _a[ANNOTATION_EDIT_URL];
374
- const displayName = (_c = (_b = profile == null ? void 0 : profile.displayName) != null ? _b : title) != null ? _c : name;
375
- const emailHref = (profile == null ? void 0 : profile.email) ? `mailto:${profile.email}` : "#";
376
- const infoCardAction = entityMetadataEditUrl ? /* @__PURE__ */ React.createElement(
377
- IconButton,
378
- {
379
- "aria-label": "Edit",
380
- title: "Edit Metadata",
381
- component: Link,
382
- to: entityMetadataEditUrl
383
- },
384
- /* @__PURE__ */ React.createElement(EditIcon, null)
385
- ) : /* @__PURE__ */ React.createElement(IconButton, { "aria-label": "Edit", disabled: true, title: "Edit Metadata" }, /* @__PURE__ */ React.createElement(EditIcon, null));
386
- return /* @__PURE__ */ React.createElement(
387
- InfoCard,
388
- {
389
- title: /* @__PURE__ */ React.createElement(CardTitle$1, { title: displayName }),
390
- subheader: description,
391
- variant: props.variant,
392
- action: /* @__PURE__ */ React.createElement(React.Fragment, null, allowRefresh && canRefresh && /* @__PURE__ */ React.createElement(
393
- IconButton,
394
- {
395
- "aria-label": "Refresh",
396
- title: "Schedule entity refresh",
397
- onClick: refreshEntity
398
- },
399
- /* @__PURE__ */ React.createElement(CachedIcon, null)
400
- ), infoCardAction)
401
- },
402
- /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: 2, xl: 1 }, /* @__PURE__ */ React.createElement(Avatar, { displayName, picture: profile == null ? void 0 : profile.picture })), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 10, xl: 11 }, /* @__PURE__ */ React.createElement(List, null, (profile == null ? void 0 : profile.email) && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Email" }, /* @__PURE__ */ React.createElement(EmailIcon, null))), /* @__PURE__ */ React.createElement(
403
- ListItemText,
404
- {
405
- primary: /* @__PURE__ */ React.createElement(Link, { to: emailHref }, profile.email),
406
- secondary: "Email"
407
- }
408
- )), /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Parent Group" }, /* @__PURE__ */ React.createElement(AccountTreeIcon, null))), /* @__PURE__ */ React.createElement(
409
- ListItemText,
410
- {
411
- primary: parentRelations.length ? /* @__PURE__ */ React.createElement(
412
- EntityRefLinks,
413
- {
414
- entityRefs: parentRelations,
415
- defaultKind: "Group"
416
- }
417
- ) : "N/A",
418
- secondary: "Parent Group"
419
- }
420
- )), /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Child Groups" }, /* @__PURE__ */ React.createElement(GroupIcon, null))), /* @__PURE__ */ React.createElement(
421
- ListItemText,
422
- {
423
- primary: childRelations.length ? /* @__PURE__ */ React.createElement(
424
- EntityRefLinks,
425
- {
426
- entityRefs: childRelations,
427
- defaultKind: "Group"
428
- }
429
- ) : "N/A",
430
- secondary: "Child Groups"
431
- }
432
- )), (props == null ? void 0 : props.showLinks) && /* @__PURE__ */ React.createElement(LinksGroup, { links }))))
433
- );
434
- };
435
-
436
- const CardTitle = (props) => props.title ? /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(PersonIcon, { fontSize: "inherit" }), /* @__PURE__ */ React.createElement(Box, { ml: 1 }, props.title)) : null;
437
- const UserProfileCard = (props) => {
438
- var _a, _b;
439
- const { entity: user } = useEntity();
440
- if (!user) {
441
- return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, "User not found");
442
- }
443
- const entityMetadataEditUrl = (_a = user.metadata.annotations) == null ? void 0 : _a[ANNOTATION_EDIT_URL];
444
- const {
445
- metadata: { name: metaName, description, links },
446
- spec: { profile }
447
- } = user;
448
- const displayName = (_b = profile == null ? void 0 : profile.displayName) != null ? _b : metaName;
449
- const emailHref = (profile == null ? void 0 : profile.email) ? `mailto:${profile.email}` : void 0;
450
- const memberOfRelations = getEntityRelations(user, RELATION_MEMBER_OF, {
451
- kind: "Group"
452
- });
453
- return /* @__PURE__ */ React.createElement(
454
- InfoCard,
455
- {
456
- title: /* @__PURE__ */ React.createElement(CardTitle, { title: displayName }),
457
- subheader: description,
458
- variant: props.variant,
459
- action: /* @__PURE__ */ React.createElement(React.Fragment, null, entityMetadataEditUrl && /* @__PURE__ */ React.createElement(
460
- IconButton,
461
- {
462
- "aria-label": "Edit",
463
- title: "Edit Metadata",
464
- component: Link,
465
- to: entityMetadataEditUrl
466
- },
467
- /* @__PURE__ */ React.createElement(EditIcon, null)
468
- ))
469
- },
470
- /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3, alignItems: "flex-start" }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, sm: 2, xl: 1 }, /* @__PURE__ */ React.createElement(Avatar, { displayName, picture: profile == null ? void 0 : profile.picture })), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 10, xl: 11 }, /* @__PURE__ */ React.createElement(List, null, (profile == null ? void 0 : profile.email) && /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Email" }, /* @__PURE__ */ React.createElement(EmailIcon, null))), /* @__PURE__ */ React.createElement(ListItemText, null, /* @__PURE__ */ React.createElement(Link, { to: emailHref != null ? emailHref : "" }, profile.email))), /* @__PURE__ */ React.createElement(ListItem, null, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Member of" }, /* @__PURE__ */ React.createElement(GroupIcon, null))), /* @__PURE__ */ React.createElement(ListItemText, null, /* @__PURE__ */ React.createElement(
471
- EntityRefLinks,
472
- {
473
- entityRefs: memberOfRelations,
474
- defaultKind: "Group"
475
- }
476
- ))), (props == null ? void 0 : props.showLinks) && /* @__PURE__ */ React.createElement(LinksGroup, { links }))))
477
- );
478
- };
479
-
480
- const limiter = limiterFactory(10);
481
- const getQueryParams = (ownersEntityRef, selectedEntity) => {
482
- const { kind, type } = selectedEntity;
483
- const owners = ownersEntityRef.map(
484
- (owner) => humanizeEntityRef(parseEntityRef(owner), { defaultKind: "group" })
485
- );
486
- const filters = {
487
- kind: kind.toLocaleLowerCase("en-US"),
488
- type,
489
- owners,
490
- user: "all"
491
- };
492
- return qs.stringify({ filters }, { arrayFormat: "repeat" });
493
- };
494
- const getMemberOfEntityRefs = (owner) => {
495
- const parentGroups = getEntityRelations(owner, RELATION_MEMBER_OF, {
496
- kind: "Group"
497
- });
498
- const ownerGroupsNames = parentGroups.map(
499
- ({ kind, namespace, name }) => stringifyEntityRef({
500
- kind,
501
- namespace,
502
- name
503
- })
504
- );
505
- return [...ownerGroupsNames, stringifyEntityRef(owner)];
506
- };
507
- const isEntity = (entity) => entity !== void 0;
508
- const getChildOwnershipEntityRefs = async (entity, catalogApi, alreadyRetrievedParentRefs = []) => {
509
- const childGroups = getEntityRelations(entity, RELATION_PARENT_OF, {
510
- kind: "Group"
511
- });
512
- const hasChildGroups = childGroups.length > 0;
513
- const entityRef = stringifyEntityRef(entity);
514
- if (hasChildGroups) {
515
- const entityRefs = childGroups.map((r) => stringifyEntityRef(r));
516
- const childGroupResponse = await catalogApi.getEntitiesByRefs({
517
- fields: ["kind", "metadata.namespace", "metadata.name", "relations"],
518
- entityRefs
519
- });
520
- const childGroupEntities = childGroupResponse.items.filter(isEntity);
521
- const unknownChildren = childGroupEntities.filter(
522
- (childGroupEntity) => !alreadyRetrievedParentRefs.includes(
523
- stringifyEntityRef(childGroupEntity)
524
- )
525
- );
526
- const childrenRefs = (await Promise.all(
527
- unknownChildren.map(
528
- (childGroupEntity) => limiter(
529
- () => getChildOwnershipEntityRefs(childGroupEntity, catalogApi, [
530
- ...alreadyRetrievedParentRefs,
531
- entityRef
532
- ])
533
- )
534
- )
535
- )).flatMap((aggregated) => aggregated);
536
- return uniq([...childrenRefs, entityRef]);
537
- }
538
- return [entityRef];
539
- };
540
- const getOwners = async (entity, relations, catalogApi) => {
541
- const isGroup = entity.kind === "Group";
542
- const isAggregated = relations === "aggregated";
543
- const isUserEntity = entity.kind === "User";
544
- if (isAggregated && isGroup) {
545
- return getChildOwnershipEntityRefs(entity, catalogApi);
546
- }
547
- if (isAggregated && isUserEntity) {
548
- return getMemberOfEntityRefs(entity);
549
- }
550
- return [stringifyEntityRef(entity)];
551
- };
552
- const getOwnedEntitiesByOwners = (owners, kinds, catalogApi) => catalogApi.getEntities({
553
- filter: [
554
- {
555
- kind: kinds,
556
- "relations.ownedBy": owners
557
- }
558
- ],
559
- fields: [
560
- "kind",
561
- "metadata.name",
562
- "metadata.namespace",
563
- "spec.type",
564
- "relations"
565
- ]
566
- });
567
- function useGetEntities(entity, relations, entityFilterKind, entityLimit = 6) {
568
- const catalogApi = useApi(catalogApiRef);
569
- const kinds = entityFilterKind != null ? entityFilterKind : ["Component", "API", "System"];
570
- const {
571
- loading,
572
- error,
573
- value: componentsWithCounters
574
- } = useAsync(async () => {
575
- const owners = await getOwners(entity, relations, catalogApi);
576
- const ownedEntitiesList = await getOwnedEntitiesByOwners(
577
- owners,
578
- kinds,
579
- catalogApi
580
- );
581
- const counts = ownedEntitiesList.items.reduce(
582
- (acc, ownedEntity) => {
583
- var _a, _b;
584
- const match = acc.find(
585
- (x) => {
586
- var _a2;
587
- return x.kind === ownedEntity.kind && x.type === ((_a2 = ownedEntity.spec) == null ? void 0 : _a2.type);
588
- }
589
- );
590
- if (match) {
591
- match.count += 1;
592
- } else {
593
- acc.push({
594
- kind: ownedEntity.kind,
595
- type: (_b = (_a = ownedEntity.spec) == null ? void 0 : _a.type) == null ? void 0 : _b.toString(),
596
- count: 1
597
- });
598
- }
599
- return acc;
600
- },
601
- []
602
- );
603
- const topN = counts.sort((a, b) => b.count - a.count).slice(0, entityLimit);
604
- return topN.map((topOwnedEntity) => ({
605
- counter: topOwnedEntity.count,
606
- type: topOwnedEntity.type,
607
- kind: topOwnedEntity.kind,
608
- queryParams: getQueryParams(owners, topOwnedEntity)
609
- }));
610
- }, [catalogApi, entity, relations]);
611
- return {
612
- componentsWithCounters,
613
- loading,
614
- error
615
- };
616
- }
617
-
618
- const useStyles$1 = makeStyles(
619
- (theme) => createStyles({
620
- card: {
621
- border: `1px solid ${theme.palette.divider}`,
622
- boxShadow: theme.shadows[2],
623
- borderRadius: "4px",
624
- padding: theme.spacing(2),
625
- transition: `${theme.transitions.duration.standard}ms`,
626
- "&:hover": {
627
- boxShadow: theme.shadows[4]
628
- },
629
- height: "100%"
630
- },
631
- bold: {
632
- fontWeight: theme.typography.fontWeightBold
633
- },
634
- smallFont: {
635
- fontSize: theme.typography.body2.fontSize
636
- },
637
- entityTypeBox: {
638
- background: (props) => theme.getPageTheme({ themeId: props.type }).backgroundImage,
639
- color: (props) => theme.getPageTheme({ themeId: props.type }).fontColor
640
- }
641
- })
642
- );
643
- const EntityCountTile = ({
644
- counter,
645
- type,
646
- kind,
647
- url
648
- }) => {
649
- const classes = useStyles$1({ type: type != null ? type : kind });
650
- const rawTitle = type != null ? type : kind;
651
- const isLongText = rawTitle.length > 10;
652
- return /* @__PURE__ */ React.createElement(Link, { to: url, variant: "body2" }, /* @__PURE__ */ React.createElement(
653
- Box,
654
- {
655
- className: `${classes.card} ${classes.entityTypeBox}`,
656
- display: "flex",
657
- flexDirection: "column",
658
- alignItems: "center"
659
- },
660
- /* @__PURE__ */ React.createElement(Typography, { className: classes.bold, variant: "h6" }, counter),
661
- /* @__PURE__ */ React.createElement(Box, { sx: { width: "100%", textAlign: "center" } }, /* @__PURE__ */ React.createElement(
662
- Typography,
663
- {
664
- className: `${classes.bold} ${isLongText && classes.smallFont}`,
665
- variant: "h6"
666
- },
667
- /* @__PURE__ */ React.createElement(
668
- OverflowTooltip,
669
- {
670
- text: pluralize(rawTitle.toLocaleUpperCase("en-US"), counter)
671
- }
672
- )
673
- )),
674
- type && /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle1" }, kind)
675
- ));
676
- };
677
- const ComponentsGrid = ({
678
- entity,
679
- relationsType,
680
- entityFilterKind,
681
- entityLimit = 6
682
- }) => {
683
- const catalogLink = useRouteRef(catalogIndexRouteRef);
684
- const { componentsWithCounters, loading, error } = useGetEntities(
685
- entity,
686
- relationsType,
687
- entityFilterKind,
688
- entityLimit
689
- );
690
- if (loading) {
691
- return /* @__PURE__ */ React.createElement(Progress, null);
692
- } else if (error) {
693
- return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
694
- }
695
- return /* @__PURE__ */ React.createElement(Grid, { container: true }, componentsWithCounters == null ? void 0 : componentsWithCounters.map((c) => {
696
- var _a;
697
- return /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 6, md: 6, lg: 4, key: (_a = c.type) != null ? _a : c.kind }, /* @__PURE__ */ React.createElement(
698
- EntityCountTile,
699
- {
700
- counter: c.counter,
701
- kind: c.kind,
702
- type: c.type,
703
- url: `${catalogLink()}/?${c.queryParams}`
704
- }
705
- ));
706
- }));
707
- };
708
-
709
- const useStyles = makeStyles((theme) => ({
710
- list: {
711
- [theme.breakpoints.down("xs")]: {
712
- padding: `0 0 12px`
713
- }
714
- },
715
- listItemText: {
716
- [theme.breakpoints.down("xs")]: {
717
- paddingRight: 0,
718
- paddingLeft: 0
719
- }
720
- },
721
- listItemSecondaryAction: {
722
- [theme.breakpoints.down("xs")]: {
723
- width: "100%",
724
- top: "auto",
725
- right: "auto",
726
- position: "relative",
727
- transform: "unset"
728
- }
729
- }
730
- }));
731
- const OwnershipCard = (props) => {
732
- const {
733
- variant,
734
- entityFilterKind,
735
- hideRelationsToggle,
736
- relationsType,
737
- entityLimit = 6
738
- } = props;
739
- const relationsToggle = hideRelationsToggle === void 0 ? false : hideRelationsToggle;
740
- const classes = useStyles();
741
- const { entity } = useEntity();
742
- const defaultRelationsType = entity.kind === "User" ? "aggregated" : "direct";
743
- const [getRelationsType, setRelationsType] = useState(
744
- relationsType != null ? relationsType : defaultRelationsType
745
- );
746
- useEffect(() => {
747
- if (!relationsType) {
748
- setRelationsType(defaultRelationsType);
749
- }
750
- }, [setRelationsType, defaultRelationsType, relationsType]);
751
- return /* @__PURE__ */ React.createElement(InfoCard, { title: "Ownership", variant }, !relationsToggle && /* @__PURE__ */ React.createElement(List, { dense: true }, /* @__PURE__ */ React.createElement(ListItem, { className: classes.list }, /* @__PURE__ */ React.createElement(ListItemText, { className: classes.listItemText }), /* @__PURE__ */ React.createElement(
752
- ListItemSecondaryAction,
753
- {
754
- className: classes.listItemSecondaryAction
755
- },
756
- "Direct Relations",
757
- /* @__PURE__ */ React.createElement(
758
- Tooltip,
759
- {
760
- placement: "top",
761
- arrow: true,
762
- title: `${getRelationsType === "direct" ? "Direct" : "Aggregated"} Relations`
763
- },
764
- /* @__PURE__ */ React.createElement(
765
- Switch,
766
- {
767
- color: "primary",
768
- checked: getRelationsType !== "direct",
769
- onChange: () => {
770
- const updatedRelationsType = getRelationsType === "direct" ? "aggregated" : "direct";
771
- setRelationsType(updatedRelationsType);
772
- },
773
- name: "pin",
774
- inputProps: { "aria-label": "Ownership Type Switch" }
775
- }
776
- )
777
- ),
778
- "Aggregated Relations"
779
- ))), /* @__PURE__ */ React.createElement(
780
- ComponentsGrid,
781
- {
782
- entity,
783
- entityLimit,
784
- relationsType: getRelationsType,
785
- entityFilterKind
786
- }
787
- ));
788
- };
789
68
 
790
69
  const MyGroupsSidebarItem = (props) => {
791
70
  const { singularTitle, pluralTitle, icon, filter } = props;
@@ -834,5 +113,5 @@ const MyGroupsSidebarItem = (props) => {
834
113
  })));
835
114
  };
836
115
 
837
- export { EntityGroupProfileCard, EntityMembersListCard, EntityOwnershipCard, EntityUserProfileCard, GroupProfileCard, MembersListCard, MyGroupsSidebarItem, OwnershipCard, UserProfileCard, orgPlugin, orgPlugin as plugin };
116
+ export { EntityGroupProfileCard, EntityMembersListCard, EntityOwnershipCard, EntityUserProfileCard, MyGroupsSidebarItem, orgPlugin, orgPlugin as plugin };
838
117
  //# sourceMappingURL=index.esm.js.map