39 lines
4.0 KiB
TypeScript
39 lines
4.0 KiB
TypeScript
import {useRef, useState} from 'react'
|
|
import {Upload} from 'lucide-react'
|
|
|
|
export function CloudFormationCreatePanel({isSubmitting, submitError, onCancel, onSubmit}: {isSubmitting: boolean; submitError: string | null; onCancel: () => void; onSubmit: (values: Record<string, unknown>) => void}) {
|
|
const [stackName, setStackName] = useState('')
|
|
const [templateBody, setTemplateBody] = useState('')
|
|
const [templateUrl, setTemplateUrl] = useState('')
|
|
const [parameters, setParameters] = useState('{}')
|
|
const [capabilities, setCapabilities] = useState('')
|
|
const [fileName, setFileName] = useState<string | null>(null)
|
|
const [fileError, setFileError] = useState<string | null>(null)
|
|
const fileInput = useRef<HTMLInputElement>(null)
|
|
|
|
async function loadTemplate(file?: File) {
|
|
if (!file) return
|
|
if (!/\.(json|ya?ml)$/i.test(file.name)) {
|
|
setFileError('Choose a JSON, YAML, or YML template file.')
|
|
return
|
|
}
|
|
setTemplateBody(await file.text())
|
|
setFileName(file.name)
|
|
setFileError(null)
|
|
}
|
|
|
|
const hasTemplate = Boolean(templateBody.trim() || templateUrl.trim())
|
|
return <form className="dynamic-form" onSubmit={(event) => { event.preventDefault(); if (hasTemplate) onSubmit({stackName, templateBody, templateUrl, parameters, capabilities}) }}>
|
|
<label className="dynamic-field"><span>Stack Name<em className="field-required">*</em></span><input className="input" value={stackName} required pattern="^[a-zA-Z][a-zA-Z0-9\-]{0,127}$" maxLength={128} onChange={(event) => setStackName(event.target.value)} placeholder="orders-stack"/><small>Start with a letter. Use letters, numbers, and hyphens.</small></label>
|
|
<label className="dynamic-field dynamic-field--span"><span>Template</span><textarea aria-label="Template" className="textarea code-textarea" value={templateBody} rows={14} spellCheck={false} onChange={(event) => setTemplateBody(event.target.value)} placeholder="Paste CloudFormation JSON or YAML, or upload a template file."/><small>Provide this or a Template S3 URL below.</small></label>
|
|
<input ref={fileInput} type="file" accept=".json,.yaml,.yml,application/json,application/x-yaml,text/yaml" hidden onChange={(event) => void loadTemplate(event.target.files?.[0])}/>
|
|
<div style={{gridColumn: '1 / -1', display: 'flex', gap: '8px', alignItems: 'center'}}><button className="button" type="button" disabled={isSubmitting} onClick={() => fileInput.current?.click()}><Upload size={14}/> Upload JSON or YAML</button>{fileName && <span className="muted compact-text">Loaded {fileName}</span>}</div>
|
|
<label className="dynamic-field dynamic-field--span"><span>Template S3 URL</span><input aria-label="Template S3 URL" className="input" value={templateUrl} onChange={(event) => setTemplateUrl(event.target.value)} placeholder="https://bucket.s3.amazonaws.com/templates/stack.yaml"/><small>Provide this or an inline/uploaded template above.</small></label>
|
|
<label className="dynamic-field dynamic-field--span"><span>Parameters (JSON)</span><textarea className="textarea code-textarea small" value={parameters} onChange={(event) => setParameters(event.target.value)} spellCheck={false}/><small>Optional object of parameter keys to string values.</small></label>
|
|
<label className="dynamic-field dynamic-field--span"><span>Capabilities</span><input className="input" value={capabilities} onChange={(event) => setCapabilities(event.target.value)} placeholder="CAPABILITY_IAM, CAPABILITY_NAMED_IAM"/><small>Optional comma-separated AWS capabilities.</small></label>
|
|
{fileError && <div className="form-error" role="alert">{fileError}</div>}
|
|
{submitError && <div className="form-error" role="alert">{submitError}</div>}
|
|
<div style={{gridColumn: '1 / -1', justifySelf: 'end', display: 'flex', gap: '8px'}}><button className="button" type="button" disabled={isSubmitting} onClick={onCancel}>Cancel</button><button className="button primary" type="submit" disabled={isSubmitting || !hasTemplate}>Create stack</button></div>
|
|
</form>
|
|
}
|