WIP - Mass delete working

This commit is contained in:
Francisco Gaona
2026-01-14 02:28:52 +01:00
parent f094fee192
commit 842376ba15
6 changed files with 197 additions and 32 deletions

View File

@@ -6,6 +6,14 @@ import { useFields, useViewState } from '@/composables/useFieldViews'
import ListView from '@/components/views/ListView.vue'
import DetailView from '@/components/views/DetailViewEnhanced.vue'
import EditView from '@/components/views/EditViewEnhanced.vue'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
const route = useRoute()
const router = useRouter()
@@ -148,8 +156,14 @@ const maxFrontendRecords = computed(() => listConfig.value?.maxFrontendRecords ?
const searchQuery = ref('')
const searchSummary = ref('')
const searchLoading = ref(false)
const deleteDialogOpen = ref(false)
const deleteSubmitting = ref(false)
const pendingDeleteRows = ref<any[]>([])
const deleteSummary = ref<{ deletedIds: string[]; deniedIds: string[] } | null>(null)
const isSearchActive = computed(() => searchQuery.value.trim().length > 0)
const pendingDeleteCount = computed(() => pendingDeleteRows.value.length)
const deniedDeleteCount = computed(() => deleteSummary.value?.deniedIds.length ?? 0)
// Fetch object definition
const fetchObjectDefinition = async () => {
@@ -194,16 +208,42 @@ const handleCreateRelated = (relatedObjectApiName: string, _parentId: string) =>
}
const handleDelete = async (rows: any[]) => {
if (confirm(`Delete ${rows.length} record(s)? This action cannot be undone.`)) {
try {
const ids = rows.map(r => r.id)
await deleteRecords(ids)
pendingDeleteRows.value = rows
deleteSummary.value = null
deleteDialogOpen.value = true
}
const resetDeleteDialog = () => {
deleteDialogOpen.value = false
deleteSubmitting.value = false
pendingDeleteRows.value = []
deleteSummary.value = null
}
const confirmDelete = async () => {
if (pendingDeleteRows.value.length === 0) {
resetDeleteDialog()
return
}
deleteSubmitting.value = true
try {
const ids = pendingDeleteRows.value.map(r => r.id)
const result = await deleteRecords(ids)
const deletedIds = result?.deletedIds ?? []
const deniedIds = result?.deniedIds ?? []
deleteSummary.value = { deletedIds, deniedIds }
if (deniedIds.length === 0) {
resetDeleteDialog()
if (view.value !== 'list') {
await router.push(`/${objectApiName.value.toLowerCase()}/`)
}
} catch (e: any) {
error.value = e.message || 'Failed to delete records'
}
} catch (e: any) {
error.value = e.message || 'Failed to delete records'
} finally {
deleteSubmitting.value = false
}
}
@@ -422,6 +462,46 @@ onMounted(async () => {
@back="handleBack"
/>
</div>
<Dialog v-model:open="deleteDialogOpen">
<DialogContent class="sm:max-w-[520px]">
<DialogHeader>
<DialogTitle>Delete records</DialogTitle>
<DialogDescription>
This action cannot be undone.
</DialogDescription>
</DialogHeader>
<div class="space-y-2 text-sm">
<p>
You are about to delete {{ pendingDeleteCount }} record<span v-if="pendingDeleteCount !== 1">s</span>.
</p>
<p v-if="deleteSummary" class="text-muted-foreground">
Deleted {{ deleteSummary.deletedIds.length }} record<span v-if="deleteSummary.deletedIds.length !== 1">s</span>.
</p>
<p v-if="deniedDeleteCount > 0" class="text-destructive">
{{ deniedDeleteCount }} record<span v-if="deniedDeleteCount !== 1">s</span> could not be deleted due to missing permissions.
</p>
<p v-if="!deleteSummary" class="text-muted-foreground">
Records you do not have permission to delete will be skipped.
</p>
</div>
<DialogFooter>
<Button variant="outline" @click="resetDeleteDialog" :disabled="deleteSubmitting">
{{ deleteSummary ? 'Close' : 'Cancel' }}
</Button>
<Button
v-if="!deleteSummary"
variant="destructive"
@click="confirmDelete"
:disabled="deleteSubmitting"
>
Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</NuxtLayout>
</template>