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