2023-08-21 01:51:35 -04:00
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { inject, ref } from "vue";
|
|
|
|
|
import { useStateStore } from "@/stores/StateStore";
|
2023-10-17 16:32:59 -04:00
|
|
|
import PvSelect from "@/components/common/pv-select.vue";
|
2025-05-06 18:21:41 -04:00
|
|
|
import PvInput from "@/components/common/pv-input.vue";
|
2023-08-21 01:51:35 -04:00
|
|
|
import axios from "axios";
|
|
|
|
|
|
|
|
|
|
const restartProgram = () => {
|
2023-08-31 16:56:58 -04:00
|
|
|
axios
|
|
|
|
|
.post("/utils/restartProgram")
|
|
|
|
|
.then(() => {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "Successfully sent program restart request",
|
|
|
|
|
color: "success"
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
// This endpoint always return 204 regardless of outcome
|
|
|
|
|
if (error.request) {
|
2023-08-21 01:51:35 -04:00
|
|
|
useStateStore().showSnackbarMessage({
|
2023-08-31 16:56:58 -04:00
|
|
|
message: "Error while trying to process the request! The backend didn't respond.",
|
|
|
|
|
color: "error"
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
2023-08-31 16:56:58 -04:00
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "An error occurred while trying to process the request.",
|
|
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-08-21 01:51:35 -04:00
|
|
|
};
|
|
|
|
|
const restartDevice = () => {
|
2023-08-31 16:56:58 -04:00
|
|
|
axios
|
|
|
|
|
.post("/utils/restartDevice")
|
|
|
|
|
.then(() => {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "Successfully dispatched the restart command. It isn't confirmed if a device restart will occur.",
|
|
|
|
|
color: "success"
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
if (error.response) {
|
2023-08-21 01:51:35 -04:00
|
|
|
useStateStore().showSnackbarMessage({
|
2023-08-31 16:56:58 -04:00
|
|
|
message: "The backend is unable to fulfil the request to restart the device.",
|
|
|
|
|
color: "error"
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
2023-08-31 16:56:58 -04:00
|
|
|
} else if (error.request) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "Error while trying to process the request! The backend didn't respond.",
|
|
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "An error occurred while trying to process the request.",
|
|
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-08-21 01:51:35 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const address = inject<string>("backendHost");
|
|
|
|
|
|
|
|
|
|
const offlineUpdate = ref();
|
|
|
|
|
const openOfflineUpdatePrompt = () => {
|
|
|
|
|
offlineUpdate.value.click();
|
|
|
|
|
};
|
2024-01-02 11:03:16 -05:00
|
|
|
const handleOfflineUpdate = () => {
|
|
|
|
|
const files = offlineUpdate.value.files;
|
|
|
|
|
if (files.length === 0) return;
|
2023-10-17 09:02:13 -04:00
|
|
|
|
|
|
|
|
const formData = new FormData();
|
2024-01-02 11:03:16 -05:00
|
|
|
formData.append("jarData", files[0]);
|
2023-10-17 09:02:13 -04:00
|
|
|
|
2023-08-31 16:56:58 -04:00
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "New Software Upload in Progress...",
|
|
|
|
|
color: "secondary",
|
|
|
|
|
timeout: -1
|
|
|
|
|
});
|
2023-08-21 01:51:35 -04:00
|
|
|
|
2023-08-31 16:56:58 -04:00
|
|
|
axios
|
|
|
|
|
.post("/utils/offlineUpdate", formData, {
|
|
|
|
|
headers: { "Content-Type": "multipart/form-data" },
|
|
|
|
|
onUploadProgress: ({ progress }) => {
|
|
|
|
|
const uploadPercentage = (progress || 0) * 100.0;
|
|
|
|
|
if (uploadPercentage < 99.5) {
|
2023-08-21 01:51:35 -04:00
|
|
|
useStateStore().showSnackbarMessage({
|
2023-08-31 16:56:58 -04:00
|
|
|
message: "New Software Upload in Process, " + uploadPercentage.toFixed(2) + "% complete",
|
|
|
|
|
color: "secondary",
|
|
|
|
|
timeout: -1
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
2023-08-31 16:56:58 -04:00
|
|
|
message: "Installing uploaded software...",
|
|
|
|
|
color: "secondary",
|
|
|
|
|
timeout: -1
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
|
|
|
|
}
|
2023-08-31 16:56:58 -04:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.then((response) => {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: response.data.text || response.data,
|
|
|
|
|
color: "success"
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
2023-08-31 16:56:58 -04:00
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
if (error.response) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
color: "error",
|
|
|
|
|
message: error.response.data.text || error.response.data
|
|
|
|
|
});
|
|
|
|
|
} else if (error.request) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
color: "error",
|
|
|
|
|
message: "Error while trying to process the request! The backend didn't respond."
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
color: "error",
|
|
|
|
|
message: "An error occurred while trying to process the request."
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-08-21 01:51:35 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exportLogFile = ref();
|
|
|
|
|
const openExportLogsPrompt = () => {
|
|
|
|
|
exportLogFile.value.click();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const exportSettings = ref();
|
|
|
|
|
const openExportSettingsPrompt = () => {
|
|
|
|
|
exportSettings.value.click();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum ImportType {
|
|
|
|
|
AllSettings,
|
|
|
|
|
HardwareConfig,
|
|
|
|
|
HardwareSettings,
|
2023-10-17 10:20:00 -04:00
|
|
|
NetworkConfig,
|
|
|
|
|
ApriltagFieldLayout
|
2023-08-21 01:51:35 -04:00
|
|
|
}
|
|
|
|
|
const showImportDialog = ref(false);
|
2025-05-06 18:21:41 -04:00
|
|
|
const importType = ref<ImportType | undefined>(undefined);
|
2023-10-17 09:02:13 -04:00
|
|
|
const importFile = ref<File | null>(null);
|
2023-08-21 01:51:35 -04:00
|
|
|
const handleSettingsImport = () => {
|
2025-05-06 18:21:41 -04:00
|
|
|
if (importType.value === undefined || importFile.value === null) return;
|
2023-08-21 01:51:35 -04:00
|
|
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append("data", importFile.value);
|
|
|
|
|
|
2023-10-17 09:02:13 -04:00
|
|
|
let settingsEndpoint: string;
|
2023-08-21 01:51:35 -04:00
|
|
|
switch (importType.value) {
|
|
|
|
|
case ImportType.HardwareConfig:
|
|
|
|
|
settingsEndpoint = "/hardwareConfig";
|
|
|
|
|
break;
|
|
|
|
|
case ImportType.HardwareSettings:
|
|
|
|
|
settingsEndpoint = "/hardwareSettings";
|
|
|
|
|
break;
|
|
|
|
|
case ImportType.NetworkConfig:
|
|
|
|
|
settingsEndpoint = "/networkConfig";
|
|
|
|
|
break;
|
2023-10-17 10:20:00 -04:00
|
|
|
case ImportType.ApriltagFieldLayout:
|
|
|
|
|
settingsEndpoint = "/aprilTagFieldLayout";
|
|
|
|
|
break;
|
2023-10-17 09:02:13 -04:00
|
|
|
default:
|
|
|
|
|
case ImportType.AllSettings:
|
|
|
|
|
settingsEndpoint = "";
|
|
|
|
|
break;
|
2023-08-21 01:51:35 -04:00
|
|
|
}
|
|
|
|
|
|
2023-08-31 16:56:58 -04:00
|
|
|
axios
|
|
|
|
|
.post(`/settings${settingsEndpoint}`, formData, {
|
|
|
|
|
headers: { "Content-Type": "multipart/form-data" }
|
|
|
|
|
})
|
|
|
|
|
.then((response) => {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: response.data.text || response.data,
|
|
|
|
|
color: "success"
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
if (error.response) {
|
2023-08-21 01:51:35 -04:00
|
|
|
useStateStore().showSnackbarMessage({
|
2023-08-31 16:56:58 -04:00
|
|
|
color: "error",
|
|
|
|
|
message: error.response.data.text || error.response.data
|
2023-08-21 01:51:35 -04:00
|
|
|
});
|
2023-08-31 16:56:58 -04:00
|
|
|
} else if (error.request) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
color: "error",
|
|
|
|
|
message: "Error while trying to process the request! The backend didn't respond."
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
color: "error",
|
|
|
|
|
message: "An error occurred while trying to process the request."
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-08-21 01:51:35 -04:00
|
|
|
|
|
|
|
|
showImportDialog.value = false;
|
2025-05-06 18:21:41 -04:00
|
|
|
importType.value = undefined;
|
2023-08-21 01:51:35 -04:00
|
|
|
importFile.value = null;
|
|
|
|
|
};
|
2024-10-24 20:48:02 -07:00
|
|
|
|
|
|
|
|
const showFactoryReset = ref(false);
|
|
|
|
|
const expected = "Delete Everything";
|
|
|
|
|
const yesDeleteMySettingsText = ref("");
|
|
|
|
|
const nukePhotonConfigDirectory = () => {
|
|
|
|
|
axios
|
|
|
|
|
.post("/utils/nukeConfigDirectory")
|
|
|
|
|
.then(() => {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "Successfully dispatched the reset command. Waiting for backend to start back up",
|
|
|
|
|
color: "success"
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
if (error.response) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
2025-06-30 22:02:44 -05:00
|
|
|
message: "The backend is unable to fulfill the request to reset the device.",
|
2024-10-24 20:48:02 -07:00
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
} else if (error.request) {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "Error while trying to process the request! The backend didn't respond.",
|
|
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
useStateStore().showSnackbarMessage({
|
|
|
|
|
message: "An error occurred while trying to process the request.",
|
|
|
|
|
color: "error"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
showFactoryReset.value = false;
|
|
|
|
|
};
|
2023-08-21 01:51:35 -04:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-card class="mb-3" style="background-color: #006492">
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-card-title class="pa-6">Device Control</v-card-title>
|
|
|
|
|
<div class="pa-6 pt-0">
|
2023-08-21 01:51:35 -04:00
|
|
|
<v-row>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" lg="4" md="6">
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-btn color="error" @click="restartProgram">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-restart </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Restart PhotonVision</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" lg="4" md="6">
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-btn color="error" @click="restartDevice">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-restart-alert </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Restart Device</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" lg="4">
|
|
|
|
|
<v-btn color="secondary" @click="openOfflineUpdatePrompt">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-upload </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Offline Update</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
2023-08-31 16:56:58 -04:00
|
|
|
<input ref="offlineUpdate" type="file" accept=".jar" style="display: none" @change="handleOfflineUpdate" />
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-col>
|
|
|
|
|
</v-row>
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-divider class="mt-3 pb-3" />
|
2023-08-21 01:51:35 -04:00
|
|
|
<v-row>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" sm="6">
|
|
|
|
|
<v-btn color="secondary" @click="() => (showImportDialog = true)">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-import </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Import Settings</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
<v-dialog
|
|
|
|
|
v-model="showImportDialog"
|
|
|
|
|
width="600"
|
2025-05-06 18:21:41 -04:00
|
|
|
@update:modelValue="
|
2023-08-31 16:56:58 -04:00
|
|
|
() => {
|
2025-05-06 18:21:41 -04:00
|
|
|
importType = undefined;
|
2023-08-31 16:56:58 -04:00
|
|
|
importFile = null;
|
|
|
|
|
}
|
|
|
|
|
"
|
2023-08-21 01:51:35 -04:00
|
|
|
>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-card color="primary" dark>
|
2023-08-21 01:51:35 -04:00
|
|
|
<v-card-title>Import Settings</v-card-title>
|
|
|
|
|
<v-card-text>
|
|
|
|
|
Upload and apply previously saved or exported PhotonVision settings to this device
|
2023-10-17 16:32:59 -04:00
|
|
|
<v-row class="mt-6 ml-4">
|
|
|
|
|
<pv-select
|
2023-08-21 01:51:35 -04:00
|
|
|
v-model="importType"
|
|
|
|
|
label="Type"
|
|
|
|
|
tooltip="Select the type of settings file you are trying to upload"
|
2023-10-17 10:20:00 -04:00
|
|
|
:items="[
|
|
|
|
|
'All Settings',
|
|
|
|
|
'Hardware Config',
|
|
|
|
|
'Hardware Settings',
|
|
|
|
|
'Network Config',
|
|
|
|
|
'Apriltag Layout'
|
|
|
|
|
]"
|
2023-08-21 01:51:35 -04:00
|
|
|
:select-cols="10"
|
2023-10-17 09:02:13 -04:00
|
|
|
style="width: 100%"
|
2023-08-21 01:51:35 -04:00
|
|
|
/>
|
|
|
|
|
</v-row>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-row class="mt-6 ml-4 mr-8">
|
2023-08-21 01:51:35 -04:00
|
|
|
<v-file-input
|
2023-10-17 09:02:13 -04:00
|
|
|
v-model="importFile"
|
2025-05-06 18:21:41 -04:00
|
|
|
:disabled="importType === undefined"
|
|
|
|
|
:error-messages="importType === undefined ? 'Settings type not selected' : ''"
|
2023-08-21 01:51:35 -04:00
|
|
|
:accept="importType === ImportType.AllSettings ? '.zip' : '.json'"
|
|
|
|
|
/>
|
|
|
|
|
</v-row>
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-row class="mt-12 ml-8 mr-8 mb-1" style="display: flex; align-items: center; justify-content: center">
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-btn color="secondary" :disabled="importFile === null" @click="handleSettingsImport">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-import </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Import Settings</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
</v-row>
|
|
|
|
|
</v-card-text>
|
|
|
|
|
</v-card>
|
|
|
|
|
</v-dialog>
|
|
|
|
|
</v-col>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" sm="6">
|
|
|
|
|
<v-btn color="secondary" @click="openExportSettingsPrompt">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-export </v-icon>
|
2024-01-02 11:03:16 -05:00
|
|
|
<span class="open-label">Export Settings</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
<a
|
|
|
|
|
ref="exportSettings"
|
|
|
|
|
style="color: black; text-decoration: none; display: none"
|
|
|
|
|
:href="`http://${address}/api/settings/photonvision_config.zip`"
|
|
|
|
|
download="photonvision-settings.zip"
|
|
|
|
|
target="_blank"
|
|
|
|
|
/>
|
|
|
|
|
</v-col>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" sm="6">
|
|
|
|
|
<v-btn color="secondary" @click="openExportLogsPrompt">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-download </v-icon>
|
2024-08-31 18:22:07 -04:00
|
|
|
<span class="open-label">Download logs</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
|
|
|
|
|
<!-- Special hidden link that gets 'clicked' when the user exports journalctl logs -->
|
|
|
|
|
<a
|
|
|
|
|
ref="exportLogFile"
|
|
|
|
|
style="color: black; text-decoration: none; display: none"
|
2023-10-20 08:04:19 -04:00
|
|
|
:href="`http://${address}/api/utils/photonvision-journalctl.txt`"
|
2023-08-21 01:51:35 -04:00
|
|
|
download="photonvision-journalctl.txt"
|
|
|
|
|
target="_blank"
|
|
|
|
|
/>
|
|
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
2023-08-31 16:56:58 -04:00
|
|
|
<v-col cols="12" sm="6">
|
|
|
|
|
<v-btn color="secondary" @click="useStateStore().showLogModal = true">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-eye </v-icon>
|
2024-08-31 18:22:07 -04:00
|
|
|
<span class="open-label">View program logs</span>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
|
|
|
|
</v-row>
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-divider class="mt-3 pb-3" />
|
2024-10-24 20:48:02 -07:00
|
|
|
<v-row>
|
|
|
|
|
<v-col cols="12">
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-btn color="error" @click="() => (showFactoryReset = true)">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-skull-crossbones </v-icon>
|
2024-10-24 20:48:02 -07:00
|
|
|
<span class="open-icon">
|
|
|
|
|
{{
|
2025-05-06 18:21:41 -04:00
|
|
|
$vuetify.display.mdAndUp
|
2025-01-07 08:45:39 -05:00
|
|
|
? "Factory Reset PhotonVision and delete EVERYTHING"
|
2024-10-24 20:48:02 -07:00
|
|
|
: "Factory Reset PhotonVision"
|
|
|
|
|
}}
|
|
|
|
|
</span>
|
|
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
|
|
|
|
</v-row>
|
2023-08-21 01:51:35 -04:00
|
|
|
</div>
|
2024-10-24 20:48:02 -07:00
|
|
|
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-dialog v-model="showFactoryReset" width="800" dark>
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-card color="primary" class="pa-3" flat>
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-card-title style="justify-content: center" class="pb-6">
|
2024-10-24 20:48:02 -07:00
|
|
|
<span class="open-label">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon end color="error" class="open-icon ma-1">mdi-nuke</v-icon>
|
2024-10-24 20:48:02 -07:00
|
|
|
Factory Reset PhotonVision
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon end color="error" class="open-icon ma-1">mdi-nuke</v-icon>
|
2024-10-24 20:48:02 -07:00
|
|
|
</span>
|
|
|
|
|
</v-card-title>
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-card-text class="pt-3">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-row class="align-center text-white">
|
2025-01-07 08:45:39 -05:00
|
|
|
<v-col cols="12" md="6">
|
|
|
|
|
<span class="mt-3"> This will delete ALL OF YOUR SETTINGS and restart PhotonVision. </span>
|
|
|
|
|
</v-col>
|
|
|
|
|
<v-col cols="12" md="6">
|
|
|
|
|
<v-btn color="secondary" style="float: right" @click="openExportSettingsPrompt">
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-export </v-icon>
|
2025-01-07 08:45:39 -05:00
|
|
|
<span class="open-label">Backup Settings</span>
|
|
|
|
|
<a
|
|
|
|
|
ref="exportSettings"
|
|
|
|
|
style="color: black; text-decoration: none; display: none"
|
|
|
|
|
:href="`http://${address}/api/settings/photonvision_config.zip`"
|
|
|
|
|
download="photonvision-settings.zip"
|
|
|
|
|
target="_blank"
|
|
|
|
|
/>
|
|
|
|
|
</v-btn>
|
|
|
|
|
</v-col>
|
|
|
|
|
</v-row>
|
|
|
|
|
</v-card-text>
|
|
|
|
|
<v-card-text>
|
|
|
|
|
<pv-input
|
|
|
|
|
v-model="yesDeleteMySettingsText"
|
|
|
|
|
:label="'Type "' + expected + '":'"
|
|
|
|
|
:label-cols="6"
|
|
|
|
|
:input-cols="6"
|
|
|
|
|
/>
|
|
|
|
|
</v-card-text>
|
|
|
|
|
<v-card-text>
|
|
|
|
|
<v-btn
|
|
|
|
|
color="error"
|
|
|
|
|
:disabled="yesDeleteMySettingsText.toLowerCase() !== expected.toLowerCase()"
|
|
|
|
|
@click="nukePhotonConfigDirectory"
|
|
|
|
|
>
|
2025-05-06 18:21:41 -04:00
|
|
|
<v-icon start class="open-icon"> mdi-trash-can-outline </v-icon>
|
2025-01-07 08:45:39 -05:00
|
|
|
<span class="open-label">
|
2025-05-06 18:21:41 -04:00
|
|
|
{{ $vuetify.display.mdAndUp ? "Delete everything, I have backed up what I need" : "Delete Everything" }}
|
2025-01-07 08:45:39 -05:00
|
|
|
</span>
|
|
|
|
|
</v-btn>
|
|
|
|
|
</v-card-text>
|
2024-10-24 20:48:02 -07:00
|
|
|
</v-card>
|
|
|
|
|
</v-dialog>
|
2023-08-21 01:51:35 -04:00
|
|
|
</v-card>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.v-btn {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
2024-01-02 11:03:16 -05:00
|
|
|
@media only screen and (max-width: 351px) {
|
|
|
|
|
.open-icon {
|
|
|
|
|
margin: 0 !important;
|
|
|
|
|
}
|
|
|
|
|
.open-label {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-21 01:51:35 -04:00
|
|
|
</style>
|