refactor: improve typing 2

This commit is contained in:
Johannes Millan 2025-08-12 00:37:33 +02:00
parent 632c140894
commit 34ac3dd757
31 changed files with 145 additions and 112 deletions

View file

@ -73,7 +73,15 @@ function inspectElements(): void {
// }
// };
export const initDebug = (opts: any, isAddReload: boolean): void => {
export const initDebug = (
opts: {
enabled?: boolean | null;
showDevTools?: boolean;
devToolsMode?: string;
mode?: string;
},
isAddReload: boolean,
): void => {
opts = Object.assign(
{
enabled: null,

View file

@ -6,7 +6,7 @@ const WAIT_FOR_WIN_TIMEOUT_DURATION = 4000;
export const errorHandlerWithFrontendInform = (
e: Error | unknown | string = 'UNDEFINED ERROR',
additionalLogInfo?: any,
additionalLogInfo?: unknown,
): void => {
const errObj = new Error(e as string);
@ -30,8 +30,8 @@ function _isReadyForFrontEndError(): boolean {
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function _handleError(
e: Error | unknown | string,
additionalLogInfo: any,
errObj: any,
additionalLogInfo: unknown,
errObj: Error,
): void {
const mainWin = getWin();
const stack = errObj.stack;
@ -47,7 +47,7 @@ function _handleError(
if (_isReadyForFrontEndError()) {
mainWin.webContents.send(IPC.ERROR, {
error: e,
errorStr: e && (e as any).toString(),
errorStr: e && String(e),
stack,
});
} else {

View file

@ -267,7 +267,7 @@ export class IdleTimeHandler {
return this.getIdleTime();
}
private logError(context: string, error: any): void {
private logError(context: string, error: unknown): void {
const now = Date.now();
if (now - this.lastErrorLog > this.ERROR_LOG_INTERVAL) {
log.debug(`${context} (falling back to 0):`, error);

View file

@ -32,7 +32,7 @@ export const sendJiraRequest = ({
}
: {}),
} as RequestInit)
.then(async (response: any) => {
.then(async (response) => {
// log('JIRA_RAW_RESPONSE', response);
if (!response.ok) {
error('Jira Error Error Response ELECTRON: ', response);
@ -50,8 +50,8 @@ export const sendJiraRequest = ({
}
return response;
})
.then((res: any) => res.text())
.then((text: any) => {
.then((res) => res.text())
.then((text) => {
try {
return text ? JSON.parse(text) : {};
} catch (e) {
@ -61,13 +61,13 @@ export const sendJiraRequest = ({
return text;
}
})
.then((response: any) => {
.then((response) => {
mainWin.webContents.send(IPC.JIRA_CB_EVENT, {
response,
requestId,
});
})
.catch((err: any) => {
.catch((err: unknown) => {
mainWin.webContents.send(IPC.JIRA_CB_EVENT, {
error: err,
requestId,

View file

@ -188,7 +188,7 @@ export const createWindow = ({
};
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function initWinEventListeners(app: any): void {
function initWinEventListeners(app: Electron.App): void {
const openUrlInBrowser = (url: string): void => {
// needed for mac; especially for jira urls we might have a host like this www.host.de//
const urlObj = new URL(url);

View file

@ -121,8 +121,8 @@ class PluginNodeExecutor {
throw new Error(`Module '${module}' is not allowed`);
},
console: {
log: (...logArgs: any[]) => console.log('[Plugin]:', ...logArgs),
error: (...errorArgs: any[]) => console.error('[Plugin]:', ...errorArgs),
log: (...logArgs: unknown[]) => console.log('[Plugin]:', ...logArgs),
error: (...errorArgs: unknown[]) => console.error('[Plugin]:', ...errorArgs),
},
JSON,
args: args || [],

View file

@ -4,7 +4,7 @@ export const lazySetInterval = (
func: () => void,
intervalDuration: number,
): (() => void) => {
let lastTimeoutId: any;
let lastTimeoutId: ReturnType<typeof setTimeout>;
const interval = (): void => {
lastTimeoutId = setTimeout(interval, intervalDuration);

View file

@ -85,6 +85,11 @@ import { ProjectService } from './features/project/project.service';
import { TagService } from './features/tag/tag.service';
import { ContextMenuComponent } from './ui/context-menu/context-menu.component';
interface BeforeInstallPromptEvent extends Event {
prompt(): Promise<void>;
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
}
const w = window as any;
const productivityTip: string[] = w.productivityTips && w.productivityTips[w.randomIndex];
@ -269,8 +274,8 @@ export class AppComponent implements OnDestroy, AfterViewInit {
effect(() => {
window.ea.on(IPC.ERROR, (ev: IpcRendererEvent, ...args: unknown[]) => {
const data = args[0] as {
error: any;
stack: any;
error: unknown;
stack: unknown;
errorStr: string | unknown;
};
const errMsg =
@ -390,7 +395,7 @@ export class AppComponent implements OnDestroy, AfterViewInit {
}
@HostListener('window:beforeinstallprompt', ['$event']) onBeforeInstallPrompt(
e: any,
e: BeforeInstallPromptEvent,
): void {
if (IS_ELECTRON || localStorage.getItem(LS.WEB_APP_INSTALL)) {
return;
@ -621,7 +626,7 @@ export class AppComponent implements OnDestroy, AfterViewInit {
if (navigator.storage) {
// try to avoid data-loss
Promise.all([navigator.storage.persisted()])
.then(([persisted]): any => {
.then(([persisted]) => {
if (!persisted) {
return navigator.storage.persist().then((granted) => {
if (granted) {
@ -636,6 +641,7 @@ export class AppComponent implements OnDestroy, AfterViewInit {
});
} else {
Log.log('Persistence already allowed');
return;
}
})
.catch((e) => {

View file

@ -30,7 +30,7 @@ export class LayoutEffects {
hideNotesNavigatingToDailySummary$ = createEffect(() =>
this.router.events.pipe(
filter((event: any) => event instanceof NavigationEnd),
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
filter((event) => !!event.url.match(/(daily-summary)$/)),
mapTo(hideNonTaskSidePanelContent()),
),

View file

@ -20,10 +20,18 @@ export class GlobalErrorHandler implements ErrorHandler {
private injector = inject<Injector>(Injector);
// TODO Cleanup this mess
async handleError(err: any): Promise<void> {
const errStr = typeof err === 'string' ? err : err.toString();
async handleError(err: unknown): Promise<void> {
const errStr = typeof err === 'string' ? err : String(err);
// eslint-disable-next-line
const simpleStack = err && err.stack;
let simpleStack = '';
if (
err &&
typeof err === 'object' &&
'stack' in err &&
typeof err.stack === 'string'
) {
simpleStack = err.stack;
}
Log.err('GLOBAL_ERROR_HANDLER', err);
// if not our custom error handler we have a critical error on our hands
@ -60,7 +68,7 @@ export class GlobalErrorHandler implements ErrorHandler {
? str
: 'Unable to parse error string. Please see console error';
} else {
return (err as any).toString();
return String(err);
}
}

View file

@ -5,7 +5,6 @@ import { getBeforeLastErrorActionLog } from '../../util/action-logger';
import { download, downloadLogs } from '../../util/download';
import { privacyExport } from '../../imex/file-imex/privacy-export';
import { getAppVersionStr } from '../../util/get-app-version-str';
import { CompleteBackup } from '../../pfapi/api';
import { Log } from '../log';
let isWasErrorAlertCreated = false;
@ -14,7 +13,7 @@ let isWasErrorAlertCreated = false;
const createSimpleThrottle = (limit: number, interval: number) => {
const timestamps: number[] = [];
return <T extends (...args: any[]) => any>(fn: T) => {
return <T extends (...args: unknown[]) => unknown>(fn: T) => {
return ((...args: Parameters<T>) => {
const now = Date.now();
@ -99,8 +98,8 @@ const _cleanHtml = (str: string): string => {
export const createErrorAlert = (
err: string = '',
stackTrace: string,
origErr: any,
userData?: CompleteBackup<any> | undefined,
origErr: unknown,
userData?: unknown,
): void => {
if (isWasErrorAlertCreated) {
return;
@ -165,9 +164,10 @@ export const createErrorAlert = (
btnPrivacyExport.title =
'Export anonymized data (to send to contact@super-productivity.com for debugging)';
btnPrivacyExport.addEventListener('click', () => {
// Type assertion needed for privacy export function
download(
'ANONYMIZED-super-productivity-crash-user-data-export.json',
privacyExport(userData),
privacyExport(userData as Parameters<typeof privacyExport>[0]),
);
});
innerWrapper.append(btnPrivacyExport);

View file

@ -1,10 +0,0 @@
import { Log } from '../log';
export class AdditionalLogErrorBase extends Error {
constructor(...additional: any) {
super(...additional);
Log.log(1, this.name, ...additional);
}
}
/// -------------------------

View file

@ -5,9 +5,7 @@ import { EMPTY, Observable } from 'rxjs';
import { IS_ELECTRON } from '../app.constants';
export const ipcIdleTime$: Observable<number> = IS_ELECTRON
? ipcEvent$(IPC.IDLE_TIME).pipe(
map(([ev, idleTimeInMs]: any) => idleTimeInMs as number),
)
? ipcEvent$(IPC.IDLE_TIME).pipe(map(([ev, idleTimeInMs]) => idleTimeInMs as number))
: EMPTY;
export const ipcAnyFileDownloaded$: Observable<unknown> = IS_ELECTRON
@ -31,6 +29,6 @@ export const ipcShowAddTaskBar$: Observable<unknown> = IS_ELECTRON
export const ipcAddTaskFromAppUri$: Observable<{ title: string }> = IS_ELECTRON
? ipcEvent$(IPC.ADD_TASK_FROM_APP_URI).pipe(
map(([ev, data]: any) => data as { title: string }),
map(([ev, data]) => data as { title: string }),
)
: EMPTY;

View file

@ -23,6 +23,13 @@ interface ClientCache {
calendars: Map<string, Calendar>;
}
interface CalDavTaskData {
data: string;
url: string;
etag: string;
update?: () => Promise<void>;
}
@Injectable({
providedIn: 'root',
})
@ -53,7 +60,10 @@ export class CaldavClientService {
return url.substring(url.lastIndexOf('/') + 1);
}
private static async _getAllTodos(calendar: any, filterOpen: boolean): Promise<any> {
private static async _getAllTodos(
calendar: Calendar,
filterOpen: boolean,
): Promise<CalDavTaskData[]> {
const query = {
name: [NS.IETF_CALDAV, 'comp-filter'],
attributes: [['name', 'VCALENDAR']],
@ -83,7 +93,10 @@ export class CaldavClientService {
return await calendar.calendarQuery([query]);
}
private static async _findTaskByUid(calendar: any, taskUid: string): Promise<any> {
private static async _findTaskByUid(
calendar: Calendar,
taskUid: string,
): Promise<CalDavTaskData[]> {
const query = {
name: [NS.IETF_CALDAV, 'comp-filter'],
attributes: [['name', 'VCALENDAR']],
@ -109,7 +122,7 @@ export class CaldavClientService {
return await calendar.calendarQuery([query]);
}
private static _mapTask(task: any): CaldavIssue {
private static _mapTask(task: CalDavTaskData): CaldavIssue {
const jCal = ICAL.parse(task.data);
const comp = new ICAL.Component(jCal);
const todo = comp.getFirstSubcomponent('vtodo');
@ -174,7 +187,7 @@ export class CaldavClientService {
await client
.connect({ enableCalDAV: true })
.catch((err: any) => this._handleNetErr(err));
.catch((err) => this._handleNetErr(err));
const cache = {
client,
@ -186,7 +199,7 @@ export class CaldavClientService {
}
}
async _getCalendar(cfg: CaldavCfg): Promise<any> {
async _getCalendar(cfg: CaldavCfg): Promise<Calendar> {
const clientCache = await this._get_client(cfg);
const resource = cfg.resourceName as string;
@ -196,7 +209,7 @@ export class CaldavClientService {
const calendars = await clientCache.client.calendarHomes[0]
.findAllCalendars()
.catch((err: any) => this._handleNetErr(err));
.catch((err) => this._handleNetErr(err));
const calendar = calendars.find(
(item: Calendar) =>
@ -267,7 +280,7 @@ export class CaldavClientService {
issueId: string,
completed: boolean,
summary: string,
): Observable<any> {
): Observable<void> {
return from(
this._updateTask(caldavCfg, issueId, { completed: completed, summary: summary }),
).pipe(
@ -275,7 +288,7 @@ export class CaldavClientService {
);
}
private _getXhrProvider(cfg: CaldavCfg): any {
private _getXhrProvider(cfg: CaldavCfg): () => XMLHttpRequest {
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
function xhrProvider(): XMLHttpRequest {
const xhr = new XMLHttpRequest();
@ -301,7 +314,7 @@ export class CaldavClientService {
return xhrProvider;
}
private _handleNetErr(err: any): void {
private _handleNetErr(err: unknown): never {
this._snackService.open({
type: 'ERROR',
msg: T.F.ISSUE.S.ERR_NETWORK,
@ -331,11 +344,11 @@ export class CaldavClientService {
filterCategory: boolean,
): Promise<CaldavIssue[]> {
const cal = await this._getCalendar(cfg);
const tasks = await CaldavClientService._getAllTodos(cal, filterOpen).catch(
(err: any) => this._handleNetErr(err),
const tasks = await CaldavClientService._getAllTodos(cal, filterOpen).catch((err) =>
this._handleNetErr(err),
);
return tasks
.map((t: any) => CaldavClientService._mapTask(t))
.map((t) => CaldavClientService._mapTask(t))
.filter(
(t: CaldavIssue) =>
!filterCategory || !cfg.categoryFilter || t.labels.includes(cfg.categoryFilter),
@ -344,7 +357,7 @@ export class CaldavClientService {
private async _getTask(cfg: CaldavCfg, uid: string): Promise<CaldavIssue> {
const cal = await this._getCalendar(cfg);
const task = await CaldavClientService._findTaskByUid(cal, uid).catch((err: any) =>
const task = await CaldavClientService._findTaskByUid(cal, uid).catch((err) =>
this._handleNetErr(err),
);
@ -363,7 +376,7 @@ export class CaldavClientService {
cfg: CaldavCfg,
uid: string,
updates: { completed: boolean; summary: string },
): Promise<any> {
): Promise<void> {
const cal = await this._getCalendar(cfg);
if (cal.readOnly) {
@ -377,7 +390,7 @@ export class CaldavClientService {
throw new Error('CALENDAR READ ONLY: ' + cfg.resourceName);
}
const tasks = await CaldavClientService._findTaskByUid(cal, uid).catch((err: any) =>
const tasks = await CaldavClientService._findTaskByUid(cal, uid).catch((err) =>
this._handleNetErr(err),
);
@ -436,6 +449,8 @@ export class CaldavClientService {
todo.updatePropertyWithValue('sequence', sequenceInt);
task.data = ICAL.stringify(jCal);
await task.update().catch((err: any) => this._handleNetErr(err));
if (task.update) {
await task.update().catch((err) => this._handleNetErr(err));
}
}
}

View file

@ -82,7 +82,7 @@ export class CalendarCommonInterfacesService implements IssueServiceInterface {
async getFreshDataForIssueTask(task: Task): Promise<{
taskChanges: Partial<Task>;
issue: any;
issue: IssueData;
issueTitle: string;
} | null> {
return null;
@ -92,7 +92,7 @@ export class CalendarCommonInterfacesService implements IssueServiceInterface {
{
task: Readonly<Task>;
taskChanges: Partial<Readonly<Task>>;
issue: any;
issue: IssueData;
}[]
> {
return [];

View file

@ -113,9 +113,9 @@ export class GithubApiService {
}
getImportToBacklogIssuesFromGraphQL(cfg: GithubCfg): Observable<GithubIssueReduced[]> {
const split: any = cfg.repo?.split('/');
const owner = encodeURIComponent(split[0]);
const repo = encodeURIComponent(split[1]);
const split = cfg.repo?.split('/') || [];
const owner = encodeURIComponent(split[0] || '');
const repo = encodeURIComponent(split[1] || '');
const assigneeFilter = cfg.backlogQuery
? `, assignee: "${cfg.filterUsernameForIssueUpdates}"`
: '';
@ -210,7 +210,9 @@ query Issues {
return this._http.request(req).pipe(
// Filter out HttpEventType.Sent (type: 0) events to only process actual responses
filter((res) => !(res === Object(res) && res.type === 0)),
map((res: any) => (res && res.body ? res.body : res)),
map((res) =>
res && (res as { body?: unknown }).body ? (res as { body: unknown }).body : res,
),
catchError(this._handleRequestError$.bind(this)),
);
}

View file

@ -258,7 +258,7 @@ export class ReminderService {
this._w.postMessage(reminders);
}
private _handleError(err: any): void {
private _handleError(err: unknown): void {
Log.err(err);
this._snackService.open({ type: 'ERROR', msg: T.F.REMINDER.S_REMINDER_ERR });
}

View file

@ -1,5 +1,6 @@
import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { addNewTagsFromShortSyntax } from './task.actions';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import {
@ -16,7 +17,7 @@ import { TaskReminderOptionId } from '../task.model';
import { GlobalConfigService } from '../../config/global-config.service';
import { unique } from '../../../util/unique';
import { TaskService } from '../task.service';
import { EMPTY, Observable, of } from 'rxjs';
import { EMPTY, of } from 'rxjs';
import { ProjectService } from '../../project/project.service';
import { TagService } from '../../tag/tag.service';
import { shortSyntax } from '../short-syntax';
@ -48,7 +49,7 @@ export class ShortSyntaxEffects {
private _layoutService = inject(LayoutService);
private _workContextService = inject(WorkContextService);
shortSyntax$: any = createEffect(() =>
shortSyntax$ = createEffect(() =>
this._actions$.pipe(
ofType(TaskSharedActions.addTask, TaskSharedActions.updateTask),
filter((action): boolean => {
@ -63,7 +64,7 @@ export class ShortSyntaxEffects {
return changeProps.length === 1 && changeProps[0] === 'title';
}),
// dirty fix to execute this after setDefaultProjectId$ effect
concatMap((originalAction): Observable<any> => {
concatMap((originalAction) => {
return this._taskService.getByIdOnce$(originalAction.task.id as string).pipe(
map((task) => ({
task,
@ -123,7 +124,7 @@ export class ShortSyntaxEffects {
if (isAddDefaultProjectIfNecessary) {
return [
TaskSharedActions.moveToOtherProject({
task,
task: { ...task, subTasks: [] },
targetProjectId: defaultProjectId as string,
}),
];
@ -131,7 +132,7 @@ export class ShortSyntaxEffects {
return EMPTY;
}
const actions: any[] = [];
const actions: Action[] = [];
const tagIds: string[] = [...(r.taskChanges.tagIds || task.tagIds)];
const { taskChanges } = r;
@ -176,7 +177,7 @@ export class ShortSyntaxEffects {
} else {
actions.push(
TaskSharedActions.moveToOtherProject({
task,
task: { ...task, subTasks: [] },
targetProjectId: r.projectId,
}),
);
@ -184,7 +185,7 @@ export class ShortSyntaxEffects {
} else if (isAddDefaultProjectIfNecessary) {
actions.push(
TaskSharedActions.moveToOtherProject({
task,
task: { ...task, subTasks: [] },
targetProjectId: defaultProjectId as string,
}),
);
@ -220,7 +221,7 @@ export class ShortSyntaxEffects {
),
);
shortSyntaxAddNewTags$: any = createEffect(() =>
shortSyntaxAddNewTags$ = createEffect(() =>
this._actions$.pipe(
ofType(addNewTagsFromShortSyntax),
// needed cause otherwise task gets the focus after blur & hide
@ -252,7 +253,7 @@ export class ShortSyntaxEffects {
// NOTE: it is important to get a fresh task here, since otherwise we might run into #3728
withLatestFrom(this._taskService.getByIdOnce$(taskId)),
mergeMap(([isConfirm, task]) => {
const actions: any[] = [];
const actions: Action[] = [];
if (isConfirm) {
const newTagIds = [...task.tagIds];
uniqueNewTitles.forEach((newTagTitle) => {

View file

@ -72,7 +72,7 @@ export class TaskElectronEffects {
});
}
taskChangeElectron$: any = createEffect(
taskChangeElectron$ = createEffect(
() =>
this._actions$.pipe(
ofType(
@ -133,7 +133,7 @@ export class TaskElectronEffects {
{ dispatch: false },
);
setTaskBarProgress$: any = createEffect(
setTaskBarProgress$ = createEffect(
() =>
this._actions$.pipe(
ofType(TimeTrackingActions.addTimeSpent),

View file

@ -25,10 +25,10 @@ import {
@Injectable()
export class TaskInternalEffects {
private _actions$ = inject(Actions);
private _store$ = inject<Store<any>>(Store);
private _store$ = inject(Store);
private _workContextSession = inject(WorkContextService);
onAllSubTasksDone$: any = createEffect(() =>
onAllSubTasksDone$ = createEffect(() =>
this._actions$.pipe(
ofType(TaskSharedActions.updateTask),
withLatestFrom(
@ -65,7 +65,7 @@ export class TaskInternalEffects {
),
);
setDefaultEstimateIfNonGiven$: any = createEffect(() =>
setDefaultEstimateIfNonGiven$ = createEffect(() =>
this._actions$.pipe(
ofType(TaskSharedActions.addTask, addSubTask),
filter(({ task }) => !task.timeEstimate),
@ -91,7 +91,7 @@ export class TaskInternalEffects {
),
);
autoSetNextTask$: any = createEffect(() =>
autoSetNextTask$ = createEffect(() =>
this._actions$.pipe(
ofType(
toggleStart,

View file

@ -24,7 +24,7 @@ export class TaskRelatedModelEffects {
// EFFECTS ===> EXTERNAL
// ---------------------
restoreTask$: any = createEffect(
restoreTask$ = createEffect(
() =>
this._actions$.pipe(
ofType(TaskSharedActions.restoreTask),
@ -38,7 +38,7 @@ export class TaskRelatedModelEffects {
switchMap((misc) => (misc.isAutoAddWorkedOnToToday ? obs : EMPTY)),
);
autoAddTodayTagOnTracking: any = createEffect(() =>
autoAddTodayTagOnTracking = createEffect(() =>
this.ifAutoAddTodayEnabled$(
this._actions$.pipe(
ofType(TimeTrackingActions.addTimeSpent),

View file

@ -45,7 +45,7 @@ export class TaskUiEffects {
private _globalConfigService = inject(GlobalConfigService);
private _workContextService = inject(WorkContextService);
taskCreatedSnack$: any = createEffect(
taskCreatedSnack$ = createEffect(
() =>
this._actions$.pipe(
ofType(TaskSharedActions.addTask),
@ -63,7 +63,7 @@ export class TaskUiEffects {
{ dispatch: false },
);
snackDelete$: any = createEffect(
snackDelete$ = createEffect(
() =>
this._actions$.pipe(
ofType(TaskSharedActions.deleteTask),
@ -82,7 +82,7 @@ export class TaskUiEffects {
{ dispatch: false },
);
timeEstimateExceeded$: any = createEffect(
timeEstimateExceeded$ = createEffect(
() =>
this._store$.pipe(select(selectConfigFeatureState)).pipe(
switchMap((globalCfg) =>
@ -113,7 +113,7 @@ export class TaskUiEffects {
{ dispatch: false },
);
timeEstimateExceededDismissBanner$: any = createEffect(
timeEstimateExceededDismissBanner$ = createEffect(
() =>
this._store$.pipe(select(selectConfigFeatureState)).pipe(
switchMap((globalCfg) =>
@ -138,7 +138,7 @@ export class TaskUiEffects {
{ dispatch: false },
);
taskDoneSound$: any = createEffect(
taskDoneSound$ = createEffect(
() =>
this._actions$.pipe(
ofType(TaskSharedActions.updateTask),

View file

@ -624,7 +624,7 @@ export class WorkContextService {
private _updateAdvancedCfgForCurrentContext(
sectionKey: WorkContextAdvancedCfgKey,
data: any,
data: unknown,
): void {
if (this.activeWorkContextType === WorkContextType.PROJECT) {
this._store$.dispatch(

View file

@ -162,7 +162,7 @@ export class SyncWrapperService {
return r.status;
}
} catch (error: any) {
} catch (error) {
SyncLog.err(error);
if (error instanceof PotentialCorsError) {
@ -236,7 +236,9 @@ export class SyncWrapperService {
} else if (error instanceof CanNotMigrateMajorDownError) {
alert(this._translateService.instant(T.F.SYNC.A.REMOTE_MODEL_VERSION_NEWER));
return 'HANDLED_ERROR';
} else if (error?.message === 'Sync already in progress') {
} else if (
(error as { message?: string })?.message === 'Sync already in progress'
) {
// Silently ignore concurrent sync attempts
SyncLog.log('Sync already in progress, skipping concurrent sync attempt');
return 'HANDLED_ERROR';

View file

@ -44,7 +44,7 @@ export class SyncEffects {
private _execBeforeCloseService = inject(ExecBeforeCloseService);
private readonly _initialPwaUpdateCheckService = inject(InitialPwaUpdateCheckService);
syncBeforeQuit$: any = createEffect(
syncBeforeQuit$ = createEffect(
() =>
!IS_ELECTRON
? EMPTY
@ -97,7 +97,7 @@ export class SyncEffects {
shareReplay(),
);
triggerSync$: any = createEffect(
triggerSync$ = createEffect(
() =>
this._dataInitStateService.isAllDataLoadedInitially$.pipe(
switchMap(() =>

View file

@ -137,8 +137,8 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
startWith({
params: { dayStr: this._dateService.todayStr() },
}),
map((s: any) => {
if (s && s.params.dayStr) {
map((s) => {
if (s && 'params' in s && s.params.dayStr) {
return s.params.dayStr;
} else {
return this._dateService.todayStr();
@ -275,10 +275,11 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
this._activatedRoute.paramMap
.pipe(takeUntil(this._onDestroy$))
.subscribe((s: any) => {
if (s && s.params.dayStr) {
.subscribe((params) => {
const dayStr = params.get('dayStr');
if (dayStr) {
this.isForToday = false;
this.dayStr = s.params.dayStr;
this.dayStr = dayStr;
}
});
}
@ -390,7 +391,7 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
Log.log('[DailySummary] Archive operation completed');
}
private async _finishDayForGood(cb?: any): Promise<void> {
private async _finishDayForGood(cb?: () => void): Promise<void> {
const cfg = this.configService.cfg();
const syncCfg = cfg?.sync;
if (syncCfg?.isEnabled) {
@ -399,7 +400,7 @@ export class DailySummaryComponent implements OnInit, OnDestroy, AfterViewInit {
this._initSuccessAnimation(cb);
}
private _initSuccessAnimation(cb?: any): void {
private _initSuccessAnimation(cb?: () => void): void {
this.showSuccessAnimation = true;
this._cd.detectChanges();
this._successAnimationTimeout = window.setTimeout(() => {

View file

@ -1,15 +1,17 @@
import { RootState } from '../root-state';
import { actionLogger } from '../../util/action-logger';
import { ActionReducer } from '@ngrx/store/src/models';
import { ActionReducer, Action } from '@ngrx/store';
import { Log } from '../../core/log';
export const actionLoggerReducer = (
reducer: ActionReducer<any, any>,
): ActionReducer<any, any> => {
return (state: RootState, action: any) => {
export const actionLoggerReducer = <S, A extends Action = Action>(
reducer: ActionReducer<S, A>,
): ActionReducer<S, A> => {
return (state: S | undefined, action: A) => {
// if (environment.production) {
Log.verbose('[a]' + action.type, (action as any)?.payload || action);
actionLogger(action);
Log.verbose(
'[a]' + action.type,
(action as Action & { payload?: unknown })?.payload || action,
);
actionLogger(action as unknown as { type: string; [key: string]: unknown });
return reducer(state, action);
};
};

View file

@ -128,7 +128,7 @@ export class SaveToDbEffects {
[TimeTrackingActions.addTimeSpent.type],
);
updateTimeTrackingStorageAuditTime$: any = createEffect(
updateTimeTrackingStorageAuditTime$ = createEffect(
() =>
this._actions.pipe(
ofType(TimeTrackingActions.addTimeSpent),

View file

@ -56,7 +56,7 @@ export class FormlyImageInputComponent extends FieldType<FormlyFieldConfig> {
data: dialogData,
});
dialogRef.afterClosed().subscribe((result: any) => {
dialogRef.afterClosed().subscribe((result: string | { url: string } | null) => {
if (result) {
// Handle both string (legacy) and object (new) return formats
const url = typeof result === 'string' ? result : result.url;

View file

@ -6,7 +6,7 @@ import { IS_IOS } from '../../util/is-ios';
export class LongPressIOSDirective implements OnDestroy {
readonly longPressIOS = output<MouseEvent | TouchEvent>();
private longPressTimeout: any;
private longPressTimeout: number | undefined;
constructor() {
const el = inject(ElementRef);

View file

@ -5,7 +5,7 @@ import { UI_LONG_PRESS_DURATION } from '../ui.const';
export class LongPressDirective implements OnDestroy {
readonly longPress = output<MouseEvent | TouchEvent>();
private longPressTimeout: any;
private longPressTimeout: number | undefined;
@HostListener('touchstart', ['$event'])
@HostListener('mousedown', ['$event'])