diff --git a/virtweb_frontend/package-lock.json b/virtweb_frontend/package-lock.json index a8cc8d7..95ada5d 100644 --- a/virtweb_frontend/package-lock.json +++ b/virtweb_frontend/package-lock.json @@ -29,7 +29,8 @@ "react-syntax-highlighter": "^15.6.1", "react-vnc": "^3.1.0", "uuid": "^11.1.0", - "xml-formatter": "^3.6.6" + "xml-formatter": "^3.6.6", + "yaml": "^2.8.0" }, "devDependencies": { "@eslint/js": "^9.27.0", diff --git a/virtweb_frontend/package.json b/virtweb_frontend/package.json index e4ef8ce..b105ec7 100644 --- a/virtweb_frontend/package.json +++ b/virtweb_frontend/package.json @@ -31,7 +31,8 @@ "react-syntax-highlighter": "^15.6.1", "react-vnc": "^3.1.0", "uuid": "^11.1.0", - "xml-formatter": "^3.6.6" + "xml-formatter": "^3.6.6", + "yaml": "^2.8.0" }, "devDependencies": { "@eslint/js": "^9.27.0", diff --git a/virtweb_frontend/src/widgets/forms/CloudInitEditor.tsx b/virtweb_frontend/src/widgets/forms/CloudInitEditor.tsx index 3f654bc..a84ba8f 100644 --- a/virtweb_frontend/src/widgets/forms/CloudInitEditor.tsx +++ b/virtweb_frontend/src/widgets/forms/CloudInitEditor.tsx @@ -2,7 +2,9 @@ import Editor from "@monaco-editor/react"; import BookIcon from "@mui/icons-material/Book"; import RefreshIcon from "@mui/icons-material/Refresh"; import { Grid, IconButton, InputAdornment, Tooltip } from "@mui/material"; +import React from "react"; import { v4 as uuidv4 } from "uuid"; +import YAML from "yaml"; import { VMInfo } from "../../api/VMApi"; import { RouterLink } from "../RouterLink"; import { CheckboxInput } from "./CheckboxInput"; @@ -44,6 +46,10 @@ export function CloudInitEditor(p: CloudInitProps): React.ReactElement { {...p} editable={p.editable && p.vm.cloud_init.attach_config} /> + ); @@ -183,3 +189,76 @@ function CloudInitNetworkConfig(p: CloudInitProps): React.ReactElement { ); } + +function CloudInitUserDataAssistant(p: CloudInitProps): React.ReactElement { + const user_data = React.useMemo(() => { + return YAML.parseDocument(p.vm.cloud_init.user_data); + }, [p.vm.cloud_init.user_data]); + + const onChange = () => { + p.vm.cloud_init.user_data = user_data.toString(); + + if (!p.vm.cloud_init.user_data.startsWith("#cloud-config")) + p.vm.cloud_init.user_data = `#cloud-config\n${p.vm.cloud_init.user_data}`; + + p.onChange?.(); + }; + + return ( + + + + + + ); +} + +function CloudInitTextInput(p: { + editable: boolean; + name: string; + refUrl: string; + attrPath: Iterable; + yaml: YAML.Document; + onChange: () => void; +}): React.ReactElement { + return ( + { + if (v !== undefined) p.yaml.setIn(p.attrPath, v); + else p.yaml.deleteIn(p.attrPath); + p.onChange?.(); + }} + endAdornment={ + + + + + + } + /> + ); +}