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

chore: fix all fixable eslint errors in src

This commit is contained in:
18alantom 2023-06-22 11:39:32 +05:30
parent 4415c04a88
commit e67e6ae257
19 changed files with 154 additions and 119 deletions

View File

@ -17,8 +17,8 @@ module.exports = {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-misused-promises': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-misused-promises': 'warn',
},
parser: '@typescript-eslint/parser',
parserOptions: { project: true, tsconfigRootDir: __dirname },
@ -28,5 +28,5 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
ignorePatterns: ['.eslintrc.js'],
ignorePatterns: ['.eslintrc.js', 'tailwind.config.js'],
};

View File

@ -9,7 +9,6 @@ import { fyo } from './initFyo';
import router from './router';
import { getErrorMessage, stringifyCircular } from './utils';
import { DialogOptions, ToastOptions } from './utils/types';
import { UnknownFunction } from 'utils/types';
const { ipcRenderer } = require('electron');
function shouldNotStore(error: Error) {
@ -40,6 +39,7 @@ export async function sendError(errorLogObj: ErrorLog) {
};
if (fyo.store.isDevelopment) {
// eslint-disable-next-line no-console
console.log('sendError', body);
}
@ -80,6 +80,7 @@ export async function handleError(
notifyUser = true
) {
if (logToConsole) {
// eslint-disable-next-line no-console
console.error(error);
}
@ -93,7 +94,7 @@ export async function handleError(
if (notifyUser) {
const toastProps = getToastProps(errorLogObj);
const { showToast } = await import('src/utils/interactive');
await showToast(toastProps);
showToast(toastProps);
}
}
@ -140,6 +141,7 @@ export async function handleErrorWithDialog(
await showDialog(options);
if (dontThrow) {
if (fyo.store.isDevelopment) {
// eslint-disable-next-line no-console
console.error(error);
}
return;
@ -156,12 +158,14 @@ export async function showErrorDialog(title?: string, content?: string) {
await ipcRenderer.invoke(IPC_ACTIONS.SHOW_ERROR, { title, content });
}
// Wrapper Functions
export function getErrorHandled(func: UnknownFunction) {
return async function errorHandled(...args: unknown[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getErrorHandled<T extends (...args: any[]) => Promise<any>>(
func: T
) {
type Return = ReturnType<T> extends Promise<infer P> ? P : true;
return async function errorHandled(...args: Parameters<T>): Promise<Return> {
try {
return await func(...args);
return (await func(...args)) as Return;
} catch (error) {
await handleError(false, error as Error, {
functionName: func.name,
@ -173,16 +177,19 @@ export function getErrorHandled(func: UnknownFunction) {
};
}
export function getErrorHandledSync(func: UnknownFunction) {
return function errorHandledSync(...args: unknown[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getErrorHandledSync<T extends (...args: any[]) => any>(
func: T
) {
type Return = ReturnType<T> extends Promise<infer P> ? P : ReturnType<T>;
return function errorHandledSync(...args: Parameters<T>) {
try {
return func(...args);
return func(...args) as Return;
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
handleError(false, error as Error, {
functionName: func.name,
functionArgs: args,
}).then(() => {
throw error;
});
}
};

View File

@ -199,7 +199,7 @@ export class Importer {
}[];
const cellErrors = [];
for (const i in this.valueMatrix) {
for (let i = 0; i < this.valueMatrix.length; i++) {
const row = this.valueMatrix[i];
for (const { tf, index } of assigned) {
if (!row[index]?.error) {
@ -278,14 +278,14 @@ export class Importer {
return { dataMap, childTableMap };
}
for (const i in this.valueMatrix) {
for (let i = 0; i < this.valueMatrix.length; i++) {
const row = this.valueMatrix[i];
const name = row[nameIndex]?.value;
if (typeof name !== 'string') {
continue;
}
for (const j in row) {
for (let j = 0; j < row.length; j++) {
const key = this.assignedTemplateFields[j];
const tf = this.templateFieldsMap.get(key ?? '');
if (!tf || !key) {
@ -387,7 +387,7 @@ export class Importer {
pushToValueMatrixFromParsedRow(row: string[]) {
const vmRow: ValueMatrix[number] = [];
for (const i in row) {
for (let i = 0; i < row.length; i++) {
const rawValue = row[i];
const index = Number(i);
@ -492,7 +492,7 @@ export class Importer {
return false;
}
for (const i in row) {
for (let i = 0; i < row.length; i++) {
const value = row[i];
const tf = this.templateFieldsMap.get(value);
let key: string | null = value;

View File

@ -6,7 +6,12 @@ import { App as VueApp, createApp } from 'vue';
import App from './App.vue';
import Badge from './components/Badge.vue';
import FeatherIcon from './components/FeatherIcon.vue';
import { getErrorHandled, handleError, sendError } from './errorHandling';
import {
getErrorHandled,
getErrorHandledSync,
handleError,
sendError,
} from './errorHandling';
import { fyo } from './initFyo';
import { outsideClickDirective } from './renderer/helpers';
import registerIpcRendererListeners from './renderer/registerIpcRendererListeners';
@ -14,6 +19,7 @@ import router from './router';
import { stringifyCircular } from './utils';
import { setLanguageMap } from './utils/language';
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
const language = fyo.config.get('language') as string;
if (language) {
@ -21,8 +27,8 @@ import { setLanguageMap } from './utils/language';
}
fyo.store.language = language || 'English';
ipcRenderer.send = getErrorHandled(ipcRenderer.send);
ipcRenderer.invoke = getErrorHandled(ipcRenderer.invoke);
ipcRenderer.send = getErrorHandledSync(ipcRenderer.send.bind(ipcRenderer));
ipcRenderer.invoke = getErrorHandled(ipcRenderer.invoke.bind(ipcRenderer));
registerIpcRendererListeners();
const { isDevelopment, platform, version } = (await ipcRenderer.invoke(
@ -69,6 +75,7 @@ import { setLanguageMap } from './utils/language';
function setErrorHandlers(app: VueApp) {
window.onerror = (message, source, lineno, colno, error) => {
error = error ?? new Error('triggered in window.onerror');
// eslint-disable-next-line @typescript-eslint/no-floating-promises
handleError(true, error, { message, source, lineno, colno });
};
@ -80,11 +87,13 @@ function setErrorHandlers(app: VueApp) {
error = new Error(String(event.reason));
}
// eslint-disable-next-line no-console
handleError(true, error).catch((err) => console.error(err));
};
window.addEventListener(CUSTOM_EVENTS.LOG_UNEXPECTED, (event) => {
const details = (event as CustomEvent)?.detail as UnexpectedLogObject;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
sendError(details);
});
@ -100,7 +109,9 @@ function setErrorHandlers(app: VueApp) {
more.props = stringifyCircular(vm.$props ?? {}, true, true);
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
handleError(false, err as Error, more);
// eslint-disable-next-line no-console
console.error(err, vm, info);
};
}

View File

@ -6,7 +6,7 @@ import { IPC_CHANNELS } from 'utils/messages';
export default function registerIpcRendererListeners() {
ipcRenderer.on(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
async (_, error, more) => {
(_, error: unknown, more?: Record<string, unknown>) => {
if (!(error instanceof Error)) {
throw error;
}
@ -22,7 +22,8 @@ export default function registerIpcRendererListeners() {
more.isMainProcess = true;
more.notifyUser ??= true;
await handleError(true, error, more, more.notifyUser);
// eslint-disable-next-line @typescript-eslint/no-floating-promises
handleError(true, error, more, !!more.notifyUser);
}
);
@ -32,6 +33,7 @@ export default function registerIpcRendererListeners() {
}
if (fyo.store.isDevelopment) {
// eslint-disable-next-line no-console
console.log(...stuff);
}
});
@ -39,6 +41,7 @@ export default function registerIpcRendererListeners() {
document.addEventListener('visibilitychange', () => {
const { visibilityState } = document;
if (visibilityState === 'visible' && !fyo.telemetry.started) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
fyo.telemetry.start();
}

View File

@ -38,7 +38,7 @@ export class CreateCOA {
const child = children[rootName];
if (rootAccount) {
rootType = (child as COARootAccount).rootType as AccountRootType;
rootType = (child as COARootAccount).rootType;
}
const accountType = (child as COAChildAccount).accountType ?? '';
@ -83,7 +83,7 @@ function identifyIsGroup(child: COARootAccount | COAChildAccount): boolean {
return false;
}
async function getCOA(chartOfAccounts: string) {
async function getCOA(chartOfAccounts: string): Promise<COATree> {
const coaList = getCOAList();
const coa = coaList.find(({ name }) => name === chartOfAccounts);
@ -93,8 +93,9 @@ async function getCOA(chartOfAccounts: string) {
}
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const countryCoa = (await import(`../../fixtures/verified/${conCode}.json`))
.default;
.default as { tree: COATree };
return countryCoa.tree;
} catch (e) {
return getStandardCOA();

View File

@ -133,7 +133,7 @@ async function updateSystemSettings(
const systemSettings = await fyo.doc.getDoc('SystemSettings');
const instanceId = getRandomString();
systemSettings.setAndSync({
await systemSettings.setAndSync({
locale,
currency,
instanceId,
@ -168,10 +168,8 @@ async function createCurrencyRecords(fyo: Fyo) {
};
const doc = checkAndCreateDoc('Currency', docObject, fyo);
if (doc) {
promises.push(doc);
queue.push(currency);
}
promises.push(doc);
queue.push(currency);
}
return Promise.all(promises);
}
@ -256,7 +254,7 @@ async function checkAndCreateDoc(
schemaName: string,
docObject: DocValueMap,
fyo: Fyo
) {
): Promise<Doc | undefined> {
const canCreate = await checkIfExactRecordAbsent(schemaName, docObject, fyo);
if (!canCreate) {
return;
@ -373,12 +371,12 @@ async function updateInventorySettings(fyo: Fyo) {
}
const settingName = accountTypeDefaultMap[accountType]!;
inventorySettings.set(settingName, accounts[0].name);
await inventorySettings.set(settingName, accounts[0].name);
}
const location = fyo.t`Stores`;
if (await fyo.db.exists(ModelNameEnum.Location, location)) {
inventorySettings.set('defaultLocation', location);
await inventorySettings.set('defaultLocation', location);
}
await inventorySettings.sync();

11
src/shims-tsx.d.ts vendored
View File

@ -1,13 +1,12 @@
import Vue, { VNode } from 'vue'
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
type Element = VNode
// tslint:disable no-empty-interface
type ElementClass = Vue
type Element = VNode;
type ElementClass = Vue;
interface IntrinsicElements {
[elem: string]: any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[elem: string]: any;
}
}
}

View File

@ -70,7 +70,7 @@ async function handleDirectoryDoesNotExist(dbPath: string) {
async function showDbErrorDialog(detail: string) {
const { showDialog } = await import('src/utils/interactive');
return await showDialog({
return showDialog({
type: 'error',
title: t`Cannot Open File`,
detail,

View File

@ -14,9 +14,7 @@ export function getGetStartedConfig() {
icon: 'general',
description: t`Set up your company information, email, country and fiscal year`,
fieldname: 'companySetup',
action() {
openSettings(ModelNameEnum.AccountingSettings);
},
action: () => openSettings(ModelNameEnum.AccountingSettings),
},
{
key: 'Print',
@ -24,9 +22,7 @@ export function getGetStartedConfig() {
icon: 'invoice',
description: t`Customize your invoices by adding a logo and address details`,
fieldname: 'printSetup',
action() {
openSettings(ModelNameEnum.PrintSettings);
},
action: () => openSettings(ModelNameEnum.PrintSettings),
},
{
key: 'System',
@ -34,9 +30,7 @@ export function getGetStartedConfig() {
icon: 'system',
description: t`Setup system defaults like date format and display precision`,
fieldname: 'systemSetup',
action() {
openSettings(ModelNameEnum.SystemSettings);
},
action: () => openSettings(ModelNameEnum.SystemSettings),
},
],
},
@ -49,9 +43,7 @@ export function getGetStartedConfig() {
label: t`Review Accounts`,
icon: 'review-ac',
description: t`Review your chart of accounts, add any account or tax heads as needed`,
action: () => {
routeTo('/chart-of-accounts');
},
action: () => routeTo('/chart-of-accounts'),
fieldname: 'chartOfAccountsReviewed',
documentation:
'https://docs.frappebooks.com/setting-up/initial-entries.html#add-additional-bank-accounts',

View File

@ -16,11 +16,11 @@ export function stringifyCircular(
obj: unknown,
ignoreCircular = false,
convertDocument = false
) {
): string {
const cacheKey: string[] = [];
const cacheValue: unknown[] = [];
return JSON.stringify(obj, (key, value) => {
return JSON.stringify(obj, (key: string, value: unknown) => {
if (typeof value !== 'object' || value === null) {
cacheKey.push(key);
cacheValue.push(value);

View File

@ -5,19 +5,13 @@ import { App, createApp, h } from 'vue';
import { getColorClass } from './colors';
import { DialogButton, DialogOptions, ToastOptions, ToastType } from './types';
type DialogReturn<DO extends DialogOptions> = DO['buttons'] extends {
action: () => Promise<infer O> | infer O;
}[]
? O
: void;
export async function showDialog<DO extends DialogOptions>(options: DO) {
const preWrappedButtons: DialogButton[] = options.buttons ?? [
{ label: t`Okay`, action: () => null, isEscape: true },
];
return new Promise(async (resolve, reject) => {
const buttons = preWrappedButtons!.map((config) => {
const resultPromise = new Promise((resolve, reject) => {
const buttons = preWrappedButtons.map((config) => {
return {
...config,
action: async () => {
@ -37,10 +31,12 @@ export async function showDialog<DO extends DialogOptions>(options: DO) {
});
fragmentMountComponent(dialogApp);
}) as DialogReturn<DO>;
});
return await resultPromise;
}
export async function showToast(options: ToastOptions) {
export function showToast(options: ToastOptions) {
const toastApp = createApp({
render() {
return h(Toast, { ...options });

View File

@ -4,9 +4,14 @@
const { ipcRenderer } = require('electron');
import { t } from 'fyo';
import { BaseError } from 'fyo/utils/errors';
import { BackendResponse } from 'utils/ipc/types';
import type { BackendResponse } from 'utils/ipc/types';
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
import { SelectFileOptions, SelectFileReturn, TemplateFile } from 'utils/types';
import type {
LanguageMap,
SelectFileOptions,
SelectFileReturn,
TemplateFile,
} from 'utils/types';
import { showDialog, showToast } from './interactive';
import { setLanguageMap } from './language';
import type { OpenDialogReturnValue } from 'electron';
@ -15,22 +20,35 @@ export function reloadWindow() {
return ipcRenderer.send(IPC_MESSAGES.RELOAD_MAIN_WINDOW);
}
export async function getLanguageMap(code: string) {
return (await ipcRenderer.invoke(IPC_ACTIONS.GET_LANGUAGE_MAP, code)) as {
languageMap: LanguageMap;
success: boolean;
message: string;
};
}
export async function getSelectedFilePath(): Promise<OpenDialogReturnValue> {
return await ipcRenderer.invoke(IPC_ACTIONS.GET_OPEN_FILEPATH, {
title: this.t`Select file`,
return (await ipcRenderer.invoke(IPC_ACTIONS.GET_OPEN_FILEPATH, {
title: t`Select file`,
properties: ['openFile'],
filters: [{ name: 'SQLite DB File', extensions: ['db'] }],
});
})) as OpenDialogReturnValue;
}
export async function getTemplates(): Promise<TemplateFile[]> {
return await ipcRenderer.invoke(IPC_ACTIONS.GET_TEMPLATES);
return (await ipcRenderer.invoke(
IPC_ACTIONS.GET_TEMPLATES
)) as TemplateFile[];
}
export async function selectFile(
options: SelectFileOptions
): Promise<SelectFileReturn> {
return await ipcRenderer.invoke(IPC_ACTIONS.SELECT_FILE, options);
return (await ipcRenderer.invoke(
IPC_ACTIONS.SELECT_FILE,
options
)) as SelectFileReturn;
}
export async function checkForUpdates() {
@ -38,7 +56,7 @@ export async function checkForUpdates() {
await setLanguageMap();
}
export async function openLink(link: string) {
export function openLink(link: string) {
ipcRenderer.send(IPC_MESSAGES.OPEN_EXTERNAL, link);
}
@ -49,19 +67,19 @@ export async function deleteDb(filePath: string) {
)) as BackendResponse;
if (error?.code === 'EBUSY') {
showDialog({
await showDialog({
title: t`Delete Failed`,
detail: t`Please restart and try again.`,
type: 'error',
});
} else if (error?.code === 'ENOENT') {
showDialog({
await showDialog({
title: t`Delete Failed`,
detail: t`File ${filePath} does not exist.`,
type: 'error',
});
} else if (error?.code === 'EPERM') {
showDialog({
await showDialog({
title: t`Cannot Delete`,
detail: t`Close Frappe Books and try manually.`,
type: 'error',
@ -87,14 +105,14 @@ export async function makePDF(
savePath: string,
width: number,
height: number
) {
const success = await ipcRenderer.invoke(
): Promise<void> {
const success = (await ipcRenderer.invoke(
IPC_ACTIONS.SAVE_HTML_AS_PDF,
html,
savePath,
width,
height
);
)) as boolean;
if (success) {
showExportInFolder(t`Save as PDF Successful`, savePath);
@ -108,8 +126,8 @@ export function showExportInFolder(message: string, filePath: string) {
message,
actionText: t`Open Folder`,
type: 'success',
action: async () => {
await showItemInFolder(filePath);
action: () => {
showItemInFolder(filePath);
},
});
}

View File

@ -1,9 +1,7 @@
const { ipcRenderer } = require('electron');
import { DEFAULT_LANGUAGE } from 'fyo/utils/consts';
import { setLanguageMapOnTranslationString } from 'fyo/utils/translation';
import { fyo } from 'src/initFyo';
import { IPC_ACTIONS } from 'utils/messages';
import { reloadWindow } from './ipcCalls';
import { getLanguageMap, reloadWindow } from './ipcCalls';
import { systemLanguageRef } from './refs';
// Language: Language Code in books/translations
@ -65,17 +63,14 @@ function getLanguageCode(initLanguage: string, oldLanguage: string) {
}
async function fetchAndSetLanguageMap(code: string) {
const { success, message, languageMap } = await ipcRenderer.invoke(
IPC_ACTIONS.GET_LANGUAGE_MAP,
code
);
const { success, message, languageMap } = await getLanguageMap(code);
if (!success) {
const { showToast } = await import('src/utils/interactive');
showToast({ type: 'error', message });
} else {
setLanguageMapOnTranslationString(languageMap);
fyo.db.translateSchemaMap(languageMap);
await fyo.db.translateSchemaMap(languageMap);
}
return success;

View File

@ -24,7 +24,7 @@ interface SearchItem {
label: string;
group: Exclude<SearchGroup, 'Docs'>;
route?: string;
action?: () => void;
action?: () => void | Promise<void>;
}
interface DocSearchItem extends Omit<SearchItem, 'group'> {
@ -319,8 +319,8 @@ function getNonDocSearchList(fyo: Fyo) {
.flat()
.map((d) => {
if (d.route && !d.action) {
d.action = () => {
routeTo(d.route!);
d.action = async () => {
await routeTo(d.route!);
};
}
return d;

View File

@ -114,7 +114,7 @@ export interface DialogOptions {
export type DialogButton = {
label: string;
action: () => any;
action: () => unknown;
isPrimary?: boolean;
isEscape?: boolean;
};

View File

@ -7,6 +7,7 @@ import type { Doc } from 'fyo/model/doc';
import { Action } from 'fyo/model/types';
import { getActions } from 'fyo/utils';
import { getDbError, LinkValidationError, ValueError } from 'fyo/utils/errors';
import { Invoice } from 'models/baseModels/Invoice/Invoice';
import { PurchaseInvoice } from 'models/baseModels/PurchaseInvoice/PurchaseInvoice';
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
import { getLedgerLink } from 'models/helpers';
@ -25,13 +26,12 @@ import { selectFile } from './ipcCalls';
import { showSidebar } from './refs';
import {
ActionGroup,
DialogButton,
QuickEditOptions,
SettingsTab,
ToastOptions,
UIGroupedFields,
} from './types';
import { Invoice } from 'models/baseModels/Invoice/Invoice';
import { assertIsType } from 'utils/index';
export const toastDurationMap = { short: 2_500, long: 5_000 } as const;
@ -56,7 +56,7 @@ export async function openQuickEdit({
showFields,
hideFields,
};
router.push({ query });
await router.push({ query });
}
export async function openSettings(tab: SettingsTab) {
@ -81,7 +81,7 @@ export async function deleteDocWithPrompt(doc: Doc) {
detail = t`This action is permanent and will delete associated ledger entries.`;
}
return await showDialog({
return (await showDialog({
title: t`Delete ${getDocReferenceLabel(doc)}?`,
detail,
type: 'warning',
@ -93,13 +93,13 @@ export async function deleteDocWithPrompt(doc: Doc) {
await doc.delete();
} catch (err) {
if (getDbError(err as Error) === LinkValidationError) {
showDialog({
await showDialog({
title: t`Delete Failed`,
detail: t`Cannot delete ${schemaLabel} "${doc.name!}" because of linked entries.`,
type: 'error',
});
} else {
handleErrorWithDialog(err as Error, doc);
await handleErrorWithDialog(err as Error, doc);
}
return false;
@ -117,7 +117,7 @@ export async function deleteDocWithPrompt(doc: Doc) {
isEscape: true,
},
],
});
})) as boolean;
}
export async function cancelDocWithPrompt(doc: Doc) {
@ -152,7 +152,7 @@ export async function cancelDocWithPrompt(doc: Doc) {
}
}
return await showDialog({
return (await showDialog({
title: t`Cancel ${getDocReferenceLabel(doc)}?`,
detail,
type: 'warning',
@ -163,7 +163,7 @@ export async function cancelDocWithPrompt(doc: Doc) {
try {
await doc.cancel();
} catch (err) {
handleErrorWithDialog(err as Error, doc);
await handleErrorWithDialog(err as Error, doc);
return false;
}
@ -179,7 +179,7 @@ export async function cancelDocWithPrompt(doc: Doc) {
isEscape: true,
},
],
});
})) as boolean;
}
export function getActionsForDoc(doc?: Doc): Action[] {
@ -280,7 +280,7 @@ function getDuplicateAction(doc: Doc): Action {
const dupe = doc.duplicate();
await openEdit(dupe);
} catch (err) {
handleErrorWithDialog(err as Error, doc);
await handleErrorWithDialog(err as Error, doc);
}
},
};
@ -385,8 +385,8 @@ export function toggleSidebar(value?: boolean) {
export function focusOrSelectFormControl(
doc: Doc,
ref: any,
clear= true
ref: unknown,
shouldClear = true
) {
if (!doc?.fyo) {
return;
@ -405,7 +405,15 @@ export function focusOrSelectFormControl(
ref = ref[0];
}
if (!clear && typeof ref?.select === 'function') {
if (
!ref ||
typeof ref !== 'object' ||
!assertIsType<Record<string, () => void>>(ref)
) {
return;
}
if (!shouldClear && typeof ref?.select === 'function') {
ref.select();
return;
}
@ -429,7 +437,7 @@ export async function selectTextFile(filters?: SelectFileOptions['filters']) {
const { success, canceled, filePath, data, name } = await selectFile(options);
if (canceled || !success) {
await showToast({
showToast({
type: 'error',
message: t`File selection failed`,
});
@ -438,7 +446,7 @@ export async function selectTextFile(filters?: SelectFileOptions['filters']) {
const text = new TextDecoder().decode(data);
if (!text) {
await showToast({
showToast({
type: 'error',
message: t`Empty file selected`,
});
@ -528,7 +536,7 @@ async function syncWithoutDialog(doc: Doc): Promise<boolean> {
try {
await doc.sync();
} catch (error) {
handleErrorWithDialog(error, doc);
await handleErrorWithDialog(error, doc);
return false;
}
@ -563,14 +571,14 @@ async function showSubmitOrSyncDialog(doc: Doc, type: 'submit' | 'sync') {
try {
await doc[type]();
} catch (error) {
handleErrorWithDialog(error, doc);
await handleErrorWithDialog(error, doc);
return false;
}
return true;
};
const buttons: DialogButton[] = [
const buttons = [
{
label: t`Yes`,
action: yesAction,
@ -583,11 +591,13 @@ async function showSubmitOrSyncDialog(doc: Doc, type: 'submit' | 'sync') {
},
];
return await showDialog({
const dialogOptions = {
title,
detail,
buttons,
});
};
return (await showDialog(dialogOptions)) as boolean;
}
function getDocSyncMessage(doc: Doc): string {

View File

@ -8,7 +8,7 @@ export function getValueMapFromList<T, K extends keyof T, V extends keyof T>(
list: T[],
key: K,
valueKey: V,
filterUndefined: boolean = true
filterUndefined = true
): Record<string, T[V]> {
if (filterUndefined) {
list = list.filter(
@ -32,7 +32,7 @@ export function getRandomString(): string {
return `${randomNumber}-${currentTime}`;
}
export async function sleep(durationMilliseconds: number = 1000) {
export async function sleep(durationMilliseconds = 1000) {
return new Promise((r) => setTimeout(() => r(null), durationMilliseconds));
}
@ -267,3 +267,9 @@ export function objectForEach<T extends object | unknown>(
return func(obj);
}
/**
* Asserts that `value` is of type T. Use with care.
*/
export const assertIsType = <T>(value: unknown): value is T => true;

View File

@ -3,7 +3,6 @@ import type { ConfigFile } from 'fyo/core/types';
export type UnknownMap = Record<string, unknown>;
export type Translation = { translation: string; context?: string };
export type LanguageMap = Record<string, Translation>;
export type UnknownFunction = (...args: unknown[]) => unknown;
export type CountryInfoMap = Record<string, CountryInfo | undefined>;
export interface CountryInfo {