@terasky/backstage-plugin-vcf-automation 1.3.0 → 1.3.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.
@@ -1,12 +1,17 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { useMemo } from 'react';
3
- import { useEntity } from '@backstage/plugin-catalog-react';
2
+ import { useState, useMemo, useCallback } from 'react';
3
+ import { useEntity, catalogApiRef } from '@backstage/plugin-catalog-react';
4
4
  import { useApi } from '@backstage/core-plugin-api';
5
+ import { usePermission } from '@backstage/plugin-permission-react';
5
6
  import { vcfAutomationApiRef } from '../api/VcfAutomationClient.esm.js';
7
+ import { supervisorResourceEditPermission } from '@terasky/backstage-plugin-vcf-automation-common';
8
+ import Editor from '@monaco-editor/react';
6
9
  import { InfoCard, Progress, ResponseErrorPanel, StructuredMetadataTable, CodeSnippet, StatusPending, StatusError, StatusOK } from '@backstage/core-components';
7
- import { Typography, Grid, Box, Chip, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core';
10
+ import { Typography, Grid, Box, Chip, Button, Accordion, AccordionSummary, AccordionDetails, Dialog, DialogTitle, DialogContent, DialogActions, Snackbar } from '@material-ui/core';
11
+ import { Alert } from '@material-ui/lab';
8
12
  import { makeStyles } from '@material-ui/core/styles';
9
13
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
14
+ import EditIcon from '@material-ui/icons/Edit';
10
15
  import yaml__default from 'js-yaml';
11
16
  import useAsync from 'react-use/lib/useAsync';
12
17
  import { VCFAutomationVMPowerManagement } from './VCFAutomationVMPowerManagement.esm.js';
@@ -30,12 +35,62 @@ const useStyles = makeStyles((theme) => ({
30
35
  dependencyChip: {
31
36
  margin: theme.spacing(0.25),
32
37
  cursor: "pointer"
38
+ },
39
+ editButton: {
40
+ marginTop: theme.spacing(1)
41
+ },
42
+ monacoEditor: {
43
+ flex: 1,
44
+ minHeight: "500px",
45
+ border: `1px solid ${theme.palette.divider}`,
46
+ borderRadius: theme.shape.borderRadius
47
+ },
48
+ validationStatus: {
49
+ padding: theme.spacing(1),
50
+ borderTop: `1px solid ${theme.palette.divider}`,
51
+ backgroundColor: theme.palette.background.paper,
52
+ flexShrink: 0
53
+ },
54
+ dialogContent: {
55
+ padding: theme.spacing(2),
56
+ height: "100%",
57
+ display: "flex",
58
+ flexDirection: "column",
59
+ overflow: "hidden"
60
+ },
61
+ editorContainer: {
62
+ flex: 1,
63
+ display: "flex",
64
+ flexDirection: "column",
65
+ minHeight: 0,
66
+ overflow: "hidden"
67
+ },
68
+ yamlValidationError: {
69
+ color: theme.palette.error.main,
70
+ marginTop: theme.spacing(1),
71
+ fontSize: "0.875rem"
33
72
  }
34
73
  }));
35
74
  const VCFAutomationCCIResourceOverview = () => {
36
75
  const classes = useStyles();
37
76
  const { entity } = useEntity();
38
77
  const api = useApi(vcfAutomationApiRef);
78
+ const catalogApi = useApi(catalogApiRef);
79
+ const { allowed: canEditResource } = usePermission({
80
+ permission: supervisorResourceEditPermission
81
+ });
82
+ const [editModalOpen, setEditModalOpen] = useState(false);
83
+ const [editingYaml, setEditingYaml] = useState("");
84
+ const [originalManifest, setOriginalManifest] = useState(null);
85
+ const [isLoadingManifest, setIsLoadingManifest] = useState(false);
86
+ const [isSaving, setIsSaving] = useState(false);
87
+ const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
88
+ const [yamlValidationError, setYamlValidationError] = useState("");
89
+ const [snackbar, setSnackbar] = useState({
90
+ open: false,
91
+ message: "",
92
+ severity: "success"
93
+ });
39
94
  const deploymentId = entity.spec?.system;
40
95
  const resourceId = entity.metadata.name;
41
96
  const instanceName = entity.metadata.annotations?.["terasky.backstage.io/vcf-automation-instance"];
@@ -120,21 +175,154 @@ const VCFAutomationCCIResourceOverview = () => {
120
175
  const objectData = annotationData.objectData || apiResourceData?.properties?.object;
121
176
  const resourceContext = annotationData.resourceContext || apiResourceData?.properties?.context;
122
177
  const resourceKind = manifest?.kind || objectData?.kind;
123
- const vmName = manifest?.metadata?.name || objectData?.metadata?.name;
178
+ const resourceName = manifest?.metadata?.name || objectData?.metadata?.name;
124
179
  const namespaceName = manifest?.metadata?.namespace || objectData?.metadata?.namespace;
125
- const namespaceUrnId = useMemo(() => {
126
- if (!isStandalone || !namespaceName) return void 0;
127
- const contextData = typeof resourceContext === "string" ? JSON.parse(resourceContext || "{}") : resourceContext;
128
- const urnId = contextData?.namespaceUrnId || namespaceName;
129
- console.log("Debug - Standalone VM URN ID resolution:", {
130
- namespaceName,
131
- resourceContext,
132
- contextData,
133
- urnId,
134
- isStandalone
135
- });
136
- return urnId;
137
- }, [isStandalone, namespaceName, resourceContext]);
180
+ const apiVersion = manifest?.apiVersion || objectData?.apiVersion;
181
+ const vmName = resourceName;
182
+ const extractNamespaceUrnId = useCallback((endpoint) => {
183
+ const match = endpoint.match(/\/namespaces\/(urn:vcloud:namespace:[^\/]+)/);
184
+ return match ? match[1] : void 0;
185
+ }, []);
186
+ const findCCINamespaceParent = useCallback(async (currentEntity, depth = 0) => {
187
+ if (depth >= 3) return void 0;
188
+ if (currentEntity.spec?.type === "CCI.Supervisor.Namespace") {
189
+ const endpoint = currentEntity.metadata?.annotations?.["terasky.backstage.io/vcf-automation-cci-namespace-endpoint"];
190
+ if (endpoint) {
191
+ return extractNamespaceUrnId(endpoint);
192
+ }
193
+ }
194
+ const parentRef = currentEntity.spec?.subcomponentOf;
195
+ if (!parentRef) return void 0;
196
+ try {
197
+ const parentEntity = await catalogApi.getEntityByRef(parentRef);
198
+ if (parentEntity) {
199
+ return await findCCINamespaceParent(parentEntity, depth + 1);
200
+ }
201
+ } catch (error2) {
202
+ console.warn("Failed to fetch parent entity:", parentRef, error2);
203
+ }
204
+ return void 0;
205
+ }, [catalogApi, extractNamespaceUrnId]);
206
+ const { value: namespaceUrnId } = useAsync(async () => {
207
+ if (!namespaceName) return void 0;
208
+ if (isStandalone) {
209
+ let contextData = null;
210
+ try {
211
+ contextData = typeof resourceContext === "string" ? JSON.parse(resourceContext || "{}") : resourceContext;
212
+ } catch (error2) {
213
+ console.log("Debug - Resource context is not JSON, treating as string:", resourceContext);
214
+ contextData = null;
215
+ }
216
+ const urnId = contextData?.namespaceUrnId || namespaceName;
217
+ console.log("Debug - Standalone CCI Resource URN ID resolution:", {
218
+ namespaceName,
219
+ resourceContext,
220
+ contextData,
221
+ urnId
222
+ });
223
+ return urnId;
224
+ } else {
225
+ console.log("Debug - Looking for CCI Supervisor Namespace parent for deployment-managed resource");
226
+ const urnId = await findCCINamespaceParent(entity);
227
+ console.log("Debug - Deployment-managed CCI Resource URN ID resolution:", {
228
+ namespaceName,
229
+ urnId,
230
+ entityRef: entity.metadata.name
231
+ });
232
+ return urnId || namespaceName;
233
+ }
234
+ }, [namespaceName, resourceContext, isStandalone, entity, findCCINamespaceParent]);
235
+ const handleEditResource = useCallback(async () => {
236
+ if (!canEditResource || !namespaceName || !resourceName || !namespaceUrnId || !apiVersion || !resourceKind) {
237
+ return;
238
+ }
239
+ setIsLoadingManifest(true);
240
+ setEditModalOpen(true);
241
+ try {
242
+ const manifestResponse = await api.getSupervisorResourceManifest(
243
+ namespaceUrnId,
244
+ namespaceName,
245
+ resourceName,
246
+ apiVersion,
247
+ resourceKind,
248
+ instanceName
249
+ );
250
+ setOriginalManifest(manifestResponse);
251
+ const yamlContent = yaml__default.dump(manifestResponse, {
252
+ indent: 2,
253
+ lineWidth: -1,
254
+ noRefs: true,
255
+ sortKeys: false
256
+ });
257
+ setEditingYaml(yamlContent);
258
+ setYamlValidationError("");
259
+ } catch (error2) {
260
+ setSnackbar({
261
+ open: true,
262
+ message: `Failed to fetch resource manifest: ${error2 instanceof Error ? error2.message : "Unknown error"}`,
263
+ severity: "error"
264
+ });
265
+ setEditModalOpen(false);
266
+ } finally {
267
+ setIsLoadingManifest(false);
268
+ }
269
+ }, [canEditResource, namespaceName, resourceName, namespaceUrnId, apiVersion, resourceKind, instanceName, api]);
270
+ const handleSaveResource = useCallback(async () => {
271
+ if (!originalManifest || !namespaceName || !resourceName || !namespaceUrnId || !apiVersion || !resourceKind) {
272
+ return;
273
+ }
274
+ setIsSaving(true);
275
+ setConfirmDialogOpen(false);
276
+ try {
277
+ const updatedManifest = yaml__default.load(editingYaml);
278
+ await api.updateSupervisorResourceManifest(
279
+ namespaceUrnId,
280
+ namespaceName,
281
+ resourceName,
282
+ apiVersion,
283
+ resourceKind,
284
+ updatedManifest,
285
+ instanceName
286
+ );
287
+ setSnackbar({
288
+ open: true,
289
+ message: "Resource manifest updated successfully",
290
+ severity: "success"
291
+ });
292
+ setEditModalOpen(false);
293
+ setTimeout(() => window.location.reload(), 1e3);
294
+ } catch (error2) {
295
+ setSnackbar({
296
+ open: true,
297
+ message: `Failed to update resource manifest: ${error2 instanceof Error ? error2.message : "Unknown error"}`,
298
+ severity: "error"
299
+ });
300
+ } finally {
301
+ setIsSaving(false);
302
+ }
303
+ }, [originalManifest, namespaceName, resourceName, namespaceUrnId, apiVersion, resourceKind, editingYaml, instanceName, api]);
304
+ const handleCloseSnackbar = useCallback(() => {
305
+ setSnackbar((prev) => ({ ...prev, open: false }));
306
+ }, []);
307
+ const validateYaml = useCallback((yamlString) => {
308
+ try {
309
+ yaml__default.load(yamlString);
310
+ setYamlValidationError("");
311
+ return true;
312
+ } catch (error2) {
313
+ const errorMessage = error2 instanceof Error ? error2.message : "Invalid YAML syntax";
314
+ setYamlValidationError(errorMessage);
315
+ return false;
316
+ }
317
+ }, []);
318
+ const handleYamlChange = useCallback((value) => {
319
+ setEditingYaml(value);
320
+ if (value.trim()) {
321
+ validateYaml(value);
322
+ } else {
323
+ setYamlValidationError("");
324
+ }
325
+ }, [validateYaml]);
138
326
  if (loading) {
139
327
  return /* @__PURE__ */ jsx(InfoCard, { title: "CCI Supervisor Resource", children: /* @__PURE__ */ jsx(Progress, {}) });
140
328
  }
@@ -208,133 +396,269 @@ const VCFAutomationCCIResourceOverview = () => {
208
396
  return Object.keys(statusInfo).length > 0 ? statusInfo : null;
209
397
  };
210
398
  const objectStatus = getObjectStatus();
211
- return /* @__PURE__ */ jsx(InfoCard, { title: "CCI Supervisor Resource Overview", children: /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 3, children: [
212
- isStandalone && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(
213
- Chip,
214
- {
215
- label: "Standalone Resource",
216
- color: "secondary",
217
- variant: "outlined",
218
- size: "small"
219
- }
220
- ) }) }),
221
- /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
222
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Basic Information" }),
223
- /* @__PURE__ */ jsx(StructuredMetadataTable, { metadata: basicInfo })
224
- ] }),
225
- vmOrganizationType === "all-apps" && resourceKind === "VirtualMachine" && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
226
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Power Management" }),
227
- /* @__PURE__ */ jsx(
228
- VCFAutomationVMPowerManagement,
229
- {
230
- entity,
231
- resourceId,
232
- instanceName,
233
- isStandalone,
234
- vmName: isStandalone ? vmName : void 0,
235
- namespaceName: isStandalone ? namespaceName : void 0,
236
- namespaceUrnId: isStandalone ? namespaceUrnId : void 0
237
- }
238
- )
239
- ] }),
240
- entity.spec?.dependsOn && Array.isArray(entity.spec.dependsOn) && entity.spec.dependsOn.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
241
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Dependencies" }),
242
- /* @__PURE__ */ jsx(Box, { children: entity.spec.dependsOn.filter((dep) => typeof dep === "string").map((dep, index) => /* @__PURE__ */ jsx(
399
+ return /* @__PURE__ */ jsxs(InfoCard, { title: "CCI Supervisor Resource Overview", children: [
400
+ /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 3, children: [
401
+ isStandalone && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(
243
402
  Chip,
244
403
  {
245
- label: dep,
246
- size: "small",
247
- className: classes.dependencyChip,
248
- color: "primary",
249
- variant: "outlined"
250
- },
251
- index
252
- )) })
253
- ] }),
254
- resourceData.wait?.conditions && resourceData.wait.conditions.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
255
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Wait Conditions" }),
256
- /* @__PURE__ */ jsx(Box, { children: resourceData.wait.conditions.map((condition, index) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mb: 1, children: [
257
- renderStatusIcon(condition.status),
404
+ label: "Standalone Resource",
405
+ color: "secondary",
406
+ variant: "outlined",
407
+ size: "small"
408
+ }
409
+ ) }) }),
410
+ /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
411
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Basic Information" }),
412
+ /* @__PURE__ */ jsx(StructuredMetadataTable, { metadata: basicInfo })
413
+ ] }),
414
+ vmOrganizationType === "all-apps" && resourceKind === "VirtualMachine" && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
415
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Power Management" }),
258
416
  /* @__PURE__ */ jsx(
259
- Chip,
417
+ VCFAutomationVMPowerManagement,
260
418
  {
261
- label: `${condition.type}: ${condition.status}`,
262
- size: "small",
263
- className: classes.conditionChip,
264
- color: condition.status === "True" ? "primary" : "default"
419
+ entity,
420
+ resourceId,
421
+ instanceName,
422
+ isStandalone,
423
+ vmName: isStandalone ? vmName : void 0,
424
+ namespaceName: isStandalone ? namespaceName : void 0,
425
+ namespaceUrnId: isStandalone ? namespaceUrnId : void 0
265
426
  }
266
427
  )
267
- ] }, index)) })
268
- ] }),
269
- objectData?.status?.conditions && objectData.status.conditions.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
270
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Conditions" }),
271
- /* @__PURE__ */ jsx(Box, { children: objectData.status.conditions.map((condition, index) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mb: 1, children: [
272
- renderStatusIcon(condition.status),
428
+ ] }),
429
+ canEditResource && vmOrganizationType === "all-apps" && resourceKind === "VirtualMachine" && resourceName && namespaceName && namespaceUrnId && apiVersion && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Box, { mt: vmOrganizationType === "all-apps" ? 0 : 2, children: [
430
+ vmOrganizationType !== "all-apps" && /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Management" }),
273
431
  /* @__PURE__ */ jsx(
432
+ Button,
433
+ {
434
+ variant: "outlined",
435
+ color: "primary",
436
+ startIcon: /* @__PURE__ */ jsx(EditIcon, {}),
437
+ onClick: handleEditResource,
438
+ className: classes.editButton,
439
+ disabled: isLoadingManifest,
440
+ children: "Edit Resource Manifest"
441
+ }
442
+ )
443
+ ] }) }),
444
+ canEditResource && (resourceKind !== "VirtualMachine" || vmOrganizationType !== "all-apps") && resourceName && namespaceName && namespaceUrnId && apiVersion && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
445
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Management" }),
446
+ /* @__PURE__ */ jsx(
447
+ Button,
448
+ {
449
+ variant: "outlined",
450
+ color: "primary",
451
+ startIcon: /* @__PURE__ */ jsx(EditIcon, {}),
452
+ onClick: handleEditResource,
453
+ className: classes.editButton,
454
+ disabled: isLoadingManifest,
455
+ children: "Edit Resource Manifest"
456
+ }
457
+ )
458
+ ] }),
459
+ entity.spec?.dependsOn && Array.isArray(entity.spec.dependsOn) && entity.spec.dependsOn.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
460
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Dependencies" }),
461
+ /* @__PURE__ */ jsx(Box, { children: entity.spec.dependsOn.filter((dep) => typeof dep === "string").map((dep, index) => /* @__PURE__ */ jsx(
274
462
  Chip,
275
463
  {
276
- label: `${condition.type}: ${condition.status}`,
464
+ label: dep,
277
465
  size: "small",
278
- className: classes.conditionChip,
279
- color: condition.status === "True" ? "primary" : "default"
466
+ className: classes.dependencyChip,
467
+ color: "primary",
468
+ variant: "outlined"
469
+ },
470
+ index
471
+ )) })
472
+ ] }),
473
+ resourceData.wait?.conditions && resourceData.wait.conditions.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
474
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Wait Conditions" }),
475
+ /* @__PURE__ */ jsx(Box, { children: resourceData.wait.conditions.map((condition, index) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mb: 1, children: [
476
+ renderStatusIcon(condition.status),
477
+ /* @__PURE__ */ jsx(
478
+ Chip,
479
+ {
480
+ label: `${condition.type}: ${condition.status}`,
481
+ size: "small",
482
+ className: classes.conditionChip,
483
+ color: condition.status === "True" ? "primary" : "default"
484
+ }
485
+ )
486
+ ] }, index)) })
487
+ ] }),
488
+ objectData?.status?.conditions && objectData.status.conditions.length > 0 && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
489
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Conditions" }),
490
+ /* @__PURE__ */ jsx(Box, { children: objectData.status.conditions.map((condition, index) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", mb: 1, children: [
491
+ renderStatusIcon(condition.status),
492
+ /* @__PURE__ */ jsx(
493
+ Chip,
494
+ {
495
+ label: `${condition.type}: ${condition.status}`,
496
+ size: "small",
497
+ className: classes.conditionChip,
498
+ color: condition.status === "True" ? "primary" : "default"
499
+ }
500
+ ),
501
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", style: { marginLeft: 8 }, children: condition.lastTransitionTime })
502
+ ] }, index)) })
503
+ ] }),
504
+ objectStatus && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
505
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Status" }),
506
+ /* @__PURE__ */ jsx(StructuredMetadataTable, { metadata: objectStatus })
507
+ ] }),
508
+ manifest && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Accordion, { className: classes.yamlContainer, children: [
509
+ /* @__PURE__ */ jsx(
510
+ AccordionSummary,
511
+ {
512
+ expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}),
513
+ "aria-controls": "manifest-content",
514
+ id: "manifest-header",
515
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Resource Manifest" })
280
516
  }
281
517
  ),
282
- /* @__PURE__ */ jsx(Typography, { variant: "caption", style: { marginLeft: 8 }, children: condition.lastTransitionTime })
283
- ] }, index)) })
284
- ] }),
285
- objectStatus && /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
286
- /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.sectionTitle, children: "Resource Status" }),
287
- /* @__PURE__ */ jsx(StructuredMetadataTable, { metadata: objectStatus })
288
- ] }),
289
- manifest && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Accordion, { className: classes.yamlContainer, children: [
290
- /* @__PURE__ */ jsx(
291
- AccordionSummary,
292
- {
293
- expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}),
294
- "aria-controls": "manifest-content",
295
- id: "manifest-header",
296
- children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Resource Manifest" })
297
- }
298
- ),
299
- /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
300
- CodeSnippet,
301
- {
302
- text: formatYaml(manifest),
303
- language: "yaml",
304
- showLineNumbers: true,
305
- customStyle: {
306
- fontSize: "12px",
307
- maxHeight: "500px",
308
- overflow: "auto"
518
+ /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
519
+ CodeSnippet,
520
+ {
521
+ text: formatYaml(manifest),
522
+ language: "yaml",
523
+ showLineNumbers: true,
524
+ customStyle: {
525
+ fontSize: "12px",
526
+ maxHeight: "500px",
527
+ overflow: "auto"
528
+ }
309
529
  }
310
- }
311
- ) }) })
312
- ] }) }),
313
- objectData && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Accordion, { className: classes.yamlContainer, children: [
314
- /* @__PURE__ */ jsx(
315
- AccordionSummary,
316
- {
317
- expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}),
318
- "aria-controls": "object-content",
319
- id: "object-header",
320
- children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Kubernetes Object" })
321
- }
322
- ),
323
- /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
324
- CodeSnippet,
325
- {
326
- text: formatYaml(objectData),
327
- language: "yaml",
328
- showLineNumbers: true,
329
- customStyle: {
330
- fontSize: "12px",
331
- maxHeight: "500px",
332
- overflow: "auto"
530
+ ) }) })
531
+ ] }) }),
532
+ objectData && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Accordion, { className: classes.yamlContainer, children: [
533
+ /* @__PURE__ */ jsx(
534
+ AccordionSummary,
535
+ {
536
+ expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}),
537
+ "aria-controls": "object-content",
538
+ id: "object-header",
539
+ children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Kubernetes Object" })
333
540
  }
334
- }
335
- ) }) })
336
- ] }) })
337
- ] }) });
541
+ ),
542
+ /* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(
543
+ CodeSnippet,
544
+ {
545
+ text: formatYaml(objectData),
546
+ language: "yaml",
547
+ showLineNumbers: true,
548
+ customStyle: {
549
+ fontSize: "12px",
550
+ maxHeight: "500px",
551
+ overflow: "auto"
552
+ }
553
+ }
554
+ ) }) })
555
+ ] }) })
556
+ ] }),
557
+ /* @__PURE__ */ jsxs(
558
+ Dialog,
559
+ {
560
+ open: editModalOpen,
561
+ onClose: () => setEditModalOpen(false),
562
+ maxWidth: "xl",
563
+ fullWidth: true,
564
+ PaperProps: {
565
+ style: {
566
+ height: "90vh",
567
+ maxHeight: "90vh"
568
+ }
569
+ },
570
+ children: [
571
+ /* @__PURE__ */ jsxs(DialogTitle, { children: [
572
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Edit Resource Manifest" }),
573
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "textSecondary", children: [
574
+ resourceName,
575
+ " (",
576
+ resourceKind,
577
+ ")"
578
+ ] })
579
+ ] }),
580
+ /* @__PURE__ */ jsx(DialogContent, { className: classes.dialogContent, dividers: true, children: isLoadingManifest ? /* @__PURE__ */ jsx(Box, { display: "flex", justifyContent: "center", alignItems: "center", flex: 1, children: /* @__PURE__ */ jsx(Progress, {}) }) : /* @__PURE__ */ jsxs(Box, { className: classes.editorContainer, children: [
581
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", gutterBottom: true, children: "YAML Editor" }),
582
+ /* @__PURE__ */ jsx(Box, { className: classes.monacoEditor, children: /* @__PURE__ */ jsx(
583
+ Editor,
584
+ {
585
+ height: "100%",
586
+ defaultLanguage: "yaml",
587
+ value: editingYaml,
588
+ onChange: (value) => handleYamlChange(value || ""),
589
+ theme: "vs-dark",
590
+ options: {
591
+ minimap: { enabled: false },
592
+ scrollBeyondLastLine: false,
593
+ fontSize: 14,
594
+ lineNumbers: "on",
595
+ wordWrap: "off",
596
+ automaticLayout: true,
597
+ tabSize: 2,
598
+ insertSpaces: true,
599
+ folding: true,
600
+ renderWhitespace: "selection"
601
+ }
602
+ }
603
+ ) }),
604
+ /* @__PURE__ */ jsx(Box, { className: classes.validationStatus, children: yamlValidationError ? /* @__PURE__ */ jsxs(Typography, { className: classes.yamlValidationError, children: [
605
+ "\u26A0\uFE0F YAML Validation Error: ",
606
+ yamlValidationError
607
+ ] }) : editingYaml.trim() ? /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "\u2705 YAML syntax is valid" }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Enter YAML content above" }) })
608
+ ] }) }),
609
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
610
+ /* @__PURE__ */ jsx(Button, { onClick: () => setEditModalOpen(false), color: "primary", children: "Cancel" }),
611
+ /* @__PURE__ */ jsx(
612
+ Button,
613
+ {
614
+ onClick: () => setConfirmDialogOpen(true),
615
+ color: "primary",
616
+ variant: "contained",
617
+ disabled: isLoadingManifest || !editingYaml.trim() || !!yamlValidationError,
618
+ children: "Save Changes"
619
+ }
620
+ )
621
+ ] })
622
+ ]
623
+ }
624
+ ),
625
+ /* @__PURE__ */ jsxs(
626
+ Dialog,
627
+ {
628
+ open: confirmDialogOpen,
629
+ onClose: () => setConfirmDialogOpen(false),
630
+ maxWidth: "sm",
631
+ fullWidth: true,
632
+ children: [
633
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Confirm Changes" }),
634
+ /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Typography, { children: "Are you sure you want to apply these changes to the resource? This action will update the Kubernetes resource based on your modifications." }) }),
635
+ /* @__PURE__ */ jsxs(DialogActions, { children: [
636
+ /* @__PURE__ */ jsx(Button, { onClick: () => setConfirmDialogOpen(false), color: "primary", children: "Cancel" }),
637
+ /* @__PURE__ */ jsx(
638
+ Button,
639
+ {
640
+ onClick: handleSaveResource,
641
+ color: "primary",
642
+ variant: "contained",
643
+ disabled: isSaving,
644
+ children: isSaving ? "Applying..." : "Apply Changes"
645
+ }
646
+ )
647
+ ] })
648
+ ]
649
+ }
650
+ ),
651
+ /* @__PURE__ */ jsx(
652
+ Snackbar,
653
+ {
654
+ open: snackbar.open,
655
+ autoHideDuration: 6e3,
656
+ onClose: handleCloseSnackbar,
657
+ anchorOrigin: { vertical: "bottom", horizontal: "left" },
658
+ children: /* @__PURE__ */ jsx(Alert, { onClose: handleCloseSnackbar, severity: snackbar.severity, children: snackbar.message })
659
+ }
660
+ )
661
+ ] });
338
662
  };
339
663
 
340
664
  export { VCFAutomationCCIResourceOverview };