mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +00:00
fix: simplify QuickEditForm and usage
- type QuickEditForm, TwoColumnForm - dont use QuickEditForm for tables - dont keep-alice QuickEditForm
This commit is contained in:
parent
5a3b87333e
commit
c754fd35ce
@ -131,24 +131,17 @@ export default {
|
||||
},
|
||||
async openNewDoc() {
|
||||
const schemaName = this.df.target;
|
||||
const linkDoc = fyo.doc.getNewDoc(schemaName);
|
||||
|
||||
const name = this.linkValue;
|
||||
const filters = await this.getCreateFilters();
|
||||
|
||||
const { openQuickEdit } = await import('src/utils/ui');
|
||||
|
||||
openQuickEdit({
|
||||
schemaName,
|
||||
name: linkDoc.name,
|
||||
defaults: Object.assign({}, filters, {
|
||||
name: this.linkValue,
|
||||
}),
|
||||
});
|
||||
const doc = fyo.doc.getNewDoc(schemaName, { name, ...filters });
|
||||
openQuickEdit({ doc });
|
||||
|
||||
linkDoc.once('afterSync', () => {
|
||||
doc.once('afterSync', () => {
|
||||
this.$router.back();
|
||||
this.results = [];
|
||||
this.triggerChange(linkDoc.name);
|
||||
this.triggerChange(doc.name);
|
||||
});
|
||||
},
|
||||
async getCreateFilters() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
ref="controls"
|
||||
size="small"
|
||||
:df="df"
|
||||
:value="doc[df.fieldname]"
|
||||
:value="(doc[df.fieldname] ?? []) as unknown[]"
|
||||
@change="async (value) => await onChange(df, value)"
|
||||
/>
|
||||
|
||||
@ -52,21 +52,25 @@
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { getErrorMessage } from 'src/utils';
|
||||
import { evaluateHidden } from 'src/utils/doc';
|
||||
import Table from './Controls/Table.vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { Field } from 'schemas/types';
|
||||
import { PropType } from 'vue';
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'TwoColumnForm',
|
||||
props: {
|
||||
doc: Doc,
|
||||
fields: { type: Array, default: () => [] },
|
||||
doc: { type: Doc, required: true },
|
||||
fields: { type: Array as PropType<Field[]>, default: () => [] },
|
||||
columnRatio: {
|
||||
type: Array,
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [1, 1],
|
||||
},
|
||||
},
|
||||
@ -79,7 +83,7 @@ export default {
|
||||
return {
|
||||
formFields: [],
|
||||
errors: {},
|
||||
};
|
||||
} as { formFields: Field[]; errors: Record<string, string> };
|
||||
},
|
||||
components: {
|
||||
FormControl,
|
||||
@ -88,22 +92,23 @@ export default {
|
||||
mounted() {
|
||||
this.setFormFields();
|
||||
if (fyo.store.isDevelopment) {
|
||||
// @ts-ignore
|
||||
window.tcf = this;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getFieldHeight(df) {
|
||||
if (['AttachImage', 'Text'].includes(df.fieldtype)) {
|
||||
getFieldHeight(field: Field) {
|
||||
if (['AttachImage', 'Text'].includes(field.fieldtype)) {
|
||||
return 'calc((var(--h-row-mid) + 1px) * 2)';
|
||||
}
|
||||
|
||||
if (this.errors[df.fieldname]) {
|
||||
if (this.errors[field.fieldname]) {
|
||||
return 'calc((var(--h-row-mid) + 1px) * 2)';
|
||||
}
|
||||
|
||||
return 'calc(var(--h-row-mid) + 1px)';
|
||||
},
|
||||
async onChange(field, value) {
|
||||
async onChange(field: Field, value: DocValue) {
|
||||
const { fieldname } = field;
|
||||
delete this.errors[fieldname];
|
||||
|
||||
@ -148,5 +153,5 @@ export default {
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
@ -120,20 +120,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #quickedit>
|
||||
<Transition name="quickedit">
|
||||
<QuickEditForm
|
||||
v-if="hasQeDoc"
|
||||
:name="qeDoc.name"
|
||||
:show-name="false"
|
||||
:show-save="false"
|
||||
:source-doc="qeDoc"
|
||||
:schema-name="qeDoc.schemaName"
|
||||
:white="true"
|
||||
:route-back="false"
|
||||
:load-on-close="false"
|
||||
@close="() => toggleQuickEditDoc(null)"
|
||||
/>
|
||||
</Transition>
|
||||
<Transition name="quickedit"> </Transition>
|
||||
<Transition name="quickedit">
|
||||
<LinkedEntries
|
||||
v-if="showLinks && !hasQeDoc"
|
||||
@ -452,7 +439,6 @@ export default defineComponent({
|
||||
StatusBadge,
|
||||
Button,
|
||||
DropdownWithActions,
|
||||
QuickEditForm,
|
||||
Barcode,
|
||||
ExchangeRate,
|
||||
LinkedEntries,
|
||||
|
@ -22,12 +22,10 @@ import { toggleSidebar } from 'src/utils/ui';
|
||||
<router-view name="edit" v-slot="{ Component, route }">
|
||||
<Transition name="quickedit">
|
||||
<div v-if="route?.query?.edit">
|
||||
<keep-alive>
|
||||
<component
|
||||
:is="Component"
|
||||
:key="route.query.schemaName + route.query.name"
|
||||
/>
|
||||
</keep-alive>
|
||||
<component
|
||||
:is="Component"
|
||||
:key="route.query.schemaName + route.query.name"
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
</router-view>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="border-s h-full overflow-auto w-quick-edit"
|
||||
:class="white ? 'bg-white' : 'bg-gray-25'"
|
||||
>
|
||||
<div class="border-s h-full overflow-auto w-quick-edit bg-white">
|
||||
<!-- Quick edit Tool bar -->
|
||||
<div
|
||||
class="
|
||||
@ -13,10 +10,10 @@
|
||||
h-row-largest
|
||||
sticky
|
||||
top-0
|
||||
border-b
|
||||
bg-white
|
||||
"
|
||||
style="z-index: 1"
|
||||
:class="{ 'border-b': showName }"
|
||||
>
|
||||
<!-- Close Button and Status Text -->
|
||||
<div class="flex items-center">
|
||||
@ -29,7 +26,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Actions, Badge and Status Change Buttons -->
|
||||
<div class="flex items-stretch gap-2" v-if="showSave">
|
||||
<div class="flex items-stretch gap-2">
|
||||
<StatusBadge :status="status" />
|
||||
<DropdownWithActions :actions="actions" />
|
||||
<Button
|
||||
@ -61,15 +58,15 @@
|
||||
height: `calc(var(--h-row-mid) * ${!!imageField ? '2 + 1px' : '1'})`,
|
||||
gridTemplateColumns: `minmax(0, 1.1fr) minmax(0, 2fr)`,
|
||||
}"
|
||||
v-if="doc && showName && (titleField || imageField)"
|
||||
v-if="doc && (titleField || imageField)"
|
||||
>
|
||||
<FormControl
|
||||
v-if="imageField"
|
||||
class="ms-4"
|
||||
:df="imageField"
|
||||
:value="doc[imageField.fieldname]"
|
||||
@change="(value) => valueChange(imageField, value)"
|
||||
:letter-placeholder="doc[titleField.fieldname]?.[0] ?? ''"
|
||||
@change="(value) => valueChange(imageField as Field, value)"
|
||||
:letter-placeholder="letterPlaceHolder"
|
||||
/>
|
||||
<FormControl
|
||||
v-if="titleField"
|
||||
@ -83,7 +80,7 @@
|
||||
:df="titleField"
|
||||
:value="doc[titleField.fieldname]"
|
||||
:read-only="doc.inserted || doc.schema.naming !== 'manual'"
|
||||
@change="(value) => valueChange(titleField, value)"
|
||||
@change="(value) => valueChange(titleField as Field, value)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -98,11 +95,14 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { t } from 'fyo';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import { DocStatus } from 'fyo/model/types';
|
||||
import { getDocStatus } from 'models/helpers';
|
||||
import { InvoiceStatus } from 'models/types';
|
||||
import { Field, Schema } from 'schemas/types';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
|
||||
@ -110,27 +110,21 @@ import StatusBadge from 'src/components/StatusBadge.vue';
|
||||
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { shortcutsKey } from 'src/utils/injectionKeys';
|
||||
import { DocRef } from 'src/utils/types';
|
||||
import {
|
||||
commonDocSubmit,
|
||||
commonDocSync,
|
||||
focusOrSelectFormControl,
|
||||
getActionsForDoc,
|
||||
openQuickEdit,
|
||||
} from 'src/utils/ui';
|
||||
import { useDocShortcuts } from 'src/utils/vueUtils';
|
||||
import { inject, ref } from 'vue';
|
||||
import { defineComponent, inject, ref } from 'vue';
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'QuickEditForm',
|
||||
props: {
|
||||
name: String,
|
||||
schemaName: String,
|
||||
defaults: String,
|
||||
white: { type: Boolean, default: false },
|
||||
routeBack: { type: Boolean, default: true },
|
||||
showName: { type: Boolean, default: true },
|
||||
showSave: { type: Boolean, default: true },
|
||||
sourceDoc: { type: Doc, default: null },
|
||||
name: { type: String, required: true },
|
||||
schemaName: { type: String, required: true },
|
||||
hideFields: { type: Array, default: () => [] },
|
||||
showFields: { type: Array, default: () => [] },
|
||||
},
|
||||
@ -143,7 +137,7 @@ export default {
|
||||
},
|
||||
emits: ['close'],
|
||||
setup() {
|
||||
const doc = ref(null);
|
||||
const doc = ref(null) as DocRef;
|
||||
const shortcuts = inject(shortcutsKey);
|
||||
|
||||
let context = 'QuickEditForm';
|
||||
@ -152,6 +146,7 @@ export default {
|
||||
}
|
||||
|
||||
return {
|
||||
form: ref<InstanceType<typeof TwoColumnForm> | null>(null),
|
||||
doc,
|
||||
context,
|
||||
shortcuts,
|
||||
@ -164,37 +159,52 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: null,
|
||||
titleField: null,
|
||||
imageField: null,
|
||||
statusText: null,
|
||||
statusText: '',
|
||||
} as {
|
||||
titleField: null | Field;
|
||||
imageField: null | Field;
|
||||
statusText: string;
|
||||
};
|
||||
},
|
||||
activated() {
|
||||
console.log('act');
|
||||
this.setShortcuts();
|
||||
},
|
||||
async mounted() {
|
||||
if (this.defaults) {
|
||||
this.values = JSON.parse(this.defaults);
|
||||
}
|
||||
|
||||
await this.fetchFieldsAndDoc();
|
||||
focusOrSelectFormControl(this.doc, this.$refs.titleControl, false);
|
||||
console.log('mou');
|
||||
await this.initialize();
|
||||
|
||||
if (fyo.store.isDevelopment) {
|
||||
// @ts-ignore
|
||||
window.qef = this;
|
||||
}
|
||||
|
||||
this.setShortcuts();
|
||||
},
|
||||
computed: {
|
||||
isChild() {
|
||||
return !!this?.doc?.schema?.isChild;
|
||||
letterPlaceHolder() {
|
||||
if (!this.doc) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const fn = this.titleField?.fieldname ?? 'name';
|
||||
const value = this.doc.get(fn);
|
||||
if (typeof value === 'string') {
|
||||
return value[0];
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
schema() {
|
||||
return fyo.schemaMap[this.schemaName] ?? null;
|
||||
schema(): Schema {
|
||||
return fyo.schemaMap[this.schemaName]!;
|
||||
},
|
||||
status() {
|
||||
status(): DocStatus | InvoiceStatus {
|
||||
if (!this.doc) {
|
||||
return 'Draft';
|
||||
}
|
||||
|
||||
return getDocStatus(this.doc);
|
||||
},
|
||||
fields() {
|
||||
@ -217,92 +227,84 @@ export default {
|
||||
return fieldnames.map((f) => fyo.getField(this.schemaName, f));
|
||||
},
|
||||
actions() {
|
||||
if (!this.doc) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getActionsForDoc(this.doc);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setShortcuts() {
|
||||
if (this.shortcuts.has(this.context, ['Escape'])) {
|
||||
if (this.shortcuts?.has(this.context, ['Escape'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.shortcuts.set(this.context, ['Escape'], () => {
|
||||
this.shortcuts?.set(this.context, ['Escape'], () => {
|
||||
this.routeToPrevious();
|
||||
});
|
||||
},
|
||||
async fetchFieldsAndDoc() {
|
||||
async initialize() {
|
||||
if (!this.schema) {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleField = this.schema.titleField;
|
||||
this.titleField = fyo.getField(this.schemaName, titleField);
|
||||
this.imageField = fyo.getField(this.schemaName, 'image');
|
||||
|
||||
await this.fetchDoc();
|
||||
// set default values
|
||||
if (this.values) {
|
||||
this.doc?.set(this.values);
|
||||
}
|
||||
},
|
||||
async fetchDoc() {
|
||||
if (this.sourceDoc) {
|
||||
return (this.doc = this.sourceDoc);
|
||||
}
|
||||
|
||||
if (!this.schemaName) {
|
||||
this.$router.back();
|
||||
}
|
||||
|
||||
if (this.name) {
|
||||
try {
|
||||
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
|
||||
} catch (e) {
|
||||
this.$router.back();
|
||||
}
|
||||
} else {
|
||||
this.doc = fyo.doc.getNewDoc(this.schemaName);
|
||||
}
|
||||
|
||||
if (this.doc === null) {
|
||||
this.setFields();
|
||||
await this.setDoc();
|
||||
if (!this.doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.doc.once('afterRename', () => {
|
||||
openQuickEdit({
|
||||
schemaName: this.schemaName,
|
||||
name: this.doc.name,
|
||||
});
|
||||
});
|
||||
focusOrSelectFormControl(this.doc, this.$refs.titleControl, false);
|
||||
},
|
||||
valueChange(df, value) {
|
||||
this.$refs.form.onChange(df, value);
|
||||
setFields() {
|
||||
const titleFieldName = this.schema.titleField ?? 'name';
|
||||
this.titleField = fyo.getField(this.schemaName, titleFieldName) ?? null;
|
||||
this.imageField = fyo.getField(this.schemaName, 'image') ?? null;
|
||||
},
|
||||
async setDoc() {
|
||||
try {
|
||||
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
|
||||
} catch (e) {
|
||||
return this.$router.back();
|
||||
}
|
||||
},
|
||||
valueChange(field: Field, value: DocValue) {
|
||||
this.form?.onChange(field, value);
|
||||
},
|
||||
async sync() {
|
||||
if (!this.doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.statusText = t`Saving`;
|
||||
await commonDocSync(this.doc);
|
||||
setTimeout(() => {
|
||||
this.statusText = null;
|
||||
this.statusText = '';
|
||||
}, 300);
|
||||
},
|
||||
async submit() {
|
||||
if (!this.doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.statusText = t`Submitting`;
|
||||
await commonDocSubmit(this.doc);
|
||||
setTimeout(() => {
|
||||
this.statusText = null;
|
||||
this.statusText = '';
|
||||
}, 300);
|
||||
},
|
||||
routeToPrevious() {
|
||||
if (this.doc.dirty && !this.doc.notInserted) {
|
||||
this.doc.load();
|
||||
async routeToPrevious() {
|
||||
if (this.doc?.dirty && this.doc?.inserted) {
|
||||
await this.doc.load();
|
||||
}
|
||||
|
||||
if (this.routeBack) {
|
||||
this.$router.back();
|
||||
} else {
|
||||
this.$emit('close');
|
||||
if (this.doc && this.doc.notInserted) {
|
||||
await this.doc.delete();
|
||||
}
|
||||
|
||||
this.$router.back();
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
@ -38,13 +38,10 @@ export type SettingsTab =
|
||||
| ModelNameEnum.SystemSettings;
|
||||
|
||||
export interface QuickEditOptions {
|
||||
doc?: Doc;
|
||||
schemaName?: string;
|
||||
name?: string;
|
||||
doc: Doc;
|
||||
hideFields?: string[];
|
||||
showFields?: string[];
|
||||
defaults?: Record<string, unknown>;
|
||||
listFilters?: QueryFilter;
|
||||
}
|
||||
|
||||
export type SidebarConfig = SidebarRoot[];
|
||||
|
@ -35,63 +35,26 @@ export const toastDurationMap = { short: 2_500, long: 5_000 } as const;
|
||||
|
||||
export async function openQuickEdit({
|
||||
doc,
|
||||
schemaName,
|
||||
name,
|
||||
hideFields = [],
|
||||
showFields = [],
|
||||
defaults = {},
|
||||
listFilters = {},
|
||||
}: QuickEditOptions) {
|
||||
if (doc) {
|
||||
schemaName = doc.schemaName;
|
||||
name = doc.name;
|
||||
const { schemaName, name } = doc;
|
||||
if (!name) {
|
||||
throw new ValueError(t`Quick edit error: ${schemaName} entry has no name.`);
|
||||
}
|
||||
|
||||
if (!doc && (!schemaName || !name)) {
|
||||
throw new ValueError(t`Schema Name or Name not passed to Open Quick Edit`);
|
||||
}
|
||||
|
||||
const currentRoute = router.currentRoute.value;
|
||||
const query = currentRoute.query;
|
||||
let method: 'push' | 'replace' = 'push';
|
||||
|
||||
if (query.edit && query.schemaName === schemaName) {
|
||||
method = 'replace';
|
||||
}
|
||||
|
||||
if (query.name === name) {
|
||||
if (router.currentRoute.value.query.name === name) {
|
||||
return;
|
||||
}
|
||||
|
||||
const forWhat = (defaults?.for ?? []) as string[];
|
||||
if (forWhat[0] === 'not in') {
|
||||
const purpose = forWhat[1]?.[0];
|
||||
|
||||
defaults = Object.assign({
|
||||
for:
|
||||
purpose === 'Sales'
|
||||
? 'Purchases'
|
||||
: purpose === 'Purchases'
|
||||
? 'Sales'
|
||||
: 'Both',
|
||||
});
|
||||
}
|
||||
|
||||
if (forWhat[0] === 'not in' && forWhat[1] === 'Sales') {
|
||||
defaults = Object.assign({ for: 'Purchases' });
|
||||
}
|
||||
|
||||
router[method]({
|
||||
query: {
|
||||
edit: 1,
|
||||
schemaName,
|
||||
name,
|
||||
showFields,
|
||||
hideFields,
|
||||
defaults: stringifyCircular(defaults),
|
||||
filters: JSON.stringify(listFilters),
|
||||
},
|
||||
});
|
||||
const query = {
|
||||
edit: 1,
|
||||
name,
|
||||
schemaName,
|
||||
showFields,
|
||||
hideFields,
|
||||
};
|
||||
router.push({ query });
|
||||
}
|
||||
|
||||
export async function openSettings(tab: SettingsTab) {
|
||||
|
Loading…
Reference in New Issue
Block a user