feat: Script Generator Phase 1 — backend models, engine, API, and AD templates #105

Merged
chihlasm merged 78 commits from feat/script-generator into main 2026-03-15 00:19:00 +00:00
Showing only changes of commit 86a9d3b977 - Show all commits

View File

@@ -0,0 +1,56 @@
import { useState } from 'react'
import { Copy, Check } from 'lucide-react'
import { useScriptGeneratorStore } from '@/store/scriptGeneratorStore'
import { PowerShellHighlighter } from './PowerShellHighlighter'
import type { ScriptParametersSchema } from '@/types'
export function ScriptPreview() {
const selectedTemplate = useScriptGeneratorStore(s => s.selectedTemplate)
const paramValues = useScriptGeneratorStore(s => s.paramValues)
const generatedScript = useScriptGeneratorStore(s => s.generatedScript)
const [copied, setCopied] = useState(false)
if (!selectedTemplate) return null
// Compute the displayed script
let displayScript: string
if (generatedScript !== null) {
displayScript = generatedScript
} else {
// Draft mode: client-side {{key}} substitution
const schema = selectedTemplate.parameters_schema as ScriptParametersSchema
const parameters = schema?.parameters ?? []
displayScript = selectedTemplate.script_body
for (const param of parameters) {
const placeholder = `{{${param.key}}}`
const replacement = param.sensitive
? '****'
: (paramValues[param.key] ?? '')
displayScript = displayScript.replaceAll(placeholder, replacement || placeholder)
}
}
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(displayScript)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch {
// silently fail — no error displayed
}
}
return (
<div className="relative">
<button
onClick={handleCopy}
className="absolute top-3 right-3 z-10 p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-white/5 transition-colors"
title={copied ? 'Copied!' : 'Copy to clipboard'}
aria-label={copied ? 'Copied!' : 'Copy to clipboard'}
>
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
</button>
<PowerShellHighlighter script={displayScript} />
</div>
)
}