diff --git a/frontend/src/components/config/index.tsx b/frontend/src/components/config/index.tsx index bfe29838b..450fc6fdc 100644 --- a/frontend/src/components/config/index.tsx +++ b/frontend/src/components/config/index.tsx @@ -60,8 +60,10 @@ export const ConfigLayout = < variant="outline" onClick={onReset} disabled={disabled || (config ? !Object.keys(config).length : true)} + className="flex items-center gap-2" > + Reset {changesMade && ( - set(true)} disabled={disabled}> + set(true)} + disabled={disabled} + className="flex items-center gap-2" + > + Save diff --git a/frontend/src/components/resources/build/config.tsx b/frontend/src/components/resources/build/config.tsx index d5cc2fc81..8e691b70d 100644 --- a/frontend/src/components/resources/build/config.tsx +++ b/frontend/src/components/resources/build/config.tsx @@ -19,8 +19,9 @@ import { } from "@ui/select"; import { Textarea } from "@ui/textarea"; import { PlusCircle } from "lucide-react"; -import { ReactNode, useEffect, useState } from "react"; +import { ReactNode, RefObject, createRef, useEffect, useState } from "react"; import { CopyGithubWebhook, LabelsConfig, ResourceSelector } from "../common"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs"; export const BuildConfig = ({ id, @@ -270,24 +271,171 @@ const BuildArgs = ({ set: (input: Partial) => void; disabled: boolean; }) => { - const [args, setArgs] = useState(env_to_text(vars)); - useEffect(() => { - !!args && set({ build_args: text_to_env(args) }); - }, [args, set]); + const ref = createRef(); + const [args, setArgs] = useState(); + useEffect(() => setArgs(env_to_text(vars)), [vars]); + + const update = () => { + if (!args) return; + const parsed = text_to_env(args); + + // Diff the vars from old to new + for (const [v, i] of vars.map( + (v, i) => [v, i] as [Types.EnvironmentVar, number] + )) { + const _v = parsed[i]; + if (!_v || v.value !== _v.value || v.variable !== _v.variable) { + set({ build_args: parsed }); + return; + } + } + + // Diff the vars from new to old + for (const [v, i] of parsed.map( + (v, i) => [v, i] as [Types.EnvironmentVar, number] + )) { + const _v = vars[i]; + if (!_v || v.value !== _v.value || v.variable !== _v.variable) { + set({ build_args: parsed }); + return; + } + } + }; return ( + {!disabled && } setArgs(e.target.value)} + onBlur={update} disabled={disabled} /> ); }; +const Secrets = ({ + args, + setArgs, + argsRef, +}: { + args?: string; + setArgs: (args: string) => void; + argsRef: RefObject; +}) => { + const { variables, secrets } = useRead("ListVariables", {}).data ?? { + variables: [], + secrets: [], + }; + + const _args = args || ""; + + if (variables.length === 0 && secrets.length === 0) return; + + if (variables.length === 0) { + // ONLY SECRETS + return ( + + Secrets + + {secrets.map((secret) => ( + + setArgs( + _args.slice(0, argsRef.current?.selectionStart) + + `[[${secret}]]` + + _args.slice(argsRef.current?.selectionStart, undefined) + ) + } + > + {secret} + + ))} + + + ); + } + + if (secrets.length === 0) { + // ONLY VARIABLES + return ( + + Variables + + {variables.map(({ name }) => ( + + setArgs( + _args.slice(0, argsRef.current?.selectionStart) + + `[[${name}]]` + + _args.slice(argsRef.current?.selectionStart, undefined) + ) + } + > + {name} + + ))} + + + ); + } + + return ( + + + Variables + Secrets + + + + {variables.map(({ name }) => ( + + setArgs( + _args.slice(0, argsRef.current?.selectionStart) + + `[[${name}]]` + + _args.slice(argsRef.current?.selectionStart, undefined) + ) + } + > + {name} + + ))} + + + + + {secrets.map((secret) => ( + + setArgs( + _args.slice(0, argsRef.current?.selectionStart) + + `[[${secret}]]` + + _args.slice(argsRef.current?.selectionStart, undefined) + ) + } + > + {secret} + + ))} + + + + ); +}; + const DockerOrganizations = ({ value, set, diff --git a/frontend/src/components/resources/deployment/config/components/environment.tsx b/frontend/src/components/resources/deployment/config/components/environment.tsx index 75d1afd82..b620b9336 100644 --- a/frontend/src/components/resources/deployment/config/components/environment.tsx +++ b/frontend/src/components/resources/deployment/config/components/environment.tsx @@ -20,10 +20,35 @@ export const EnvVars = ({ server?: string; }) => { const ref = createRef(); - const [env, setEnv] = useState(env_to_text(vars)); - useEffect(() => { - !!env && set({ environment: text_to_env(env) }); - }, [env, set]); + const [env, setEnv] = useState(); + useEffect(() => setEnv(env_to_text(vars)), [vars]); + + const update = () => { + if (!env) return; + const parsed = text_to_env(env); + + // Diff the vars from old to new + for (const [v, i] of vars.map( + (v, i) => [v, i] as [Types.EnvironmentVar, number] + )) { + const _v = parsed[i]; + if (!_v || v.value !== _v.value || v.variable !== _v.variable) { + set({ environment: parsed }); + return; + } + } + + // Diff the vars from new to old + for (const [v, i] of parsed.map( + (v, i) => [v, i] as [Types.EnvironmentVar, number] + )) { + const _v = vars[i]; + if (!_v || v.value !== _v.value || v.variable !== _v.variable) { + set({ environment: parsed }); + return; + } + } + }; return ( @@ -36,6 +61,7 @@ export const EnvVars = ({ placeholder="VARIABLE=value" value={env} onChange={(e) => setEnv(e.target.value)} + onBlur={update} disabled={disabled} />