Skip to content

Commit 09ab5bd

Browse files
menu: settings: general: Add dedicated section and logic around the folder location
1 parent 11f9b37 commit 09ab5bd

1 file changed

Lines changed: 104 additions & 9 deletions

File tree

src/views/ConfigurationGeneralView.vue

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,6 @@
4444
<v-btn size="x-small" class="bg-[#FFFFFF22] shadow-1" variant="flat" @click="openTutorial">
4545
Show tutorial
4646
</v-btn>
47-
<v-btn
48-
v-if="isElectron()"
49-
size="x-small"
50-
class="bg-[#FFFFFF22] shadow-1"
51-
variant="flat"
52-
@click="openCockpitFolder"
53-
>
54-
Open Cockpit folder
55-
</v-btn>
5647
<v-btn
5748
size="x-small"
5849
class="bg-[#FFFFFF22] shadow-1"
@@ -70,6 +61,44 @@
7061
{{ interfaceStore.pirateMode ? 'Disable pirate mode' : 'Enable pirate mode' }}
7162
</v-btn>
7263
</div>
64+
<v-divider v-if="isElectron()" class="w-full opacity-[0.08]" />
65+
<div v-if="isElectron()" class="flex flex-col w-full py-4 gap-1">
66+
<div class="flex align-center w-full justify-between pr-2">
67+
<div class="flex items-center min-w-0">
68+
<span class="mr-2 whitespace-nowrap">Cockpit folder location:</span>
69+
<v-tooltip :text="cockpitFolderPath" location="bottom" open-delay="300">
70+
<template #activator="{ props }">
71+
<span v-bind="props" class="font-semibold text-base truncate">{{ cockpitFolderPath }}</span>
72+
</template>
73+
</v-tooltip>
74+
</div>
75+
<div class="flex justify-end">
76+
<v-btn
77+
size="small"
78+
append-icon="mdi-folder-open-outline"
79+
class="bg-[#FFFFFF22] shadow-2 -mr-2"
80+
variant="flat"
81+
@click="openCockpitFolder"
82+
>
83+
Open folder
84+
</v-btn>
85+
</div>
86+
</div>
87+
<div class="flex items-center gap-1">
88+
<span class="text-xs text-slate-400 cursor-pointer hover:text-slate-100" @click="browseCockpitFolder">
89+
Change cockpit folder location
90+
</span>
91+
<template v-if="cockpitFolderPath !== defaultCockpitFolderPath">
92+
<span class="text-xs text-slate-400">or</span>
93+
<span
94+
class="text-xs text-slate-400 cursor-pointer hover:text-slate-100"
95+
@click="resetCockpitFolderPath"
96+
>
97+
reset to the default location
98+
</span>
99+
</template>
100+
</div>
101+
</div>
73102
</div>
74103
</template>
75104
</ExpansiblePanel>
@@ -392,6 +421,7 @@ import { defaultGlobalAddress } from '@/assets/defaults'
392421
import ManageCockpitSettings from '@/components/configuration/CockpitSettingsManager.vue'
393422
import ExpansiblePanel from '@/components/ExpansiblePanel.vue'
394423
import VehicleDiscoveryDialog from '@/components/VehicleDiscoveryDialog.vue'
424+
import { useInteractionDialog } from '@/composables/interactionDialog'
395425
import { useSnackbar } from '@/composables/snackbar'
396426
import * as Connection from '@/libs/connection/connection'
397427
import { ConnectionManager } from '@/libs/connection/connection-manager'
@@ -416,12 +446,76 @@ const mainVehicleStore = useMainVehicleStore()
416446
const interfaceStore = useAppInterfaceStore()
417447
const missionStore = useMissionStore()
418448
const { openSnackbar } = useSnackbar()
449+
const { showDialog, closeDialog } = useInteractionDialog()
419450
420451
const globalAddressForm = ref()
421452
const globalAddressFormValid = ref(false)
422453
const newGlobalAddress = ref(mainVehicleStore.globalAddress)
423454
const showCockpitSettingsDialog = ref(false)
424455
456+
const cockpitFolderPath = ref('')
457+
const defaultCockpitFolderPath = ref('')
458+
459+
const loadCockpitFolderPath = async (): Promise<void> => {
460+
if (!isElectron() || !window.electronAPI) return
461+
cockpitFolderPath.value = await window.electronAPI.getCockpitFolderPath()
462+
defaultCockpitFolderPath.value = await window.electronAPI.getDefaultCockpitFolderPath()
463+
}
464+
465+
const applyFolderPath = async (path: string): Promise<void> => {
466+
if (!window.electronAPI) return
467+
await window.electronAPI.setCockpitFolderPath(path)
468+
cockpitFolderPath.value = path
469+
}
470+
471+
const browseCockpitFolder = async (): Promise<void> => {
472+
if (!window.electronAPI) return
473+
const selected = await window.electronAPI.selectCockpitFolder()
474+
if (!selected) return
475+
476+
const folderName = selected.split(/[/\\]/).filter(Boolean).pop()
477+
if (folderName === 'Cockpit') {
478+
await applyFolderPath(selected)
479+
return
480+
}
481+
482+
const selectedName = selected.split(/[/\\]/).filter(Boolean).pop() ?? ''
483+
showDialog({
484+
title: 'Cockpit folder location',
485+
message:
486+
`The selected folder is not named "Cockpit". Would you like to use ` +
487+
`${selected} directly, or create and use a Cockpit subfolder inside it?`,
488+
variant: 'info',
489+
persistent: true,
490+
maxWidth: 700,
491+
actions: [
492+
{ text: 'Cancel', size: 'small', action: () => closeDialog() },
493+
{
494+
text: `Use ${selectedName}`,
495+
size: 'small',
496+
action: () => {
497+
closeDialog()
498+
applyFolderPath(selected)
499+
},
500+
},
501+
{
502+
text: `Use ${selectedName}/Cockpit`,
503+
size: 'small',
504+
action: () => {
505+
closeDialog()
506+
applyFolderPath(`${selected}/Cockpit`)
507+
},
508+
},
509+
],
510+
})
511+
}
512+
513+
const resetCockpitFolderPath = async (): Promise<void> => {
514+
if (!window.electronAPI) return
515+
await window.electronAPI.setCockpitFolderPath(defaultCockpitFolderPath.value)
516+
cockpitFolderPath.value = defaultCockpitFolderPath.value
517+
}
518+
425519
const setGlobalAddress = async (): Promise<void> => {
426520
await globalAddressForm.value.validate()
427521
@@ -643,6 +737,7 @@ const newGenericWebSocketUrl = ref(exampleGenericWebSocketUrl)
643737
let unsubscribeGenericWebSocket: (() => void) | null = null
644738
645739
onMounted(() => {
740+
loadCockpitFolderPath()
646741
tryToPrettifyRtcConfig()
647742
unsubscribeGenericWebSocket = listenToGenericWebSocketConnections((connections) => {
648743
genericWebSocketConnections.value = connections

0 commit comments

Comments
 (0)