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:
parent
7c202ecee8
commit
247d4a4718
12
.eslintrc.js
12
.eslintrc.js
@ -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
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -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[];
|
||||||
|
11
src/App.vue
11
src/App.vue
@ -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> {
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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) {
|
||||||
|
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
@ -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>
|
||||||
|
@ -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 = [
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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>
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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">
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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
|
||||||
|
@ -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');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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`,
|
||||||
});
|
});
|
||||||
|
@ -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() {
|
||||||
|
@ -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,
|
||||||
|
@ -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',
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user