Merge pull request #1239 from frappe/main-hotfix
This commit is contained in:
commit
8d7a155d78
@ -10,8 +10,15 @@ from crm.fcrm.doctype.crm_notification.crm_notification import notify_user
|
|||||||
def validate(doc, method):
|
def validate(doc, method):
|
||||||
if doc.type == "Incoming" and doc.get("from"):
|
if doc.type == "Incoming" and doc.get("from"):
|
||||||
name, doctype = get_lead_or_deal_from_number(doc.get("from"))
|
name, doctype = get_lead_or_deal_from_number(doc.get("from"))
|
||||||
doc.reference_doctype = doctype
|
if name != None:
|
||||||
doc.reference_name = name
|
doc.reference_doctype = doctype
|
||||||
|
doc.reference_name = name
|
||||||
|
|
||||||
|
if doc.type == "Outgoing" and doc.get("to"):
|
||||||
|
name, doctype = get_lead_or_deal_from_number(doc.get("to"))
|
||||||
|
if name != None:
|
||||||
|
doc.reference_doctype = doctype
|
||||||
|
doc.reference_name = name
|
||||||
|
|
||||||
|
|
||||||
def on_update(doc, method):
|
def on_update(doc, method):
|
||||||
@ -29,7 +36,7 @@ def on_update(doc, method):
|
|||||||
def notify_agent(doc):
|
def notify_agent(doc):
|
||||||
if doc.type == "Incoming":
|
if doc.type == "Incoming":
|
||||||
doctype = doc.reference_doctype
|
doctype = doc.reference_doctype
|
||||||
if doctype.startswith("CRM "):
|
if doctype and doctype.startswith("CRM "):
|
||||||
doctype = doctype[4:].lower()
|
doctype = doctype[4:].lower()
|
||||||
notification_text = f"""
|
notification_text = f"""
|
||||||
<div class="mb-2 leading-5 text-ink-gray-5">
|
<div class="mb-2 leading-5 text-ink-gray-5">
|
||||||
|
|||||||
1855
crm/locale/ar.po
1855
crm/locale/ar.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/bs.po
1857
crm/locale/bs.po
File diff suppressed because it is too large
Load Diff
1855
crm/locale/cs.po
1855
crm/locale/cs.po
File diff suppressed because it is too large
Load Diff
6329
crm/locale/da.po
Normal file
6329
crm/locale/da.po
Normal file
File diff suppressed because it is too large
Load Diff
1859
crm/locale/de.po
1859
crm/locale/de.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/eo.po
1857
crm/locale/eo.po
File diff suppressed because it is too large
Load Diff
1861
crm/locale/es.po
1861
crm/locale/es.po
File diff suppressed because it is too large
Load Diff
1861
crm/locale/fa.po
1861
crm/locale/fa.po
File diff suppressed because it is too large
Load Diff
1855
crm/locale/fr.po
1855
crm/locale/fr.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/hr.po
1857
crm/locale/hr.po
File diff suppressed because it is too large
Load Diff
1871
crm/locale/hu.po
1871
crm/locale/hu.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/id.po
1857
crm/locale/id.po
File diff suppressed because it is too large
Load Diff
1855
crm/locale/it.po
1855
crm/locale/it.po
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.16.0\n"
|
"Generated-By: Babel 2.16.0\n"
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1217
|
#: frontend/src/components/ViewControls.vue:1172
|
||||||
msgid " (New)"
|
msgid " (New)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: frontend/src/components/CustomActions.vue:69
|
#: frontend/src/components/CustomActions.vue:69
|
||||||
#: frontend/src/components/ViewControls.vue:683
|
#: frontend/src/components/ViewControls.vue:683
|
||||||
#: frontend/src/components/ViewControls.vue:1109
|
#: frontend/src/components/ViewControls.vue:1064
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1796,8 +1796,8 @@ msgstr ""
|
|||||||
msgid "Delete Task"
|
msgid "Delete Task"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1157
|
#: frontend/src/components/ViewControls.vue:1112
|
||||||
#: frontend/src/components/ViewControls.vue:1165
|
#: frontend/src/components/ViewControls.vue:1120
|
||||||
msgid "Delete View"
|
msgid "Delete View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1986,7 +1986,7 @@ msgstr ""
|
|||||||
#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:225
|
#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:225
|
||||||
#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:228
|
#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:228
|
||||||
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:19
|
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:19
|
||||||
#: frontend/src/components/ViewControls.vue:1113
|
#: frontend/src/components/ViewControls.vue:1068
|
||||||
msgid "Duplicate"
|
msgid "Duplicate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3429,11 +3429,11 @@ msgstr ""
|
|||||||
msgid "Make Call"
|
msgid "Make Call"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1146
|
#: frontend/src/components/ViewControls.vue:1101
|
||||||
msgid "Make Private"
|
msgid "Make Private"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1146
|
#: frontend/src/components/ViewControls.vue:1101
|
||||||
msgid "Make Public"
|
msgid "Make Public"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4244,7 +4244,7 @@ msgstr ""
|
|||||||
msgid "Phone Numbers"
|
msgid "Phone Numbers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1138
|
#: frontend/src/components/ViewControls.vue:1093
|
||||||
msgid "Pin View"
|
msgid "Pin View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4963,7 +4963,7 @@ msgstr ""
|
|||||||
msgid "Set as Primary Contact"
|
msgid "Set as Primary Contact"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1123
|
#: frontend/src/components/ViewControls.vue:1078
|
||||||
msgid "Set as default"
|
msgid "Set as default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -5653,7 +5653,7 @@ msgstr ""
|
|||||||
msgid "Unlink {0} item(s)"
|
msgid "Unlink {0} item(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:1138
|
#: frontend/src/components/ViewControls.vue:1093
|
||||||
msgid "Unpin View"
|
msgid "Unpin View"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -5688,7 +5688,6 @@ msgstr ""
|
|||||||
#: frontend/src/components/Settings/SettingsPage.vue:20
|
#: frontend/src/components/Settings/SettingsPage.vue:20
|
||||||
#: frontend/src/components/Settings/TelephonySettings.vue:23
|
#: frontend/src/components/Settings/TelephonySettings.vue:23
|
||||||
#: frontend/src/components/Telephony/ExotelCallUI.vue:210
|
#: frontend/src/components/Telephony/ExotelCallUI.vue:210
|
||||||
#: frontend/src/components/ViewControls.vue:980
|
|
||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -5917,10 +5916,6 @@ msgstr ""
|
|||||||
msgid "You do not have permission to access this document"
|
msgid "You do not have permission to access this document"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: frontend/src/components/ViewControls.vue:976
|
|
||||||
msgid "You have unsaved changes. Do you want to save them?"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: crm/fcrm/doctype/crm_form_script/crm_form_script.py:24
|
#: crm/fcrm/doctype/crm_form_script/crm_form_script.py:24
|
||||||
msgid "You need to be in developer mode to edit a Standard Form Script"
|
msgid "You need to be in developer mode to edit a Standard Form Script"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
6329
crm/locale/nb.po
Normal file
6329
crm/locale/nb.po
Normal file
File diff suppressed because it is too large
Load Diff
1855
crm/locale/nl.po
1855
crm/locale/nl.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/pl.po
1857
crm/locale/pl.po
File diff suppressed because it is too large
Load Diff
1861
crm/locale/pt.po
1861
crm/locale/pt.po
File diff suppressed because it is too large
Load Diff
1865
crm/locale/pt_BR.po
1865
crm/locale/pt_BR.po
File diff suppressed because it is too large
Load Diff
1855
crm/locale/ru.po
1855
crm/locale/ru.po
File diff suppressed because it is too large
Load Diff
1863
crm/locale/sr.po
1863
crm/locale/sr.po
File diff suppressed because it is too large
Load Diff
1875
crm/locale/sr_CS.po
1875
crm/locale/sr_CS.po
File diff suppressed because it is too large
Load Diff
1863
crm/locale/sv.po
1863
crm/locale/sv.po
File diff suppressed because it is too large
Load Diff
1895
crm/locale/th.po
1895
crm/locale/th.po
File diff suppressed because it is too large
Load Diff
1859
crm/locale/tr.po
1859
crm/locale/tr.po
File diff suppressed because it is too large
Load Diff
1855
crm/locale/vi.po
1855
crm/locale/vi.po
File diff suppressed because it is too large
Load Diff
1857
crm/locale/zh.po
1857
crm/locale/zh.po
File diff suppressed because it is too large
Load Diff
3
frontend/components.d.ts
vendored
3
frontend/components.d.ts
vendored
@ -85,7 +85,6 @@ declare module 'vue' {
|
|||||||
DragIcon: typeof import('./src/components/Icons/DragIcon.vue')['default']
|
DragIcon: typeof import('./src/components/Icons/DragIcon.vue')['default']
|
||||||
DragVerticalIcon: typeof import('./src/components/Icons/DragVerticalIcon.vue')['default']
|
DragVerticalIcon: typeof import('./src/components/Icons/DragVerticalIcon.vue')['default']
|
||||||
Dropdown: typeof import('./src/components/frappe-ui/Dropdown.vue')['default']
|
Dropdown: typeof import('./src/components/frappe-ui/Dropdown.vue')['default']
|
||||||
DropdownItem: typeof import('./src/components/DropdownItem.vue')['default']
|
|
||||||
DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default']
|
DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default']
|
||||||
DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default']
|
DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default']
|
||||||
EditEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/EditEmailTemplate.vue')['default']
|
EditEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/EditEmailTemplate.vue')['default']
|
||||||
@ -202,6 +201,8 @@ declare module 'vue' {
|
|||||||
PlaybackSpeedOption: typeof import('./src/components/Activities/PlaybackSpeedOption.vue')['default']
|
PlaybackSpeedOption: typeof import('./src/components/Activities/PlaybackSpeedOption.vue')['default']
|
||||||
PlayIcon: typeof import('./src/components/Icons/PlayIcon.vue')['default']
|
PlayIcon: typeof import('./src/components/Icons/PlayIcon.vue')['default']
|
||||||
Popover: typeof import('./src/components/frappe-ui/Popover.vue')['default']
|
Popover: typeof import('./src/components/frappe-ui/Popover.vue')['default']
|
||||||
|
PrimaryDropdown: typeof import('./src/components/PrimaryDropdown.vue')['default']
|
||||||
|
PrimaryDropdownItem: typeof import('./src/components/PrimaryDropdownItem.vue')['default']
|
||||||
ProfileSettings: typeof import('./src/components/Settings/ProfileSettings.vue')['default']
|
ProfileSettings: typeof import('./src/components/Settings/ProfileSettings.vue')['default']
|
||||||
QuickEntryModal: typeof import('./src/components/Modals/QuickEntryModal.vue')['default']
|
QuickEntryModal: typeof import('./src/components/Modals/QuickEntryModal.vue')['default']
|
||||||
QuickFilterField: typeof import('./src/components/QuickFilterField.vue')['default']
|
QuickFilterField: typeof import('./src/components/QuickFilterField.vue')['default']
|
||||||
|
|||||||
@ -106,6 +106,8 @@ function convertToDeal(selections, unselectAll) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteValues(selections, unselectAll) {
|
function deleteValues(selections, unselectAll) {
|
||||||
|
unselectAllAction.value = unselectAll
|
||||||
|
|
||||||
const selectedDocs = Array.from(selections)
|
const selectedDocs = Array.from(selections)
|
||||||
if (selectedDocs.length == 1) {
|
if (selectedDocs.length == 1) {
|
||||||
showDeleteDocModal.value = {
|
showDeleteDocModal.value = {
|
||||||
@ -217,6 +219,12 @@ function bulkActions(selections, unselectAll) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reload(unselectAll) {
|
function reload(unselectAll) {
|
||||||
|
showDeleteDocModal.value = {
|
||||||
|
showLinkedDocsModal: false,
|
||||||
|
showDeleteModal: false,
|
||||||
|
docname: null,
|
||||||
|
}
|
||||||
|
|
||||||
unselectAllAction.value?.()
|
unselectAllAction.value?.()
|
||||||
unselectAll?.()
|
unselectAll?.()
|
||||||
list.value?.reload()
|
list.value?.reload()
|
||||||
|
|||||||
@ -175,6 +175,5 @@ function openAddressModal(_address) {
|
|||||||
doctype: 'Address',
|
doctype: 'Address',
|
||||||
address: _address,
|
address: _address,
|
||||||
}
|
}
|
||||||
nextTick(() => (show.value = false))
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
69
frontend/src/components/PrimaryDropdown.vue
Normal file
69
frontend/src/components/PrimaryDropdown.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<Popover>
|
||||||
|
<template #target="{ isOpen, togglePopover }">
|
||||||
|
<Button
|
||||||
|
:label="value"
|
||||||
|
class="dropdown-button flex items-center justify-between bg-surface-white !px-2.5 py-1.5 text-base text-ink-gray-8 placeholder-ink-gray-4 transition-colors hover:bg-surface-white focus:bg-surface-white focus:shadow-sm focus:outline-none focus:ring-0"
|
||||||
|
@click="togglePopover"
|
||||||
|
>
|
||||||
|
<div v-if="value" class="truncate">{{ value }}</div>
|
||||||
|
<div v-else class="text-base leading-5 text-ink-gray-4 truncate">
|
||||||
|
{{ placeholder }}
|
||||||
|
</div>
|
||||||
|
<template #suffix>
|
||||||
|
<FeatherIcon
|
||||||
|
:name="isOpen ? 'chevron-up' : 'chevron-down'"
|
||||||
|
class="h-4 text-ink-gray-5"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div
|
||||||
|
class="my-2 p-1.5 min-w-40 space-y-1.5 divide-y divide-outline-gray-1 rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<PrimaryDropdownItem
|
||||||
|
v-for="option in options"
|
||||||
|
:key="option.name || option.value"
|
||||||
|
:option="option"
|
||||||
|
/>
|
||||||
|
<div v-if="!options?.length">
|
||||||
|
<div class="p-1.5 pl-3 pr-4 text-base text-ink-gray-4">
|
||||||
|
{{ __('No {0} Available', [label]) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pt-1.5">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="w-full !justify-start"
|
||||||
|
:label="__('Create New')"
|
||||||
|
iconLeft="plus"
|
||||||
|
@click="create && create()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import PrimaryDropdownItem from '@/components/PrimaryDropdownItem.vue'
|
||||||
|
import { Popover } from 'frappe-ui'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: { type: [String, Number], default: '' },
|
||||||
|
placeholder: { type: String, default: '' },
|
||||||
|
options: { type: Array, default: [] },
|
||||||
|
create: { type: Function },
|
||||||
|
label: { type: String, default: '' },
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dropdown-button {
|
||||||
|
border-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
||||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||||
import { TextInput, Tooltip } from 'frappe-ui'
|
import { TextInput } from 'frappe-ui'
|
||||||
import { nextTick, ref, onMounted } from 'vue'
|
import { nextTick, ref, onMounted } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -79,70 +79,14 @@
|
|||||||
<div>{{ doc[field.fieldname] }}</div>
|
<div>{{ doc[field.fieldname] }}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="field.fieldtype === 'Dropdown'">
|
<PrimaryDropdown
|
||||||
<Popover>
|
v-else-if="field.fieldtype === 'Dropdown'"
|
||||||
<template #target="{ isOpen, togglePopover }">
|
:value="doc[field.fieldname]"
|
||||||
<Button
|
:placeholder="field.placeholder"
|
||||||
:label="doc[field.fieldname]"
|
:options="field.options"
|
||||||
class="dropdown-button flex items-center justify-between bg-surface-white !px-2.5 py-1.5 text-base text-ink-gray-8 placeholder-ink-gray-4 transition-colors hover:bg-surface-white focus:bg-surface-white focus:shadow-sm focus:outline-none focus:ring-0"
|
:create="field.create"
|
||||||
@click="togglePopover"
|
:label="field.label"
|
||||||
>
|
/>
|
||||||
<div
|
|
||||||
v-if="doc[field.fieldname]"
|
|
||||||
class="truncate"
|
|
||||||
>
|
|
||||||
{{ doc[field.fieldname] }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
class="text-base leading-5 text-ink-gray-4 truncate"
|
|
||||||
>
|
|
||||||
{{ field.placeholder }}
|
|
||||||
</div>
|
|
||||||
<template #suffix>
|
|
||||||
<FeatherIcon
|
|
||||||
:name="
|
|
||||||
isOpen ? 'chevron-up' : 'chevron-down'
|
|
||||||
"
|
|
||||||
class="h-4 text-ink-gray-5"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</Button>
|
|
||||||
</template>
|
|
||||||
<template #body>
|
|
||||||
<div
|
|
||||||
class="my-2 p-1.5 min-w-40 space-y-1.5 divide-y divide-outline-gray-1 rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<DropdownItem
|
|
||||||
v-if="field.options?.length"
|
|
||||||
v-for="option in field.options"
|
|
||||||
:key="option.name"
|
|
||||||
:option="option"
|
|
||||||
/>
|
|
||||||
<div v-else>
|
|
||||||
<div
|
|
||||||
class="p-1.5 pl-3 pr-4 text-base text-ink-gray-4"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
__('No {0} Available', [field.label])
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pt-1.5">
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
class="w-full !justify-start"
|
|
||||||
:label="__('Create New')"
|
|
||||||
iconLeft="plus"
|
|
||||||
@click="field.create()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
<FormControl
|
<FormControl
|
||||||
v-else-if="field.fieldtype == 'Check'"
|
v-else-if="field.fieldtype == 'Check'"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
@ -366,7 +310,7 @@
|
|||||||
import Password from '@/components/Controls/Password.vue'
|
import Password from '@/components/Controls/Password.vue'
|
||||||
import FormattedInput from '@/components/Controls/FormattedInput.vue'
|
import FormattedInput from '@/components/Controls/FormattedInput.vue'
|
||||||
import Section from '@/components/Section.vue'
|
import Section from '@/components/Section.vue'
|
||||||
import DropdownItem from '@/components/DropdownItem.vue'
|
import PrimaryDropdown from '@/components/PrimaryDropdown.vue'
|
||||||
import FadedScrollableDiv from '@/components/FadedScrollableDiv.vue'
|
import FadedScrollableDiv from '@/components/FadedScrollableDiv.vue'
|
||||||
import ArrowUpRightIcon from '@/components/Icons/ArrowUpRightIcon.vue'
|
import ArrowUpRightIcon from '@/components/Icons/ArrowUpRightIcon.vue'
|
||||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||||
@ -378,7 +322,7 @@ import { usersStore } from '@/stores/users'
|
|||||||
import { isMobileView } from '@/composables/settings'
|
import { isMobileView } from '@/composables/settings'
|
||||||
import { getFormat, evaluateDependsOnValue } from '@/utils'
|
import { getFormat, evaluateDependsOnValue } from '@/utils'
|
||||||
import { flt } from '@/utils/numberFormat.js'
|
import { flt } from '@/utils/numberFormat.js'
|
||||||
import { Tooltip, DateTimePicker, DatePicker, Popover } from 'frappe-ui'
|
import { Tooltip, DateTimePicker, DatePicker } from 'frappe-ui'
|
||||||
import { useDocument } from '@/data/document'
|
import { useDocument } from '@/data/document'
|
||||||
import { ref, computed, getCurrentInstance } from 'vue'
|
import { ref, computed, getCurrentInstance } from 'vue'
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@
|
|||||||
class="flex flex-1 flex-col justify-between overflow-hidden"
|
class="flex flex-1 flex-col justify-between overflow-hidden"
|
||||||
>
|
>
|
||||||
<SidePanelLayout
|
<SidePanelLayout
|
||||||
:sections="sections.data"
|
:sections="parsedSections"
|
||||||
doctype="Contact"
|
doctype="Contact"
|
||||||
:docname="contact.doc.name"
|
:docname="contact.doc.name"
|
||||||
@reload="sections.reload"
|
@reload="sections.reload"
|
||||||
@ -293,9 +293,7 @@ const tabs = [
|
|||||||
const deals = createResource({
|
const deals = createResource({
|
||||||
url: 'crm.api.contact.get_linked_deals',
|
url: 'crm.api.contact.get_linked_deals',
|
||||||
cache: ['deals', props.contactId],
|
cache: ['deals', props.contactId],
|
||||||
params: {
|
params: { contact: props.contactId },
|
||||||
contact: props.contactId,
|
|
||||||
},
|
|
||||||
auto: true,
|
auto: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -310,118 +308,110 @@ const sections = createResource({
|
|||||||
cache: ['sidePanelSections', 'Contact'],
|
cache: ['sidePanelSections', 'Contact'],
|
||||||
params: { doctype: 'Contact' },
|
params: { doctype: 'Contact' },
|
||||||
auto: true,
|
auto: true,
|
||||||
transform: (data) => computed(() => getParsedSections(data)),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function getParsedSections(_sections) {
|
const parsedSections = computed(() => {
|
||||||
return _sections.map((section) => {
|
if (!sections.data) return []
|
||||||
section.columns = section.columns.map((column) => {
|
return sections.data.map((section) => ({
|
||||||
column.fields = column.fields.map((field) => {
|
...section,
|
||||||
|
columns: section.columns.map((column) => ({
|
||||||
|
...column,
|
||||||
|
fields: column.fields.map((field) => {
|
||||||
if (field.fieldname === 'email_id') {
|
if (field.fieldname === 'email_id') {
|
||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
read_only: false,
|
read_only: false,
|
||||||
fieldtype: 'Dropdown',
|
fieldtype: 'Dropdown',
|
||||||
options:
|
options: (contact.doc?.email_ids || []).map((email) => ({
|
||||||
contact.doc?.email_ids?.map((email) => {
|
name: email.name,
|
||||||
return {
|
value: email.email_id,
|
||||||
name: email.name,
|
selected: email.email_id === contact.doc.email_id,
|
||||||
value: email.email_id,
|
placeholder: 'john@doe.com',
|
||||||
selected: email.email_id === contact.doc.email_id,
|
onClick: () => setAsPrimary('email', email.email_id),
|
||||||
placeholder: 'john@doe.com',
|
onSave: (option, isNew) =>
|
||||||
onClick: () => {
|
isNew
|
||||||
setAsPrimary('email', email.email_id)
|
? createNew('email', option.value)
|
||||||
},
|
: editOption(
|
||||||
onSave: (option, isNew) => {
|
'Contact Email',
|
||||||
if (isNew) {
|
option.name,
|
||||||
createNew('email', option.value)
|
'email_id',
|
||||||
} else {
|
option.value,
|
||||||
editOption(
|
),
|
||||||
'Contact Email',
|
onDelete: async (option, isNew) => {
|
||||||
option.name,
|
contact.doc.email_ids = contact.doc.email_ids.filter(
|
||||||
'email_id',
|
(e) => e.name !== option.name,
|
||||||
option.value
|
)
|
||||||
)
|
if (!isNew) await deleteOption('Contact Email', option.name)
|
||||||
}
|
},
|
||||||
},
|
})),
|
||||||
onDelete: async (option, isNew) => {
|
|
||||||
contact.doc.email_ids = contact.doc.email_ids.filter(
|
|
||||||
(email) => email.name !== option.name,
|
|
||||||
)
|
|
||||||
!isNew && (await deleteOption('Contact Email', option.name))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}) || [],
|
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.doc?.email_ids?.push({
|
// Add a temporary new option locally (mirrors original behavior)
|
||||||
name: 'new-1',
|
contact.doc.email_ids = [
|
||||||
value: '',
|
...(contact.doc.email_ids || []),
|
||||||
selected: false,
|
{
|
||||||
isNew: true,
|
name: 'new-1',
|
||||||
})
|
value: '',
|
||||||
|
selected: false,
|
||||||
|
isNew: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (field.fieldname === 'mobile_no') {
|
}
|
||||||
|
if (field.fieldname === 'mobile_no') {
|
||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
read_only: false,
|
read_only: false,
|
||||||
fieldtype: 'Dropdown',
|
fieldtype: 'Dropdown',
|
||||||
options:
|
options: (contact.doc?.phone_nos || []).map((phone) => ({
|
||||||
contact.doc?.phone_nos?.map((phone) => {
|
name: phone.name,
|
||||||
return {
|
value: phone.phone,
|
||||||
name: phone.name,
|
selected: phone.phone === contact.doc.mobile_no,
|
||||||
value: phone.phone,
|
onClick: () => setAsPrimary('mobile_no', phone.phone),
|
||||||
selected: phone.phone === contact.doc.mobile_no,
|
onSave: (option, isNew) =>
|
||||||
onClick: () => {
|
isNew
|
||||||
setAsPrimary('mobile_no', phone.phone)
|
? createNew('phone', option.value)
|
||||||
},
|
: editOption(
|
||||||
onSave: (option, isNew) => {
|
'Contact Phone',
|
||||||
if (isNew) {
|
option.name,
|
||||||
createNew('phone', option.value)
|
'phone',
|
||||||
} else {
|
option.value,
|
||||||
editOption(
|
),
|
||||||
'Contact Phone',
|
onDelete: async (option, isNew) => {
|
||||||
option.name,
|
contact.doc.phone_nos = contact.doc.phone_nos.filter(
|
||||||
'phone',
|
(p) => p.name !== option.name,
|
||||||
option.value
|
)
|
||||||
)
|
if (!isNew) await deleteOption('Contact Phone', option.name)
|
||||||
}
|
},
|
||||||
},
|
})),
|
||||||
onDelete: async (option, isNew) => {
|
|
||||||
contact.doc.phone_nos = contact.doc.phone_nos.filter(
|
|
||||||
(phone) => phone.name !== option.name,
|
|
||||||
)
|
|
||||||
!isNew && (await deleteOption('Contact Phone', option.name))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}) || [],
|
|
||||||
create: () => {
|
create: () => {
|
||||||
contact.doc?.phone_nos?.push({
|
contact.doc.phone_nos = [
|
||||||
name: 'new-1',
|
...(contact.doc.phone_nos || []),
|
||||||
value: '',
|
{
|
||||||
selected: false,
|
name: 'new-1',
|
||||||
isNew: true,
|
value: '',
|
||||||
})
|
selected: false,
|
||||||
|
isNew: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (field.fieldname === 'address') {
|
}
|
||||||
|
if (field.fieldname === 'address') {
|
||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
create: (value, close) => {
|
create: (_value, close) => {
|
||||||
openAddressModal()
|
openAddressModal()
|
||||||
close()
|
close && close()
|
||||||
},
|
},
|
||||||
edit: (address) => openAddressModal(address),
|
edit: (address) => openAddressModal(address),
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return field
|
|
||||||
}
|
}
|
||||||
})
|
return field
|
||||||
return column
|
}),
|
||||||
})
|
})),
|
||||||
return section
|
}))
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
async function setAsPrimary(field, value) {
|
async function setAsPrimary(field, value) {
|
||||||
let d = await call('crm.api.contact.set_as_primary', {
|
let d = await call('crm.api.contact.set_as_primary', {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user