Merge pull request #69 from shariquerik/custom-bulk-action
feat: Custom Bulk Actions
This commit is contained in:
commit
3f9c23bd4a
@ -4,6 +4,7 @@ from frappe.model import no_value_fields
|
||||
from pypika import Criterion
|
||||
|
||||
from crm.api.views import get_views
|
||||
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@ -239,6 +240,7 @@ def get_list_data(
|
||||
"views": get_views(doctype),
|
||||
"total_count": len(frappe.get_all(doctype, filters=filters)),
|
||||
"row_count": len(data),
|
||||
"form_script": get_form_script(doctype)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -87,11 +87,16 @@
|
||||
</ListRows>
|
||||
<ListSelectBanner>
|
||||
<template #actions="{ selections, unselectAll }">
|
||||
<Button variant="subtle" label="Edit" @click="editValues(selections, unselectAll)">
|
||||
<template #prefix>
|
||||
<EditIcon class="h-3 w-3" />
|
||||
</template>
|
||||
</Button>
|
||||
<Dropdown
|
||||
v-if="bulkActions.length"
|
||||
:options="bulkActions(selections, unselectAll)"
|
||||
>
|
||||
<Button variant="ghost">
|
||||
<template #icon>
|
||||
<FeatherIcon name="more-horizontal" class="h-4 w-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</template>
|
||||
</ListSelectBanner>
|
||||
</ListView>
|
||||
@ -110,7 +115,7 @@
|
||||
v-model:unselectAll="unselectAllAction"
|
||||
doctype="CRM Deal"
|
||||
:selectedValues="selectedValues"
|
||||
@reload="emit('reload')"
|
||||
@reload="list.reload()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -118,7 +123,6 @@
|
||||
import MultipleAvatar from '@/components/MultipleAvatar.vue'
|
||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
||||
import {
|
||||
Avatar,
|
||||
@ -129,8 +133,10 @@ import {
|
||||
ListRowItem,
|
||||
ListSelectBanner,
|
||||
ListFooter,
|
||||
Dropdown,
|
||||
} from 'frappe-ui'
|
||||
import { ref, watch } from 'vue'
|
||||
import { setupBulkActions } from '@/utils'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
rows: {
|
||||
@ -151,9 +157,10 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['loadMore', 'updatePageCount', 'reload'])
|
||||
const emit = defineEmits(['loadMore', 'updatePageCount'])
|
||||
|
||||
const pageLengthCount = defineModel()
|
||||
const list = defineModel('list')
|
||||
|
||||
watch(pageLengthCount, (val, old_value) => {
|
||||
if (val === old_value) return
|
||||
@ -169,4 +176,28 @@ function editValues(selections, unselectAll) {
|
||||
showEditModal.value = true
|
||||
unselectAllAction.value = unselectAll
|
||||
}
|
||||
|
||||
const customBulkActions = ref([])
|
||||
|
||||
function bulkActions(selections, unselectAll) {
|
||||
let actions = [
|
||||
{
|
||||
label: 'Edit',
|
||||
onClick: () => editValues(selections, unselectAll),
|
||||
},
|
||||
]
|
||||
customBulkActions.value.forEach((action) => {
|
||||
actions.push({
|
||||
label: action.label,
|
||||
onClick: () => action.onClick(selections, unselectAll, list.value),
|
||||
})
|
||||
})
|
||||
return actions
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!list.value?.data) return
|
||||
setupBulkActions(list.value.data)
|
||||
customBulkActions.value = list.value?.data?.bulkActions || []
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -96,11 +96,16 @@
|
||||
</ListRows>
|
||||
<ListSelectBanner>
|
||||
<template #actions="{ selections, unselectAll }">
|
||||
<Button variant="subtle" label="Edit" @click="editValues(selections, unselectAll)">
|
||||
<template #prefix>
|
||||
<EditIcon class="h-3 w-3" />
|
||||
</template>
|
||||
</Button>
|
||||
<Dropdown
|
||||
v-if="bulkActions.length"
|
||||
:options="bulkActions(selections, unselectAll)"
|
||||
>
|
||||
<Button variant="ghost">
|
||||
<template #icon>
|
||||
<FeatherIcon name="more-horizontal" class="h-4 w-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</template>
|
||||
</ListSelectBanner>
|
||||
</ListView>
|
||||
@ -119,7 +124,7 @@
|
||||
v-model:unselectAll="unselectAllAction"
|
||||
doctype="CRM Lead"
|
||||
:selectedValues="selectedValues"
|
||||
@reload="emit('reload')"
|
||||
@reload="list.reload()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -127,7 +132,6 @@
|
||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import MultipleAvatar from '@/components/MultipleAvatar.vue'
|
||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
||||
import {
|
||||
Avatar,
|
||||
@ -138,8 +142,10 @@ import {
|
||||
ListSelectBanner,
|
||||
ListRowItem,
|
||||
ListFooter,
|
||||
Dropdown,
|
||||
} from 'frappe-ui'
|
||||
import { ref, watch } from 'vue'
|
||||
import { setupBulkActions } from '@/utils'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
rows: {
|
||||
@ -160,9 +166,10 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['loadMore', 'updatePageCount', 'reload'])
|
||||
const emit = defineEmits(['loadMore', 'updatePageCount'])
|
||||
|
||||
const pageLengthCount = defineModel()
|
||||
const list = defineModel('list')
|
||||
|
||||
watch(pageLengthCount, (val, old_value) => {
|
||||
if (val === old_value) return
|
||||
@ -178,4 +185,28 @@ function editValues(selections, unselectAll) {
|
||||
showEditModal.value = true
|
||||
unselectAllAction.value = unselectAll
|
||||
}
|
||||
|
||||
const customBulkActions = ref([])
|
||||
|
||||
function bulkActions(selections, unselectAll) {
|
||||
let actions = [
|
||||
{
|
||||
label: 'Edit',
|
||||
onClick: () => editValues(selections, unselectAll),
|
||||
},
|
||||
]
|
||||
customBulkActions.value.forEach((action) => {
|
||||
actions.push({
|
||||
label: action.label,
|
||||
onClick: () => action.onClick(selections, unselectAll, list.value),
|
||||
})
|
||||
})
|
||||
return actions
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!list.value?.data) return
|
||||
setupBulkActions(list.value.data)
|
||||
customBulkActions.value = list.value?.data?.bulkActions || []
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<DealsListView
|
||||
v-if="deals.data && rows.length"
|
||||
v-model="deals.data.page_length_count"
|
||||
v-model:list="deals"
|
||||
:rows="rows"
|
||||
:columns="deals.data.columns"
|
||||
:options="{
|
||||
@ -26,7 +27,6 @@
|
||||
}"
|
||||
@loadMore="() => loadMore++"
|
||||
@updatePageCount="(count) => (updatedPageCount = count)"
|
||||
@reload="deals.reload()"
|
||||
/>
|
||||
<div v-else-if="deals.data" class="flex h-full items-center justify-center">
|
||||
<div
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
<LeadsListView
|
||||
v-if="leads.data && rows.length"
|
||||
v-model="leads.data.page_length_count"
|
||||
v-model:list="leads"
|
||||
:rows="rows"
|
||||
:columns="leads.data.columns"
|
||||
:options="{
|
||||
@ -27,7 +28,6 @@
|
||||
}"
|
||||
@loadMore="() => loadMore++"
|
||||
@updatePageCount="(count) => (updatedPageCount = count)"
|
||||
@reload="leads.reload()"
|
||||
/>
|
||||
<div v-else-if="leads.data" class="flex h-full items-center justify-center">
|
||||
<div
|
||||
|
||||
@ -131,6 +131,13 @@ export function setupCustomActions(data, obj) {
|
||||
data._customActions = formScript?.actions || []
|
||||
}
|
||||
|
||||
export function setupBulkActions(data, obj = {}) {
|
||||
if (!data.form_script) return []
|
||||
let script = new Function(data.form_script + '\nreturn setupForm')()
|
||||
let formScript = script(obj)
|
||||
data.bulkActions = formScript?.bulk_actions || []
|
||||
}
|
||||
|
||||
export function errorMessage(title, message) {
|
||||
createToast({
|
||||
title: title || 'Error',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user