@thecodingsheikh/backstage-plugin-multi-owner 1.0.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/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @thecodingsheikh/backstage-plugin-multi-owner
2
+
3
+ A frontend plugin that displays multiple owners for Backstage entities, with optional role labels.
4
+
5
+ ![screenshow](https://github.com/TheCodingSheikh/backstage-plugins/blob/main/plugins/multi-owner/multi-owner/screenshot.png?raw=true)
6
+
7
+ ## Features
8
+
9
+ - **EntityMultiOwnerCard** — An info card showing all owners with clickable entity reference links
10
+ - **Role chips** — Optional role labels displayed as Material UI chips
11
+ - **Smart icons** — Group icon for groups, person icon for users
12
+ - **Fallback** — Falls back to `spec.owner` when `spec.owners` is not configured
13
+ - **EntitySwitch guard** — `isMultiOwnerAvailable()` for conditional rendering
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ yarn add @thecodingsheikh/backstage-plugin-multi-owner
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Entity Page
24
+
25
+ Add the card to your entity pages in `packages/app/src/components/catalog/EntityPage.tsx`:
26
+
27
+ ```tsx
28
+ import {
29
+ EntityMultiOwnerCard,
30
+ isMultiOwnerAvailable,
31
+ } from '@thecodingsheikh/backstage-plugin-multi-owner';
32
+
33
+ // In your entity page layout:
34
+ const overviewContent = (
35
+ <Grid container spacing={3}>
36
+ {/* ... other cards ... */}
37
+
38
+ <EntitySwitch>
39
+ <EntitySwitch.Case if={isMultiOwnerAvailable}>
40
+ <Grid item md={6}>
41
+ <EntityMultiOwnerCard />
42
+ </Grid>
43
+ </EntitySwitch.Case>
44
+ </EntitySwitch>
45
+ </Grid>
46
+ );
47
+ ```
48
+
49
+ ### Props
50
+
51
+ | Prop | Type | Default | Description |
52
+ |---|---|---|---|
53
+ | `title` | `string` | `"Owners"` | Card title |
54
+ | `variant` | `'gridItem' \| 'fullHeight'` | — | Card variant |
55
+
56
+ ### Custom Hook
57
+
58
+ You can also use the `useMultiOwners` hook directly:
59
+
60
+ ```tsx
61
+ import { useMultiOwners } from '@thecodingsheikh/backstage-plugin-multi-owner';
62
+
63
+ function MyComponent() {
64
+ const { owners, loading } = useMultiOwners();
65
+
66
+ if (loading) return <Progress />;
67
+
68
+ return (
69
+ <ul>
70
+ {owners.map(owner => (
71
+ <li key={owner.name}>
72
+ {owner.name} {owner.role && `(${owner.role})`}
73
+ </li>
74
+ ))}
75
+ </ul>
76
+ );
77
+ }
78
+ ```
79
+
80
+ ## Requirements
81
+
82
+ This plugin requires the backend processor module to be installed:
83
+
84
+ ```bash
85
+ yarn add @thecodingsheikh/backstage-plugin-catalog-backend-module-multi-owner-processor
86
+ ```
87
+
88
+ See the [backend module README](../catalog-backend-module-multi-owner-processor/README.md) for setup instructions.
@@ -0,0 +1,103 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { InfoCard } from '@backstage/core-components';
3
+ import { EntityRefLinks } from '@backstage/plugin-catalog-react';
4
+ import { makeStyles, Typography, List, ListItem, ListItemIcon, ListItemText, Chip, createStyles } from '@material-ui/core';
5
+ import PeopleIcon from '@material-ui/icons/People';
6
+ import PersonIcon from '@material-ui/icons/Person';
7
+ import { parseEntityRef } from '@backstage/catalog-model';
8
+ import { useMultiOwners } from '../../hooks/useMultiOwners.esm.js';
9
+
10
+ const useStyles = makeStyles(
11
+ (theme) => createStyles({
12
+ list: {
13
+ padding: 0
14
+ },
15
+ listItem: {
16
+ paddingLeft: theme.spacing(1),
17
+ paddingRight: theme.spacing(1),
18
+ "&:not(:last-child)": {
19
+ borderBottom: `1px solid ${theme.palette.divider}`
20
+ }
21
+ },
22
+ chip: {
23
+ marginLeft: theme.spacing(1),
24
+ height: 22,
25
+ fontSize: "0.75rem",
26
+ fontWeight: 500
27
+ },
28
+ ownerContent: {
29
+ display: "flex",
30
+ alignItems: "center",
31
+ flexWrap: "wrap",
32
+ gap: theme.spacing(0.5)
33
+ },
34
+ emptyState: {
35
+ padding: theme.spacing(2),
36
+ textAlign: "center"
37
+ }
38
+ })
39
+ );
40
+ function EntityMultiOwnerCard(props) {
41
+ const { title = "Owners", variant } = props;
42
+ const classes = useStyles();
43
+ const { owners } = useMultiOwners();
44
+ if (owners.length === 0) {
45
+ return /* @__PURE__ */ jsx(InfoCard, { title, variant, children: /* @__PURE__ */ jsx(
46
+ Typography,
47
+ {
48
+ variant: "body2",
49
+ color: "textSecondary",
50
+ className: classes.emptyState,
51
+ children: "No owners defined"
52
+ }
53
+ ) });
54
+ }
55
+ return /* @__PURE__ */ jsx(InfoCard, { title, variant, children: /* @__PURE__ */ jsx(List, { className: classes.list, children: owners.map((owner, index) => {
56
+ const isGroup = getOwnerKind(owner.name) === "group";
57
+ return /* @__PURE__ */ jsxs(
58
+ ListItem,
59
+ {
60
+ className: classes.listItem,
61
+ children: [
62
+ /* @__PURE__ */ jsx(ListItemIcon, { children: isGroup ? /* @__PURE__ */ jsx(PeopleIcon, {}) : /* @__PURE__ */ jsx(PersonIcon, {}) }),
63
+ /* @__PURE__ */ jsx(
64
+ ListItemText,
65
+ {
66
+ disableTypography: true,
67
+ primary: /* @__PURE__ */ jsxs("div", { className: classes.ownerContent, children: [
68
+ /* @__PURE__ */ jsx(
69
+ EntityRefLinks,
70
+ {
71
+ entityRefs: [owner.name],
72
+ defaultKind: "group"
73
+ }
74
+ ),
75
+ owner.role && /* @__PURE__ */ jsx(
76
+ Chip,
77
+ {
78
+ label: owner.role,
79
+ size: "small",
80
+ color: "primary",
81
+ variant: "outlined",
82
+ className: classes.chip
83
+ }
84
+ )
85
+ ] })
86
+ }
87
+ )
88
+ ]
89
+ },
90
+ `${owner.name}-${index}`
91
+ );
92
+ }) }) });
93
+ }
94
+ function getOwnerKind(ref) {
95
+ try {
96
+ return parseEntityRef(ref, { defaultKind: "group", defaultNamespace: "default" }).kind.toLowerCase();
97
+ } catch {
98
+ return "group";
99
+ }
100
+ }
101
+
102
+ export { EntityMultiOwnerCard };
103
+ //# sourceMappingURL=EntityMultiOwnerCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityMultiOwnerCard.esm.js","sources":["../../../src/components/EntityMultiOwnerCard/EntityMultiOwnerCard.tsx"],"sourcesContent":["import {\n InfoCard,\n} from '@backstage/core-components';\nimport { EntityRefLinks } from '@backstage/plugin-catalog-react';\nimport {\n List,\n ListItem,\n ListItemText,\n ListItemIcon,\n Chip,\n makeStyles,\n createStyles,\n Theme,\n Typography,\n} from '@material-ui/core';\nimport PeopleIcon from '@material-ui/icons/People';\nimport PersonIcon from '@material-ui/icons/Person';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { useMultiOwners } from '../../hooks/useMultiOwners';\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n list: {\n padding: 0,\n },\n listItem: {\n paddingLeft: theme.spacing(1),\n paddingRight: theme.spacing(1),\n '&:not(:last-child)': {\n borderBottom: `1px solid ${theme.palette.divider}`,\n },\n },\n chip: {\n marginLeft: theme.spacing(1),\n height: 22,\n fontSize: '0.75rem',\n fontWeight: 500,\n },\n ownerContent: {\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: theme.spacing(0.5),\n },\n emptyState: {\n padding: theme.spacing(2),\n textAlign: 'center',\n },\n }),\n);\n\n/** Props for the {@link EntityMultiOwnerCard} component. */\nexport interface EntityMultiOwnerCardProps {\n /** Optional card title override. Defaults to `\"Owners\"`. */\n title?: string;\n /** Optional card variant. */\n variant?: 'gridItem' | 'fullHeight';\n}\n\n/**\n * An info card that displays multiple owners for an entity, each with an\n * optional role label. Owners are rendered as clickable entity reference\n * links that navigate to the owner's entity page.\n *\n * @remarks\n * Requires the entity to have the `backstage.io/owners` annotation,\n * typically set by the backend {@link MultiOwnerEntitiesProcessor}.\n * Falls back to `spec.owner` if the annotation is absent.\n */\nexport function EntityMultiOwnerCard(props: EntityMultiOwnerCardProps) {\n const { title = 'Owners', variant } = props;\n const classes = useStyles();\n const { owners } = useMultiOwners();\n\n if (owners.length === 0) {\n return (\n <InfoCard title={title} variant={variant}>\n <Typography\n variant=\"body2\"\n color=\"textSecondary\"\n className={classes.emptyState}\n >\n No owners defined\n </Typography>\n </InfoCard>\n );\n }\n\n return (\n <InfoCard title={title} variant={variant}>\n <List className={classes.list}>\n {owners.map((owner, index) => {\n const isGroup = getOwnerKind(owner.name) === 'group';\n\n return (\n <ListItem\n key={`${owner.name}-${index}`}\n className={classes.listItem}\n >\n <ListItemIcon>\n {isGroup ? <PeopleIcon /> : <PersonIcon />}\n </ListItemIcon>\n <ListItemText\n disableTypography\n primary={\n <div className={classes.ownerContent}>\n <EntityRefLinks\n entityRefs={[owner.name]}\n defaultKind=\"group\"\n />\n {owner.role && (\n <Chip\n label={owner.role}\n size=\"small\"\n color=\"primary\"\n variant=\"outlined\"\n className={classes.chip}\n />\n )}\n </div>\n }\n />\n </ListItem>\n );\n })}\n </List>\n </InfoCard>\n );\n}\n\n/** Extracts the kind from an entity reference string, defaulting to \"group\". */\nfunction getOwnerKind(ref: string): string {\n try {\n return parseEntityRef(ref, { defaultKind: 'group', defaultNamespace: 'default' }).kind.toLowerCase();\n } catch {\n return 'group';\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { EntityMultiOwnerCard } from './EntityMultiOwnerCard.esm.js';
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import { useEntity } from '@backstage/plugin-catalog-react';
2
+ import { MULTI_OWNER_ANNOTATION, parseOwners } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
3
+
4
+ function useMultiOwners() {
5
+ const { entity } = useEntity();
6
+ const annotation = entity.metadata.annotations?.[MULTI_OWNER_ANNOTATION];
7
+ if (!annotation) {
8
+ const specOwner = entity.spec?.owner;
9
+ if (typeof specOwner === "string" && specOwner.trim()) {
10
+ return {
11
+ owners: [{ name: specOwner.trim() }]
12
+ };
13
+ }
14
+ return { owners: [] };
15
+ }
16
+ try {
17
+ const parsed = JSON.parse(annotation);
18
+ return { owners: parseOwners(parsed) };
19
+ } catch {
20
+ return { owners: [] };
21
+ }
22
+ }
23
+
24
+ export { useMultiOwners };
25
+ //# sourceMappingURL=useMultiOwners.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMultiOwners.esm.js","sources":["../../src/hooks/useMultiOwners.ts"],"sourcesContent":["import { useEntity } from '@backstage/plugin-catalog-react';\nimport {\n MULTI_OWNER_ANNOTATION,\n parseOwners,\n} from '@thecodingsheikh/backstage-plugin-multi-owner-common';\nimport type { MultiOwnerEntry } from '@thecodingsheikh/backstage-plugin-multi-owner-common';\n\n/**\n * Custom hook that reads the multi-owner annotation from the current\n * entity context and returns a typed array of owner entries.\n *\n * @returns An object containing:\n * - `owners`: The parsed array of {@link MultiOwnerEntry} objects\n *\n * @example\n * ```tsx\n * const { owners } = useMultiOwners();\n * ```\n */\nexport function useMultiOwners(): {\n owners: MultiOwnerEntry[];\n} {\n const { entity } = useEntity();\n\n const annotation =\n entity.metadata.annotations?.[MULTI_OWNER_ANNOTATION];\n\n if (!annotation) {\n // Fall back to spec.owner if present\n const specOwner = (entity.spec as Record<string, unknown> | undefined)\n ?.owner;\n if (typeof specOwner === 'string' && specOwner.trim()) {\n return {\n owners: [{ name: specOwner.trim() }],\n };\n }\n return { owners: [] };\n }\n\n try {\n const parsed = JSON.parse(annotation);\n return { owners: parseOwners(parsed) };\n } catch {\n return { owners: [] };\n }\n}\n"],"names":[],"mappings":";;;AAmBO,SAAS,cAAA,GAEd;AACE,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,SAAA,EAAU;AAE7B,EAAA,MAAM,UAAA,GACF,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,sBAAsB,CAAA;AAExD,EAAA,IAAI,CAAC,UAAA,EAAY;AAEb,IAAA,MAAM,SAAA,GAAa,OAAO,IAAA,EACpB,KAAA;AACN,IAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,CAAU,MAAK,EAAG;AACnD,MAAA,OAAO;AAAA,QACH,QAAQ,CAAC,EAAE,MAAM,SAAA,CAAU,IAAA,IAAQ;AAAA,OACvC;AAAA,IACJ;AACA,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAC,EAAE;AAAA,EACxB;AAEA,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA;AACpC,IAAA,OAAO,EAAE,MAAA,EAAQ,WAAA,CAAY,MAAM,CAAA,EAAE;AAAA,EACzC,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAC,EAAE;AAAA,EACxB;AACJ;;;;"}
@@ -0,0 +1,67 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
+ import { Entity } from '@backstage/catalog-model';
4
+ import { MultiOwnerEntry } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
5
+
6
+ /** Props for the {@link EntityMultiOwnerCard} component. */
7
+ interface EntityMultiOwnerCardProps {
8
+ /** Optional card title override. Defaults to `"Owners"`. */
9
+ title?: string;
10
+ /** Optional card variant. */
11
+ variant?: 'gridItem' | 'fullHeight';
12
+ }
13
+ /**
14
+ * An info card that displays multiple owners for an entity, each with an
15
+ * optional role label. Owners are rendered as clickable entity reference
16
+ * links that navigate to the owner's entity page.
17
+ *
18
+ * @remarks
19
+ * Requires the entity to have the `backstage.io/owners` annotation,
20
+ * typically set by the backend {@link MultiOwnerEntitiesProcessor}.
21
+ * Falls back to `spec.owner` if the annotation is absent.
22
+ */
23
+ declare function EntityMultiOwnerCard$1(props: EntityMultiOwnerCardProps): react_jsx_runtime.JSX.Element;
24
+
25
+ /**
26
+ * The multi-owner frontend plugin.
27
+ */
28
+ declare const multiOwnerPlugin: _backstage_core_plugin_api.BackstagePlugin<{}, {}, {}>;
29
+ /**
30
+ * An info card component that displays the list of owners (with optional roles)
31
+ * for an entity that uses `spec.owners`.
32
+ *
33
+ * @remarks
34
+ * Place this card on entity pages in your Backstage app:
35
+ * ```tsx
36
+ * <EntitySwitch>
37
+ * <EntitySwitch.Case if={isMultiOwnerAvailable}>
38
+ * <EntityMultiOwnerCard />
39
+ * </EntitySwitch.Case>
40
+ * </EntitySwitch>
41
+ * ```
42
+ */
43
+ declare const EntityMultiOwnerCard: typeof EntityMultiOwnerCard$1;
44
+ /**
45
+ * Utility function that checks whether the multi-owner annotation is
46
+ * present on an entity. Use with `EntitySwitch` to conditionally render
47
+ * the card only when relevant.
48
+ */
49
+ declare function isMultiOwnerAvailable(entity: Entity): boolean;
50
+
51
+ /**
52
+ * Custom hook that reads the multi-owner annotation from the current
53
+ * entity context and returns a typed array of owner entries.
54
+ *
55
+ * @returns An object containing:
56
+ * - `owners`: The parsed array of {@link MultiOwnerEntry} objects
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * const { owners } = useMultiOwners();
61
+ * ```
62
+ */
63
+ declare function useMultiOwners(): {
64
+ owners: MultiOwnerEntry[];
65
+ };
66
+
67
+ export { EntityMultiOwnerCard, isMultiOwnerAvailable, multiOwnerPlugin, useMultiOwners };
@@ -0,0 +1,3 @@
1
+ export { EntityMultiOwnerCard, isMultiOwnerAvailable, multiOwnerPlugin } from './plugin.esm.js';
2
+ export { useMultiOwners } from './hooks/useMultiOwners.esm.js';
3
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,22 @@
1
+ import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';
2
+ import { MULTI_OWNER_ANNOTATION } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
3
+
4
+ const multiOwnerPlugin = createPlugin({
5
+ id: "multi-owner"
6
+ });
7
+ const EntityMultiOwnerCard = multiOwnerPlugin.provide(
8
+ createComponentExtension({
9
+ name: "EntityMultiOwnerCard",
10
+ component: {
11
+ lazy: () => import('./components/EntityMultiOwnerCard/index.esm.js').then(
12
+ (m) => m.EntityMultiOwnerCard
13
+ )
14
+ }
15
+ })
16
+ );
17
+ function isMultiOwnerAvailable(entity) {
18
+ return Boolean(entity.metadata.annotations?.[MULTI_OWNER_ANNOTATION]);
19
+ }
20
+
21
+ export { EntityMultiOwnerCard, isMultiOwnerAvailable, multiOwnerPlugin };
22
+ //# sourceMappingURL=plugin.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n createComponentExtension,\n} from '@backstage/core-plugin-api';\nimport { Entity } from '@backstage/catalog-model';\nimport { MULTI_OWNER_ANNOTATION } from '@thecodingsheikh/backstage-plugin-multi-owner-common';\n\n/**\n * The multi-owner frontend plugin.\n */\nexport const multiOwnerPlugin = createPlugin({\n id: 'multi-owner',\n});\n\n/**\n * An info card component that displays the list of owners (with optional roles)\n * for an entity that uses `spec.owners`.\n *\n * @remarks\n * Place this card on entity pages in your Backstage app:\n * ```tsx\n * <EntitySwitch>\n * <EntitySwitch.Case if={isMultiOwnerAvailable}>\n * <EntityMultiOwnerCard />\n * </EntitySwitch.Case>\n * </EntitySwitch>\n * ```\n */\nexport const EntityMultiOwnerCard = multiOwnerPlugin.provide(\n createComponentExtension({\n name: 'EntityMultiOwnerCard',\n component: {\n lazy: () =>\n import('./components/EntityMultiOwnerCard').then(\n m => m.EntityMultiOwnerCard,\n ),\n },\n }),\n);\n\n/**\n * Utility function that checks whether the multi-owner annotation is\n * present on an entity. Use with `EntitySwitch` to conditionally render\n * the card only when relevant.\n */\nexport function isMultiOwnerAvailable(entity: Entity): boolean {\n return Boolean(entity.metadata.annotations?.[MULTI_OWNER_ANNOTATION]);\n}\n"],"names":[],"mappings":";;;AAUO,MAAM,mBAAmB,YAAA,CAAa;AAAA,EACzC,EAAA,EAAI;AACR,CAAC;AAgBM,MAAM,uBAAuB,gBAAA,CAAiB,OAAA;AAAA,EACjD,wBAAA,CAAyB;AAAA,IACrB,IAAA,EAAM,sBAAA;AAAA,IACN,SAAA,EAAW;AAAA,MACP,IAAA,EAAM,MACF,OAAO,gDAAmC,CAAA,CAAE,IAAA;AAAA,QACxC,OAAK,CAAA,CAAE;AAAA;AACX;AACR,GACH;AACL;AAOO,SAAS,sBAAsB,MAAA,EAAyB;AAC3D,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,sBAAsB,CAAC,CAAA;AACxE;;;;"}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@thecodingsheikh/backstage-plugin-multi-owner",
3
+ "version": "1.0.2",
4
+ "license": "Apache-2.0",
5
+ "main": "./dist/index.esm.js",
6
+ "types": "./dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "backstage": {
11
+ "role": "frontend-plugin",
12
+ "pluginId": "multi-owner",
13
+ "pluginPackages": [
14
+ "@thecodingsheikh/backstage-plugin-multi-owner-common",
15
+ "@thecodingsheikh/backstage-plugin-multi-owner",
16
+ "@thecodingsheikh/backstage-plugin-catalog-backend-module-multi-owner-processor"
17
+ ]
18
+ },
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "start": "backstage-cli package start",
22
+ "build": "backstage-cli package build",
23
+ "lint": "backstage-cli package lint",
24
+ "test": "backstage-cli package test",
25
+ "clean": "backstage-cli package clean",
26
+ "prepack": "backstage-cli package prepack",
27
+ "postpack": "backstage-cli package postpack"
28
+ },
29
+ "dependencies": {
30
+ "@backstage/catalog-model": "^1.7.3",
31
+ "@backstage/core-components": "^0.18.3",
32
+ "@backstage/core-plugin-api": "^1.12.0",
33
+ "@backstage/plugin-catalog-react": "^1.15.3",
34
+ "@backstage/theme": "^0.7.0",
35
+ "@material-ui/core": "^4.9.13",
36
+ "@material-ui/icons": "^4.9.1",
37
+ "@thecodingsheikh/backstage-plugin-multi-owner-common": "^1.0.2",
38
+ "react-use": "^17.2.4"
39
+ },
40
+ "peerDependencies": {
41
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@backstage/cli": "^0.34.5",
45
+ "@backstage/core-app-api": "^1.19.2",
46
+ "@backstage/dev-utils": "^1.1.17",
47
+ "@backstage/test-utils": "^1.7.13",
48
+ "@testing-library/jest-dom": "^6.0.0",
49
+ "@testing-library/react": "^14.0.0",
50
+ "@testing-library/user-event": "^14.0.0",
51
+ "msw": "^1.0.0",
52
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0"
53
+ },
54
+ "files": [
55
+ "dist"
56
+ ],
57
+ "typesVersions": {
58
+ "*": {
59
+ "package.json": [
60
+ "package.json"
61
+ ]
62
+ }
63
+ },
64
+ "module": "./dist/index.esm.js"
65
+ }