@openchoreo/backstage-plugin-openchoreo-observability 1.1.0

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.
Files changed (196) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +22 -0
  3. package/dist/api/FinOpsAgentApi.esm.js +43 -0
  4. package/dist/api/FinOpsAgentApi.esm.js.map +1 -0
  5. package/dist/api/ObservabilityApi.esm.js +568 -0
  6. package/dist/api/ObservabilityApi.esm.js.map +1 -0
  7. package/dist/api/ObserverUrlCache.esm.js +59 -0
  8. package/dist/api/ObserverUrlCache.esm.js.map +1 -0
  9. package/dist/api/RCAAgentApi.esm.js +104 -0
  10. package/dist/api/RCAAgentApi.esm.js.map +1 -0
  11. package/dist/components/Alerts/AlertRow.esm.js +203 -0
  12. package/dist/components/Alerts/AlertRow.esm.js.map +1 -0
  13. package/dist/components/Alerts/AlertsActions.esm.js +77 -0
  14. package/dist/components/Alerts/AlertsActions.esm.js.map +1 -0
  15. package/dist/components/Alerts/AlertsFilter.esm.js +95 -0
  16. package/dist/components/Alerts/AlertsFilter.esm.js.map +1 -0
  17. package/dist/components/Alerts/AlertsTable.esm.js +63 -0
  18. package/dist/components/Alerts/AlertsTable.esm.js.map +1 -0
  19. package/dist/components/Alerts/ObservabilityAlertsPage.esm.js +251 -0
  20. package/dist/components/Alerts/ObservabilityAlertsPage.esm.js.map +1 -0
  21. package/dist/components/Alerts/types.esm.js +4 -0
  22. package/dist/components/Alerts/types.esm.js.map +1 -0
  23. package/dist/components/CostAnalysis/CostAnalysisPage.esm.js +141 -0
  24. package/dist/components/CostAnalysis/CostAnalysisPage.esm.js.map +1 -0
  25. package/dist/components/CostAnalysis/CostAnalysisReport.esm.js +128 -0
  26. package/dist/components/CostAnalysis/CostAnalysisReport.esm.js.map +1 -0
  27. package/dist/components/CostAnalysis/CostAnalysisReportView.esm.js +517 -0
  28. package/dist/components/CostAnalysis/CostAnalysisReportView.esm.js.map +1 -0
  29. package/dist/components/CostAnalysis/CostAnalysisTable.esm.js +149 -0
  30. package/dist/components/CostAnalysis/CostAnalysisTable.esm.js.map +1 -0
  31. package/dist/components/CostAnalysis/FinOpsApplyButton.esm.js +112 -0
  32. package/dist/components/CostAnalysis/FinOpsApplyButton.esm.js.map +1 -0
  33. package/dist/components/CostAnalysis/index.esm.js +2 -0
  34. package/dist/components/CostAnalysis/index.esm.js.map +1 -0
  35. package/dist/components/Incidents/IncidentRow.esm.js +258 -0
  36. package/dist/components/Incidents/IncidentRow.esm.js.map +1 -0
  37. package/dist/components/Incidents/IncidentsActions.esm.js +77 -0
  38. package/dist/components/Incidents/IncidentsActions.esm.js.map +1 -0
  39. package/dist/components/Incidents/IncidentsFilter.esm.js +144 -0
  40. package/dist/components/Incidents/IncidentsFilter.esm.js.map +1 -0
  41. package/dist/components/Incidents/IncidentsTable.esm.js +68 -0
  42. package/dist/components/Incidents/IncidentsTable.esm.js.map +1 -0
  43. package/dist/components/Incidents/ObservabilityProjectIncidentsPage.esm.js +283 -0
  44. package/dist/components/Incidents/ObservabilityProjectIncidentsPage.esm.js.map +1 -0
  45. package/dist/components/Incidents/types.esm.js +8 -0
  46. package/dist/components/Incidents/types.esm.js.map +1 -0
  47. package/dist/components/Metrics/ChartTooltip.esm.js +53 -0
  48. package/dist/components/Metrics/ChartTooltip.esm.js.map +1 -0
  49. package/dist/components/Metrics/HTTPMetricsSection.esm.js +109 -0
  50. package/dist/components/Metrics/HTTPMetricsSection.esm.js.map +1 -0
  51. package/dist/components/Metrics/MetricGraphByComponent.esm.js +99 -0
  52. package/dist/components/Metrics/MetricGraphByComponent.esm.js.map +1 -0
  53. package/dist/components/Metrics/MetricsActions.esm.js +30 -0
  54. package/dist/components/Metrics/MetricsActions.esm.js.map +1 -0
  55. package/dist/components/Metrics/MetricsFilters.esm.js +49 -0
  56. package/dist/components/Metrics/MetricsFilters.esm.js.map +1 -0
  57. package/dist/components/Metrics/ObservabilityMetricsPage.esm.js +196 -0
  58. package/dist/components/Metrics/ObservabilityMetricsPage.esm.js.map +1 -0
  59. package/dist/components/Metrics/styles.esm.js +55 -0
  60. package/dist/components/Metrics/styles.esm.js.map +1 -0
  61. package/dist/components/Metrics/utils.esm.js +221 -0
  62. package/dist/components/Metrics/utils.esm.js.map +1 -0
  63. package/dist/components/RCA/RCAActions.esm.js +42 -0
  64. package/dist/components/RCA/RCAActions.esm.js.map +1 -0
  65. package/dist/components/RCA/RCAFilters.esm.js +100 -0
  66. package/dist/components/RCA/RCAFilters.esm.js.map +1 -0
  67. package/dist/components/RCA/RCAPage.esm.js +137 -0
  68. package/dist/components/RCA/RCAPage.esm.js.map +1 -0
  69. package/dist/components/RCA/RCAReport/EntityLinkContext.esm.js +9 -0
  70. package/dist/components/RCA/RCAReport/EntityLinkContext.esm.js.map +1 -0
  71. package/dist/components/RCA/RCAReport/FormattedText.esm.js +94 -0
  72. package/dist/components/RCA/RCAReport/FormattedText.esm.js.map +1 -0
  73. package/dist/components/RCA/RCAReport/RCAReportView.esm.js +308 -0
  74. package/dist/components/RCA/RCAReport/RCAReportView.esm.js.map +1 -0
  75. package/dist/components/RCA/RCAReport/sections/AssessmentSection.esm.js +113 -0
  76. package/dist/components/RCA/RCAReport/sections/AssessmentSection.esm.js.map +1 -0
  77. package/dist/components/RCA/RCAReport/sections/ChatPanelSection.esm.js +272 -0
  78. package/dist/components/RCA/RCAReport/sections/ChatPanelSection.esm.js.map +1 -0
  79. package/dist/components/RCA/RCAReport/sections/ExcludedCausesSection.esm.js +48 -0
  80. package/dist/components/RCA/RCAReport/sections/ExcludedCausesSection.esm.js.map +1 -0
  81. package/dist/components/RCA/RCAReport/sections/IncidentOverviewSection.esm.js +205 -0
  82. package/dist/components/RCA/RCAReport/sections/IncidentOverviewSection.esm.js.map +1 -0
  83. package/dist/components/RCA/RCAReport/sections/InvestigationPathSection.esm.js +121 -0
  84. package/dist/components/RCA/RCAReport/sections/InvestigationPathSection.esm.js.map +1 -0
  85. package/dist/components/RCA/RCAReport/sections/PatchTabContent.esm.js +593 -0
  86. package/dist/components/RCA/RCAReport/sections/PatchTabContent.esm.js.map +1 -0
  87. package/dist/components/RCA/RCAReport/sections/QuickFixesPanelSection.esm.js +35 -0
  88. package/dist/components/RCA/RCAReport/sections/QuickFixesPanelSection.esm.js.map +1 -0
  89. package/dist/components/RCA/RCAReport/sections/RecommendationsSection.esm.js +54 -0
  90. package/dist/components/RCA/RCAReport/sections/RecommendationsSection.esm.js.map +1 -0
  91. package/dist/components/RCA/RCAReport/sections/RootCausesSection.esm.js +526 -0
  92. package/dist/components/RCA/RCAReport/sections/RootCausesSection.esm.js.map +1 -0
  93. package/dist/components/RCA/RCAReport/sections/SystemTimelineSection.esm.js +70 -0
  94. package/dist/components/RCA/RCAReport/sections/SystemTimelineSection.esm.js.map +1 -0
  95. package/dist/components/RCA/RCAReport/sections/VisibilityImprovementsSection.esm.js +54 -0
  96. package/dist/components/RCA/RCAReport/sections/VisibilityImprovementsSection.esm.js.map +1 -0
  97. package/dist/components/RCA/RCAReport/styles.esm.js +467 -0
  98. package/dist/components/RCA/RCAReport/styles.esm.js.map +1 -0
  99. package/dist/components/RCA/RCAReport.esm.js +109 -0
  100. package/dist/components/RCA/RCAReport.esm.js.map +1 -0
  101. package/dist/components/RCA/RCATable.esm.js +140 -0
  102. package/dist/components/RCA/RCATable.esm.js.map +1 -0
  103. package/dist/components/RuntimeLogs/LogEntry.esm.js +182 -0
  104. package/dist/components/RuntimeLogs/LogEntry.esm.js.map +1 -0
  105. package/dist/components/RuntimeLogs/LogsActions.esm.js +106 -0
  106. package/dist/components/RuntimeLogs/LogsActions.esm.js.map +1 -0
  107. package/dist/components/RuntimeLogs/LogsFilter.esm.js +200 -0
  108. package/dist/components/RuntimeLogs/LogsFilter.esm.js.map +1 -0
  109. package/dist/components/RuntimeLogs/LogsTable.esm.js +91 -0
  110. package/dist/components/RuntimeLogs/LogsTable.esm.js.map +1 -0
  111. package/dist/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.esm.js +220 -0
  112. package/dist/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.esm.js.map +1 -0
  113. package/dist/components/RuntimeLogs/ObservabilityRuntimeLogsPage.esm.js +222 -0
  114. package/dist/components/RuntimeLogs/ObservabilityRuntimeLogsPage.esm.js.map +1 -0
  115. package/dist/components/RuntimeLogs/styles.esm.js +256 -0
  116. package/dist/components/RuntimeLogs/styles.esm.js.map +1 -0
  117. package/dist/components/RuntimeLogs/types.esm.js +16 -0
  118. package/dist/components/RuntimeLogs/types.esm.js.map +1 -0
  119. package/dist/components/TimeRangeFilter/TimeRangeFilter.esm.js +280 -0
  120. package/dist/components/TimeRangeFilter/TimeRangeFilter.esm.js.map +1 -0
  121. package/dist/components/Traces/ObservabilityTracesPage.esm.js +165 -0
  122. package/dist/components/Traces/ObservabilityTracesPage.esm.js.map +1 -0
  123. package/dist/components/Traces/TracesActions.esm.js +37 -0
  124. package/dist/components/Traces/TracesActions.esm.js.map +1 -0
  125. package/dist/components/Traces/TracesFilters.esm.js +121 -0
  126. package/dist/components/Traces/TracesFilters.esm.js.map +1 -0
  127. package/dist/components/Traces/TracesTable.esm.js +137 -0
  128. package/dist/components/Traces/TracesTable.esm.js.map +1 -0
  129. package/dist/components/Traces/WaterfallView.esm.js +567 -0
  130. package/dist/components/Traces/WaterfallView.esm.js.map +1 -0
  131. package/dist/components/Traces/styles.esm.js +198 -0
  132. package/dist/components/Traces/styles.esm.js.map +1 -0
  133. package/dist/components/Traces/utils.esm.js +19 -0
  134. package/dist/components/Traces/utils.esm.js.map +1 -0
  135. package/dist/hooks/useAutoSelectFirstEnvironment.esm.js +25 -0
  136. package/dist/hooks/useAutoSelectFirstEnvironment.esm.js.map +1 -0
  137. package/dist/hooks/useComponentAlerts.esm.js +80 -0
  138. package/dist/hooks/useComponentAlerts.esm.js.map +1 -0
  139. package/dist/hooks/useDataPlaneNetPolProvider.esm.js +55 -0
  140. package/dist/hooks/useDataPlaneNetPolProvider.esm.js.map +1 -0
  141. package/dist/hooks/useDebouncedSearch.esm.js +24 -0
  142. package/dist/hooks/useDebouncedSearch.esm.js.map +1 -0
  143. package/dist/hooks/useFilters.esm.js +29 -0
  144. package/dist/hooks/useFilters.esm.js.map +1 -0
  145. package/dist/hooks/useFinOpsReport.esm.js +66 -0
  146. package/dist/hooks/useFinOpsReport.esm.js.map +1 -0
  147. package/dist/hooks/useFinOpsReports.esm.js +70 -0
  148. package/dist/hooks/useFinOpsReports.esm.js.map +1 -0
  149. package/dist/hooks/useGetComponentsByProject.esm.js +57 -0
  150. package/dist/hooks/useGetComponentsByProject.esm.js.map +1 -0
  151. package/dist/hooks/useGetEnvironmentsByNamespace.esm.js +53 -0
  152. package/dist/hooks/useGetEnvironmentsByNamespace.esm.js.map +1 -0
  153. package/dist/hooks/useGetNamespaceAndProjectByEntity.esm.js +40 -0
  154. package/dist/hooks/useGetNamespaceAndProjectByEntity.esm.js.map +1 -0
  155. package/dist/hooks/useMetrics.esm.js +107 -0
  156. package/dist/hooks/useMetrics.esm.js.map +1 -0
  157. package/dist/hooks/useProjectIncidents.esm.js +111 -0
  158. package/dist/hooks/useProjectIncidents.esm.js.map +1 -0
  159. package/dist/hooks/useProjectRuntimeLogs.esm.js +185 -0
  160. package/dist/hooks/useProjectRuntimeLogs.esm.js.map +1 -0
  161. package/dist/hooks/useRCAReportByAlert.esm.js +54 -0
  162. package/dist/hooks/useRCAReportByAlert.esm.js.map +1 -0
  163. package/dist/hooks/useRCAReports.esm.js +75 -0
  164. package/dist/hooks/useRCAReports.esm.js.map +1 -0
  165. package/dist/hooks/useRuntimeLogs.esm.js +147 -0
  166. package/dist/hooks/useRuntimeLogs.esm.js.map +1 -0
  167. package/dist/hooks/useSpanDetails.esm.js +71 -0
  168. package/dist/hooks/useSpanDetails.esm.js.map +1 -0
  169. package/dist/hooks/useTraceSpans.esm.js +80 -0
  170. package/dist/hooks/useTraceSpans.esm.js.map +1 -0
  171. package/dist/hooks/useTraces.esm.js +112 -0
  172. package/dist/hooks/useTraces.esm.js.map +1 -0
  173. package/dist/hooks/useUpdateIncident.esm.js +50 -0
  174. package/dist/hooks/useUpdateIncident.esm.js.map +1 -0
  175. package/dist/hooks/useUrlFilters.esm.js +63 -0
  176. package/dist/hooks/useUrlFilters.esm.js.map +1 -0
  177. package/dist/hooks/useUrlFiltersForAlerts.esm.js +80 -0
  178. package/dist/hooks/useUrlFiltersForAlerts.esm.js.map +1 -0
  179. package/dist/hooks/useUrlFiltersForIncidents.esm.js +87 -0
  180. package/dist/hooks/useUrlFiltersForIncidents.esm.js.map +1 -0
  181. package/dist/hooks/useUrlFiltersForRuntimeLogs.esm.js +135 -0
  182. package/dist/hooks/useUrlFiltersForRuntimeLogs.esm.js.map +1 -0
  183. package/dist/index.d.ts +41 -0
  184. package/dist/index.esm.js +2 -0
  185. package/dist/index.esm.js.map +1 -0
  186. package/dist/plugin.esm.js +107 -0
  187. package/dist/plugin.esm.js.map +1 -0
  188. package/dist/routes.esm.js +8 -0
  189. package/dist/routes.esm.js.map +1 -0
  190. package/dist/types.esm.js +18 -0
  191. package/dist/types.esm.js.map +1 -0
  192. package/dist/utils/applyResourceChange.esm.js +79 -0
  193. package/dist/utils/applyResourceChange.esm.js.map +1 -0
  194. package/dist/utils/urlTimeRange.esm.js +52 -0
  195. package/dist/utils/urlTimeRange.esm.js.map +1 -0
  196. package/package.json +81 -0
@@ -0,0 +1,593 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useCallback } from 'react';
3
+ import { Box, Typography, TextField, LinearProgress, Button, Tooltip } from '@material-ui/core';
4
+ import BuildIcon from '@material-ui/icons/Build';
5
+ import CheckIcon from '@material-ui/icons/Check';
6
+ import CloseIcon from '@material-ui/icons/Close';
7
+ import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
8
+ import { useApi, fetchApiRef } from '@backstage/core-plugin-api';
9
+ import { useRcaUpdatePermission } from '@openchoreo/backstage-plugin-react';
10
+ import { useRCAReportStyles } from '../styles.esm.js';
11
+ import { FormattedText } from '../FormattedText.esm.js';
12
+ import { applyEnvChange, applyFileChange, applyJsonPointer } from '../../../../utils/applyResourceChange.esm.js';
13
+
14
+ function allActionsResolved(actions) {
15
+ return actions.length > 0 && actions.every(
16
+ ({ action }) => action.status === "applied" || action.status === "dismissed"
17
+ );
18
+ }
19
+ function buildFieldTree(fields) {
20
+ const prefixMap = /* @__PURE__ */ new Map();
21
+ const leaves = [];
22
+ for (const f of fields) {
23
+ const dot = f.label.indexOf(".");
24
+ if (dot > 0) {
25
+ const prefix = f.label.slice(0, dot);
26
+ const list = prefixMap.get(prefix) ?? [];
27
+ list.push({ ...f, label: f.label.slice(dot + 1) });
28
+ prefixMap.set(prefix, list);
29
+ } else {
30
+ leaves.push({ label: null, field: f });
31
+ }
32
+ }
33
+ const nodes = [...leaves];
34
+ for (const [prefix, children] of prefixMap) {
35
+ if (children.length === 1) {
36
+ nodes.push({
37
+ label: null,
38
+ field: { ...children[0], label: `${prefix}.${children[0].label}` }
39
+ });
40
+ } else {
41
+ nodes.push({ label: prefix, children: buildFieldTree(children) });
42
+ }
43
+ }
44
+ return nodes;
45
+ }
46
+ function extractPatchSections(rc) {
47
+ const sections = [];
48
+ let fieldIdx = 0;
49
+ const envVars = [];
50
+ const files = [];
51
+ for (const e of rc.env ?? []) {
52
+ envVars.push({ label: e.key, value: e.value, fieldIdx: fieldIdx++ });
53
+ }
54
+ for (const f of rc.files ?? []) {
55
+ files.push({
56
+ fileKey: f.key,
57
+ mountPath: f.mount_path,
58
+ content: { value: f.value, fieldIdx: fieldIdx++ }
59
+ });
60
+ }
61
+ if (envVars.length > 0 || files.length > 0) {
62
+ sections.push({
63
+ title: "Workload Overrides",
64
+ envVars: envVars.length > 0 ? envVars : void 0,
65
+ files: files.length > 0 ? files : void 0
66
+ });
67
+ }
68
+ const componentTypeFields = [];
69
+ const traitFieldsMap = /* @__PURE__ */ new Map();
70
+ for (const f of rc.fields ?? []) {
71
+ const parts = f.json_pointer.replace(/^\/spec\//, "").split("/");
72
+ const section = parts[0];
73
+ const label = parts.slice(section === "traitEnvironmentConfigs" ? 2 : 1).join(".");
74
+ if (section === "traitEnvironmentConfigs" && parts.length >= 2) {
75
+ const traitName = parts[1];
76
+ const list = traitFieldsMap.get(traitName) ?? [];
77
+ list.push({ label, value: f.value, fieldIdx: fieldIdx++ });
78
+ traitFieldsMap.set(traitName, list);
79
+ } else {
80
+ componentTypeFields.push({
81
+ label,
82
+ value: f.value,
83
+ fieldIdx: fieldIdx++
84
+ });
85
+ }
86
+ }
87
+ if (componentTypeFields.length > 0) {
88
+ sections.push({
89
+ title: "Component Overrides",
90
+ fieldTree: buildFieldTree(componentTypeFields)
91
+ });
92
+ }
93
+ for (const [traitName, traitFields] of traitFieldsMap) {
94
+ sections.push({
95
+ title: `Trait: ${traitName}`,
96
+ fieldTree: buildFieldTree(traitFields)
97
+ });
98
+ }
99
+ return sections;
100
+ }
101
+ const monoInputStyle = { fontFamily: "monospace", fontSize: "0.8rem" };
102
+ const PatchTabContent = ({
103
+ reportId,
104
+ chatContext,
105
+ revisedActions
106
+ }) => {
107
+ const classes = useRCAReportStyles();
108
+ const fetchApi = useApi(fetchApiRef);
109
+ const {
110
+ canUpdateRca,
111
+ loading: permissionLoading,
112
+ deniedTooltip
113
+ } = useRcaUpdatePermission();
114
+ const allResolved = allActionsResolved(revisedActions);
115
+ const [phase, setPhase] = useState(allResolved ? "done" : "idle");
116
+ const [actionStates, setActionStates] = useState(
117
+ () => {
118
+ if (!allResolved) return /* @__PURE__ */ new Map();
119
+ const m = /* @__PURE__ */ new Map();
120
+ for (const { index, action } of revisedActions) {
121
+ m.set(index, {
122
+ status: action.status === "dismissed" ? "dismissed" : "success"
123
+ });
124
+ }
125
+ return m;
126
+ }
127
+ );
128
+ const [error, setError] = useState("");
129
+ const [editedValues, setEditedValues] = useState(
130
+ /* @__PURE__ */ new Map()
131
+ );
132
+ const getEditedValue = (actionIdx, rcIdx, fieldIdx, original) => {
133
+ const key = `${actionIdx}-${rcIdx}-${fieldIdx}`;
134
+ return editedValues.get(key) ?? String(original);
135
+ };
136
+ const getPatchValue = (actionIdx, rcIdx, fieldIdx, original) => {
137
+ const key = `${actionIdx}-${rcIdx}-${fieldIdx}`;
138
+ const edited = editedValues.get(key);
139
+ if (edited === void 0) return original;
140
+ if (typeof original === "number") {
141
+ const n = Number(edited);
142
+ return Number.isNaN(n) ? edited : n;
143
+ }
144
+ if (typeof original === "boolean") {
145
+ return edited === "true";
146
+ }
147
+ return edited;
148
+ };
149
+ const setEditedValue = (actionIdx, rcIdx, fieldIdx, value) => {
150
+ setEditedValues((prev) => {
151
+ const next = new Map(prev);
152
+ next.set(`${actionIdx}-${rcIdx}-${fieldIdx}`, value);
153
+ return next;
154
+ });
155
+ };
156
+ const applyFixes = useCallback(
157
+ async (actions) => {
158
+ if (!chatContext.backendBaseUrl) {
159
+ setError("Backend URL is not available");
160
+ setPhase("error");
161
+ return;
162
+ }
163
+ setPhase("running");
164
+ setError("");
165
+ const initial = /* @__PURE__ */ new Map();
166
+ for (const { index } of actions) {
167
+ initial.set(index, { status: "applying" });
168
+ }
169
+ setActionStates(initial);
170
+ const successIndices = [];
171
+ const resultStates = /* @__PURE__ */ new Map();
172
+ try {
173
+ const bindingPatches = /* @__PURE__ */ new Map();
174
+ for (const { index: actionIndex, action } of actions) {
175
+ const resourceChange = action.change;
176
+ if (!resourceChange) continue;
177
+ const name = resourceChange.release_binding;
178
+ const patches = bindingPatches.get(name) ?? [];
179
+ patches.push({ actionIndex, rcIdx: 0, resourceChange });
180
+ bindingPatches.set(name, patches);
181
+ }
182
+ const failedActions = /* @__PURE__ */ new Set();
183
+ for (const [bindingName, patches] of bindingPatches) {
184
+ const bindingUrl = `${chatContext.backendBaseUrl}/release-binding?namespaceName=${encodeURIComponent(
185
+ chatContext.namespaceName
186
+ )}&bindingName=${encodeURIComponent(bindingName)}`;
187
+ const getResponse = await fetchApi.fetch(bindingUrl);
188
+ if (!getResponse.ok) {
189
+ const detail = getResponse.status === 404 ? `Release binding '${bindingName}' not found` : `Failed to get release binding: ${getResponse.statusText}`;
190
+ for (const { actionIndex } of patches) {
191
+ resultStates.set(actionIndex, {
192
+ status: "failed",
193
+ details: detail
194
+ });
195
+ failedActions.add(actionIndex);
196
+ }
197
+ continue;
198
+ }
199
+ const binding = await getResponse.json();
200
+ const updated = structuredClone(binding);
201
+ try {
202
+ for (const { actionIndex, rcIdx, resourceChange } of patches) {
203
+ let itemIdx = 0;
204
+ for (const e of resourceChange.env ?? []) {
205
+ const editedVal = getEditedValue(
206
+ actionIndex,
207
+ rcIdx,
208
+ itemIdx,
209
+ e.value
210
+ );
211
+ applyEnvChange(updated, e.key, editedVal);
212
+ itemIdx++;
213
+ }
214
+ for (const f of resourceChange.files ?? []) {
215
+ const editedValue = getEditedValue(
216
+ actionIndex,
217
+ rcIdx,
218
+ itemIdx++,
219
+ f.value
220
+ );
221
+ applyFileChange(updated, f.key, f.mount_path, editedValue);
222
+ }
223
+ for (const f of resourceChange.fields ?? []) {
224
+ const patchVal = getPatchValue(
225
+ actionIndex,
226
+ rcIdx,
227
+ itemIdx,
228
+ f.value
229
+ );
230
+ applyJsonPointer(updated, f.json_pointer, patchVal);
231
+ itemIdx++;
232
+ }
233
+ }
234
+ } catch (err) {
235
+ for (const { actionIndex } of patches) {
236
+ resultStates.set(actionIndex, {
237
+ status: "failed",
238
+ details: err instanceof Error ? err.message : "Failed to apply changes"
239
+ });
240
+ failedActions.add(actionIndex);
241
+ }
242
+ continue;
243
+ }
244
+ const putResponse = await fetchApi.fetch(bindingUrl, {
245
+ method: "PUT",
246
+ body: JSON.stringify({
247
+ metadata: updated.metadata,
248
+ spec: updated.spec
249
+ }),
250
+ headers: {
251
+ "Content-Type": "application/json"
252
+ }
253
+ });
254
+ if (!putResponse.ok) {
255
+ for (const { actionIndex } of patches) {
256
+ resultStates.set(actionIndex, {
257
+ status: "failed",
258
+ details: `Failed to update release binding: ${putResponse.statusText}`
259
+ });
260
+ failedActions.add(actionIndex);
261
+ }
262
+ }
263
+ }
264
+ for (const { index } of actions) {
265
+ if (!failedActions.has(index)) {
266
+ successIndices.push(index);
267
+ resultStates.set(index, {
268
+ status: "success",
269
+ details: "Applied successfully"
270
+ });
271
+ }
272
+ }
273
+ if (successIndices.length > 0) {
274
+ try {
275
+ await chatContext.rcaAgentApi.updateActionStatuses(
276
+ reportId,
277
+ {
278
+ namespaceName: chatContext.namespaceName,
279
+ environmentName: chatContext.environmentName
280
+ },
281
+ { appliedIndices: successIndices }
282
+ );
283
+ } catch {
284
+ }
285
+ }
286
+ setActionStates(resultStates);
287
+ setPhase(successIndices.length > 0 ? "done" : "error");
288
+ } catch (err) {
289
+ const msg = err instanceof Error ? err.message : "Failed to apply fixes";
290
+ const failed = /* @__PURE__ */ new Map();
291
+ for (const { index } of actions) {
292
+ failed.set(index, { status: "failed", details: msg });
293
+ }
294
+ setActionStates(failed);
295
+ setError(msg);
296
+ setPhase("error");
297
+ }
298
+ },
299
+ // eslint-disable-next-line react-hooks/exhaustive-deps
300
+ [chatContext, reportId, fetchApi, editedValues]
301
+ );
302
+ const handleApplySingle = useCallback(
303
+ (index, action) => {
304
+ applyFixes([{ index, action }]);
305
+ },
306
+ [applyFixes]
307
+ );
308
+ const handleDismiss = useCallback(
309
+ async (index) => {
310
+ setActionStates((prev) => {
311
+ const next = new Map(prev);
312
+ next.set(index, { status: "applying" });
313
+ return next;
314
+ });
315
+ try {
316
+ await chatContext.rcaAgentApi.updateActionStatuses(
317
+ reportId,
318
+ {
319
+ namespaceName: chatContext.namespaceName,
320
+ environmentName: chatContext.environmentName
321
+ },
322
+ { dismissedIndices: [index] }
323
+ );
324
+ setActionStates((prev) => {
325
+ const next = new Map(prev);
326
+ next.set(index, { status: "dismissed" });
327
+ return next;
328
+ });
329
+ } catch {
330
+ setActionStates((prev) => {
331
+ const next = new Map(prev);
332
+ next.set(index, { status: "failed", details: "Failed to dismiss" });
333
+ return next;
334
+ });
335
+ }
336
+ },
337
+ [chatContext, reportId]
338
+ );
339
+ const renderActionButtons = (index, action) => {
340
+ const localStatus = actionStates.get(index)?.status;
341
+ if (localStatus === "applying") {
342
+ return /* @__PURE__ */ jsx(Button, { variant: "outlined", size: "small", disabled: true, children: "Applying..." });
343
+ }
344
+ if (localStatus === "success" || action.status === "applied") {
345
+ return /* @__PURE__ */ jsx(
346
+ Button,
347
+ {
348
+ variant: "outlined",
349
+ size: "small",
350
+ disabled: true,
351
+ startIcon: /* @__PURE__ */ jsx(CheckIcon, {}),
352
+ children: "Applied"
353
+ }
354
+ );
355
+ }
356
+ if (localStatus === "dismissed" || action.status === "dismissed") {
357
+ return /* @__PURE__ */ jsx(Button, { variant: "outlined", size: "small", disabled: true, children: "Dismissed" });
358
+ }
359
+ if (localStatus === "failed") {
360
+ return /* @__PURE__ */ jsx(
361
+ Button,
362
+ {
363
+ variant: "outlined",
364
+ color: "secondary",
365
+ size: "small",
366
+ startIcon: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}),
367
+ disabled: true,
368
+ children: "Failed"
369
+ }
370
+ );
371
+ }
372
+ const busy = phase === "running";
373
+ const disableActions = busy || permissionLoading || !canUpdateRca;
374
+ return /* @__PURE__ */ jsxs(Box, { display: "flex", style: { gap: 8 }, children: [
375
+ /* @__PURE__ */ jsx(Tooltip, { title: deniedTooltip, children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
376
+ Button,
377
+ {
378
+ variant: "outlined",
379
+ size: "small",
380
+ startIcon: /* @__PURE__ */ jsx(CloseIcon, {}),
381
+ onClick: () => handleDismiss(index),
382
+ disabled: disableActions,
383
+ children: "Dismiss"
384
+ }
385
+ ) }) }),
386
+ /* @__PURE__ */ jsx(Tooltip, { title: deniedTooltip, children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
387
+ Button,
388
+ {
389
+ variant: "outlined",
390
+ color: "primary",
391
+ size: "small",
392
+ startIcon: /* @__PURE__ */ jsx(BuildIcon, {}),
393
+ onClick: () => handleApplySingle(index, action),
394
+ disabled: disableActions,
395
+ children: "Apply Fix"
396
+ }
397
+ ) }) })
398
+ ] });
399
+ };
400
+ if (revisedActions.length === 0) {
401
+ return /* @__PURE__ */ jsx(Box, { padding: 2, textAlign: "center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "No revised actions available. The remediation agent has not yet proposed any concrete fixes for this report." }) });
402
+ }
403
+ const isRunning = phase === "running";
404
+ const renderFieldNodes = (nodes, actionIdx, disabled, depth = 0) => nodes.map((node, nIdx) => {
405
+ if (node.field) {
406
+ const f = node.field;
407
+ return /* @__PURE__ */ jsx(
408
+ TextField,
409
+ {
410
+ fullWidth: true,
411
+ variant: "outlined",
412
+ size: "small",
413
+ label: f.label,
414
+ value: getEditedValue(actionIdx, 0, f.fieldIdx, f.value),
415
+ onChange: (e) => setEditedValue(actionIdx, 0, f.fieldIdx, e.target.value),
416
+ disabled,
417
+ InputProps: { style: monoInputStyle },
418
+ InputLabelProps: { shrink: true }
419
+ },
420
+ `${actionIdx}-field-${f.fieldIdx}`
421
+ );
422
+ }
423
+ return /* @__PURE__ */ jsxs(
424
+ Box,
425
+ {
426
+ display: "flex",
427
+ flexDirection: "column",
428
+ style: { gap: 10 },
429
+ children: [
430
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: node.label }),
431
+ node.children && renderFieldNodes(node.children, actionIdx, disabled, depth + 1)
432
+ ]
433
+ },
434
+ `${actionIdx}-grp-${depth}-${nIdx}`
435
+ );
436
+ });
437
+ return /* @__PURE__ */ jsxs(Box, { children: [
438
+ revisedActions.map(({ index, action }) => {
439
+ const rc = action.change;
440
+ const sections = rc ? extractPatchSections(rc) : [];
441
+ const state = actionStates.get(index)?.status;
442
+ const disabled = isRunning || action.status === "applied" || action.status === "dismissed" || state === "success" || state === "dismissed";
443
+ return /* @__PURE__ */ jsxs(Box, { className: classes.patchActionCard, children: [
444
+ rc && /* @__PURE__ */ jsx(Typography, { className: classes.patchBindingName, children: rc.release_binding }),
445
+ /* @__PURE__ */ jsx(
446
+ Typography,
447
+ {
448
+ component: "div",
449
+ className: classes.patchActionDescription,
450
+ children: /* @__PURE__ */ jsx(FormattedText, { text: action.description, disableMarkdown: true })
451
+ }
452
+ ),
453
+ sections.length > 0 && /* @__PURE__ */ jsx(Box, { display: "flex", flexDirection: "column", style: { gap: 16 }, children: sections.map((section, sIdx) => /* @__PURE__ */ jsxs(
454
+ Box,
455
+ {
456
+ display: "flex",
457
+ flexDirection: "column",
458
+ style: { gap: 10 },
459
+ children: [
460
+ /* @__PURE__ */ jsx(
461
+ Typography,
462
+ {
463
+ variant: "caption",
464
+ style: {
465
+ fontSize: "0.65rem",
466
+ fontWeight: 600,
467
+ textTransform: "uppercase",
468
+ letterSpacing: "0.5px"
469
+ },
470
+ color: "textSecondary",
471
+ children: section.title
472
+ }
473
+ ),
474
+ section.envVars && /* @__PURE__ */ jsxs(
475
+ Box,
476
+ {
477
+ display: "flex",
478
+ flexDirection: "column",
479
+ style: { gap: 8 },
480
+ children: [
481
+ /* @__PURE__ */ jsx(
482
+ Typography,
483
+ {
484
+ variant: "caption",
485
+ style: { fontSize: "0.6rem" },
486
+ color: "textSecondary",
487
+ children: "Environment Variables"
488
+ }
489
+ ),
490
+ section.envVars.map((ev) => /* @__PURE__ */ jsx(
491
+ TextField,
492
+ {
493
+ fullWidth: true,
494
+ variant: "outlined",
495
+ size: "small",
496
+ label: ev.label,
497
+ value: getEditedValue(
498
+ index,
499
+ 0,
500
+ ev.fieldIdx,
501
+ ev.value
502
+ ),
503
+ onChange: (e) => setEditedValue(
504
+ index,
505
+ 0,
506
+ ev.fieldIdx,
507
+ e.target.value
508
+ ),
509
+ disabled,
510
+ InputProps: { style: monoInputStyle },
511
+ InputLabelProps: { shrink: true }
512
+ },
513
+ `${index}-env-${ev.fieldIdx}`
514
+ ))
515
+ ]
516
+ }
517
+ ),
518
+ section.files && /* @__PURE__ */ jsxs(
519
+ Box,
520
+ {
521
+ display: "flex",
522
+ flexDirection: "column",
523
+ style: { gap: 8 },
524
+ children: [
525
+ /* @__PURE__ */ jsx(
526
+ Typography,
527
+ {
528
+ variant: "caption",
529
+ style: { fontSize: "0.6rem" },
530
+ color: "textSecondary",
531
+ children: "Files"
532
+ }
533
+ ),
534
+ section.files.map((file) => /* @__PURE__ */ jsx(
535
+ TextField,
536
+ {
537
+ fullWidth: true,
538
+ variant: "outlined",
539
+ size: "small",
540
+ label: `${file.mountPath.replace(/\/?$/, "/")}${file.fileKey}`,
541
+ value: getEditedValue(
542
+ index,
543
+ 0,
544
+ file.content.fieldIdx,
545
+ file.content.value
546
+ ),
547
+ onChange: (e) => setEditedValue(
548
+ index,
549
+ 0,
550
+ file.content.fieldIdx,
551
+ e.target.value
552
+ ),
553
+ disabled,
554
+ multiline: true,
555
+ minRows: 3,
556
+ maxRows: 12,
557
+ InputProps: { style: monoInputStyle },
558
+ InputLabelProps: {
559
+ shrink: true,
560
+ style: {
561
+ maxWidth: "100%",
562
+ overflow: "hidden",
563
+ textOverflow: "ellipsis",
564
+ whiteSpace: "nowrap"
565
+ }
566
+ }
567
+ },
568
+ `${index}-file-${file.content.fieldIdx}`
569
+ ))
570
+ ]
571
+ }
572
+ ),
573
+ section.fieldTree && renderFieldNodes(section.fieldTree, index, disabled)
574
+ ]
575
+ },
576
+ `${index}-s-${sIdx}`
577
+ )) }),
578
+ actionStates.get(index)?.status === "applying" && /* @__PURE__ */ jsx(LinearProgress, { style: { borderRadius: 2 } }),
579
+ /* @__PURE__ */ jsxs(Box, { className: classes.patchActionFooter, children: [
580
+ /* @__PURE__ */ jsx(Box, {}),
581
+ renderActionButtons(index, action)
582
+ ] })
583
+ ] }, index);
584
+ }),
585
+ phase === "error" && /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mt: 1, p: 1, style: { gap: 8 }, children: [
586
+ /* @__PURE__ */ jsx(ErrorOutlineIcon, { color: "error", fontSize: "small" }),
587
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "error", children: error })
588
+ ] })
589
+ ] });
590
+ };
591
+
592
+ export { PatchTabContent, allActionsResolved };
593
+ //# sourceMappingURL=PatchTabContent.esm.js.map