Merge pull request #194 from frappe/develop
chore: Merge develop to main
This commit is contained in:
commit
53cc1df965
@ -376,7 +376,7 @@ def get_type(field):
|
|||||||
return "read_only"
|
return "read_only"
|
||||||
return field.fieldtype.lower()
|
return field.fieldtype.lower()
|
||||||
|
|
||||||
def get_assigned_users(doctype, name):
|
def get_assigned_users(doctype, name, default_assigned_to=None):
|
||||||
assigned_users = frappe.get_all(
|
assigned_users = frappe.get_all(
|
||||||
"ToDo",
|
"ToDo",
|
||||||
fields=["allocated_to"],
|
fields=["allocated_to"],
|
||||||
@ -388,7 +388,12 @@ def get_assigned_users(doctype, name):
|
|||||||
pluck="allocated_to",
|
pluck="allocated_to",
|
||||||
)
|
)
|
||||||
|
|
||||||
return list(set(assigned_users))
|
users = list(set(assigned_users))
|
||||||
|
|
||||||
|
# if users is empty, add default_assigned_to
|
||||||
|
if not users and default_assigned_to:
|
||||||
|
users = [default_assigned_to]
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@ -30,7 +30,7 @@ def get_deal(name):
|
|||||||
deal["doctype_fields"], deal["all_fields"] = get_doctype_fields("CRM Deal", name)
|
deal["doctype_fields"], deal["all_fields"] = get_doctype_fields("CRM Deal", name)
|
||||||
deal["doctype"] = "CRM Deal"
|
deal["doctype"] = "CRM Deal"
|
||||||
deal["_form_script"] = get_form_script('CRM Deal')
|
deal["_form_script"] = get_form_script('CRM Deal')
|
||||||
deal["_assign"] = get_assigned_users("CRM Deal", deal.name)
|
deal["_assign"] = get_assigned_users("CRM Deal", deal.name, deal.owner)
|
||||||
return deal
|
return deal
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@ -108,8 +108,8 @@ class CRMDeal(Document):
|
|||||||
"""
|
"""
|
||||||
sla = get_sla(self)
|
sla = get_sla(self)
|
||||||
if not sla:
|
if not sla:
|
||||||
self.first_responded_on = None
|
# self.first_responded_on = None
|
||||||
self.first_response_time = None
|
# self.first_response_time = None
|
||||||
return
|
return
|
||||||
self.sla = sla.name
|
self.sla = sla.name
|
||||||
|
|
||||||
|
|||||||
@ -18,5 +18,5 @@ def get_lead(name):
|
|||||||
lead["doctype_fields"], lead["all_fields"] = get_doctype_fields("CRM Lead", name)
|
lead["doctype_fields"], lead["all_fields"] = get_doctype_fields("CRM Lead", name)
|
||||||
lead["doctype"] = "CRM Lead"
|
lead["doctype"] = "CRM Lead"
|
||||||
lead["_form_script"] = get_form_script('CRM Lead')
|
lead["_form_script"] = get_form_script('CRM Lead')
|
||||||
lead["_assign"] = get_assigned_users("CRM Lead", lead.name)
|
lead["_assign"] = get_assigned_users("CRM Lead", lead.name, lead.owner)
|
||||||
return lead
|
return lead
|
||||||
|
|||||||
@ -234,8 +234,8 @@ class CRMLead(Document):
|
|||||||
"""
|
"""
|
||||||
sla = get_sla(self)
|
sla = get_sla(self)
|
||||||
if not sla:
|
if not sla:
|
||||||
self.first_responded_on = None
|
# self.first_responded_on = None
|
||||||
self.first_response_time = None
|
# self.first_response_time = None
|
||||||
return
|
return
|
||||||
self.sla = sla.name
|
self.sla = sla.name
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,16 @@
|
|||||||
</template>
|
</template>
|
||||||
<span>{{ __('New Email') }}</span>
|
<span>{{ __('New Email') }}</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
v-else-if="title == 'Comments'"
|
||||||
|
variant="solid"
|
||||||
|
@click="$refs.emailBox.showComment = true"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<FeatherIcon name="plus" class="h-4 w-4" />
|
||||||
|
</template>
|
||||||
|
<span>{{ __('New Comment') }}</span>
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
v-else-if="title == 'Calls'"
|
v-else-if="title == 'Calls'"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
@ -146,6 +156,62 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="title == 'Comments'" class="activity pb-5">
|
||||||
|
<div v-for="(comment, i) in activities">
|
||||||
|
<div class="grid grid-cols-[30px_minmax(auto,_1fr)] gap-4 px-10">
|
||||||
|
<div
|
||||||
|
class="relative flex justify-center after:absolute after:left-[50%] after:top-0 after:-z-10 after:border-l after:border-gray-200"
|
||||||
|
:class="i != activities.length - 1 ? 'after:h-full' : 'after:h-4'"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="z-10 flex h-7 w-7 items-center justify-center rounded bg-gray-100"
|
||||||
|
>
|
||||||
|
<CommentIcon class="text-gray-800" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4" :id="comment.name">
|
||||||
|
<div
|
||||||
|
class="mb-0.5 flex items-start justify-stretch gap-2 py-1.5 text-base"
|
||||||
|
>
|
||||||
|
<div class="inline-flex flex-wrap gap-1 text-gray-600">
|
||||||
|
<span class="font-medium text-gray-800">
|
||||||
|
{{ comment.owner_name }}
|
||||||
|
</span>
|
||||||
|
<span>{{ __('added a') }}</span>
|
||||||
|
<span class="max-w-xs truncate font-medium text-gray-800">
|
||||||
|
{{ __('comment') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ml-auto whitespace-nowrap">
|
||||||
|
<Tooltip
|
||||||
|
:text="dateFormat(comment.creation, dateTooltipFormat)"
|
||||||
|
>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
{{ __(timeAgo(comment.creation)) }}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="cursor-pointer rounded bg-gray-50 px-4 py-3 text-base leading-6 transition-all duration-300 ease-in-out"
|
||||||
|
>
|
||||||
|
<div class="prose-f" v-html="comment.content" />
|
||||||
|
<div
|
||||||
|
v-if="comment.attachments.length"
|
||||||
|
class="mt-2 flex flex-wrap gap-2"
|
||||||
|
>
|
||||||
|
<AttachmentItem
|
||||||
|
v-for="a in comment.attachments"
|
||||||
|
:key="a.file_url"
|
||||||
|
:label="a.file_name"
|
||||||
|
:url="a.file_url"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else-if="title == 'Tasks'" class="activity px-10 pb-5">
|
<div v-else-if="title == 'Tasks'" class="activity px-10 pb-5">
|
||||||
<div v-for="(task, i) in activities">
|
<div v-for="(task, i) in activities">
|
||||||
<div
|
<div
|
||||||
@ -756,6 +822,11 @@
|
|||||||
:label="__('New Email')"
|
:label="__('New Email')"
|
||||||
@click="$refs.emailBox.show = true"
|
@click="$refs.emailBox.show = true"
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
v-else-if="title == 'Comments'"
|
||||||
|
:label="__('New Comment')"
|
||||||
|
@click="$refs.emailBox.showComment = true"
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
v-else-if="title == 'Tasks'"
|
v-else-if="title == 'Tasks'"
|
||||||
:label="__('Create Task')"
|
:label="__('Create Task')"
|
||||||
@ -764,7 +835,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<CommunicationArea
|
<CommunicationArea
|
||||||
ref="emailBox"
|
ref="emailBox"
|
||||||
v-if="['Emails', 'Activity'].includes(title)"
|
v-if="['Emails', 'Comments', 'Activity'].includes(title)"
|
||||||
v-model="doc"
|
v-model="doc"
|
||||||
v-model:reload="reload_email"
|
v-model:reload="reload_email"
|
||||||
:doctype="doctype"
|
:doctype="doctype"
|
||||||
@ -983,6 +1054,11 @@ const defaultActions = computed(() => {
|
|||||||
label: __('New Email'),
|
label: __('New Email'),
|
||||||
onClick: () => (emailBox.value.show = true),
|
onClick: () => (emailBox.value.show = true),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: h(CommentIcon, { class: 'h-4 w-4' }),
|
||||||
|
label: __('New Comment'),
|
||||||
|
onClick: () => (emailBox.value.showComment = true),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: h(PhoneIcon, { class: 'h-4 w-4' }),
|
icon: h(PhoneIcon, { class: 'h-4 w-4' }),
|
||||||
label: __('Make a Call'),
|
label: __('Make a Call'),
|
||||||
@ -1027,6 +1103,11 @@ const activities = computed(() => {
|
|||||||
activities = all_activities.data.versions.filter(
|
activities = all_activities.data.versions.filter(
|
||||||
(activity) => activity.activity_type === 'communication'
|
(activity) => activity.activity_type === 'communication'
|
||||||
)
|
)
|
||||||
|
} else if (props.title == 'Comments') {
|
||||||
|
if (!all_activities.data?.versions) return []
|
||||||
|
activities = all_activities.data.versions.filter(
|
||||||
|
(activity) => activity.activity_type === 'comment'
|
||||||
|
)
|
||||||
} else if (props.title == 'Calls') {
|
} else if (props.title == 'Calls') {
|
||||||
if (!all_activities.data?.calls) return []
|
if (!all_activities.data?.calls) return []
|
||||||
return sortByCreation(all_activities.data.calls)
|
return sortByCreation(all_activities.data.calls)
|
||||||
@ -1089,6 +1170,8 @@ const emptyText = computed(() => {
|
|||||||
let text = 'No Activities'
|
let text = 'No Activities'
|
||||||
if (props.title == 'Emails') {
|
if (props.title == 'Emails') {
|
||||||
text = 'No Email Communications'
|
text = 'No Email Communications'
|
||||||
|
} else if (props.title == 'Comments') {
|
||||||
|
text = 'No Comments'
|
||||||
} else if (props.title == 'Calls') {
|
} else if (props.title == 'Calls') {
|
||||||
text = 'No Call Logs'
|
text = 'No Call Logs'
|
||||||
} else if (props.title == 'Notes') {
|
} else if (props.title == 'Notes') {
|
||||||
@ -1105,6 +1188,8 @@ const emptyTextIcon = computed(() => {
|
|||||||
let icon = ActivityIcon
|
let icon = ActivityIcon
|
||||||
if (props.title == 'Emails') {
|
if (props.title == 'Emails') {
|
||||||
icon = EmailIcon
|
icon = EmailIcon
|
||||||
|
} else if (props.title == 'Comments') {
|
||||||
|
icon = CommentIcon
|
||||||
} else if (props.title == 'Calls') {
|
} else if (props.title == 'Calls') {
|
||||||
icon = PhoneIcon
|
icon = PhoneIcon
|
||||||
} else if (props.title == 'Notes') {
|
} else if (props.title == 'Notes') {
|
||||||
|
|||||||
@ -248,5 +248,5 @@ function toggleCommentBox() {
|
|||||||
showCommentBox.value = !showCommentBox.value
|
showCommentBox.value = !showCommentBox.value
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ show: showEmailBox, editor: newEmailEditor })
|
defineExpose({ show: showEmailBox, showComment: showCommentBox, editor: newEmailEditor })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { gemoji } from 'gemoji'
|
import { gemoji } from 'gemoji'
|
||||||
import { Popover } from 'frappe-ui'
|
import { Popover } from 'frappe-ui'
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const emoji = defineModel()
|
const emoji = defineModel()
|
||||||
@ -109,9 +109,5 @@ function randomInt(min, max) {
|
|||||||
return Math.floor(Math.random() * (max - min + 1) + min)
|
return Math.floor(Math.random() * (max - min + 1) + min)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!emoji.value) setRandom()
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({ setRandom })
|
defineExpose({ setRandom })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
205
frontend/src/components/ListBulkActions.vue
Normal file
205
frontend/src/components/ListBulkActions.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<EditValueModal
|
||||||
|
v-model="showEditModal"
|
||||||
|
:doctype="doctype"
|
||||||
|
:selectedValues="selectedValues"
|
||||||
|
@reload="reload"
|
||||||
|
/>
|
||||||
|
<AssignmentModal
|
||||||
|
v-if="selectedValues"
|
||||||
|
:docs="selectedValues"
|
||||||
|
:doctype="doctype"
|
||||||
|
v-model="showAssignmentModal"
|
||||||
|
v-model:assignees="bulkAssignees"
|
||||||
|
@reload="reload"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
||||||
|
import AssignmentModal from '@/components/Modals/AssignmentModal.vue'
|
||||||
|
import { setupListActions, createToast } from '@/utils'
|
||||||
|
import { globalStore } from '@/stores/global'
|
||||||
|
import { call } from 'frappe-ui'
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
doctype: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
hideEdit: false,
|
||||||
|
hideDelete: false,
|
||||||
|
hideAssign: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const list = defineModel()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { $dialog } = globalStore()
|
||||||
|
|
||||||
|
const showEditModal = ref(false)
|
||||||
|
const selectedValues = ref([])
|
||||||
|
const unselectAllAction = ref(() => {})
|
||||||
|
|
||||||
|
function editValues(selections, unselectAll) {
|
||||||
|
selectedValues.value = selections
|
||||||
|
showEditModal.value = true
|
||||||
|
unselectAllAction.value = unselectAll
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteValues(selections, unselectAll) {
|
||||||
|
$dialog({
|
||||||
|
title: __('Delete'),
|
||||||
|
message: __('Are you sure you want to delete {0} item(s)?', [
|
||||||
|
selections.size,
|
||||||
|
]),
|
||||||
|
variant: 'solid',
|
||||||
|
theme: 'red',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: __('Delete'),
|
||||||
|
variant: 'solid',
|
||||||
|
theme: 'red',
|
||||||
|
onClick: (close) => {
|
||||||
|
call('frappe.desk.reportview.delete_items', {
|
||||||
|
items: JSON.stringify(Array.from(selections)),
|
||||||
|
doctype: props.doctype,
|
||||||
|
}).then(() => {
|
||||||
|
createToast({
|
||||||
|
title: __('Deleted successfully'),
|
||||||
|
icon: 'check',
|
||||||
|
iconClasses: 'text-green-600',
|
||||||
|
})
|
||||||
|
unselectAll()
|
||||||
|
list.value.reload()
|
||||||
|
close()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showAssignmentModal = ref(false)
|
||||||
|
const bulkAssignees = ref([])
|
||||||
|
|
||||||
|
function assignValues(selections, unselectAll) {
|
||||||
|
showAssignmentModal.value = true
|
||||||
|
selectedValues.value = selections
|
||||||
|
unselectAllAction.value = unselectAll
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAssignemnts(selections, unselectAll) {
|
||||||
|
$dialog({
|
||||||
|
title: __('Clear Assignment'),
|
||||||
|
message: __('Are you sure you want to clear assignment for {0} item(s)?', [
|
||||||
|
selections.size,
|
||||||
|
]),
|
||||||
|
variant: 'solid',
|
||||||
|
theme: 'red',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: __('Clear Assignment'),
|
||||||
|
variant: 'solid',
|
||||||
|
theme: 'red',
|
||||||
|
onClick: (close) => {
|
||||||
|
call('frappe.desk.form.assign_to.remove_multiple', {
|
||||||
|
doctype: props.doctype,
|
||||||
|
names: JSON.stringify(Array.from(selections)),
|
||||||
|
ignore_permissions: true,
|
||||||
|
}).then(() => {
|
||||||
|
createToast({
|
||||||
|
title: __('Assignment cleared successfully'),
|
||||||
|
icon: 'check',
|
||||||
|
iconClasses: 'text-green-600',
|
||||||
|
})
|
||||||
|
reload(unselectAll)
|
||||||
|
close()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const customBulkActions = ref([])
|
||||||
|
const customListActions = ref([])
|
||||||
|
|
||||||
|
function bulkActions(selections, unselectAll) {
|
||||||
|
let actions = []
|
||||||
|
|
||||||
|
if (!props.options.hideEdit) {
|
||||||
|
actions.push({
|
||||||
|
label: __('Edit'),
|
||||||
|
onClick: () => editValues(selections, unselectAll),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.options.hideDelete) {
|
||||||
|
actions.push({
|
||||||
|
label: __('Delete'),
|
||||||
|
onClick: () => deleteValues(selections, unselectAll),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.options.hideAssign) {
|
||||||
|
actions.push({
|
||||||
|
label: __('Assign To'),
|
||||||
|
onClick: () => assignValues(selections, unselectAll),
|
||||||
|
})
|
||||||
|
actions.push({
|
||||||
|
label: __('Clear Assignment'),
|
||||||
|
onClick: () => clearAssignemnts(selections, unselectAll),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
customBulkActions.value.forEach((action) => {
|
||||||
|
actions.push({
|
||||||
|
label: __(action.label),
|
||||||
|
onClick: () =>
|
||||||
|
action.onClick({
|
||||||
|
list: list.value,
|
||||||
|
selections,
|
||||||
|
unselectAll,
|
||||||
|
call,
|
||||||
|
createToast,
|
||||||
|
$dialog,
|
||||||
|
router,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload(unselectAll) {
|
||||||
|
unselectAllAction.value?.()
|
||||||
|
unselectAll?.()
|
||||||
|
list.value?.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!list.value?.data) return
|
||||||
|
setupListActions(list.value.data, {
|
||||||
|
list: list.value,
|
||||||
|
call,
|
||||||
|
createToast,
|
||||||
|
$dialog,
|
||||||
|
router,
|
||||||
|
})
|
||||||
|
customBulkActions.value = list.value?.data?.bulkActions || []
|
||||||
|
customListActions.value = list.value?.data?.listActions || []
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
bulkActions,
|
||||||
|
customListActions,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -80,7 +80,9 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown
|
||||||
|
:options="listBulkActionsRef.bulkActions(selections, unselectAll)"
|
||||||
|
>
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -95,8 +97,18 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
|
<ListBulkActions
|
||||||
|
ref="listBulkActionsRef"
|
||||||
|
v-model="list"
|
||||||
|
doctype="CRM Call Log"
|
||||||
|
:options="{
|
||||||
|
hideEdit: true,
|
||||||
|
hideAssign: true,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -108,12 +120,8 @@ import {
|
|||||||
ListFooter,
|
ListFooter,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { setupListActions, createToast } from '@/utils'
|
import { ref, watch } from 'vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { onMounted, ref, watch } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -146,89 +154,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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)
|
||||||
})
|
})
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
const listBulkActionsRef = ref(null)
|
||||||
$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 Call Log',
|
|
||||||
}).then(() => {
|
|
||||||
createToast({
|
|
||||||
title: 'Deleted successfully',
|
|
||||||
icon: 'check',
|
|
||||||
iconClasses: 'text-green-600',
|
|
||||||
})
|
|
||||||
unselectAll()
|
|
||||||
list.value.reload()
|
|
||||||
close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const customBulkActions = ref([])
|
|
||||||
const customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: 'Delete',
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
customBulkActions.value.forEach((action) => {
|
|
||||||
actions.push({
|
|
||||||
label: action.label,
|
|
||||||
onClick: () =>
|
|
||||||
action.onClick({
|
|
||||||
list: list.value,
|
|
||||||
selections,
|
|
||||||
unselectAll,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -82,7 +82,9 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown
|
||||||
|
:options="listBulkActionsRef.bulkActions(selections, unselectAll)"
|
||||||
|
>
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -98,19 +100,18 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions
|
||||||
v-model="showEditModal"
|
ref="listBulkActionsRef"
|
||||||
v-model:unselectAll="unselectAllAction"
|
v-model="list"
|
||||||
doctype="Contact"
|
doctype="Contact"
|
||||||
:selectedValues="selectedValues"
|
:options="{
|
||||||
@reload="list.reload()"
|
hideAssign: true,
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { setupListActions, createToast } from '@/utils'
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -122,10 +123,8 @@ import {
|
|||||||
ListFooter,
|
ListFooter,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -158,87 +157,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
// customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -114,7 +114,9 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown
|
||||||
|
:options="listBulkActionsRef.bulkActions(selections, unselectAll)"
|
||||||
|
>
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -130,20 +132,14 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions ref="listBulkActionsRef" v-model="list" doctype="CRM Deal" />
|
||||||
v-model="showEditModal"
|
|
||||||
v-model:unselectAll="unselectAllAction"
|
|
||||||
doctype="CRM Deal"
|
|
||||||
:selectedValues="selectedValues"
|
|
||||||
@reload="list.reload()"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
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 EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -154,13 +150,9 @@ import {
|
|||||||
ListSelectBanner,
|
ListSelectBanner,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { setupListActions, createToast } from '@/utils'
|
import { ref, watch } from 'vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { onMounted, ref, watch } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -193,103 +185,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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 customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
customBulkActions.value.forEach((action) => {
|
|
||||||
actions.push({
|
|
||||||
label: __(action.label),
|
|
||||||
onClick: () =>
|
|
||||||
action.onClick({
|
|
||||||
list: list.value,
|
|
||||||
selections,
|
|
||||||
unselectAll,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -69,7 +69,7 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown :options="listBulkActionsRef.bulkActions(selections, unselectAll)">
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -84,18 +84,17 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions
|
||||||
v-model="showEditModal"
|
ref="listBulkActionsRef"
|
||||||
v-model:unselectAll="unselectAllAction"
|
v-model="list"
|
||||||
doctype="Email Template"
|
doctype="Email Template"
|
||||||
:selectedValues="selectedValues"
|
:options="{
|
||||||
@reload="list.reload()"
|
hideAssign: true,
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { setupListActions, createToast } from '@/utils'
|
|
||||||
import {
|
import {
|
||||||
ListView,
|
ListView,
|
||||||
ListHeader,
|
ListHeader,
|
||||||
@ -105,11 +104,9 @@ import {
|
|||||||
ListRowItem,
|
ListRowItem,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -143,87 +140,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
// customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -123,7 +123,7 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown :options="listBulkActionsRef.bulkActions(selections, unselectAll)">
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -139,20 +139,14 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions ref="listBulkActionsRef" v-model="list" doctype="CRM Lead" />
|
||||||
v-model="showEditModal"
|
|
||||||
v-model:unselectAll="unselectAllAction"
|
|
||||||
doctype="CRM Lead"
|
|
||||||
:selectedValues="selectedValues"
|
|
||||||
@reload="list.reload()"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
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 EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -163,13 +157,9 @@ import {
|
|||||||
ListRowItem,
|
ListRowItem,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { setupListActions, createToast } from '@/utils'
|
import { ref, watch } from 'vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { onMounted, ref, watch } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -202,103 +192,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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 customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
customBulkActions.value.forEach((action) => {
|
|
||||||
actions.push({
|
|
||||||
label: __(action.label),
|
|
||||||
onClick: () =>
|
|
||||||
action.onClick({
|
|
||||||
list: list.value,
|
|
||||||
selections,
|
|
||||||
unselectAll,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -69,7 +69,9 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown
|
||||||
|
:options="listBulkActionsRef.bulkActions(selections, unselectAll)"
|
||||||
|
>
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -84,18 +86,17 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions
|
||||||
v-model="showEditModal"
|
ref="listBulkActionsRef"
|
||||||
v-model:unselectAll="unselectAllAction"
|
v-model="list"
|
||||||
doctype="CRM Organization"
|
doctype="CRM Organization"
|
||||||
:selectedValues="selectedValues"
|
:options="{
|
||||||
@reload="list.reload()"
|
hideAssign: true,
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { setupListActions, createToast } from '@/utils'
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -107,10 +108,8 @@ import {
|
|||||||
ListFooter,
|
ListFooter,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -143,87 +142,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
// customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -82,7 +82,7 @@
|
|||||||
</ListRows>
|
</ListRows>
|
||||||
<ListSelectBanner>
|
<ListSelectBanner>
|
||||||
<template #actions="{ selections, unselectAll }">
|
<template #actions="{ selections, unselectAll }">
|
||||||
<Dropdown :options="bulkActions(selections, unselectAll)">
|
<Dropdown :options="listBulkActionsRef.bulkActions(selections, unselectAll)">
|
||||||
<Button icon="more-horizontal" variant="ghost" />
|
<Button icon="more-horizontal" variant="ghost" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</template>
|
</template>
|
||||||
@ -97,22 +97,21 @@
|
|||||||
}"
|
}"
|
||||||
@loadMore="emit('loadMore')"
|
@loadMore="emit('loadMore')"
|
||||||
/>
|
/>
|
||||||
<EditValueModal
|
<ListBulkActions
|
||||||
v-model="showEditModal"
|
ref="listBulkActionsRef"
|
||||||
v-model:unselectAll="unselectAllAction"
|
v-model="list"
|
||||||
doctype="CRM Task"
|
doctype="CRM Task"
|
||||||
:selectedValues="selectedValues"
|
:options="{
|
||||||
@reload="list.reload()"
|
hideAssign: true,
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</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 EditValueModal from '@/components/Modals/EditValueModal.vue'
|
import ListBulkActions from '@/components/ListBulkActions.vue'
|
||||||
import { dateFormat } from '@/utils'
|
import { dateFormat } from '@/utils'
|
||||||
import { globalStore } from '@/stores/global'
|
|
||||||
import { setupListActions, createToast } from '@/utils'
|
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
ListView,
|
ListView,
|
||||||
@ -123,11 +122,9 @@ import {
|
|||||||
ListRowItem,
|
ListRowItem,
|
||||||
ListFooter,
|
ListFooter,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
call,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'frappe-ui'
|
} from 'frappe-ui'
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rows: {
|
rows: {
|
||||||
@ -161,87 +158,14 @@ const emit = defineEmits([
|
|||||||
const pageLengthCount = defineModel()
|
const pageLengthCount = defineModel()
|
||||||
const list = defineModel('list')
|
const list = defineModel('list')
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
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 showEditModal = ref(false)
|
const listBulkActionsRef = ref(null)
|
||||||
const selectedValues = ref([])
|
|
||||||
const unselectAllAction = ref(() => {})
|
|
||||||
|
|
||||||
function editValues(selections, unselectAll) {
|
|
||||||
selectedValues.value = selections
|
|
||||||
showEditModal.value = true
|
|
||||||
unselectAllAction.value = unselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
|
||||||
$dialog({
|
|
||||||
title: __('Delete'),
|
|
||||||
message: __('Are you sure you want to delete {0} item(s)?', [
|
|
||||||
selections.size,
|
|
||||||
]),
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const customListActions = ref([])
|
|
||||||
|
|
||||||
function bulkActions(selections, unselectAll) {
|
|
||||||
let actions = [
|
|
||||||
{
|
|
||||||
label: __('Edit'),
|
|
||||||
onClick: () => editValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Delete'),
|
|
||||||
onClick: () => deleteValues(selections, unselectAll),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (!list.value?.data) return
|
|
||||||
setupListActions(list.value.data, {
|
|
||||||
list: list.value,
|
|
||||||
call,
|
|
||||||
createToast,
|
|
||||||
$dialog,
|
|
||||||
router,
|
|
||||||
})
|
|
||||||
// customBulkActions.value = list.value?.data?.bulkActions || []
|
|
||||||
customListActions.value = list.value?.data?.listActions || []
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
customListActions,
|
customListActions: listBulkActionsRef.value?.customListActions,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
value=""
|
value=""
|
||||||
doctype="User"
|
doctype="User"
|
||||||
@change="(option) => addValue(option) && ($refs.input.value = '')"
|
@change="(option) => addValue(option) && ($refs.input.value = '')"
|
||||||
|
:placeholder="__('John Doe')"
|
||||||
:hideMe="true"
|
:hideMe="true"
|
||||||
>
|
>
|
||||||
<template #item-prefix="{ option }">
|
<template #item-prefix="{ option }">
|
||||||
@ -83,8 +84,18 @@ const props = defineProps({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
docs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
doctype: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['reload'])
|
||||||
|
|
||||||
const show = defineModel()
|
const show = defineModel()
|
||||||
const assignees = defineModel('assignees')
|
const assignees = defineModel('assignees')
|
||||||
const oldAssignees = ref([])
|
const oldAssignees = ref([])
|
||||||
@ -101,7 +112,7 @@ const removeValue = (value) => {
|
|||||||
|
|
||||||
const owner = computed(() => {
|
const owner = computed(() => {
|
||||||
if (!props.doc) return ''
|
if (!props.doc) return ''
|
||||||
if (props.doc.doctype == 'CRM Lead') return props.doc.lead_owner
|
if (props.doctype == 'CRM Lead') return props.doc.lead_owner
|
||||||
return props.doc.deal_owner
|
return props.doc.deal_owner
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -137,7 +148,7 @@ function updateAssignees() {
|
|||||||
if (removedAssignees.length) {
|
if (removedAssignees.length) {
|
||||||
for (let a of removedAssignees) {
|
for (let a of removedAssignees) {
|
||||||
call('frappe.desk.form.assign_to.remove', {
|
call('frappe.desk.form.assign_to.remove', {
|
||||||
doctype: props.doc.doctype,
|
doctype: props.doctype,
|
||||||
name: props.doc.name,
|
name: props.doc.name,
|
||||||
assign_to: a,
|
assign_to: a,
|
||||||
})
|
})
|
||||||
@ -145,11 +156,23 @@ function updateAssignees() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addedAssignees.length) {
|
if (addedAssignees.length) {
|
||||||
call('frappe.desk.form.assign_to.add', {
|
if (props.docs.size) {
|
||||||
doctype: props.doc.doctype,
|
call('frappe.desk.form.assign_to.add_multiple', {
|
||||||
name: props.doc.name,
|
doctype: props.doctype,
|
||||||
assign_to: addedAssignees,
|
name: JSON.stringify(Array.from(props.docs)),
|
||||||
})
|
assign_to: addedAssignees,
|
||||||
|
bulk_assign: true,
|
||||||
|
re_assign: true,
|
||||||
|
}).then(() => {
|
||||||
|
emit('reload')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
call('frappe.desk.form.assign_to.add', {
|
||||||
|
doctype: props.doctype,
|
||||||
|
name: props.doc.name,
|
||||||
|
assign_to: addedAssignees,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
show.value = false
|
show.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,6 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const show = defineModel()
|
const show = defineModel()
|
||||||
const unselectAll = defineModel('unselectAll')
|
|
||||||
|
|
||||||
const emit = defineEmits(['reload'])
|
const emit = defineEmits(['reload'])
|
||||||
|
|
||||||
@ -114,7 +113,6 @@ function updateValues() {
|
|||||||
newValue.value = ''
|
newValue.value = ''
|
||||||
loading.value = false
|
loading.value = false
|
||||||
show.value = false
|
show.value = false
|
||||||
unselectAll.value()
|
|
||||||
emit('reload')
|
emit('reload')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -130,6 +128,10 @@ function updateValue(v) {
|
|||||||
newValue.value = value
|
newValue.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSelectOptions(options) {
|
||||||
|
return options.split('\n')
|
||||||
|
}
|
||||||
|
|
||||||
function getValueComponent(f) {
|
function getValueComponent(f) {
|
||||||
const { type, options } = f
|
const { type, options } = f
|
||||||
if (typeSelect.includes(type) || typeCheck.includes(type)) {
|
if (typeSelect.includes(type) || typeCheck.includes(type)) {
|
||||||
@ -140,6 +142,7 @@ function getValueComponent(f) {
|
|||||||
label: o,
|
label: o,
|
||||||
value: o,
|
value: o,
|
||||||
})),
|
})),
|
||||||
|
modelValue: newValue.value,
|
||||||
})
|
})
|
||||||
} else if (typeLink.includes(type)) {
|
} else if (typeLink.includes(type)) {
|
||||||
if (type == 'Dynamic Link') {
|
if (type == 'Dynamic Link') {
|
||||||
|
|||||||
@ -67,7 +67,7 @@ import IconPicker from '@/components/IconPicker.vue'
|
|||||||
import SmileIcon from '@/components/Icons/SmileIcon.vue'
|
import SmileIcon from '@/components/Icons/SmileIcon.vue'
|
||||||
import { createResource, Textarea, FileUploader, Dropdown } from 'frappe-ui'
|
import { createResource, Textarea, FileUploader, Dropdown } from 'frappe-ui'
|
||||||
import FeatherIcon from 'frappe-ui/src/components/FeatherIcon.vue'
|
import FeatherIcon from 'frappe-ui/src/components/FeatherIcon.vue'
|
||||||
import { ref, computed, nextTick, watch } from 'vue'
|
import { ref, nextTick, watch } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
doctype: String,
|
doctype: String,
|
||||||
|
|||||||
@ -280,6 +280,7 @@
|
|||||||
<AssignmentModal
|
<AssignmentModal
|
||||||
v-if="deal.data"
|
v-if="deal.data"
|
||||||
:doc="deal.data"
|
:doc="deal.data"
|
||||||
|
doctype="CRM Deal"
|
||||||
v-model="showAssignmentModal"
|
v-model="showAssignmentModal"
|
||||||
v-model:assignees="deal.data._assignedTo"
|
v-model:assignees="deal.data._assignedTo"
|
||||||
/>
|
/>
|
||||||
@ -289,6 +290,7 @@ import Resizer from '@/components/Resizer.vue'
|
|||||||
import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
|
import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
|
||||||
import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
|
import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
|
||||||
import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
||||||
|
import CommentIcon from '@/components/Icons/CommentIcon.vue'
|
||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
||||||
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
||||||
@ -447,6 +449,11 @@ const tabs = computed(() => {
|
|||||||
label: __('Emails'),
|
label: __('Emails'),
|
||||||
icon: EmailIcon,
|
icon: EmailIcon,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Comments',
|
||||||
|
label: __('Comments'),
|
||||||
|
icon: CommentIcon,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Calls',
|
name: 'Calls',
|
||||||
label: __('Calls'),
|
label: __('Calls'),
|
||||||
|
|||||||
@ -186,6 +186,7 @@
|
|||||||
<AssignmentModal
|
<AssignmentModal
|
||||||
v-if="lead.data"
|
v-if="lead.data"
|
||||||
:doc="lead.data"
|
:doc="lead.data"
|
||||||
|
doctype="CRM Lead"
|
||||||
v-model="showAssignmentModal"
|
v-model="showAssignmentModal"
|
||||||
v-model:assignees="lead.data._assignedTo"
|
v-model:assignees="lead.data._assignedTo"
|
||||||
/>
|
/>
|
||||||
@ -260,6 +261,7 @@
|
|||||||
import Resizer from '@/components/Resizer.vue'
|
import Resizer from '@/components/Resizer.vue'
|
||||||
import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
|
import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
|
||||||
import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
||||||
|
import CommentIcon from '@/components/Icons/CommentIcon.vue'
|
||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
||||||
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
||||||
@ -416,6 +418,11 @@ const tabs = computed(() => {
|
|||||||
label: __('Emails'),
|
label: __('Emails'),
|
||||||
icon: EmailIcon,
|
icon: EmailIcon,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Comments',
|
||||||
|
label: __('Comments'),
|
||||||
|
icon: CommentIcon,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Calls',
|
name: 'Calls',
|
||||||
label: __('Calls'),
|
label: __('Calls'),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user