mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +00:00
feat: TwoColumnForm
- Supports inline editing of links for e.g Address
This commit is contained in:
parent
6d624438de
commit
6994c2fa11
@ -2,37 +2,15 @@ module.exports = {
|
|||||||
name: 'Address',
|
name: 'Address',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
isSingle: 0,
|
isSingle: 0,
|
||||||
keywordFields: ['name'],
|
keywordFields: [
|
||||||
pageSettings: {
|
'addressLine1',
|
||||||
hideTitle: true
|
'addressLine2',
|
||||||
},
|
'city',
|
||||||
|
'state',
|
||||||
|
'country',
|
||||||
|
'postalCode'
|
||||||
|
],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
|
||||||
fieldname: 'name',
|
|
||||||
label: 'Address Title',
|
|
||||||
fieldtype: 'Data',
|
|
||||||
defaultValue: 'Work',
|
|
||||||
required: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldname: 'addressType',
|
|
||||||
label: 'Address Type',
|
|
||||||
fieldtype: 'Select',
|
|
||||||
options: [
|
|
||||||
'Billing',
|
|
||||||
'Shipping',
|
|
||||||
'Office',
|
|
||||||
'Personal',
|
|
||||||
'Plant',
|
|
||||||
'Postal',
|
|
||||||
'Shop',
|
|
||||||
'Subsidary',
|
|
||||||
'Warehouse',
|
|
||||||
'Current',
|
|
||||||
'Permanent',
|
|
||||||
'Other'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fieldname: 'addressLine1',
|
fieldname: 'addressLine1',
|
||||||
label: 'Address Line 1',
|
label: 'Address Line 1',
|
||||||
@ -82,60 +60,31 @@ module.exports = {
|
|||||||
fieldtype: 'Data'
|
fieldtype: 'Data'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'isPreferredBilling',
|
fieldname: 'addressDisplay',
|
||||||
label: 'Preferred Billing Address',
|
fieldtype: 'Text',
|
||||||
fieldtype: 'Check'
|
label: 'Address Display',
|
||||||
},
|
readOnly: true,
|
||||||
{
|
formula: doc => {
|
||||||
fieldname: 'isShippingBilling',
|
return [
|
||||||
label: 'Preferred Shipping Address',
|
doc.addressLine1,
|
||||||
fieldtype: 'Check'
|
doc.addressLine2,
|
||||||
|
doc.city,
|
||||||
|
doc.state,
|
||||||
|
doc.country,
|
||||||
|
doc.postalCode
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(', ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
quickEditFields: [
|
||||||
// events: {
|
|
||||||
// validate: (doc) => {
|
|
||||||
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
|
|
||||||
listSettings: {
|
|
||||||
getFields(list) {
|
|
||||||
return ['name', 'addressType'];
|
|
||||||
},
|
|
||||||
getRowHTML(list, data) {
|
|
||||||
return `<div class="col-11">${list.getNameHTML(data)} (${
|
|
||||||
data.addressType
|
|
||||||
})</div>`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
layout: [
|
|
||||||
// section 1
|
|
||||||
{
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
'name',
|
|
||||||
'addressType',
|
|
||||||
'addressLine1',
|
'addressLine1',
|
||||||
'addressLine2',
|
'addressLine2',
|
||||||
'city',
|
'city',
|
||||||
'country',
|
|
||||||
'state',
|
'state',
|
||||||
|
'country',
|
||||||
'postalCode'
|
'postalCode'
|
||||||
]
|
],
|
||||||
},
|
inlineEditDisplayField: 'addressDisplay'
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
'emailAddress',
|
|
||||||
'phone',
|
|
||||||
'fax',
|
|
||||||
'isPreferredBilling',
|
|
||||||
'isShippingBilling'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
@ -1,40 +1,178 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="border-t">
|
<div class="text-sm" :class="{ 'border-t': !noBorder }">
|
||||||
<div class="grid border-b text-xs" style="grid-template-columns: 1fr 1fr" v-for="df in fields">
|
<template v-for="df in fields">
|
||||||
<div class="py-2 pl-4 text-gray-600 flex items-center">{{ df.label }}</div>
|
|
||||||
<div class="py-2 pr-4">
|
|
||||||
<FormControl
|
<FormControl
|
||||||
|
v-if="df.fieldtype === 'Table'"
|
||||||
|
ref="controls"
|
||||||
size="small"
|
size="small"
|
||||||
:df="df"
|
:df="df"
|
||||||
:value="doc[df.fieldname]"
|
:value="doc[df.fieldname]"
|
||||||
@change="value => onChange(df, value)"
|
@change="value => onChange(df, value)"
|
||||||
/>
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<template v-if="inlineEditField === df && inlineEditDoc">
|
||||||
|
<div class="border-b">
|
||||||
|
<TwoColumnForm
|
||||||
|
:doc="inlineEditDoc"
|
||||||
|
:fields="inlineEditFields"
|
||||||
|
:column-ratio="columnRatio"
|
||||||
|
:no-border="true"
|
||||||
|
:focus-first-input="true"
|
||||||
|
/>
|
||||||
|
<div class="flex px-4 pb-2">
|
||||||
|
<Button
|
||||||
|
class="w-1/2 text-gray-900"
|
||||||
|
@click="inlineEditField = null"
|
||||||
|
>
|
||||||
|
{{ _('Cancel') }}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
class="ml-2 w-1/2 text-white"
|
||||||
|
@click="saveInlineEditDoc"
|
||||||
|
>
|
||||||
|
{{ df.inlineSaveText || _('Save') }}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="grid"
|
||||||
|
:class="{ 'border-b': !noBorder }"
|
||||||
|
:style="style"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="py-2 pl-4 flex items-center"
|
||||||
|
:class="validateForm && df.required ? 'text-red-600' : 'text-gray-600'"
|
||||||
|
>
|
||||||
|
{{ df.label }}
|
||||||
|
</div>
|
||||||
|
<div class="py-2 pr-4" @click="activateInlineEditing(df)">
|
||||||
|
<FormControl
|
||||||
|
ref="controls"
|
||||||
|
size="small"
|
||||||
|
:df="df"
|
||||||
|
:value="
|
||||||
|
df.inline && doc.getLink(df.fieldname)
|
||||||
|
? doc.getLink(df.fieldname)[
|
||||||
|
doc.getLink(df.fieldname).meta.inlineEditDisplayField ||
|
||||||
|
'name'
|
||||||
|
]
|
||||||
|
: doc[df.fieldname]
|
||||||
|
"
|
||||||
|
@change="value => onChange(df, value)"
|
||||||
|
@focus="activateInlineEditing(df)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import FormControl from '@/components/Controls/FormControl';
|
import FormControl from '@/components/Controls/FormControl';
|
||||||
|
import Button from '@/components/Button';
|
||||||
|
|
||||||
export default {
|
let TwoColumnForm = {
|
||||||
name: 'TwoColumnForm',
|
name: 'TwoColumnForm',
|
||||||
props: ['doc', 'fields', 'autosave'],
|
props: {
|
||||||
|
doc: Object,
|
||||||
|
fields: Array,
|
||||||
|
autosave: Boolean,
|
||||||
|
columnRatio: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [1, 1]
|
||||||
|
},
|
||||||
|
noBorder: Boolean,
|
||||||
|
focusFirstInput: Boolean,
|
||||||
|
validateForm: Boolean
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inlineEditField: null,
|
||||||
|
inlineEditDoc: null,
|
||||||
|
inlineEditFields: null,
|
||||||
|
inlineEditDisplayField: null
|
||||||
|
};
|
||||||
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
doctype: this.doc.doctype,
|
doctype: this.doc.doctype,
|
||||||
name: this.doc.name
|
name: this.doc.name
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
FormControl
|
FormControl,
|
||||||
|
Button,
|
||||||
|
TwoColumnForm: () => TwoColumnForm
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.focusFirstInput) {
|
||||||
|
this.$refs['controls'][0].focus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onChange(df, value) {
|
onChange(df, value) {
|
||||||
|
if (value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let oldValue = this.doc.get(df.fieldname);
|
||||||
|
|
||||||
|
if (oldValue === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle rename
|
||||||
|
if (this.autosave && df.fieldname === 'name' && !this.doc.isNew()) {
|
||||||
|
return this.doc.rename(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.doc.set(df.fieldname, value);
|
this.doc.set(df.fieldname, value);
|
||||||
if (this.autosave) {
|
|
||||||
this.doc.update()
|
if (this.autosave && this.doc._dirty && !this.doc.isNew()) {
|
||||||
|
if (df.fieldtype === 'Table') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.doc.update();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async activateInlineEditing(df) {
|
||||||
|
if (df.inline) {
|
||||||
|
this.inlineEditField = df;
|
||||||
|
if (!this.doc[df.fieldname]) {
|
||||||
|
this.inlineEditDoc = await frappe.getNewDoc(df.target);
|
||||||
|
this.inlineEditDoc.once('afterInsert', () => {
|
||||||
|
this.onChange(df, this.inlineEditDoc.name);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.inlineEditDoc = this.doc.getLink(df.fieldname);
|
||||||
|
}
|
||||||
|
this.inlineEditDisplayField =
|
||||||
|
this.doc.meta.inlineEditDisplayField || 'name';
|
||||||
|
this.inlineEditFields = frappe.getMeta(df.target).getQuickEditFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async saveInlineEditDoc() {
|
||||||
|
if (this.inlineEditDoc) {
|
||||||
|
await this.inlineEditDoc.insertOrUpdate();
|
||||||
|
await this.doc.loadLinks();
|
||||||
|
this.inlineEditField = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
style() {
|
||||||
|
let templateColumns = (this.columnRatio || [1, 1])
|
||||||
|
.map(r => `${r}fr`)
|
||||||
|
.join(' ');
|
||||||
|
return {
|
||||||
|
'grid-template-columns': templateColumns
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TwoColumnForm;
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user