Skip to content

Commit c3f49b7

Browse files
authored
Merge pull request #1016 from pascalbreuninger/feat/additional-env-vars
feat(desktop): add experimental extra environment variables setting
2 parents ca73d7c + f381eeb commit c3f49b7

7 files changed

Lines changed: 122 additions & 24 deletions

File tree

desktop/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tauri-build = { version = "1.2", features = [] }
1212

1313
[dependencies]
1414
# Tauri
15-
tauri = { version = "1.2.4", features = [ "updater",
15+
tauri = { version = "1.2.4", features = [
1616
"process-relaunch",
1717
"window-close",
1818
"notification-all",

desktop/src-tauri/src/settings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct Settings {
2929
#[serde(rename = "experimental_devPodPro")]
3030
experimental_devpod_pro: bool,
3131
additional_cli_flags: String,
32+
additional_env_vars: String,
3233
}
3334

3435
#[derive(Debug, Serialize, TS)]

desktop/src/client/command.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,26 @@ export class Command implements TCommand<ChildProcess> {
2020
private childProcess?: Child
2121
private args: string[]
2222

23+
public static ADDITIONAL_ENV_VARS: string = ""
24+
2325
constructor(args: string[]) {
2426
debug("commands", "Creating Devpod command with args: ", args)
27+
const extraEnvVars = Command.ADDITIONAL_ENV_VARS.split(",")
28+
.map((envVarStr) => envVarStr.split("="))
29+
.reduce((acc, pair) => {
30+
const [key, value] = pair
31+
if (key === undefined || value === undefined) {
32+
return acc
33+
}
34+
35+
return { ...acc, [key]: value }
36+
}, {})
37+
2538
this.sidecarCommand = ShellCommand.sidecar(DEVPOD_BINARY, args, {
26-
env: { [DEVPOD_UI_ENV_VAR]: "true" },
39+
env: {
40+
...extraEnvVars,
41+
[DEVPOD_UI_ENV_VAR]: "true",
42+
},
2743
})
2844
this.args = args
2945
}

desktop/src/contexts/SettingsContext.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,17 @@ const initialSettings: TSettings = {
3737
experimental_vscodeInsiders: true,
3838
experimental_devPodPro: false,
3939
additionalCliFlags: "",
40+
additionalEnvVars: "",
4041
}
4142
function getSettingKeys(): readonly TSetting[] {
4243
return getKeys(initialSettings)
4344
}
4445

4546
// WARN: needs to match the filename on the rust side
4647
const SETTING_STORE_KEY = "settings"
47-
const settingsStore = new Store(new LocalStorageToFileMigrationBackend(SETTING_STORE_KEY))
48+
const settingsStore = new Store<Record<TSetting, string | boolean | unknown>>(
49+
new LocalStorageToFileMigrationBackend(SETTING_STORE_KEY)
50+
)
4851

4952
export function SettingsProvider({ children }: Readonly<{ children?: ReactNode }>) {
5053
const [settings, setSettings] = useState(initialSettings)

desktop/src/gen/Settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export interface Settings {
1616
experimental_vscodeInsiders: boolean
1717
experimental_devPodPro: boolean
1818
additionalCliFlags: string
19+
additionalEnvVars: string
1920
}

desktop/src/views/Settings/Settings.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ import {
3737
useVersion,
3838
} from "../../lib"
3939
import { useWelcomeModal } from "../../useWelcomeModal"
40-
import { useCLIFlagsOption, useAgentURLOption, useTelemetryOption } from "./useContextOptions"
40+
import {
41+
useCLIFlagsOption,
42+
useAgentURLOption,
43+
useTelemetryOption,
44+
useExtraEnvVarsOption,
45+
} from "./useContextOptions"
4146
import { useIDESettings } from "./useIDESettings"
4247

4348
const SETTINGS_TABS = [
@@ -319,6 +324,7 @@ function UpdateSettings() {
319324

320325
function ExperimentalSettings() {
321326
const { input: cliFlagsInput, helpText: cliFlagsHelpText } = useCLIFlagsOption()
327+
const { input: extraEnvVarsInput, helpText: extraEnvVarsHelpText } = useExtraEnvVarsOption()
322328
const { settings, set } = useChangeSettings()
323329

324330
return (
@@ -365,10 +371,14 @@ function ExperimentalSettings() {
365371
</HStack>
366372
</SettingSection>
367373

368-
<SettingSection title="CLI Additional Flags" description={cliFlagsHelpText}>
374+
<SettingSection title="Additional CLI Flags" description={cliFlagsHelpText}>
369375
{cliFlagsInput}
370376
</SettingSection>
371377

378+
<SettingSection title="Additional Environment Variables" description={extraEnvVarsHelpText}>
379+
{extraEnvVarsInput}
380+
</SettingSection>
381+
372382
<SettingSection
373383
showDivider={false}
374384
title="DevPod Pro (alpha)"

desktop/src/views/Settings/useContextOptions.tsx

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { client } from "../../client"
1414
import { useChangeSettings } from "../../contexts"
1515
import { QueryKeys } from "../../queryKeys"
1616
import { TContextOptionName } from "../../types"
17+
import { Command } from "../../client/command"
1718

1819
const DEFAULT_DEVPOD_AGENT_URL = "https://github.com/loft-sh/devpod/releases/latest/download/"
1920

@@ -40,34 +41,22 @@ export function useContextOptions() {
4041
[options, updateOption]
4142
)
4243
}
43-
44-
export function useSettingsOptions() {
44+
export function useCLIFlagsOption() {
4545
const { settings, set } = useChangeSettings()
46-
const { mutate: updateOption } = useMutation({
47-
mutationFn: async ({ value }: { value: string }) => {
46+
const updateOption = useCallback(
47+
(value: string) => {
4848
set("additionalCliFlags", value)
4949
client.setSetting("additionalCliFlags", value)
5050
},
51-
})
52-
53-
return useMemo(
54-
() => ({
55-
settings,
56-
updateOption,
57-
}),
58-
[settings, updateOption]
51+
[set]
5952
)
60-
}
61-
62-
export function useCLIFlagsOption() {
63-
const { settings, updateOption } = useSettingsOptions()
6453
const [hasFocus, setHasFocus] = useState(false)
6554
const inputRef = useRef<HTMLInputElement>(null)
6655

6756
const handleBlur = useCallback(
6857
(e: FocusEvent<HTMLInputElement>) => {
6958
const value = e.target.value.trim()
70-
updateOption({ value })
59+
updateOption(value)
7160
setHasFocus(false)
7261
},
7362
[updateOption]
@@ -96,7 +85,7 @@ export function useCLIFlagsOption() {
9685
<Input
9786
ref={inputRef}
9887
spellCheck={false}
99-
placeholder="CLI Additional Flags"
88+
placeholder="Additional CLI Flags"
10089
defaultValue={settings.additionalCliFlags}
10190
onBlur={handleBlur}
10291
onKeyUp={handleKeyUp}
@@ -129,10 +118,11 @@ export function useCLIFlagsOption() {
129118
]
130119
)
131120

132-
const helpText = useMemo(() => <>Set the additional CLI Flags to use.</>, [])
121+
const helpText = useMemo(() => <>Set additional CLI Flags to use.</>, [])
133122

134123
return { input, helpText }
135124
}
125+
136126
export function useAgentURLOption() {
137127
const { options, updateOption } = useContextOptions()
138128
const [hasFocus, setHasFocus] = useState(false)
@@ -244,3 +234,80 @@ export function useTelemetryOption() {
244234

245235
return { input, helpText }
246236
}
237+
238+
export function useExtraEnvVarsOption() {
239+
const { settings, set } = useChangeSettings()
240+
const [hasFocus, setHasFocus] = useState(false)
241+
const inputRef = useRef<HTMLInputElement>(null)
242+
243+
const handleBlur = useCallback(
244+
(e: FocusEvent<HTMLInputElement>) => {
245+
const value = e.target.value.trim()
246+
set("additionalEnvVars", value)
247+
Command.ADDITIONAL_ENV_VARS = value
248+
setHasFocus(false)
249+
},
250+
[set]
251+
)
252+
253+
const handleKeyUp = useCallback((e: KeyboardEvent<HTMLInputElement>) => {
254+
if (e.key !== "Enter") return
255+
256+
e.currentTarget.blur()
257+
}, [])
258+
259+
const handleFocus = useCallback(() => {
260+
setHasFocus(true)
261+
}, [])
262+
263+
const handleClear = useCallback(() => {
264+
const el = inputRef.current
265+
if (!el) return
266+
267+
el.value = ""
268+
}, [])
269+
270+
const input = useMemo(
271+
() => (
272+
<InputGroup maxWidth="72">
273+
<Input
274+
ref={inputRef}
275+
spellCheck={false}
276+
placeholder="Additional Environment Variables"
277+
defaultValue={settings.additionalEnvVars}
278+
onBlur={handleBlur}
279+
onKeyUp={handleKeyUp}
280+
onFocus={handleFocus}
281+
/>
282+
<InputRightElement>
283+
<IconButton
284+
visibility={hasFocus ? "visible" : "hidden"}
285+
size="xs"
286+
borderRadius="full"
287+
icon={<CloseIcon />}
288+
aria-label="clear"
289+
onMouseDown={(e) => {
290+
// needed to prevent losing focus from input
291+
e.stopPropagation()
292+
e.preventDefault()
293+
}}
294+
onClick={handleClear}
295+
/>
296+
</InputRightElement>
297+
</InputGroup>
298+
),
299+
[settings.additionalEnvVars, handleBlur, handleKeyUp, handleFocus, hasFocus, handleClear]
300+
)
301+
302+
const helpText = useMemo(
303+
() => (
304+
<>
305+
Set additional environment variables DevPod passes to all commands. Accepts a comma
306+
separated list, e.g. FOO=bar,BAZ=false
307+
</>
308+
),
309+
[]
310+
)
311+
312+
return { input, helpText }
313+
}

0 commit comments

Comments
 (0)