@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 +14 -0
- package/dist/components/ask/askScope.esm.js +3 -2
- package/dist/components/ask/askScope.esm.js.map +1 -1
- package/dist/components/cloud/CloudImpactSection.esm.js +54 -0
- package/dist/components/cloud/CloudImpactSection.esm.js.map +1 -0
- package/dist/components/cloud/CloudRelationshipSections.esm.js +43 -0
- package/dist/components/cloud/CloudRelationshipSections.esm.js.map +1 -0
- package/dist/components/cloud/CloudResourceContent.esm.js +306 -172
- package/dist/components/cloud/CloudResourceContent.esm.js.map +1 -1
- package/dist/components/entity/AnyshiftEntityContent.esm.js +8 -10
- package/dist/components/entity/AnyshiftEntityContent.esm.js.map +1 -1
- package/dist/components/entity/entityIdentity.esm.js +30 -0
- package/dist/components/entity/entityIdentity.esm.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/package.json.esm.js +1 -1
- package/dist/plugin.esm.js +6 -2
- package/dist/plugin.esm.js.map +1 -1
- package/package.json +2 -2
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/
|
|
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 {
|
|
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 {
|
|
8
|
-
import { useEntity
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 [
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
}) =>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
/* @__PURE__ */ jsx(
|
|
280
|
-
|
|
281
|
-
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
}) =>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
" ",
|
|
314
|
-
difference
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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,
|
|
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
|
|
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,
|
|
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>;
|
package/dist/package.json.esm.js
CHANGED
package/dist/plugin.esm.js
CHANGED
|
@@ -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
|
|
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
|
|
74
|
+
return isCloudResourceEntity(entity) && Boolean(cloudResourceIdentity(entity));
|
|
71
75
|
}
|
|
72
76
|
const anyshiftPlugin = createFrontendPlugin({
|
|
73
77
|
pluginId: "anyshift",
|
package/dist/plugin.esm.js.map
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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",
|