mirror of
https://github.com/frappe/books.git
synced 2025-02-03 04:28:32 +00:00
Merge pull request #567 from frappe/fix-inline-fields
fix(ux): inline fieldtype
This commit is contained in:
commit
0f2f923bd2
@ -41,12 +41,12 @@ export class AccountingLedgerEntry extends Doc {
|
||||
static getListViewSettings(): ListViewSettings {
|
||||
return {
|
||||
columns: [
|
||||
'date',
|
||||
'account',
|
||||
'party',
|
||||
'debit',
|
||||
'credit',
|
||||
'referenceName',
|
||||
'reverted',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
import { t } from 'fyo';
|
||||
import { Fyo, t } from 'fyo';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { EmptyMessageMap, FormulaMap, ListsMap } from 'fyo/model/types';
|
||||
import {
|
||||
EmptyMessageMap,
|
||||
FormulaMap,
|
||||
ListsMap,
|
||||
ListViewSettings,
|
||||
} from 'fyo/model/types';
|
||||
import { codeStateMap } from 'regional/in';
|
||||
import { getCountryInfo } from 'utils/misc';
|
||||
|
||||
@ -54,4 +59,10 @@ export class Address extends Doc {
|
||||
return t`Enter Country to load States`;
|
||||
},
|
||||
};
|
||||
|
||||
static override getListViewSettings(): ListViewSettings {
|
||||
return {
|
||||
columns: ['name', 'addressLine1', 'city', 'state', 'country'],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { ListViewSettings } from 'fyo/model/types';
|
||||
import { Money } from 'pesa';
|
||||
|
||||
|
||||
export class StockLedgerEntry extends Doc {
|
||||
date?: Date;
|
||||
item?: string;
|
||||
@ -11,4 +11,17 @@ export class StockLedgerEntry extends Doc {
|
||||
referenceName?: string;
|
||||
referenceType?: string;
|
||||
batch?: string;
|
||||
|
||||
static override getListViewSettings(): ListViewSettings {
|
||||
return {
|
||||
columns: [
|
||||
'date',
|
||||
'item',
|
||||
'location',
|
||||
'rate',
|
||||
'quantity',
|
||||
'referenceName',
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,15 @@
|
||||
{
|
||||
"name": "Address",
|
||||
"label": "Address",
|
||||
"naming": "manual",
|
||||
"isSingle": false,
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "name",
|
||||
"label": "Address Name",
|
||||
"fieldtype": "Data",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"fieldname": "addressLine1",
|
||||
"label": "Address Line 1",
|
||||
@ -69,6 +76,7 @@
|
||||
}
|
||||
],
|
||||
"quickEditFields": [
|
||||
"name",
|
||||
"addressLine1",
|
||||
"addressLine2",
|
||||
"city",
|
||||
@ -76,5 +84,5 @@
|
||||
"country",
|
||||
"postalCode"
|
||||
],
|
||||
"inlineEditDisplayField": "addressDisplay"
|
||||
"linkDisplayField": "addressDisplay"
|
||||
}
|
||||
|
@ -74,7 +74,7 @@
|
||||
"label": "Address",
|
||||
"fieldtype": "Link",
|
||||
"target": "Address",
|
||||
"inline": true
|
||||
"create": true
|
||||
},
|
||||
{
|
||||
"fieldname": "taxId",
|
||||
|
@ -34,7 +34,7 @@
|
||||
"label": "Address",
|
||||
"fieldtype": "Link",
|
||||
"target": "Address",
|
||||
"inline": true,
|
||||
"create": true,
|
||||
"section": "Contacts"
|
||||
},
|
||||
{
|
||||
|
@ -16,7 +16,7 @@
|
||||
"label": "Address",
|
||||
"fieldtype": "Link",
|
||||
"target": "Address",
|
||||
"inline": true
|
||||
"create": true
|
||||
}
|
||||
],
|
||||
"quickEditFields": ["item", "address"]
|
||||
|
@ -50,8 +50,8 @@ function removeFields(schemaMap: SchemaMap): SchemaMap {
|
||||
(fn) => fn !== fieldname
|
||||
);
|
||||
|
||||
if (schema.inlineEditDisplayField === fieldname) {
|
||||
delete schema.inlineEditDisplayField;
|
||||
if (schema.linkDisplayField === fieldname) {
|
||||
delete schema.linkDisplayField;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
}
|
||||
],
|
||||
"quickEditFields": [
|
||||
"name",
|
||||
"addressLine1",
|
||||
"addressLine2",
|
||||
"city",
|
||||
|
@ -72,8 +72,7 @@
|
||||
"fieldname": "address",
|
||||
"label": "Address",
|
||||
"fieldtype": "Link",
|
||||
"target": "Address",
|
||||
"inline": true
|
||||
"target": "Address"
|
||||
}
|
||||
],
|
||||
"quickEditFields": [
|
||||
|
@ -61,7 +61,6 @@ export interface BaseField {
|
||||
placeholder?: string; // UI Facing config, form field placeholder
|
||||
groupBy?: string; // UI Facing used in dropdowns fields
|
||||
meta?: boolean; // Field is a meta field, i.e. only for the db, not UI
|
||||
inline?: boolean; // UI Facing config, whether to display doc inline.
|
||||
filter?: boolean; // UI Facing config, whether to be used to filter the List.
|
||||
computed?: boolean; // Computed values are not stored in the database.
|
||||
section?: string; // UI Facing config, for grouping by sections
|
||||
@ -118,7 +117,7 @@ export interface Schema {
|
||||
isSubmittable?: boolean; // For transactional types, values considered only after submit
|
||||
keywordFields?: string[]; // Used to get fields that are to be used for search.
|
||||
quickEditFields?: string[]; // Used to get fields for the quickEditForm
|
||||
inlineEditDisplayField?:string;// Display field if inline editable
|
||||
linkDisplayField?:string;// Display field if inline editable
|
||||
naming?: Naming; // Used for assigning name, default is 'random' else 'numberSeries' if present
|
||||
titleField?: string; // Main display field
|
||||
removeFields?: string[]; // Used by the builder to remove fields.
|
||||
|
@ -25,6 +25,7 @@
|
||||
:placeholder="inputPlaceholder"
|
||||
:readonly="isReadOnly"
|
||||
@focus="(e) => !isReadOnly && onFocus(e, toggleDropdown)"
|
||||
@click="(e) => !isReadOnly && onFocus(e, toggleDropdown)"
|
||||
@blur="(e) => !isReadOnly && onBlur(e.target.value)"
|
||||
@input="onInput"
|
||||
@keydown.up="highlightItemUp"
|
||||
@ -55,7 +56,6 @@
|
||||
</template>
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getOptionList } from 'fyo/utils';
|
||||
import Dropdown from 'src/components/Dropdown.vue';
|
||||
@ -81,7 +81,7 @@ export default {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(newValue) {
|
||||
this.linkValue = this.getLinkValue(newValue);
|
||||
this.setLinkValue(this.getLinkValue(newValue));
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -89,7 +89,8 @@ export default {
|
||||
doc: { default: null },
|
||||
},
|
||||
mounted() {
|
||||
this.linkValue = this.getLinkValue(this.linkValue || this.value);
|
||||
const value = this.linkValue || this.value;
|
||||
this.setLinkValue(this.getLinkValue(value));
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
@ -101,6 +102,9 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setLinkValue(value) {
|
||||
this.linkValue = value;
|
||||
},
|
||||
getLinkValue(value) {
|
||||
const oldValue = this.linkValue;
|
||||
let option = this.options.find((o) => o.value === value);
|
||||
@ -116,7 +120,7 @@ export default {
|
||||
},
|
||||
async updateSuggestions(keyword) {
|
||||
if (typeof keyword === 'string') {
|
||||
this.linkValue = keyword;
|
||||
this.setLinkValue(keyword, true);
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
@ -152,12 +156,12 @@ export default {
|
||||
},
|
||||
setSuggestion(suggestion) {
|
||||
if (suggestion?.actionOnly) {
|
||||
this.linkValue = this.value;
|
||||
this.setLinkValue(this.value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (suggestion) {
|
||||
this.linkValue = suggestion.label;
|
||||
this.setLinkValue(suggestion.label);
|
||||
this.triggerChange(suggestion.value);
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,12 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
clear() {
|
||||
const input = this.$refs.control.$refs.input;
|
||||
if (input instanceof HTMLInputElement) {
|
||||
input.value = '';
|
||||
}
|
||||
},
|
||||
focus() {
|
||||
this.$refs.control.focus();
|
||||
},
|
||||
|
@ -16,18 +16,42 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
if (this.value) {
|
||||
this.linkValue = this.value;
|
||||
this.setLinkValue();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(newValue) {
|
||||
this.linkValue = newValue;
|
||||
this.setLinkValue(newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async setLinkValue(newValue, isInput) {
|
||||
if (isInput) {
|
||||
return (this.linkValue = newValue || '');
|
||||
}
|
||||
|
||||
const value = newValue ?? this.value;
|
||||
const { fieldname, target } = this.df ?? {};
|
||||
const displayField = fyo.schemaMap[target ?? '']?.linkDisplayField;
|
||||
|
||||
if (!displayField) {
|
||||
return (this.linkValue = value);
|
||||
}
|
||||
|
||||
let displayValue = this.docs?.links?.[fieldname]?.get(displayField);
|
||||
if (!displayValue) {
|
||||
displayValue = await fyo.getValue(
|
||||
target,
|
||||
this.value ?? '',
|
||||
displayField
|
||||
);
|
||||
}
|
||||
|
||||
this.linkValue = displayValue;
|
||||
},
|
||||
getTargetSchemaName() {
|
||||
return this.df.target;
|
||||
},
|
||||
@ -104,10 +128,11 @@ export default {
|
||||
'<Badge color="blue" class="ms-2" v-if="isNewValue">{{ linkValue }}</Badge>' +
|
||||
'</div>',
|
||||
computed: {
|
||||
value: () => this.value,
|
||||
linkValue: () => this.linkValue,
|
||||
isNewValue: () => {
|
||||
let values = this.suggestions.map((d) => d.value);
|
||||
return this.linkValue && !values.includes(this.linkValue);
|
||||
return this.value && !values.includes(this.value);
|
||||
},
|
||||
},
|
||||
components: { Badge },
|
||||
@ -134,6 +159,7 @@ export default {
|
||||
this.$emit('new-doc', doc);
|
||||
this.$router.back();
|
||||
this.results = [];
|
||||
this.triggerChange(doc.name);
|
||||
});
|
||||
},
|
||||
async getCreateFilters() {
|
||||
|
@ -23,7 +23,12 @@
|
||||
@change="(e) => triggerChange(e.target.value)"
|
||||
@focus="(e) => $emit('focus', e)"
|
||||
>
|
||||
<option value="" disabled selected v-if="inputPlaceholder">
|
||||
<option
|
||||
value=""
|
||||
disabled
|
||||
selected
|
||||
v-if="inputPlaceholder && !showLabel"
|
||||
>
|
||||
{{ inputPlaceholder }}
|
||||
</option>
|
||||
<option
|
||||
|
@ -165,7 +165,11 @@ export default {
|
||||
methods: {
|
||||
getRandomString,
|
||||
addNewFilter() {
|
||||
let df = this.fields[0];
|
||||
const df = this.fields[0];
|
||||
if (!df) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addFilter(df.fieldname, 'like', '', false);
|
||||
},
|
||||
addFilter(fieldname, condition, value, implicit) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="text-sm" :class="{ 'border-t': !noBorder }">
|
||||
<div class="text-sm border-t">
|
||||
<template v-for="df in formFields">
|
||||
<!-- Table Field Form (Eg: PaymentFor) -->
|
||||
<FormControl
|
||||
<Table
|
||||
v-if="df.fieldtype === 'Table'"
|
||||
:key="`${df.fieldname}-table`"
|
||||
ref="controls"
|
||||
@ -13,53 +13,13 @@
|
||||
:read-only="readOnly"
|
||||
/>
|
||||
|
||||
<!-- Inline Field Form (Eg: Address) -->
|
||||
<div
|
||||
v-else-if="renderInline(df)"
|
||||
class="border-b"
|
||||
:key="`${df.fieldname}-inline`"
|
||||
>
|
||||
<TwoColumnForm
|
||||
class="overflow-auto custom-scroll"
|
||||
style="max-height: calc((var(--h-row-mid) + 1px) * 3 - 1px)"
|
||||
ref="inlineEditForm"
|
||||
:doc="inlineEditDoc"
|
||||
:fields="getInlineEditFields(df)"
|
||||
:column-ratio="columnRatio"
|
||||
:no-border="true"
|
||||
:focus-first-input="true"
|
||||
:autosave="false"
|
||||
:read-only="readOnly"
|
||||
@error="(msg) => $emit('error', msg)"
|
||||
/>
|
||||
<div
|
||||
class="flex px-4 py-4 justify-between items-center"
|
||||
style="max-height: calc(var(--h-row-mid) + 1px)"
|
||||
>
|
||||
<Button class="text-gray-900 w-20" @click="stopInlineEditing">
|
||||
{{ t`Cancel` }}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
class="text-white w-20"
|
||||
@click="saveInlineEditDoc(df)"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Regular Field Form -->
|
||||
<div
|
||||
v-else
|
||||
class="grid items-center"
|
||||
:class="{
|
||||
'border-b': !noBorder,
|
||||
}"
|
||||
class="grid items-center border-b"
|
||||
:key="`${df.fieldname}-regular`"
|
||||
:style="{
|
||||
...style,
|
||||
|
||||
height: getFieldHeight(df),
|
||||
}"
|
||||
>
|
||||
@ -69,7 +29,6 @@
|
||||
|
||||
<div
|
||||
class="py-2 pe-4"
|
||||
@click="activateInlineEditing(df)"
|
||||
:class="{
|
||||
'ps-2': df.fieldtype === 'AttachImage',
|
||||
}"
|
||||
@ -78,12 +37,11 @@
|
||||
ref="controls"
|
||||
size="small"
|
||||
:df="df"
|
||||
:value="getRegularValue(df)"
|
||||
:value="doc[df.fieldname]"
|
||||
:class="{ 'p-2': df.fieldtype === 'Check' }"
|
||||
:read-only="readOnly"
|
||||
:text-end="false"
|
||||
@change="async (value) => await onChange(df, value)"
|
||||
@focus="activateInlineEditing(df)"
|
||||
@new-doc="async (newdoc) => await onChange(df, newdoc.name)"
|
||||
/>
|
||||
<div
|
||||
@ -99,12 +57,12 @@
|
||||
</template>
|
||||
<script>
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import { handleErrorWithDialog } from 'src/errorHandling';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { getErrorMessage } from 'src/utils';
|
||||
import { evaluateHidden } from 'src/utils/doc';
|
||||
import Table from './Controls/Table.vue';
|
||||
|
||||
export default {
|
||||
name: 'TwoColumnForm',
|
||||
@ -121,7 +79,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
noBorder: Boolean,
|
||||
focusFirstInput: Boolean,
|
||||
readOnly: { type: [null, Boolean], default: null },
|
||||
},
|
||||
@ -132,8 +89,6 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inlineEditDoc: null,
|
||||
inlineEditField: null,
|
||||
formFields: [],
|
||||
errors: {},
|
||||
};
|
||||
@ -147,8 +102,7 @@ export default {
|
||||
},
|
||||
components: {
|
||||
FormControl,
|
||||
Button,
|
||||
TwoColumnForm: () => TwoColumnForm,
|
||||
Table,
|
||||
},
|
||||
mounted() {
|
||||
this.setFormFields();
|
||||
@ -172,51 +126,25 @@ export default {
|
||||
|
||||
return 'calc(var(--h-row-mid) + 1px)';
|
||||
},
|
||||
getRegularValue(df) {
|
||||
if (!df.inline) {
|
||||
return this.doc[df.fieldname];
|
||||
}
|
||||
async onChange(field, value) {
|
||||
const { fieldname } = field;
|
||||
delete this.errors[fieldname];
|
||||
|
||||
const link = this.doc.getLink(df.fieldname);
|
||||
if (!link) {
|
||||
return this.doc[df.fieldname];
|
||||
}
|
||||
|
||||
const fieldname = link.schema.inlineEditDisplayField ?? 'name';
|
||||
return link[fieldname];
|
||||
},
|
||||
renderInline(df) {
|
||||
return (
|
||||
this.inlineEditField?.fieldname === df?.fieldname && this.inlineEditDoc
|
||||
);
|
||||
},
|
||||
async onChange(df, value) {
|
||||
if (df.inline) {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle rename
|
||||
if (this.autosave && df.fieldname === 'name' && this.doc.inserted) {
|
||||
return this.doc.rename(value);
|
||||
}
|
||||
|
||||
const oldValue = this.doc.get(df.fieldname);
|
||||
this.errors[df.fieldname] = null;
|
||||
await this.onChangeCommon(df, value, oldValue);
|
||||
},
|
||||
async onChangeCommon(df, value, oldValue) {
|
||||
let isSet = false;
|
||||
const oldValue = this.doc.get(fieldname);
|
||||
try {
|
||||
isSet = await this.doc.set(df.fieldname, value);
|
||||
isSet = await this.doc.set(fieldname, value);
|
||||
} catch (err) {
|
||||
this.errors[df.fieldname] = getErrorMessage(err, this.doc);
|
||||
if (!(err instanceof Error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.errors[fieldname] = getErrorMessage(err, this.doc);
|
||||
}
|
||||
|
||||
if (!isSet) {
|
||||
return;
|
||||
if (isSet) {
|
||||
await this.handlePostSet(field, value, oldValue);
|
||||
}
|
||||
|
||||
await this.handlePostSet(df, value, oldValue);
|
||||
},
|
||||
async handlePostSet(df, value, oldValue) {
|
||||
this.setFormFields();
|
||||
@ -224,17 +152,16 @@ export default {
|
||||
this.$emit('change', df, value, oldValue);
|
||||
}
|
||||
|
||||
if (this.autosave && this.doc.dirty) {
|
||||
if (df.fieldtype === 'Table') {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.doc.sync();
|
||||
if (df.fieldtype === 'Table' || !this.doc.dirty || !this.autosave) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.doc.sync();
|
||||
},
|
||||
async sync() {
|
||||
try {
|
||||
await this.doc.sync();
|
||||
this.setFormFields();
|
||||
} catch (err) {
|
||||
await handleErrorWithDialog(err, this.doc);
|
||||
}
|
||||
@ -242,57 +169,11 @@ export default {
|
||||
async submit() {
|
||||
try {
|
||||
await this.doc.submit();
|
||||
this.setFormFields();
|
||||
} catch (err) {
|
||||
await handleErrorWithDialog(err, this.doc);
|
||||
}
|
||||
},
|
||||
async activateInlineEditing(df) {
|
||||
if (!df.inline) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.inlineEditField = df;
|
||||
if (!this.doc[df.fieldname]) {
|
||||
this.inlineEditDoc = await fyo.doc.getNewDoc(df.target);
|
||||
} else {
|
||||
this.inlineEditDoc = this.doc.getLink(df.fieldname);
|
||||
}
|
||||
},
|
||||
getInlineEditFields(df) {
|
||||
const inlineEditFieldNames =
|
||||
fyo.schemaMap[df.target].quickEditFields ?? [];
|
||||
return inlineEditFieldNames.map((fieldname) =>
|
||||
fyo.getField(df.target, fieldname)
|
||||
);
|
||||
},
|
||||
async saveInlineEditDoc(df) {
|
||||
if (!this.inlineEditDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.inlineEditDoc.sync();
|
||||
} catch (error) {
|
||||
return await handleErrorWithDialog(error, this.inlineEditDoc);
|
||||
}
|
||||
|
||||
await this.onChangeCommon(df, this.inlineEditDoc.name);
|
||||
await this.doc.loadLinks();
|
||||
|
||||
if (this.emitChange) {
|
||||
this.$emit('change', this.inlineEditField);
|
||||
}
|
||||
|
||||
await this.stopInlineEditing();
|
||||
},
|
||||
async stopInlineEditing() {
|
||||
if (this.inlineEditDoc?.dirty && !this.inlineEditDoc?.notInserted) {
|
||||
await this.inlineEditDoc.load();
|
||||
}
|
||||
|
||||
this.inlineEditDoc = null;
|
||||
this.inlineEditField = null;
|
||||
},
|
||||
setFormFields() {
|
||||
let fieldList = this.fields;
|
||||
|
||||
|
@ -66,15 +66,19 @@ export default defineComponent({
|
||||
methods: {
|
||||
focusOnNameField() {
|
||||
const naming = this.fyo.schemaMap[this.doc.schemaName]?.naming;
|
||||
if (naming !== 'manual') {
|
||||
if (naming !== 'manual' || this.doc.inserted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nameField = (this.$refs.nameField as { focus: Function }[])?.[0];
|
||||
const nameField = (
|
||||
this.$refs.nameField as { focus: Function; clear: Function }[]
|
||||
)?.[0];
|
||||
|
||||
if (!nameField) {
|
||||
return;
|
||||
}
|
||||
|
||||
nameField.clear();
|
||||
nameField.focus();
|
||||
},
|
||||
},
|
||||
|
@ -12,12 +12,11 @@
|
||||
class="sticky top-0 bg-white border-b"
|
||||
>
|
||||
</FormHeader>
|
||||
<!-- Section Container -->
|
||||
|
||||
<!-- Section Container -->
|
||||
<div class="overflow-auto custom-scroll" v-if="doc">
|
||||
<CommonFormSection
|
||||
v-for="([name, fields], idx) in activeGroup.entries()"
|
||||
@editrow="(doc: Doc) => toggleQuickEditDoc(doc)"
|
||||
:key="name + idx"
|
||||
ref="section"
|
||||
class="p-4"
|
||||
@ -95,13 +94,11 @@ export default defineComponent({
|
||||
canSave: false,
|
||||
activeTab: ModelNameEnum.AccountingSettings,
|
||||
groupedFields: null,
|
||||
quickEditDoc: null,
|
||||
} as {
|
||||
errors: Record<string, string>;
|
||||
canSave: boolean;
|
||||
activeTab: string;
|
||||
groupedFields: null | UIGroupedFields;
|
||||
quickEditDoc: null | Doc;
|
||||
};
|
||||
},
|
||||
provide() {
|
||||
@ -118,10 +115,26 @@ export default defineComponent({
|
||||
activated(): void {
|
||||
docsPathRef.value = docsPathMap.Settings ?? '';
|
||||
},
|
||||
deactivated(): void {
|
||||
async deactivated(): Promise<void> {
|
||||
docsPathRef.value = '';
|
||||
|
||||
if (!this.canSave) {
|
||||
return;
|
||||
}
|
||||
await this.reset();
|
||||
},
|
||||
methods: {
|
||||
async reset() {
|
||||
const resetableDocs = this.schemas
|
||||
.map(({ name }) => this.fyo.singles[name])
|
||||
.filter((doc) => doc?.dirty) as Doc[];
|
||||
|
||||
for (const doc of resetableDocs) {
|
||||
await doc.load();
|
||||
}
|
||||
|
||||
this.update();
|
||||
},
|
||||
async sync(): Promise<void> {
|
||||
const syncableDocs = this.schemas
|
||||
.map(({ name }) => this.fyo.singles[name])
|
||||
@ -151,14 +164,6 @@ export default defineComponent({
|
||||
await handleErrorWithDialog(err, doc);
|
||||
}
|
||||
},
|
||||
async toggleQuickEditDoc(doc: Doc | null): Promise<void> {
|
||||
if (this.quickEditDoc && doc) {
|
||||
this.quickEditDoc = null;
|
||||
await nextTick();
|
||||
}
|
||||
|
||||
this.quickEditDoc = doc;
|
||||
},
|
||||
async onValueChange(field: Field, value: DocValue): Promise<void> {
|
||||
const { fieldname } = field;
|
||||
delete this.errors[fieldname];
|
||||
|
@ -2,7 +2,14 @@ import { Doc } from 'fyo/model/doc';
|
||||
import { Field } from 'schemas/types';
|
||||
|
||||
export function evaluateReadOnly(field: Field, doc?: Doc) {
|
||||
if (field.fieldname === 'numberSeries' && !doc?.notInserted) {
|
||||
if (doc?.inserted && field.fieldname === 'numberSeries') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
field.fieldname === 'name' &&
|
||||
(doc?.inserted || doc?.schema.naming !== 'manual')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,10 @@ function getListViewList(fyo: Fyo): SearchItem[] {
|
||||
ModelNameEnum.PurchaseInvoice,
|
||||
ModelNameEnum.SalesInvoice,
|
||||
ModelNameEnum.Tax,
|
||||
ModelNameEnum.UOM,
|
||||
ModelNameEnum.Address,
|
||||
ModelNameEnum.AccountingLedgerEntry,
|
||||
ModelNameEnum.Currency,
|
||||
];
|
||||
|
||||
const hasInventory = fyo.doc.singles.AccountingSettings?.enableInventory;
|
||||
@ -231,7 +235,8 @@ function getListViewList(fyo: Fyo): SearchItem[] {
|
||||
ModelNameEnum.StockMovement,
|
||||
ModelNameEnum.Shipment,
|
||||
ModelNameEnum.PurchaseReceipt,
|
||||
ModelNameEnum.Location
|
||||
ModelNameEnum.Location,
|
||||
ModelNameEnum.StockLedgerEntry
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user