Skip to content

Commit 1d7a919

Browse files
committed
feat: render form from current state
1 parent b5c31fe commit 1d7a919

File tree

7 files changed

+78
-36
lines changed

7 files changed

+78
-36
lines changed

preview/main.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,24 @@ func tfpreview(this js.Value, p []js.Value) (output any) {
6363

6464
handler := slog.NewJSONHandler(l, nil)
6565
logger := slog.New(handler)
66+
67+
var parameters map[string]string
68+
if len(p) >= 2 {
69+
params, err := jsValueToStringMap(p[1])
70+
if err != nil {
71+
logger.Error("Unable to convert second prameter into map[string]string", "err", err)
72+
}
73+
74+
parameters = params
75+
} else {
76+
logger.Error(fmt.Sprintf("Expected 2 arguments but got %v", len(p)))
77+
78+
}
79+
6680
pOutput, diags := preview.Preview(context.Background(), preview.Input{
6781
PlanJSONPath: "",
6882
PlanJSON: nil,
69-
ParameterValues: nil,
83+
ParameterValues: parameters,
7084
Owner: types.WorkspaceOwner{},
7185
Logger: logger,
7286
}, tf)
@@ -145,3 +159,41 @@ func (l *Logger) Write(p []byte) (n int, err error) {
145159

146160
return len(p), nil
147161
}
162+
163+
func jsValueToStringMap(jsVal js.Value) (map[string]string, error) {
164+
result := make(map[string]string)
165+
166+
// Validate input
167+
if jsVal.IsUndefined() || jsVal.IsNull() {
168+
return nil, fmt.Errorf("js.Value is undefined or null")
169+
}
170+
171+
if jsVal.Type() != js.TypeObject {
172+
return nil, fmt.Errorf("js.Value is not an object")
173+
}
174+
175+
// Get object keys
176+
keys := js.Global().Get("Object").Call("keys", jsVal)
177+
178+
for i := range keys.Length() {
179+
key := keys.Index(i).String()
180+
value := jsVal.Get(key)
181+
182+
// Handle different value types
183+
switch value.Type() {
184+
case js.TypeString:
185+
result[key] = value.String()
186+
case js.TypeNumber:
187+
result[key] = fmt.Sprintf("%f", value.Float())
188+
case js.TypeBoolean:
189+
result[key] = fmt.Sprintf("%t", value.Bool())
190+
case js.TypeNull, js.TypeUndefined:
191+
result[key] = ""
192+
default:
193+
// For objects, arrays, etc., use String() method
194+
result[key] = value.String()
195+
}
196+
}
197+
198+
return result, nil
199+
}

public/build/preview.wasm

12.8 KB
Binary file not shown.

src/client/App.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ import {
3232
import { rpc } from "@/utils/rpc";
3333
import { useLoaderData, type LoaderFunctionArgs } from "react-router";
3434

35-
type GoPreviewDef = (v: unknown) => Promise<string>;
35+
type GoPreviewDef = (
36+
v: Record<string, string>,
37+
params: Record<string, string>,
38+
) => Promise<string>;
3639

3740
// Extend the Window object to include the Go related code that is added from
3841
// wasm_exec.js and our loaded Go code.

src/client/Preview.tsx

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export const Preview: FC = () => {
3939
const $setError = useStore((state) => state.setError);
4040
const $parameters = useStore((state) => state.parameters);
4141
const $setParameters = useStore((state) => state.setParameters);
42+
const $form = useStore((state) => state.form);
43+
const $resetForm = useStore((state) => state.resetForm);
4244

4345
const [debouncedCode, isDebouncing] = useDebouncedValue($code, 1000);
4446
const [output, setOutput] = useState<PreviewOutput | null>(() => null);
@@ -77,9 +79,12 @@ export const Preview: FC = () => {
7779

7880
const getOutput = async () => {
7981
try {
80-
const rawOutput = await window.go_preview?.({
81-
"main.tf": debouncedCode,
82-
});
82+
const rawOutput = await window.go_preview?.(
83+
{
84+
"main.tf": debouncedCode,
85+
},
86+
$form,
87+
);
8388

8489
if (rawOutput === undefined) {
8590
console.error("Something went wrong");
@@ -90,7 +95,7 @@ export const Preview: FC = () => {
9095
const errors = outputToDiagnostics(output);
9196
$setError(errors);
9297

93-
if (errors.length === 0) {
98+
if (output.diags.length === 0) {
9499
$setParameters(output.output?.Parameters ?? []);
95100
}
96101
}
@@ -118,7 +123,7 @@ export const Preview: FC = () => {
118123
};
119124

120125
getOutput();
121-
}, [debouncedCode, $setError, $wasmState, $setParameters]);
126+
}, [debouncedCode, $setError, $wasmState, $setParameters, $form]);
122127

123128
return (
124129
<Tabs.Root
@@ -206,7 +211,9 @@ export const Preview: FC = () => {
206211
) : null}
207212
</AnimatePresence>
208213
</div>
209-
<Button variant="destructive">Reset form</Button>
214+
<Button variant="destructive" onClick={$resetForm}>
215+
Reset form
216+
</Button>
210217
</div>
211218
}
212219
{!output ? (
@@ -592,32 +599,7 @@ const FormElement: FC<FormElementProps> = ({ parameter }) => {
592599
value={value}
593600
autofill={false}
594601
onChange={onValueChange}
602+
disabled={parameter.styling.disabled}
595603
/>
596604
);
597-
598-
// if (parameter.form_type === ParameterFormType.ParameterFormTypeInput) {
599-
// return (
600-
// <Input
601-
// onChange={(e) => onValueChange(e.target.value)}
602-
// id={parameter.name}
603-
// value={value}
604-
// />
605-
// );
606-
// }
607-
// if (parameter.form_type === ParameterFormType.ParameterFormTypeRadio) {
608-
// return (
609-
// <RadioGroup value={value} onValueChange={onValueChange}>
610-
// {parameter.options
611-
// .filter((o) => o !== null)
612-
// .map((o, index) => (
613-
// <div className="flex items-center gap-2" key={index}>
614-
// <RadioGroupItem value={o.value.value} title={"foo"} />
615-
// <p className="text-content-primary text-sm">{o.name}</p>
616-
// </div>
617-
// ))}
618-
// </RadioGroup>
619-
// );
620-
// }
621-
622-
// return null;
623605
};

src/client/components/DynamicParameter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ const ParameterField: FC<ParameterFieldProps> = ({
531531
max={parameter.validations[0]?.validation_max ?? 100}
532532
disabled={disabled}
533533
/>
534-
<span className="w-4 font-medium">
534+
<span className="w-4 font-medium text-content-secondary">
535535
{Number.isFinite(Number(value)) ? value : "0"}
536536
</span>
537537
</div>

src/client/components/Markdown.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export const Markdown: FC<MarkdownProps> = (props) => {
4343
// className={className}
4444
remarkPlugins={[gfm]}
4545
components={{
46+
p: ({ children }) => {
47+
return <p className="text-xs">{children}</p>;
48+
},
4649
a: ({ href, children }) => {
4750
const isExternal = href?.startsWith("http");
4851

@@ -118,7 +121,7 @@ export const Markdown: FC<MarkdownProps> = (props) => {
118121
},
119122

120123
h2: ({ children }) => {
121-
return <h2 className="mt-8 mb-4">{children}</h2>;
124+
return <h2 className="mt-8 mb-4">{children}</h2>;
122125
},
123126

124127
h3: ({ children }) => {

src/client/store.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type State = {
3535
setWasmState: (wasmState: WasmState) => void;
3636
setParameters: (parameters: Parameter[]) => void;
3737
setFormState: (key: string, value: string) => void;
38+
resetForm: () => void;
3839
};
3940

4041
export const useStore = create<State>()((set) => ({
@@ -70,4 +71,5 @@ export const useStore = create<State>()((set) => ({
7071

7172
return { form };
7273
}),
74+
resetForm: () => set(() => ({ form: {} })),
7375
}));

0 commit comments

Comments
 (0)