diff --git a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json b/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json
index 208be71..bace9c0 100644
--- a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json
+++ b/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json
@@ -5,14 +5,6 @@
"category": "script",
"type": "powershell",
"script": "# Define the file path\n$filePath = \"C:\\Canary.txt\"\n\n# Write some content into the file\n\"SYSTEM Canary is alive.\"ddss | Out-File -FilePath $filePath -Encoding UTF8\n",
- "script_lines": [
- "# Define the file path",
- "$filePath = \"C:\\Canary.txt\"",
- "",
- "# Write some content into the file",
- "\"SYSTEM Canary is alive.\"ddss | Out-File -FilePath $filePath -Encoding UTF8",
- ""
- ],
"timeout_seconds": 3600,
"sites": {
"mode": "specific",
diff --git a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx
index f9dc7ce..e27bf4f 100644
--- a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx
+++ b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx
@@ -212,13 +212,11 @@ function fromServerDocument(doc = {}, defaultType = "powershell") {
assembly.description = doc.description || "";
assembly.category = doc.category || assembly.category;
assembly.type = doc.type || assembly.type;
- if (Array.isArray(doc.script_lines)) {
- assembly.script = doc.script_lines
- .map((line) => (line == null ? "" : String(line)))
- .join("\n");
- } else {
- assembly.script = doc.script ?? doc.content ?? "";
- }
+ const legacyScript = Array.isArray(doc.script_lines)
+ ? doc.script_lines.map((line) => (line == null ? "" : String(line))).join("\n")
+ : "";
+ const script = doc.script ?? doc.content ?? legacyScript;
+ assembly.script = typeof script === "string" ? script : legacyScript;
const timeout = doc.timeout_seconds ?? doc.timeout ?? assembly.timeoutSeconds;
assembly.timeoutSeconds = Number.isFinite(Number(timeout))
? Number(timeout)
@@ -238,7 +236,6 @@ function toServerDocument(assembly) {
const normalizedScript = typeof assembly.script === "string"
? assembly.script.replace(/\r\n/g, "\n")
: "";
- const scriptLines = normalizedScript ? normalizedScript.split("\n") : [];
const timeoutNumeric = Number(assembly.timeoutSeconds);
const timeoutSeconds = Number.isFinite(timeoutNumeric) ? Math.max(0, Math.round(timeoutNumeric)) : 3600;
return {
@@ -248,7 +245,6 @@ function toServerDocument(assembly) {
category: assembly.category || "script",
type: assembly.type || "powershell",
script: normalizedScript,
- script_lines: scriptLines,
timeout_seconds: timeoutSeconds,
sites: {
mode: assembly.sites?.mode === "specific" ? "specific" : "all",
@@ -728,12 +724,16 @@ export default function AssemblyEditor({
value={assembly.description}
onChange={(e) => updateAssembly({ description: e.target.value })}
multiline
- minRows={3}
+ minRows={2}
+ maxRows={8}
fullWidth
variant="outlined"
sx={{
...INPUT_BASE_SX,
- "& .MuiOutlinedInput-inputMultiline": { padding: "4px 8px" }
+ "& .MuiOutlinedInput-inputMultiline": {
+ padding: "6px 12px",
+ lineHeight: 1.4
+ }
}}
/>
@@ -902,92 +902,177 @@ export default function AssemblyEditor({
key={variable.id}
sx={{ p: 2, bgcolor: BACKGROUND_COLORS.field, border: "1px solid #2b3544", borderRadius: 1 }}
>
-
-
- updateVariable(variable.id, { name: e.target.value })}
- fullWidth
- variant="outlined"
- sx={INPUT_BASE_SX}
- />
-
-
- updateVariable(variable.id, { label: e.target.value })}
- fullWidth
- variant="outlined"
- sx={INPUT_BASE_SX}
- />
-
-
- updateVariable(variable.id, { type: e.target.value })}
- sx={SELECT_BASE_SX}
- SelectProps={{ MenuProps: MENU_PROPS }}
- >
- {VARIABLE_TYPE_OPTIONS.map((opt) => (
-
- ))}
-
-
-
- {variable.type === "boolean" ? (
- updateVariable(variable.id, { defaultValue: e.target.checked })}
- sx={{ color: "#58a6ff" }}
- />
- }
- label="Default Value"
- />
- ) : (
+
+
+
+ \". For example, a variable named \"message\" would be written in the script as \"$env:message\"."
+ arrow
+ placement="top-start"
+ >
updateVariable(variable.id, { defaultValue: e.target.value })}
+ label="Variable"
+ value={variable.name}
+ onChange={(e) => updateVariable(variable.id, { name: e.target.value })}
fullWidth
variant="outlined"
sx={INPUT_BASE_SX}
/>
+
+
+
+
+ updateVariable(variable.id, { label: e.target.value })}
+ fullWidth
+ variant="outlined"
+ sx={INPUT_BASE_SX}
+ />
+
+
+
+
+ updateVariable(variable.id, { type: e.target.value })}
+ sx={SELECT_BASE_SX}
+ SelectProps={{ MenuProps: MENU_PROPS }}
+ >
+ {VARIABLE_TYPE_OPTIONS.map((opt) => (
+
+ ))}
+
+
+
+
+ {variable.type === "boolean" ? (
+
+ updateVariable(variable.id, { defaultValue: e.target.checked })}
+ sx={{ color: "#58a6ff" }}
+ />
+ }
+ label="Default Value"
+ sx={{
+ color: "#9ba3b4",
+ m: 0,
+ "& .MuiFormControlLabel-label": { fontSize: "0.95rem" }
+ }}
+ />
+
+ ) : (
+
+ updateVariable(variable.id, { defaultValue: e.target.value })}
+ fullWidth
+ variant="outlined"
+ sx={INPUT_BASE_SX}
+ />
+
)}
-
-
-
+
+
+
+ Required
+
updateVariable(variable.id, { required: e.target.checked })}
- sx={{ color: "#58a6ff" }}
+ sx={{ color: "#58a6ff", p: 0.5 }}
+ inputProps={{ "aria-label": "Required" }}
/>
-
-
-
- updateVariable(variable.id, { description: e.target.value })}
- fullWidth
- multiline
- minRows={2}
- variant="outlined"
- sx={INPUT_BASE_SX}
- />
-
-
- removeVariable(variable.id)} sx={{ color: "#ff6b6b" }}>
-
-
-
-
+
+
+
+ removeVariable(variable.id)} sx={{ color: "#ff6b6b" }}>
+
+
+
+
+
+
+
+
+ updateVariable(variable.id, { description: e.target.value })}
+ fullWidth
+ variant="outlined"
+ sx={INPUT_BASE_SX}
+ />
+
+
+
+
))}
diff --git a/Data/Server/job_scheduler.py b/Data/Server/job_scheduler.py
index f236faf..e6fd70e 100644
--- a/Data/Server/job_scheduler.py
+++ b/Data/Server/job_scheduler.py
@@ -182,7 +182,6 @@ class JobScheduler:
"category": "application" if default_type == "ansible" else "script",
"type": default_type,
"script": "",
- "script_lines": [],
"variables": [],
"files": [],
"timeout_seconds": 3600,
@@ -217,7 +216,6 @@ class JobScheduler:
doc["script"] = content_val
normalized_script = (doc["script"] or "").replace("\r\n", "\n")
doc["script"] = normalized_script
- doc["script_lines"] = normalized_script.split("\n") if normalized_script else []
try:
timeout_raw = data.get("timeout_seconds", data.get("timeout"))
if timeout_raw is None:
@@ -271,7 +269,6 @@ class JobScheduler:
content = ""
normalized_script = (content or "").replace("\r\n", "\n")
doc["script"] = normalized_script
- doc["script_lines"] = normalized_script.split("\n") if normalized_script else []
return doc
def _ansible_root(self) -> str:
diff --git a/Data/Server/server.py b/Data/Server/server.py
index 6c80221..631eb86 100644
--- a/Data/Server/server.py
+++ b/Data/Server/server.py
@@ -682,7 +682,6 @@ def _empty_assembly_document(default_type: str = "powershell") -> Dict[str, Any]
"category": "application" if (default_type or "").lower() == "ansible" else "script",
"type": default_type or "powershell",
"script": "",
- "script_lines": [],
"timeout_seconds": 3600,
"sites": {"mode": "all", "values": []},
"variables": [],
@@ -718,7 +717,6 @@ def _normalize_assembly_document(obj: Any, default_type: str, base_name: str) ->
doc["script"] = content_val
normalized_script = (doc["script"] or "").replace("\r\n", "\n")
doc["script"] = normalized_script
- doc["script_lines"] = normalized_script.split("\n") if normalized_script else []
timeout_val = obj.get("timeout_seconds", obj.get("timeout"))
if timeout_val is not None:
try:
@@ -798,7 +796,6 @@ def _load_assembly_document(abs_path: str, island: str, type_hint: str = "") ->
doc["name"] = base_name
normalized_script = (content or "").replace("\r\n", "\n")
doc["script"] = normalized_script
- doc["script_lines"] = normalized_script.split("\n") if normalized_script else []
if default_type == "ansible":
doc["category"] = "application"
return doc