1
0
forked from test/crm

fix: render fields in side panel, quick entry & data tab in new format

This commit is contained in:
Shariq Ansari 2024-12-31 22:30:22 +05:30
parent 0b4ee64a36
commit 37f357ac08
17 changed files with 411 additions and 399 deletions

View File

@ -593,17 +593,18 @@ def get_sidebar_fields(doctype, name):
for section in layout:
section["name"] = section.get("name") or section.get("label")
for field in section.get("fields") if section.get("fields") else []:
field_obj = next((f for f in fields if f.fieldname == field), None)
if field_obj:
if field_obj.permlevel > 0:
field_has_write_access = field_obj.permlevel in has_write_access_to_permlevels
field_has_read_access = field_obj.permlevel in has_read_access_to_permlevels
if not field_has_write_access and field_has_read_access:
field_obj.read_only = 1
if not field_has_read_access and not field_has_write_access:
field_obj.hidden = 1
section["fields"][section.get("fields").index(field)] = get_field_obj(field_obj)
for column in section.get("columns") if section.get("columns") else []:
for field in column.get("fields") if column.get("fields") else []:
field_obj = next((f for f in fields if f.fieldname == field), None)
if field_obj:
if field_obj.permlevel > 0:
field_has_write_access = field_obj.permlevel in has_write_access_to_permlevels
field_has_read_access = field_obj.permlevel in has_read_access_to_permlevels
if not field_has_write_access and field_has_read_access:
field_obj.read_only = 1
if not field_has_read_access and not field_has_write_access:
field_obj.hidden = 1
column["fields"][column.get("fields").index(field)] = get_field_obj(field_obj)
fields_meta = {}
for field in fields:

View File

@ -101,10 +101,12 @@ function saveChanges() {
_tabs.forEach((tab) => {
if (!tab.sections) return
tab.sections.forEach((section) => {
if (!section.fields) return
section.fields = section.fields.map(
(field) => field.fieldname || field.name,
)
section.columns.forEach((column) => {
if (!column.fields) return
column.fields = column.fields.map(
(field) => field.fieldname || field.name,
)
})
})
})
loading.value = true

View File

@ -125,10 +125,12 @@ const tabs = createResource({
transform: (_tabs) => {
return _tabs.forEach((tab) => {
tab.sections.forEach((section) => {
section.fields.forEach((field) => {
if (field.type === 'Table') {
_contact.value[field.name] = []
}
section.columns.forEach((column) => {
column.fields.forEach((field) => {
if (field.type === 'Table') {
_contact.value[field.name] = []
}
})
})
})
})

View File

@ -101,10 +101,12 @@ function saveChanges() {
_tabs.forEach((tab) => {
if (!tab.sections) return
tab.sections.forEach((section) => {
if (!section.fields) return
section.fields = section.fields.map(
(field) => field.fieldname || field.name,
)
section.columns.forEach((column) => {
if (!column.fields) return
column.fields = column.fields.map(
(field) => field.fieldname || field.name,
)
})
})
})
loading.value = true

View File

@ -109,18 +109,20 @@ const tabs = createResource({
transform: (_tabs) => {
return _tabs.forEach((tab) => {
tab.sections.forEach((section) => {
section.fields.forEach((field) => {
if (field.name == 'status') {
field.type = 'Select'
field.options = dealStatuses.value
field.prefix = getDealStatus(deal.status).iconColorClass
} else if (field.name == 'deal_owner') {
field.type = 'User'
}
section.columns.forEach((column) => {
column.fields.forEach((field) => {
if (field.name == 'status') {
field.type = 'Select'
field.options = dealStatuses.value
field.prefix = getDealStatus(deal.status).iconColorClass
} else if (field.name == 'deal_owner') {
field.type = 'User'
}
if (field.type === 'Table') {
deal[field.name] = []
}
if (field.type === 'Table') {
deal[field.name] = []
}
})
})
})
})

View File

@ -71,18 +71,20 @@ const tabs = createResource({
transform: (_tabs) => {
return _tabs.forEach((tab) => {
tab.sections.forEach((section) => {
section.fields.forEach((field) => {
if (field.name == 'status') {
field.type = 'Select'
field.options = leadStatuses.value
field.prefix = getLeadStatus(lead.status).iconColorClass
} else if (field.name == 'lead_owner') {
field.type = 'User'
}
section.columns.forEach((column) => {
column.fields.forEach((field) => {
if (field.name == 'status') {
field.type = 'Select'
field.options = leadStatuses.value
field.prefix = getLeadStatus(lead.status).iconColorClass
} else if (field.name == 'lead_owner') {
field.type = 'User'
}
if (field.type === 'Table') {
lead[field.name] = []
}
if (field.type === 'Table') {
lead[field.name] = []
}
})
})
})
})

View File

@ -124,10 +124,12 @@ const tabs = createResource({
transform: (_tabs) => {
return _tabs.forEach((tab) => {
tab.sections.forEach((section) => {
section.fields.forEach((field) => {
if (field.type === 'Table') {
_organization.value[field.name] = []
}
section.columns.forEach((column) => {
column.fields.forEach((field) => {
if (field.type === 'Table') {
_organization.value[field.name] = []
}
})
})
})
})

View File

@ -99,10 +99,12 @@ function saveChanges() {
_tabs.forEach((tab) => {
if (!tab.sections) return
tab.sections.forEach((section) => {
if (!section.fields) return
section.fields = section.fields.map(
(field) => field.fieldname || field.name,
)
section.columns.forEach((column) => {
if (!column.fields) return
column.fields = column.fields.map(
(field) => field.fieldname || field.name,
)
})
})
})
loading.value = true

View File

@ -51,7 +51,7 @@
:opened="section.opened"
>
<SidePanelLayout
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == section.data?.length - 1"
v-model="data"
/>
@ -129,10 +129,12 @@ function saveChanges() {
let _tabs = JSON.parse(JSON.stringify(tabs.data))
_tabs.forEach((tab) => {
tab.sections.forEach((section) => {
if (!section.fields) return
section.fields = section.fields
.map((field) => field.fieldname || field.name)
.filter(Boolean)
section.columns.forEach((column) => {
if (!column.fields) return
column.fields = column.fields
.map((field) => field.fieldname || field.name)
.filter(Boolean)
})
})
})
loading.value = true

View File

@ -139,8 +139,8 @@
</Button>
</template>
<SidePanelLayout
v-if="section.fields"
:fields="section.fields"
v-if="section.columns?.[0].fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="Contact"
v-model="contact.data"
@ -377,148 +377,147 @@ const fieldsLayout = createResource({
function getParsedFields(data) {
return data.map((section) => {
return {
...section,
fields: computed(() =>
section.fields.map((field) => {
if (field.name === 'email_id') {
return {
...field,
type: 'dropdown',
options:
contact.data?.email_ids?.map((email) => {
return {
name: email.name,
value: email.email_id,
selected: email.email_id === contact.data.email_id,
placeholder: 'john@doe.com',
onClick: () => {
_contact.value.email_id = email.email_id
setAsPrimary('email', email.email_id)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('email', option.value)
if (contact.data.email_ids.length === 1) {
_contact.value.email_id = option.value
}
} else {
editOption(
'Contact Email',
option.name,
'email_id',
option.value,
)
section.columns = section.columns.map((column) => {
column.fields = column.fields.map((field) => {
if (field.name === 'email_id') {
return {
...field,
read_only: false,
type: 'dropdown',
options:
contact.data?.email_ids?.map((email) => {
return {
name: email.name,
value: email.email_id,
selected: email.email_id === contact.data.email_id,
placeholder: 'john@doe.com',
onClick: () => {
_contact.value.email_id = email.email_id
setAsPrimary('email', email.email_id)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('email', option.value)
if (contact.data.email_ids.length === 1) {
_contact.value.email_id = option.value
}
},
onDelete: async (option, isNew) => {
contact.data.email_ids = contact.data.email_ids.filter(
(email) => email.name !== option.name,
} else {
editOption(
'Contact Email',
option.name,
'email_id',
option.value,
)
!isNew &&
(await deleteOption('Contact Email', option.name))
if (_contact.value.email_id === option.value) {
if (contact.data.email_ids.length === 0) {
_contact.value.email_id = ''
} else {
_contact.value.email_id = contact.data.email_ids.find(
(email) => email.is_primary,
)?.email_id
}
}
},
}
}) || [],
create: () => {
contact.data?.email_ids?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'mobile_no') {
return {
...field,
type: 'dropdown',
options:
contact.data?.phone_nos?.map((phone) => {
return {
name: phone.name,
value: phone.phone,
selected: phone.phone === contact.data.actual_mobile_no,
onClick: () => {
_contact.value.actual_mobile_no = phone.phone
_contact.value.mobile_no = phone.phone
setAsPrimary('mobile_no', phone.phone)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('phone', option.value)
if (contact.data.phone_nos.length === 1) {
_contact.value.actual_mobile_no = option.value
}
}
},
onDelete: async (option, isNew) => {
contact.data.email_ids = contact.data.email_ids.filter(
(email) => email.name !== option.name,
)
!isNew && (await deleteOption('Contact Email', option.name))
if (_contact.value.email_id === option.value) {
if (contact.data.email_ids.length === 0) {
_contact.value.email_id = ''
} else {
editOption(
'Contact Phone',
option.name,
'phone',
option.value,
)
_contact.value.email_id = contact.data.email_ids.find(
(email) => email.is_primary,
)?.email_id
}
},
onDelete: async (option, isNew) => {
contact.data.phone_nos = contact.data.phone_nos.filter(
(phone) => phone.name !== option.name,
)
!isNew &&
(await deleteOption('Contact Phone', option.name))
if (_contact.value.actual_mobile_no === option.value) {
if (contact.data.phone_nos.length === 0) {
_contact.value.actual_mobile_no = ''
} else {
_contact.value.actual_mobile_no =
contact.data.phone_nos.find(
(phone) => phone.is_primary_mobile_no,
)?.phone
}
}
},
}
}) || [],
create: () => {
contact.data?.phone_nos?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_contact.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
}
},
}
}) || [],
create: () => {
contact.data?.email_ids?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
}),
),
}
} else if (field.name === 'mobile_no') {
return {
...field,
read_only: false,
type: 'dropdown',
options:
contact.data?.phone_nos?.map((phone) => {
return {
name: phone.name,
value: phone.phone,
selected: phone.phone === contact.data.actual_mobile_no,
onClick: () => {
_contact.value.actual_mobile_no = phone.phone
_contact.value.mobile_no = phone.phone
setAsPrimary('mobile_no', phone.phone)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('phone', option.value)
if (contact.data.phone_nos.length === 1) {
_contact.value.actual_mobile_no = option.value
}
} else {
editOption(
'Contact Phone',
option.name,
'phone',
option.value,
)
}
},
onDelete: async (option, isNew) => {
contact.data.phone_nos = contact.data.phone_nos.filter(
(phone) => phone.name !== option.name,
)
!isNew && (await deleteOption('Contact Phone', option.name))
if (_contact.value.actual_mobile_no === option.value) {
if (contact.data.phone_nos.length === 0) {
_contact.value.actual_mobile_no = ''
} else {
_contact.value.actual_mobile_no =
contact.data.phone_nos.find(
(phone) => phone.is_primary_mobile_no,
)?.phone
}
}
},
}
}) || [],
create: () => {
contact.data?.phone_nos?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_contact.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
}
})
return column
})
return section
})
}

View File

@ -168,8 +168,8 @@
</Button>
</template>
<SidePanelLayout
v-if="section.fields"
:fields="section.fields"
v-if="section.columns?.[0].fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="CRM Deal"
v-model="deal.data"
@ -611,7 +611,7 @@ const fieldsLayout = createResource({
function getParsedFields(sections) {
sections.forEach((section) => {
if (section.name == 'contacts_section') return
section.fields.forEach((field) => {
section.columns[0].fields.forEach((field) => {
if (field.name == 'organization') {
field.create = (value, close) => {
_organization.value.organization_name = value

View File

@ -183,7 +183,7 @@
:opened="section.opened"
>
<SidePanelLayout
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
v-model="lead.data"
@update="updateField"

View File

@ -143,7 +143,7 @@
>
<Section :label="section.label" :opened="section.opened">
<SidePanelLayout
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="Contact"
v-model="contact.data"
@ -357,148 +357,145 @@ const fieldsLayout = createResource({
function getParsedFields(data) {
return data.map((section) => {
return {
...section,
fields: computed(() =>
section.fields.map((field) => {
if (field.name === 'email_id') {
return {
...field,
type: 'dropdown',
options:
contact.data?.email_ids?.map((email) => {
return {
name: email.name,
value: email.email_id,
selected: email.email_id === contact.data.email_id,
placeholder: 'john@doe.com',
onClick: () => {
_contact.value.email_id = email.email_id
setAsPrimary('email', email.email_id)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('email', option.value)
if (contact.data.email_ids.length === 1) {
_contact.value.email_id = option.value
}
} else {
editOption(
'Contact Email',
option.name,
'email_id',
option.value,
)
section.columns = section.columns.map((column) => {
column.fields = column.fields.map((field) => {
if (field.name === 'email_id') {
return {
...field,
type: 'dropdown',
options:
contact.data?.email_ids?.map((email) => {
return {
name: email.name,
value: email.email_id,
selected: email.email_id === contact.data.email_id,
placeholder: 'john@doe.com',
onClick: () => {
_contact.value.email_id = email.email_id
setAsPrimary('email', email.email_id)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('email', option.value)
if (contact.data.email_ids.length === 1) {
_contact.value.email_id = option.value
}
},
onDelete: async (option, isNew) => {
contact.data.email_ids = contact.data.email_ids.filter(
(email) => email.name !== option.name,
} else {
editOption(
'Contact Email',
option.name,
'email_id',
option.value,
)
!isNew &&
(await deleteOption('Contact Email', option.name))
if (_contact.value.email_id === option.value) {
if (contact.data.email_ids.length === 0) {
_contact.value.email_id = ''
} else {
_contact.value.email_id = contact.data.email_ids.find(
(email) => email.is_primary,
)?.email_id
}
}
},
}
}) || [],
create: () => {
contact.data?.email_ids?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'mobile_no') {
return {
...field,
type: 'dropdown',
options:
contact.data?.phone_nos?.map((phone) => {
return {
name: phone.name,
value: phone.phone,
selected: phone.phone === contact.data.actual_mobile_no,
onClick: () => {
_contact.value.actual_mobile_no = phone.phone
_contact.value.mobile_no = phone.phone
setAsPrimary('mobile_no', phone.phone)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('phone', option.value)
if (contact.data.phone_nos.length === 1) {
_contact.value.actual_mobile_no = option.value
}
}
},
onDelete: async (option, isNew) => {
contact.data.email_ids = contact.data.email_ids.filter(
(email) => email.name !== option.name,
)
!isNew && (await deleteOption('Contact Email', option.name))
if (_contact.value.email_id === option.value) {
if (contact.data.email_ids.length === 0) {
_contact.value.email_id = ''
} else {
editOption(
'Contact Phone',
option.name,
'phone',
option.value,
)
_contact.value.email_id = contact.data.email_ids.find(
(email) => email.is_primary,
)?.email_id
}
},
onDelete: async (option, isNew) => {
contact.data.phone_nos = contact.data.phone_nos.filter(
(phone) => phone.name !== option.name,
)
!isNew &&
(await deleteOption('Contact Phone', option.name))
if (_contact.value.actual_mobile_no === option.value) {
if (contact.data.phone_nos.length === 0) {
_contact.value.actual_mobile_no = ''
} else {
_contact.value.actual_mobile_no =
contact.data.phone_nos.find(
(phone) => phone.is_primary_mobile_no,
)?.phone
}
}
},
}
}) || [],
create: () => {
contact.data?.phone_nos?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_contact.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
}
},
}
}) || [],
create: () => {
contact.data?.email_ids?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
}),
),
}
} else if (field.name === 'mobile_no') {
return {
...field,
type: 'dropdown',
options:
contact.data?.phone_nos?.map((phone) => {
return {
name: phone.name,
value: phone.phone,
selected: phone.phone === contact.data.actual_mobile_no,
onClick: () => {
_contact.value.actual_mobile_no = phone.phone
_contact.value.mobile_no = phone.phone
setAsPrimary('mobile_no', phone.phone)
},
onSave: (option, isNew) => {
if (isNew) {
createNew('phone', option.value)
if (contact.data.phone_nos.length === 1) {
_contact.value.actual_mobile_no = option.value
}
} else {
editOption(
'Contact Phone',
option.name,
'phone',
option.value,
)
}
},
onDelete: async (option, isNew) => {
contact.data.phone_nos = contact.data.phone_nos.filter(
(phone) => phone.name !== option.name,
)
!isNew && (await deleteOption('Contact Phone', option.name))
if (_contact.value.actual_mobile_no === option.value) {
if (contact.data.phone_nos.length === 0) {
_contact.value.actual_mobile_no = ''
} else {
_contact.value.actual_mobile_no =
contact.data.phone_nos.find(
(phone) => phone.is_primary_mobile_no,
)?.phone
}
}
},
}
}) || [],
create: () => {
contact.data?.phone_nos?.push({
name: 'new-1',
value: '',
selected: false,
isNew: true,
})
},
}
} else if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_contact.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
}
})
return column
})
return section
})
}

View File

@ -99,8 +99,8 @@
</div>
</template>
<SidePanelLayout
v-if="section.fields"
:fields="section.fields"
v-if="section.columns?.[0].fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="CRM Deal"
v-model="deal.data"
@ -289,7 +289,7 @@ import {
Tabs,
Breadcrumbs,
call,
usePageMeta
usePageMeta,
} from 'frappe-ui'
import { ref, computed, h, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
@ -511,7 +511,7 @@ const fieldsLayout = createResource({
function getParsedFields(sections) {
sections.forEach((section) => {
if (section.name == 'contacts_section') return
section.fields.forEach((field) => {
section.columns[0].fields.forEach((field) => {
if (field.name == 'organization') {
field.create = (value, close) => {
_organization.value.organization_name = value

View File

@ -76,7 +76,7 @@
>
<Section :label="section.label" :opened="section.opened">
<SidePanelLayout
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
v-model="lead.data"
@update="updateField"

View File

@ -125,8 +125,9 @@
>
<Section :label="section.label" :opened="section.opened">
<SidePanelLayout
v-if="section.columns?.[0].fields"
v-model="organization.doc"
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="CRM Organization"
@update="updateField"
@ -335,33 +336,32 @@ const fieldsLayout = createResource({
function getParsedFields(data) {
return data.map((section) => {
return {
...section,
fields: computed(() =>
section.fields.map((field) => {
if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_organization.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
section.columns = section.columns.map((column) => {
column.fields = column.fields.map((field) => {
if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_organization.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
}),
),
}
} else {
return field
}
})
return column
})
return section
})
}

View File

@ -124,9 +124,9 @@
</Button>
</template>
<SidePanelLayout
v-if="section.fields"
v-if="section.columns?.[0].fields"
v-model="organization.doc"
:fields="section.fields"
:fields="section.columns[0].fields"
:isLastSection="i == fieldsLayout.data.length - 1"
doctype="CRM Organization"
@update="updateField"
@ -377,33 +377,32 @@ const fieldsLayout = createResource({
function getParsedFields(data) {
return data.map((section) => {
return {
...section,
fields: computed(() =>
section.fields.map((field) => {
if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_organization.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
} else {
return field
section.columns = section.columns.map((column) => {
column.fields = column.fields.map((field) => {
if (field.name === 'address') {
return {
...field,
create: (value, close) => {
_organization.value.address = value
_address.value = {}
showAddressModal.value = true
close()
},
edit: async (addr) => {
_address.value = await call('frappe.client.get', {
doctype: 'Address',
name: addr,
})
showAddressModal.value = true
},
}
}),
),
}
} else {
return field
}
})
return column
})
return section
})
}