2
0
mirror of https://github.com/frappe/books.git synced 2024-11-09 15:20:56 +00:00

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

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

View File

@ -37,6 +37,17 @@ module.exports = {
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin: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: [
'*.mjs',
'.eslintrc.js',
@ -46,5 +57,6 @@ module.exports = {
'*.spec.ts',
'vite.config.ts',
'postcss.config.js',
'src/components/**/*.vue', // Incrementally fix these
],
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -80,7 +80,9 @@ export default defineComponent({
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}`);
},
fields() {

View File

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

View File

@ -42,7 +42,7 @@
/>
</div>
</template>
<script>
<script lang="ts">
import { AccountTypeEnum } from 'models/baseModels/Account/types';
import { ModelNameEnum } from 'models/types';
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 { uicolors } from 'src/utils/colors';
import { getDatesAndPeriodList } from 'src/utils/misc';
import { getMapFromList } from 'utils/';
import DashboardChartBase from './BaseDashboardChart.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',
components: {
PeriodSelector,
@ -62,7 +70,7 @@ export default {
},
extends: DashboardChartBase,
data: () => ({
data: [],
data: [] as { inflow: number; outflow: number; yearmonth: string }[],
periodList: [],
periodOptions: ['This Year', 'This Quarter'],
hasData: false,
@ -76,10 +84,12 @@ export default {
colors = [uicolors.gray['200'], uicolors.gray['100']];
}
const xLabels = data.map((cf) => cf['yearmonth']);
const points = ['inflow', 'outflow'].map((k) => data.map((d) => d[k]));
const xLabels = data.map((cf) => cf.yearmonth);
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);
return { points, xLabels, colors, format, yMax, formatX: formatXLabels };
},
@ -92,8 +102,8 @@ export default {
},
methods: {
async setData() {
const { periodList, fromDate, toDate } = await getDatesAndPeriodList(
this.period
const { periodList, fromDate, toDate } = getDatesAndPeriodList(
this.period as PeriodKey
);
const data = await fyo.db.getCashflow(fromDate.toISO(), toDate.toISO());
@ -118,14 +128,14 @@ export default {
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, {
filters: { account: ['in', accountNames] },
});
this.hasData = count > 0;
},
},
};
});
const dummyData = [
{

View File

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

View File

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

View File

@ -29,7 +29,7 @@
</div>
</div>
</template>
<script>
<script lang="ts">
import BarChart from 'src/components/Charts/BarChart.vue';
import { fyo } from 'src/initFyo';
import { formatXLabels, getYMax, getYMin } from 'src/utils/chart';
@ -39,8 +39,14 @@ import { getValueMapFromList } from 'utils';
import DashboardChartBase from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.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',
components: {
PeriodSelector,
@ -49,7 +55,7 @@ export default {
},
extends: DashboardChartBase,
data: () => ({
data: [],
data: [] as { yearmonth: string; balance: number }[],
hasData: false,
periodOptions: ['This Year', 'This Quarter'],
}),
@ -59,7 +65,7 @@ export default {
const colors = [
{ 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 yMin = getYMin(points);
return {
@ -78,7 +84,7 @@ export default {
},
methods: {
async setData() {
const { fromDate, toDate, periodList } = await getDatesAndPeriodList(
const { fromDate, toDate, periodList } = getDatesAndPeriodList(
this.period
);
@ -102,5 +108,5 @@ export default {
this.hasData = data.income.length > 0 || data.expense.length > 0;
},
},
};
});
</script>

View File

@ -89,11 +89,17 @@ import { getDatesAndPeriodList } from 'src/utils/misc';
import { PeriodKey } from 'src/utils/types';
import { routeTo } from 'src/utils/ui';
import { safeParseFloat } from 'utils/index';
import { defineComponent } from 'vue';
import { PropType, defineComponent } from 'vue';
import BaseDashboardChart from './BaseDashboardChart.vue';
import PeriodSelector from './PeriodSelector.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({
name: 'UnpaidInvoices',
components: {
@ -103,7 +109,7 @@ export default defineComponent({
},
extends: BaseDashboardChart,
props: {
schemaName: { type: String, required: true },
schemaName: { type: String as PropType<string>, required: true },
},
data() {
return {
@ -211,7 +217,7 @@ export default defineComponent({
},
async newInvoice() {
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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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