@thecodingsheikh/backstage-plugin-multi-owner 1.0.2 → 1.0.3

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.
@@ -1,5 +1,6 @@
1
1
  import { useEntity } from '@backstage/plugin-catalog-react';
2
- import { MULTI_OWNER_ANNOTATION, parseOwners } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
2
+ import { MULTI_OWNER_ANNOTATION } from '../utils/constants.esm.js';
3
+ import { parseOwners } from '../utils/parseOwners.esm.js';
3
4
 
4
5
  function useMultiOwners() {
5
6
  const { entity } = useEntity();
@@ -1 +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;;;;"}
1
+ {"version":3,"file":"useMultiOwners.esm.js","sources":["../../src/hooks/useMultiOwners.ts"],"sourcesContent":["import { useEntity } from '@backstage/plugin-catalog-react';\nimport { MULTI_OWNER_ANNOTATION } from '../utils/constants';\nimport { parseOwners } from '../utils/parseOwners';\nimport type { MultiOwnerEntry } from '../utils/types';\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":";;;;AAiBO,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;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
3
3
  import { Entity } from '@backstage/catalog-model';
4
- import { MultiOwnerEntry } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
5
4
 
6
5
  /** Props for the {@link EntityMultiOwnerCard} component. */
7
6
  interface EntityMultiOwnerCardProps {
@@ -48,6 +47,20 @@ declare const EntityMultiOwnerCard: typeof EntityMultiOwnerCard$1;
48
47
  */
49
48
  declare function isMultiOwnerAvailable(entity: Entity): boolean;
50
49
 
50
+ /**
51
+ * A single owner entry in the multi-owner spec.
52
+ *
53
+ * Can be declared as either:
54
+ * - A plain entity reference string: `"group:default/platform-team"`
55
+ * - An object with a name and optional role: `{ name: "group:default/platform-team", role: "maintainer" }`
56
+ */
57
+ interface MultiOwnerEntry {
58
+ /** Entity reference string, e.g. `"group:default/platform-team"` */
59
+ name: string;
60
+ /** Optional human-readable role label, e.g. `"maintainer"`, `"tech-lead"` */
61
+ role?: string;
62
+ }
63
+
51
64
  /**
52
65
  * Custom hook that reads the multi-owner annotation from the current
53
66
  * entity context and returns a typed array of owner entries.
@@ -57,7 +70,7 @@ declare function isMultiOwnerAvailable(entity: Entity): boolean;
57
70
  *
58
71
  * @example
59
72
  * ```tsx
60
- * const { owners } = useMultiOwners();
73
+ * const { owners } = useMultiOwners();
61
74
  * ```
62
75
  */
63
76
  declare function useMultiOwners(): {
@@ -1,5 +1,5 @@
1
1
  import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';
2
- import { MULTI_OWNER_ANNOTATION } from '@thecodingsheikh/backstage-plugin-multi-owner-common';
2
+ import { MULTI_OWNER_ANNOTATION } from './utils/constants.esm.js';
3
3
 
4
4
  const multiOwnerPlugin = createPlugin({
5
5
  id: "multi-owner"
@@ -1 +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;;;;"}
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 './utils/constants';\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;;;;"}
@@ -0,0 +1,4 @@
1
+ const MULTI_OWNER_ANNOTATION = "backstage.io/owners";
2
+
3
+ export { MULTI_OWNER_ANNOTATION };
4
+ //# sourceMappingURL=constants.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.esm.js","sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * Annotation key used to store the normalized list of owners as JSON\n * on a processed entity. This is written by the backend processor and\n * read by the frontend card.\n */\nexport const MULTI_OWNER_ANNOTATION = 'backstage.io/owners';\n\n/**\n * The field name under `spec` where multiple owners are declared\n * in the entity YAML.\n */\nexport const MULTI_OWNER_SPEC_FIELD = 'owners';\n"],"names":[],"mappings":"AAKO,MAAM,sBAAA,GAAyB;;;;"}
@@ -0,0 +1,28 @@
1
+ function parseOwners(raw) {
2
+ if (!Array.isArray(raw)) {
3
+ return [];
4
+ }
5
+ const result = [];
6
+ for (const entry of raw) {
7
+ if (typeof entry === "string") {
8
+ const trimmed = entry.trim();
9
+ if (trimmed.length > 0) {
10
+ result.push({ name: trimmed });
11
+ }
12
+ } else if (typeof entry === "object" && entry !== null && // @ts-ignore
13
+ typeof entry.name === "string") {
14
+ const trimmedName = entry.name.trim();
15
+ if (trimmedName.length > 0) {
16
+ result.push({
17
+ name: trimmedName,
18
+ // @ts-ignore
19
+ ...entry.role ? { role: entry.role.trim() } : {}
20
+ });
21
+ }
22
+ }
23
+ }
24
+ return result;
25
+ }
26
+
27
+ export { parseOwners };
28
+ //# sourceMappingURL=parseOwners.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseOwners.esm.js","sources":["../../src/utils/parseOwners.ts"],"sourcesContent":["import { MultiOwnerEntry, MultiOwnerSpec } from './types';\n\n/**\n * Normalizes a `spec.owners` value into a consistent array of\n * {@link MultiOwnerEntry} objects.\n *\n * Accepts both string shorthand (`\"group:default/team\"`) and\n * full objects (`{ name: \"group:default/team\", role: \"maintainer\" }`).\n *\n * @param raw - The raw `spec.owners` value from the entity YAML\n * @returns A normalized array of owner entries, or an empty array if input is invalid\n */\nexport function parseOwners(raw: unknown): MultiOwnerEntry[] {\n if (!Array.isArray(raw)) {\n return [];\n }\n\n const result: MultiOwnerEntry[] = [];\n\n for (const entry of raw as MultiOwnerSpec) {\n if (typeof entry === 'string') {\n const trimmed = entry.trim();\n if (trimmed.length > 0) {\n result.push({ name: trimmed });\n }\n } else if (\n typeof entry === 'object' &&\n entry !== null &&\n // @ts-ignore\n typeof entry.name === 'string'\n ) {\n // @ts-ignore\n const trimmedName = entry.name.trim();\n if (trimmedName.length > 0) {\n result.push({\n name: trimmedName,\n // @ts-ignore\n ...(entry.role ? { role: entry.role.trim() } : {}),\n });\n }\n }\n // silently skip malformed entries\n }\n\n return result;\n}\n"],"names":[],"mappings":"AAYO,SAAS,YAAY,GAAA,EAAiC;AACzD,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACrB,IAAA,OAAO,EAAC;AAAA,EACZ;AAEA,EAAA,MAAM,SAA4B,EAAC;AAEnC,EAAA,KAAA,MAAW,SAAS,GAAA,EAAuB;AACvC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,MAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpB,QAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AAAA,MACjC;AAAA,IACJ,CAAA,MAAA,IACI,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA;AAAA,IAEV,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,EACxB;AAEE,MAAA,MAAM,WAAA,GAAc,KAAA,CAAM,IAAA,CAAK,IAAA,EAAK;AACpC,MAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AACxB,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACR,IAAA,EAAM,WAAA;AAAA;AAAA,UAEN,GAAI,KAAA,CAAM,IAAA,GAAO,EAAE,IAAA,EAAM,MAAM,IAAA,CAAK,IAAA,EAAK,EAAE,GAAI;AAAC,SACnD,CAAA;AAAA,MACL;AAAA,IACJ;AAAA,EAEJ;AAEA,EAAA,OAAO,MAAA;AACX;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecodingsheikh/backstage-plugin-multi-owner",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index.esm.js",
6
6
  "types": "./dist/index.d.ts",
@@ -34,7 +34,6 @@
34
34
  "@backstage/theme": "^0.7.0",
35
35
  "@material-ui/core": "^4.9.13",
36
36
  "@material-ui/icons": "^4.9.1",
37
- "@thecodingsheikh/backstage-plugin-multi-owner-common": "^1.0.2",
38
37
  "react-use": "^17.2.4"
39
38
  },
40
39
  "peerDependencies": {