2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 14:50:56 +00:00

chore: ignore linting in component/**/*.vue

- fix linting errors in the rest of the files
This commit is contained in:
18alantom 2023-06-26 13:40:23 +05:30
parent 7c202ecee8
commit 247d4a4718
35 changed files with 434 additions and 270 deletions

View File

@ -37,6 +37,17 @@ module.exports = {
'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:prettier/recommended', 'plugin:prettier/recommended',
], ],
overrides: [
{
files: ['*.vue'],
rules: {
'@typescript-eslint/no-misused-promises': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
},
},
],
ignorePatterns: [ ignorePatterns: [
'*.mjs', '*.mjs',
'.eslintrc.js', '.eslintrc.js',
@ -46,5 +57,6 @@ module.exports = {
'*.spec.ts', '*.spec.ts',
'vite.config.ts', 'vite.config.ts',
'postcss.config.js', 'postcss.config.js',
'src/components/**/*.vue', // Incrementally fix these
], ],
}; };

View File

@ -305,7 +305,7 @@ export class DatabaseHandler extends DatabaseBase {
)) as IncomeExpense; )) as IncomeExpense;
} }
async getTotalCreditAndDebit(): Promise<unknown> { async getTotalCreditAndDebit(): Promise<TotalCreditAndDebit[]> {
return (await this.#demux.callBespoke( return (await this.#demux.callBespoke(
'getTotalCreditAndDebit' 'getTotalCreditAndDebit'
)) as TotalCreditAndDebit[]; )) as TotalCreditAndDebit[];

View File

@ -116,12 +116,12 @@ export default defineComponent({
}, },
}, },
watch: { watch: {
language(value) { language(value: string) {
this.languageDirection = getLanguageDirection(value); this.languageDirection = getLanguageDirection(value);
}, },
}, },
async mounted() { async mounted() {
this.setInitialScreen(); await this.setInitialScreen();
}, },
methods: { methods: {
async setInitialScreen(): Promise<void> { async setInitialScreen(): Promise<void> {
@ -209,7 +209,8 @@ export default defineComponent({
} }
if (actionSymbol === dbErrorActionSymbols.SelectFile) { if (actionSymbol === dbErrorActionSymbols.SelectFile) {
return await this.databaseSelector?.existingDatabase(); await this.databaseSelector?.existingDatabase();
return;
} }
throw error; throw error;
@ -219,9 +220,9 @@ export default defineComponent({
const { hideGetStarted } = await fyo.doc.getDoc('SystemSettings'); const { hideGetStarted } = await fyo.doc.getDoc('SystemSettings');
if (hideGetStarted || onboardingComplete) { if (hideGetStarted || onboardingComplete) {
routeTo('/'); await routeTo('/');
} else { } else {
routeTo('/get-started'); await routeTo('/get-started');
} }
}, },
async showDbSelector(): Promise<void> { async showDbSelector(): Promise<void> {

View File

@ -93,7 +93,7 @@
fieldname: 'value', fieldname: 'value',
fieldtype: 'Data', fieldtype: 'Data',
}" }"
:value="filter.value" :value="String(filter.value)"
@change="(value) => (filter.value = value)" @change="(value) => (filter.value = value)"
/> />
</div> </div>
@ -127,7 +127,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { t } from 'fyo'; import { t } from 'fyo';
import { Field, FieldTypeEnum, SelectOption } from 'schemas/types'; import { Field, FieldTypeEnum } from 'schemas/types';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { getRandomString } from 'utils'; import { getRandomString } from 'utils';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
@ -136,7 +136,7 @@ import Data from './Controls/Data.vue';
import Select from './Controls/Select.vue'; import Select from './Controls/Select.vue';
import Icon from './Icon.vue'; import Icon from './Icon.vue';
import Popover from './Popover.vue'; import Popover from './Popover.vue';
import { cloneDeep } from 'lodash'; import { QueryFilter } from 'utils/db/types';
const conditions = [ const conditions = [
{ label: t`Is`, value: '=' }, { label: t`Is`, value: '=' },
@ -154,7 +154,7 @@ type Condition = typeof conditions[number]['value'];
type Filter = { type Filter = {
fieldname: string; fieldname: string;
condition: Condition; condition: Condition;
value: string; value: QueryFilter[string];
implicit: boolean; implicit: boolean;
}; };
@ -237,7 +237,7 @@ export default defineComponent({
addFilter( addFilter(
fieldname: string, fieldname: string,
condition: Condition, condition: Condition,
value: string, value: Filter['value'],
implicit?: boolean implicit?: boolean
): void { ): void {
this.filters.push({ fieldname, condition, value, implicit: !!implicit }); this.filters.push({ fieldname, condition, value, implicit: !!implicit });
@ -245,16 +245,17 @@ export default defineComponent({
removeFilter(filter: Filter): void { removeFilter(filter: Filter): void {
this.filters = this.filters.filter((f) => f !== filter); this.filters = this.filters.filter((f) => f !== filter);
}, },
setFilter(filters: Record<string, Filter>, implicit?: boolean): void { setFilter(filters: QueryFilter, implicit?: boolean): void {
this.filters = []; this.filters = [];
Object.keys(filters).map((fieldname) => { Object.keys(filters).map((fieldname) => {
let parts = filters[fieldname]; let parts = filters[fieldname];
let condition, value; let condition: Condition;
let value: Filter['value'];
if (Array.isArray(parts)) { if (Array.isArray(parts)) {
condition = parts[0]; condition = parts[0] as Condition;
value = parts[1]; value = parts[1] as Filter['value'];
} else { } else {
condition = '='; condition = '=';
value = parts; value = parts;
@ -266,7 +267,7 @@ export default defineComponent({
this.emitFilterChange(); this.emitFilterChange();
}, },
emitFilterChange(): void { emitFilterChange(): void {
const filters: Record<string, [Condition, string]> = {}; const filters: Record<string, [Condition, Filter['value']]> = {};
for (const { condition, value, fieldname } of this.filters) { for (const { condition, value, fieldname } of this.filters) {
if (value === '' && condition) { if (value === '' && condition) {
continue; continue;

View File

@ -34,7 +34,7 @@
:style="getItemStyle(account.level)" :style="getItemStyle(account.level)"
@click="onClick(account)" @click="onClick(account)"
> >
<component :is="getIconComponent(account)" /> <component :is="getIconComponent(!!account.isGroup, account.name)" />
<div class="flex items-baseline"> <div class="flex items-baseline">
<div <div
class="ms-4" class="ms-4"
@ -91,9 +91,7 @@
" "
:style="getGroupStyle(account.level + 1)" :style="getGroupStyle(account.level + 1)"
> >
<component <component :is="getIconComponent(account.addingGroupAccount)" />
:is="getIconComponent({ isGroup: account.addingGroupAccount })"
/>
<div class="flex ms-4 h-row-mid items-center"> <div class="flex ms-4 h-row-mid items-center">
<input <input
:ref="account.name" :ref="account.name"
@ -140,7 +138,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script lang="ts">
import { t } from 'fyo'; import { t } from 'fyo';
import { isCredit } from 'models/helpers'; import { isCredit } from 'models/helpers';
import { ModelNameEnum } from 'models/types'; import { ModelNameEnum } from 'models/types';
@ -151,12 +149,32 @@ import { docsPathMap } from 'src/utils/misc';
import { docsPathRef } from 'src/utils/refs'; import { docsPathRef } from 'src/utils/refs';
import { openQuickEdit } from 'src/utils/ui'; import { openQuickEdit } from 'src/utils/ui';
import { getMapFromList, removeAtIndex } from 'utils/index'; import { getMapFromList, removeAtIndex } from 'utils/index';
import { nextTick } from 'vue'; import { defineComponent, nextTick } from 'vue';
import Button from '../components/Button.vue'; import Button from '../components/Button.vue';
import { inject } from 'vue'; import { inject } from 'vue';
import { handleErrorWithDialog } from '../errorHandling'; import { handleErrorWithDialog } from '../errorHandling';
import { AccountRootType, AccountType } from 'models/baseModels/Account/types';
import { TreeViewSettings } from 'fyo/model/types';
import { Doc } from 'fyo/model/doc';
import { Component } from 'vue';
export default { type AccountItem = {
name: string;
parentAccount: string;
rootType: AccountRootType;
accountType: AccountType;
level: number;
location: number[];
isGroup?: boolean;
children: AccountItem[];
expanded: boolean;
addingAccount: boolean;
addingGroupAccount: boolean;
};
type AccKey = 'addingAccount' | 'addingGroupAccount';
export default defineComponent({
components: { components: {
Button, Button,
PageHeader, PageHeader,
@ -170,21 +188,26 @@ export default {
return { return {
isAllCollapsed: true, isAllCollapsed: true,
isAllExpanded: false, isAllExpanded: false,
root: null, root: null as null | { label: string; balance: number; currency: string },
accounts: [], accounts: [] as AccountItem[],
schemaName: 'Account', schemaName: 'Account',
newAccountName: '', newAccountName: '',
insertingAccount: false, insertingAccount: false,
totals: {}, totals: {} as Record<string, { totalDebit: number; totalCredit: number }>,
refetchTotals: false, refetchTotals: false,
settings: null as null | TreeViewSettings,
}; };
}, },
computed: { computed: {
allAccounts() { allAccounts() {
const allAccounts = []; const allAccounts: AccountItem[] = [];
(function getAccounts(accounts, level, location) { (function getAccounts(
for (let i in accounts) { accounts: AccountItem[],
level: number,
location: number[]
) {
for (let i = 0; i < accounts.length; i++) {
const account = accounts[i]; const account = accounts[i];
account.level = level; account.level = level;
@ -207,12 +230,13 @@ export default {
}); });
}, },
async activated() { async activated() {
this.fetchAccounts(); await this.fetchAccounts();
if (fyo.store.isDevelopment) { if (fyo.store.isDevelopment) {
// @ts-ignore
window.coa = this; window.coa = this;
} }
docsPathRef.value = docsPathMap.ChartOfAccounts; docsPathRef.value = docsPathMap.ChartOfAccounts!;
if (this.refetchTotals) { if (this.refetchTotals) {
await this.setTotalDebitAndCredit(); await this.setTotalDebitAndCredit();
@ -233,7 +257,7 @@ export default {
this.isAllExpanded = false; this.isAllExpanded = false;
this.isAllCollapsed = true; this.isAllCollapsed = true;
}, },
async toggleAll(accounts, expand) { async toggleAll(accounts: AccountItem | AccountItem[], expand: boolean) {
if (!Array.isArray(accounts)) { if (!Array.isArray(accounts)) {
await this.toggle(accounts, expand); await this.toggle(accounts, expand);
accounts = accounts.children ?? []; accounts = accounts.children ?? [];
@ -243,14 +267,14 @@ export default {
await this.toggleAll(account, expand); await this.toggleAll(account, expand);
} }
}, },
async toggle(account, expand) { async toggle(account: AccountItem, expand: boolean) {
if (account.expanded === expand || !account.isGroup) { if (account.expanded === expand || !account.isGroup) {
return; return;
} }
await this.toggleChildren(account); await this.toggleChildren(account);
}, },
getBalance(account) { getBalance(account: AccountItem) {
const total = this.totals[account.name]; const total = this.totals[account.name];
if (!total) { if (!total) {
return 0; return 0;
@ -264,7 +288,7 @@ export default {
return totalDebit - totalCredit; return totalDebit - totalCredit;
}, },
getBalanceString(account) { getBalanceString(account: AccountItem) {
const suffix = isCredit(account.rootType) ? t`Cr.` : t`Dr.`; const suffix = isCredit(account.rootType) ? t`Cr.` : t`Dr.`;
const balance = this.getBalance(account); const balance = this.getBalance(account);
return `${fyo.format(balance, 'Currency')} ${suffix}`; return `${fyo.format(balance, 'Currency')} ${suffix}`;
@ -274,16 +298,19 @@ export default {
this.totals = getMapFromList(totals, 'account'); this.totals = getMapFromList(totals, 'account');
}, },
async fetchAccounts() { async fetchAccounts() {
this.settings = fyo.models[ModelNameEnum.Account].getTreeSettings(fyo); this.settings =
const { currency } = await fyo.doc.getDoc('AccountingSettings'); fyo.models[ModelNameEnum.Account]?.getTreeSettings(fyo) ?? null;
const currency = this.fyo.singles.SystemSettings?.currency ?? '';
const label = (await this.settings?.getRootLabel()) ?? '';
this.root = { this.root = {
label: await this.settings.getRootLabel(), label,
balance: 0, balance: 0,
currency, currency,
}; };
this.accounts = await this.getChildren(); this.accounts = await this.getChildren();
}, },
async onClick(account) { async onClick(account: AccountItem) {
let shouldOpen = !account.isGroup; let shouldOpen = !account.isGroup;
if (account.isGroup) { if (account.isGroup) {
shouldOpen = !(await this.toggleChildren(account)); shouldOpen = !(await this.toggleChildren(account));
@ -305,21 +332,29 @@ export default {
this.setOpenAccountDocListener(doc, account); this.setOpenAccountDocListener(doc, account);
await openQuickEdit({ doc }); await openQuickEdit({ doc });
}, },
setOpenAccountDocListener(doc, account, parentAccount) { setOpenAccountDocListener(
doc: Doc,
account?: AccountItem,
parentAccount?: AccountItem
) {
if (doc.hasListener('afterDelete')) { if (doc.hasListener('afterDelete')) {
return; return;
} }
doc.once('afterDelete', () => { doc.once('afterDelete', () => {
this.removeAccount(doc.name, account, parentAccount); this.removeAccount(doc.name!, account, parentAccount);
}); });
}, },
removeAccount(name, account, parentAccount) { removeAccount(
name: string,
account?: AccountItem,
parentAccount?: AccountItem
) {
if (account == null && parentAccount == null) { if (account == null && parentAccount == null) {
return; return;
} }
if (account == null) { if (account == null && parentAccount) {
account = parentAccount.children.find((ch) => ch?.name === name); account = parentAccount.children.find((ch) => ch?.name === name);
} }
@ -334,7 +369,7 @@ export default {
let children = this.accounts[i].children; let children = this.accounts[i].children;
while (indices.length > 1) { while (indices.length > 1) {
i = indices.shift(); i = indices.shift()!;
parent = children[i]; parent = children[i];
children = children[i].children; children = children[i].children;
@ -348,7 +383,7 @@ export default {
parent.children = removeAtIndex(children, i); parent.children = removeAtIndex(children, i);
}, },
async toggleChildren(account) { async toggleChildren(account: AccountItem) {
const hasChildren = await this.fetchChildren(account); const hasChildren = await this.fetchChildren(account);
if (!hasChildren) { if (!hasChildren) {
return false; return false;
@ -356,20 +391,20 @@ export default {
account.expanded = !account.expanded; account.expanded = !account.expanded;
if (!account.expanded) { if (!account.expanded) {
account.addingAccount = 0; account.addingAccount = false;
account.addingGroupAccount = 0; account.addingGroupAccount = false;
} }
return true; return true;
}, },
async fetchChildren(account, force = false) { async fetchChildren(account: AccountItem, force = false) {
if (account.children == null || force) { if (account.children == null || force) {
account.children = await this.getChildren(account.name); account.children = await this.getChildren(account.name);
} }
return !!account?.children?.length; return !!account?.children?.length;
}, },
async getChildren(parent = null) { async getChildren(parent: null | string = null): Promise<AccountItem[]> {
const children = await fyo.db.getAll(ModelNameEnum.Account, { const children = await fyo.db.getAll(ModelNameEnum.Account, {
filters: { filters: {
parentAccount: parent, parentAccount: parent,
@ -380,39 +415,39 @@ export default {
}); });
return children.map((d) => { return children.map((d) => {
d.expanded = 0; d.expanded = false;
d.addingAccount = 0; d.addingAccount = false;
d.addingGroupAccount = 0; d.addingGroupAccount = false;
return d;
return d as unknown as AccountItem;
}); });
}, },
async addAccount(parentAccount, key) { async addAccount(parentAccount: AccountItem, key: AccKey) {
if (!parentAccount.expanded) { if (!parentAccount.expanded) {
await this.fetchChildren(parentAccount); await this.fetchChildren(parentAccount);
parentAccount.expanded = true; parentAccount.expanded = true;
} }
// activate editing of type 'key' and deactivate other type // activate editing of type 'key' and deactivate other type
let otherKey = let otherKey: AccKey =
key === 'addingAccount' ? 'addingGroupAccount' : 'addingAccount'; key === 'addingAccount' ? 'addingGroupAccount' : 'addingAccount';
parentAccount[key] = 1; parentAccount[key] = true;
parentAccount[otherKey] = 0; parentAccount[otherKey] = false;
nextTick(() => { await nextTick();
let input = this.$refs[parentAccount.name][0]; let input = (this.$refs[parentAccount.name] as HTMLInputElement[])[0];
input.focus(); input.focus();
});
}, },
cancelAddingAccount(parentAccount) { cancelAddingAccount(parentAccount: AccountItem) {
parentAccount.addingAccount = 0; parentAccount.addingAccount = false;
parentAccount.addingGroupAccount = 0; parentAccount.addingGroupAccount = false;
this.newAccountName = ''; this.newAccountName = '';
}, },
async createNewAccount(parentAccount, isGroup) { async createNewAccount(parentAccount: AccountItem, isGroup: boolean) {
// freeze input // freeze input
this.insertingAccount = true; this.insertingAccount = true;
const accountName = this.newAccountName.trim(); const accountName = this.newAccountName.trim();
const doc = await fyo.doc.getNewDoc('Account'); const doc = fyo.doc.getNewDoc('Account');
try { try {
let { name, rootType, accountType } = parentAccount; let { name, rootType, accountType } = parentAccount;
await doc.set({ await doc.set({
@ -425,15 +460,15 @@ export default {
await doc.sync(); await doc.sync();
// turn off editing // turn off editing
parentAccount.addingAccount = 0; parentAccount.addingAccount = false;
parentAccount.addingGroupAccount = 0; parentAccount.addingGroupAccount = false;
// update accounts // update accounts
await this.fetchChildren(parentAccount, true); await this.fetchChildren(parentAccount, true);
// open quick edit // open quick edit
await openQuickEdit({ doc }); await openQuickEdit({ doc });
this.setOpenAccountDocListener(doc, null, parentAccount); this.setOpenAccountDocListener(doc, undefined, parentAccount);
// unfreeze input // unfreeze input
this.insertingAccount = false; this.insertingAccount = false;
@ -444,11 +479,11 @@ export default {
await handleErrorWithDialog(e, doc); await handleErrorWithDialog(e, doc);
} }
}, },
isQuickEditOpen(account) { isQuickEditOpen(account: AccountItem) {
let { edit, schemaName, name } = this.$route.query; let { edit, schemaName, name } = this.$route.query;
return !!(edit && schemaName === 'Account' && name === account.name); return !!(edit && schemaName === 'Account' && name === account.name);
}, },
getIconComponent(account) { getIconComponent(isGroup: boolean, name?: string): Component {
let icons = { let icons = {
'Application of Funds (Assets)': `<svg class="w-4 h-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> 'Application of Funds (Assets)': `<svg class="w-4 h-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
@ -481,14 +516,14 @@ export default {
<path d="M8.333 3.367L6.333.7H.667A.667.667 0 000 1.367v12a2 2 0 002 2h12a2 2 0 002-2V4.033a.667.667 0 00-.667-.666h-7z" fill="#415668" fill-rule="evenodd"/> <path d="M8.333 3.367L6.333.7H.667A.667.667 0 000 1.367v12a2 2 0 002 2h12a2 2 0 002-2V4.033a.667.667 0 00-.667-.666h-7z" fill="#415668" fill-rule="evenodd"/>
</svg>`; </svg>`;
let icon = account.isGroup ? folder : leaf; let icon = isGroup ? folder : leaf;
return { return {
template: icons[account.name] || icon, template: icons[name as keyof typeof icons] || icon,
}; };
}, },
getItemStyle(level) { getItemStyle(level: number) {
const styles = { const styles: Record<string, string> = {
height: 'calc(var(--h-row-mid) + 1px)', height: 'calc(var(--h-row-mid) + 1px)',
}; };
if (this.languageDirection === 'rtl') { if (this.languageDirection === 'rtl') {
@ -498,8 +533,8 @@ export default {
} }
return styles; return styles;
}, },
getGroupStyle(level) { getGroupStyle(level: number) {
const styles = { const styles: Record<string, string> = {
height: 'height: calc(var(--h-row-mid) + 1px)', height: 'height: calc(var(--h-row-mid) + 1px)',
}; };
if (this.languageDirection === 'rtl') { if (this.languageDirection === 'rtl') {
@ -510,5 +545,5 @@ export default {
return styles; return styles;
}, },
}, },
}; });
</script> </script>

View File

@ -81,13 +81,13 @@
<!-- Section Container --> <!-- Section Container -->
<div v-if="hasDoc" class="overflow-auto custom-scroll"> <div v-if="hasDoc" class="overflow-auto custom-scroll">
<CommonFormSection <CommonFormSection
v-for="([name, fields], idx) in activeGroup.entries()" v-for="([n, fields], idx) in activeGroup.entries()"
:key="name + idx" :key="n + idx"
ref="section" ref="section"
class="p-4" class="p-4"
:class="idx !== 0 && activeGroup.size > 1 ? 'border-t' : ''" :class="idx !== 0 && activeGroup.size > 1 ? 'border-t' : ''"
:show-title="activeGroup.size > 1 && name !== t`Default`" :show-title="activeGroup.size > 1 && n !== t`Default`"
:title="name" :title="n"
:fields="fields" :fields="fields"
:doc="doc" :doc="doc"
:errors="errors" :errors="errors"
@ -348,7 +348,7 @@ export default defineComponent({
const group = this.groupedFields.get(this.activeTab); const group = this.groupedFields.get(this.activeTab);
if (!group) { if (!group) {
const tab = [...this.groupedFields.keys()][0]; const tab = [...this.groupedFields.keys()][0];
return this.groupedFields.get(tab) ?? new Map(); return this.groupedFields.get(tab) ?? new Map<string, Field[]>();
} }
return group; return group;
@ -361,7 +361,7 @@ export default defineComponent({
return getGroupedActionsForDoc(this.doc); return getGroupedActionsForDoc(this.doc);
}, },
}, },
async beforeMount() { beforeMount() {
this.useFullWidth = !!this.fyo.singles.Misc?.useFullWidth; this.useFullWidth = !!this.fyo.singles.Misc?.useFullWidth;
}, },
async mounted() { async mounted() {
@ -438,14 +438,14 @@ export default defineComponent({
this.name this.name
); );
}, },
async replacePathAfterSync() { replacePathAfterSync() {
if (!this.hasDoc || this.doc.inserted) { if (!this.hasDoc || this.doc.inserted) {
return; return;
} }
this.doc.once('afterSync', () => { this.doc.once('afterSync', async () => {
const route = getFormRoute(this.schemaName, this.doc.name!); const route = getFormRoute(this.schemaName, this.doc.name!);
this.$router.replace(route); await this.$router.replace(route);
}); });
}, },
async showRowEditForm(doc: Doc) { async showRowEditForm(doc: Doc) {

View File

@ -56,6 +56,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { DocValue } from 'fyo/core/types'; import { DocValue } from 'fyo/core/types';
import { Doc } from 'fyo/model/doc'; import { Doc } from 'fyo/model/doc';
import { Field } from 'schemas/types'; import { Field } from 'schemas/types';
@ -67,12 +68,15 @@ import { defineComponent, PropType } from 'vue';
export default defineComponent({ export default defineComponent({
components: { FormControl, Table }, components: { FormControl, Table },
props: { props: {
title: String, title: { type: String, default: '' },
errors: Object as PropType<Record<string, string>>, errors: {
type: Object as PropType<Record<string, string>>,
required: true,
},
showTitle: Boolean, showTitle: Boolean,
doc: { type: Object as PropType<Doc>, required: true }, doc: { type: Object as PropType<Doc>, required: true },
collapsible: { type: Boolean, default: true }, collapsible: { type: Boolean, default: true },
fields: Array as PropType<Field[]>, fields: { type: Array as PropType<Field[]>, required: true },
}, },
emits: ['editrow', 'value-change', 'row-change'], emits: ['editrow', 'value-change', 'row-change'],
data() { data() {

View File

@ -80,7 +80,9 @@ export default defineComponent({
return rows[this.index]; return rows[this.index];
} }
const label = `${this.doc.name}.${this.fieldname}[${this.index}]`; const label = `${this.doc.name ?? '_name'}.${this.fieldname}[${
this.index
}]`;
throw new ValueError(this.t`Invalid value found for ${label}`); throw new ValueError(this.t`Invalid value found for ${label}`);
}, },
fields() { fields() {

View File

@ -1,19 +1,22 @@
<script lang="ts"> <script lang="ts">
import { PeriodKey } from 'src/utils/types';
import { PropType } from 'vue';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
export default defineComponent({ export default defineComponent({
props: { props: {
commonPeriod: String, commonPeriod: { type: String as PropType<PeriodKey>, default: 'This Year' },
}, },
emits: ['period-change'],
data() { data() {
return { return {
period: 'This Year', period: 'This Year' as PeriodKey,
periodOptions: ['This Year', 'This Quarter', 'This Month'], periodOptions: ['This Year', 'This Quarter', 'This Month'] as PeriodKey[],
}; };
}, },
watch: { watch: {
period: 'periodChange', period: 'periodChange',
commonPeriod(val) { commonPeriod(val: PeriodKey) {
if (!this.periodOptions.includes(val)) { if (!this.periodOptions.includes(val)) {
return; return;
} }
@ -26,7 +29,9 @@ export default defineComponent({
this.$emit('period-change', this.period); this.$emit('period-change', this.period);
await this.setData(); await this.setData();
}, },
async setData() {}, async setData() {
return Promise.resolve(null);
},
}, },
}); });
</script> </script>

View File

@ -42,7 +42,7 @@
/> />
</div> </div>
</template> </template>
<script> <script lang="ts">
import { AccountTypeEnum } from 'models/baseModels/Account/types'; import { AccountTypeEnum } from 'models/baseModels/Account/types';
import { ModelNameEnum } from 'models/types'; import { ModelNameEnum } from 'models/types';
import LineChart from 'src/components/Charts/LineChart.vue'; import LineChart from 'src/components/Charts/LineChart.vue';
@ -50,11 +50,19 @@ import { fyo } from 'src/initFyo';
import { formatXLabels, getYMax } from 'src/utils/chart'; import { formatXLabels, getYMax } from 'src/utils/chart';
import { uicolors } from 'src/utils/colors'; import { uicolors } from 'src/utils/colors';
import { getDatesAndPeriodList } from 'src/utils/misc'; import { getDatesAndPeriodList } from 'src/utils/misc';
import { getMapFromList } from 'utils/';
import DashboardChartBase from './BaseDashboardChart.vue'; import DashboardChartBase from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.vue'; import PeriodSelector from './PeriodSelector.vue';
import { defineComponent } from 'vue';
import { getMapFromList } from 'utils/index';
import { PeriodKey } from 'src/utils/types';
export default { // Linting broken in this file cause of `extends: ...`
/*
eslint-disable @typescript-eslint/no-unsafe-argument,
@typescript-eslint/no-unsafe-return
*/
export default defineComponent({
name: 'Cashflow', name: 'Cashflow',
components: { components: {
PeriodSelector, PeriodSelector,
@ -62,7 +70,7 @@ export default {
}, },
extends: DashboardChartBase, extends: DashboardChartBase,
data: () => ({ data: () => ({
data: [], data: [] as { inflow: number; outflow: number; yearmonth: string }[],
periodList: [], periodList: [],
periodOptions: ['This Year', 'This Quarter'], periodOptions: ['This Year', 'This Quarter'],
hasData: false, hasData: false,
@ -76,10 +84,12 @@ export default {
colors = [uicolors.gray['200'], uicolors.gray['100']]; colors = [uicolors.gray['200'], uicolors.gray['100']];
} }
const xLabels = data.map((cf) => cf['yearmonth']); const xLabels = data.map((cf) => cf.yearmonth);
const points = ['inflow', 'outflow'].map((k) => data.map((d) => d[k])); const points = (['inflow', 'outflow'] as const).map((k) =>
data.map((d) => d[k])
);
const format = (value) => fyo.format(value ?? 0, 'Currency'); const format = (value: number) => fyo.format(value ?? 0, 'Currency');
const yMax = getYMax(points); const yMax = getYMax(points);
return { points, xLabels, colors, format, yMax, formatX: formatXLabels }; return { points, xLabels, colors, format, yMax, formatX: formatXLabels };
}, },
@ -92,8 +102,8 @@ export default {
}, },
methods: { methods: {
async setData() { async setData() {
const { periodList, fromDate, toDate } = await getDatesAndPeriodList( const { periodList, fromDate, toDate } = getDatesAndPeriodList(
this.period this.period as PeriodKey
); );
const data = await fyo.db.getCashflow(fromDate.toISO(), toDate.toISO()); const data = await fyo.db.getCashflow(fromDate.toISO(), toDate.toISO());
@ -118,14 +128,14 @@ export default {
accountType: ['in', [AccountTypeEnum.Cash, AccountTypeEnum.Bank]], accountType: ['in', [AccountTypeEnum.Cash, AccountTypeEnum.Bank]],
}, },
}); });
const accountNames = accounts.map((a) => a.name); const accountNames = accounts.map((a) => a.name as string);
const count = await fyo.db.count(ModelNameEnum.AccountingLedgerEntry, { const count = await fyo.db.count(ModelNameEnum.AccountingLedgerEntry, {
filters: { account: ['in', accountNames] }, filters: { account: ['in', accountNames] },
}); });
this.hasData = count > 0; this.hasData = count > 0;
}, },
}, },
}; });
const dummyData = [ const dummyData = [
{ {

View File

@ -13,7 +13,7 @@
<!-- Ledgend Item --> <!-- Ledgend Item -->
<div <div
v-for="(d, i) in expenses" v-for="(d, i) in expenses"
:key="d.name" :key="d.account"
class="flex items-center text-sm" class="flex items-center text-sm"
@mouseover="active = i" @mouseover="active = i"
@mouseleave="active = null" @mouseleave="active = null"
@ -34,9 +34,9 @@
:offset-x="3" :offset-x="3"
:thickness="10" :thickness="10"
:text-offset-x="6.5" :text-offset-x="6.5"
:value-formatter="(value) => fyo.format(value, 'Currency')" :value-formatter="(value: number) => fyo.format(value, 'Currency')"
:total-label="t`Total Spending`" :total-label="t`Total Spending`"
@change="(value) => (active = value)" @change="(value: number) => (active = value)"
/> />
</div> </div>
@ -52,17 +52,24 @@
</div> </div>
</template> </template>
<script> <script lang="ts">
import { truncate } from 'lodash'; import { truncate } from 'lodash';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { uicolors } from 'src/utils/colors'; import { uicolors } from 'src/utils/colors';
import { getDatesAndPeriodList } from 'src/utils/misc'; import { getDatesAndPeriodList } from 'src/utils/misc';
import { defineComponent } from 'vue';
import DonutChart from '../../components/Charts/DonutChart.vue'; import DonutChart from '../../components/Charts/DonutChart.vue';
import DashboardChartBase from './BaseDashboardChart.vue'; import DashboardChartBase from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.vue'; import PeriodSelector from './PeriodSelector.vue';
import SectionHeader from './SectionHeader.vue'; import SectionHeader from './SectionHeader.vue';
export default { // Linting broken in this file cause of `extends: ...`
/*
eslint-disable @typescript-eslint/no-unsafe-argument,
@typescript-eslint/no-unsafe-return,
@typescript-eslint/restrict-plus-operands
*/
export default defineComponent({
name: 'Expenses', name: 'Expenses',
components: { components: {
DonutChart, DonutChart,
@ -71,17 +78,22 @@ export default {
}, },
extends: DashboardChartBase, extends: DashboardChartBase,
data: () => ({ data: () => ({
active: null, active: null as null | number,
expenses: [], expenses: [] as {
account: string;
total: number;
color: string;
class: string;
}[],
}), }),
computed: { computed: {
totalExpense() { totalExpense(): number {
return this.expenses.reduce((sum, expense) => sum + expense.total, 0); return this.expenses.reduce((sum, expense) => sum + expense.total, 0);
}, },
hasData() { hasData(): boolean {
return this.expenses.length > 0; return this.expenses.length > 0;
}, },
sectors() { sectors(): { color: string; label: string; value: number }[] {
return this.expenses.map(({ account, color, total }) => ({ return this.expenses.map(({ account, color, total }) => ({
color, color,
label: truncate(account, { length: 21 }), label: truncate(account, { length: 21 }),
@ -94,7 +106,7 @@ export default {
}, },
methods: { methods: {
async setData() { async setData() {
const { fromDate, toDate } = await getDatesAndPeriodList(this.period); const { fromDate, toDate } = getDatesAndPeriodList(this.period);
let topExpenses = await fyo.db.getTopExpenses( let topExpenses = await fyo.db.getTopExpenses(
fromDate.toISO(), fromDate.toISO(),
toDate.toISO() toDate.toISO()
@ -108,16 +120,16 @@ export default {
{ class: 'bg-pink-100', hex: uicolors.pink['100'] }, { class: 'bg-pink-100', hex: uicolors.pink['100'] },
]; ];
topExpenses = topExpenses this.expenses = topExpenses
.filter((e) => e.total > 0) .filter((e) => e.total > 0)
.map((d, i) => { .map((d, i) => {
d.color = shades[i].hex; return {
d.class = shades[i].class; ...d,
return d; color: shades[i].hex,
class: shades[i].class,
};
}); });
this.expenses = topExpenses;
}, },
}, },
}; });
</script> </script>

View File

@ -35,27 +35,30 @@
</Dropdown> </Dropdown>
</template> </template>
<script> <script lang="ts">
import { t } from 'fyo'; import { t } from 'fyo';
import Dropdown from 'src/components/Dropdown.vue'; import Dropdown from 'src/components/Dropdown.vue';
import { PeriodKey } from 'src/utils/types';
import { PropType } from 'vue';
import { defineComponent } from 'vue';
export default { export default defineComponent({
name: 'PeriodSelector', name: 'PeriodSelector',
components: { components: {
Dropdown, Dropdown,
}, },
props: { props: {
value: String, value: { type: String as PropType<PeriodKey>, default: 'This Year' },
options: { options: {
type: Array, type: Array as PropType<PeriodKey[]>,
default: () => ['This Year', 'This Quarter', 'This Month'], default: () => ['This Year', 'This Quarter', 'This Month'],
}, },
}, },
emits: ['change'], emits: ['change'],
data() { data() {
return { return {
periodSelectorMap: {}, periodSelectorMap: {} as Record<PeriodKey | '', string>,
periodOptions: [], periodOptions: [] as { label: string; action: () => void }[],
}; };
}, },
mounted() { mounted() {
@ -76,10 +79,12 @@ export default {
}); });
}, },
methods: { methods: {
selectOption(value) { selectOption(value: PeriodKey) {
this.$emit('change', value); this.$emit('change', value);
this.$refs.dropdown.toggleDropdown(false); (this.$refs.dropdown as InstanceType<typeof Dropdown>).toggleDropdown(
false
);
}, },
}, },
}; });
</script> </script>

View File

@ -29,7 +29,7 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script lang="ts">
import BarChart from 'src/components/Charts/BarChart.vue'; import BarChart from 'src/components/Charts/BarChart.vue';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { formatXLabels, getYMax, getYMin } from 'src/utils/chart'; import { formatXLabels, getYMax, getYMin } from 'src/utils/chart';
@ -39,8 +39,14 @@ import { getValueMapFromList } from 'utils';
import DashboardChartBase from './BaseDashboardChart.vue'; import DashboardChartBase from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.vue'; import PeriodSelector from './PeriodSelector.vue';
import SectionHeader from './SectionHeader.vue'; import SectionHeader from './SectionHeader.vue';
import { defineComponent } from 'vue';
export default { // Linting broken in this file cause of `extends: ...`
/*
eslint-disable @typescript-eslint/no-unsafe-argument,
@typescript-eslint/no-unsafe-return
*/
export default defineComponent({
name: 'ProfitAndLoss', name: 'ProfitAndLoss',
components: { components: {
PeriodSelector, PeriodSelector,
@ -49,7 +55,7 @@ export default {
}, },
extends: DashboardChartBase, extends: DashboardChartBase,
data: () => ({ data: () => ({
data: [], data: [] as { yearmonth: string; balance: number }[],
hasData: false, hasData: false,
periodOptions: ['This Year', 'This Quarter'], periodOptions: ['This Year', 'This Quarter'],
}), }),
@ -59,7 +65,7 @@ export default {
const colors = [ const colors = [
{ positive: uicolors.blue['500'], negative: uicolors.pink['500'] }, { positive: uicolors.blue['500'], negative: uicolors.pink['500'] },
]; ];
const format = (value) => fyo.format(value ?? 0, 'Currency'); const format = (value: number) => fyo.format(value ?? 0, 'Currency');
const yMax = getYMax(points); const yMax = getYMax(points);
const yMin = getYMin(points); const yMin = getYMin(points);
return { return {
@ -78,7 +84,7 @@ export default {
}, },
methods: { methods: {
async setData() { async setData() {
const { fromDate, toDate, periodList } = await getDatesAndPeriodList( const { fromDate, toDate, periodList } = getDatesAndPeriodList(
this.period this.period
); );
@ -102,5 +108,5 @@ export default {
this.hasData = data.income.length > 0 || data.expense.length > 0; this.hasData = data.income.length > 0 || data.expense.length > 0;
}, },
}, },
}; });
</script> </script>

View File

@ -89,11 +89,17 @@ import { getDatesAndPeriodList } from 'src/utils/misc';
import { PeriodKey } from 'src/utils/types'; import { PeriodKey } from 'src/utils/types';
import { routeTo } from 'src/utils/ui'; import { routeTo } from 'src/utils/ui';
import { safeParseFloat } from 'utils/index'; import { safeParseFloat } from 'utils/index';
import { defineComponent } from 'vue'; import { PropType, defineComponent } from 'vue';
import BaseDashboardChart from './BaseDashboardChart.vue'; import BaseDashboardChart from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.vue'; import PeriodSelector from './PeriodSelector.vue';
import SectionHeader from './SectionHeader.vue'; import SectionHeader from './SectionHeader.vue';
// Linting broken in this file cause of `extends: ...`
/*
eslint-disable @typescript-eslint/no-unsafe-argument,
@typescript-eslint/restrict-template-expressions,
@typescript-eslint/no-unsafe-return
*/
export default defineComponent({ export default defineComponent({
name: 'UnpaidInvoices', name: 'UnpaidInvoices',
components: { components: {
@ -103,7 +109,7 @@ export default defineComponent({
}, },
extends: BaseDashboardChart, extends: BaseDashboardChart,
props: { props: {
schemaName: { type: String, required: true }, schemaName: { type: String as PropType<string>, required: true },
}, },
data() { data() {
return { return {
@ -211,7 +217,7 @@ export default defineComponent({
}, },
async newInvoice() { async newInvoice() {
const doc = fyo.doc.getNewDoc(this.schemaName); const doc = fyo.doc.getNewDoc(this.schemaName);
await routeTo(`/edit/${this.schemaName}/${doc.name}`); await routeTo(`/edit/${this.schemaName}/${doc.name!}`);
}, },
async getCounts(schemaName: string, fromDate: DateTime, toDate: DateTime) { async getCounts(schemaName: string, fromDate: DateTime, toDate: DateTime) {

View File

@ -280,7 +280,7 @@ export default defineComponent({
}, },
async deleteDb(i: number) { async deleteDb(i: number) {
const file = this.files[i]; const file = this.files[i];
const vm = this; const setFiles = this.setFiles.bind(this);
await showDialog({ await showDialog({
title: t`Delete ${file.companyName}?`, title: t`Delete ${file.companyName}?`,
@ -291,13 +291,15 @@ export default defineComponent({
label: this.t`Yes`, label: this.t`Yes`,
async action() { async action() {
await deleteDb(file.dbPath); await deleteDb(file.dbPath);
await vm.setFiles(); await setFiles();
}, },
isPrimary: true, isPrimary: true,
}, },
{ {
label: this.t`No`, label: this.t`No`,
action() {}, action() {
return null;
},
isEscape: true, isEscape: true,
}, },
], ],
@ -305,7 +307,7 @@ export default defineComponent({
}, },
async createDemo() { async createDemo() {
if (!fyo.store.isDevelopment) { if (!fyo.store.isDevelopment) {
this.startDummyInstanceSetup(); await this.startDummyInstanceSetup();
} else { } else {
this.openModal = true; this.openModal = true;
} }
@ -363,14 +365,14 @@ export default defineComponent({
const filePath = (await getSelectedFilePath())?.filePaths?.[0]; const filePath = (await getSelectedFilePath())?.filePaths?.[0];
this.emitFileSelected(filePath); this.emitFileSelected(filePath);
}, },
async selectFile(file: ConfigFilesWithModified) { selectFile(file: ConfigFilesWithModified) {
if (this.creatingDemo) { if (this.creatingDemo) {
return; return;
} }
await this.emitFileSelected(file.dbPath); this.emitFileSelected(file.dbPath);
}, },
async emitFileSelected(filePath: string, isNew?: boolean) { emitFileSelected(filePath: string, isNew?: boolean) {
if (!filePath) { if (!filePath) {
return; return;
} }

View File

@ -5,6 +5,7 @@ import { toggleSidebar } from 'src/utils/ui';
<template> <template>
<div class="flex overflow-hidden"> <div class="flex overflow-hidden">
<Transition name="sidebar"> <Transition name="sidebar">
<!-- eslint-disable vue/require-explicit-emits -->
<Sidebar <Sidebar
v-show="showSidebar" v-show="showSidebar"
class="flex-shrink-0 border-e whitespace-nowrap w-sidebar" class="flex-shrink-0 border-e whitespace-nowrap w-sidebar"

View File

@ -47,7 +47,7 @@
@click="handleAction(item)" @click="handleAction(item)"
> >
<span class="text-base text-white"> <span class="text-base text-white">
{{ item.actionLabel || t`Set Up` }} {{ t`Set Up` }}
</span> </span>
</Button> </Button>
<Button <Button
@ -69,15 +69,21 @@
</div> </div>
</template> </template>
<script> <script lang="ts">
import { DocValue } from 'fyo/core/types';
import Button from 'src/components/Button.vue'; import Button from 'src/components/Button.vue';
import Icon from 'src/components/Icon.vue'; import Icon from 'src/components/Icon.vue';
import PageHeader from 'src/components/PageHeader.vue'; import PageHeader from 'src/components/PageHeader.vue';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { getGetStartedConfig } from 'src/utils/getStartedConfig'; import { getGetStartedConfig } from 'src/utils/getStartedConfig';
import { openLink } from 'src/utils/ipcCalls'; import { openLink } from 'src/utils/ipcCalls';
import { h } from 'vue'; import { GetStartedConfigItem } from 'src/utils/types';
export default { import { Component } from 'vue';
import { defineComponent, h } from 'vue';
type ListItem = GetStartedConfigItem['items'][number];
export default defineComponent({
name: 'GetStarted', name: 'GetStarted',
components: { components: {
PageHeader, PageHeader,
@ -86,19 +92,19 @@ export default {
}, },
data() { data() {
return { return {
activeCard: null, activeCard: null as string | null,
sections: [], sections: getGetStartedConfig(),
}; };
}, },
mounted() { mounted() {
this.sections = getGetStartedConfig(); // this.sections = getGetStartedConfig();
}, },
async activated() { async activated() {
await fyo.doc.getDoc('GetStarted'); await fyo.doc.getDoc('GetStarted');
this.checkForCompletedTasks(); await this.checkForCompletedTasks();
}, },
methods: { methods: {
async handleDocumentation({ key, documentation }) { async handleDocumentation({ key, documentation }: ListItem) {
if (documentation) { if (documentation) {
openLink(documentation); openLink(documentation);
} }
@ -109,7 +115,7 @@ export default {
break; break;
} }
}, },
async handleAction({ key, action }) { async handleAction({ key, action }: ListItem) {
if (action) { if (action) {
action(); action();
this.activeCard = null; this.activeCard = null;
@ -134,12 +140,12 @@ export default {
} }
}, },
async checkIsOnboardingComplete() { async checkIsOnboardingComplete() {
if (fyo.singles.GetStarted.onboardingComplete) { if (fyo.singles.GetStarted?.onboardingComplete) {
return true; return true;
} }
const doc = await fyo.doc.getDoc('GetStarted'); const doc = await fyo.doc.getDoc('GetStarted');
const onboardingComplete = fyo.schemaMap.GetStarted.fields const onboardingComplete = fyo.schemaMap.GetStarted?.fields
.filter(({ fieldname }) => fieldname !== 'onboardingComplete') .filter(({ fieldname }) => fieldname !== 'onboardingComplete')
.map(({ fieldname }) => doc.get(fieldname)) .map(({ fieldname }) => doc.get(fieldname))
.every(Boolean); .every(Boolean);
@ -154,41 +160,41 @@ export default {
return onboardingComplete; return onboardingComplete;
}, },
async checkForCompletedTasks() { async checkForCompletedTasks() {
let toUpdate = {}; let toUpdate: Record<string, DocValue> = {};
if (await this.checkIsOnboardingComplete()) { if (await this.checkIsOnboardingComplete()) {
return; return;
} }
if (!fyo.singles.GetStarted.salesItemCreated) { if (!fyo.singles.GetStarted?.salesItemCreated) {
const count = await fyo.db.count('Item', { filters: { for: 'Sales' } }); const count = await fyo.db.count('Item', { filters: { for: 'Sales' } });
toUpdate.salesItemCreated = count > 0; toUpdate.salesItemCreated = count > 0;
} }
if (!fyo.singles.GetStarted.purchaseItemCreated) { if (!fyo.singles.GetStarted?.purchaseItemCreated) {
const count = await fyo.db.count('Item', { const count = await fyo.db.count('Item', {
filters: { for: 'Purchases' }, filters: { for: 'Purchases' },
}); });
toUpdate.purchaseItemCreated = count > 0; toUpdate.purchaseItemCreated = count > 0;
} }
if (!fyo.singles.GetStarted.invoiceCreated) { if (!fyo.singles.GetStarted?.invoiceCreated) {
const count = await fyo.db.count('SalesInvoice'); const count = await fyo.db.count('SalesInvoice');
toUpdate.invoiceCreated = count > 0; toUpdate.invoiceCreated = count > 0;
} }
if (!fyo.singles.GetStarted.customerCreated) { if (!fyo.singles.GetStarted?.customerCreated) {
const count = await fyo.db.count('Party', { const count = await fyo.db.count('Party', {
filters: { role: 'Customer' }, filters: { role: 'Customer' },
}); });
toUpdate.customerCreated = count > 0; toUpdate.customerCreated = count > 0;
} }
if (!fyo.singles.GetStarted.billCreated) { if (!fyo.singles.GetStarted?.billCreated) {
const count = await fyo.db.count('SalesInvoice'); const count = await fyo.db.count('SalesInvoice');
toUpdate.billCreated = count > 0; toUpdate.billCreated = count > 0;
} }
if (!fyo.singles.GetStarted.supplierCreated) { if (!fyo.singles.GetStarted?.supplierCreated) {
const count = await fyo.db.count('Party', { const count = await fyo.db.count('Party', {
filters: { role: 'Supplier' }, filters: { role: 'Supplier' },
}); });
@ -196,20 +202,21 @@ export default {
} }
await this.updateChecks(toUpdate); await this.updateChecks(toUpdate);
}, },
async updateChecks(toUpdate) { async updateChecks(toUpdate: Record<string, DocValue>) {
await fyo.singles.GetStarted.setAndSync(toUpdate); await fyo.singles.GetStarted?.setAndSync(toUpdate);
await fyo.doc.getDoc('GetStarted'); await fyo.doc.getDoc('GetStarted');
}, },
isCompleted(item) { isCompleted(item: ListItem) {
return fyo.singles.GetStarted.get(item.fieldname) || false; return fyo.singles.GetStarted?.get(item.fieldname) || false;
}, },
getIconComponent(item) { getIconComponent(item: ListItem) {
let completed = fyo.singles.GetStarted[item.fieldname] || false; let completed = fyo.singles.GetStarted?.[item.fieldname] || false;
let name = completed ? 'green-check' : item.icon; let name = completed ? 'green-check' : item.icon;
let size = completed ? '24' : '18'; let size = completed ? '24' : '18';
return { return {
name, name,
render() { render() {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return h(Icon, { return h(Icon, {
...Object.assign( ...Object.assign(
{ {
@ -220,8 +227,8 @@ export default {
), ),
}); });
}, },
}; } as Component;
}, },
}, },
}; });
</script> </script>

View File

@ -384,10 +384,10 @@ import DropdownWithActions from 'src/components/DropdownWithActions.vue';
import FormHeader from 'src/components/FormHeader.vue'; import FormHeader from 'src/components/FormHeader.vue';
import Modal from 'src/components/Modal.vue'; import Modal from 'src/components/Modal.vue';
import PageHeader from 'src/components/PageHeader.vue'; import PageHeader from 'src/components/PageHeader.vue';
import { getColumnLabel, Importer, TemplateField } from 'src/importer'; import { Importer, TemplateField, getColumnLabel } from 'src/importer';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { showDialog } from 'src/utils/interactive'; import { showDialog } from 'src/utils/interactive';
import { getSavePath, saveData, selectFile } from 'src/utils/ipcCalls'; import { getSavePath, saveData } from 'src/utils/ipcCalls';
import { docsPathMap } from 'src/utils/misc'; import { docsPathMap } from 'src/utils/misc';
import { docsPathRef } from 'src/utils/refs'; import { docsPathRef } from 'src/utils/refs';
import { selectTextFile } from 'src/utils/ui'; import { selectTextFile } from 'src/utils/ui';
@ -603,7 +603,7 @@ export default defineComponent({
component: { component: {
template: `<span>{{ "${selectFileLabel}" }}</span>`, template: `<span>{{ "${selectFileLabel}" }}</span>`,
}, },
action: this.selectFile, action: this.selectFile.bind(this),
}); });
} }
@ -620,7 +620,7 @@ export default defineComponent({
component: { component: {
template: '<span class="text-red-700" >{{ t`Cancel` }}</span>', template: '<span class="text-red-700" >{{ t`Cancel` }}</span>',
}, },
action: this.clear, action: this.clear.bind(this),
}; };
actions.push(pickColumnsAction, cancelAction); actions.push(pickColumnsAction, cancelAction);
@ -668,8 +668,8 @@ export default defineComponent({
}, },
pickedArray(): string[] { pickedArray(): string[] {
return [...this.importer.templateFieldsPicked.entries()] return [...this.importer.templateFieldsPicked.entries()]
.filter(([_, picked]) => picked) .filter(([, picked]) => picked)
.map(([key, _]) => key); .map(([key]) => key);
}, },
}, },
watch: { watch: {
@ -750,7 +750,11 @@ export default defineComponent({
return; return;
} }
for (const idx in this.importer.assignedTemplateFields) { for (
let idx = 0;
idx < this.importer.assignedTemplateFields.length;
idx++
) {
this.importer.assignedTemplateFields[idx] = null; this.importer.assignedTemplateFields[idx] = null;
} }
@ -764,10 +768,10 @@ export default defineComponent({
idx += 1; idx += 1;
} }
}, },
showMe(): void { async showMe(): Promise<void> {
const schemaName = this.importer.schemaName; const schemaName = this.importer.schemaName;
this.clear(); this.clear();
this.$router.push(`/list/${schemaName}`); await this.$router.push(`/list/${schemaName}`);
}, },
clear(): void { clear(): void {
this.file = null; this.file = null;
@ -821,7 +825,7 @@ export default defineComponent({
title, title,
type: 'error', type: 'error',
detail: this.t`Following links do not exist: ${absentLinks detail: this.t`Following links do not exist: ${absentLinks
.map((l) => `(${l.schemaLabel}, ${l.name})`) .map((l) => `(${l.schemaLabel ?? l.schemaName}, ${l.name})`)
.join(', ')}.`, .join(', ')}.`,
}); });
return false; return false;
@ -883,7 +887,9 @@ export default defineComponent({
}, },
{ {
label: this.t`No`, label: this.t`No`,
action() {}, action() {
return null;
},
isEscape: true, isEscape: true,
}, },
], ],

View File

@ -37,7 +37,7 @@
<!-- Data Rows --> <!-- Data Rows -->
<div v-if="dataSlice.length !== 0" class="overflow-y-auto custom-scroll"> <div v-if="dataSlice.length !== 0" class="overflow-y-auto custom-scroll">
<div v-for="(row, i) in dataSlice" :key="row.name"> <div v-for="(row, i) in dataSlice" :key="(row.name as string)">
<!-- Row Content --> <!-- Row Content -->
<div class="flex hover:bg-gray-50 items-center"> <div class="flex hover:bg-gray-50 items-center">
<p class="w-8 text-end me-4 text-gray-900"> <p class="w-8 text-end me-4 text-gray-900">
@ -56,7 +56,7 @@
'text-end': isNumeric(column.fieldtype), 'text-end': isNumeric(column.fieldtype),
'pe-4': c === columns.length - 1, 'pe-4': c === columns.length - 1,
}" }"
:row="row" :row="(row as RenderData)"
:column="column" :column="column"
/> />
</Row> </Row>
@ -93,14 +93,16 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script lang="ts">
import { ListViewSettings, RenderData } from 'fyo/model/types';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import Button from 'src/components/Button.vue'; import Button from 'src/components/Button.vue';
import Paginator from 'src/components/Paginator.vue'; import Paginator from 'src/components/Paginator.vue';
import Row from 'src/components/Row.vue'; import Row from 'src/components/Row.vue';
import { fyo } from 'src/initFyo'; import { fyo } from 'src/initFyo';
import { isNumeric } from 'src/utils'; import { isNumeric } from 'src/utils';
import { defineComponent } from 'vue'; import { QueryFilter } from 'utils/db/types';
import { PropType, defineComponent } from 'vue';
import ListCell from './ListCell.vue'; import ListCell from './ListCell.vue';
export default defineComponent({ export default defineComponent({
@ -112,15 +114,21 @@ export default defineComponent({
Paginator, Paginator,
}, },
props: { props: {
listConfig: Object, listConfig: {
filters: Object, type: Object as PropType<ListViewSettings | undefined>,
schemaName: String, default: () => ({ columns: [] }),
},
filters: {
type: Object as PropType<QueryFilter>,
default: () => ({}),
},
schemaName: { type: String, required: true },
canCreate: Boolean, canCreate: Boolean,
}, },
emits: ['openDoc', 'makeNewDoc', 'updatedData'], emits: ['openDoc', 'makeNewDoc', 'updatedData'],
data() { data() {
return { return {
data: [], data: [] as RenderData[],
pageStart: 0, pageStart: 0,
pageEnd: 0, pageEnd: 0,
}; };
@ -136,7 +144,7 @@ export default defineComponent({
let columns = this.listConfig?.columns ?? []; let columns = this.listConfig?.columns ?? [];
if (columns.length === 0) { if (columns.length === 0) {
columns = fyo.schemaMap[this.schemaName].quickEditFields ?? []; columns = fyo.schemaMap[this.schemaName]?.quickEditFields ?? [];
columns = [...new Set(['name', ...columns])]; columns = [...new Set(['name', ...columns])];
} }
@ -152,12 +160,12 @@ export default defineComponent({
}, },
}, },
watch: { watch: {
schemaName(oldValue, newValue) { async schemaName(oldValue, newValue) {
if (oldValue === newValue) { if (oldValue === newValue) {
return; return;
} }
this.updateData(); await this.updateData();
}, },
}, },
async mounted() { async mounted() {
@ -166,7 +174,7 @@ export default defineComponent({
}, },
methods: { methods: {
isNumeric, isNumeric,
setPageIndices({ start, end }) { setPageIndices({ start, end }: { start: number; end: number }) {
this.pageStart = start; this.pageStart = start;
this.pageEnd = end; this.pageEnd = end;
}, },
@ -175,11 +183,11 @@ export default defineComponent({
return; return;
} }
const listener = () => { const listener = async () => {
this.updateData(); await this.updateData();
}; };
if (fyo.schemaMap[this.schemaName].isSubmittable) { if (fyo.schemaMap[this.schemaName]?.isSubmittable) {
fyo.doc.observer.on(`submit:${this.schemaName}`, listener); fyo.doc.observer.on(`submit:${this.schemaName}`, listener);
fyo.doc.observer.on(`revert:${this.schemaName}`, listener); fyo.doc.observer.on(`revert:${this.schemaName}`, listener);
} }
@ -188,7 +196,7 @@ export default defineComponent({
fyo.db.observer.on(`delete:${this.schemaName}`, listener); fyo.db.observer.on(`delete:${this.schemaName}`, listener);
fyo.doc.observer.on(`rename:${this.schemaName}`, listener); fyo.doc.observer.on(`rename:${this.schemaName}`, listener);
}, },
async updateData(filters) { async updateData(filters?: Record<string, unknown>) {
if (!filters) { if (!filters) {
filters = { ...this.filters }; filters = { ...this.filters };
} }
@ -201,13 +209,16 @@ export default defineComponent({
orderBy.unshift('date'); orderBy.unshift('date');
} }
this.data = ( const tableData = await fyo.db.getAll(this.schemaName, {
await fyo.db.getAll(this.schemaName, { fields: ['*'],
fields: ['*'], filters: filters as QueryFilter,
filters, orderBy,
orderBy, });
})
).map((d) => ({ ...d, schema: fyo.schemaMap[this.schemaName] })); this.data = tableData.map((d) => ({
...d,
schema: fyo.schemaMap[this.schemaName],
})) as RenderData[];
this.$emit('updatedData', filters); this.$emit('updatedData', filters);
}, },
}, },

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="flex items-center truncate" :class="cellClass"> <div class="flex items-center truncate" :class="cellClass">
<span v-if="!customRenderer" class="truncate">{{ columnValue }}</span> <span v-if="!customRenderer" class="truncate">{{ columnValue }}</span>
<component :is="customRenderer" v-else /> <component :is="(customRenderer as {})" v-else />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -28,9 +28,9 @@
:filters="filters" :filters="filters"
:can-create="canCreate" :can-create="canCreate"
class="flex-1 flex h-full" class="flex-1 flex h-full"
@openDoc="openDoc" @open-doc="openDoc"
@updatedData="updatedData" @updated-data="updatedData"
@makeNewDoc="makeNewDoc" @make-new-doc="makeNewDoc"
/> />
<Modal :open-modal="openExportModal" @closemodal="openExportModal = false"> <Modal :open-modal="openExportModal" @closemodal="openExportModal = false">
<ExportWizard <ExportWizard
@ -73,7 +73,7 @@ export default defineComponent({
}, },
props: { props: {
schemaName: { type: String, required: true }, schemaName: { type: String, required: true },
filters: Object, filters: { type: Object, default: undefined },
pageTitle: { type: String, default: '' }, pageTitle: { type: String, default: '' },
}, },
setup() { setup() {
@ -114,7 +114,7 @@ export default defineComponent({
return fyo.schemaMap[this.schemaName]?.create !== false; return fyo.schemaMap[this.schemaName]?.create !== false;
}, },
}, },
async activated() { activated() {
if (typeof this.filters === 'object') { if (typeof this.filters === 'object') {
this.filterDropdown?.setFilter(this.filters, true); this.filterDropdown?.setFilter(this.filters, true);
} }

View File

@ -244,7 +244,7 @@ export default defineComponent({
this.templateList = list.map(({ name }) => name); this.templateList = list.map(({ name }) => name);
}, },
async savePDF() { savePDF() {
const printContainer = this.$refs.printContainer as { const printContainer = this.$refs.printContainer as {
savePDF: (name?: string) => void; savePDF: (name?: string) => void;
}; };

View File

@ -205,11 +205,13 @@ export default defineComponent({
const matrix: { value: string; idx: number }[][] = [columns]; const matrix: { value: string; idx: number }[][] = [columns];
const start = Math.max(this.start - 1, 1); const start = Math.max(this.start - 1, 1);
const end = Math.min(start + this.limit, this.report.reportData.length); const end = Math.min(start + this.limit, this.report.reportData.length);
for (const i in this.report.reportData.slice(start, end)) { const slice = this.report.reportData.slice(start, end);
const row = this.report.reportData[Number(i) + start];
for (let i = 0; i < slice.length; i++) {
const row = slice[i];
matrix.push([]); matrix.push([]);
for (const j in row.cells) { for (let j = 0; j < row.cells.length; j++) {
if (!this.columnSelection[j]) { if (!this.columnSelection[j]) {
continue; continue;
} }

View File

@ -87,8 +87,6 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed } from 'vue';
import { t } from 'fyo';
import { DocValue } from 'fyo/core/types'; import { DocValue } from 'fyo/core/types';
import { Field, Schema } from 'schemas/types'; import { Field, Schema } from 'schemas/types';
import Button from 'src/components/Button.vue'; import Button from 'src/components/Button.vue';
@ -104,7 +102,7 @@ import {
focusOrSelectFormControl, focusOrSelectFormControl,
} from 'src/utils/ui'; } from 'src/utils/ui';
import { useDocShortcuts } from 'src/utils/vueUtils'; import { useDocShortcuts } from 'src/utils/vueUtils';
import { defineComponent, inject, ref } from 'vue'; import { computed, defineComponent, inject, ref } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'QuickEditForm', name: 'QuickEditForm',
@ -191,6 +189,7 @@ export default defineComponent({
activated() { activated() {
this.setShortcuts(); this.setShortcuts();
}, },
// eslint-disable-next-line @typescript-eslint/no-misused-promises
async mounted() { async mounted() {
await this.initialize(); await this.initialize();
@ -203,8 +202,8 @@ export default defineComponent({
}, },
methods: { methods: {
setShortcuts() { setShortcuts() {
this.shortcuts?.set(this.context, ['Escape'], () => { this.shortcuts?.set(this.context, ['Escape'], async () => {
this.routeToPrevious(); await this.routeToPrevious();
}); });
}, },
async initialize() { async initialize() {

View File

@ -45,8 +45,8 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed } from 'vue';
import { t } from 'fyo'; import { t } from 'fyo';
import { DocValue } from 'fyo/core/types';
import { reports } from 'reports'; import { reports } from 'reports';
import { Report } from 'reports/Report'; import { Report } from 'reports/Report';
import Button from 'src/components/Button.vue'; import Button from 'src/components/Button.vue';
@ -60,7 +60,7 @@ import { docsPathMap, getReport } from 'src/utils/misc';
import { docsPathRef } from 'src/utils/refs'; import { docsPathRef } from 'src/utils/refs';
import { ActionGroup } from 'src/utils/types'; import { ActionGroup } from 'src/utils/types';
import { routeTo } from 'src/utils/ui'; import { routeTo } from 'src/utils/ui';
import { PropType, defineComponent, inject } from 'vue'; import { PropType, computed, defineComponent, inject } from 'vue';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -119,12 +119,13 @@ export default defineComponent({
return Object.values(actionsMap); return Object.values(actionsMap);
}, },
}, },
// eslint-disable-next-line @typescript-eslint/no-misused-promises
async activated() { async activated() {
docsPathRef.value = docsPathRef.value =
docsPathMap[this.reportClassName] ?? docsPathMap.Reports!; docsPathMap[this.reportClassName] ?? docsPathMap.Reports!;
await this.setReportData(); await this.setReportData();
const filters = JSON.parse(this.defaultFilters); const filters = JSON.parse(this.defaultFilters) as Record<string, DocValue>;
const filterKeys = Object.keys(filters); const filterKeys = Object.keys(filters);
for (const key of filterKeys) { for (const key of filterKeys) {
await this.report?.set(key, filters[key]); await this.report?.set(key, filters[key]);
@ -139,8 +140,8 @@ export default defineComponent({
window.rep = this; window.rep = this;
} }
this.shortcuts?.pmod.set(this.reportClassName, ['KeyP'], () => { this.shortcuts?.pmod.set(this.reportClassName, ['KeyP'], async () => {
routeTo(`/report-print/${this.reportClassName}`); await routeTo(`/report-print/${this.reportClassName}`);
}); });
}, },
deactivated() { deactivated() {

View File

@ -176,12 +176,12 @@ export default defineComponent({
} }
docsPathRef.value = docsPathMap.Settings ?? ''; docsPathRef.value = docsPathMap.Settings ?? '';
this.shortcuts?.pmod.set(COMPONENT_NAME, ['KeyS'], () => { this.shortcuts?.pmod.set(COMPONENT_NAME, ['KeyS'], async () => {
if (!this.canSave) { if (!this.canSave) {
return; return;
} }
this.sync(); await this.sync();
}); });
}, },
async deactivated(): Promise<void> { async deactivated(): Promise<void> {
@ -214,7 +214,7 @@ export default defineComponent({
} }
this.update(); this.update();
showDialog({ await showDialog({
title: this.t`Reload Frappe Books?`, title: this.t`Reload Frappe Books?`,
detail: this.t`Changes made to settings will be visible on reload.`, detail: this.t`Changes made to settings will be visible on reload.`,
type: 'info', type: 'info',
@ -226,7 +226,7 @@ export default defineComponent({
}, },
{ {
label: this.t`No`, label: this.t`No`,
action() {}, action: () => null,
isEscape: true, isEscape: true,
}, },
], ],

View File

@ -97,7 +97,8 @@ export default defineComponent({
return ''; return '';
}, },
}, },
} as {} /** to silence :is type check */; // eslint-disable-next-line @typescript-eslint/ban-types
} as {};
}, },
}, },
watch: { watch: {
@ -128,8 +129,8 @@ export default defineComponent({
this.error = null; this.error = null;
return compile(template, { return compile(template, {
hoistStatic: true, hoistStatic: true,
onWarn: this.onError, onWarn: this.onError.bind(this),
onError: this.onError, onError: this.onError.bind(this),
}); });
}, },
handleErrorCaptured(error: unknown) { handleErrorCaptured(error: unknown) {
@ -160,6 +161,8 @@ export default defineComponent({
return generateCodeFrame(this.template, loc.start.offset, loc.end.offset); return generateCodeFrame(this.template, loc.start.offset, loc.end.offset);
}, },
async savePDF(name?: string) { async savePDF(name?: string) {
/* eslint-disable */
/** /**
* To be called through ref by the parent component. * To be called through ref by the parent component.
*/ */

View File

@ -29,8 +29,8 @@ export default defineComponent({
computed: { computed: {
innerContainerStyle(): Record<string, string> { innerContainerStyle(): Record<string, string> {
const style: Record<string, string> = {}; const style: Record<string, string> = {};
style['width'] = this.width + 'cm'; style['width'] = `${this.width}cm`;
style['height'] = this.height + 'cm'; style['height'] = `${this.height}cm`;
style['transform'] = `scale(${this.scale})`; style['transform'] = `scale(${this.scale})`;
style['margin-top'] = `calc(-1 * (${this.height}cm * ${ style['margin-top'] = `calc(-1 * (${this.height}cm * ${
1 - this.scale 1 - this.scale

View File

@ -55,6 +55,7 @@ type SizeName = typeof printSizes[number];
export default defineComponent({ export default defineComponent({
components: { Float, FormHeader, Select, Button }, components: { Float, FormHeader, Select, Button },
props: { doc: { type: PrintTemplate, required: true } }, props: { doc: { type: PrintTemplate, required: true } },
emits: ['done'],
data() { data() {
return { size: 'A4', width: 21, height: 29.7 }; return { size: 'A4', width: 21, height: 29.7 };
}, },
@ -100,9 +101,9 @@ export default defineComponent({
this.size = 'Custom'; this.size = 'Custom';
this[name] = v; this[name] = v;
}, },
done() { async done() {
this.doc.set('width', this.width); await this.doc.set('width', this.width);
this.doc.set('height', this.height); await this.doc.set('height', this.height);
this.$emit('done'); this.$emit('done');
}, },
}, },

View File

@ -235,6 +235,7 @@ import { showDialog, showToast } from 'src/utils/interactive';
import { getSavePath } from 'src/utils/ipcCalls'; import { getSavePath } from 'src/utils/ipcCalls';
import { docsPathMap } from 'src/utils/misc'; import { docsPathMap } from 'src/utils/misc';
import { import {
PrintTemplateHint,
baseTemplate, baseTemplate,
getPrintTemplatePropHints, getPrintTemplatePropHints,
getPrintTemplatePropValues, getPrintTemplatePropValues,
@ -275,7 +276,7 @@ export default defineComponent({
provide() { provide() {
return { doc: computed(() => this.doc) }; return { doc: computed(() => this.doc) };
}, },
props: { name: String }, props: { name: { type: String, required: true } },
setup() { setup() {
const doc = ref(null) as DocRef<PrintTemplate>; const doc = ref(null) as DocRef<PrintTemplate>;
const shortcuts = inject(shortcutsKey); const shortcuts = inject(shortcutsKey);
@ -310,7 +311,7 @@ export default defineComponent({
} as { } as {
editMode: boolean; editMode: boolean;
showHints: boolean; showHints: boolean;
hints?: Record<string, unknown>; hints?: PrintTemplateHint;
values: null | PrintValues; values: null | PrintValues;
displayDoc: PrintTemplate | null; displayDoc: PrintTemplate | null;
showSizeModal: boolean; showSizeModal: boolean;
@ -377,14 +378,14 @@ export default defineComponent({
actions.push({ actions.push({
label: this.t`Select Template File`, label: this.t`Select Template File`,
group: this.t`Action`, group: this.t`Action`,
action: this.selectFile, action: this.selectFile.bind(this),
}); });
} }
actions.push({ actions.push({
label: this.t`Save Template File`, label: this.t`Save Template File`,
group: this.t`Action`, group: this.t`Action`,
action: this.saveFile, action: this.saveFile.bind(this),
}); });
return actions; return actions;
@ -464,9 +465,21 @@ export default defineComponent({
return; return;
} }
this.shortcuts.ctrl.set(this.context, ['Enter'], this.setTemplate); this.shortcuts.ctrl.set(
this.shortcuts.ctrl.set(this.context, ['KeyE'], this.toggleEditMode); this.context,
this.shortcuts.ctrl.set(this.context, ['KeyH'], this.toggleShowHints); ['Enter'],
this.setTemplate.bind(this)
);
this.shortcuts.ctrl.set(
this.context,
['KeyE'],
this.toggleEditMode.bind(this)
);
this.shortcuts.ctrl.set(
this.context,
['KeyH'],
this.toggleShowHints.bind(this)
);
this.shortcuts.ctrl.set(this.context, ['Equal'], () => this.shortcuts.ctrl.set(this.context, ['Equal'], () =>
this.setScale(this.scale + 0.1) this.setScale(this.scale + 0.1)
); );
@ -523,7 +536,7 @@ export default defineComponent({
toggleShowHints() { toggleShowHints() {
this.showHints = !this.showHints; this.showHints = !this.showHints;
}, },
async toggleEditMode() { toggleEditMode() {
if (!this.doc?.isCustom) { if (!this.doc?.isCustom) {
return; return;
} }
@ -558,7 +571,7 @@ export default defineComponent({
}, },
getEditModeScale(): number { getEditModeScale(): number {
// @ts-ignore // @ts-ignore
const div = this.$refs.printContainer.$el; const div = this.$refs.printContainer.$el as unknown;
if (!(div instanceof HTMLDivElement)) { if (!(div instanceof HTMLDivElement)) {
return this.scale; return this.scale;
} }
@ -570,7 +583,7 @@ export default defineComponent({
return Number(targetScale.toFixed(2)); return Number(targetScale.toFixed(2));
}, },
async savePDF() { savePDF() {
const printContainer = this.$refs.printContainer as { const printContainer = this.$refs.printContainer as {
savePDF: (name?: string) => void; savePDF: (name?: string) => void;
}; };
@ -695,14 +708,14 @@ export default defineComponent({
const template = this.getTemplateEditorState(); const template = this.getTemplateEditorState();
if (!name) { if (!name) {
return await showToast({ return showToast({
type: 'warning', type: 'warning',
message: this.t`Print Template Name not set`, message: this.t`Print Template Name not set`,
}); });
} }
if (!template) { if (!template) {
return await showToast({ return showToast({
type: 'warning', type: 'warning',
message: this.t`Print Template is empty`, message: this.t`Print Template is empty`,
}); });

View File

@ -63,10 +63,12 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { PrintTemplateHint } from 'src/utils/printTemplates';
import { PropType } from 'vue';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
type HintRow = { type HintRow = {
key: string; key: string;
value: string | Record<string, unknown>; value: PrintTemplateHint[string];
isCollapsible: boolean; isCollapsible: boolean;
collapsed: boolean; collapsed: boolean;
}; };
@ -74,7 +76,10 @@ export default defineComponent({
name: 'TemplateBuilderHint', name: 'TemplateBuilderHint',
props: { props: {
prefix: { type: String, default: '' }, prefix: { type: String, default: '' },
hints: { type: Object, required: true }, hints: {
type: Object as PropType<PrintTemplateHint>,
required: true,
},
level: { type: Number, default: 0 }, level: { type: Number, default: 0 },
}, },
data() { data() {

View File

@ -20,7 +20,7 @@ export default defineComponent({
props: { props: {
initialValue: { type: String, required: true }, initialValue: { type: String, required: true },
disabled: { type: Boolean, default: false }, disabled: { type: Boolean, default: false },
hints: { type: Object }, hints: { type: Object, default: undefined },
}, },
emits: ['input', 'blur'], emits: ['input', 'blur'],
data() { data() {
@ -76,7 +76,7 @@ export default defineComponent({
const view = new EditorView({ const view = new EditorView({
doc: this.initialValue, doc: this.initialValue,
extensions: [ extensions: [
EditorView.updateListener.of(this.updateListener), EditorView.updateListener.of(this.updateListener.bind(this)),
readOnly.of(EditorState.readOnly.of(this.disabled)), readOnly.of(EditorState.readOnly.of(this.disabled)),
editable.of(EditorView.editable.of(!this.disabled)), editable.of(EditorView.editable.of(!this.disabled)),
basicSetup, basicSetup,

View File

@ -1,12 +1,13 @@
import { t } from 'fyo'; import { t } from 'fyo';
import { ModelNameEnum } from 'models/types'; import { ModelNameEnum } from 'models/types';
import { openSettings, routeTo } from './ui'; import { openSettings, routeTo } from './ui';
import { GetStartedConfigItem } from './types';
export function getGetStartedConfig() { export function getGetStartedConfig(): GetStartedConfigItem[] {
/* eslint-disable @typescript-eslint/no-misused-promises */
return [ return [
{ {
label: t`Organisation`, label: t`Organisation`,
items: [ items: [
{ {
key: 'General', key: 'General',
@ -36,7 +37,6 @@ export function getGetStartedConfig() {
}, },
{ {
label: t`Accounts`, label: t`Accounts`,
items: [ items: [
{ {
key: 'Review Accounts', key: 'Review Accounts',
@ -71,7 +71,6 @@ export function getGetStartedConfig() {
}, },
{ {
label: t`Sales`, label: t`Sales`,
items: [ items: [
{ {
key: 'Add Sales Items', key: 'Add Sales Items',
@ -119,7 +118,6 @@ export function getGetStartedConfig() {
}, },
{ {
label: t`Purchase`, label: t`Purchase`,
items: [ items: [
{ {
key: 'Add Purchase Items', key: 'Add Purchase Items',

View File

@ -9,6 +9,9 @@ import { getSavePath, getTemplates, makePDF } from './ipcCalls';
import { PrintValues } from './types'; import { PrintValues } from './types';
import { getDocFromNameIfExistsElseNew } from './ui'; import { getDocFromNameIfExistsElseNew } from './ui';
export type PrintTemplateHint = {
[key: string]: string | PrintTemplateHint | PrintTemplateHint[];
};
type PrintTemplateData = Record<string, unknown>; type PrintTemplateData = Record<string, unknown>;
type TemplateUpdateItem = { name: string; template: string; type: string }; type TemplateUpdateItem = { name: string; template: string; type: string };
@ -62,11 +65,11 @@ export async function getPrintTemplatePropValues(
} }
export function getPrintTemplatePropHints(schemaName: string, fyo: Fyo) { export function getPrintTemplatePropHints(schemaName: string, fyo: Fyo) {
const hints: PrintTemplateData = {}; const hints: PrintTemplateHint = {};
const schema = fyo.schemaMap[schemaName]!; const schema = fyo.schemaMap[schemaName]!;
hints.doc = getPrintTemplateDocHints(schema, fyo); hints.doc = getPrintTemplateDocHints(schema, fyo);
(hints.doc as PrintTemplateData).entryType = fyo.t`Entry Type`; hints.doc.entryType = fyo.t`Entry Type`;
(hints.doc as PrintTemplateData).entryLabel = fyo.t`Entry Label`; hints.doc.entryLabel = fyo.t`Entry Label`;
const printSettingsHints = getPrintTemplateDocHints( const printSettingsHints = getPrintTemplateDocHints(
fyo.schemaMap[ModelNameEnum.PrintSettings]!, fyo.schemaMap[ModelNameEnum.PrintSettings]!,
@ -119,10 +122,10 @@ function getPrintTemplateDocHints(
fyo: Fyo, fyo: Fyo,
fieldnames?: string[], fieldnames?: string[],
linkLevel?: number linkLevel?: number
): PrintTemplateData { ): PrintTemplateHint {
linkLevel ??= 0; linkLevel ??= 0;
const hints: PrintTemplateData = {}; const hints: PrintTemplateHint = {};
const links: PrintTemplateData = {}; const links: PrintTemplateHint = {};
let fields = schema.fields; let fields = schema.fields;
if (fieldnames) { if (fieldnames) {

View File

@ -118,3 +118,16 @@ export type DialogButton = {
isPrimary?: boolean; isPrimary?: boolean;
isEscape?: boolean; isEscape?: boolean;
}; };
export type GetStartedConfigItem = {
label: string;
items: {
key: string;
label: string;
icon: string;
description: string;
fieldname: string;
documentation?: string;
action?: () => void;
}[];
};