fixed dialogs behaviour

This commit is contained in:
tdv
2025-10-07 11:43:49 +03:00
parent a404a37a60
commit 79dbd98ca6
7 changed files with 57 additions and 51 deletions

View File

@@ -1,40 +1,42 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenu, DropdownMenuItem, import { ref } from 'vue'
DropdownMenuTrigger, DropdownMenuContent } from '@/components/ui/dropdown-menu'; import {
import { Ellipsis } from 'lucide-vue-next'; DropdownMenu, DropdownMenuItem,
import EditDeviceDialog from './EditDeviceDialog.vue'; DropdownMenuTrigger, DropdownMenuContent
import DeleteDeviceDialog from './DeleteDeviceDialog.vue'; } from '@/components/ui/dropdown-menu'
import { ref } from 'vue'; import EditDeviceDialog from './EditDeviceDialog.vue'
import DeleteDeviceDialog from './DeleteDeviceDialog.vue'
import { Ellipsis } from 'lucide-vue-next'
import type { Device } from '@/lib/interfaces'
// import { api } from '@/lib/api'
const props = defineProps<{ row: Device }>() // ← accept full row
const isEditOpen = ref(false) const isEditOpen = ref(false)
const isDeleteOpen = ref(false) const isDeleteOpen = ref(false)
// your actual delete logic
function onDeleteConfirmed() { function onDeleteConfirmed() {
// e.g. await api.deleteUser(props.userId) // await api.delete(`/devices/${encodeURIComponent(props.row.guid)}`)
isDeleteOpen.value = false isDeleteOpen.value = false
} }
function onEditConfirm() { function onEditConfirm() {
isEditOpen.value = false isEditOpen.value = false
} }
</script> </script>
<template> <template>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<button class="p-2 rounded hover:bg-muted"> <button class="p-2 rounded hover:bg-muted">
<Ellipsis/> <Ellipsis />
</button> </button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-[160px]"> <DropdownMenuContent align="end" class="w-[160px]">
<DropdownMenuItem @click.prevent="isEditOpen = true"> <DropdownMenuItem @click.prevent="isEditOpen = true">Rename</DropdownMenuItem>
Rename <DropdownMenuItem @click.prevent="isDeleteOpen = true">Delete</DropdownMenuItem>
</DropdownMenuItem>
<DropdownMenuItem @click.prevent="isDeleteOpen = true">
Delete
</DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<EditDeviceDialog v-model:modelValue="isEditOpen"@confirm="onEditConfirm()" />
<DeleteDeviceDialog v-model:modelValue="isDeleteOpen" @confirm="onDeleteConfirmed" /> <EditDeviceDialog v-model:modelValue="isEditOpen" :device="props.row" @confirm="onEditConfirm" />
<DeleteDeviceDialog v-model:modelValue="isDeleteOpen" :device="props.row" @confirm="onDeleteConfirmed" />
</template> </template>

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'
import { import {
DropdownMenu, DropdownMenuItem, DropdownMenu, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuContent DropdownMenuTrigger, DropdownMenuContent
} from '@/components/ui/dropdown-menu' } from '@/components/ui/dropdown-menu'
import EditUserDialog from './EditUserDialog.vue' import EditUserDialog from './EditUserDialog.vue'
import DeleteUserDialog from './DeleteUserDialog.vue' import DeleteUserDialog from './DeleteUserDialog.vue'
import { Ellipsis } from 'lucide-vue-next' import { Ellipsis } from 'lucide-vue-next'
import { ref } from 'vue' import { api } from '@/lib/api'
import { api } from '@/lib/api' // <-- use your axios/fetch wrapper import type { Users } from '@/lib/interfaces'
const props = defineProps<{ userId: string }>() const props = defineProps<{ row: Users }>() // ← accept full row
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'deleted', id: string): void (e: 'deleted', id: string): void
(e: 'error', err: unknown): void (e: 'error', err: unknown): void
@@ -20,18 +20,17 @@ const isEditOpen = ref(false)
const isDeleteOpen = ref(false) const isDeleteOpen = ref(false)
const deleting = ref(false) const deleting = ref(false)
// DELETE /users/:id
async function onDeleteConfirmed() { async function onDeleteConfirmed() {
try { try {
deleting.value = true deleting.value = true
await api.delete(`/users/${encodeURIComponent(props.userId)}`) await api.delete(`/users/${encodeURIComponent(String(props.row.id))}`)
emit('deleted', props.userId) emit('deleted', String(props.row.id))
} catch (err) { } catch (err) {
console.error(err) console.error(err)
emit('error', err) emit('error', err)
} finally { } finally {
deleting.value = false deleting.value = false
// The dialog already closes itself on confirm; nothing else required. // DeleteUserDialog closes itself after confirm
} }
} }
@@ -49,21 +48,13 @@ function onEditConfirm() {
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-[160px]"> <DropdownMenuContent align="end" class="w-[160px]">
<DropdownMenuItem @click.prevent="isEditOpen = true"> <DropdownMenuItem @click.prevent="isEditOpen = true">Edit</DropdownMenuItem>
Edit
</DropdownMenuItem>
<DropdownMenuItem @click.prevent="isDeleteOpen = true" :disabled="deleting"> <DropdownMenuItem @click.prevent="isDeleteOpen = true" :disabled="deleting">
Delete Delete
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<EditUserDialog v-model:modelValue="isEditOpen" @confirm="onEditConfirm()" /> <EditUserDialog v-model:modelValue="isEditOpen" @confirm="onEditConfirm" />
<DeleteUserDialog v-model:modelValue="isDeleteOpen" :loading="deleting" @confirm="onDeleteConfirmed" />
<!-- pass 'deleting' to disable the confirm button during request -->
<DeleteUserDialog
v-model:modelValue="isDeleteOpen"
:loading="deleting"
@confirm="onDeleteConfirmed"
/>
</template> </template>

View File

@@ -96,6 +96,7 @@ const table = useVueTable({
<component <component
:is="props.dropdownComponent" :is="props.dropdownComponent"
:row="row.original" :row="row.original"
:key="row.id"
/> />
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@@ -26,7 +26,7 @@ const emit = defineEmits<{
<template> <template>
<AlertDialog <AlertDialog
:open="props.modelValue" :open="props.modelValue"
@openChange="(v: boolean) => emit('update:modelValue', v)" @update:open="(v: boolean) => emit('update:modelValue', v)"
> >
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader> <AlertDialogHeader>

View File

@@ -24,7 +24,7 @@ const emit = defineEmits<{
<template> <template>
<AlertDialog <AlertDialog
:open="props.modelValue" :open="props.modelValue"
@openChange="(v: boolean) => emit('update:modelValue', v)" @update:open="(v: boolean) => emit('update:modelValue', v)"
> >
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader> <AlertDialogHeader>

View File

@@ -10,9 +10,10 @@ import {
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { defineProps, defineEmits } from 'vue' import { defineProps, defineEmits, ref, watch } from 'vue'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import AssignDevice from './AssignDevice.vue' import AssignDevice from './AssignDevice.vue'
import type { Device } from '@/lib/interfaces'
// 1) runtime props so Vue + TS agree // 1) runtime props so Vue + TS agree
const props = defineProps({ const props = defineProps({
@@ -20,6 +21,7 @@ const props = defineProps({
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
required: true, required: true,
}, },
device: { type: Object as PropType<Device>, required: false },
}) })
// 2) two emits: v-model and confirm // 2) two emits: v-model and confirm
@@ -28,6 +30,16 @@ const emit = defineEmits<{
(e: 'confirm'): void (e: 'confirm'): void
}>() }>()
const name = ref('')
// when device changes or dialog opens, update local value
watch(
() => props.device,
(dev) => {
name.value = dev?.devicename ?? ''
},
{ immediate: true }
)
function onSave() { function onSave() {
emit('confirm') emit('confirm')
// close the dialog // close the dialog
@@ -38,7 +50,7 @@ function onSave() {
<template> <template>
<Dialog <Dialog
:open="props.modelValue" :open="props.modelValue"
@openChange="(v: boolean) => emit('update:modelValue', v)" @update:open="(v: boolean) => emit('update:modelValue', v)"
> >
<DialogContent class="sm:max-w-[425px]"> <DialogContent class="sm:max-w-[425px]">
<DialogHeader> <DialogHeader>
@@ -51,11 +63,11 @@ function onSave() {
<div class="grid gap-4 py-4"> <div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4"> <div class="grid grid-cols-4 items-center gap-4">
<Label for="guid" class="text-right">GUID</Label> <Label for="guid" class="text-right">GUID</Label>
<Input id="guid" class="col-span-3" /> <p id="guid" class="col-span-3"> {{ props.device?.guid }}</p>
</div> </div>
<div class="grid grid-cols-4 items-center gap-4"> <div class="grid grid-cols-4 items-center gap-4">
<Label for="name" class="text-right">Name</Label> <Label for="name" class="text-right">Name</Label>
<Input id="name" class="col-span-3" /> <Input id="name" class="col-span-3" v-model="name" />
</div> </div>
<div class="grid grid-cols-4 items-center gap-4"> <div class="grid grid-cols-4 items-center gap-4">
<Label for="users" class="text-right">Allowed users</Label> <Label for="users" class="text-right">Allowed users</Label>

View File

@@ -38,7 +38,7 @@ function onSave() {
<template> <template>
<Dialog <Dialog
:open="props.modelValue" :open="props.modelValue"
@openChange="(v: boolean) => emit('update:modelValue', v)" @update:open="(v: boolean) => emit('update:modelValue', v)"
> >
<DialogContent class="sm:max-w-[425px]"> <DialogContent class="sm:max-w-[425px]">
<DialogHeader> <DialogHeader>