@anyshift/backstage-plugin-anyshift 0.1.0-beta.11 → 0.1.0-beta.13

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,19 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.1.0-beta.13
6
+
7
+ - Keep zero-event cloud-resource pages quiet: identity-completeness codes do not become alerts
8
+ without a returned event, while source and status limits remain one evidence caveat.
9
+
10
+ ## 0.1.0-beta.12
11
+
12
+ - Render cloud Resources through shared Cloud and Anyshift evidence cards, with direct catalog
13
+ dependencies, typed potential impact, cloud changes, IaC evidence, and ARN-scoped Ask.
14
+ - Keep cloud evidence separate from workload/Kubernetes safeguards and make absent catalog, change,
15
+ IaC, or impact evidence explicitly unknown rather than healthy.
16
+
3
17
  ## 0.1.0-beta.11
4
18
 
5
19
  - Add one reusable Ask Anyshift card to the estate dashboard and supported entity pages.
@@ -1,9 +1,10 @@
1
1
  import { stringifyEntityRef } from '@backstage/catalog-model';
2
- import { entityTarget } from '../entity/AnyshiftEntityContent.esm.js';
2
+ import { isCloudResourceEntity, cloudResourceAskTarget, entityTarget } from '../entity/entityIdentity.esm.js';
3
3
 
4
4
  const MAX_TARGET_CODE_POINTS = 200;
5
5
  function askScopeForEntity(entity) {
6
- const target = entityTarget(entity);
6
+ const target = isCloudResourceEntity(entity) ? cloudResourceAskTarget(entity) : entityTarget(entity);
7
+ if (!target) return void 0;
7
8
  if (!isValidTarget(target)) return void 0;
8
9
  return {
9
10
  entityRef: stringifyEntityRef(entity),
@@ -1 +1 @@
1
- {"version":3,"file":"askScope.esm.js","sources":["../../../src/components/ask/askScope.ts"],"sourcesContent":["import { stringifyEntityRef, type Entity } from '@backstage/catalog-model';\nimport type { AskScope } from '../../api/types';\nimport { entityTarget } from '../entity/AnyshiftEntityContent';\n\nconst MAX_TARGET_CODE_POINTS = 200;\n\nexport function askScopeForEntity(entity: Entity): AskScope | undefined {\n const target = entityTarget(entity);\n if (!isValidTarget(target)) return undefined;\n\n return {\n entityRef: stringifyEntityRef(entity),\n target,\n };\n}\n\nfunction isValidTarget(target: string): boolean {\n return (\n Boolean(target.trim()) &&\n Array.from(target).length <= MAX_TARGET_CODE_POINTS &&\n !hasControlCharacter(target)\n );\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return Array.from(value).some(character => {\n const codePoint = character.codePointAt(0);\n return (\n codePoint !== undefined &&\n (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f))\n );\n });\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,sBAAA,GAAyB,GAAA;AAExB,SAAS,kBAAkB,MAAA,EAAsC;AACtE,EAAA,MAAM,MAAA,GAAS,aAAa,MAAM,CAAA;AAClC,EAAA,IAAI,CAAC,aAAA,CAAc,MAAM,CAAA,EAAG,OAAO,MAAA;AAEnC,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,mBAAmB,MAAM,CAAA;AAAA,IACpC;AAAA,GACF;AACF;AAEA,SAAS,cAAc,MAAA,EAAyB;AAC9C,EAAA,OACE,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,CAAA,IACrB,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,IAAU,sBAAA,IAC7B,CAAC,oBAAoB,MAAM,CAAA;AAE/B;AAEA,SAAS,oBAAoB,KAAA,EAAwB;AACnD,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,CAAE,KAAK,CAAA,SAAA,KAAa;AACzC,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,WAAA,CAAY,CAAC,CAAA;AACzC,IAAA,OACE,cAAc,MAAA,KACb,SAAA,IAAa,EAAA,IAAS,SAAA,IAAa,OAAQ,SAAA,IAAa,GAAA,CAAA;AAAA,EAE7D,CAAC,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"askScope.esm.js","sources":["../../../src/components/ask/askScope.ts"],"sourcesContent":["import { stringifyEntityRef, type Entity } from '@backstage/catalog-model';\nimport type { AskScope } from '../../api/types';\nimport {\n cloudResourceAskTarget,\n entityTarget,\n isCloudResourceEntity,\n} from '../entity/entityIdentity';\n\nconst MAX_TARGET_CODE_POINTS = 200;\n\nexport function askScopeForEntity(entity: Entity): AskScope | undefined {\n const target = isCloudResourceEntity(entity)\n ? cloudResourceAskTarget(entity)\n : entityTarget(entity);\n if (!target) return undefined;\n if (!isValidTarget(target)) return undefined;\n\n return {\n entityRef: stringifyEntityRef(entity),\n target,\n };\n}\n\nfunction isValidTarget(target: string): boolean {\n return (\n Boolean(target.trim()) &&\n Array.from(target).length <= MAX_TARGET_CODE_POINTS &&\n !hasControlCharacter(target)\n );\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return Array.from(value).some(character => {\n const codePoint = character.codePointAt(0);\n return (\n codePoint !== undefined &&\n (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f))\n );\n });\n}\n"],"names":[],"mappings":";;;AAQA,MAAM,sBAAA,GAAyB,GAAA;AAExB,SAAS,kBAAkB,MAAA,EAAsC;AACtE,EAAA,MAAM,MAAA,GAAS,sBAAsB,MAAM,CAAA,GACvC,uBAAuB,MAAM,CAAA,GAC7B,aAAa,MAAM,CAAA;AACvB,EAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AACpB,EAAA,IAAI,CAAC,aAAA,CAAc,MAAM,CAAA,EAAG,OAAO,MAAA;AAEnC,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,mBAAmB,MAAM,CAAA;AAAA,IACpC;AAAA,GACF;AACF;AAEA,SAAS,cAAc,MAAA,EAAyB;AAC9C,EAAA,OACE,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,CAAA,IACrB,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,IAAU,sBAAA,IAC7B,CAAC,oBAAoB,MAAM,CAAA;AAE/B;AAEA,SAAS,oBAAoB,KAAA,EAAwB;AACnD,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,CAAE,KAAK,CAAA,SAAA,KAAa;AACzC,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,WAAA,CAAY,CAAC,CAAA;AACzC,IAAA,OACE,cAAc,MAAA,KACb,SAAA,IAAa,EAAA,IAAS,SAAA,IAAa,OAAQ,SAAA,IAAa,GAAA,CAAA;AAAA,EAE7D,CAAC,CAAA;AACH;;;;"}
@@ -0,0 +1,54 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { InfoCard } from '@backstage/core-components';
3
+ import { Alert } from '@material-ui/lab';
4
+ import { Button, Typography } from '@material-ui/core';
5
+
6
+ const BOUNDARY_CAVEAT = "Potential reachability through reviewed graph edges; not proof of outage or causality.";
7
+ const CloudImpactSection = ({
8
+ section,
9
+ onRetry
10
+ }) => /* @__PURE__ */ jsx(InfoCard, { title: "Potential impact", children: section.state === "error" ? /* @__PURE__ */ jsxs(Alert, { severity: "error", children: [
11
+ section.message,
12
+ section.retryable && onRetry && /* @__PURE__ */ jsx(Button, { size: "small", onClick: onRetry, children: "Retry" })
13
+ ] }) : section.state === "unsupported" ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: section.message }) : section.state === "empty" ? /* @__PURE__ */ jsxs(Fragment, { children: [
14
+ /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: section.message || "No potential impact was observed through the reviewed edge set." }),
15
+ /* @__PURE__ */ jsx(BoundaryCaveat, {})
16
+ ] }) : /* @__PURE__ */ jsx(ImpactEvidence, { impact: section.data }) });
17
+ const ImpactEvidence = ({ impact }) => {
18
+ if (!impact) return null;
19
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
20
+ /* @__PURE__ */ jsxs(Typography, { children: [
21
+ /* @__PURE__ */ jsx("strong", { children: impact.total }),
22
+ " potentially impacted resource",
23
+ impact.total === 1 ? "" : "s"
24
+ ] }),
25
+ /* @__PURE__ */ jsxs(Typography, { color: "textSecondary", children: [
26
+ "Evidence ",
27
+ impact.evidence.status,
28
+ " \xB7 maximum depth",
29
+ " ",
30
+ impact.filter.maxDepth
31
+ ] }),
32
+ impact.total === 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No potential impact was observed through the reviewed edge set." }) : impact.items.map((item) => /* @__PURE__ */ jsxs("div", { style: { marginTop: 16 }, children: [
33
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: item.name || item.id || item.hashedID }),
34
+ /* @__PURE__ */ jsxs(Typography, { color: "textSecondary", children: [
35
+ item.kind || "Unknown kind",
36
+ " \xB7 depth ",
37
+ item.depth,
38
+ item.id ? ` \xB7 ${item.id}` : ""
39
+ ] }),
40
+ /* @__PURE__ */ jsx(Typography, { color: "textSecondary", variant: "caption", children: formatPath(item.path) })
41
+ ] }, item.hashedID)),
42
+ /* @__PURE__ */ jsx(BoundaryCaveat, {})
43
+ ] });
44
+ };
45
+ const BoundaryCaveat = () => /* @__PURE__ */ jsx(Typography, { color: "textSecondary", variant: "caption", display: "block", children: BOUNDARY_CAVEAT });
46
+ function formatPath(path) {
47
+ if (path.length === 0) return "No reviewed path details were returned.";
48
+ return path.map(
49
+ (step) => step.relationshipDirection === "reverse" ? `${step.from} \u2190${step.type}\u2014 ${step.to}` : `${step.from} \u2014${step.type}\u2192 ${step.to}`
50
+ ).join(" \xB7 ");
51
+ }
52
+
53
+ export { CloudImpactSection };
54
+ //# sourceMappingURL=CloudImpactSection.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloudImpactSection.esm.js","sources":["../../../src/components/cloud/CloudImpactSection.tsx"],"sourcesContent":["import { InfoCard } from '@backstage/core-components';\nimport { Alert } from '@material-ui/lab';\nimport { Button, Typography } from '@material-ui/core';\nimport type { BriefSection, ImpactResult } from '../../api/types';\n\nconst BOUNDARY_CAVEAT =\n 'Potential reachability through reviewed graph edges; not proof of outage or causality.';\n\nexport const CloudImpactSection = ({\n section,\n onRetry,\n}: {\n section: BriefSection<ImpactResult>;\n onRetry?: () => void;\n}) => (\n <InfoCard title=\"Potential impact\">\n {section.state === 'error' ? (\n <Alert severity=\"error\">\n {section.message}\n {section.retryable && onRetry && (\n <Button size=\"small\" onClick={onRetry}>\n Retry\n </Button>\n )}\n </Alert>\n ) : section.state === 'unsupported' ? (\n <Typography color=\"textSecondary\">{section.message}</Typography>\n ) : section.state === 'empty' ? (\n <>\n <Typography color=\"textSecondary\">\n {section.message ||\n 'No potential impact was observed through the reviewed edge set.'}\n </Typography>\n <BoundaryCaveat />\n </>\n ) : (\n <ImpactEvidence impact={section.data} />\n )}\n </InfoCard>\n);\n\nconst ImpactEvidence = ({ impact }: { impact?: ImpactResult }) => {\n if (!impact) return null;\n return (\n <>\n <Typography>\n <strong>{impact.total}</strong> potentially impacted resource\n {impact.total === 1 ? '' : 's'}\n </Typography>\n <Typography color=\"textSecondary\">\n Evidence {impact.evidence.status} · maximum depth{' '}\n {impact.filter.maxDepth}\n </Typography>\n {impact.total === 0 ? (\n <Typography color=\"textSecondary\">\n No potential impact was observed through the reviewed edge set.\n </Typography>\n ) : (\n impact.items.map(item => (\n <div key={item.hashedID} style={{ marginTop: 16 }}>\n <Typography variant=\"subtitle1\">\n {item.name || item.id || item.hashedID}\n </Typography>\n <Typography color=\"textSecondary\">\n {item.kind || 'Unknown kind'} · depth {item.depth}\n {item.id ? ` · ${item.id}` : ''}\n </Typography>\n <Typography color=\"textSecondary\" variant=\"caption\">\n {formatPath(item.path)}\n </Typography>\n </div>\n ))\n )}\n <BoundaryCaveat />\n </>\n );\n};\n\nconst BoundaryCaveat = () => (\n <Typography color=\"textSecondary\" variant=\"caption\" display=\"block\">\n {BOUNDARY_CAVEAT}\n </Typography>\n);\n\nfunction formatPath(path: ImpactResult['items'][number]['path']): string {\n if (path.length === 0) return 'No reviewed path details were returned.';\n return path\n .map(step =>\n step.relationshipDirection === 'reverse'\n ? `${step.from} ←${step.type}— ${step.to}`\n : `${step.from} —${step.type}→ ${step.to}`,\n )\n .join(' · ');\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { InfoCard } from '@backstage/core-components';
3
+ import { EntityRefLink } from '@backstage/plugin-catalog-react';
4
+ import { Typography } from '@material-ui/core';
5
+
6
+ function relationshipsFor(entity, type) {
7
+ const seen = /* @__PURE__ */ new Set();
8
+ return (entity.relations ?? []).filter((relation) => relation.type === type).filter((relation) => {
9
+ if (seen.has(relation.targetRef)) return false;
10
+ seen.add(relation.targetRef);
11
+ return true;
12
+ }).sort((left, right) => left.targetRef.localeCompare(right.targetRef));
13
+ }
14
+ const RelationshipSection = ({
15
+ entity,
16
+ type,
17
+ title,
18
+ empty
19
+ }) => {
20
+ const relationships = relationshipsFor(entity, type);
21
+ return /* @__PURE__ */ jsx(InfoCard, { title, children: relationships.length === 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: empty }) : /* @__PURE__ */ jsx("ul", { children: relationships.map((relation) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(EntityRefLink, { entityRef: relation.targetRef }) }, relation.targetRef)) }) });
22
+ };
23
+ const CloudDependenciesSection = ({ entity }) => /* @__PURE__ */ jsx(
24
+ RelationshipSection,
25
+ {
26
+ entity,
27
+ type: "dependsOn",
28
+ title: "Dependencies",
29
+ empty: "No dependencies are recorded in the current catalog evidence."
30
+ }
31
+ );
32
+ const CloudDependentsSection = ({ entity }) => /* @__PURE__ */ jsx(
33
+ RelationshipSection,
34
+ {
35
+ entity,
36
+ type: "dependencyOf",
37
+ title: "Dependents",
38
+ empty: "No dependents are recorded in the current catalog evidence."
39
+ }
40
+ );
41
+
42
+ export { CloudDependenciesSection, CloudDependentsSection };
43
+ //# sourceMappingURL=CloudRelationshipSections.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloudRelationshipSections.esm.js","sources":["../../../src/components/cloud/CloudRelationshipSections.tsx"],"sourcesContent":["import { InfoCard } from '@backstage/core-components';\nimport type { Entity } from '@backstage/catalog-model';\nimport { EntityRefLink } from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\n\ntype RelationshipType = 'dependsOn' | 'dependencyOf';\ntype Relation = NonNullable<Entity['relations']>[number];\n\nfunction relationshipsFor(entity: Entity, type: RelationshipType): Relation[] {\n const seen = new Set<string>();\n return (entity.relations ?? [])\n .filter(relation => relation.type === type)\n .filter(relation => {\n if (seen.has(relation.targetRef)) return false;\n seen.add(relation.targetRef);\n return true;\n })\n .sort((left, right) => left.targetRef.localeCompare(right.targetRef));\n}\n\nconst RelationshipSection = ({\n entity,\n type,\n title,\n empty,\n}: {\n entity: Entity;\n type: RelationshipType;\n title: string;\n empty: string;\n}) => {\n const relationships = relationshipsFor(entity, type);\n return (\n <InfoCard title={title}>\n {relationships.length === 0 ? (\n <Typography color=\"textSecondary\">{empty}</Typography>\n ) : (\n <ul>\n {relationships.map(relation => (\n <li key={relation.targetRef}>\n <EntityRefLink entityRef={relation.targetRef} />\n </li>\n ))}\n </ul>\n )}\n </InfoCard>\n );\n};\n\nexport const CloudDependenciesSection = ({ entity }: { entity: Entity }) => (\n <RelationshipSection\n entity={entity}\n type=\"dependsOn\"\n title=\"Dependencies\"\n empty=\"No dependencies are recorded in the current catalog evidence.\"\n />\n);\n\nexport const CloudDependentsSection = ({ entity }: { entity: Entity }) => (\n <RelationshipSection\n entity={entity}\n type=\"dependencyOf\"\n title=\"Dependents\"\n empty=\"No dependents are recorded in the current catalog evidence.\"\n />\n);\n"],"names":[],"mappings":";;;;;AAQA,SAAS,gBAAA,CAAiB,QAAgB,IAAA,EAAoC;AAC5E,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,OAAA,CAAQ,MAAA,CAAO,SAAA,IAAa,EAAC,EAC1B,MAAA,CAAO,CAAA,QAAA,KAAY,QAAA,CAAS,IAAA,KAAS,IAAI,CAAA,CACzC,MAAA,CAAO,CAAA,QAAA,KAAY;AAClB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,SAAS,GAAG,OAAO,KAAA;AACzC,IAAA,IAAA,CAAK,GAAA,CAAI,SAAS,SAAS,CAAA;AAC3B,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,IAAA,EAAM,KAAA,KAAU,IAAA,CAAK,SAAA,CAAU,aAAA,CAAc,KAAA,CAAM,SAAS,CAAC,CAAA;AACxE;AAEA,MAAM,sBAAsB,CAAC;AAAA,EAC3B,MAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,KAKM;AACJ,EAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,MAAA,EAAQ,IAAI,CAAA;AACnD,EAAA,uBACE,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EACP,QAAA,EAAA,aAAA,CAAc,MAAA,KAAW,CAAA,mBACxB,GAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAM,eAAA,EAAiB,QAAA,EAAA,KAAA,EAAM,CAAA,mBAEzC,GAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,aAAA,CAAc,GAAA,CAAI,CAAA,QAAA,qBACjB,GAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EAAW,QAAA,CAAS,SAAA,EAAW,CAAA,EAAA,EADvC,QAAA,CAAS,SAElB,CACD,GACH,CAAA,EAEJ,CAAA;AAEJ,CAAA;AAEO,MAAM,wBAAA,GAA2B,CAAC,EAAE,MAAA,EAAO,qBAChD,GAAA;AAAA,EAAC,mBAAA;AAAA,EAAA;AAAA,IACC,MAAA;AAAA,IACA,IAAA,EAAK,WAAA;AAAA,IACL,KAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAM;AAAA;AACR;AAGK,MAAM,sBAAA,GAAyB,CAAC,EAAE,MAAA,EAAO,qBAC9C,GAAA;AAAA,EAAC,mBAAA;AAAA,EAAA;AAAA,IACC,MAAA;AAAA,IACA,IAAA,EAAK,cAAA;AAAA,IACL,KAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAM;AAAA;AACR;;;;"}
@@ -1,44 +1,82 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { useState, useCallback, useEffect } from 'react';
2
+ import { useState, useRef, useMemo, useLayoutEffect, useCallback, useEffect } from 'react';
3
3
  import { Button, Grid, Typography, CircularProgress, Chip } from '@material-ui/core';
4
4
  import { Alert } from '@material-ui/lab';
5
5
  import { Progress, InfoCard, Link } from '@backstage/core-components';
6
6
  import { useApi } from '@backstage/frontend-plugin-api';
7
- import { ANYSHIFT_RESOURCE_ID_ANNOTATION, ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION, ANYSHIFT_CLOUD_PROVIDER_ANNOTATION, ANYSHIFT_RESOURCE_TYPE_ANNOTATION, ANYSHIFT_CLOUD_REGION_ANNOTATION, ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
8
- import { useEntity, EntityRefLink } from '@backstage/plugin-catalog-react';
7
+ import { ANYSHIFT_CLOUD_PROVIDER_ANNOTATION, ANYSHIFT_RESOURCE_TYPE_ANNOTATION, ANYSHIFT_CLOUD_REGION_ANNOTATION, ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
8
+ import { useEntity } from '@backstage/plugin-catalog-react';
9
9
  import { anyshiftApiRef } from '../../api/AnyshiftApi.esm.js';
10
+ import { AskAnyshiftCard } from '../ask/AskAnyshiftCard.esm.js';
11
+ import { askScopeForEntity } from '../ask/askScope.esm.js';
12
+ import { cloudResourceIdentity } from '../entity/entityIdentity.esm.js';
13
+ import { CloudImpactSection } from './CloudImpactSection.esm.js';
14
+ import { CloudDependenciesSection, CloudDependentsSection } from './CloudRelationshipSections.esm.js';
10
15
 
11
- function cloudResourceIdentity(entity) {
12
- const annotations = entity.metadata.annotations ?? {};
13
- return annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION] || annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION];
14
- }
15
- const CloudResourceContent = () => {
16
+ const CloudResourceContent = () => /* @__PURE__ */ jsx(CloudResourceEvidenceContent, {});
17
+ const CloudAnyshiftEntityContent = () => /* @__PURE__ */ jsx(CloudResourceEvidenceContent, { includeAsk: true });
18
+ const CloudResourceEvidenceContent = ({ includeAsk = false }) => {
16
19
  const { entity } = useEntity();
17
20
  const api = useApi(anyshiftApiRef);
18
21
  const resourceId = cloudResourceIdentity(entity);
19
- const [brief, setBrief] = useState();
22
+ const [loadedBrief, setLoadedBrief] = useState();
23
+ const brief = loadedBrief && loadedBrief.resourceId === resourceId ? loadedBrief.value : void 0;
20
24
  const [error, setError] = useState();
21
25
  const [refreshing, setRefreshing] = useState(false);
22
26
  const [loadingMore, setLoadingMore] = useState(false);
27
+ const [paginationError, setPaginationError] = useState();
28
+ const [capabilities, setCapabilities] = useState({
29
+ askEnabled: false,
30
+ queryEnabled: false
31
+ });
32
+ const operations = useRef({ identity: 0, primary: 0, pagination: 0 });
33
+ const askScope = useMemo(
34
+ () => includeAsk ? askScopeForEntity(entity) : void 0,
35
+ [entity, includeAsk]
36
+ );
37
+ useLayoutEffect(() => {
38
+ operations.current.identity += 1;
39
+ operations.current.primary += 1;
40
+ operations.current.pagination += 1;
41
+ setLoadedBrief(void 0);
42
+ setError(void 0);
43
+ setRefreshing(false);
44
+ setLoadingMore(false);
45
+ setPaginationError(void 0);
46
+ }, [resourceId]);
23
47
  const load = useCallback(
24
48
  async (refresh = false) => {
25
49
  if (!resourceId) return;
50
+ const identity = operations.current.identity;
51
+ const primary = ++operations.current.primary;
52
+ ++operations.current.pagination;
26
53
  setRefreshing(refresh);
54
+ setLoadingMore(false);
55
+ setPaginationError(void 0);
27
56
  setError(void 0);
28
57
  try {
29
- setBrief(
30
- await api.cloudResourceBrief(resourceId, {
31
- since: "24h",
32
- diff: true,
33
- refresh
34
- })
35
- );
58
+ const next = await api.cloudResourceBrief(resourceId, {
59
+ since: "24h",
60
+ diff: true,
61
+ ...refresh ? { refresh: true } : {}
62
+ });
63
+ if (operations.current.identity === identity && operations.current.primary === primary) {
64
+ ++operations.current.pagination;
65
+ setLoadingMore(false);
66
+ setLoadedBrief({ resourceId, value: next });
67
+ }
36
68
  } catch (loadError) {
37
- setError(
38
- loadError instanceof Error ? loadError.message : "Unable to load cloud evidence"
39
- );
69
+ if (operations.current.identity === identity && operations.current.primary === primary) {
70
+ ++operations.current.pagination;
71
+ setLoadingMore(false);
72
+ setError(
73
+ loadError instanceof Error ? loadError.message : "Unable to load cloud evidence"
74
+ );
75
+ }
40
76
  } finally {
41
- setRefreshing(false);
77
+ if (operations.current.identity === identity && operations.current.primary === primary) {
78
+ setRefreshing(false);
79
+ }
42
80
  }
43
81
  },
44
82
  [api, resourceId]
@@ -46,41 +84,71 @@ const CloudResourceContent = () => {
46
84
  useEffect(() => {
47
85
  void load();
48
86
  }, [load]);
87
+ useEffect(() => {
88
+ if (!includeAsk) return void 0;
89
+ let active = true;
90
+ api.capabilities().then((next) => active && setCapabilities(next)).catch(
91
+ () => active && setCapabilities({ askEnabled: false, queryEnabled: false })
92
+ );
93
+ return () => {
94
+ active = false;
95
+ };
96
+ }, [api, includeAsk]);
49
97
  const loadMore = useCallback(async () => {
50
98
  const cursor = brief?.changes.data?.page.nextCursor;
51
99
  if (!resourceId || !cursor) return;
100
+ const identity = operations.current.identity;
101
+ const primary = operations.current.primary;
102
+ const pagination = ++operations.current.pagination;
52
103
  setLoadingMore(true);
104
+ setPaginationError(void 0);
53
105
  try {
54
106
  const next = await api.cloudResourceBrief(resourceId, {
55
107
  since: brief.since,
56
108
  diff: true,
57
109
  cursor
58
110
  });
59
- setBrief((current) => {
60
- if (!current?.changes.data || next.changes.state !== "data" || !next.changes.data) {
111
+ if (operations.current.identity !== identity || operations.current.primary !== primary || operations.current.pagination !== pagination) {
112
+ return;
113
+ }
114
+ if (next.changes.state === "error") {
115
+ setPaginationError(
116
+ next.changes.message || "Unable to load more cloud changes"
117
+ );
118
+ return;
119
+ }
120
+ if (next.changes.state === "data" && next.changes.data) {
121
+ setPaginationError(void 0);
122
+ }
123
+ setLoadedBrief((current) => {
124
+ if (!current || current.resourceId !== resourceId || !current.value.changes.data || next.changes.state !== "data" || !next.changes.data) {
61
125
  return current;
62
126
  }
63
127
  return {
64
- ...current,
65
- refreshedAt: next.refreshedAt,
66
- changes: {
67
- state: "data",
68
- data: {
69
- ...next.changes.data,
70
- items: [
71
- ...current.changes.data.items,
72
- ...next.changes.data.items
73
- ]
128
+ resourceId,
129
+ value: {
130
+ ...current.value,
131
+ refreshedAt: next.refreshedAt,
132
+ changes: {
133
+ state: "data",
134
+ data: mergeCloudEventsEvidence(
135
+ current.value.changes.data,
136
+ next.changes.data
137
+ )
74
138
  }
75
139
  }
76
140
  };
77
141
  });
78
142
  } catch (loadError) {
79
- setError(
80
- loadError instanceof Error ? loadError.message : "Unable to load more cloud changes"
81
- );
143
+ if (operations.current.identity === identity && operations.current.primary === primary && operations.current.pagination === pagination) {
144
+ setPaginationError(
145
+ loadError instanceof Error ? loadError.message : "Unable to load more cloud changes"
146
+ );
147
+ }
82
148
  } finally {
83
- setLoadingMore(false);
149
+ if (operations.current.identity === identity && operations.current.primary === primary && operations.current.pagination === pagination) {
150
+ setLoadingMore(false);
151
+ }
84
152
  }
85
153
  }, [api, brief, resourceId]);
86
154
  if (!resourceId) {
@@ -103,10 +171,50 @@ const CloudResourceContent = () => {
103
171
  onRefresh: () => void load(true),
104
172
  loadingMore,
105
173
  onLoadMore: () => void loadMore(),
106
- error
174
+ error,
175
+ paginationError,
176
+ askEnabled: includeAsk && capabilities.askEnabled && Boolean(askScope),
177
+ askScope
107
178
  }
108
179
  );
109
180
  };
181
+ function mergeCloudEventsEvidence(current, next) {
182
+ return {
183
+ ...next,
184
+ availability: mergeCloudEventAvailability(
185
+ current.availability,
186
+ next.availability
187
+ ),
188
+ warnings: [.../* @__PURE__ */ new Set([...current.warnings, ...next.warnings])],
189
+ items: [...current.items, ...next.items]
190
+ };
191
+ }
192
+ function mergeCloudEventAvailability(current, next) {
193
+ const availability = {};
194
+ for (const field of /* @__PURE__ */ new Set([
195
+ ...Object.keys(current),
196
+ ...Object.keys(next)
197
+ ])) {
198
+ availability[field] = leastCompleteAvailability(
199
+ current[field],
200
+ next[field]
201
+ );
202
+ }
203
+ return availability;
204
+ }
205
+ function leastCompleteAvailability(current, next) {
206
+ const normalizedCurrent = normalizeAvailability(current);
207
+ const normalizedNext = normalizeAvailability(next);
208
+ return AVAILABILITY_RANK[normalizedCurrent] <= AVAILABILITY_RANK[normalizedNext] ? normalizedCurrent : normalizedNext;
209
+ }
210
+ const AVAILABILITY_RANK = {
211
+ unavailable: 0,
212
+ partial: 1,
213
+ available: 2
214
+ };
215
+ function normalizeAvailability(value) {
216
+ return value && value in AVAILABILITY_RANK ? value : "unavailable";
217
+ }
110
218
  const CloudResourceBriefView = ({
111
219
  entity,
112
220
  brief,
@@ -114,12 +222,12 @@ const CloudResourceBriefView = ({
114
222
  onRefresh,
115
223
  loadingMore,
116
224
  onLoadMore,
117
- error
225
+ error,
226
+ paginationError,
227
+ askEnabled = false,
228
+ askScope
118
229
  }) => {
119
230
  const annotations = entity.metadata.annotations ?? {};
120
- const relationships = (entity.relations ?? []).filter(
121
- (relation) => ["dependencyOf", "dependsOn"].includes(relation.type)
122
- );
123
231
  const consoleLink = entity.metadata.links?.find(
124
232
  (link) => link.url.startsWith("https://console.aws.amazon.com/")
125
233
  );
@@ -134,7 +242,6 @@ const CloudResourceBriefView = ({
134
242
  {
135
243
  size: "small",
136
244
  onClick: onRefresh,
137
- disabled: refreshing,
138
245
  startIcon: refreshing ? /* @__PURE__ */ jsx(CircularProgress, { size: 14 }) : void 0,
139
246
  children: "Refresh"
140
247
  }
@@ -148,17 +255,7 @@ const CloudResourceBriefView = ({
148
255
  ] })
149
256
  }
150
257
  ) }),
151
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
152
- ChangesSection,
153
- {
154
- section: brief.changes,
155
- loadingMore,
156
- onLoadMore
157
- }
158
- ) }),
159
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(ProvenanceSection, { section: brief.provenance }) }),
160
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(DriftSection, { section: brief.drift }) }),
161
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsxs(InfoCard, { title: "Cloud identity", children: [
258
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(InfoCard, { title: "Cloud identity", children: [
162
259
  /* @__PURE__ */ jsx(
163
260
  Definition,
164
261
  {
@@ -187,137 +284,174 @@ const CloudResourceBriefView = ({
187
284
  value: annotations[ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION]
188
285
  }
189
286
  ),
287
+ /* @__PURE__ */ jsx(Definition, { label: "Stable resource ID", value: brief.resourceId }),
190
288
  consoleLink && /* @__PURE__ */ jsx(Link, { to: consoleLink.url, children: "Open in AWS Console" })
191
289
  ] }) }),
192
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsxs(InfoCard, { title: "Catalog context", children: [
193
- /* @__PURE__ */ jsx(
194
- Definition,
195
- {
196
- label: "Owner",
197
- value: typeof entity.spec?.owner === "string" ? entity.spec.owner : void 0
198
- }
199
- ),
200
- /* @__PURE__ */ jsx(
201
- Definition,
202
- {
203
- label: "Namespace",
204
- value: entity.metadata.namespace || "default"
205
- }
206
- ),
207
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", children: "Relationships" }),
208
- relationships.length === 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No component or resource relationships are available yet." }) : /* @__PURE__ */ jsx("ul", { children: relationships.map((relation) => /* @__PURE__ */ jsxs("li", { children: [
209
- /* @__PURE__ */ jsx(
210
- Chip,
211
- {
212
- size: "small",
213
- label: relation.type,
214
- style: { marginRight: 8 }
215
- }
216
- ),
217
- /* @__PURE__ */ jsx(EntityRefLink, { entityRef: relation.targetRef })
218
- ] }, `${relation.type}:${relation.targetRef}`)) })
219
- ] }) }),
220
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(InfoCard, { title: "Stable resource identity", children: /* @__PURE__ */ jsx(
221
- Typography,
290
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(CloudDependenciesSection, { entity }) }),
291
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(CloudDependentsSection, { entity }) }),
292
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(CloudImpactSection, { section: brief.impact, onRetry: onRefresh }) }),
293
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
294
+ ChangesSection,
222
295
  {
223
- component: "code",
224
- style: { overflowWrap: "anywhere", whiteSpace: "pre-wrap" },
225
- children: brief.resourceId
296
+ section: brief.changes,
297
+ loadingMore,
298
+ onLoadMore,
299
+ paginationError
226
300
  }
227
- ) }) })
301
+ ) }),
302
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(ProvenanceSection, { section: brief.provenance }) }),
303
+ /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(DriftSection, { section: brief.drift }) }),
304
+ askEnabled && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(AskAnyshiftCard, { context: "entity", scope: askScope }) })
228
305
  ] });
229
306
  };
230
307
  const ChangesSection = ({
231
308
  section,
232
309
  loadingMore,
233
- onLoadMore
234
- }) => /* @__PURE__ */ jsx(InfoCard, { title: "Recent cloud changes", children: /* @__PURE__ */ jsxs(SectionState, { section, children: [
235
- section.data?.warnings?.map((warning) => /* @__PURE__ */ jsx(Alert, { severity: "warning", style: { marginBottom: 8 }, children: humanize(warning) }, warning)),
236
- section.data?.items?.length ? section.data.items.map((event) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 20 }, children: [
237
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: event.summary || humanize(event.type) }),
238
- /* @__PURE__ */ jsxs(Typography, { color: "textSecondary", children: [
239
- formatCloudTimestamp(event.timestamp),
240
- " \xB7 ",
241
- event.category,
242
- " \xB7",
243
- " ",
244
- event.evidence.source,
245
- " \xB7 ",
246
- event.evidence.status,
247
- event.actor?.name || event.actor?.id ? ` \xB7 ${event.actor.name || event.actor.id}` : ""
248
- ] }),
249
- event.change.fields.length > 0 && /* @__PURE__ */ jsxs("details", { children: [
250
- /* @__PURE__ */ jsx("summary", { children: "View sanitized field changes" }),
251
- /* @__PURE__ */ jsx("ul", { children: event.change.fields.map((field) => {
252
- const detail = event.change.details.find(
253
- (candidate) => candidate.field === field
254
- );
255
- return /* @__PURE__ */ jsxs("li", { children: [
256
- /* @__PURE__ */ jsx("code", { children: field }),
257
- detail ? `: ${detail.before ?? "\u2205"} \u2192 ${detail.after ?? "\u2205"}` : ""
258
- ] }, field);
259
- }) })
260
- ] })
261
- ] }, event.id)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No cloud changes were found in this window." }),
262
- section.data?.page.hasMore && onLoadMore && /* @__PURE__ */ jsx(
263
- Button,
264
- {
265
- size: "small",
266
- onClick: onLoadMore,
267
- disabled: loadingMore,
268
- startIcon: loadingMore ? /* @__PURE__ */ jsx(CircularProgress, { size: 14 }) : void 0,
269
- children: "Load more changes"
270
- }
271
- )
272
- ] }) });
310
+ onLoadMore,
311
+ paginationError
312
+ }) => {
313
+ const { hasEvidenceLimitations, actionableWarnings } = partitionCloudEventWarnings(
314
+ section.data?.warnings,
315
+ section.data?.items.length ?? 0
316
+ );
317
+ if (section.state === "empty") {
318
+ return /* @__PURE__ */ jsx(InfoCard, { title: "Recent cloud changes", children: /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: section.message || "No cloud changes were found in this window." }) });
319
+ }
320
+ return /* @__PURE__ */ jsx(InfoCard, { title: "Recent cloud changes", children: /* @__PURE__ */ jsxs(SectionState, { section, children: [
321
+ paginationError && /* @__PURE__ */ jsx(Alert, { severity: "error", style: { marginBottom: 8 }, children: paginationError }),
322
+ hasEvidenceLimitations && /* @__PURE__ */ jsx(
323
+ Typography,
324
+ {
325
+ "aria-label": "Cloud event evidence limitations",
326
+ variant: "caption",
327
+ color: "textSecondary",
328
+ display: "block",
329
+ style: { marginBottom: 8 },
330
+ children: "Event source is derived from graph relationships, and event status may be incomplete."
331
+ }
332
+ ),
333
+ actionableWarnings.map((warning) => /* @__PURE__ */ jsx(Alert, { severity: "warning", style: { marginBottom: 8 }, children: humanize(warning) }, warning)),
334
+ section.data?.items?.length ? section.data.items.map((event) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 20 }, children: [
335
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: event.summary || humanize(event.type) }),
336
+ /* @__PURE__ */ jsxs(Typography, { color: "textSecondary", children: [
337
+ formatCloudTimestamp(event.timestamp),
338
+ " \xB7 ",
339
+ event.category,
340
+ " \xB7",
341
+ " ",
342
+ event.evidence.source,
343
+ " \xB7 ",
344
+ event.evidence.status,
345
+ event.actor?.name || event.actor?.id ? ` \xB7 ${event.actor.name || event.actor.id}` : ""
346
+ ] }),
347
+ event.change.fields.length > 0 && /* @__PURE__ */ jsxs("details", { children: [
348
+ /* @__PURE__ */ jsx("summary", { children: "View sanitized field changes" }),
349
+ /* @__PURE__ */ jsx("ul", { children: event.change.fields.map((field) => {
350
+ const detail = event.change.details.find(
351
+ (candidate) => candidate.field === field
352
+ );
353
+ return /* @__PURE__ */ jsxs("li", { children: [
354
+ /* @__PURE__ */ jsx("code", { children: field }),
355
+ detail ? `: ${detail.before ?? "\u2205"} \u2192 ${detail.after ?? "\u2205"}` : ""
356
+ ] }, field);
357
+ }) })
358
+ ] })
359
+ ] }, event.id)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No cloud changes were found in this window." }),
360
+ section.data?.page.hasMore && onLoadMore && /* @__PURE__ */ jsx(
361
+ Button,
362
+ {
363
+ size: "small",
364
+ onClick: onLoadMore,
365
+ disabled: loadingMore,
366
+ startIcon: loadingMore ? /* @__PURE__ */ jsx(CircularProgress, { size: 14 }) : void 0,
367
+ children: "Load more changes"
368
+ }
369
+ )
370
+ ] }) });
371
+ };
372
+ const QUIET_EVIDENCE_LIMITATIONS = /* @__PURE__ */ new Set([
373
+ "event_source_derived",
374
+ "event_status_incomplete"
375
+ ]);
376
+ const IDENTITY_COMPLETENESS_WARNINGS = /* @__PURE__ */ new Set([
377
+ "target_identity_incomplete",
378
+ "actor_identity_incomplete"
379
+ ]);
380
+ function partitionCloudEventWarnings(warnings, eventCount) {
381
+ const allWarnings = warnings ?? [];
382
+ return {
383
+ hasEvidenceLimitations: allWarnings.some(
384
+ (warning) => QUIET_EVIDENCE_LIMITATIONS.has(warning)
385
+ ),
386
+ actionableWarnings: allWarnings.filter(
387
+ (warning) => !QUIET_EVIDENCE_LIMITATIONS.has(warning) && (eventCount > 0 || !IDENTITY_COMPLETENESS_WARNINGS.has(warning))
388
+ )
389
+ };
390
+ }
273
391
  const ProvenanceSection = ({
274
392
  section
275
- }) => /* @__PURE__ */ jsx(InfoCard, { title: "IaC provenance", children: /* @__PURE__ */ jsx(SectionState, { section, children: section.data?.resources?.length ? section.data.resources.map((resource) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
276
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: resource.terraform.address }),
277
- /* @__PURE__ */ jsx(Chip, { size: "small", label: humanize(resource.status) }),
278
- /* @__PURE__ */ jsx(Definition, { label: "File", value: resource.terraform.fileRef ?? "" }),
279
- /* @__PURE__ */ jsx(
280
- Definition,
281
- {
282
- label: "State links",
283
- value: String(resource.states.length)
284
- }
285
- ),
286
- /* @__PURE__ */ jsx(
287
- Definition,
288
- {
289
- label: "Cloud links",
290
- value: String(resource.clouds.length)
291
- }
292
- ),
293
- resource.terraform.githubUrl && /* @__PURE__ */ jsx(Link, { to: resource.terraform.githubUrl, children: "Open source" })
294
- ] }, resource.terraform.hashedID)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No Terraform provenance is linked to this resource." }) }) });
393
+ }) => {
394
+ if (section.state === "empty") {
395
+ return /* @__PURE__ */ jsx(InfoCard, { title: "IaC provenance", children: /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: section.message || "No Terraform provenance is linked to this resource." }) });
396
+ }
397
+ return /* @__PURE__ */ jsx(InfoCard, { title: "IaC provenance", children: /* @__PURE__ */ jsx(SectionState, { section, children: section.data?.resources?.length ? section.data.resources.map((resource) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
398
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: resource.terraform.address }),
399
+ /* @__PURE__ */ jsx(Chip, { size: "small", label: humanize(resource.status) }),
400
+ /* @__PURE__ */ jsx(
401
+ Definition,
402
+ {
403
+ label: "File",
404
+ value: resource.terraform.fileRef ?? ""
405
+ }
406
+ ),
407
+ /* @__PURE__ */ jsx(
408
+ Definition,
409
+ {
410
+ label: "State links",
411
+ value: String(resource.states.length)
412
+ }
413
+ ),
414
+ /* @__PURE__ */ jsx(
415
+ Definition,
416
+ {
417
+ label: "Cloud links",
418
+ value: String(resource.clouds.length)
419
+ }
420
+ ),
421
+ resource.terraform.githubUrl && /* @__PURE__ */ jsx(Link, { to: resource.terraform.githubUrl, children: "Open source" })
422
+ ] }, resource.terraform.hashedID)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No Terraform provenance is linked to this resource." }) }) });
423
+ };
295
424
  const DriftSection = ({
296
425
  section
297
- }) => /* @__PURE__ */ jsx(InfoCard, { title: "IaC drift evidence", children: /* @__PURE__ */ jsx(SectionState, { section, children: section.data?.items?.length ? section.data.items.map((item) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
298
- /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: item.terraform.address }),
299
- /* @__PURE__ */ jsx(
300
- Chip,
301
- {
302
- size: "small",
303
- color: item.status === "drifted" ? "secondary" : "default",
304
- label: humanize(item.status)
305
- }
306
- ),
307
- /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: item.status === "unknown" ? `Unknown is not drift: ${humanize(item.reason)}.` : `${item.comparedFields} supported fields compared.` }),
308
- item.differences.length > 0 && /* @__PURE__ */ jsxs("details", { children: [
309
- /* @__PURE__ */ jsx("summary", { children: "View sanitized differences" }),
310
- /* @__PURE__ */ jsx("ul", { children: item.differences.map((difference) => /* @__PURE__ */ jsxs("li", { children: [
311
- /* @__PURE__ */ jsx("code", { children: difference.field }),
312
- ":",
313
- " ",
314
- difference.lastApplied ?? "\u2205",
315
- " \u2192",
316
- " ",
317
- difference.observed ?? "\u2205"
318
- ] }, difference.field)) })
319
- ] })
320
- ] }, item.terraform.hashedID)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No comparable Terraform evidence is available." }) }) });
426
+ }) => {
427
+ if (section.state === "empty") {
428
+ return /* @__PURE__ */ jsx(InfoCard, { title: "IaC drift evidence", children: /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: section.message || "No comparable Terraform evidence is available." }) });
429
+ }
430
+ return /* @__PURE__ */ jsx(InfoCard, { title: "IaC drift evidence", children: /* @__PURE__ */ jsx(SectionState, { section, children: section.data?.items?.length ? section.data.items.map((item) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
431
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle1", children: item.terraform.address }),
432
+ /* @__PURE__ */ jsx(
433
+ Chip,
434
+ {
435
+ size: "small",
436
+ color: item.status === "drifted" ? "secondary" : "default",
437
+ label: humanize(item.status)
438
+ }
439
+ ),
440
+ /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: item.status === "unknown" ? `Unknown is not drift: ${humanize(item.reason)}.` : `${item.comparedFields} supported fields compared.` }),
441
+ item.differences.length > 0 && /* @__PURE__ */ jsxs("details", { children: [
442
+ /* @__PURE__ */ jsx("summary", { children: "View sanitized differences" }),
443
+ /* @__PURE__ */ jsx("ul", { children: item.differences.map((difference) => /* @__PURE__ */ jsxs("li", { children: [
444
+ /* @__PURE__ */ jsx("code", { children: difference.field }),
445
+ ":",
446
+ " ",
447
+ difference.lastApplied ?? "\u2205",
448
+ " \u2192",
449
+ " ",
450
+ difference.observed ?? "\u2205"
451
+ ] }, difference.field)) })
452
+ ] })
453
+ ] }, item.terraform.hashedID)) : /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: "No comparable Terraform evidence is available." }) }) });
454
+ };
321
455
  const SectionState = ({
322
456
  section,
323
457
  children
@@ -354,5 +488,5 @@ function formatCloudTimestamp(value) {
354
488
  return Number.isNaN(normalizedTimestamp) ? value : new Date(normalizedTimestamp).toLocaleString();
355
489
  }
356
490
 
357
- export { CloudResourceBriefView, CloudResourceContent, cloudResourceIdentity, formatCloudTimestamp };
491
+ export { CloudAnyshiftEntityContent, CloudResourceBriefView, CloudResourceContent, formatCloudTimestamp, mergeCloudEventsEvidence };
358
492
  //# sourceMappingURL=CloudResourceContent.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CloudResourceContent.esm.js","sources":["../../../src/components/cloud/CloudResourceContent.tsx"],"sourcesContent":["import { useCallback, useEffect, useState, type ReactNode } from 'react';\nimport {\n Button,\n Chip,\n CircularProgress,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport { InfoCard, Link, Progress } from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport type { Entity } from '@backstage/catalog-model';\nimport {\n ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION,\n ANYSHIFT_CLOUD_PROVIDER_ANNOTATION,\n ANYSHIFT_CLOUD_REGION_ANNOTATION,\n ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION,\n ANYSHIFT_RESOURCE_ID_ANNOTATION,\n ANYSHIFT_RESOURCE_TYPE_ANNOTATION,\n type BriefSection,\n type CloudEventsEvidence,\n type CloudResourceBrief,\n type IacDriftEvidence,\n type IacEvidence,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport { EntityRefLink, useEntity } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\n\nexport function cloudResourceIdentity(entity: Entity): string | undefined {\n const annotations = entity.metadata.annotations ?? {};\n return (\n annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION] ||\n annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION]\n );\n}\n\nexport const CloudResourceContent = () => {\n const { entity } = useEntity();\n const api = useApi(anyshiftApiRef);\n const resourceId = cloudResourceIdentity(entity);\n const [brief, setBrief] = useState<CloudResourceBrief>();\n const [error, setError] = useState<string>();\n const [refreshing, setRefreshing] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n\n const load = useCallback(\n async (refresh = false) => {\n if (!resourceId) return;\n setRefreshing(refresh);\n setError(undefined);\n try {\n setBrief(\n await api.cloudResourceBrief(resourceId, {\n since: '24h',\n diff: true,\n refresh,\n }),\n );\n } catch (loadError) {\n setError(\n loadError instanceof Error\n ? loadError.message\n : 'Unable to load cloud evidence',\n );\n } finally {\n setRefreshing(false);\n }\n },\n [api, resourceId],\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const loadMore = useCallback(async () => {\n const cursor = brief?.changes.data?.page.nextCursor;\n if (!resourceId || !cursor) return;\n setLoadingMore(true);\n try {\n const next = await api.cloudResourceBrief(resourceId, {\n since: brief.since,\n diff: true,\n cursor,\n });\n setBrief(current => {\n if (\n !current?.changes.data ||\n next.changes.state !== 'data' ||\n !next.changes.data\n ) {\n return current;\n }\n return {\n ...current,\n refreshedAt: next.refreshedAt,\n changes: {\n state: 'data',\n data: {\n ...next.changes.data,\n items: [\n ...current.changes.data.items,\n ...next.changes.data.items,\n ],\n },\n },\n };\n });\n } catch (loadError) {\n setError(\n loadError instanceof Error\n ? loadError.message\n : 'Unable to load more cloud changes',\n );\n } finally {\n setLoadingMore(false);\n }\n }, [api, brief, resourceId]);\n\n if (!resourceId) {\n return (\n <Alert severity=\"info\">\n This catalog entity has no stable Anyshift resource ID or cloud ARN.\n </Alert>\n );\n }\n if (error && !brief) {\n return (\n <Alert severity=\"error\">\n {error} <Button onClick={() => void load(true)}>Retry</Button>\n </Alert>\n );\n }\n if (!brief) return <Progress />;\n\n return (\n <CloudResourceBriefView\n entity={entity}\n brief={brief}\n refreshing={refreshing}\n onRefresh={() => void load(true)}\n loadingMore={loadingMore}\n onLoadMore={() => void loadMore()}\n error={error}\n />\n );\n};\n\nexport const CloudResourceBriefView = ({\n entity,\n brief,\n refreshing,\n onRefresh,\n loadingMore,\n onLoadMore,\n error,\n}: {\n entity: Entity;\n brief: CloudResourceBrief;\n refreshing?: boolean;\n onRefresh: () => void;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n error?: string;\n}) => {\n const annotations = entity.metadata.annotations ?? {};\n const relationships = (entity.relations ?? []).filter(relation =>\n ['dependencyOf', 'dependsOn'].includes(relation.type),\n );\n const consoleLink = entity.metadata.links?.find(link =>\n link.url.startsWith('https://console.aws.amazon.com/'),\n );\n\n return (\n <Grid container spacing={3}>\n {error && (\n <Grid item xs={12}>\n <Alert severity=\"error\">{error}</Alert>\n </Grid>\n )}\n <Grid item xs={12}>\n <InfoCard\n title=\"Cloud evidence\"\n action={\n <Button\n size=\"small\"\n onClick={onRefresh}\n disabled={refreshing}\n startIcon={\n refreshing ? <CircularProgress size={14} /> : undefined\n }\n >\n Refresh\n </Button>\n }\n >\n <Typography color=\"textSecondary\">\n Read-only Anyshift evidence · last refreshed{' '}\n {formatCloudTimestamp(brief.refreshedAt)} · window {brief.since}\n </Typography>\n </InfoCard>\n </Grid>\n\n <Grid item xs={12}>\n <ChangesSection\n section={brief.changes}\n loadingMore={loadingMore}\n onLoadMore={onLoadMore}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <ProvenanceSection section={brief.provenance} />\n </Grid>\n <Grid item xs={12} md={6}>\n <DriftSection section={brief.drift} />\n </Grid>\n\n <Grid item xs={12} md={6}>\n <InfoCard title=\"Cloud identity\">\n <Definition\n label=\"Provider\"\n value={annotations[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION]}\n />\n <Definition\n label=\"Resource type\"\n value={\n annotations[ANYSHIFT_RESOURCE_TYPE_ANNOTATION] ||\n String(entity.spec?.type || '')\n }\n />\n <Definition\n label=\"Region\"\n value={annotations[ANYSHIFT_CLOUD_REGION_ANNOTATION] || 'Global'}\n />\n <Definition\n label=\"Account\"\n value={annotations[ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION]}\n />\n {consoleLink && <Link to={consoleLink.url}>Open in AWS Console</Link>}\n </InfoCard>\n </Grid>\n <Grid item xs={12} md={6}>\n <InfoCard title=\"Catalog context\">\n <Definition\n label=\"Owner\"\n value={\n typeof entity.spec?.owner === 'string'\n ? entity.spec.owner\n : undefined\n }\n />\n <Definition\n label=\"Namespace\"\n value={entity.metadata.namespace || 'default'}\n />\n <Typography variant=\"subtitle2\">Relationships</Typography>\n {relationships.length === 0 ? (\n <Typography color=\"textSecondary\">\n No component or resource relationships are available yet.\n </Typography>\n ) : (\n <ul>\n {relationships.map(relation => (\n <li key={`${relation.type}:${relation.targetRef}`}>\n <Chip\n size=\"small\"\n label={relation.type}\n style={{ marginRight: 8 }}\n />\n <EntityRefLink entityRef={relation.targetRef} />\n </li>\n ))}\n </ul>\n )}\n </InfoCard>\n </Grid>\n <Grid item xs={12}>\n <InfoCard title=\"Stable resource identity\">\n <Typography\n component=\"code\"\n style={{ overflowWrap: 'anywhere', whiteSpace: 'pre-wrap' }}\n >\n {brief.resourceId}\n </Typography>\n </InfoCard>\n </Grid>\n </Grid>\n );\n};\n\nconst ChangesSection = ({\n section,\n loadingMore,\n onLoadMore,\n}: {\n section: BriefSection<CloudEventsEvidence>;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n}) => (\n <InfoCard title=\"Recent cloud changes\">\n <SectionState section={section}>\n {section.data?.warnings?.map(warning => (\n <Alert severity=\"warning\" key={warning} style={{ marginBottom: 8 }}>\n {humanize(warning)}\n </Alert>\n ))}\n {section.data?.items?.length ? (\n section.data.items.map(event => (\n <div key={event.id} style={{ marginBottom: 20 }}>\n <Typography variant=\"subtitle1\">\n {event.summary || humanize(event.type)}\n </Typography>\n <Typography color=\"textSecondary\">\n {formatCloudTimestamp(event.timestamp)} · {event.category} ·{' '}\n {event.evidence.source} · {event.evidence.status}\n {event.actor?.name || event.actor?.id\n ? ` · ${event.actor.name || event.actor.id}`\n : ''}\n </Typography>\n {event.change.fields.length > 0 && (\n <details>\n <summary>View sanitized field changes</summary>\n <ul>\n {event.change.fields.map(field => {\n const detail = event.change.details.find(\n candidate => candidate.field === field,\n );\n return (\n <li key={field}>\n <code>{field}</code>\n {detail\n ? `: ${detail.before ?? '∅'} → ${detail.after ?? '∅'}`\n : ''}\n </li>\n );\n })}\n </ul>\n </details>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No cloud changes were found in this window.\n </Typography>\n )}\n {section.data?.page.hasMore && onLoadMore && (\n <Button\n size=\"small\"\n onClick={onLoadMore}\n disabled={loadingMore}\n startIcon={loadingMore ? <CircularProgress size={14} /> : undefined}\n >\n Load more changes\n </Button>\n )}\n </SectionState>\n </InfoCard>\n);\n\nconst ProvenanceSection = ({\n section,\n}: {\n section: BriefSection<IacEvidence>;\n}) => (\n <InfoCard title=\"IaC provenance\">\n <SectionState section={section}>\n {section.data?.resources?.length ? (\n section.data.resources.map(resource => (\n <div key={resource.terraform.hashedID} style={{ marginBottom: 16 }}>\n <Typography variant=\"subtitle1\">\n {resource.terraform.address}\n </Typography>\n <Chip size=\"small\" label={humanize(resource.status)} />\n <Definition label=\"File\" value={resource.terraform.fileRef ?? ''} />\n <Definition\n label=\"State links\"\n value={String(resource.states.length)}\n />\n <Definition\n label=\"Cloud links\"\n value={String(resource.clouds.length)}\n />\n {resource.terraform.githubUrl && (\n <Link to={resource.terraform.githubUrl}>Open source</Link>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No Terraform provenance is linked to this resource.\n </Typography>\n )}\n </SectionState>\n </InfoCard>\n);\n\nconst DriftSection = ({\n section,\n}: {\n section: BriefSection<IacDriftEvidence>;\n}) => (\n <InfoCard title=\"IaC drift evidence\">\n <SectionState section={section}>\n {section.data?.items?.length ? (\n section.data.items.map(item => (\n <div key={item.terraform.hashedID} style={{ marginBottom: 16 }}>\n <Typography variant=\"subtitle1\">\n {item.terraform.address}\n </Typography>\n <Chip\n size=\"small\"\n color={item.status === 'drifted' ? 'secondary' : 'default'}\n label={humanize(item.status)}\n />\n <Typography color=\"textSecondary\">\n {item.status === 'unknown'\n ? `Unknown is not drift: ${humanize(item.reason)}.`\n : `${item.comparedFields} supported fields compared.`}\n </Typography>\n {item.differences.length > 0 && (\n <details>\n <summary>View sanitized differences</summary>\n <ul>\n {item.differences.map(difference => (\n <li key={difference.field}>\n <code>{difference.field}</code>:{' '}\n {difference.lastApplied ?? '∅'} →{' '}\n {difference.observed ?? '∅'}\n </li>\n ))}\n </ul>\n </details>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No comparable Terraform evidence is available.\n </Typography>\n )}\n </SectionState>\n </InfoCard>\n);\n\nconst SectionState = ({\n section,\n children,\n}: {\n section: BriefSection;\n children: ReactNode;\n}) => {\n if (section.state === 'error') {\n return <Alert severity=\"error\">{section.message}</Alert>;\n }\n if (section.state === 'unsupported') {\n return <Alert severity=\"info\">{section.message}</Alert>;\n }\n if (section.state === 'empty') {\n return <Typography color=\"textSecondary\">{section.message}</Typography>;\n }\n return <>{children}</>;\n};\n\nconst Definition = ({ label, value }: { label: string; value?: string }) => (\n <Typography paragraph>\n <strong>{label}:</strong> {value || 'Not available'}\n </Typography>\n);\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ');\n}\n\nexport function formatCloudTimestamp(value: string): string {\n const directTimestamp = Date.parse(value);\n if (!Number.isNaN(directTimestamp)) {\n return new Date(directTimestamp).toLocaleString();\n }\n\n const withoutBracketedZone = value.replace(/\\[[^\\]]+\\]$/, '');\n const normalizedTimestamp = Date.parse(withoutBracketedZone);\n return Number.isNaN(normalizedTimestamp)\n ? value\n : new Date(normalizedTimestamp).toLocaleString();\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CloudResourceContent.esm.js","sources":["../../../src/components/cloud/CloudResourceContent.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n Button,\n Chip,\n CircularProgress,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport { InfoCard, Link, Progress } from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport type { Entity } from '@backstage/catalog-model';\nimport {\n ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION,\n ANYSHIFT_CLOUD_PROVIDER_ANNOTATION,\n ANYSHIFT_CLOUD_REGION_ANNOTATION,\n ANYSHIFT_RESOURCE_TYPE_ANNOTATION,\n type BriefSection,\n type CloudEventsEvidence,\n type CloudResourceBrief,\n type IacDriftEvidence,\n type IacEvidence,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport { AskAnyshiftCard } from '../ask/AskAnyshiftCard';\nimport { askScopeForEntity } from '../ask/askScope';\nimport type { AnyshiftCapabilities, AskScope } from '../../api/types';\nimport { cloudResourceIdentity } from '../entity/entityIdentity';\nimport { CloudImpactSection } from './CloudImpactSection';\nimport {\n CloudDependenciesSection,\n CloudDependentsSection,\n} from './CloudRelationshipSections';\n\nexport const CloudResourceContent = () => <CloudResourceEvidenceContent />;\n\nexport const CloudAnyshiftEntityContent = () => (\n <CloudResourceEvidenceContent includeAsk />\n);\n\nconst CloudResourceEvidenceContent = ({ includeAsk = false }) => {\n const { entity } = useEntity();\n const api = useApi(anyshiftApiRef);\n const resourceId = cloudResourceIdentity(entity);\n const [loadedBrief, setLoadedBrief] = useState<{\n resourceId: string;\n value: CloudResourceBrief;\n }>();\n const brief =\n loadedBrief && loadedBrief.resourceId === resourceId\n ? loadedBrief.value\n : undefined;\n const [error, setError] = useState<string>();\n const [refreshing, setRefreshing] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const [paginationError, setPaginationError] = useState<string>();\n const [capabilities, setCapabilities] = useState<AnyshiftCapabilities>({\n askEnabled: false,\n queryEnabled: false,\n });\n const operations = useRef({ identity: 0, primary: 0, pagination: 0 });\n const askScope = useMemo(\n () => (includeAsk ? askScopeForEntity(entity) : undefined),\n [entity, includeAsk],\n );\n\n useLayoutEffect(() => {\n operations.current.identity += 1;\n operations.current.primary += 1;\n operations.current.pagination += 1;\n setLoadedBrief(undefined);\n setError(undefined);\n setRefreshing(false);\n setLoadingMore(false);\n setPaginationError(undefined);\n }, [resourceId]);\n\n const load = useCallback(\n async (refresh = false) => {\n if (!resourceId) return;\n const identity = operations.current.identity;\n const primary = ++operations.current.primary;\n ++operations.current.pagination;\n setRefreshing(refresh);\n setLoadingMore(false);\n setPaginationError(undefined);\n setError(undefined);\n try {\n const next = await api.cloudResourceBrief(resourceId, {\n since: '24h',\n diff: true,\n ...(refresh ? { refresh: true } : {}),\n });\n if (\n operations.current.identity === identity &&\n operations.current.primary === primary\n ) {\n ++operations.current.pagination;\n setLoadingMore(false);\n setLoadedBrief({ resourceId, value: next });\n }\n } catch (loadError) {\n if (\n operations.current.identity === identity &&\n operations.current.primary === primary\n ) {\n ++operations.current.pagination;\n setLoadingMore(false);\n setError(\n loadError instanceof Error\n ? loadError.message\n : 'Unable to load cloud evidence',\n );\n }\n } finally {\n if (\n operations.current.identity === identity &&\n operations.current.primary === primary\n ) {\n setRefreshing(false);\n }\n }\n },\n [api, resourceId],\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n useEffect(() => {\n if (!includeAsk) return undefined;\n let active = true;\n api\n .capabilities()\n .then(next => active && setCapabilities(next))\n .catch(\n () =>\n active && setCapabilities({ askEnabled: false, queryEnabled: false }),\n );\n return () => {\n active = false;\n };\n }, [api, includeAsk]);\n\n const loadMore = useCallback(async () => {\n const cursor = brief?.changes.data?.page.nextCursor;\n if (!resourceId || !cursor) return;\n const identity = operations.current.identity;\n const primary = operations.current.primary;\n const pagination = ++operations.current.pagination;\n setLoadingMore(true);\n setPaginationError(undefined);\n try {\n const next = await api.cloudResourceBrief(resourceId, {\n since: brief.since,\n diff: true,\n cursor,\n });\n if (\n operations.current.identity !== identity ||\n operations.current.primary !== primary ||\n operations.current.pagination !== pagination\n ) {\n return;\n }\n if (next.changes.state === 'error') {\n setPaginationError(\n next.changes.message || 'Unable to load more cloud changes',\n );\n return;\n }\n if (next.changes.state === 'data' && next.changes.data) {\n setPaginationError(undefined);\n }\n setLoadedBrief(current => {\n if (\n !current ||\n current.resourceId !== resourceId ||\n !current.value.changes.data ||\n next.changes.state !== 'data' ||\n !next.changes.data\n ) {\n return current;\n }\n return {\n resourceId,\n value: {\n ...current.value,\n refreshedAt: next.refreshedAt,\n changes: {\n state: 'data',\n data: mergeCloudEventsEvidence(\n current.value.changes.data,\n next.changes.data,\n ),\n },\n },\n };\n });\n } catch (loadError) {\n if (\n operations.current.identity === identity &&\n operations.current.primary === primary &&\n operations.current.pagination === pagination\n ) {\n setPaginationError(\n loadError instanceof Error\n ? loadError.message\n : 'Unable to load more cloud changes',\n );\n }\n } finally {\n if (\n operations.current.identity === identity &&\n operations.current.primary === primary &&\n operations.current.pagination === pagination\n ) {\n setLoadingMore(false);\n }\n }\n }, [api, brief, resourceId]);\n\n if (!resourceId) {\n return (\n <Alert severity=\"info\">\n This catalog entity has no stable Anyshift resource ID or cloud ARN.\n </Alert>\n );\n }\n if (error && !brief) {\n return (\n <Alert severity=\"error\">\n {error} <Button onClick={() => void load(true)}>Retry</Button>\n </Alert>\n );\n }\n if (!brief) return <Progress />;\n\n return (\n <CloudResourceBriefView\n entity={entity}\n brief={brief}\n refreshing={refreshing}\n onRefresh={() => void load(true)}\n loadingMore={loadingMore}\n onLoadMore={() => void loadMore()}\n error={error}\n paginationError={paginationError}\n askEnabled={includeAsk && capabilities.askEnabled && Boolean(askScope)}\n askScope={askScope}\n />\n );\n};\n\nexport function mergeCloudEventsEvidence(\n current: CloudEventsEvidence,\n next: CloudEventsEvidence,\n): CloudEventsEvidence {\n return {\n ...next,\n availability: mergeCloudEventAvailability(\n current.availability,\n next.availability,\n ),\n warnings: [...new Set([...current.warnings, ...next.warnings])],\n items: [...current.items, ...next.items],\n };\n}\n\nfunction mergeCloudEventAvailability(\n current: Record<string, string>,\n next: Record<string, string>,\n): Record<string, string> {\n const availability: Record<string, string> = {};\n for (const field of new Set([\n ...Object.keys(current),\n ...Object.keys(next),\n ])) {\n availability[field] = leastCompleteAvailability(\n current[field],\n next[field],\n );\n }\n return availability;\n}\n\nfunction leastCompleteAvailability(\n current: string | undefined,\n next: string | undefined,\n): string {\n const normalizedCurrent = normalizeAvailability(current);\n const normalizedNext = normalizeAvailability(next);\n return AVAILABILITY_RANK[normalizedCurrent] <=\n AVAILABILITY_RANK[normalizedNext]\n ? normalizedCurrent\n : normalizedNext;\n}\n\nconst AVAILABILITY_RANK: Record<string, number> = {\n unavailable: 0,\n partial: 1,\n available: 2,\n};\n\nfunction normalizeAvailability(value: string | undefined): string {\n return value && value in AVAILABILITY_RANK ? value : 'unavailable';\n}\n\nexport const CloudResourceBriefView = ({\n entity,\n brief,\n refreshing,\n onRefresh,\n loadingMore,\n onLoadMore,\n error,\n paginationError,\n askEnabled = false,\n askScope,\n}: {\n entity: Entity;\n brief: CloudResourceBrief;\n refreshing?: boolean;\n onRefresh: () => void;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n error?: string;\n paginationError?: string;\n askEnabled?: boolean;\n askScope?: AskScope;\n}) => {\n const annotations = entity.metadata.annotations ?? {};\n const consoleLink = entity.metadata.links?.find(link =>\n link.url.startsWith('https://console.aws.amazon.com/'),\n );\n\n return (\n <Grid container spacing={3}>\n {error && (\n <Grid item xs={12}>\n <Alert severity=\"error\">{error}</Alert>\n </Grid>\n )}\n <Grid item xs={12}>\n <InfoCard\n title=\"Cloud evidence\"\n action={\n <Button\n size=\"small\"\n onClick={onRefresh}\n startIcon={\n refreshing ? <CircularProgress size={14} /> : undefined\n }\n >\n Refresh\n </Button>\n }\n >\n <Typography color=\"textSecondary\">\n Read-only Anyshift evidence · last refreshed{' '}\n {formatCloudTimestamp(brief.refreshedAt)} · window {brief.since}\n </Typography>\n </InfoCard>\n </Grid>\n\n <Grid item xs={12}>\n <InfoCard title=\"Cloud identity\">\n <Definition\n label=\"Provider\"\n value={annotations[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION]}\n />\n <Definition\n label=\"Resource type\"\n value={\n annotations[ANYSHIFT_RESOURCE_TYPE_ANNOTATION] ||\n String(entity.spec?.type || '')\n }\n />\n <Definition\n label=\"Region\"\n value={annotations[ANYSHIFT_CLOUD_REGION_ANNOTATION] || 'Global'}\n />\n <Definition\n label=\"Account\"\n value={annotations[ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION]}\n />\n <Definition label=\"Stable resource ID\" value={brief.resourceId} />\n {consoleLink && <Link to={consoleLink.url}>Open in AWS Console</Link>}\n </InfoCard>\n </Grid>\n <Grid item xs={12} md={6}>\n <CloudDependenciesSection entity={entity} />\n </Grid>\n <Grid item xs={12} md={6}>\n <CloudDependentsSection entity={entity} />\n </Grid>\n <Grid item xs={12}>\n <CloudImpactSection section={brief.impact} onRetry={onRefresh} />\n </Grid>\n <Grid item xs={12}>\n <ChangesSection\n section={brief.changes}\n loadingMore={loadingMore}\n onLoadMore={onLoadMore}\n paginationError={paginationError}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <ProvenanceSection section={brief.provenance} />\n </Grid>\n <Grid item xs={12} md={6}>\n <DriftSection section={brief.drift} />\n </Grid>\n {askEnabled && (\n <Grid item xs={12}>\n <AskAnyshiftCard context=\"entity\" scope={askScope} />\n </Grid>\n )}\n </Grid>\n );\n};\n\nconst ChangesSection = ({\n section,\n loadingMore,\n onLoadMore,\n paginationError,\n}: {\n section: BriefSection<CloudEventsEvidence>;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n paginationError?: string;\n}) => {\n const { hasEvidenceLimitations, actionableWarnings } =\n partitionCloudEventWarnings(\n section.data?.warnings,\n section.data?.items.length ?? 0,\n );\n\n if (section.state === 'empty') {\n return (\n <InfoCard title=\"Recent cloud changes\">\n <Typography color=\"textSecondary\">\n {section.message || 'No cloud changes were found in this window.'}\n </Typography>\n </InfoCard>\n );\n }\n\n return (\n <InfoCard title=\"Recent cloud changes\">\n <SectionState section={section}>\n {paginationError && (\n <Alert severity=\"error\" style={{ marginBottom: 8 }}>\n {paginationError}\n </Alert>\n )}\n {hasEvidenceLimitations && (\n <Typography\n aria-label=\"Cloud event evidence limitations\"\n variant=\"caption\"\n color=\"textSecondary\"\n display=\"block\"\n style={{ marginBottom: 8 }}\n >\n Event source is derived from graph relationships, and event status\n may be incomplete.\n </Typography>\n )}\n {actionableWarnings.map(warning => (\n <Alert severity=\"warning\" key={warning} style={{ marginBottom: 8 }}>\n {humanize(warning)}\n </Alert>\n ))}\n {section.data?.items?.length ? (\n section.data.items.map(event => (\n <div key={event.id} style={{ marginBottom: 20 }}>\n <Typography variant=\"subtitle1\">\n {event.summary || humanize(event.type)}\n </Typography>\n <Typography color=\"textSecondary\">\n {formatCloudTimestamp(event.timestamp)} · {event.category} ·{' '}\n {event.evidence.source} · {event.evidence.status}\n {event.actor?.name || event.actor?.id\n ? ` · ${event.actor.name || event.actor.id}`\n : ''}\n </Typography>\n {event.change.fields.length > 0 && (\n <details>\n <summary>View sanitized field changes</summary>\n <ul>\n {event.change.fields.map(field => {\n const detail = event.change.details.find(\n candidate => candidate.field === field,\n );\n return (\n <li key={field}>\n <code>{field}</code>\n {detail\n ? `: ${detail.before ?? '∅'} → ${\n detail.after ?? '∅'\n }`\n : ''}\n </li>\n );\n })}\n </ul>\n </details>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No cloud changes were found in this window.\n </Typography>\n )}\n {section.data?.page.hasMore && onLoadMore && (\n <Button\n size=\"small\"\n onClick={onLoadMore}\n disabled={loadingMore}\n startIcon={loadingMore ? <CircularProgress size={14} /> : undefined}\n >\n Load more changes\n </Button>\n )}\n </SectionState>\n </InfoCard>\n );\n};\n\nconst QUIET_EVIDENCE_LIMITATIONS = new Set([\n 'event_source_derived',\n 'event_status_incomplete',\n]);\nconst IDENTITY_COMPLETENESS_WARNINGS = new Set([\n 'target_identity_incomplete',\n 'actor_identity_incomplete',\n]);\n\nfunction partitionCloudEventWarnings(\n warnings: string[] | undefined,\n eventCount: number,\n) {\n const allWarnings = warnings ?? [];\n return {\n hasEvidenceLimitations: allWarnings.some(warning =>\n QUIET_EVIDENCE_LIMITATIONS.has(warning),\n ),\n actionableWarnings: allWarnings.filter(\n warning =>\n !QUIET_EVIDENCE_LIMITATIONS.has(warning) &&\n (eventCount > 0 || !IDENTITY_COMPLETENESS_WARNINGS.has(warning)),\n ),\n };\n}\n\nconst ProvenanceSection = ({\n section,\n}: {\n section: BriefSection<IacEvidence>;\n}) => {\n if (section.state === 'empty') {\n return (\n <InfoCard title=\"IaC provenance\">\n <Typography color=\"textSecondary\">\n {section.message ||\n 'No Terraform provenance is linked to this resource.'}\n </Typography>\n </InfoCard>\n );\n }\n return (\n <InfoCard title=\"IaC provenance\">\n <SectionState section={section}>\n {section.data?.resources?.length ? (\n section.data.resources.map(resource => (\n <div key={resource.terraform.hashedID} style={{ marginBottom: 16 }}>\n <Typography variant=\"subtitle1\">\n {resource.terraform.address}\n </Typography>\n <Chip size=\"small\" label={humanize(resource.status)} />\n <Definition\n label=\"File\"\n value={resource.terraform.fileRef ?? ''}\n />\n <Definition\n label=\"State links\"\n value={String(resource.states.length)}\n />\n <Definition\n label=\"Cloud links\"\n value={String(resource.clouds.length)}\n />\n {resource.terraform.githubUrl && (\n <Link to={resource.terraform.githubUrl}>Open source</Link>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No Terraform provenance is linked to this resource.\n </Typography>\n )}\n </SectionState>\n </InfoCard>\n );\n};\n\nconst DriftSection = ({\n section,\n}: {\n section: BriefSection<IacDriftEvidence>;\n}) => {\n if (section.state === 'empty') {\n return (\n <InfoCard title=\"IaC drift evidence\">\n <Typography color=\"textSecondary\">\n {section.message || 'No comparable Terraform evidence is available.'}\n </Typography>\n </InfoCard>\n );\n }\n return (\n <InfoCard title=\"IaC drift evidence\">\n <SectionState section={section}>\n {section.data?.items?.length ? (\n section.data.items.map(item => (\n <div key={item.terraform.hashedID} style={{ marginBottom: 16 }}>\n <Typography variant=\"subtitle1\">\n {item.terraform.address}\n </Typography>\n <Chip\n size=\"small\"\n color={item.status === 'drifted' ? 'secondary' : 'default'}\n label={humanize(item.status)}\n />\n <Typography color=\"textSecondary\">\n {item.status === 'unknown'\n ? `Unknown is not drift: ${humanize(item.reason)}.`\n : `${item.comparedFields} supported fields compared.`}\n </Typography>\n {item.differences.length > 0 && (\n <details>\n <summary>View sanitized differences</summary>\n <ul>\n {item.differences.map(difference => (\n <li key={difference.field}>\n <code>{difference.field}</code>:{' '}\n {difference.lastApplied ?? '∅'} →{' '}\n {difference.observed ?? '∅'}\n </li>\n ))}\n </ul>\n </details>\n )}\n </div>\n ))\n ) : (\n <Typography color=\"textSecondary\">\n No comparable Terraform evidence is available.\n </Typography>\n )}\n </SectionState>\n </InfoCard>\n );\n};\n\nconst SectionState = ({\n section,\n children,\n}: {\n section: BriefSection;\n children: ReactNode;\n}) => {\n if (section.state === 'error') {\n return <Alert severity=\"error\">{section.message}</Alert>;\n }\n if (section.state === 'unsupported') {\n return <Alert severity=\"info\">{section.message}</Alert>;\n }\n if (section.state === 'empty') {\n return <Typography color=\"textSecondary\">{section.message}</Typography>;\n }\n return <>{children}</>;\n};\n\nconst Definition = ({ label, value }: { label: string; value?: string }) => (\n <Typography paragraph>\n <strong>{label}:</strong> {value || 'Not available'}\n </Typography>\n);\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ');\n}\n\nexport function formatCloudTimestamp(value: string): string {\n const directTimestamp = Date.parse(value);\n if (!Number.isNaN(directTimestamp)) {\n return new Date(directTimestamp).toLocaleString();\n }\n\n const withoutBracketedZone = value.replace(/\\[[^\\]]+\\]$/, '');\n const normalizedTimestamp = Date.parse(withoutBracketedZone);\n return Number.isNaN(normalizedTimestamp)\n ? value\n : new Date(normalizedTimestamp).toLocaleString();\n}\n"],"names":[],"mappings":"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"}
@@ -3,14 +3,20 @@ import { useState, useRef, useCallback, useEffect } from 'react';
3
3
  import { Typography, Box, Chip, Button, CircularProgress, Grid } from '@material-ui/core';
4
4
  import { Progress } from '@backstage/core-components';
5
5
  import { useApi } from '@backstage/frontend-plugin-api';
6
- import { ANYSHIFT_KIND_ANNOTATION, ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION, ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION, ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION, ANYSHIFT_TARGET_ANNOTATION, GITHUB_PROJECT_SLUG_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
6
+ import { ANYSHIFT_KIND_ANNOTATION, ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION, ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION, ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
7
7
  import { useEntity } from '@backstage/plugin-catalog-react';
8
8
  import { anyshiftApiRef } from '../../api/AnyshiftApi.esm.js';
9
9
  import { AskAnyshiftCard } from '../ask/AskAnyshiftCard.esm.js';
10
10
  import { askScopeForEntity } from '../ask/askScope.esm.js';
11
+ import { CloudAnyshiftEntityContent } from '../cloud/CloudResourceContent.esm.js';
12
+ import { isCloudResourceEntity, entityTarget } from './entityIdentity.esm.js';
11
13
  import { OverviewSection, WhyNowSection, DatadogSignalSection, ArchitectureSection, DependencySection, BriefRail, TimelineSection } from './BriefSections.esm.js';
12
14
 
13
15
  const AnyshiftEntityContent = () => {
16
+ const { entity } = useEntity();
17
+ return isCloudResourceEntity(entity) ? /* @__PURE__ */ jsx(CloudAnyshiftEntityContent, {}) : /* @__PURE__ */ jsx(ServiceAnyshiftEntityContent, {});
18
+ };
19
+ const ServiceAnyshiftEntityContent = () => {
14
20
  const { entity } = useEntity();
15
21
  const api = useApi(anyshiftApiRef);
16
22
  const annotations = entity.metadata.annotations ?? {};
@@ -134,14 +140,6 @@ const AnyshiftEntityContent = () => {
134
140
  }
135
141
  );
136
142
  };
137
- function entityTarget(entity) {
138
- const annotations = entity.metadata.annotations ?? {};
139
- const explicit = annotations[ANYSHIFT_TARGET_ANNOTATION]?.trim();
140
- if (explicit) return explicit;
141
- const slug = annotations[GITHUB_PROJECT_SLUG_ANNOTATION]?.trim();
142
- const repository = slug?.split("/").filter(Boolean).at(-1);
143
- return repository || entity.metadata.name;
144
- }
145
143
  const ServiceBriefView = ({
146
144
  brief,
147
145
  onRetry,
@@ -265,5 +263,5 @@ function formatTimestamp(value) {
265
263
  return Number.isNaN(parsed) ? value : new Date(parsed).toLocaleString();
266
264
  }
267
265
 
268
- export { AnyshiftEntityContent, ServiceBriefView, entityTarget };
266
+ export { AnyshiftEntityContent, ServiceAnyshiftEntityContent, ServiceBriefView };
269
267
  //# sourceMappingURL=AnyshiftEntityContent.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnyshiftEntityContent.esm.js","sources":["../../../src/components/entity/AnyshiftEntityContent.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport { Progress } from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport {\n ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION,\n ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION,\n ANYSHIFT_KIND_ANNOTATION,\n ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION,\n ANYSHIFT_TARGET_ANNOTATION,\n GITHUB_PROJECT_SLUG_ANNOTATION,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport type { Entity } from '@backstage/catalog-model';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport type {\n AnyshiftCapabilities,\n AskScope,\n BriefSectionName,\n ServiceBrief,\n} from '../../api/types';\nimport { AskAnyshiftCard } from '../ask/AskAnyshiftCard';\nimport { askScopeForEntity } from '../ask/askScope';\nimport {\n ArchitectureSection,\n BriefRail,\n DatadogSignalSection,\n DependencySection,\n OverviewSection,\n TimelineSection,\n WhyNowSection,\n} from './BriefSections';\n\nexport const AnyshiftEntityContent = () => {\n const { entity } = useEntity();\n const api = useApi(anyshiftApiRef);\n const annotations = entity.metadata.annotations ?? {};\n const target = entityTarget(entity);\n const kind = annotations[ANYSHIFT_KIND_ANNOTATION] || 'workload';\n const namespace = entity.metadata.namespace;\n const configurationEndpoints =\n annotations[ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION];\n const configurationDependencies =\n annotations[ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION];\n const configurationTarget =\n annotations[ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION];\n const [brief, setBrief] = useState<ServiceBrief>();\n const [capabilities, setCapabilities] = useState<AnyshiftCapabilities>({\n askEnabled: false,\n queryEnabled: false,\n });\n const [error, setError] = useState<string>();\n const [refreshingAll, setRefreshingAll] = useState(false);\n const [refreshing, setRefreshing] = useState<Set<BriefSectionName>>(\n new Set(),\n );\n const active = useRef(true);\n\n const load = useCallback(\n async (refresh = false) => {\n setError(undefined);\n if (refresh) setRefreshingAll(true);\n try {\n const next = await api.brief(kind, target, {\n namespace,\n refresh,\n configurationEndpoints,\n configurationDependencies,\n configurationTarget,\n });\n if (active.current) setBrief(next);\n } catch (cause) {\n if (active.current)\n setError(cause instanceof Error ? cause.message : String(cause));\n } finally {\n if (active.current) setRefreshingAll(false);\n }\n },\n [\n api,\n configurationDependencies,\n configurationEndpoints,\n configurationTarget,\n kind,\n namespace,\n target,\n ],\n );\n\n const retrySection = useCallback(\n async (section: BriefSectionName) => {\n setRefreshing(current => new Set(current).add(section));\n try {\n const response = await api.briefSection(kind, target, section, {\n namespace,\n refresh: true,\n configurationEndpoints,\n configurationDependencies,\n configurationTarget,\n });\n if (active.current) {\n setBrief(current =>\n current\n ? {\n ...current,\n [section]: response.value,\n refreshedAt: response.refreshedAt,\n ...(response.observedService\n ? { observedService: response.observedService }\n : {}),\n }\n : current,\n );\n }\n } finally {\n if (active.current) {\n setRefreshing(current => {\n const next = new Set(current);\n next.delete(section);\n return next;\n });\n }\n }\n },\n [\n api,\n configurationDependencies,\n configurationEndpoints,\n configurationTarget,\n kind,\n namespace,\n target,\n ],\n );\n\n useEffect(() => {\n active.current = true;\n void load();\n return () => {\n active.current = false;\n };\n }, [load]);\n\n useEffect(() => {\n api\n .capabilities()\n .then(next => {\n if (active.current) setCapabilities(next);\n })\n .catch(() => {\n if (active.current) {\n setCapabilities({ askEnabled: false, queryEnabled: false });\n }\n });\n }, [api]);\n\n if (error && !brief) return <Typography color=\"error\">{error}</Typography>;\n if (!brief) return <Progress />;\n return (\n <ServiceBriefView\n brief={brief}\n onRetry={retrySection}\n refreshing={refreshing}\n onRefresh={() => void load(true)}\n refreshingAll={refreshingAll}\n refreshError={error}\n askEnabled={capabilities.askEnabled}\n askScope={askScopeForEntity(entity)}\n />\n );\n};\n\nexport function entityTarget(entity: Entity): string {\n const annotations = entity.metadata.annotations ?? {};\n const explicit = annotations[ANYSHIFT_TARGET_ANNOTATION]?.trim();\n if (explicit) return explicit;\n\n const slug = annotations[GITHUB_PROJECT_SLUG_ANNOTATION]?.trim();\n const repository = slug?.split('/').filter(Boolean).at(-1);\n return repository || entity.metadata.name;\n}\n\nexport const ServiceBriefView = ({\n brief,\n onRetry,\n refreshing = new Set(),\n onRefresh = () => {},\n refreshingAll = false,\n refreshError,\n askEnabled = false,\n askScope,\n}: {\n brief: ServiceBrief;\n onRetry: (section: BriefSectionName) => void;\n refreshing?: ReadonlySet<BriefSectionName>;\n onRefresh?: () => void;\n refreshingAll?: boolean;\n refreshError?: string;\n askEnabled?: boolean;\n askScope?: AskScope;\n}) => (\n <>\n <Box\n mb={3}\n px={2.5}\n py={2}\n borderLeft={4}\n borderColor=\"primary.main\"\n bgcolor=\"background.paper\"\n >\n <Box display=\"flex\" justifyContent=\"space-between\" gridGap={16}>\n <Box>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Anyshift evidence trace\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"center\" gridGap={8}>\n <Chip size=\"small\" label={`Workload · ${brief.target}`} />\n <Typography aria-hidden=\"true\" color=\"primary\">\n →\n </Typography>\n <Chip\n size=\"small\"\n color=\"primary\"\n label={`Observed service · ${\n brief.observedService || 'Not resolved'\n }`}\n />\n </Box>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Runtime namespace: {brief.namespace || 'Not set'} · Refreshed{' '}\n {formatTimestamp(brief.refreshedAt)}\n </Typography>\n </Box>\n <Button\n type=\"button\"\n variant=\"outlined\"\n size=\"small\"\n onClick={onRefresh}\n disabled={refreshingAll}\n startIcon={refreshingAll ? <CircularProgress size={14} /> : undefined}\n >\n {refreshingAll ? 'Refreshing…' : 'Refresh brief'}\n </Button>\n </Box>\n {refreshError && (\n <Typography color=\"error\" variant=\"caption\">\n Refresh failed: {refreshError}. Existing evidence is still shown.\n </Typography>\n )}\n </Box>\n\n <Grid container spacing={3} alignItems=\"stretch\">\n <Grid item xs={12}>\n <OverviewSection\n section={brief.overview}\n onRetry={onRetry}\n refreshing={refreshing.has('overview')}\n />\n </Grid>\n <Grid item xs={12}>\n <WhyNowSection\n section={brief.whyNow}\n onRetry={onRetry}\n refreshing={refreshing.has('whyNow')}\n />\n </Grid>\n {askEnabled && (\n <Grid item xs={12}>\n <AskAnyshiftCard context=\"entity\" scope={askScope} />\n </Grid>\n )}\n <Grid item xs={12}>\n <DatadogSignalSection\n section={brief.observability}\n onRetry={onRetry}\n refreshing={refreshing.has('observability')}\n />\n </Grid>\n <Grid item xs={12}>\n <ArchitectureSection\n section={brief.architecture}\n onRetry={onRetry}\n refreshing={refreshing.has('architecture')}\n />\n </Grid>\n <Grid item xs={12} md={8}>\n <DependencySection\n section={brief.topology}\n onRetry={onRetry}\n refreshing={refreshing.has('topology')}\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <BriefRail brief={brief} onRetry={onRetry} refreshing={refreshing} />\n </Grid>\n <Grid item xs={12}>\n <TimelineSection\n section={brief.timeline}\n onRetry={onRetry}\n refreshing={refreshing.has('timeline')}\n />\n </Grid>\n </Grid>\n </>\n);\n\nfunction formatTimestamp(value: string): string {\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? value : new Date(parsed).toLocaleString();\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AnyshiftEntityContent.esm.js","sources":["../../../src/components/entity/AnyshiftEntityContent.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Box,\n Button,\n Chip,\n CircularProgress,\n Grid,\n Typography,\n} from '@material-ui/core';\nimport { Progress } from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport {\n ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION,\n ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION,\n ANYSHIFT_KIND_ANNOTATION,\n ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport type {\n AnyshiftCapabilities,\n AskScope,\n BriefSectionName,\n ServiceBrief,\n} from '../../api/types';\nimport { AskAnyshiftCard } from '../ask/AskAnyshiftCard';\nimport { askScopeForEntity } from '../ask/askScope';\nimport { CloudAnyshiftEntityContent } from '../cloud/CloudResourceContent';\nimport { entityTarget, isCloudResourceEntity } from './entityIdentity';\nimport {\n ArchitectureSection,\n BriefRail,\n DatadogSignalSection,\n DependencySection,\n OverviewSection,\n TimelineSection,\n WhyNowSection,\n} from './BriefSections';\n\nexport const AnyshiftEntityContent = () => {\n const { entity } = useEntity();\n return isCloudResourceEntity(entity) ? (\n <CloudAnyshiftEntityContent />\n ) : (\n <ServiceAnyshiftEntityContent />\n );\n};\n\nexport const ServiceAnyshiftEntityContent = () => {\n const { entity } = useEntity();\n const api = useApi(anyshiftApiRef);\n const annotations = entity.metadata.annotations ?? {};\n const target = entityTarget(entity);\n const kind = annotations[ANYSHIFT_KIND_ANNOTATION] || 'workload';\n const namespace = entity.metadata.namespace;\n const configurationEndpoints =\n annotations[ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION];\n const configurationDependencies =\n annotations[ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION];\n const configurationTarget =\n annotations[ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION];\n const [brief, setBrief] = useState<ServiceBrief>();\n const [capabilities, setCapabilities] = useState<AnyshiftCapabilities>({\n askEnabled: false,\n queryEnabled: false,\n });\n const [error, setError] = useState<string>();\n const [refreshingAll, setRefreshingAll] = useState(false);\n const [refreshing, setRefreshing] = useState<Set<BriefSectionName>>(\n new Set(),\n );\n const active = useRef(true);\n\n const load = useCallback(\n async (refresh = false) => {\n setError(undefined);\n if (refresh) setRefreshingAll(true);\n try {\n const next = await api.brief(kind, target, {\n namespace,\n refresh,\n configurationEndpoints,\n configurationDependencies,\n configurationTarget,\n });\n if (active.current) setBrief(next);\n } catch (cause) {\n if (active.current)\n setError(cause instanceof Error ? cause.message : String(cause));\n } finally {\n if (active.current) setRefreshingAll(false);\n }\n },\n [\n api,\n configurationDependencies,\n configurationEndpoints,\n configurationTarget,\n kind,\n namespace,\n target,\n ],\n );\n\n const retrySection = useCallback(\n async (section: BriefSectionName) => {\n setRefreshing(current => new Set(current).add(section));\n try {\n const response = await api.briefSection(kind, target, section, {\n namespace,\n refresh: true,\n configurationEndpoints,\n configurationDependencies,\n configurationTarget,\n });\n if (active.current) {\n setBrief(current =>\n current\n ? {\n ...current,\n [section]: response.value,\n refreshedAt: response.refreshedAt,\n ...(response.observedService\n ? { observedService: response.observedService }\n : {}),\n }\n : current,\n );\n }\n } finally {\n if (active.current) {\n setRefreshing(current => {\n const next = new Set(current);\n next.delete(section);\n return next;\n });\n }\n }\n },\n [\n api,\n configurationDependencies,\n configurationEndpoints,\n configurationTarget,\n kind,\n namespace,\n target,\n ],\n );\n\n useEffect(() => {\n active.current = true;\n void load();\n return () => {\n active.current = false;\n };\n }, [load]);\n\n useEffect(() => {\n api\n .capabilities()\n .then(next => {\n if (active.current) setCapabilities(next);\n })\n .catch(() => {\n if (active.current) {\n setCapabilities({ askEnabled: false, queryEnabled: false });\n }\n });\n }, [api]);\n\n if (error && !brief) return <Typography color=\"error\">{error}</Typography>;\n if (!brief) return <Progress />;\n return (\n <ServiceBriefView\n brief={brief}\n onRetry={retrySection}\n refreshing={refreshing}\n onRefresh={() => void load(true)}\n refreshingAll={refreshingAll}\n refreshError={error}\n askEnabled={capabilities.askEnabled}\n askScope={askScopeForEntity(entity)}\n />\n );\n};\n\nexport const ServiceBriefView = ({\n brief,\n onRetry,\n refreshing = new Set(),\n onRefresh = () => {},\n refreshingAll = false,\n refreshError,\n askEnabled = false,\n askScope,\n}: {\n brief: ServiceBrief;\n onRetry: (section: BriefSectionName) => void;\n refreshing?: ReadonlySet<BriefSectionName>;\n onRefresh?: () => void;\n refreshingAll?: boolean;\n refreshError?: string;\n askEnabled?: boolean;\n askScope?: AskScope;\n}) => (\n <>\n <Box\n mb={3}\n px={2.5}\n py={2}\n borderLeft={4}\n borderColor=\"primary.main\"\n bgcolor=\"background.paper\"\n >\n <Box display=\"flex\" justifyContent=\"space-between\" gridGap={16}>\n <Box>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Anyshift evidence trace\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"center\" gridGap={8}>\n <Chip size=\"small\" label={`Workload · ${brief.target}`} />\n <Typography aria-hidden=\"true\" color=\"primary\">\n →\n </Typography>\n <Chip\n size=\"small\"\n color=\"primary\"\n label={`Observed service · ${\n brief.observedService || 'Not resolved'\n }`}\n />\n </Box>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Runtime namespace: {brief.namespace || 'Not set'} · Refreshed{' '}\n {formatTimestamp(brief.refreshedAt)}\n </Typography>\n </Box>\n <Button\n type=\"button\"\n variant=\"outlined\"\n size=\"small\"\n onClick={onRefresh}\n disabled={refreshingAll}\n startIcon={refreshingAll ? <CircularProgress size={14} /> : undefined}\n >\n {refreshingAll ? 'Refreshing…' : 'Refresh brief'}\n </Button>\n </Box>\n {refreshError && (\n <Typography color=\"error\" variant=\"caption\">\n Refresh failed: {refreshError}. Existing evidence is still shown.\n </Typography>\n )}\n </Box>\n\n <Grid container spacing={3} alignItems=\"stretch\">\n <Grid item xs={12}>\n <OverviewSection\n section={brief.overview}\n onRetry={onRetry}\n refreshing={refreshing.has('overview')}\n />\n </Grid>\n <Grid item xs={12}>\n <WhyNowSection\n section={brief.whyNow}\n onRetry={onRetry}\n refreshing={refreshing.has('whyNow')}\n />\n </Grid>\n {askEnabled && (\n <Grid item xs={12}>\n <AskAnyshiftCard context=\"entity\" scope={askScope} />\n </Grid>\n )}\n <Grid item xs={12}>\n <DatadogSignalSection\n section={brief.observability}\n onRetry={onRetry}\n refreshing={refreshing.has('observability')}\n />\n </Grid>\n <Grid item xs={12}>\n <ArchitectureSection\n section={brief.architecture}\n onRetry={onRetry}\n refreshing={refreshing.has('architecture')}\n />\n </Grid>\n <Grid item xs={12} md={8}>\n <DependencySection\n section={brief.topology}\n onRetry={onRetry}\n refreshing={refreshing.has('topology')}\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <BriefRail brief={brief} onRetry={onRetry} refreshing={refreshing} />\n </Grid>\n <Grid item xs={12}>\n <TimelineSection\n section={brief.timeline}\n onRetry={onRetry}\n refreshing={refreshing.has('timeline')}\n />\n </Grid>\n </Grid>\n </>\n);\n\nfunction formatTimestamp(value: string): string {\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? value : new Date(parsed).toLocaleString();\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { ANYSHIFT_CLOUD_PROVIDER_ANNOTATION, ANYSHIFT_RESOURCE_ID_ANNOTATION, ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION, ANYSHIFT_TARGET_ANNOTATION, GITHUB_PROJECT_SLUG_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
2
+
3
+ function isCloudResourceEntity(entity) {
4
+ return entity.kind.toLocaleLowerCase("en-US") === "resource" && Boolean(
5
+ entity.metadata.annotations?.[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION]?.trim()
6
+ );
7
+ }
8
+ function cloudResourceIdentity(entity) {
9
+ const annotations = entity.metadata.annotations ?? {};
10
+ return annotationValue(annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION]) ?? annotationValue(annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION]);
11
+ }
12
+ function cloudResourceAskTarget(entity) {
13
+ const annotations = entity.metadata.annotations ?? {};
14
+ return annotationValue(annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION]) ?? annotationValue(annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION]);
15
+ }
16
+ function entityTarget(entity) {
17
+ const annotations = entity.metadata.annotations ?? {};
18
+ const explicit = annotationValue(annotations[ANYSHIFT_TARGET_ANNOTATION]);
19
+ if (explicit) return explicit;
20
+ const slug = annotationValue(annotations[GITHUB_PROJECT_SLUG_ANNOTATION]);
21
+ const repository = slug?.split("/").filter(Boolean).at(-1);
22
+ return repository || entity.metadata.name;
23
+ }
24
+ function annotationValue(value) {
25
+ const trimmed = value?.trim();
26
+ return trimmed || void 0;
27
+ }
28
+
29
+ export { cloudResourceAskTarget, cloudResourceIdentity, entityTarget, isCloudResourceEntity };
30
+ //# sourceMappingURL=entityIdentity.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entityIdentity.esm.js","sources":["../../../src/components/entity/entityIdentity.ts"],"sourcesContent":["import type { Entity } from '@backstage/catalog-model';\nimport {\n ANYSHIFT_CLOUD_PROVIDER_ANNOTATION,\n ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION,\n ANYSHIFT_RESOURCE_ID_ANNOTATION,\n ANYSHIFT_TARGET_ANNOTATION,\n GITHUB_PROJECT_SLUG_ANNOTATION,\n} from '@anyshift/backstage-plugin-anyshift-common';\n\nexport function isCloudResourceEntity(entity: Entity): boolean {\n return (\n entity.kind.toLocaleLowerCase('en-US') === 'resource' &&\n Boolean(\n entity.metadata.annotations?.[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION]?.trim(),\n )\n );\n}\n\nexport function cloudResourceIdentity(entity: Entity): string | undefined {\n const annotations = entity.metadata.annotations ?? {};\n return (\n annotationValue(annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION]) ??\n annotationValue(annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION])\n );\n}\n\nexport function cloudResourceAskTarget(entity: Entity): string | undefined {\n const annotations = entity.metadata.annotations ?? {};\n return (\n annotationValue(annotations[ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION]) ??\n annotationValue(annotations[ANYSHIFT_RESOURCE_ID_ANNOTATION])\n );\n}\n\nexport function entityTarget(entity: Entity): string {\n const annotations = entity.metadata.annotations ?? {};\n const explicit = annotationValue(annotations[ANYSHIFT_TARGET_ANNOTATION]);\n if (explicit) return explicit;\n\n const slug = annotationValue(annotations[GITHUB_PROJECT_SLUG_ANNOTATION]);\n const repository = slug?.split('/').filter(Boolean).at(-1);\n return repository || entity.metadata.name;\n}\n\nfunction annotationValue(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed || undefined;\n}\n"],"names":[],"mappings":";;AASO,SAAS,sBAAsB,MAAA,EAAyB;AAC7D,EAAA,OACE,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAO,MAAM,UAAA,IAC3C,OAAA;AAAA,IACE,MAAA,CAAO,QAAA,CAAS,WAAA,GAAc,kCAAkC,GAAG,IAAA;AAAK,GAC1E;AAEJ;AAEO,SAAS,sBAAsB,MAAA,EAAoC;AACxE,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,IAAe,EAAC;AACpD,EAAA,OACE,eAAA,CAAgB,YAAY,+BAA+B,CAAC,KAC5D,eAAA,CAAgB,WAAA,CAAY,sCAAsC,CAAC,CAAA;AAEvE;AAEO,SAAS,uBAAuB,MAAA,EAAoC;AACzE,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,IAAe,EAAC;AACpD,EAAA,OACE,eAAA,CAAgB,YAAY,sCAAsC,CAAC,KACnE,eAAA,CAAgB,WAAA,CAAY,+BAA+B,CAAC,CAAA;AAEhE;AAEO,SAAS,aAAa,MAAA,EAAwB;AACnD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,IAAe,EAAC;AACpD,EAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,WAAA,CAAY,0BAA0B,CAAC,CAAA;AACxE,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,WAAA,CAAY,8BAA8B,CAAC,CAAA;AACxE,EAAA,MAAM,UAAA,GAAa,MAAM,KAAA,CAAM,GAAG,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,EAAA,CAAG,EAAE,CAAA;AACzD,EAAA,OAAO,UAAA,IAAc,OAAO,QAAA,CAAS,IAAA;AACvC;AAEA,SAAS,gBAAgB,KAAA,EAA+C;AACtE,EAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,EAAA,OAAO,OAAA,IAAW,MAAA;AACpB;;;;"}
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _backstage_filter_predicates from '@backstage/filter-predicates';
3
3
  import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
4
4
  import { Entity } from '@backstage/catalog-model';
5
5
  import { AskAnyshiftRequest, AskAnyshiftResponse, AnyshiftCapabilities, ServiceBrief, BriefSectionName, BriefSectionResponse, EstateInsights, DatadogSignals, CloudResourceBrief, CatalogSummary, QueryResult, CatalogSyncReport } from '@anyshift/backstage-plugin-anyshift-common';
6
- export { ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION, ANYSHIFT_CLOUD_PROVIDER_ANNOTATION, ANYSHIFT_CLOUD_REGION_ANNOTATION, ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION, ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION, ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION, ANYSHIFT_KIND_ANNOTATION, ANYSHIFT_OBSERVED_SERVICE_ANNOTATION, ANYSHIFT_RESOURCE_ID_ANNOTATION, ANYSHIFT_RESOURCE_TYPE_ANNOTATION, ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION, ANYSHIFT_TARGET_ANNOTATION, BriefSection, CatalogSummary, CloudEventEvidenceItem, CloudEventsEvidence, CloudResourceBrief, EntityImpact, EstateInsights, EvidenceCoverage, GITHUB_PROJECT_SLUG_ANNOTATION, IacDriftEvidence, IacEvidence, QueryResult, ServiceBrief, WhyNowAssessment, anyshiftQueryPermission, anyshiftViewPermission } from '@anyshift/backstage-plugin-anyshift-common';
6
+ export { ANYSHIFT_CLOUD_ACCOUNT_ANNOTATION, ANYSHIFT_CLOUD_PROVIDER_ANNOTATION, ANYSHIFT_CLOUD_REGION_ANNOTATION, ANYSHIFT_CLOUD_RESOURCE_ARN_ANNOTATION, ANYSHIFT_CONFIGURATION_DEPENDENCIES_ANNOTATION, ANYSHIFT_CONFIGURATION_ENDPOINTS_ANNOTATION, ANYSHIFT_KIND_ANNOTATION, ANYSHIFT_OBSERVED_SERVICE_ANNOTATION, ANYSHIFT_RESOURCE_ID_ANNOTATION, ANYSHIFT_RESOURCE_TYPE_ANNOTATION, ANYSHIFT_RUNTIME_RESOURCE_ID_ANNOTATION, ANYSHIFT_TARGET_ANNOTATION, BriefSection, CatalogSummary, CloudEventEvidenceItem, CloudEventsEvidence, CloudResourceBrief, EntityImpact, EstateInsights, EvidenceCoverage, GITHUB_PROJECT_SLUG_ANNOTATION, IacDriftEvidence, IacEvidence, ImpactResult, QueryResult, ServiceBrief, WhyNowAssessment, anyshiftQueryPermission, anyshiftViewPermission } from '@anyshift/backstage-plugin-anyshift-common';
7
7
 
8
8
  declare const anyshiftPlugin: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{
9
9
  root: _backstage_frontend_plugin_api.RouteRef<undefined>;
@@ -1,5 +1,5 @@
1
1
  var name = "@anyshift/backstage-plugin-anyshift";
2
- var version = "0.1.0-beta.11";
2
+ var version = "0.1.0-beta.13";
3
3
  var description = "Read-only Anyshift infrastructure context for Backstage";
4
4
  var main = "src/index.ts";
5
5
  var types = "src/index.ts";
@@ -3,7 +3,8 @@ import DeviceHubIcon from '@material-ui/icons/DeviceHub';
3
3
  import CloudQueueIcon from '@material-ui/icons/CloudQueue';
4
4
  import { ApiBlueprint, fetchApiRef, discoveryApiRef, PageBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
5
5
  import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
6
- import { anyshiftViewPermission, ANYSHIFT_TARGET_ANNOTATION, GITHUB_PROJECT_SLUG_ANNOTATION, ANYSHIFT_KIND_ANNOTATION, isAnyshiftResourceKind, ANYSHIFT_MANAGED_BY_ANNOTATION, ANYSHIFT_CLOUD_PROVIDER_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
6
+ import { anyshiftViewPermission, ANYSHIFT_TARGET_ANNOTATION, GITHUB_PROJECT_SLUG_ANNOTATION, ANYSHIFT_KIND_ANNOTATION, isAnyshiftResourceKind, ANYSHIFT_MANAGED_BY_ANNOTATION } from '@anyshift/backstage-plugin-anyshift-common';
7
+ import { isCloudResourceEntity, cloudResourceIdentity } from './components/entity/entityIdentity.esm.js';
7
8
  import { AnyshiftPermissionBoundary } from './components/AnyshiftPermissionBoundary.esm.js';
8
9
  import { AnyshiftClient, anyshiftApiRef } from './api/AnyshiftApi.esm.js';
9
10
  import { rootRouteRef, cloudRouteRef } from './routes.esm.js';
@@ -57,6 +58,9 @@ const cloudEntityContent = EntityContentBlueprint.make({
57
58
  }
58
59
  });
59
60
  function isAnyshiftEntityContentAvailable(entity) {
61
+ if (isCloudResourceEntity(entity)) {
62
+ return Boolean(cloudResourceIdentity(entity));
63
+ }
60
64
  const annotations = entity.metadata.annotations ?? {};
61
65
  const hasTarget = Boolean(
62
66
  annotations[ANYSHIFT_TARGET_ANNOTATION] || annotations[GITHUB_PROJECT_SLUG_ANNOTATION]
@@ -67,7 +71,7 @@ function isAnyshiftEntityContentAvailable(entity) {
67
71
  return annotations[ANYSHIFT_MANAGED_BY_ANNOTATION] !== "catalog-provider";
68
72
  }
69
73
  function isCloudResourceContentAvailable(entity) {
70
- return entity.kind.toLocaleLowerCase("en-US") === "resource" && Boolean(entity.metadata.annotations?.[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION]);
74
+ return isCloudResourceEntity(entity) && Boolean(cloudResourceIdentity(entity));
71
75
  }
72
76
  const anyshiftPlugin = createFrontendPlugin({
73
77
  pluginId: "anyshift",
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["import DeviceHubIcon from '@material-ui/icons/DeviceHub';\nimport CloudQueueIcon from '@material-ui/icons/CloudQueue';\nimport {\n ApiBlueprint,\n PageBlueprint,\n createFrontendPlugin,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport type { Entity } from '@backstage/catalog-model';\nimport {\n ANYSHIFT_KIND_ANNOTATION,\n ANYSHIFT_CLOUD_PROVIDER_ANNOTATION,\n ANYSHIFT_MANAGED_BY_ANNOTATION,\n ANYSHIFT_TARGET_ANNOTATION,\n GITHUB_PROJECT_SLUG_ANNOTATION,\n anyshiftViewPermission,\n isAnyshiftResourceKind,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport { AnyshiftPermissionBoundary } from './components/AnyshiftPermissionBoundary';\nimport { anyshiftApiRef, AnyshiftClient } from './api/AnyshiftApi';\nimport { cloudRouteRef, rootRouteRef } from './routes';\n\nconst anyshiftApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: anyshiftApiRef,\n deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },\n factory: ({ discoveryApi, fetchApi }) =>\n new AnyshiftClient({ discoveryApi, fetchApi }),\n }),\n});\n\nconst anyshiftPage = PageBlueprint.make({\n params: {\n path: '/anyshift',\n title: 'Anyshift',\n icon: <DeviceHubIcon fontSize=\"inherit\" />,\n routeRef: rootRouteRef,\n noHeader: true,\n loader: () =>\n import('./components/explorer/AnyshiftExplorerPage').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.AnyshiftExplorerPage />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst cloudPage = PageBlueprint.make({\n name: 'cloud',\n params: {\n path: '/cloud',\n title: 'Cloud',\n icon: <CloudQueueIcon fontSize=\"inherit\" />,\n routeRef: cloudRouteRef,\n noHeader: true,\n loader: () =>\n import('./components/cloud/CloudPage').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.CloudPage />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst anyshiftEntityContent = EntityContentBlueprint.make({\n name: 'entity-content',\n params: {\n path: '/anyshift',\n title: 'Anyshift',\n group: 'observability',\n filter: isAnyshiftEntityContentAvailable,\n loader: () =>\n import('./components/entity/AnyshiftEntityContent').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.AnyshiftEntityContent />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst cloudEntityContent = EntityContentBlueprint.make({\n name: 'cloud-resource-content',\n params: {\n path: '/cloud',\n title: 'Cloud',\n group: 'observability',\n filter: isCloudResourceContentAvailable,\n loader: () =>\n import('./components/cloud/CloudResourceContent').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.CloudResourceContent />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nexport function isAnyshiftEntityContentAvailable(entity: Entity): boolean {\n const annotations = entity.metadata.annotations ?? {};\n const hasTarget = Boolean(\n annotations[ANYSHIFT_TARGET_ANNOTATION] ||\n annotations[GITHUB_PROJECT_SLUG_ANNOTATION],\n );\n if (!hasTarget) return false;\n\n const kind = annotations[ANYSHIFT_KIND_ANNOTATION];\n if (kind) return isAnyshiftResourceKind(kind);\n\n return annotations[ANYSHIFT_MANAGED_BY_ANNOTATION] !== 'catalog-provider';\n}\n\nexport function isCloudResourceContentAvailable(entity: Entity): boolean {\n return (\n entity.kind.toLocaleLowerCase('en-US') === 'resource' &&\n Boolean(entity.metadata.annotations?.[ANYSHIFT_CLOUD_PROVIDER_ANNOTATION])\n );\n}\n\nexport const anyshiftPlugin = createFrontendPlugin({\n pluginId: 'anyshift',\n info: {\n packageJson: () => import('../package.json'),\n },\n routes: { root: rootRouteRef, cloud: cloudRouteRef },\n extensions: [\n anyshiftApi,\n anyshiftPage,\n cloudPage,\n anyshiftEntityContent,\n cloudEntityContent,\n ],\n});\n\nexport default anyshiftPlugin;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["import DeviceHubIcon from '@material-ui/icons/DeviceHub';\nimport CloudQueueIcon from '@material-ui/icons/CloudQueue';\nimport {\n ApiBlueprint,\n PageBlueprint,\n createFrontendPlugin,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';\nimport type { Entity } from '@backstage/catalog-model';\nimport {\n ANYSHIFT_KIND_ANNOTATION,\n ANYSHIFT_MANAGED_BY_ANNOTATION,\n ANYSHIFT_TARGET_ANNOTATION,\n GITHUB_PROJECT_SLUG_ANNOTATION,\n anyshiftViewPermission,\n isAnyshiftResourceKind,\n} from '@anyshift/backstage-plugin-anyshift-common';\nimport {\n cloudResourceIdentity,\n isCloudResourceEntity,\n} from './components/entity/entityIdentity';\nimport { AnyshiftPermissionBoundary } from './components/AnyshiftPermissionBoundary';\nimport { anyshiftApiRef, AnyshiftClient } from './api/AnyshiftApi';\nimport { cloudRouteRef, rootRouteRef } from './routes';\n\nconst anyshiftApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: anyshiftApiRef,\n deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },\n factory: ({ discoveryApi, fetchApi }) =>\n new AnyshiftClient({ discoveryApi, fetchApi }),\n }),\n});\n\nconst anyshiftPage = PageBlueprint.make({\n params: {\n path: '/anyshift',\n title: 'Anyshift',\n icon: <DeviceHubIcon fontSize=\"inherit\" />,\n routeRef: rootRouteRef,\n noHeader: true,\n loader: () =>\n import('./components/explorer/AnyshiftExplorerPage').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.AnyshiftExplorerPage />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst cloudPage = PageBlueprint.make({\n name: 'cloud',\n params: {\n path: '/cloud',\n title: 'Cloud',\n icon: <CloudQueueIcon fontSize=\"inherit\" />,\n routeRef: cloudRouteRef,\n noHeader: true,\n loader: () =>\n import('./components/cloud/CloudPage').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.CloudPage />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst anyshiftEntityContent = EntityContentBlueprint.make({\n name: 'entity-content',\n params: {\n path: '/anyshift',\n title: 'Anyshift',\n group: 'observability',\n filter: isAnyshiftEntityContentAvailable,\n loader: () =>\n import('./components/entity/AnyshiftEntityContent').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.AnyshiftEntityContent />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nconst cloudEntityContent = EntityContentBlueprint.make({\n name: 'cloud-resource-content',\n params: {\n path: '/cloud',\n title: 'Cloud',\n group: 'observability',\n filter: isCloudResourceContentAvailable,\n loader: () =>\n import('./components/cloud/CloudResourceContent').then(module => (\n <AnyshiftPermissionBoundary permission={anyshiftViewPermission}>\n <module.CloudResourceContent />\n </AnyshiftPermissionBoundary>\n )),\n },\n});\n\nexport function isAnyshiftEntityContentAvailable(entity: Entity): boolean {\n if (isCloudResourceEntity(entity)) {\n return Boolean(cloudResourceIdentity(entity));\n }\n\n const annotations = entity.metadata.annotations ?? {};\n const hasTarget = Boolean(\n annotations[ANYSHIFT_TARGET_ANNOTATION] ||\n annotations[GITHUB_PROJECT_SLUG_ANNOTATION],\n );\n if (!hasTarget) return false;\n\n const kind = annotations[ANYSHIFT_KIND_ANNOTATION];\n if (kind) return isAnyshiftResourceKind(kind);\n\n return annotations[ANYSHIFT_MANAGED_BY_ANNOTATION] !== 'catalog-provider';\n}\n\nexport function isCloudResourceContentAvailable(entity: Entity): boolean {\n return (\n isCloudResourceEntity(entity) && Boolean(cloudResourceIdentity(entity))\n );\n}\n\nexport const anyshiftPlugin = createFrontendPlugin({\n pluginId: 'anyshift',\n info: {\n packageJson: () => import('../package.json'),\n },\n routes: { root: rootRouteRef, cloud: cloudRouteRef },\n extensions: [\n anyshiftApi,\n anyshiftPage,\n cloudPage,\n anyshiftEntityContent,\n cloudEntityContent,\n ],\n});\n\nexport default anyshiftPlugin;\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anyshift/backstage-plugin-anyshift",
3
- "version": "0.1.0-beta.11",
3
+ "version": "0.1.0-beta.13",
4
4
  "description": "Read-only Anyshift infrastructure context for Backstage",
5
5
  "main": "dist/index.esm.js",
6
6
  "types": "dist/index.d.ts",
@@ -45,7 +45,7 @@
45
45
  "clean": "backstage-cli package clean"
46
46
  },
47
47
  "dependencies": {
48
- "@anyshift/backstage-plugin-anyshift-common": "^0.1.0-beta.11",
48
+ "@anyshift/backstage-plugin-anyshift-common": "^0.1.0-beta.13",
49
49
  "@backstage/catalog-model": "^1.9.0",
50
50
  "@backstage/core-components": "^0.18.11",
51
51
  "@backstage/frontend-plugin-api": "^0.17.2",