2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 10:58:59 +00:00

chore: enable typescript eslint rules

- refactor code to satisfy rules (batch 1)
- use ensuredir in build to prevent ENOENT
This commit is contained in:
18alantom 2023-06-21 16:08:39 +05:30
parent 8a1392e533
commit 4415c04a88
41 changed files with 240 additions and 183 deletions

View File

@ -1,23 +1,32 @@
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2020: true,
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-console': 'warn',
'no-debugger': 'warn',
'arrow-body-style': 'off',
'prefer-arrow-callback': 'off',
'prefer-arrow-callback': 'warn',
'vue/no-mutating-props': 'off',
'vue/multi-word-component-names': 'off',
'vue/no-useless-template-attributes': 'off',
'vue/one-component-per-file': 'off',
'@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',
},
parserOptions: {
parser: '@typescript-eslint/parser',
},
extends: ['plugin:vue/vue3-essential', '@vue/typescript'],
parser: '@typescript-eslint/parser',
parserOptions: { project: true, tsconfigRootDir: __dirname },
plugins: ['@typescript-eslint'],
extends: [
'plugin:vue/vue3-strongly-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
ignorePatterns: ['.eslintrc.js'],
};

View File

@ -24,9 +24,9 @@ await packageApp();
function updatePaths() {
fs.removeSync(buildDirPath);
fs.mkdirSync(buildDirPath);
fs.ensureDirSync(buildDirPath);
fs.removeSync(packageDirPath);
fs.mkdirSync(packageDirPath);
fs.ensureDirSync(packageDirPath);
fs.ensureDirSync(path.join(buildDirPath, 'node_modules'));
}

View File

@ -58,7 +58,10 @@ export class AuthHandler {
return { ...this.#config };
}
init() {}
init() {
return null;
}
async login(email: string, password: string) {
if (email === 'Administrator') {
this.#session.user = 'Administrator';
@ -107,8 +110,6 @@ export class AuthHandler {
// TODO: Implement this with auth flow
}
async purgeCache() {}
#getServerURL() {
return this.#config.serverURL || '';
}

View File

@ -28,7 +28,7 @@ export class DocHandler {
this.observer = new Observable();
}
async purgeCache() {
purgeCache() {
this.init();
}
@ -82,10 +82,10 @@ export class DocHandler {
getNewDoc(
schemaName: string,
data: DocValueMap | RawValueMap = {},
cacheDoc: boolean = true,
cacheDoc = true,
schema?: Schema,
Model?: typeof Doc,
isRawValueMap: boolean = true
isRawValueMap = true
): Doc {
if (!this.models[schemaName] && Model) {
this.models[schemaName] = Model;
@ -153,7 +153,7 @@ export class DocHandler {
// propagate change to `docs`
doc.on('change', (params: unknown) => {
this.docs!.trigger('change', params);
this.docs.trigger('change', params);
});
doc.on('afterSync', () => {

View File

@ -1,8 +1,8 @@
import { Doc } from 'fyo/model/doc';
import { Money } from 'pesa';
import { RawValue } from 'schemas/types';
import { AuthDemuxBase } from 'utils/auth/types';
import { DatabaseDemuxBase } from 'utils/db/types';
import type { Doc } from 'fyo/model/doc';
import type { Money } from 'pesa';
import type { RawValue } from 'schemas/types';
import type { AuthDemuxBase } from 'utils/auth/types';
import type { DatabaseDemuxBase } from 'utils/db/types';
export type Attachment = { name: string; type: string; data: string };
export type DocValue =
@ -31,12 +31,12 @@ export type DatabaseDemuxConstructor = new (
export type AuthDemuxConstructor = new (isElectron?: boolean) => AuthDemuxBase;
export enum ConfigKeys {
Files = 'files',
LastSelectedFilePath = 'lastSelectedFilePath',
Language = 'language',
DeviceId = 'deviceId',
}
export type ConfigMap = {
files: ConfigFile[];
lastSelectedFilePath: null | string;
language: string
deviceId: string
};
export interface ConfigFile {
id: string;

View File

@ -1,11 +1,12 @@
import type Store from 'electron-store';
import { ConfigMap } from 'fyo/core/types';
export class Config {
config: Map<string, unknown> | Store;
constructor(isElectron: boolean) {
this.config = new Map();
if (isElectron) {
const Config: typeof Store = require('electron-store');
const Config = require('electron-store') as typeof Store;
this.config = new Config();
}
}
@ -23,15 +24,19 @@ export class Config {
}
}
get(key: string, defaultValue?: unknown): unknown {
return this.config.get(key) ?? defaultValue;
get<K extends keyof ConfigMap>(
key: K,
defaultValue?: ConfigMap[K]
): ConfigMap[K] | undefined {
const value = this.config.get(key) as ConfigMap[K] | undefined;
return value ?? defaultValue;
}
set(key: string, value: unknown) {
set<K extends keyof ConfigMap>(key: K, value: ConfigMap[K]) {
this.config.set(key, value);
}
delete(key: string) {
delete(key: keyof ConfigMap) {
this.config.delete(key);
}

View File

@ -35,7 +35,7 @@ export class Fyo {
doc: DocHandler;
db: DatabaseHandler;
_initialized: boolean = false;
_initialized = false;
errorLog: ErrorLog[] = [];
temp?: Record<string, unknown>;
@ -94,7 +94,7 @@ export class Fyo {
return format(value, field, doc ?? null, this);
}
async setIsElectron() {
setIsElectron() {
try {
this.isElectron = Boolean(require('electron'));
} catch {
@ -105,7 +105,7 @@ export class Fyo {
async initializeAndRegister(
models: ModelMap = {},
regionalModels: ModelMap = {},
force: boolean = false
force = false
) {
if (this._initialized && !force) return;
@ -121,8 +121,8 @@ export class Fyo {
// temp params while calling routes
this.temp = {};
await this.doc.init();
await this.auth.init();
this.doc.init();
this.auth.init();
await this.db.init();
}
@ -189,14 +189,14 @@ export class Fyo {
let value: DocValue | Doc[];
try {
doc = await this.doc.getDoc(schemaName, name);
value = doc.get(fieldname!);
value = doc.get(fieldname);
} catch (err) {
value = undefined;
}
if (value === undefined && schemaName === name) {
const sv = await this.db.getSingleValues({
fieldname: fieldname!,
fieldname: fieldname,
parent: schemaName,
});
@ -221,8 +221,7 @@ export class Fyo {
this.errorLog = [];
this.temp = {};
await this.db.purgeCache();
await this.auth.purgeCache();
await this.doc.purgeCache();
this.doc.purgeCache();
}
store = {

View File

@ -1,5 +1,4 @@
import { Fyo } from 'fyo';
import { ConfigKeys } from 'fyo/core/types';
import { Noun, Telemetry, Verb } from './types';
/**
@ -28,8 +27,8 @@ import { Noun, Telemetry, Verb } from './types';
*/
export class TelemetryManager {
#url: string = '';
#token: string = '';
#url = '';
#token = '';
#started = false;
fyo: Fyo;
@ -108,16 +107,12 @@ export class TelemetryManager {
noun: Noun,
more?: Record<string, unknown>
): Telemetry {
const countryCode = this.fyo.singles.SystemSettings?.countryCode as
| string
| undefined;
const countryCode = this.fyo.singles.SystemSettings?.countryCode;
return {
country: countryCode ?? '',
language: this.fyo.store.language,
deviceId:
this.fyo.store.deviceId ||
(this.fyo.config.get(ConfigKeys.DeviceId) as string),
this.fyo.store.deviceId || (this.fyo.config.get('deviceId') ?? '-'),
instanceId: this.fyo.store.instanceId,
version: this.fyo.store.appVersion,
openCount: this.fyo.store.openCount,

View File

@ -1,3 +1,4 @@
// eslint-disable-next-line
require('source-map-support').install({
handleUncaughtException: false,
environment: 'node',
@ -22,10 +23,10 @@ import registerIpcMainMessageListeners from './main/registerIpcMainMessageListen
import registerProcessListeners from './main/registerProcessListeners';
export class Main {
title: string = 'Frappe Books';
title = 'Frappe Books';
icon: string;
winURL: string = '';
winURL = '';
checkedForUpdate = false;
mainWindow: BrowserWindow | null = null;
@ -130,9 +131,9 @@ export class Main {
this.registerAppProtocol();
}
this.mainWindow!.loadURL(this.winURL);
this.mainWindow.loadURL(this.winURL);
if (this.isDevelopment && !this.isTest) {
this.mainWindow!.webContents.openDevTools();
this.mainWindow.webContents.openDevTools();
}
this.setMainWindowListeners();

View File

@ -4,6 +4,7 @@ import fetch from 'node-fetch';
import path from 'path';
import { Creds } from 'utils/types';
import { rendererLog } from './helpers';
import type { Main } from 'main';
export function getUrlAndTokenString(): Creds {
const inProduction = app.isPackaged;
@ -42,7 +43,7 @@ export function getUrlAndTokenString(): Creds {
};
}
export async function sendError(body: string) {
export async function sendError(body: string, main: Main) {
const { errorLogUrl, tokenString } = getUrlAndTokenString();
const headers = {
Authorization: tokenString,
@ -51,6 +52,6 @@ export async function sendError(body: string) {
};
await fetch(errorLogUrl, { method: 'POST', headers, body }).catch((err) => {
rendererLog(err);
rendererLog(main, err);
});
}

View File

@ -16,8 +16,7 @@ import fs from 'fs/promises';
import path from 'path';
import { parseCSV } from 'utils/csvParser';
import { LanguageMap } from 'utils/types';
const fetch = require('node-fetch').default;
import fetch from 'node-fetch';
const VALENTINES_DAY = 1644796800000;
@ -100,7 +99,7 @@ async function fetchContentsFromApi(code: string) {
return null;
}
const resJson = await res.json();
const resJson = (await res.json()) as { content: string };
return Buffer.from(resJson.content, 'base64').toString();
}
@ -138,7 +137,9 @@ async function getLastUpdated(code: string): Promise<Date> {
return new Date(VALENTINES_DAY);
}
const resJson = await res.json();
const resJson = (await res.json()) as {
commit: { author: { date: string } };
}[];
try {
return new Date(resJson[0].commit.author.date);
} catch {
@ -187,7 +188,7 @@ async function storeFile(code: string, contents: string) {
async function errorHandledFetch(url: string) {
try {
return (await fetch(url)) as Response;
return await fetch(url);
} catch {
return null;
}

View File

@ -1,6 +1,6 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
import { ConfigFile } from 'fyo/core/types';
import { Main } from 'main';
import config from 'utils/config';
import { BackendResponse } from 'utils/ipc/types';
@ -8,7 +8,7 @@ import { IPC_CHANNELS } from 'utils/messages';
import type { ConfigFilesWithModified } from 'utils/types';
export async function setAndGetCleanedConfigFiles() {
const files = config.get(ConfigKeys.Files, []) as ConfigFile[];
const files = config.get('files', []);
const cleanedFileMap: Map<string, ConfigFile> = new Map();
for (const file of files) {
@ -30,7 +30,7 @@ export async function setAndGetCleanedConfigFiles() {
}
const cleanedFiles = Array.from(cleanedFileMap.values());
config.set(ConfigKeys.Files, cleanedFiles);
config.set('files', cleanedFiles);
return cleanedFiles;
}
@ -50,7 +50,9 @@ export async function getConfigFilesWithModified(files: ConfigFile[]) {
return filesWithModified;
}
export async function getErrorHandledReponse(func: () => Promise<unknown>) {
export async function getErrorHandledReponse(
func: () => Promise<unknown> | unknown
) {
const response: BackendResponse = {};
try {

View File

@ -1,4 +1,11 @@
import { app, dialog, ipcMain } from 'electron';
import {
MessageBoxOptions,
OpenDialogOptions,
SaveDialogOptions,
app,
dialog,
ipcMain,
} from 'electron';
import { autoUpdater } from 'electron-updater';
import fs from 'fs/promises';
import path from 'path';
@ -20,39 +27,60 @@ import {
import { saveHtmlAsPdf } from './saveHtmlAsPdf';
export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(IPC_ACTIONS.GET_OPEN_FILEPATH, async (event, options) => {
return await dialog.showOpenDialog(main.mainWindow!, options);
});
ipcMain.handle(IPC_ACTIONS.GET_SAVE_FILEPATH, async (event, options) => {
return await dialog.showSaveDialog(main.mainWindow!, options);
});
ipcMain.handle(IPC_ACTIONS.GET_DIALOG_RESPONSE, async (event, options) => {
if (main.isDevelopment || main.isLinux) {
Object.assign(options, { icon: main.icon });
ipcMain.handle(
IPC_ACTIONS.GET_OPEN_FILEPATH,
async (_, options: OpenDialogOptions) => {
return await dialog.showOpenDialog(main.mainWindow!, options);
}
);
return await dialog.showMessageBox(main.mainWindow!, options);
});
ipcMain.handle(
IPC_ACTIONS.GET_SAVE_FILEPATH,
async (_, options: SaveDialogOptions) => {
return await dialog.showSaveDialog(main.mainWindow!, options);
}
);
ipcMain.handle(IPC_ACTIONS.SHOW_ERROR, async (event, { title, content }) => {
return await dialog.showErrorBox(title, content);
});
ipcMain.handle(
IPC_ACTIONS.GET_DIALOG_RESPONSE,
async (_, options: MessageBoxOptions) => {
if (main.isDevelopment || main.isLinux) {
Object.assign(options, { icon: main.icon });
}
return await dialog.showMessageBox(main.mainWindow!, options);
}
);
ipcMain.handle(
IPC_ACTIONS.SHOW_ERROR,
(_, { title, content }: { title: string; content: string }) => {
return dialog.showErrorBox(title, content);
}
);
ipcMain.handle(
IPC_ACTIONS.SAVE_HTML_AS_PDF,
async (event, html, savePath, width: number, height: number) => {
async (
_,
html: string,
savePath: string,
width: number,
height: number
) => {
return await saveHtmlAsPdf(html, savePath, app, width, height);
}
);
ipcMain.handle(IPC_ACTIONS.SAVE_DATA, async (event, data, savePath) => {
return await fs.writeFile(savePath, data, { encoding: 'utf-8' });
});
ipcMain.handle(
IPC_ACTIONS.SAVE_DATA,
async (_, data: string, savePath: string) => {
return await fs.writeFile(savePath, data, { encoding: 'utf-8' });
}
);
ipcMain.handle(IPC_ACTIONS.SEND_ERROR, (event, bodyJson) => {
sendError(bodyJson);
ipcMain.handle(IPC_ACTIONS.SEND_ERROR, (_, bodyJson: string) => {
sendError(bodyJson, main);
});
ipcMain.handle(IPC_ACTIONS.CHECK_FOR_UPDATES, async () => {
@ -72,7 +100,7 @@ export default function registerIpcMainActionListeners(main: Main) {
main.checkedForUpdate = true;
});
ipcMain.handle(IPC_ACTIONS.GET_LANGUAGE_MAP, async (event, code) => {
ipcMain.handle(IPC_ACTIONS.GET_LANGUAGE_MAP, async (_, code: string) => {
const obj = { languageMap: {}, success: true, message: '' };
try {
obj.languageMap = await getLanguageMap(code);
@ -117,20 +145,20 @@ export default function registerIpcMainActionListeners(main: Main) {
}
);
ipcMain.handle(IPC_ACTIONS.GET_CREDS, async (event) => {
ipcMain.handle(IPC_ACTIONS.GET_CREDS, () => {
return getUrlAndTokenString();
});
ipcMain.handle(IPC_ACTIONS.DELETE_FILE, async (_, filePath) => {
ipcMain.handle(IPC_ACTIONS.DELETE_FILE, async (_, filePath: string) => {
return getErrorHandledReponse(async () => await fs.unlink(filePath));
});
ipcMain.handle(IPC_ACTIONS.GET_DB_LIST, async (_) => {
ipcMain.handle(IPC_ACTIONS.GET_DB_LIST, async () => {
const files = await setAndGetCleanedConfigFiles();
return await getConfigFilesWithModified(files);
});
ipcMain.handle(IPC_ACTIONS.GET_ENV, async (_) => {
ipcMain.handle(IPC_ACTIONS.GET_ENV, () => {
return {
isDevelopment: main.isDevelopment,
platform: process.platform,
@ -149,7 +177,7 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(
IPC_ACTIONS.DB_CREATE,
async (_, dbPath: string, countryCode: string) => {
return await getErrorHandledReponse(async function dbFunc() {
return await getErrorHandledReponse(async () => {
return await databaseManager.createNewDatabase(dbPath, countryCode);
});
}
@ -158,7 +186,7 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(
IPC_ACTIONS.DB_CONNECT,
async (_, dbPath: string, countryCode?: string) => {
return await getErrorHandledReponse(async function dbFunc() {
return await getErrorHandledReponse(async () => {
return await databaseManager.connectToDatabase(dbPath, countryCode);
});
}
@ -167,7 +195,7 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(
IPC_ACTIONS.DB_CALL,
async (_, method: DatabaseMethod, ...args: unknown[]) => {
return await getErrorHandledReponse(async function dbFunc() {
return await getErrorHandledReponse(async () => {
return await databaseManager.call(method, ...args);
});
}
@ -176,15 +204,15 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(
IPC_ACTIONS.DB_BESPOKE,
async (_, method: string, ...args: unknown[]) => {
return await getErrorHandledReponse(async function dbFunc() {
return await getErrorHandledReponse(async () => {
return await databaseManager.callBespoke(method, ...args);
});
}
);
ipcMain.handle(IPC_ACTIONS.DB_SCHEMA, async (_) => {
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.getSchemaMap();
ipcMain.handle(IPC_ACTIONS.DB_SCHEMA, async () => {
return await getErrorHandledReponse(() => {
return databaseManager.getSchemaMap();
});
});
}

View File

@ -20,11 +20,11 @@ export default function registerIpcMainMessageListeners(main: Main) {
main.mainWindow!.reload();
});
ipcMain.on(IPC_MESSAGES.OPEN_EXTERNAL, (_, link) => {
ipcMain.on(IPC_MESSAGES.OPEN_EXTERNAL, (_, link: string) => {
shell.openExternal(link);
});
ipcMain.on(IPC_MESSAGES.SHOW_ITEM_IN_FOLDER, (_, filePath) => {
ipcMain.on(IPC_MESSAGES.SHOW_ITEM_IN_FOLDER, (_, filePath: string) => {
return shell.showItemInFolder(filePath);
});
}

View File

@ -36,7 +36,6 @@
</div>
</template>
<script lang="ts">
import { ConfigKeys } from 'fyo/core/types';
import { RTL_LANGUAGES } from 'fyo/utils/consts';
import { ModelNameEnum } from 'models/types';
import { systemLanguageRef } from 'src/utils/refs';
@ -126,10 +125,7 @@ export default defineComponent({
},
methods: {
async setInitialScreen(): Promise<void> {
const lastSelectedFilePath = fyo.config.get(
ConfigKeys.LastSelectedFilePath,
null
);
const lastSelectedFilePath = fyo.config.get('lastSelectedFilePath', null);
if (
typeof lastSelectedFilePath !== 'string' ||
@ -159,7 +155,7 @@ export default defineComponent({
updateConfigFiles(fyo);
},
async fileSelected(filePath: string, isNew?: boolean): Promise<void> {
fyo.config.set(ConfigKeys.LastSelectedFilePath, filePath);
fyo.config.set('lastSelectedFilePath', filePath);
if (isNew) {
this.activeScreen = Screen.SetupWizard;
return;
@ -173,7 +169,7 @@ export default defineComponent({
}
},
async setupComplete(setupWizardOptions: SetupWizardOptions): Promise<void> {
const filePath = fyo.config.get(ConfigKeys.LastSelectedFilePath);
const filePath = fyo.config.get('lastSelectedFilePath');
if (typeof filePath !== 'string') {
return;
}

View File

@ -1,5 +1,4 @@
import { t } from 'fyo';
import { ConfigKeys } from 'fyo/core/types';
import { Doc } from 'fyo/model/doc';
import { BaseError } from 'fyo/utils/errors';
import { ErrorLog } from 'fyo/utils/types';
@ -10,6 +9,7 @@ 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) {
@ -23,7 +23,7 @@ export async function sendError(errorLogObj: ErrorLog) {
}
errorLogObj.more ??= {};
errorLogObj.more!.path ??= router.currentRoute.value.fullPath;
errorLogObj.more.path ??= router.currentRoute.value.fullPath;
const body = {
error_name: errorLogObj.name,
@ -77,7 +77,7 @@ export async function handleError(
logToConsole: boolean,
error: Error,
more: Record<string, unknown> = {},
notifyUser: boolean = true
notifyUser = true
) {
if (logToConsole) {
console.error(error);
@ -127,7 +127,13 @@ export async function handleErrorWithDialog(
},
isPrimary: true,
},
{ label: t`Cancel`, action() {}, isEscape: true },
{
label: t`Cancel`,
action() {
return null;
},
isEscape: true,
},
];
}
@ -152,7 +158,7 @@ export async function showErrorDialog(title?: string, content?: string) {
// Wrapper Functions
export function getErrorHandled(func: Function) {
export function getErrorHandled(func: UnknownFunction) {
return async function errorHandled(...args: unknown[]) {
try {
return await func(...args);
@ -167,7 +173,7 @@ export function getErrorHandled(func: Function) {
};
}
export function getErrorHandledSync(func: Function) {
export function getErrorHandledSync(func: UnknownFunction) {
return function errorHandledSync(...args: unknown[]) {
try {
return func(...args);
@ -208,7 +214,7 @@ function getIssueUrlQuery(errorLogObj?: ErrorLog): string {
body.push(`**Platform**: \`${fyo.store.platform}\``);
body.push(`**Path**: \`${router.currentRoute.value.fullPath}\``);
body.push(`**Language**: \`${fyo.config.get(ConfigKeys.Language)}\``);
body.push(`**Language**: \`${fyo.config.get('language') ?? '-'}\``);
if (fyo.singles.SystemSettings?.countryCode) {
body.push(`**Country**: \`${fyo.singles.SystemSettings.countryCode}\``);
}

View File

@ -117,7 +117,7 @@ export class Importer {
this.templateFieldsMap = new Map();
this.templateFieldsPicked = new Map();
templateFields.forEach((f, i) => {
templateFields.forEach((f) => {
this.templateFieldsMap.set(f.fieldKey, f);
this.templateFieldsPicked.set(f.fieldKey, true);
});

View File

@ -214,7 +214,6 @@
</template>
<script lang="ts">
import { setupDummyInstance } from 'dummy';
const { ipcRenderer } = require('electron');
import { t } from 'fyo';
import { DateTime } from 'luxon';
import Button from 'src/components/Button.vue';
@ -224,11 +223,12 @@ import Loading from 'src/components/Loading.vue';
import Modal from 'src/components/Modal.vue';
import { fyo } from 'src/initFyo';
import { showDialog } from 'src/utils/interactive';
import { deleteDb, getSavePath } from 'src/utils/ipcCalls';
import { deleteDb, getSavePath, getSelectedFilePath } from 'src/utils/ipcCalls';
import { updateConfigFiles } from 'src/utils/misc';
import { IPC_ACTIONS } from 'utils/messages';
import type { ConfigFilesWithModified } from 'utils/types';
import { defineComponent } from 'vue';
const { ipcRenderer } = require('electron');
export default defineComponent({
name: 'DatabaseSelector',
@ -353,13 +353,7 @@ export default defineComponent({
return;
}
const filePath = (
await ipcRenderer.invoke(IPC_ACTIONS.GET_OPEN_FILEPATH, {
title: this.t`Select file`,
properties: ['openFile'],
filters: [{ name: 'SQLite DB File', extensions: ['db'] }],
})
)?.filePaths?.[0];
const filePath = (await getSelectedFilePath())?.filePaths?.[0];
this.emitFileSelected(filePath);
},
async selectFile(file: ConfigFilesWithModified) {

View File

@ -1,5 +1,4 @@
const { ipcRenderer } = require('electron');
import { ConfigKeys } from 'fyo/core/types';
import { DateTime } from 'luxon';
import { CUSTOM_EVENTS, IPC_ACTIONS } from 'utils/messages';
import { UnexpectedLogObject } from 'utils/types';
@ -16,7 +15,7 @@ import { stringifyCircular } from './utils';
import { setLanguageMap } from './utils/language';
(async () => {
const language = fyo.config.get(ConfigKeys.Language) as string;
const language = fyo.config.get('language') as string;
if (language) {
await setLanguageMap(language);
}
@ -74,7 +73,13 @@ function setErrorHandlers(app: VueApp) {
};
window.onunhandledrejection = (event: PromiseRejectionEvent) => {
const error = event.reason;
let error: Error;
if (event.reason instanceof Error) {
error = event.reason;
} else {
error = new Error(String(event.reason));
}
handleError(true, error).catch((err) => console.error(err));
};

View File

@ -36,7 +36,7 @@ export default function registerIpcRendererListeners() {
}
});
document.addEventListener('visibilitychange', function () {
document.addEventListener('visibilitychange', () => {
const { visibilityState } = document;
if (visibilityState === 'visible' && !fyo.telemetry.started) {
fyo.telemetry.start();

View File

@ -12,6 +12,7 @@ import Settings from 'src/pages/Settings/Settings.vue';
import TemplateBuilder from 'src/pages/TemplateBuilder/TemplateBuilder.vue';
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import { historyState } from './utils/refs';
import type { HistoryState } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
@ -122,8 +123,9 @@ const routes: RouteRecordRaw[] = [
const router = createRouter({ routes, history: createWebHistory() });
router.afterEach(() => {
historyState.forward = !!history.state?.forward;
historyState.back = !!history.state?.back;
const state = history.state as HistoryState;
historyState.forward = !!state.forward;
historyState.back = !!state.back;
});
export default router;

View File

@ -262,7 +262,7 @@ async function checkAndCreateDoc(
return;
}
const doc = await fyo.doc.getNewDoc(schemaName, docObject);
const doc = fyo.doc.getNewDoc(schemaName, docObject);
return doc.sync();
}

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

@ -3,9 +3,9 @@ import Vue, { VNode } from 'vue'
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
type Element = VNode
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
type ElementClass = Vue
interface IntrinsicElements {
[elem: string]: any
}

View File

@ -37,7 +37,7 @@ function evaluateFieldMeta(
field: Field,
doc?: Doc,
meta?: 'required' | 'hidden' | 'readOnly',
defaultValue: boolean = false
defaultValue = false
) {
if (meta === undefined) {
return defaultValue;

View File

@ -118,7 +118,7 @@ export async function getCsvExportData(
const tableFieldRowMap = parentNameMap[parentName];
if (!tableFieldRowMap || !Object.keys(tableFieldRowMap ?? {}).length) {
rows.push([baseRowData, headers.child.map((_) => '')].flat());
rows.push([baseRowData, headers.child.map(() => '')].flat());
continue;
}

View File

@ -14,8 +14,8 @@ import { fyo } from 'src/initFyo';
export function stringifyCircular(
obj: unknown,
ignoreCircular: boolean = false,
convertDocument: boolean = false
ignoreCircular = false,
convertDocument = false
) {
const cacheKey: string[] = [];
const cacheValue: unknown[] = [];

View File

@ -1,5 +1,5 @@
import { Fyo } from 'fyo';
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
import { ConfigFile } from 'fyo/core/types';
import { getRegionalModels, models } from 'models/index';
import { ModelNameEnum } from 'models/types';
import { TargetField } from 'schemas/types';
@ -68,7 +68,7 @@ async function checkSingleLinks(fyo: Fyo) {
.flat()
.filter((field) => field.fieldtype === 'Link' && field.target)
.map((field) => ({
fieldKey: `${field.schemaName}.${field.fieldname}`,
fieldKey: `${field.schemaName!}.${field.fieldname}`,
target: (field as TargetField).target,
}));
const linkFieldsMap = getMapFromList(linkFields, 'fieldKey');
@ -126,10 +126,10 @@ async function setVersion(fyo: Fyo) {
}
function setDeviceId(fyo: Fyo) {
let deviceId = fyo.config.get(ConfigKeys.DeviceId) as string | undefined;
let deviceId = fyo.config.get('deviceId');
if (deviceId === undefined) {
deviceId = getRandomString();
fyo.config.set(ConfigKeys.DeviceId, deviceId);
fyo.config.set('deviceId', deviceId);
}
fyo.store.deviceId = deviceId;
@ -176,7 +176,7 @@ async function setOpenCount(fyo: Fyo) {
}
function getOpenCountFromFiles(fyo: Fyo) {
const configFile = fyo.config.get(ConfigKeys.Files, []) as ConfigFile[];
const configFile = fyo.config.get('files', []) as ConfigFile[];
for (const file of configFile) {
if (file.id === fyo.singles.SystemSettings?.instanceId) {
return file.openCount ?? 0;

View File

@ -13,7 +13,7 @@ type DialogReturn<DO extends DialogOptions> = DO['buttons'] extends {
export async function showDialog<DO extends DialogOptions>(options: DO) {
const preWrappedButtons: DialogButton[] = options.buttons ?? [
{ label: t`Okay`, action: () => {}, isEscape: true },
{ label: t`Okay`, action: () => null, isEscape: true },
];
return new Promise(async (resolve, reject) => {

View File

@ -9,11 +9,20 @@ import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
import { SelectFileOptions, SelectFileReturn, TemplateFile } from 'utils/types';
import { showDialog, showToast } from './interactive';
import { setLanguageMap } from './language';
import type { OpenDialogReturnValue } from 'electron';
export function reloadWindow() {
return ipcRenderer.send(IPC_MESSAGES.RELOAD_MAIN_WINDOW);
}
export async function getSelectedFilePath(): Promise<OpenDialogReturnValue> {
return await ipcRenderer.invoke(IPC_ACTIONS.GET_OPEN_FILEPATH, {
title: this.t`Select file`,
properties: ['openFile'],
filters: [{ name: 'SQLite DB File', extensions: ['db'] }],
});
}
export async function getTemplates(): Promise<TemplateFile[]> {
return await ipcRenderer.invoke(IPC_ACTIONS.GET_TEMPLATES);
}

View File

@ -25,7 +25,7 @@ export const languageCodeMap: Record<string, string> = {
export async function setLanguageMap(
initLanguage?: string,
dontReload: boolean = false
dontReload = false
) {
const oldLanguage = fyo.config.get('language') as string;
initLanguage ??= oldLanguage;

View File

@ -1,5 +1,5 @@
import { Fyo } from 'fyo';
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
import { ConfigFile } from 'fyo/core/types';
import { DateTime } from 'luxon';
import { SetupWizard } from 'models/baseModels/SetupWizard/SetupWizard';
import { ModelNameEnum } from 'models/types';
@ -64,7 +64,7 @@ export function getSetupWizardDoc() {
}
export function updateConfigFiles(fyo: Fyo): ConfigFile {
const configFiles = fyo.config.get(ConfigKeys.Files, []) as ConfigFile[];
const configFiles = fyo.config.get('files', []) as ConfigFile[];
const companyName = fyo.singles.AccountingSettings!.companyName as string;
const id = fyo.singles.SystemSettings!.instanceId as string;
@ -83,7 +83,7 @@ export function updateConfigFiles(fyo: Fyo): ConfigFile {
newFile = configFiles[fileIndex];
}
fyo.config.set(ConfigKeys.Files, configFiles);
fyo.config.set('files', configFiles);
return newFile;
}

View File

@ -93,11 +93,12 @@ export function getPrintTemplatePropHints(schemaName: string, fyo: Fyo) {
}
function showHSN(doc: Doc): boolean {
if (!Array.isArray(doc.items)) {
const items = doc.items;
if (!Array.isArray(items)) {
return false;
}
return doc.items.map((i) => i.hsnCode).every(Boolean);
return items.map((i: Doc) => i.hsnCode).every(Boolean);
}
function formattedTotalDiscount(doc: Doc): string {
@ -246,15 +247,14 @@ function constructPrintDocument(innerHTML: string) {
}
function getAllCSSAsStyleElem() {
const cssTexts = [];
const cssTexts: string[] = [];
for (const sheet of document.styleSheets) {
for (const rule of sheet.cssRules) {
cssTexts.push(rule.cssText);
}
// @ts-ignore
for (const rule of sheet.ownerRule ?? []) {
cssTexts.push(rule.cssText);
if (sheet.ownerRule) {
cssTexts.push(sheet.ownerRule.cssText);
}
}

View File

@ -1,9 +1,10 @@
import { reactive, ref } from 'vue';
import type { HistoryState } from 'vue-router';
export const showSidebar = ref(true);
export const docsPathRef = ref<string>('');
export const systemLanguageRef = ref<string>('');
export const historyState = reactive({
forward: !!history.state?.forward,
back: !!history.state?.back,
forward: !!(history.state as HistoryState)?.forward,
back: !!(history.state as HistoryState)?.back,
});

View File

@ -346,8 +346,8 @@ export class Search {
* - Marked indices are rebuilt when the modal is opened.
*/
_obsSet: boolean = false;
numSearches: number = 0;
_obsSet = false;
numSearches = 0;
searchables: Record<string, Searchable>;
keywords: Record<string, Keyword[]>;
priorityMap: Record<string, number> = {
@ -707,7 +707,7 @@ export class Search {
_getDocSearchItemFromKeyword(keyword: Keyword): DocSearchItem {
const schemaName = keyword.meta.schemaName as string;
const schemaLabel = this.fyo.schemaMap[schemaName]?.label!;
const schemaLabel = this.fyo.schemaMap[schemaName]?.label ?? schemaName;
const route = this._getRouteFromKeyword(keyword);
return {
label: keyword.values[0],

View File

@ -12,7 +12,7 @@ interface ModMap {
type Mod = keyof ModMap;
type Context = unknown;
type ShortcutFunction = () => void;
type ShortcutFunction = () => unknown;
type ShortcutConfig = {
callback: ShortcutFunction;
propagate: boolean;
@ -117,8 +117,8 @@ export class Shortcuts {
context: Context,
shortcut: string[],
callback: ShortcutFunction,
propagate: boolean = false,
removeIfSet: boolean = true
propagate = false,
removeIfSet = true
): void {
const key = this.getKey(shortcut);
if (!key) {

View File

@ -3,8 +3,8 @@ import { routeFilters } from 'src/utils/filters';
import { fyo } from '../initFyo';
import { SidebarConfig, SidebarItem, SidebarRoot } from './types';
export async function getSidebarConfig(): Promise<SidebarConfig> {
const sideBar = await getCompleteSidebar();
export function getSidebarConfig(): SidebarConfig {
const sideBar = getCompleteSidebar();
return getFilteredSidebar(sideBar);
}
@ -54,7 +54,7 @@ function getRegionalSidebar(): SidebarRoot[] {
];
}
async function getInventorySidebar(): Promise<SidebarRoot[]> {
function getInventorySidebar(): SidebarRoot[] {
const hasInventory = !!fyo.singles.AccountingSettings?.enableInventory;
if (!hasInventory) {
return [];
@ -101,7 +101,7 @@ async function getInventorySidebar(): Promise<SidebarRoot[]> {
];
}
async function getReportSidebar() {
function getReportSidebar() {
return {
label: t`Reports`,
name: 'reports',
@ -132,7 +132,7 @@ async function getReportSidebar() {
};
}
async function getCompleteSidebar(): Promise<SidebarConfig> {
function getCompleteSidebar(): SidebarConfig {
return [
{
label: t`Get Started`,
@ -141,7 +141,7 @@ async function getCompleteSidebar(): Promise<SidebarConfig> {
icon: 'general',
iconSize: '24',
iconHeight: 5,
hidden: () => fyo.singles.SystemSettings!.hideGetStarted as boolean,
hidden: () => !!fyo.singles.SystemSettings?.hideGetStarted,
},
{
label: t`Dashboard`,
@ -254,9 +254,9 @@ async function getCompleteSidebar(): Promise<SidebarConfig> {
},
] as SidebarItem[],
},
await getReportSidebar(),
await getInventorySidebar(),
await getRegionalSidebar(),
getReportSidebar(),
getInventorySidebar(),
getRegionalSidebar(),
{
label: t`Setup`,
name: 'setup',

View File

@ -90,7 +90,7 @@ export type ActionGroup = {
export type DropdownItem = {
label: string;
value?: string;
action?: Function;
action?: () => unknown;
group?: string;
component?: { template: string };
isGroup?: boolean;

View File

@ -386,7 +386,7 @@ export function toggleSidebar(value?: boolean) {
export function focusOrSelectFormControl(
doc: Doc,
ref: any,
clear: boolean = true
clear= true
) {
if (!doc?.fyo) {
return;
@ -507,7 +507,7 @@ export async function commonDocCancel(doc: Doc): Promise<boolean> {
export async function commonDocSync(
doc: Doc,
useDialog: boolean = false
useDialog = false
): Promise<boolean> {
let success: boolean;
if (useDialog) {

View File

@ -100,7 +100,7 @@ export function useDocShortcuts(
shortcuts: Shortcuts,
docRef: DocRef,
name: string,
isMultiple: boolean = true
isMultiple = true
) {
let context = name;
if (isMultiple) {

View File

@ -1,4 +1,5 @@
import Store from 'electron-store';
import type { ConfigMap } from 'fyo/core/types';
const config = new Store();
const config = new Store<ConfigMap>();
export default config;

View File

@ -1,8 +1,9 @@
import type { ConfigFile } from "fyo/core/types";
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 {