fix: added delete option in list view bulk actions for all list view

This commit is contained in:
Shariq Ansari 2024-03-17 12:30:11 +05:30
parent 980defb368
commit d6f8106cfb
10 changed files with 314 additions and 142 deletions

View File

@ -70,15 +70,13 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<Button <Dropdown :options="bulkActions(selections, unselectAll)">
variant="subtle" <Button variant="ghost">
label="Edit" <template #icon>
@click="editValues(selections, unselectAll)" <FeatherIcon name="more-horizontal" class="h-4 w-4" />
> </template>
<template #prefix> </Button>
<EditIcon class="h-3 w-3" /> </Dropdown>
</template>
</Button>
</template> </template>
</ListSelectBanner> </ListSelectBanner>
</ListView> </ListView>
@ -97,13 +95,14 @@
v-model:unselectAll="unselectAllAction" v-model:unselectAll="unselectAllAction"
doctype="Contact" doctype="Contact"
:selectedValues="selectedValues" :selectedValues="selectedValues"
@reload="emit('reload')" @reload="list.reload()"
/> />
</template> </template>
<script setup> <script setup>
import PhoneIcon from '@/components/Icons/PhoneIcon.vue' import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import EditIcon from '@/components/Icons/EditIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue' import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { globalStore } from '@/stores/global'
import { createToast } from '@/utils'
import { import {
Avatar, Avatar,
ListView, ListView,
@ -114,6 +113,8 @@ import {
ListRowItem, ListRowItem,
ListFooter, ListFooter,
Tooltip, Tooltip,
Dropdown,
call,
} from 'frappe-ui' } from 'frappe-ui'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
@ -141,12 +142,14 @@ const props = defineProps({
const emit = defineEmits([ const emit = defineEmits([
'loadMore', 'loadMore',
'updatePageCount', 'updatePageCount',
'reload',
'columnWidthUpdated', 'columnWidthUpdated',
'applyFilter', 'applyFilter',
]) ])
const pageLengthCount = defineModel() const pageLengthCount = defineModel()
const list = defineModel('list')
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => { watch(pageLengthCount, (val, old_value) => {
if (val === old_value) return if (val === old_value) return
@ -162,4 +165,50 @@ function editValues(selections, unselectAll) {
showEditModal.value = true showEditModal.value = true
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'Contact',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
function bulkActions(selections, unselectAll) {
let actions = [
{
label: 'Edit',
onClick: () => editValues(selections, unselectAll),
},
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
]
return actions
}
</script> </script>

View File

@ -98,10 +98,7 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<Dropdown <Dropdown :options="bulkActions(selections, unselectAll)">
v-if="bulkActions.length"
:options="bulkActions(selections, unselectAll)"
>
<Button variant="ghost"> <Button variant="ghost">
<template #icon> <template #icon>
<FeatherIcon name="more-horizontal" class="h-4 w-4" /> <FeatherIcon name="more-horizontal" class="h-4 w-4" />
@ -203,6 +200,38 @@ function editValues(selections, unselectAll) {
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'CRM Deal',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
const customBulkActions = ref([]) const customBulkActions = ref([])
function bulkActions(selections, unselectAll) { function bulkActions(selections, unselectAll) {
@ -211,6 +240,10 @@ function bulkActions(selections, unselectAll) {
label: 'Edit', label: 'Edit',
onClick: () => editValues(selections, unselectAll), onClick: () => editValues(selections, unselectAll),
}, },
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
] ]
customBulkActions.value.forEach((action) => { customBulkActions.value.forEach((action) => {
actions.push({ actions.push({

View File

@ -54,23 +54,13 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<div class="flex gap-2"> <Dropdown :options="bulkActions(selections, unselectAll)">
<Button <Button variant="ghost">
theme="red" <template #icon>
variant="subtle" <FeatherIcon name="more-horizontal" class="h-4 w-4" />
label="Delete"
@click="deleteEmailTemplate(selections, unselectAll)"
/>
<Button
variant="subtle"
label="Edit"
@click="editValues(selections, unselectAll)"
>
<template #prefix>
<EditIcon class="h-3 w-3" />
</template> </template>
</Button> </Button>
</div> </Dropdown>
</template> </template>
</ListSelectBanner> </ListSelectBanner>
</ListView> </ListView>
@ -88,13 +78,13 @@
v-model:unselectAll="unselectAllAction" v-model:unselectAll="unselectAllAction"
doctype="Email Template" doctype="Email Template"
:selectedValues="selectedValues" :selectedValues="selectedValues"
@reload="emit('reload')" @reload="list.reload()"
/> />
</template> </template>
<script setup> <script setup>
import EditIcon from '@/components/Icons/EditIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue' import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { globalStore } from '@/stores/global' import { globalStore } from '@/stores/global'
import { createToast } from '@/utils'
import { import {
ListView, ListView,
ListHeader, ListHeader,
@ -103,6 +93,7 @@ import {
ListSelectBanner, ListSelectBanner,
ListRowItem, ListRowItem,
ListFooter, ListFooter,
Dropdown,
call, call,
Tooltip, Tooltip,
} from 'frappe-ui' } from 'frappe-ui'
@ -133,53 +124,20 @@ const emit = defineEmits([
'loadMore', 'loadMore',
'updatePageCount', 'updatePageCount',
'showEmailTemplate', 'showEmailTemplate',
'reload',
'columnWidthUpdated', 'columnWidthUpdated',
'applyFilter', 'applyFilter',
]) ])
const pageLengthCount = defineModel() const pageLengthCount = defineModel()
const list = defineModel('list')
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => { watch(pageLengthCount, (val, old_value) => {
if (val === old_value) return if (val === old_value) return
emit('updatePageCount', val) emit('updatePageCount', val)
}) })
const { $dialog } = globalStore()
function deleteEmailTemplate(selections, unselectAll) {
let title = 'Delete email template'
let message = 'Are you sure you want to delete this email template?'
if (selections.size > 1) {
title = 'Delete email templates'
message = 'Are you sure you want to delete these email templates?'
}
$dialog({
title: title,
message: message,
actions: [
{
label: 'Delete',
theme: 'red',
variant: 'solid',
async onClick(close) {
for (const selection of selections) {
await call('frappe.client.delete', {
doctype: 'Email Template',
name: selection,
})
}
close()
unselectAll()
emit('reload')
},
},
],
})
}
const showEditModal = ref(false) const showEditModal = ref(false)
const selectedValues = ref([]) const selectedValues = ref([])
const unselectAllAction = ref(() => {}) const unselectAllAction = ref(() => {})
@ -189,4 +147,50 @@ function editValues(selections, unselectAll) {
showEditModal.value = true showEditModal.value = true
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'Email Template',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
function bulkActions(selections, unselectAll) {
let actions = [
{
label: 'Edit',
onClick: () => editValues(selections, unselectAll),
},
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
]
return actions
}
</script> </script>

View File

@ -107,10 +107,7 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<Dropdown <Dropdown :options="bulkActions(selections, unselectAll)">
v-if="bulkActions.length"
:options="bulkActions(selections, unselectAll)"
>
<Button variant="ghost"> <Button variant="ghost">
<template #icon> <template #icon>
<FeatherIcon name="more-horizontal" class="h-4 w-4" /> <FeatherIcon name="more-horizontal" class="h-4 w-4" />
@ -212,6 +209,38 @@ function editValues(selections, unselectAll) {
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'CRM Lead',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
const customBulkActions = ref([]) const customBulkActions = ref([])
function bulkActions(selections, unselectAll) { function bulkActions(selections, unselectAll) {
@ -220,6 +249,10 @@ function bulkActions(selections, unselectAll) {
label: 'Edit', label: 'Edit',
onClick: () => editValues(selections, unselectAll), onClick: () => editValues(selections, unselectAll),
}, },
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
] ]
customBulkActions.value.forEach((action) => { customBulkActions.value.forEach((action) => {
actions.push({ actions.push({

View File

@ -57,15 +57,13 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<Button <Dropdown :options="bulkActions(selections, unselectAll)">
variant="subtle" <Button variant="ghost">
label="Edit" <template #icon>
@click="editValues(selections, unselectAll)" <FeatherIcon name="more-horizontal" class="h-4 w-4" />
> </template>
<template #prefix> </Button>
<EditIcon class="h-3 w-3" /> </Dropdown>
</template>
</Button>
</template> </template>
</ListSelectBanner> </ListSelectBanner>
</ListView> </ListView>
@ -83,12 +81,13 @@
v-model:unselectAll="unselectAllAction" v-model:unselectAll="unselectAllAction"
doctype="CRM Organization" doctype="CRM Organization"
:selectedValues="selectedValues" :selectedValues="selectedValues"
@reload="emit('reload')" @reload="list.reload()"
/> />
</template> </template>
<script setup> <script setup>
import EditIcon from '@/components/Icons/EditIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue' import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { globalStore } from '@/stores/global'
import { createToast } from '@/utils'
import { import {
Avatar, Avatar,
ListView, ListView,
@ -99,6 +98,8 @@ import {
ListRowItem, ListRowItem,
ListFooter, ListFooter,
Tooltip, Tooltip,
Dropdown,
call,
} from 'frappe-ui' } from 'frappe-ui'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
@ -126,12 +127,14 @@ const props = defineProps({
const emit = defineEmits([ const emit = defineEmits([
'loadMore', 'loadMore',
'updatePageCount', 'updatePageCount',
'reload',
'columnWidthUpdated', 'columnWidthUpdated',
'applyFilter', 'applyFilter',
]) ])
const pageLengthCount = defineModel() const pageLengthCount = defineModel()
const list = defineModel('list')
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => { watch(pageLengthCount, (val, old_value) => {
if (val === old_value) return if (val === old_value) return
@ -147,4 +150,50 @@ function editValues(selections, unselectAll) {
showEditModal.value = true showEditModal.value = true
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'CRM Organization',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
function bulkActions(selections, unselectAll) {
let actions = [
{
label: 'Edit',
onClick: () => editValues(selections, unselectAll),
},
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
]
return actions
}
</script> </script>

View File

@ -73,23 +73,13 @@
</ListRows> </ListRows>
<ListSelectBanner> <ListSelectBanner>
<template #actions="{ selections, unselectAll }"> <template #actions="{ selections, unselectAll }">
<div class="flex gap-2"> <Dropdown :options="bulkActions(selections, unselectAll)">
<Button <Button variant="ghost">
theme="red" <template #icon>
variant="subtle" <FeatherIcon name="more-horizontal" class="h-4 w-4" />
label="Delete"
@click="deleteTask(selections, unselectAll)"
/>
<Button
variant="subtle"
label="Edit"
@click="editValues(selections, unselectAll)"
>
<template #prefix>
<EditIcon class="h-3 w-3" />
</template> </template>
</Button> </Button>
</div> </Dropdown>
</template> </template>
</ListSelectBanner> </ListSelectBanner>
</ListView> </ListView>
@ -107,17 +97,17 @@
v-model:unselectAll="unselectAllAction" v-model:unselectAll="unselectAllAction"
doctype="CRM Task" doctype="CRM Task"
:selectedValues="selectedValues" :selectedValues="selectedValues"
@reload="emit('reload')" @reload="list.reload()"
/> />
</template> </template>
<script setup> <script setup>
import TaskStatusIcon from '@/components/Icons/TaskStatusIcon.vue' import TaskStatusIcon from '@/components/Icons/TaskStatusIcon.vue'
import TaskPriorityIcon from '@/components/Icons/TaskPriorityIcon.vue' import TaskPriorityIcon from '@/components/Icons/TaskPriorityIcon.vue'
import CalendarIcon from '@/components/Icons/CalendarIcon.vue' import CalendarIcon from '@/components/Icons/CalendarIcon.vue'
import EditIcon from '@/components/Icons/EditIcon.vue'
import EditValueModal from '@/components/Modals/EditValueModal.vue' import EditValueModal from '@/components/Modals/EditValueModal.vue'
import { dateFormat } from '@/utils' import { dateFormat } from '@/utils'
import { globalStore } from '@/stores/global' import { globalStore } from '@/stores/global'
import { createToast } from '@/utils'
import { import {
Avatar, Avatar,
ListView, ListView,
@ -127,6 +117,7 @@ import {
ListSelectBanner, ListSelectBanner,
ListRowItem, ListRowItem,
ListFooter, ListFooter,
Dropdown,
call, call,
Tooltip, Tooltip,
} from 'frappe-ui' } from 'frappe-ui'
@ -157,53 +148,20 @@ const emit = defineEmits([
'loadMore', 'loadMore',
'updatePageCount', 'updatePageCount',
'showTask', 'showTask',
'reload',
'columnWidthUpdated', 'columnWidthUpdated',
'applyFilter', 'applyFilter',
]) ])
const pageLengthCount = defineModel() const pageLengthCount = defineModel()
const list = defineModel('list')
const { $dialog } = globalStore()
watch(pageLengthCount, (val, old_value) => { watch(pageLengthCount, (val, old_value) => {
if (val === old_value) return if (val === old_value) return
emit('updatePageCount', val) emit('updatePageCount', val)
}) })
const { $dialog } = globalStore()
function deleteTask(selections, unselectAll) {
let title = 'Delete task'
let message = 'Are you sure you want to delete this task?'
if (selections.size > 1) {
title = 'Delete tasks'
message = 'Are you sure you want to delete these tasks?'
}
$dialog({
title: title,
message: message,
actions: [
{
label: 'Delete',
theme: 'red',
variant: 'solid',
async onClick(close) {
for (const selection of selections) {
await call('frappe.client.delete', {
doctype: 'CRM Task',
name: selection,
})
}
close()
unselectAll()
emit('reload')
},
},
],
})
}
const showEditModal = ref(false) const showEditModal = ref(false)
const selectedValues = ref([]) const selectedValues = ref([])
const unselectAllAction = ref(() => {}) const unselectAllAction = ref(() => {})
@ -213,4 +171,50 @@ function editValues(selections, unselectAll) {
showEditModal.value = true showEditModal.value = true
unselectAllAction.value = unselectAll unselectAllAction.value = unselectAll
} }
function deleteValues(selections, unselectAll) {
$dialog({
title: 'Delete',
message: `Are you sure you want to delete ${selections.size} item${
selections.size > 1 ? 's' : ''
}?`,
variant: 'danger',
actions: [
{
label: 'Delete',
variant: 'solid',
theme: 'red',
onClick: (close) => {
call('frappe.desk.reportview.delete_items', {
items: JSON.stringify(Array.from(selections)),
doctype: 'CRM Task',
}).then(() => {
createToast({
title: 'Deleted successfully',
icon: 'check',
iconClasses: 'text-green-600',
})
unselectAll()
list.value.reload()
close()
})
},
},
],
})
}
function bulkActions(selections, unselectAll) {
let actions = [
{
label: 'Edit',
onClick: () => editValues(selections, unselectAll),
},
{
label: 'Delete',
onClick: () => deleteValues(selections, unselectAll),
},
]
return actions
}
</script> </script>

View File

@ -20,6 +20,7 @@
<ContactsListView <ContactsListView
v-if="contacts.data && rows.length" v-if="contacts.data && rows.length"
v-model="contacts.data.page_length_count" v-model="contacts.data.page_length_count"
v-model:list="contacts"
:rows="rows" :rows="rows"
:columns="contacts.data.columns" :columns="contacts.data.columns"
:options="{ :options="{
@ -31,7 +32,6 @@
@loadMore="() => loadMore++" @loadMore="() => loadMore++"
@columnWidthUpdated="() => triggerResize++" @columnWidthUpdated="() => triggerResize++"
@updatePageCount="(count) => (updatedPageCount = count)" @updatePageCount="(count) => (updatedPageCount = count)"
@reload="contacts.reload()"
@applyFilter="(data) => viewControls.applyFilter(data)" @applyFilter="(data) => viewControls.applyFilter(data)"
/> />
<div <div

View File

@ -20,6 +20,7 @@
<EmailTemplatesListView <EmailTemplatesListView
v-if="emailTemplates.data && rows.length" v-if="emailTemplates.data && rows.length"
v-model="emailTemplates.data.page_length_count" v-model="emailTemplates.data.page_length_count"
v-model:list="emailTemplates"
:rows="rows" :rows="rows"
:columns="emailTemplates.data.columns" :columns="emailTemplates.data.columns"
:options="{ :options="{
@ -32,7 +33,6 @@
@columnWidthUpdated="() => triggerResize++" @columnWidthUpdated="() => triggerResize++"
@updatePageCount="(count) => (updatedPageCount = count)" @updatePageCount="(count) => (updatedPageCount = count)"
@showEmailTemplate="showEmailTemplate" @showEmailTemplate="showEmailTemplate"
@reload="emailTemplates.reload()"
@applyFilter="(data) => viewControls.applyFilter(data)" @applyFilter="(data) => viewControls.applyFilter(data)"
/> />
<div <div

View File

@ -24,6 +24,7 @@
<OrganizationsListView <OrganizationsListView
v-if="organizations.data && rows.length" v-if="organizations.data && rows.length"
v-model="organizations.data.page_length_count" v-model="organizations.data.page_length_count"
v-model:list="organizations"
:rows="rows" :rows="rows"
:columns="organizations.data.columns" :columns="organizations.data.columns"
:options="{ :options="{
@ -35,7 +36,6 @@
@loadMore="() => loadMore++" @loadMore="() => loadMore++"
@columnWidthUpdated="() => triggerResize++" @columnWidthUpdated="() => triggerResize++"
@updatePageCount="(count) => (updatedPageCount = count)" @updatePageCount="(count) => (updatedPageCount = count)"
@reload="organizations.reload()"
@applyFilter="(data) => viewControls.applyFilter(data)" @applyFilter="(data) => viewControls.applyFilter(data)"
/> />
<div <div

View File

@ -20,6 +20,7 @@
<TasksListView <TasksListView
v-if="tasks.data && rows.length" v-if="tasks.data && rows.length"
v-model="tasks.data.page_length_count" v-model="tasks.data.page_length_count"
v-model:list="tasks"
:rows="rows" :rows="rows"
:columns="tasks.data.columns" :columns="tasks.data.columns"
:options="{ :options="{
@ -32,7 +33,6 @@
@columnWidthUpdated="() => triggerResize++" @columnWidthUpdated="() => triggerResize++"
@updatePageCount="(count) => (updatedPageCount = count)" @updatePageCount="(count) => (updatedPageCount = count)"
@showTask="showTask" @showTask="showTask"
@reload="tasks.reload()"
@applyFilter="(data) => viewControls.applyFilter(data)" @applyFilter="(data) => viewControls.applyFilter(data)"
/> />
<div v-else-if="tasks.data" class="flex h-full items-center justify-center"> <div v-else-if="tasks.data" class="flex h-full items-center justify-center">