mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-24 01:31:44 +00:00
Modal template for deletion confirmation (#2190)
## Description <!-- What changed? Why? (the code + comments should speak for itself on the "how") --> <!-- Fun screenshots or a cool video or something are super helpful as well. If this touches platform-specific behavior, this is where test evidence should be collected. --> <!-- Any issues this pull request closes or pull requests this supersedes should be linked with `Closes #issuenumber`. --> This adds a template modal that can be used for confirming that the user wants to delete something. The main goal is to reduce complication and duplicated code, and standardize the way we handle deletion. closes #2175 ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [x] This PR has been [linted](https://docs.photonvision.org/en/latest/docs/contributing/linting.html). - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Devolian <devondoyle@outlook.com>
This commit is contained in:
@@ -7,15 +7,13 @@ import {
|
||||
PVCameraInfo,
|
||||
type PVCSICameraInfo,
|
||||
type PVFileCameraInfo,
|
||||
type PVUsbCameraInfo,
|
||||
type UiCameraConfiguration
|
||||
type PVUsbCameraInfo
|
||||
} from "@/types/SettingTypes";
|
||||
import { axiosPost, getResolutionString } from "@/lib/PhotonUtils";
|
||||
import PhotonCameraStream from "@/components/app/photon-camera-stream.vue";
|
||||
import PvInput from "@/components/common/pv-input.vue";
|
||||
import PvDeleteModal from "@/components/common/pv-delete-modal.vue";
|
||||
import PvCameraInfoCard from "@/components/common/pv-camera-info-card.vue";
|
||||
import PvCameraMatchCard from "@/components/common/pv-camera-match-card.vue";
|
||||
import type { WebsocketCameraSettingsUpdate } from "@/types/WebsocketDataTypes";
|
||||
import { useTheme } from "vuetify";
|
||||
|
||||
const theme = useTheme();
|
||||
@@ -55,17 +53,14 @@ const deactivateModule = (cameraUniqueName: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
const deletingCamera = ref(false);
|
||||
const deleteThisCamera = (cameraName: string) => {
|
||||
if (deletingCamera.value) return;
|
||||
deletingCamera.value = true;
|
||||
const payload = {
|
||||
cameraUniqueName: cameraName
|
||||
};
|
||||
const confirmDeleteDialog = ref({ show: false, nickname: "", cameraUniqueName: "" });
|
||||
const deletingCamera = ref<string | null>(null);
|
||||
|
||||
axiosPost("/utils/nukeOneCamera", "delete a camera", payload).finally(() => {
|
||||
setCameraDeleting(null);
|
||||
deletingCamera.value = false;
|
||||
const deleteThisCamera = (cameraUniqueName: string) => {
|
||||
if (deletingCamera.value) return;
|
||||
deletingCamera.value = cameraUniqueName;
|
||||
axiosPost("/utils/nukeOneCamera", "delete a camera", { cameraUniqueName: cameraUniqueName }).finally(() => {
|
||||
deletingCamera.value = null;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -110,15 +105,6 @@ const setCameraView = (camera: PVCameraInfo | null, isConnected: boolean | null)
|
||||
viewingCamera.value = [camera, isConnected];
|
||||
};
|
||||
|
||||
const viewingDeleteCamera = ref(false);
|
||||
const cameraToDelete = ref<UiCameraConfiguration | WebsocketCameraSettingsUpdate | null>(null);
|
||||
const setCameraDeleting = (camera: UiCameraConfiguration | WebsocketCameraSettingsUpdate | null) => {
|
||||
yesDeleteMySettingsText.value = "";
|
||||
viewingDeleteCamera.value = camera !== null;
|
||||
cameraToDelete.value = camera;
|
||||
};
|
||||
const yesDeleteMySettingsText = ref("");
|
||||
|
||||
/**
|
||||
* Get the connection-type-specific camera info from the given PVCameraInfo object.
|
||||
*/
|
||||
@@ -274,8 +260,16 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
|
||||
class="pa-0"
|
||||
color="error"
|
||||
style="width: 100%"
|
||||
:loading="module.uniqueName === deletingCamera"
|
||||
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
|
||||
@click="setCameraDeleting(module)"
|
||||
@click="
|
||||
() =>
|
||||
(confirmDeleteDialog = {
|
||||
show: true,
|
||||
nickname: module.nickname,
|
||||
cameraUniqueName: module.uniqueName
|
||||
})
|
||||
"
|
||||
>
|
||||
<v-icon size="x-large">mdi-trash-can-outline</v-icon>
|
||||
</v-btn>
|
||||
@@ -360,8 +354,16 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
|
||||
class="pa-0"
|
||||
color="error"
|
||||
style="width: 100%"
|
||||
:loading="module.uniqueName === deletingCamera"
|
||||
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
|
||||
@click="setCameraDeleting(module)"
|
||||
@click="
|
||||
() =>
|
||||
(confirmDeleteDialog = {
|
||||
show: true,
|
||||
nickname: module.nickname,
|
||||
cameraUniqueName: module.uniqueName
|
||||
})
|
||||
"
|
||||
>
|
||||
<v-icon size="x-large">mdi-trash-can-outline</v-icon>
|
||||
</v-btn>
|
||||
@@ -465,43 +467,13 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Camera delete modal -->
|
||||
<v-dialog v-model="viewingDeleteCamera" width="800">
|
||||
<v-card v-if="cameraToDelete !== null" class="dialog-container" color="surface" flat>
|
||||
<v-card-title> Delete {{ cameraToDelete.nickname }}? </v-card-title>
|
||||
<v-card-text class="pb-10px">
|
||||
Are you sure you want to delete "{{ cameraToDelete.nickname }}"? This cannot be undone.
|
||||
</v-card-text>
|
||||
<v-card-text class="pt-0 pb-10px">
|
||||
<pv-input
|
||||
v-model="yesDeleteMySettingsText"
|
||||
:label="'Type "' + cameraToDelete.nickname + '":'"
|
||||
:label-cols="6"
|
||||
:input-cols="6"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions class="pa-5 pt-0">
|
||||
<v-btn
|
||||
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
|
||||
color="primary"
|
||||
class="text-black"
|
||||
@click="cameraToDelete = null"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
:disabled="yesDeleteMySettingsText.toLowerCase() !== cameraToDelete.nickname.toLowerCase()"
|
||||
:loading="deletingCamera"
|
||||
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
|
||||
@click="deleteThisCamera(cameraToDelete.uniqueName)"
|
||||
>
|
||||
<v-icon start class="open-icon" size="large"> mdi-trash-can-outline </v-icon>
|
||||
<span class="open-label">Delete</span>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<pv-delete-modal
|
||||
v-model="confirmDeleteDialog.show"
|
||||
title="Delete Camera"
|
||||
:description="`Are you sure you want to delete the camera '${useCameraSettingsStore().currentCameraSettings.nickname}'? This action cannot be undone.`"
|
||||
:expected-confirmation-text="confirmDeleteDialog.nickname"
|
||||
:on-confirm="() => deleteThisCamera(confirmDeleteDialog.cameraUniqueName)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user