@anyshift/backstage-plugin-anyshift 0.1.0-beta.1
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 +6 -0
- package/LICENSE +176 -0
- package/README.md +9 -0
- package/dist/api/AnyshiftApi.esm.js +80 -0
- package/dist/api/AnyshiftApi.esm.js.map +1 -0
- package/dist/components/AnyshiftPermissionBoundary.esm.js +25 -0
- package/dist/components/AnyshiftPermissionBoundary.esm.js.map +1 -0
- package/dist/components/entity/AnyshiftEntityContent.esm.js +213 -0
- package/dist/components/entity/AnyshiftEntityContent.esm.js.map +1 -0
- package/dist/components/entity/BriefSections.esm.js +218 -0
- package/dist/components/entity/BriefSections.esm.js.map +1 -0
- package/dist/components/entity/DatadogLiveSignal.esm.js +190 -0
- package/dist/components/entity/DatadogLiveSignal.esm.js.map +1 -0
- package/dist/components/entity/EvidenceDisclosure.esm.js +20 -0
- package/dist/components/entity/EvidenceDisclosure.esm.js.map +1 -0
- package/dist/components/entity/MermaidArchitecture.esm.js +89 -0
- package/dist/components/entity/MermaidArchitecture.esm.js.map +1 -0
- package/dist/components/entity/SectionPresenters.esm.js +341 -0
- package/dist/components/entity/SectionPresenters.esm.js.map +1 -0
- package/dist/components/entity/architectureDiagram.esm.js +236 -0
- package/dist/components/entity/architectureDiagram.esm.js.map +1 -0
- package/dist/components/entity/sectionData.esm.js +127 -0
- package/dist/components/entity/sectionData.esm.js.map +1 -0
- package/dist/components/explorer/AnyshiftExplorerPage.esm.js +193 -0
- package/dist/components/explorer/AnyshiftExplorerPage.esm.js.map +1 -0
- package/dist/components/explorer/DatadogOperationsRadar.esm.js +294 -0
- package/dist/components/explorer/DatadogOperationsRadar.esm.js.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.esm.js +4 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/package.json.esm.js +96 -0
- package/dist/package.json.esm.js.map +1 -0
- package/dist/plugin.esm.js +49 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +6 -0
- package/dist/routes.esm.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architectureDiagram.esm.js","sources":["../../../src/components/entity/architectureDiagram.ts"],"sourcesContent":["export interface ArchitectureNode {\n id: string;\n name: string;\n type?: string | null;\n namespace?: string | null;\n image?: string | null;\n}\n\nexport interface ArchitectureEdge {\n from: string;\n to: string;\n type: string;\n}\n\nexport interface ArchitectureGraph {\n nodes: ArchitectureNode[];\n edges: ArchitectureEdge[];\n}\n\nexport interface ArchitectureDiagramDefinition {\n source: string;\n fallbackRelationships: string[];\n}\n\ninterface CompactGraph {\n nodes: ArchitectureNode[];\n edges: ArchitectureEdge[];\n}\n\nconst RUNTIME_INSTANCE_TYPES = new Set(['K8S_REPLICASET', 'K8S_POD']);\nconst MAX_DIRECT_DEPENDENCIES = 5;\n\nexport function buildArchitectureDiagram(\n graph: ArchitectureGraph,\n options: { view?: 'context' | 'runtime' } = {},\n): ArchitectureDiagramDefinition {\n const base = compactArchitectureGraph(graph);\n const viewed = options.view === 'context' ? serviceContextGraph(base) : base;\n const compact = summarizeDirectDependencies(viewed);\n const nodeIds = new Map(\n compact.nodes.map((node, index) => [node.id, `n${index}`]),\n );\n const names = new Map(\n compact.nodes.map(node => [node.id, readableNodeLabel(node)]),\n );\n const lines = ['flowchart LR'];\n\n compact.nodes.forEach(node => {\n const id = nodeIds.get(node.id)!;\n const label = mermaidNodeLabel(node);\n if (node.type === 'DATADOG_DATASTORE') {\n lines.push(` ${id}[(\"${label}\")]`);\n } else if (\n node.type === 'DATADOG_EXTERNAL' ||\n node.type === 'DATADOG_DESTINATION'\n ) {\n lines.push(` ${id}([\"${label}\"])`);\n } else {\n lines.push(` ${id}[\"${label}\"]`);\n }\n });\n\n compact.edges.forEach(edge => {\n const from = nodeIds.get(edge.from);\n const to = nodeIds.get(edge.to);\n if (from && to) {\n lines.push(` ${from} -->|${sanitize(edge.type)}| ${to}`);\n }\n });\n\n lines.push(\n ' classDef service fill:#e8f0fe,stroke:#1967d2,color:#174ea6',\n ' classDef runtime fill:#e6f4ea,stroke:#188038,color:#137333',\n ' classDef dependency fill:#fef7e0,stroke:#f9ab00,color:#7a4f01',\n );\n compact.nodes.forEach(node => {\n const id = nodeIds.get(node.id)!;\n lines.push(` class ${id} ${className(node)}`);\n });\n\n return {\n source: lines.join('\\n'),\n fallbackRelationships: compact.edges.flatMap(edge => {\n const from = names.get(edge.from);\n const to = names.get(edge.to);\n return from && to\n ? [`${from} → ${readableRelationship(edge.type)} → ${to}`]\n : [];\n }),\n };\n}\n\nfunction serviceContextGraph(graph: CompactGraph): CompactGraph {\n const nodes = graph.nodes.filter(node => node.type !== 'K8S_CONTAINER');\n const visible = new Set(nodes.map(node => node.id));\n return {\n nodes,\n edges: graph.edges.filter(\n edge => visible.has(edge.from) && visible.has(edge.to),\n ),\n };\n}\n\nfunction compactArchitectureGraph(graph: ArchitectureGraph): CompactGraph {\n const nodeById = new Map(graph.nodes.map(node => [node.id, node]));\n const visibleNodes = graph.nodes\n .filter(node => !isRuntimeInstance(node))\n .map(normalizeNode);\n const canonicalNodes = new Map<string, ArchitectureNode>();\n const canonicalId = new Map<string, string>();\n\n visibleNodes.forEach(node => {\n const key = semanticNodeKey(node);\n const existing = canonicalNodes.get(key);\n if (existing) {\n canonicalId.set(node.id, existing.id);\n } else {\n canonicalNodes.set(key, node);\n canonicalId.set(node.id, node.id);\n }\n });\n\n const outgoing = new Map<string, ArchitectureEdge[]>();\n graph.edges.forEach(edge => {\n const list = outgoing.get(edge.from) ?? [];\n list.push(edge);\n outgoing.set(edge.from, list);\n });\n\n const compactEdges = new Map<string, ArchitectureEdge>();\n visibleNodes.forEach(source => {\n const sourceId = canonicalId.get(source.id)!;\n walkToVisibleTargets(source.id, outgoing, nodeById).forEach(target => {\n const targetId = canonicalId.get(target.node.id);\n if (!targetId || sourceId === targetId) return;\n const type = target.collapsed ? 'RUNS' : target.edgeType;\n const key = `${sourceId}|${type}|${targetId}`;\n compactEdges.set(key, { from: sourceId, to: targetId, type });\n });\n });\n\n return {\n nodes: [...canonicalNodes.values()],\n edges: [...compactEdges.values()],\n };\n}\n\nfunction summarizeDirectDependencies(graph: CompactGraph): CompactGraph {\n const root = graph.edges.find(edge => edge.type === 'RESOLVES_TO')?.from;\n if (!root) return graph;\n\n const nodes = new Map(graph.nodes.map(node => [node.id, node]));\n const groups = new Map<string, ArchitectureEdge[]>();\n const groupedEdges = new Set<ArchitectureEdge>();\n\n graph.edges.forEach(edge => {\n if (edge.type === 'RESOLVES_TO') return;\n let neighborId: string | undefined;\n if (edge.from === root) neighborId = edge.to;\n if (edge.to === root) neighborId = edge.from;\n if (!neighborId) return;\n const neighbor = nodes.get(neighborId);\n if (!neighbor || neighbor.type?.startsWith('K8S_')) return;\n const direction = edge.from === root ? 'out' : 'in';\n const key = `${direction}|${edge.type}|${neighbor.type ?? ''}`;\n const group = groups.get(key) ?? [];\n group.push(edge);\n groups.set(key, group);\n groupedEdges.add(edge);\n });\n\n const edges = graph.edges.filter(edge => !groupedEdges.has(edge));\n const aggregateNodes: ArchitectureNode[] = [];\n groups.forEach((group, key) => {\n if (group.length <= MAX_DIRECT_DEPENDENCIES) {\n edges.push(...group);\n return;\n }\n\n const visible = group.slice(0, MAX_DIRECT_DEPENDENCIES - 1);\n const hidden = group.slice(MAX_DIRECT_DEPENDENCIES - 1);\n const sample = group[0];\n const direction = sample.from === root ? 'out' : 'in';\n const neighbor = nodes.get(direction === 'out' ? sample.to : sample.from)!;\n const aggregateId = `aggregate-${key.replace(/[^A-Za-z0-9]/g, '-')}`;\n aggregateNodes.push({\n id: aggregateId,\n name: `${hidden.length} more ${pluralType(neighbor.type)}`,\n type: neighbor.type,\n });\n edges.push(...visible);\n edges.push(\n direction === 'out'\n ? { from: root, to: aggregateId, type: sample.type }\n : { from: aggregateId, to: root, type: sample.type },\n );\n });\n\n const referenced = new Set(edges.flatMap(edge => [edge.from, edge.to]));\n return {\n nodes: [\n ...graph.nodes.filter(node => referenced.has(node.id)),\n ...aggregateNodes,\n ],\n edges,\n };\n}\n\nfunction walkToVisibleTargets(\n start: string,\n outgoing: Map<string, ArchitectureEdge[]>,\n nodeById: Map<string, ArchitectureNode>,\n): Array<{\n node: ArchitectureNode;\n edgeType: string;\n collapsed: boolean;\n}> {\n const targets: Array<{\n node: ArchitectureNode;\n edgeType: string;\n collapsed: boolean;\n }> = [];\n const queue = (outgoing.get(start) ?? []).map(edge => ({\n id: edge.to,\n edgeType: edge.type,\n collapsed: false,\n }));\n const visited = new Set<string>();\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const visitKey = `${current.id}|${current.collapsed}`;\n if (visited.has(visitKey)) continue;\n visited.add(visitKey);\n\n const node = nodeById.get(current.id);\n if (!node) continue;\n if (!isRuntimeInstance(node)) {\n targets.push({ node, ...current });\n continue;\n }\n\n (outgoing.get(current.id) ?? []).forEach(edge => {\n queue.push({ id: edge.to, edgeType: edge.type, collapsed: true });\n });\n }\n\n return targets;\n}\n\nfunction isRuntimeInstance(node: ArchitectureNode): boolean {\n return RUNTIME_INSTANCE_TYPES.has(node.type ?? '');\n}\n\nfunction normalizeNode(node: ArchitectureNode): ArchitectureNode {\n if (node.type !== 'K8S_CONTAINER') return node;\n const slash = node.name.lastIndexOf('/');\n return {\n ...node,\n name: slash >= 0 ? node.name.slice(slash + 1) : node.name,\n image: node.image ? imageRepository(node.image) : node.image,\n };\n}\n\nfunction imageRepository(image: string): string {\n const withoutDigest = image.split('@', 1)[0];\n const slash = withoutDigest.lastIndexOf('/');\n const tag = withoutDigest.lastIndexOf(':');\n const repository = tag > slash ? withoutDigest.slice(0, tag) : withoutDigest;\n return repository.slice(repository.lastIndexOf('/') + 1);\n}\n\nfunction semanticNodeKey(node: ArchitectureNode): string {\n return [\n node.type ?? '',\n node.namespace ?? '',\n node.name,\n node.image ?? '',\n ].join('|');\n}\n\nfunction readableNodeLabel(node: ArchitectureNode): string {\n const type = shortType(node.type);\n const typed = type ? `${node.name} [${type}]` : node.name;\n return node.type?.startsWith('K8S_') && node.namespace\n ? `${typed} (${node.namespace})`\n : typed;\n}\n\nfunction mermaidNodeLabel(node: ArchitectureNode): string {\n const parts = [sanitize(node.name)];\n const type = shortType(node.type);\n if (type) parts.push(`[${type}]`);\n if (node.type?.startsWith('K8S_') && node.namespace) {\n parts.push(`namespace: ${sanitize(node.namespace)}`);\n }\n if (node.image) parts.push(sanitize(node.image));\n return parts.join('<br/>');\n}\n\nfunction shortType(type?: string | null): string {\n return (type ?? '').replace(/^K8S_|^DATADOG_/, '');\n}\n\nfunction pluralType(type?: string | null): string {\n return `${shortType(type).toLocaleLowerCase()}s`;\n}\n\nfunction readableRelationship(type: string): string {\n return type.toLocaleLowerCase().replace(/_/g, ' ');\n}\n\nfunction sanitize(value: string): string {\n return value\n .replace(/\"/g, \"'\")\n .replace(/[<>|]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction className(node: ArchitectureNode): string {\n if (node.type?.startsWith('K8S_')) return 'runtime';\n if (node.type === 'DATADOG_SERVICE') return 'service';\n return 'dependency';\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const COLLECTION_KEYS = [
|
|
2
|
+
"recent",
|
|
3
|
+
"items",
|
|
4
|
+
"resources",
|
|
5
|
+
"nodes",
|
|
6
|
+
"events",
|
|
7
|
+
"deployments",
|
|
8
|
+
"affected",
|
|
9
|
+
"dependencies",
|
|
10
|
+
"claims"
|
|
11
|
+
];
|
|
12
|
+
const RESULT_ENVELOPE_KEYS = [
|
|
13
|
+
"spof",
|
|
14
|
+
"scaling",
|
|
15
|
+
"pdb",
|
|
16
|
+
"deployments",
|
|
17
|
+
"blastRadius",
|
|
18
|
+
"topology"
|
|
19
|
+
];
|
|
20
|
+
const EVENT_FACT_KEYS = /* @__PURE__ */ new Set([
|
|
21
|
+
"type",
|
|
22
|
+
"eventType",
|
|
23
|
+
"kind",
|
|
24
|
+
"target",
|
|
25
|
+
"resource",
|
|
26
|
+
"name",
|
|
27
|
+
"ts",
|
|
28
|
+
"timestamp",
|
|
29
|
+
"time",
|
|
30
|
+
"occurredAt",
|
|
31
|
+
"summary",
|
|
32
|
+
"message",
|
|
33
|
+
"description"
|
|
34
|
+
]);
|
|
35
|
+
const TRANSPORT_METADATA_KEYS = /* @__PURE__ */ new Set([
|
|
36
|
+
"question",
|
|
37
|
+
"intent",
|
|
38
|
+
"countOnly",
|
|
39
|
+
"elapsedMs",
|
|
40
|
+
"sql",
|
|
41
|
+
"projectId"
|
|
42
|
+
]);
|
|
43
|
+
function recordsFrom(value) {
|
|
44
|
+
if (Array.isArray(value)) return value.filter(isRecord);
|
|
45
|
+
if (!isRecord(value)) return [];
|
|
46
|
+
for (const key of COLLECTION_KEYS) {
|
|
47
|
+
const candidate = value[key];
|
|
48
|
+
if (Array.isArray(candidate)) return candidate.filter(isRecord);
|
|
49
|
+
if (isRecord(candidate)) {
|
|
50
|
+
const nested = recordsFrom(candidate);
|
|
51
|
+
if (nested.length > 0) return nested;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const key of RESULT_ENVELOPE_KEYS) {
|
|
55
|
+
const nested = recordsFrom(value[key]);
|
|
56
|
+
if (nested.length > 0) return nested;
|
|
57
|
+
}
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
function firstRecordFrom(value) {
|
|
61
|
+
const records = recordsFrom(value);
|
|
62
|
+
if (records.length > 0) return records[0];
|
|
63
|
+
if (isRecord(value) && primitiveEntries(value).length > 0) return value;
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
function factsFrom(value, limit = 6) {
|
|
67
|
+
if (!isRecord(value)) return [];
|
|
68
|
+
return primitiveEntries(value).filter(([key]) => !TRANSPORT_METADATA_KEYS.has(key)).slice(0, limit).map(([key, item]) => ({ label: titleCase(key), value: String(item) }));
|
|
69
|
+
}
|
|
70
|
+
function eventFrom(value) {
|
|
71
|
+
const record = firstRecordFrom(value) ?? {};
|
|
72
|
+
return {
|
|
73
|
+
type: readableText(readText(record, ["type", "eventType", "kind"])),
|
|
74
|
+
target: readText(record, ["target", "resource", "name"]),
|
|
75
|
+
timestamp: readText(record, ["ts", "timestamp", "time", "occurredAt"]),
|
|
76
|
+
summary: readText(record, ["summary", "message", "description"]),
|
|
77
|
+
status: statusFrom(record),
|
|
78
|
+
facts: primitiveEntries(record).filter(([key]) => !EVENT_FACT_KEYS.has(key)).slice(0, 6).map(([key, item]) => ({ label: titleCase(key), value: String(item) }))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function statusFrom(value) {
|
|
82
|
+
if (!isRecord(value)) return void 0;
|
|
83
|
+
const status = readText(value, ["status", "state", "severity", "health"]);
|
|
84
|
+
if (!status) return void 0;
|
|
85
|
+
const normalized = status.toLocaleLowerCase().replace(/[\s_-]+/g, "");
|
|
86
|
+
const success = ["healthy", "ok", "passing", "ready", "stable", "success"];
|
|
87
|
+
const warning = ["warning", "warn", "degraded", "atrisk", "pending"];
|
|
88
|
+
const error = [
|
|
89
|
+
"error",
|
|
90
|
+
"critical",
|
|
91
|
+
"failed",
|
|
92
|
+
"failure",
|
|
93
|
+
"unhealthy",
|
|
94
|
+
"breached"
|
|
95
|
+
];
|
|
96
|
+
return {
|
|
97
|
+
label: titleCase(status),
|
|
98
|
+
tone: success.includes(normalized) ? "success" : warning.includes(normalized) ? "warning" : error.includes(normalized) ? "error" : "default"
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function readText(value, keys) {
|
|
102
|
+
if (!isRecord(value)) return void 0;
|
|
103
|
+
for (const key of keys) {
|
|
104
|
+
const item = value[key];
|
|
105
|
+
if (typeof item === "string" && item.trim()) return item.trim();
|
|
106
|
+
if (typeof item === "number") return String(item);
|
|
107
|
+
}
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
function titleCase(value) {
|
|
111
|
+
const words = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().toLocaleLowerCase();
|
|
112
|
+
return words ? `${words[0].toLocaleUpperCase()}${words.slice(1)}` : value;
|
|
113
|
+
}
|
|
114
|
+
function isRecord(value) {
|
|
115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116
|
+
}
|
|
117
|
+
function primitiveEntries(value) {
|
|
118
|
+
return Object.entries(value).filter(
|
|
119
|
+
(entry) => ["string", "number", "boolean"].includes(typeof entry[1])
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
function readableText(value) {
|
|
123
|
+
return value?.replace(/[_-]+/g, " ").toLocaleLowerCase();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { eventFrom, factsFrom, firstRecordFrom, isRecord, readText, recordsFrom, statusFrom, titleCase };
|
|
127
|
+
//# sourceMappingURL=sectionData.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sectionData.esm.js","sources":["../../../src/components/entity/sectionData.ts"],"sourcesContent":["export interface Fact {\n label: string;\n value: string;\n}\n\nexport interface EventSummary {\n type?: string;\n target?: string;\n timestamp?: string;\n summary?: string;\n status?: StatusSummary;\n facts: Fact[];\n}\n\nexport interface StatusSummary {\n label: string;\n tone: 'default' | 'success' | 'warning' | 'error';\n}\n\nconst COLLECTION_KEYS = [\n 'recent',\n 'items',\n 'resources',\n 'nodes',\n 'events',\n 'deployments',\n 'affected',\n 'dependencies',\n 'claims',\n] as const;\n\nconst RESULT_ENVELOPE_KEYS = [\n 'spof',\n 'scaling',\n 'pdb',\n 'deployments',\n 'blastRadius',\n 'topology',\n] as const;\n\nconst EVENT_FACT_KEYS = new Set([\n 'type',\n 'eventType',\n 'kind',\n 'target',\n 'resource',\n 'name',\n 'ts',\n 'timestamp',\n 'time',\n 'occurredAt',\n 'summary',\n 'message',\n 'description',\n]);\n\nconst TRANSPORT_METADATA_KEYS = new Set([\n 'question',\n 'intent',\n 'countOnly',\n 'elapsedMs',\n 'sql',\n 'projectId',\n]);\n\nexport function recordsFrom(value: unknown): Record<string, unknown>[] {\n if (Array.isArray(value)) return value.filter(isRecord);\n if (!isRecord(value)) return [];\n\n for (const key of COLLECTION_KEYS) {\n const candidate = value[key];\n if (Array.isArray(candidate)) return candidate.filter(isRecord);\n if (isRecord(candidate)) {\n const nested = recordsFrom(candidate);\n if (nested.length > 0) return nested;\n }\n }\n for (const key of RESULT_ENVELOPE_KEYS) {\n const nested = recordsFrom(value[key]);\n if (nested.length > 0) return nested;\n }\n return [];\n}\n\nexport function firstRecordFrom(\n value: unknown,\n): Record<string, unknown> | undefined {\n const records = recordsFrom(value);\n if (records.length > 0) return records[0];\n if (isRecord(value) && primitiveEntries(value).length > 0) return value;\n return undefined;\n}\n\nexport function factsFrom(value: unknown, limit = 6): Fact[] {\n if (!isRecord(value)) return [];\n return primitiveEntries(value)\n .filter(([key]) => !TRANSPORT_METADATA_KEYS.has(key))\n .slice(0, limit)\n .map(([key, item]) => ({ label: titleCase(key), value: String(item) }));\n}\n\nexport function eventFrom(value: unknown): EventSummary {\n const record = firstRecordFrom(value) ?? {};\n return {\n type: readableText(readText(record, ['type', 'eventType', 'kind'])),\n target: readText(record, ['target', 'resource', 'name']),\n timestamp: readText(record, ['ts', 'timestamp', 'time', 'occurredAt']),\n summary: readText(record, ['summary', 'message', 'description']),\n status: statusFrom(record),\n facts: primitiveEntries(record)\n .filter(([key]) => !EVENT_FACT_KEYS.has(key))\n .slice(0, 6)\n .map(([key, item]) => ({ label: titleCase(key), value: String(item) })),\n };\n}\n\nexport function statusFrom(value: unknown): StatusSummary | undefined {\n if (!isRecord(value)) return undefined;\n const status = readText(value, ['status', 'state', 'severity', 'health']);\n if (!status) return undefined;\n\n const normalized = status.toLocaleLowerCase().replace(/[\\s_-]+/g, '');\n const success = ['healthy', 'ok', 'passing', 'ready', 'stable', 'success'];\n const warning = ['warning', 'warn', 'degraded', 'atrisk', 'pending'];\n const error = [\n 'error',\n 'critical',\n 'failed',\n 'failure',\n 'unhealthy',\n 'breached',\n ];\n\n return {\n label: titleCase(status),\n tone: success.includes(normalized)\n ? 'success'\n : warning.includes(normalized)\n ? 'warning'\n : error.includes(normalized)\n ? 'error'\n : 'default',\n };\n}\n\nexport function readText(\n value: unknown,\n keys: readonly string[],\n): string | undefined {\n if (!isRecord(value)) return undefined;\n for (const key of keys) {\n const item = value[key];\n if (typeof item === 'string' && item.trim()) return item.trim();\n if (typeof item === 'number') return String(item);\n }\n return undefined;\n}\n\nexport function titleCase(value: string): string {\n const words = value\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim()\n .toLocaleLowerCase();\n return words ? `${words[0].toLocaleUpperCase()}${words.slice(1)}` : value;\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction primitiveEntries(\n value: Record<string, unknown>,\n): Array<[string, string | number | boolean]> {\n return Object.entries(value).filter(\n (entry): entry is [string, string | number | boolean] =>\n ['string', 'number', 'boolean'].includes(typeof entry[1]),\n );\n}\n\nfunction readableText(value: string | undefined): string | undefined {\n return value?.replace(/[_-]+/g, ' ').toLocaleLowerCase();\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Typography, TextField, Grid, Button } from '@material-ui/core';
|
|
4
|
+
import { Page, Header, Content, Progress, ContentHeader, InfoCard } from '@backstage/core-components';
|
|
5
|
+
import { useApi } from '@backstage/frontend-plugin-api';
|
|
6
|
+
import { usePermission } from '@backstage/plugin-permission-react';
|
|
7
|
+
import { anyshiftQueryPermission } from '@anyshift/backstage-plugin-anyshift-common';
|
|
8
|
+
import { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';
|
|
9
|
+
import { anyshiftApiRef } from '../../api/AnyshiftApi.esm.js';
|
|
10
|
+
import { TimelinePresenter, ImpactPresenter } from '../entity/SectionPresenters.esm.js';
|
|
11
|
+
import { DatadogOperationsRadar } from './DatadogOperationsRadar.esm.js';
|
|
12
|
+
|
|
13
|
+
const DEFAULT_QUERY = "SELECT * FROM resources WHERE type = deployment LIMIT 10";
|
|
14
|
+
function isDeterministicSelect(value) {
|
|
15
|
+
const sql = value.trim();
|
|
16
|
+
return /^SELECT\b/i.test(sql) && sql.length <= 4096 && !sql.includes(";") && !sql.includes("--") && !sql.includes("/*");
|
|
17
|
+
}
|
|
18
|
+
function matchesCatalogEntity(entity, value) {
|
|
19
|
+
const query = value.trim().toLocaleLowerCase();
|
|
20
|
+
if (!query) return true;
|
|
21
|
+
const searchable = [
|
|
22
|
+
entity.metadata.name,
|
|
23
|
+
entity.metadata.title,
|
|
24
|
+
entity.metadata.description,
|
|
25
|
+
entity.metadata.annotations?.["anyshift.io/target"],
|
|
26
|
+
typeof entity.spec?.owner === "string" ? entity.spec.owner : void 0
|
|
27
|
+
];
|
|
28
|
+
return searchable.some((item) => item?.toLocaleLowerCase().includes(query));
|
|
29
|
+
}
|
|
30
|
+
const EstateInsightsGrid = ({
|
|
31
|
+
insights
|
|
32
|
+
}) => /* @__PURE__ */ jsx(Fragment, { children: insights.sections.map((item) => /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsx(InfoCard, { title: item.title, children: item.section.state === "error" ? /* @__PURE__ */ jsx(Typography, { color: "error", children: item.section.message }) : item.section.state === "empty" || item.section.state === "unsupported" || item.section.data === void 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", children: item.section.message || "No insight evidence is available." }) : item.id === "recent-change" ? /* @__PURE__ */ jsx(
|
|
33
|
+
TimelinePresenter,
|
|
34
|
+
{
|
|
35
|
+
data: item.section.data,
|
|
36
|
+
fallbackLabel: "Deployment"
|
|
37
|
+
}
|
|
38
|
+
) : /* @__PURE__ */ jsx(ImpactPresenter, { data: item.section.data }) }) }, item.id)) });
|
|
39
|
+
const AnyshiftExplorerPage = () => {
|
|
40
|
+
const api = useApi(anyshiftApiRef);
|
|
41
|
+
const catalogApi = useApi(catalogApiRef);
|
|
42
|
+
const queryPermission = usePermission({
|
|
43
|
+
permission: anyshiftQueryPermission
|
|
44
|
+
});
|
|
45
|
+
const [queryEnabled, setQueryEnabled] = useState(false);
|
|
46
|
+
const [insights, setInsights] = useState();
|
|
47
|
+
const [insightError, setInsightError] = useState();
|
|
48
|
+
const [datadogSignals, setDatadogSignals] = useState();
|
|
49
|
+
const [datadogError, setDatadogError] = useState();
|
|
50
|
+
const [refreshingDatadog, setRefreshingDatadog] = useState(false);
|
|
51
|
+
const [catalogEntities, setCatalogEntities] = useState([]);
|
|
52
|
+
const [catalogError, setCatalogError] = useState();
|
|
53
|
+
const [catalogQuery, setCatalogQuery] = useState("");
|
|
54
|
+
const [sql, setSql] = useState(DEFAULT_QUERY);
|
|
55
|
+
const [queryResult, setQueryResult] = useState();
|
|
56
|
+
const [queryError, setQueryError] = useState();
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
api.capabilities().then((capabilities) => setQueryEnabled(capabilities.queryEnabled)).catch(() => setQueryEnabled(false));
|
|
59
|
+
}, [api]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
api.datadogSignals().then(setDatadogSignals).catch((error) => {
|
|
62
|
+
setDatadogError(error instanceof Error ? error.message : String(error));
|
|
63
|
+
});
|
|
64
|
+
}, [api]);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
api.insights().then(setInsights).catch((error) => {
|
|
67
|
+
setInsightError(error instanceof Error ? error.message : String(error));
|
|
68
|
+
});
|
|
69
|
+
}, [api]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
catalogApi.getEntities({
|
|
72
|
+
filter: [{ kind: "Component" }, { kind: "Resource" }]
|
|
73
|
+
}).then(
|
|
74
|
+
(response) => setCatalogEntities(
|
|
75
|
+
response.items.filter(
|
|
76
|
+
(entity) => entity.metadata.annotations?.["anyshift.io/target"]
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
).catch((error) => {
|
|
80
|
+
setCatalogError(error instanceof Error ? error.message : String(error));
|
|
81
|
+
});
|
|
82
|
+
}, [catalogApi]);
|
|
83
|
+
const matchingEntities = catalogEntities.filter((entity) => matchesCatalogEntity(entity, catalogQuery)).slice(0, 12);
|
|
84
|
+
const runQuery = async () => {
|
|
85
|
+
if (!isDeterministicSelect(sql)) {
|
|
86
|
+
setQueryError("Enter one deterministic SELECT query.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
setQueryError(void 0);
|
|
90
|
+
try {
|
|
91
|
+
setQueryResult(await api.query(sql.trim()));
|
|
92
|
+
} catch (error) {
|
|
93
|
+
setQueryError(error instanceof Error ? error.message : String(error));
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const refreshDatadog = async () => {
|
|
97
|
+
setRefreshingDatadog(true);
|
|
98
|
+
setDatadogError(void 0);
|
|
99
|
+
try {
|
|
100
|
+
setDatadogSignals(await api.datadogSignals({ refresh: true }));
|
|
101
|
+
} catch (error) {
|
|
102
|
+
setDatadogError(error instanceof Error ? error.message : String(error));
|
|
103
|
+
} finally {
|
|
104
|
+
setRefreshingDatadog(false);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
|
|
108
|
+
/* @__PURE__ */ jsx(
|
|
109
|
+
Header,
|
|
110
|
+
{
|
|
111
|
+
title: "Anyshift",
|
|
112
|
+
subtitle: "Live infrastructure context for your software catalog"
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
/* @__PURE__ */ jsxs(Content, { children: [
|
|
116
|
+
datadogSignals ? /* @__PURE__ */ jsx(
|
|
117
|
+
DatadogOperationsRadar,
|
|
118
|
+
{
|
|
119
|
+
signals: datadogSignals,
|
|
120
|
+
catalogEntities,
|
|
121
|
+
onRefresh: refreshDatadog,
|
|
122
|
+
refreshing: refreshingDatadog,
|
|
123
|
+
error: datadogError
|
|
124
|
+
}
|
|
125
|
+
) : datadogError ? /* @__PURE__ */ jsx(Typography, { color: "error", children: datadogError }) : /* @__PURE__ */ jsx(Progress, {}),
|
|
126
|
+
/* @__PURE__ */ jsx(ContentHeader, { title: "Find a service" }),
|
|
127
|
+
/* @__PURE__ */ jsxs(InfoCard, { subheader: "Anyshift-annotated Components and Resources in the Backstage catalog", children: [
|
|
128
|
+
/* @__PURE__ */ jsx(
|
|
129
|
+
TextField,
|
|
130
|
+
{
|
|
131
|
+
fullWidth: true,
|
|
132
|
+
variant: "outlined",
|
|
133
|
+
label: "Search services and resources",
|
|
134
|
+
value: catalogQuery,
|
|
135
|
+
onChange: (event) => setCatalogQuery(event.target.value)
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
catalogError && /* @__PURE__ */ jsx(Typography, { color: "error", children: catalogError }),
|
|
139
|
+
!catalogError && matchingEntities.length === 0 ? /* @__PURE__ */ jsx(Typography, { color: "textSecondary", style: { marginTop: 12 }, children: "No matching Anyshift catalog entities." }) : /* @__PURE__ */ jsx("ul", { children: matchingEntities.map((entity) => /* @__PURE__ */ jsxs(
|
|
140
|
+
"li",
|
|
141
|
+
{
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ jsx(EntityRefLink, { entityRef: entity }),
|
|
144
|
+
entity.metadata.description ? ` - ${entity.metadata.description}` : null
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
`${entity.kind}:${entity.metadata.namespace ?? "default"}/${entity.metadata.name}`
|
|
148
|
+
)) })
|
|
149
|
+
] }),
|
|
150
|
+
/* @__PURE__ */ jsx(ContentHeader, { title: "Estate insights" }),
|
|
151
|
+
insightError && /* @__PURE__ */ jsx(Typography, { color: "error", children: insightError }),
|
|
152
|
+
!insights && !insightError ? /* @__PURE__ */ jsx(Progress, {}) : null,
|
|
153
|
+
/* @__PURE__ */ jsxs(Grid, { container: true, spacing: 3, children: [
|
|
154
|
+
insights && /* @__PURE__ */ jsx(EstateInsightsGrid, { insights }),
|
|
155
|
+
queryEnabled && queryPermission.allowed && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(
|
|
156
|
+
InfoCard,
|
|
157
|
+
{
|
|
158
|
+
title: "Advanced query",
|
|
159
|
+
subheader: "Deterministic Graph API SELECT queries only",
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx(
|
|
162
|
+
TextField,
|
|
163
|
+
{
|
|
164
|
+
fullWidth: true,
|
|
165
|
+
multiline: true,
|
|
166
|
+
minRows: 2,
|
|
167
|
+
variant: "outlined",
|
|
168
|
+
value: sql,
|
|
169
|
+
onChange: (event) => setSql(event.target.value)
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
/* @__PURE__ */ jsx(
|
|
173
|
+
Button,
|
|
174
|
+
{
|
|
175
|
+
variant: "contained",
|
|
176
|
+
color: "primary",
|
|
177
|
+
onClick: runQuery,
|
|
178
|
+
style: { marginTop: 12 },
|
|
179
|
+
children: "Run query"
|
|
180
|
+
}
|
|
181
|
+
),
|
|
182
|
+
queryError && /* @__PURE__ */ jsx(Typography, { color: "error", children: queryError }),
|
|
183
|
+
queryResult && /* @__PURE__ */ jsx("pre", { style: { whiteSpace: "pre-wrap", fontSize: 12 }, children: JSON.stringify(queryResult, null, 2) })
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
) })
|
|
187
|
+
] })
|
|
188
|
+
] })
|
|
189
|
+
] });
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export { AnyshiftExplorerPage, EstateInsightsGrid, isDeterministicSelect, matchesCatalogEntity };
|
|
193
|
+
//# sourceMappingURL=AnyshiftExplorerPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnyshiftExplorerPage.esm.js","sources":["../../../src/components/explorer/AnyshiftExplorerPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Button, Grid, TextField, Typography } from '@material-ui/core';\nimport {\n Content,\n ContentHeader,\n Header,\n InfoCard,\n Page,\n Progress,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/frontend-plugin-api';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { anyshiftQueryPermission } from '@anyshift/backstage-plugin-anyshift-common';\nimport type { Entity } from '@backstage/catalog-model';\nimport { catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';\nimport { anyshiftApiRef } from '../../api/AnyshiftApi';\nimport type {\n DatadogSignals,\n EstateInsights,\n QueryResult,\n} from '../../api/types';\nimport {\n ImpactPresenter,\n TimelinePresenter,\n} from '../entity/SectionPresenters';\nimport { DatadogOperationsRadar } from './DatadogOperationsRadar';\n\nconst DEFAULT_QUERY =\n 'SELECT * FROM resources WHERE type = deployment LIMIT 10';\n\nexport function isDeterministicSelect(value: string): boolean {\n const sql = value.trim();\n return (\n /^SELECT\\b/i.test(sql) &&\n sql.length <= 4_096 &&\n !sql.includes(';') &&\n !sql.includes('--') &&\n !sql.includes('/*')\n );\n}\n\nexport function matchesCatalogEntity(entity: Entity, value: string): boolean {\n const query = value.trim().toLocaleLowerCase();\n if (!query) return true;\n const searchable = [\n entity.metadata.name,\n entity.metadata.title,\n entity.metadata.description,\n entity.metadata.annotations?.['anyshift.io/target'],\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : undefined,\n ];\n return searchable.some(item => item?.toLocaleLowerCase().includes(query));\n}\n\nexport const EstateInsightsGrid = ({\n insights,\n}: {\n insights: EstateInsights;\n}) => (\n <>\n {insights.sections.map(item => (\n <Grid item xs={12} md={6} key={item.id}>\n <InfoCard title={item.title}>\n {item.section.state === 'error' ? (\n <Typography color=\"error\">{item.section.message}</Typography>\n ) : item.section.state === 'empty' ||\n item.section.state === 'unsupported' ||\n item.section.data === undefined ? (\n <Typography color=\"textSecondary\">\n {item.section.message || 'No insight evidence is available.'}\n </Typography>\n ) : item.id === 'recent-change' ? (\n <TimelinePresenter\n data={item.section.data}\n fallbackLabel=\"Deployment\"\n />\n ) : (\n <ImpactPresenter data={item.section.data} />\n )}\n </InfoCard>\n </Grid>\n ))}\n </>\n);\n\nexport const AnyshiftExplorerPage = () => {\n const api = useApi(anyshiftApiRef);\n const catalogApi = useApi(catalogApiRef);\n const queryPermission = usePermission({\n permission: anyshiftQueryPermission,\n });\n const [queryEnabled, setQueryEnabled] = useState(false);\n const [insights, setInsights] = useState<EstateInsights>();\n const [insightError, setInsightError] = useState<string>();\n const [datadogSignals, setDatadogSignals] = useState<DatadogSignals>();\n const [datadogError, setDatadogError] = useState<string>();\n const [refreshingDatadog, setRefreshingDatadog] = useState(false);\n const [catalogEntities, setCatalogEntities] = useState<Entity[]>([]);\n const [catalogError, setCatalogError] = useState<string>();\n const [catalogQuery, setCatalogQuery] = useState('');\n const [sql, setSql] = useState(DEFAULT_QUERY);\n const [queryResult, setQueryResult] = useState<QueryResult>();\n const [queryError, setQueryError] = useState<string>();\n\n useEffect(() => {\n api\n .capabilities()\n .then(capabilities => setQueryEnabled(capabilities.queryEnabled))\n .catch(() => setQueryEnabled(false));\n }, [api]);\n\n useEffect(() => {\n api\n .datadogSignals()\n .then(setDatadogSignals)\n .catch(error => {\n setDatadogError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n api\n .insights()\n .then(setInsights)\n .catch(error => {\n setInsightError(error instanceof Error ? error.message : String(error));\n });\n }, [api]);\n\n useEffect(() => {\n catalogApi\n .getEntities({\n filter: [{ kind: 'Component' }, { kind: 'Resource' }],\n })\n .then(response =>\n setCatalogEntities(\n response.items.filter(\n entity => entity.metadata.annotations?.['anyshift.io/target'],\n ),\n ),\n )\n .catch(error => {\n setCatalogError(error instanceof Error ? error.message : String(error));\n });\n }, [catalogApi]);\n\n const matchingEntities = catalogEntities\n .filter(entity => matchesCatalogEntity(entity, catalogQuery))\n .slice(0, 12);\n\n const runQuery = async () => {\n if (!isDeterministicSelect(sql)) {\n setQueryError('Enter one deterministic SELECT query.');\n return;\n }\n setQueryError(undefined);\n try {\n setQueryResult(await api.query(sql.trim()));\n } catch (error) {\n setQueryError(error instanceof Error ? error.message : String(error));\n }\n };\n\n const refreshDatadog = async () => {\n setRefreshingDatadog(true);\n setDatadogError(undefined);\n try {\n setDatadogSignals(await api.datadogSignals({ refresh: true }));\n } catch (error) {\n setDatadogError(error instanceof Error ? error.message : String(error));\n } finally {\n setRefreshingDatadog(false);\n }\n };\n\n return (\n <Page themeId=\"tool\">\n <Header\n title=\"Anyshift\"\n subtitle=\"Live infrastructure context for your software catalog\"\n />\n <Content>\n {datadogSignals ? (\n <DatadogOperationsRadar\n signals={datadogSignals}\n catalogEntities={catalogEntities}\n onRefresh={refreshDatadog}\n refreshing={refreshingDatadog}\n error={datadogError}\n />\n ) : datadogError ? (\n <Typography color=\"error\">{datadogError}</Typography>\n ) : (\n <Progress />\n )}\n <ContentHeader title=\"Find a service\" />\n <InfoCard subheader=\"Anyshift-annotated Components and Resources in the Backstage catalog\">\n <TextField\n fullWidth\n variant=\"outlined\"\n label=\"Search services and resources\"\n value={catalogQuery}\n onChange={event => setCatalogQuery(event.target.value)}\n />\n {catalogError && (\n <Typography color=\"error\">{catalogError}</Typography>\n )}\n {!catalogError && matchingEntities.length === 0 ? (\n <Typography color=\"textSecondary\" style={{ marginTop: 12 }}>\n No matching Anyshift catalog entities.\n </Typography>\n ) : (\n <ul>\n {matchingEntities.map(entity => (\n <li\n key={`${entity.kind}:${\n entity.metadata.namespace ?? 'default'\n }/${entity.metadata.name}`}\n >\n <EntityRefLink entityRef={entity} />\n {entity.metadata.description\n ? ` - ${entity.metadata.description}`\n : null}\n </li>\n ))}\n </ul>\n )}\n </InfoCard>\n <ContentHeader title=\"Estate insights\" />\n {insightError && <Typography color=\"error\">{insightError}</Typography>}\n {!insights && !insightError ? <Progress /> : null}\n <Grid container spacing={3}>\n {insights && <EstateInsightsGrid insights={insights} />}\n {queryEnabled && queryPermission.allowed && (\n <Grid item xs={12}>\n <InfoCard\n title=\"Advanced query\"\n subheader=\"Deterministic Graph API SELECT queries only\"\n >\n <TextField\n fullWidth\n multiline\n minRows={2}\n variant=\"outlined\"\n value={sql}\n onChange={event => setSql(event.target.value)}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={runQuery}\n style={{ marginTop: 12 }}\n >\n Run query\n </Button>\n {queryError && (\n <Typography color=\"error\">{queryError}</Typography>\n )}\n {queryResult && (\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: 12 }}>\n {JSON.stringify(queryResult, null, 2)}\n </pre>\n )}\n </InfoCard>\n </Grid>\n )}\n </Grid>\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|