refactor: replace console.* with Log methods throughout codebase

- Created migration script to replace console.log/info/error/warn/debug with Log methods
- Replaced 584 console calls across 89 files:
  - console.log → Log.log (385 occurrences)
  - console.info → Log.info (4 occurrences)
  - console.error → Log.err (107 occurrences)
  - console.warn → Log.err (87 occurrences)
  - console.debug → Log.debug (1 occurrence)
- Added appropriate import statements for Log
- Removed unused Log imports from files with only commented-out usage
- Fixed all linting errors

All logging now goes through our centralized Log class which:
- Records logs to history for export/download
- Provides consistent log level filtering
- Supports context-aware logging
- Trade-off: Line numbers show log.ts instead of actual location
This commit is contained in:
Johannes Millan 2025-07-10 14:15:56 +02:00
parent f9902d59e4
commit 97f96f2393
103 changed files with 860 additions and 566 deletions

171
scripts/migrate-console-to-log.ts Executable file
View file

@ -0,0 +1,171 @@
#!/usr/bin/env ts-node
import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
interface Replacement {
pattern: RegExp;
replacement: string;
logMethod: string;
}
const replacements: Replacement[] = [
{ pattern: /console\.log\(/g, replacement: 'Log.log(', logMethod: 'log' },
{ pattern: /console\.info\(/g, replacement: 'Log.info(', logMethod: 'info' },
{ pattern: /console\.error\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /console\.warn\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /console\.debug\(/g, replacement: 'Log.debug(', logMethod: 'debug' },
];
// Files to exclude
const excludePatterns = [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/*.spec.ts',
'**/core/log.ts',
'**/scripts/migrate-console-to-log.ts',
'**/e2e/**',
'**/coverage/**',
'**/.angular/**',
];
function calculateImportPath(filePath: string): string {
const fileDir = path.dirname(filePath);
const logPath = path.join(__dirname, '../src/app/core/log');
let relativePath = path.relative(fileDir, logPath).replace(/\\/g, '/');
// Remove .ts extension if present
relativePath = relativePath.replace(/\.ts$/, '');
// Ensure it starts with ./ or ../
if (!relativePath.startsWith('.')) {
relativePath = './' + relativePath;
}
return relativePath;
}
function hasLogImport(content: string): boolean {
return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"].*\/log['"]/.test(content);
}
function addLogImport(content: string, importPath: string): string {
// Find the last import statement
const importRegex = /^import\s+.*?;$/gm;
const imports = content.match(importRegex);
if (imports && imports.length > 0) {
const lastImport = imports[imports.length - 1];
const lastImportIndex = content.lastIndexOf(lastImport);
const insertPosition = lastImportIndex + lastImport.length;
return (
content.slice(0, insertPosition) +
`\nimport { Log } from '${importPath}';` +
content.slice(insertPosition)
);
} else {
// No imports found, add at the beginning
return `import { Log } from '${importPath}';\n\n` + content;
}
}
function processFile(filePath: string): boolean {
try {
let content = fs.readFileSync(filePath, 'utf8');
const originalContent = content;
let hasChanges = false;
// Check if file uses any console methods
const usesConsole = replacements.some((r) => r.pattern.test(content));
if (!usesConsole) {
return false;
}
// Apply replacements
for (const { pattern, replacement } of replacements) {
if (pattern.test(content)) {
content = content.replace(pattern, replacement);
hasChanges = true;
}
}
if (hasChanges && !hasLogImport(content)) {
const importPath = calculateImportPath(filePath);
content = addLogImport(content, importPath);
}
if (content !== originalContent) {
fs.writeFileSync(filePath, content, 'utf8');
return true;
}
return false;
} catch (error) {
console.error(`Error processing ${filePath}:`, error);
return false;
}
}
function main() {
console.log('Starting console to Log migration...\n');
// Find all TypeScript files
const files = glob.sync('src/**/*.ts', {
ignore: excludePatterns,
absolute: true,
});
console.log(`Found ${files.length} TypeScript files to check\n`);
const modifiedFiles: string[] = [];
const stats = {
total: 0,
log: 0,
info: 0,
error: 0,
warn: 0,
debug: 0,
};
for (const file of files) {
const content = fs.readFileSync(file, 'utf8');
// Count occurrences before processing
stats.log += (content.match(/console\.log\(/g) || []).length;
stats.info += (content.match(/console\.info\(/g) || []).length;
stats.error += (content.match(/console\.error\(/g) || []).length;
stats.warn += (content.match(/console\.warn\(/g) || []).length;
stats.debug += (content.match(/console\.debug\(/g) || []).length;
if (processFile(file)) {
modifiedFiles.push(file);
}
}
stats.total = stats.log + stats.info + stats.error + stats.warn + stats.debug;
console.log('Migration complete!\n');
console.log('Statistics:');
console.log(` Total console calls found: ${stats.total}`);
console.log(` - console.log: ${stats.log}`);
console.log(` - console.info: ${stats.info}`);
console.log(` - console.error: ${stats.error}`);
console.log(` - console.warn: ${stats.warn}`);
console.log(` - console.debug: ${stats.debug}`);
console.log(`\nModified ${modifiedFiles.length} files:`);
modifiedFiles.forEach((file) => {
console.log(` - ${path.relative(process.cwd(), file)}`);
});
if (modifiedFiles.length === 0) {
console.log(' No files needed modification.');
}
}
// Run the migration
main();

View file

@ -0,0 +1,72 @@
#!/usr/bin/env ts-node
import * as fs from 'fs';
import * as path from 'path';
const filesToFix = [
'src/app/features/calendar-integration/is-calender-event-due.ts',
'src/app/features/schedule/map-schedule-data/create-sorted-blocker-blocks.ts',
'src/app/features/schedule/map-schedule-data/create-view-entries-for-day.ts',
'src/app/features/tasks/short-syntax.ts',
'src/app/features/tasks/task-detail-panel/task-detail-panel.component.ts',
'src/app/imex/sync/sync-trigger.service.ts',
'src/app/pfapi/api/encryption/encryption.ts',
'src/app/ui/stuck/stuck.directive.ts',
];
function removeUnusedLogImport(filePath: string): void {
try {
const fullPath = path.join(process.cwd(), filePath);
let content = fs.readFileSync(fullPath, 'utf8');
// Check if Log is actually used in the file (excluding import statement and comments)
const importRegex = /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"][^'"]+['"]/g;
let contentWithoutImports = content.replace(importRegex, '');
// Remove single line comments
contentWithoutImports = contentWithoutImports.replace(/\/\/.*$/gm, '');
// Remove multi-line comments
contentWithoutImports = contentWithoutImports.replace(/\/\*[\s\S]*?\*\//g, '');
const isLogUsed = /\bLog\./g.test(contentWithoutImports);
if (!isLogUsed) {
// Remove Log from imports
content = content.replace(
/import\s+{([^}]*)\bLog\b([^}]*)}\s+from\s+(['"][^'"]+['"])/g,
(match, before, after, path) => {
// Clean up the remaining imports
const remainingImports = (before + after)
.split(',')
.map((s) => s.trim())
.filter((s) => s && s !== 'Log')
.join(', ');
if (remainingImports) {
return `import { ${remainingImports} } from ${path}`;
} else {
// If Log was the only import, remove the entire import line
return '';
}
},
);
// Clean up any empty lines left by removed imports
content = content.replace(/^\s*;\s*$/gm, ''); // Remove standalone semicolons
content = content.replace(/\n\n+/g, '\n\n'); // Replace multiple newlines with double newline
fs.writeFileSync(fullPath, content, 'utf8');
console.log(`Fixed: ${filePath}`);
} else {
console.log(`Skipped (Log is used): ${filePath}`);
}
} catch (error) {
console.error(`Error processing ${filePath}:`, error);
}
}
console.log('Removing unused Log imports...\n');
filesToFix.forEach(removeUnusedLogImport);
console.log('\nDone!');

View file

@ -70,6 +70,7 @@ import { MarkdownPasteService } from './features/tasks/markdown-paste.service';
import { TaskService } from './features/tasks/task.service';
import { IpcRendererEvent } from 'electron';
import { SyncSafetyBackupService } from './imex/sync/sync-safety-backup.service';
import { Log } from './core/log';
const w = window as any;
const productivityTip: string[] = w.productivityTips && w.productivityTips[w.randomIndex];
@ -224,9 +225,9 @@ export class AppComponent implements OnDestroy {
// Initialize plugin system
try {
await this._pluginService.initializePlugins();
console.log('Plugin system initialized');
Log.log('Plugin system initialized');
} catch (error) {
console.error('Failed to initialize plugin system:', error);
Log.err('Failed to initialize plugin system:', error);
}
}, 1000);
@ -248,7 +249,7 @@ export class AppComponent implements OnDestroy {
msg: errMsg,
type: 'ERROR',
});
console.error(data);
Log.err(data);
});
});
@ -414,7 +415,7 @@ export class AppComponent implements OnDestroy {
this.imexMetaService.setDataImportInProgress(true);
const legacyData = await this._persistenceLegacyService.loadComplete();
console.log({ legacyData: legacyData });
Log.log({ legacyData: legacyData });
alert(this._translateService.instant(T.MIGRATE.DETECTED_LEGACY));
@ -449,7 +450,7 @@ export class AppComponent implements OnDestroy {
} catch (error) {
// prevent any interaction with the app on after failure
this.imexMetaService.setDataImportInProgress(true);
console.error(error);
Log.err(error);
try {
alert(
@ -537,21 +538,21 @@ export class AppComponent implements OnDestroy {
if (!persisted) {
return navigator.storage.persist().then((granted) => {
if (granted) {
console.log('Persistent store granted');
Log.log('Persistent store granted');
}
// NOTE: we never execute for android web view, because it is always true
else if (!IS_ANDROID_WEB_VIEW) {
const msg = T.GLOBAL_SNACK.PERSISTENCE_DISALLOWED;
console.warn('Persistence not allowed');
Log.err('Persistence not allowed');
this._snackService.open({ msg });
}
});
} else {
console.log('Persistence already allowed');
Log.log('Persistence already allowed');
}
})
.catch((e) => {
console.log(e);
Log.log(e);
const err = e && e.toString ? e.toString() : 'UNKNOWN';
const msg = T.GLOBAL_SNACK.PERSISTENCE_ERROR;
this._snackService.open({
@ -576,7 +577,7 @@ export class AppComponent implements OnDestroy {
const usageInMib = Math.round(u / (1024 * 1024));
const quotaInMib = Math.round(q / (1024 * 1024));
const details = `${usageInMib} out of ${quotaInMib} MiB used (${percentUsed}%)`;
console.log(details);
Log.log(details);
if (quotaInMib - usageInMib <= 333) {
alert(
`There is only very little disk space available (${

View file

@ -11,6 +11,7 @@ import { saveBeforeLastErrorActionLog } from '../../util/action-logger';
import { error } from 'electron-log/renderer';
import { PfapiService } from '../../pfapi/pfapi.service';
import { CompleteBackup } from '../../pfapi/api';
import { Log } from '../log';
let isErrorAlertShown = false;
@ -23,7 +24,7 @@ export class GlobalErrorHandler implements ErrorHandler {
const errStr = typeof err === 'string' ? err : err.toString();
// eslint-disable-next-line
const simpleStack = err && err.stack;
console.error('GLOBAL_ERROR_HANDLER', err);
Log.err('GLOBAL_ERROR_HANDLER', err);
// if not our custom error handler we have a critical error on our hands
if (!isHandledError(err) && !isErrorAlertShown) {
@ -67,8 +68,8 @@ export class GlobalErrorHandler implements ErrorHandler {
try {
return await this.injector.get(PfapiService).pf.loadCompleteBackup(true);
} catch (e) {
console.warn('Cannot load user data for error modal');
console.error(e);
Log.err('Cannot load user data for error modal');
Log.err(e);
return undefined;
}
}

View file

@ -6,6 +6,7 @@ import { download } 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;
@ -48,7 +49,7 @@ const _getStacktrace = async (err: Error | any): Promise<string> => {
.join('\n');
});
} else if (!isHandledError(err)) {
console.warn('Error without stack', err);
Log.err('Error without stack', err);
}
return Promise.resolve('');
};
@ -74,7 +75,7 @@ export const logAdvancedStacktrace = (
}
const githubIssueLinks = document.getElementsByClassName('github-issue-urlX');
console.log(githubIssueLinks);
Log.log(githubIssueLinks);
if (githubIssueLinks) {
const errEscaped = _cleanHtml(origErr as string);
@ -144,7 +145,7 @@ export const createErrorAlert = (
});
innerWrapper.append(btnReload);
console.log(userData);
Log.log(userData);
if (userData) {
const btnExport = document.createElement('BUTTON');

View file

@ -11,6 +11,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { GlobalConfigService } from 'src/app/features/config/global-config.service';
import { map, startWith } from 'rxjs/operators';
import { DEFAULT_GLOBAL_CONFIG } from 'src/app/features/config/default-global-config.const';
import { Log } from '../log';
@Injectable({ providedIn: 'root' })
export class LanguageService {
@ -36,7 +37,7 @@ export class LanguageService {
if (lng) {
console.error('Invalid language code', lng);
} else {
console.warn('No language code provided');
Log.err('No language code provided');
}
this.setFromBrowserLngIfAutoSwitchLng();
}

View file

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { androidInterface } from '../../features/android/android-interface';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -15,7 +16,7 @@ export class AndroidDbAdapterService {
async load(key: string): Promise<unknown> {
const data = await androidInterface.loadFromDbWrapped(key);
console.log('load', key, data);
Log.log('load', key, data);
return typeof data === 'string'
? JSON.parse((data as string).replace(/\n/g, '\\n'))
@ -23,7 +24,7 @@ export class AndroidDbAdapterService {
}
async save(key: string, data: unknown): Promise<unknown> {
console.log('save', key, data);
Log.log('save', key, data);
return await androidInterface.saveToDbWrapped(key, JSON.stringify(data));
}

View file

@ -6,6 +6,7 @@ import { T } from '../../t.const';
import { IndexedDBAdapterService } from './indexed-db-adapter.service';
import { DBAdapter } from './db-adapter.model';
import { AndroidDbAdapterService } from './android-db-adapter.service';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -32,7 +33,7 @@ export class DatabaseService {
try {
return await this._adapter.load(key);
} catch (e) {
console.warn('DB Load Error: Last Params,', this._lastParams);
Log.err('DB Load Error: Last Params,', this._lastParams);
return this._errorHandler(e, this.load, [key]);
}
}
@ -44,7 +45,7 @@ export class DatabaseService {
try {
return await this._adapter.save(key, data);
} catch (e) {
console.warn('DB Save Error: Last Params,', this._lastParams);
Log.err('DB Save Error: Last Params,', this._lastParams);
return this._errorHandler(e, this.save, [key, data]);
}
}
@ -54,7 +55,7 @@ export class DatabaseService {
try {
return await this._adapter.remove(key);
} catch (e) {
console.warn('DB Remove Error: Last Params,', this._lastParams);
Log.err('DB Remove Error: Last Params,', this._lastParams);
return this._errorHandler(e, this.remove, [key]);
}
}
@ -64,7 +65,7 @@ export class DatabaseService {
try {
return await this._adapter.clearDatabase();
} catch (e) {
console.warn('DB Clear Error: Last Params,', this._lastParams);
Log.err('DB Clear Error: Last Params,', this._lastParams);
return this._errorHandler(e, this.clearDatabase, []);
}
}
@ -73,9 +74,9 @@ export class DatabaseService {
try {
await this._adapter.init();
} catch (e) {
console.error('Database initialization failed');
console.error('_lastParams', this._lastParams);
console.error(e);
Log.err('Database initialization failed');
Log.err('_lastParams', this._lastParams);
Log.err(e);
alert('DB INIT Error');
throw new Error(e as any);
}

View file

@ -4,6 +4,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { filter, shareReplay, take } from 'rxjs/operators';
import { DBSchema, openDB } from 'idb';
import { DBAdapter } from './db-adapter.model';
import { Log } from '../log';
const DB_NAME = 'SUP';
const DB_MAIN_NAME = 'SUP_STORE';
@ -70,23 +71,20 @@ export class IndexedDBAdapterService implements DBAdapter {
const result = await (this._db as IDBPDatabase<MyDb>).get(DB_MAIN_NAME, key);
return result;
} catch (e) {
console.error(
`[IndexedDB] Error loading key "${key}" from store "${DB_MAIN_NAME}":`,
e,
);
Log.err(`[IndexedDB] Error loading key "${key}" from store "${DB_MAIN_NAME}":`, e);
if (e instanceof Error) {
console.error('[IndexedDB] Error name:', e.name);
console.error('[IndexedDB] Error message:', e.message);
Log.err('[IndexedDB] Error name:', e.name);
Log.err('[IndexedDB] Error message:', e.message);
// Log specific details for the large value error
if (e.message && e.message.includes('Failed to read large IndexedDB value')) {
console.error('[IndexedDB] CRITICAL: Large value read failure detected');
console.error(
Log.err('[IndexedDB] CRITICAL: Large value read failure detected');
Log.err(
'[IndexedDB] This indicates IndexedDB blob files are missing or corrupted',
);
console.error('[IndexedDB] Affected store:', DB_MAIN_NAME);
console.error('[IndexedDB] Affected key:', key);
Log.err('[IndexedDB] Affected store:', DB_MAIN_NAME);
Log.err('[IndexedDB] Affected key:', key);
}
}
@ -100,10 +98,7 @@ export class IndexedDBAdapterService implements DBAdapter {
try {
return await (this._db as IDBPDatabase<MyDb>).put(DB_MAIN_NAME, data, key);
} catch (e) {
console.error(
`[IndexedDB] Error saving key "${key}" to store "${DB_MAIN_NAME}":`,
e,
);
Log.err(`[IndexedDB] Error saving key "${key}" to store "${DB_MAIN_NAME}":`, e);
throw e;
}
}
@ -122,7 +117,7 @@ export class IndexedDBAdapterService implements DBAdapter {
try {
return await this._afterReady$.pipe(take(1)).toPromise();
} catch (e) {
console.warn('DB After Ready Error: Last Params');
Log.err('DB After Ready Error: Last Params');
throw new Error(e as string);
}
}

View file

@ -5,6 +5,7 @@ import { LocalSyncMetaForProvider, LocalSyncMetaModel } from '../../imex/sync/sy
import { LegacySyncProvider } from 'src/app/imex/sync/legacy-sync-provider.model';
import { environment } from 'src/environments/environment';
import { BehaviorSubject } from 'rxjs';
import { Log } from '../log';
const DEFAULT_LOCAL_SYNC_META: LocalSyncMetaModel = {
[LegacySyncProvider.Dropbox]: {
@ -46,7 +47,7 @@ export class PersistenceLocalService {
r[LegacySyncProvider.LocalFile]
) {
if (environment.production) {
console.log(r);
Log.log(r);
}
return r;
}
@ -82,7 +83,7 @@ export class PersistenceLocalService {
}
async updateLastSyncModelChange(lastSyncModelChange: number): Promise<unknown> {
console.log(lastSyncModelChange);
Log.log(lastSyncModelChange);
console.trace();
this.lastSnyModelChange$.next(lastSyncModelChange);
return await this._databaseService.save(

View file

@ -29,6 +29,7 @@ import { androidInterface } from '../../features/android/android-interface';
import { HttpClient } from '@angular/common/http';
import { LS } from '../persistence/storage-keys.const';
import { CustomThemeService } from './custom-theme.service';
import { Log } from '../log';
export type DarkModeCfg = 'dark' | 'light' | 'system';
@ -176,7 +177,7 @@ export class GlobalThemeService {
);
})
.catch((error) => {
console.error(`Error loading icon: ${iconName} from ${url}`, error);
Log.err(`Error loading icon: ${iconName} from ${url}`, error);
});
});

View file

@ -2,6 +2,7 @@ import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view';
import { nanoid } from 'nanoid';
import { BehaviorSubject, merge, Observable, Subject } from 'rxjs';
import { mapTo } from 'rxjs/operators';
import { Log } from '../../core/log';
export interface AndroidInterface {
getVersion?(): string;
@ -123,5 +124,5 @@ if (IS_ANDROID_WEB_VIEW) {
delete requestMap[rId];
};
console.log('Android Web View interfaces initialized', androidInterface);
Log.log('Android Web View interfaces initialized', androidInterface);
}

View file

@ -8,6 +8,7 @@ import { LocalNotifications } from '@capacitor/local-notifications';
import { SnackService } from '../../../core/snack/snack.service';
import { IS_ANDROID_WEB_VIEW } from '../../../util/is-android-web-view';
import { LocalNotificationSchema } from '@capacitor/local-notifications/dist/esm/definitions';
import { Log } from '../../../core/log';
// TODO send message to electron when current task changes here
@ -30,11 +31,11 @@ export class AndroidEffects {
try {
const checkResult = await LocalNotifications.checkPermissions();
if (checkResult.display === 'denied') {
console.log(await LocalNotifications.requestPermissions());
console.log(await LocalNotifications.changeExactNotificationSetting());
Log.log(await LocalNotifications.requestPermissions());
Log.log(await LocalNotifications.changeExactNotificationSetting());
}
} catch (error) {
console.error(error);
Log.err(error);
this._snackService.open({
type: 'ERROR',
msg: error?.toString() || 'Notifications not supported',
@ -58,7 +59,7 @@ export class AndroidEffects {
const checkResult = await LocalNotifications.checkPermissions();
if (checkResult.display === 'granted') {
const pendingNotifications = await LocalNotifications.getPending();
console.log({ pendingNotifications });
Log.log({ pendingNotifications });
if (pendingNotifications.notifications.length > 0) {
await LocalNotifications.cancel({
notifications: pendingNotifications.notifications.map((n) => ({
@ -90,7 +91,7 @@ export class AndroidEffects {
});
}
} catch (error) {
console.error(error);
Log.err(error);
this._snackService.open({
type: 'ERROR',
msg: error?.toString() || 'Notifications not supported',

View file

@ -35,6 +35,7 @@ import { selectCalendarProviders } from '../issue/store/issue-provider.selectors
import { IssueProviderCalendar } from '../issue/issue.model';
import { CalendarProviderCfg } from '../issue/providers/calendar/calendar.model';
import { CORS_SKIP_EXTRA_HEADERS } from '../../app.constants';
import { Log } from '../../core/log';
const ONE_MONTHS = 60 * 60 * 1000 * 24 * 31;
@ -75,7 +76,7 @@ export class CalendarIntegrationService {
.pipe(distinctUntilChanged(fastArrayCompare)),
this.skippedEventIds$.pipe(distinctUntilChanged(fastArrayCompare)),
]).pipe(
// tap((val) => console.log('selectAllCalendarTaskEventIds', val)),
// tap((val) => Log.log('selectAllCalendarTaskEventIds', val)),
map(([allCalendarTaskEventIds, skippedEventIds]) => {
return resultForProviders.map(({ itemsForProvider, calProvider }) => {
return {
@ -90,7 +91,7 @@ export class CalendarIntegrationService {
}),
),
),
// tap((v) => console.log('icalEvents$ final', v)),
// tap((v) => Log.log('icalEvents$ final', v)),
tap((val) => {
saveToRealLs(LS.CAL_EVENTS_CACHE, val);
}),
@ -104,7 +105,7 @@ export class CalendarIntegrationService {
public readonly skippedEventIds$ = new BehaviorSubject<string[]>([]);
constructor() {
// console.log(
// Log.log(
// localStorage.getItem(LS.CALENDER_EVENTS_LAST_SKIP_DAY),
// localStorage.getItem(LS.CALENDER_EVENTS_SKIPPED_TODAY),
// localStorage.getItem(LS.CAL_EVENTS_CACHE),
@ -132,7 +133,7 @@ export class CalendarIntegrationService {
.pipe(
map((v) => !!v),
catchError((err) => {
console.error(err);
Log.err(err);
return of(false);
}),
)
@ -155,7 +156,7 @@ export class CalendarIntegrationService {
end = getEndOfDayTimestamp(),
isForwardError = false,
): Observable<CalendarIntegrationEvent[]> {
// console.log('REQUEST EVENTS', calProvider, start, end);
// Log.log('REQUEST EVENTS', calProvider, start, end);
return this._http
.get(calProvider.icalUrl, {
@ -174,7 +175,7 @@ export class CalendarIntegrationService {
),
),
catchError((err) => {
console.error(err);
Log.err(err);
this._snackService.open({
type: 'ERROR',
msg: T.F.CALENDARS.S.CAL_PROVIDER_ERROR,

View file

@ -8,9 +8,9 @@ export const isCalenderEventDue = (
skippedEventIds: string[],
now: number,
): boolean => {
// console.log(calEv);
// console.log(calEv.start >= now - START_OFFSET, calEv.start, now - START_OFFSET);
// console.log(
// Log.log(calEv);
// Log.log(calEv.start >= now - START_OFFSET, calEv.start, now - START_OFFSET);
// Log.log(
// calEv.start <= now + (calProvider.showBannerBeforeThreshold || 0),
// calEv.start,
// now + (calProvider.showBannerBeforeThreshold || 0),

View file

@ -20,6 +20,7 @@ import { IssueProviderCalendar } from '../../issue/issue.model';
import { IssueService } from '../../issue/issue.service';
import { isToday } from '../../../util/is-today.util';
import { TaskService } from '../../tasks/task.service';
import { Log } from '../../../core/log';
const CHECK_TO_SHOW_INTERVAL = 60 * 1000;
@ -58,7 +59,7 @@ export class CalendarIntegrationEffects {
activatedProviders.map((calProvider) =>
timer(0, calProvider.checkUpdatesEvery).pipe(
// timer(0, 10000).pipe(
// tap(() => console.log('REQUEST CALENDAR', calProvider)),
// tap(() => Log.log('REQUEST CALENDAR', calProvider)),
switchMap(() =>
this._calendarIntegrationService.requestEvents$(calProvider),
),
@ -103,7 +104,7 @@ export class CalendarIntegrationEffects {
),
);
}),
tap((a) => console.log('_____END___', a)),
tap((a) => Log.log('_____END___', a)),
),
{ dispatch: false },
);
@ -123,11 +124,11 @@ export class CalendarIntegrationEffects {
calProvider: IssueProviderCalendar,
): void {
const curVal = this._currentlyShownBanners$.getValue();
console.log('addEvToShow', curVal, calEv);
Log.log('addEvToShow', curVal, calEv);
if (!curVal.map((val) => val.id).includes(calEv.id)) {
const newBanners = [...curVal, { id: calEv.id, calEv, calProvider }];
newBanners.sort((a, b) => a.calEv.start - b.calEv.start);
console.log('UDATE _currentlyShownBanners$');
Log.log('UDATE _currentlyShownBanners$');
this._currentlyShownBanners$.next(newBanners);
}
@ -162,7 +163,7 @@ export class CalendarIntegrationEffects {
const isInPast = calEv.start < Date.now();
const nrOfAllBanners = allEvsToShow.length;
console.log({ taskForEvent, allEvsToShow });
Log.log({ taskForEvent, allEvsToShow });
this._bannerService.open({
id: BannerId.CalendarEvent,

View file

@ -10,6 +10,7 @@ import { MODEL_VERSION_KEY } from '../../app.constants';
import { isMigrateModel } from '../../util/is-migrate-model';
import { LegacySyncProvider } from '../../imex/sync/legacy-sync-provider.model';
import { MODEL_VERSION } from '../../core/model-version';
import { Log } from '../../core/log';
export const migrateGlobalConfigState = (
globalConfigState: GlobalConfigState,
@ -111,7 +112,7 @@ const _extendConfigDefaults = (config: GlobalConfigState): GlobalConfigState =>
if (!newCfg[key].hasOwnProperty(entryKey)) {
// @ts-ignore
const defaultVal = DEFAULT_GLOBAL_CONFIG[key][entryKey];
console.log('EXTEND globalConfig', key, entryKey, defaultVal);
Log.log('EXTEND globalConfig', key, entryKey, defaultVal);
// @ts-ignore
newCfg[key] = { ...newCfg[key], [entryKey]: defaultVal };
}
@ -214,10 +215,7 @@ const _migrateSyncCfg = (config: GlobalConfigState): GlobalConfigState => {
}
if (!config.sync.localFileSync || !config.sync.webDav) {
console.warn(
'sync config was missing some keys, reverting to default',
config.sync,
);
Log.err('sync config was missing some keys, reverting to default', config.sync);
return {
...config,
sync: {
@ -233,7 +231,7 @@ const _migrateSyncCfg = (config: GlobalConfigState): GlobalConfigState => {
// config.sync.localFileSync.syncFolderPath = getDir(
// config.sync.localFileSync.syncFilePath,
// );
// console.log(
// Log.log(
// 'migrating new folder path localFileSync',
// JSON.stringify(config.sync.localFileSync),
// );
@ -242,7 +240,7 @@ const _migrateSyncCfg = (config: GlobalConfigState): GlobalConfigState => {
// }
// if (!config.sync.webDav.syncFolderPath && config.sync.webDav.syncFilePath?.length) {
// config.sync.webDav.syncFolderPath = getDir(config.sync.webDav.syncFilePath);
// console.log('migrating new folder path webDav', JSON.stringify(config.sync.webDav));
// Log.log('migrating new folder path webDav', JSON.stringify(config.sync.webDav));
// // TODO add delete with next version
// // delete config.sync.webDav.syncFilePath;
// }

View file

@ -20,6 +20,7 @@ import { getErrorTxt } from 'src/app/util/get-error-text';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { DatePipe } from '@angular/common';
import { standardListAnimation } from '../../../ui/animations/standard-list.ani';
import { Log } from '../../../core/log';
@Component({
selector: 'issue-panel-calendar-agenda',
@ -113,7 +114,7 @@ export class IssuePanelCalendarAgendaComponent implements OnInit {
.catch((e) => {
this.isLoading.set(false);
this._setAgendaItems([]);
console.error(e);
Log.err(e);
this.error.set(getErrorTxt(e));
});
}

View file

@ -58,6 +58,7 @@ import { TranslatePipe } from '@ngx-translate/core';
import { MatInput } from '@angular/material/input';
import { MatTooltip } from '@angular/material/tooltip';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import { Log } from '../../../core/log';
@Component({
selector: 'issue-provider-tab',
@ -122,7 +123,7 @@ export class IssueProviderTabComponent implements OnDestroy, AfterViewInit {
: of(null),
),
catchError(() => {
console.error('Project not found for issueProvider');
Log.err('Project not found for issueProvider');
return of(null);
}),
);

View file

@ -28,6 +28,7 @@ import { IssueServiceInterface } from './issue-service-interface';
import { JiraCommonInterfacesService } from './providers/jira/jira-common-interfaces.service';
import { GithubCommonInterfacesService } from './providers/github/github-common-interfaces.service';
import { catchError, map, switchMap } from 'rxjs/operators';
import { Log } from '../../core/log';
import { GitlabCommonInterfacesService } from './providers/gitlab/gitlab-common-interfaces.service';
import { CaldavCommonInterfacesService } from './providers/caldav/caldav-common-interfaces.service';
import { OpenProjectCommonInterfacesService } from './providers/open-project/open-project-common-interfaces.service';
@ -324,7 +325,7 @@ export class IssueService {
for (const pKey of Object.keys(tasksIssueIdsByIssueProviderKey)) {
const providerKey = pKey as IssueProviderKey;
console.log(
Log.log(
'POLLING CHANGES FOR ' + providerKey,
tasksIssueIdsByIssueProviderKey[providerKey],
);
@ -426,7 +427,7 @@ export class IssueService {
const { title = null, ...additionalFromProviderIssueService } =
this.ISSUE_SERVICE_MAP[issueProviderKey].getAddTaskData(issueDataReduced);
console.log({ title, additionalFromProviderIssueService });
Log.log({ title, additionalFromProviderIssueService });
const getProjectOrTagId = async (): Promise<Partial<TaskCopy>> => {
const defaultProjectId = (

View file

@ -16,6 +16,7 @@ import { T } from '../../../../t.const';
import { catchError } from 'rxjs/operators';
import { HANDLED_ERROR_PROP_STR } from '../../../../app.constants';
import { throwHandledError } from '../../../../util/throw-handled-error';
import { Log } from '../../../../core/log';
interface ClientCache {
client: DavClient;
@ -397,7 +398,7 @@ export class CaldavClientService {
const todo = comp.getFirstSubcomponent('vtodo');
if (!todo) {
console.warn('No todo found for task', task);
Log.err('No todo found for task', task);
return;
}

View file

@ -4,6 +4,7 @@ import { IssueProviderCalendar } from '../../issue.model';
import { CalendarProviderCfg } from './calendar.model';
import { ISSUE_PROVIDER_FF_DEFAULT_PROJECT } from '../../common-issue-form-stuff.const';
import { IS_ELECTRON } from '../../../../app.constants';
import { Log } from '../../../../core/log';
export const DEFAULT_CALENDAR_CFG: CalendarProviderCfg = {
isEnabled: false,
@ -45,7 +46,7 @@ export const CALENDAR_FORM_CFG_NEW: ConfigFormSection<IssueProviderCalendar> = {
key: 'checkUpdatesEvery',
hooks: {
onInit: (field) => {
console.log(field?.formControl?.value);
Log.log(field?.formControl?.value);
if (!field?.formControl?.value) {
field?.formControl?.setValue(2 * 60 * 60000);
}
@ -61,7 +62,7 @@ export const CALENDAR_FORM_CFG_NEW: ConfigFormSection<IssueProviderCalendar> = {
key: 'showBannerBeforeThreshold',
hooks: {
onInit: (field) => {
console.log(field?.formControl?.value);
Log.log(field?.formControl?.value);
if (!field?.formControl?.value && field?.formControl?.value !== null) {
field?.formControl?.setValue(2 * 60 * 60000);
}

View file

@ -34,6 +34,7 @@ import { SearchResultItem } from '../../../issue.model';
import { GITLAB_TYPE, ISSUE_PROVIDER_HUMANIZED } from '../../../issue.const';
import { assertTruthy } from '../../../../../util/assert-truthy';
import { handleIssueProviderHttpError$ } from '../../../handle-issue-provider-http-error';
import { Log } from '../../../../../core/log';
@Injectable({
providedIn: 'root',
@ -43,7 +44,7 @@ export class GitlabApiService {
private _http = inject(HttpClient);
getById$(id: string, cfg: GitlabCfg): Observable<GitlabIssue> {
console.log(this._issueApiLink(cfg, id));
Log.log(this._issueApiLink(cfg, id));
return this._sendIssuePaginatedRequest$(
{
@ -307,7 +308,7 @@ export class GitlabApiService {
responseType: params.responseType,
},
];
console.log(allArgs);
Log.log(allArgs);
const req = new HttpRequest(p.method, p.url, ...allArgs);
@ -325,7 +326,7 @@ export class GitlabApiService {
}
private _issueApiLink(cfg: GitlabCfg, issueId: string): string {
console.log(issueId);
Log.log(issueId);
const { projectIssueId } = getPartsFromGitlabIssueId(issueId);
return `${this._apiLink(cfg)}/issues/${projectIssueId}`;
}

View file

@ -30,6 +30,7 @@ import { MsToStringPipe } from '../../../../../ui/duration/ms-to-string.pipe';
import { SortPipe } from '../../../../../ui/pipes/sort.pipe';
import { TranslatePipe } from '@ngx-translate/core';
import { SnackService } from '../../../../../core/snack/snack.service';
import { Log } from '../../../../../core/log';
interface JiraSubtaskWithUrl extends JiraSubtask {
href: string;
@ -102,7 +103,7 @@ export class JiraIssueContentComponent {
}),
).pipe(
catchError((e) => {
console.error(e);
Log.err(e);
this._snackService.open({
type: 'ERROR',
msg: 'Failed to load subtasks for Jira Issue',

View file

@ -52,6 +52,7 @@ import { DialogPromptComponent } from '../../../../ui/dialog-prompt/dialog-promp
import { stripTrailing } from '../../../../util/strip-trailing';
import { IS_ANDROID_WEB_VIEW } from '../../../../util/is-android-web-view';
import { formatJiraDate } from '../../../../util/format-jira-date';
import { Log } from '../../../../core/log';
const BLOCK_ACCESS_KEY = 'SUP_BLOCK_JIRA_ACCESS';
const API_VERSION = 'latest';
@ -149,7 +150,7 @@ export class JiraApiService {
// switchMap((res) =>
// res.length > 0 ? of(res) : this.issuePicker$(searchTerm, cfg),
// ),
tap((v) => console.log('AAAAA', v)),
tap((v) => Log.log('AAAAA', v)),
);
}
@ -421,7 +422,7 @@ export class JiraApiService {
}
if (this._isBlockAccess && !isForce) {
console.error('Blocked Jira Access to prevent being shut out');
Log.err('Blocked Jira Access to prevent being shut out');
this._bannerService.open({
id: BannerId.JiraUnblock,
msg: T.F.JIRA.BANNER.BLOCK_ACCESS_MSG,
@ -513,8 +514,8 @@ export class JiraApiService {
}),
).pipe(
catchError((err) => {
console.log(err);
console.log(getErrorTxt(err));
Log.log(err);
Log.log(getErrorTxt(err));
const errTxt = `Jira: ${getErrorTxt(err)}`;
this._snackService.open({ type: 'ERROR', msg: errTxt });
return throwError({ [HANDLED_ERROR_PROP_STR]: errTxt });
@ -527,8 +528,8 @@ export class JiraApiService {
this._globalProgressBarService.countUp(url);
return fromPromise(promise).pipe(
catchError((err) => {
console.log(err);
console.log(getErrorTxt(err));
Log.log(err);
Log.log(getErrorTxt(err));
const errTxt = `Jira: ${getErrorTxt(err)}`;
this._snackService.open({ type: 'ERROR', msg: errTxt });
return throwError({ [HANDLED_ERROR_PROP_STR]: errTxt });
@ -625,7 +626,7 @@ export class JiraApiService {
jiraCfg,
timeoutId: window.setTimeout(() => {
console.log('ERROR', 'Jira Request timed out', requestInit);
Log.log('ERROR', 'Jira Request timed out', requestInit);
this._blockAccess();
// delete entry for promise
this._snackService.open({
@ -647,7 +648,7 @@ export class JiraApiService {
// resolve saved promise
if (!res || res.error) {
console.error('JIRA_RESPONSE_ERROR', res, currentRequest);
Log.err('JIRA_RESPONSE_ERROR', res, currentRequest);
// let msg =
if (
res?.error &&
@ -661,15 +662,15 @@ export class JiraApiService {
currentRequest.reject(res);
} else {
// console.log('JIRA_RESPONSE', res);
// Log.log('JIRA_RESPONSE', res);
if (currentRequest.transform) {
// data can be invalid, that's why we check
try {
currentRequest.resolve(currentRequest.transform(res, currentRequest.jiraCfg));
} catch (e) {
console.log(res);
console.log(currentRequest);
console.error(e);
Log.log(res);
Log.log(currentRequest);
Log.err(e);
this._snackService.open({
type: 'ERROR',
msg: T.F.JIRA.S.INVALID_RESPONSE,
@ -682,7 +683,7 @@ export class JiraApiService {
// delete entry for promise afterwards
delete this._requestsLog[res.requestId];
} else {
console.warn('Jira: Response Request ID not existing', res && res.requestId);
Log.err('Jira: Response Request ID not existing', res && res.requestId);
}
}
@ -726,7 +727,7 @@ async function streamToJsonIfPossible(stream: ReadableStream): Promise<any> {
try {
return JSON.parse(text);
} catch (e) {
console.error('Jira: Could not parse response', text);
Log.err('Jira: Could not parse response', text);
return text;
}
}

View file

@ -26,9 +26,10 @@ import { IssueProviderKey, SearchResultItem } from '../../issue.model';
import { TaskAttachment } from '../../../tasks/task-attachment/task-attachment.model';
import { dedupeByKey } from '../../../../util/de-dupe-by-key';
import { JIRA_TYPE } from '../../issue.const';
import { Log } from '../../../../core/log';
export const mapToSearchResults = (res: any): SearchResultItem[] => {
console.log(res);
Log.log(res);
const issues = dedupeByKey(
res.response.sections.map((sec: any) => sec.issues).flat(),
@ -50,7 +51,7 @@ export const mapToSearchResults = (res: any): SearchResultItem[] => {
};
export const mapToSearchResultsForJQL = (res: any): SearchResultItem[] => {
console.log(res);
Log.log(res);
const issues = dedupeByKey(res.response.issues, 'key').map((issue: any) => {
return {
@ -82,7 +83,7 @@ export const mapIssueResponse = (res: any, cfg: JiraCfg): JiraIssue =>
export const mapIssue = (issue: JiraIssueOriginal, cfg: JiraCfg): JiraIssue => {
const issueCopy = Object.assign({}, issue);
const fields = issueCopy.fields;
console.log(fields);
Log.log(fields);
return {
key: issueCopy.key,
@ -113,7 +114,7 @@ export const mapIssue = (issue: JiraIssueOriginal, cfg: JiraCfg): JiraIssue => {
};
const mapIssueLinks = (issueLinks: JiraOriginalIssueLink[]): JiraRelatedIssue[] => {
console.log(issueLinks);
Log.log(issueLinks);
return issueLinks.map((il) => {
const isInwardIssue = !!il.inwardIssue;

View file

@ -54,6 +54,7 @@ import { MatOption, MatSelect } from '@angular/material/select';
import { formatLocalIsoWithoutSeconds } from '../../../../../../util/format-local-iso-without-seconds';
import { formatDateYYYYMMDD } from '../../../../../../util/format-date-yyyy-mm-dd';
import { msToIsoDuration } from '../../../../../../util/ms-to-iso-duration';
import { Log } from '../../../../../../core/log';
@Component({
selector: 'dialog-open-project-track-time',
@ -152,7 +153,7 @@ export class DialogOpenProjectTrackTimeComponent implements OnDestroy {
);
constructor() {
this._issueProviderIdOnce$.subscribe((v) => console.log(`_issueProviderIdOnce$`, v));
this._issueProviderIdOnce$.subscribe((v) => Log.log(`_issueProviderIdOnce$`, v));
this.timeSpent = this.data.task.timeSpent;
this.workPackage = this.data.workPackage;
@ -183,7 +184,7 @@ export class DialogOpenProjectTrackTimeComponent implements OnDestroy {
}
async postTime(): Promise<void> {
console.log({
Log.log({
wp: this.workPackage,
started: this.started,
timeSpent: this.timeSpent,

View file

@ -20,6 +20,7 @@ import { IssueProvider } from '../issue.model';
import { SnackService } from '../../../core/snack/snack.service';
import { getErrorTxt } from '../../../util/get-error-text';
import { DELAY_BEFORE_ISSUE_POLLING } from '../issue.const';
import { Log } from '../../../core/log';
@Injectable()
export class PollToBacklogEffects {
@ -79,7 +80,7 @@ export class PollToBacklogEffects {
),
),
catchError((e) => {
console.error(e);
Log.err(e);
this._snackService.open({
type: 'ERROR',
// TODO translate

View file

@ -1,3 +1,5 @@
import { Log } from '../../core/log';
/*
we want to match:
- [x] task
@ -25,8 +27,8 @@ export const isMarkdownChecklist = (text: string): boolean => {
);
return items.length === lines.length || items.length >= 2;
} catch (e) {
console.error('Checklist parsing failed');
console.error(e);
Log.err('Checklist parsing failed');
Log.err(e);
return false;
}
};

View file

@ -14,6 +14,7 @@ import {
} from '../obstruction/store/obstruction.reducer';
import { ObstructionState } from '../obstruction/obstruction.model';
import { unique } from '../../../util/unique';
import { Log } from '../../../core/log';
import {
selectAllSimpleCounters,
selectSimpleCounterFeatureState,
@ -159,7 +160,7 @@ export const selectImprovementCountsPieChartData = createSelector(
chart.labels?.push(imp.title);
chart.datasets[0].data.push(counts[id]);
} else {
console.warn('No improvement entity found');
Log.err('No improvement entity found');
}
});
return chart;
@ -190,7 +191,7 @@ export const selectObstructionCountsPieChartData = createSelector(
chart.labels?.push(obstr.title);
chart.datasets[0].data.push(counts[id]);
} else {
console.warn('No obstruction entity found');
Log.err('No obstruction entity found');
}
});
return chart;

View file

@ -51,6 +51,7 @@ import {
import { MatSelect } from '@angular/material/select';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { MatInput } from '@angular/material/input';
import { Log } from '../../../core/log';
const DEFAULT_TIME = '09:00';
@ -122,7 +123,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
reminder.remindAt,
);
} else {
console.warn('No reminder found for task', this.data.task);
Log.err('No reminder found for task', this.data.task);
}
// for tasks without anything scheduled
} else if (!this.data.task.dueWithTime) {
@ -184,10 +185,10 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
onKeyDownOnCalendar(ev: KeyboardEvent): void {
this._timeCheckVal = null;
// console.log(ev.key, ev.keyCode);
// Log.log(ev.key, ev.keyCode);
if (ev.key === 'Enter' || ev.keyCode === 32) {
this.isShowEnterMsg = true;
// console.log(
// Log.log(
// 'check to submit',
// this.selectedDate &&
// new Date(this.selectedDate).getTime() ===
@ -208,7 +209,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
}
onTimeKeyDown(ev: KeyboardEvent): void {
// console.log('ev.key!', ev.key);
// Log.log('ev.key!', ev.key);
if (ev.key === 'Enter') {
this.isShowEnterMsg = true;
@ -226,7 +227,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
}
dateSelected(newDate: Date): void {
// console.log('dateSelected', typeof newDate, newDate, this.selectedDate);
// Log.log('dateSelected', typeof newDate, newDate, this.selectedDate);
// we do the timeout is there to make sure this happens after our click handler
setTimeout(() => {
this.selectedDate = new Date(newDate);
@ -283,7 +284,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
}
onTimeFocus(): void {
console.log('onTimeFocus');
Log.log('onTimeFocus');
if (!this.selectedTime && this.isInitValOnTimeFocus) {
this.isInitValOnTimeFocus = false;
@ -303,7 +304,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
async submit(): Promise<void> {
if (!this.selectedDate) {
console.warn('no selected date');
Log.err('no selected date');
return;
}

View file

@ -13,6 +13,7 @@ import { selectTodayTaskIds } from '../work-context/store/work-context.selectors
import { msToString } from '../../ui/duration/ms-to-string.pipe';
import { getWorklogStr } from '../../util/get-work-log-str';
import { selectAllTaskRepeatCfgs } from '../task-repeat-cfg/store/task-repeat-cfg.selectors';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -26,7 +27,7 @@ export class PlannerService {
includedWeekDays$ = of([0, 1, 2, 3, 4, 5, 6]);
daysToShow$ = this._globalTrackingIntervalService.todayDateStr$.pipe(
tap((val) => console.log('daysToShow$', val)),
tap((val) => Log.log('daysToShow$', val)),
switchMap(() => this.includedWeekDays$),
map((includedWeekDays) => {
const today = new Date().getTime();
@ -74,8 +75,8 @@ export class PlannerService {
),
// for better performance
// TODO better solution, gets called very often
// tap((val) => console.log('days$', val)),
// tap((val) => console.log('days$ SIs', val[0]?.scheduledIItems)),
// tap((val) => Log.log('days$', val)),
// tap((val) => Log.log('days$ SIs', val[0]?.scheduledIItems)),
shareReplay(1),
);
tomorrow$ = this.days$.pipe(

View file

@ -6,6 +6,7 @@ import { loadAllData } from '../../../root-store/meta/load-all-data.action';
import { unique } from '../../../util/unique';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { Log } from '../../../core/log';
export const plannerFeatureKey = 'planner';
@ -139,7 +140,7 @@ export const plannerReducer = createReducer(
// when moving a parent to the day, remove all sub-tasks
.filter((id) => !action.task.subTaskIds.includes(id)),
};
console.log({ updateNextDay, updatePrevDay });
Log.log({ updateNextDay, updatePrevDay });
return {
...state,
@ -174,7 +175,7 @@ export const plannerReducer = createReducer(
}
const toIndex = daysCopy[dayI].indexOf(action.toTaskId);
if (toIndex > -1) {
console.log('toIndex', toIndex);
Log.log('toIndex', toIndex);
const tidsForDay = [...daysCopy[dayI]];
tidsForDay.splice(toIndex, 0, action.fromTask.id);
daysCopy[dayI] = tidsForDay;

View file

@ -6,6 +6,7 @@ import { isMigrateModel } from '../../util/is-migrate-model';
import { WORK_CONTEXT_DEFAULT_THEME } from '../work-context/work-context.const';
import { dirtyDeepCopy } from '../../util/dirtyDeepCopy';
import { MODEL_VERSION } from '../../core/model-version';
import { Log } from '../../core/log';
export const migrateProjectState = (projectState: ProjectState): ProjectState => {
if (!isMigrateModel(projectState, MODEL_VERSION.PROJECT, 'Project')) {
@ -77,7 +78,7 @@ const _fixIds = (projectState: ProjectState): ProjectState => {
const allIds = Object.keys(projectState.entities);
if (!currentIds) {
console.error('Project Ids not defined');
Log.err('Project Ids not defined');
console.log('Attempting to fix...');
return {
...projectState,

View file

@ -58,6 +58,7 @@ import {
} from '../../note/store/note.actions';
import { MODEL_VERSION } from '../../../core/model-version';
import { INBOX_PROJECT } from '../project.const';
import { Log } from '../../../core/log';
export const PROJECT_FEATURE_NAME = 'projects';
const WORK_CONTEXT_TYPE: WorkContextType = WorkContextType.PROJECT;
@ -271,7 +272,7 @@ export const projectReducer = createReducer<ProjectState>(
on(moveProjectTaskToBacklogList, (state, { taskId, newOrderedIds, workContextId }) => {
const project = state.entities[workContextId] as Project;
if (!project.isEnableBacklog) {
console.warn('Project backlog is disabled');
Log.err('Project backlog is disabled');
return state;
}
const todaysTaskIdsBefore = project.taskIds;
@ -461,7 +462,7 @@ export const projectReducer = createReducer<ProjectState>(
on(moveProjectTaskToBacklogListAuto, (state, { taskId, projectId }) => {
const project = state.entities[projectId] as Project;
if (!project.isEnableBacklog) {
console.warn('Project backlog is disabled');
Log.err('Project backlog is disabled');
return state;
}
const todaysTaskIdsBefore = project.taskIds;

View file

@ -15,6 +15,7 @@ import { devError } from '../../util/dev-error';
import { Note } from '../note/note.model';
import { environment } from 'src/environments/environment';
import { PfapiService } from '../../pfapi/pfapi.service';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -49,10 +50,10 @@ export class ReminderService {
private _reminders: Reminder[] = [];
constructor() {
// this._triggerPauseAfterUpdate$.subscribe((v) => console.log('_triggerPauseAfterUpdate$', v));
// this._pauseAfterUpdate$.subscribe((v) => console.log('_pauseAfterUpdate$', v));
// this._onRemindersActive$.subscribe((v) => console.log('_onRemindersActive$', v));
// this.onRemindersActive$.subscribe((v) => console.log('onRemindersActive$', v));
// this._triggerPauseAfterUpdate$.subscribe((v) => Log.log('_triggerPauseAfterUpdate$', v));
// this._pauseAfterUpdate$.subscribe((v) => Log.log('_pauseAfterUpdate$', v));
// this._onRemindersActive$.subscribe((v) => Log.log('_onRemindersActive$', v));
// this.onRemindersActive$.subscribe((v) => Log.log('onRemindersActive$', v));
if (typeof (Worker as any) === 'undefined') {
throw new Error('No service workers supported :(');
@ -78,7 +79,7 @@ export class ReminderService {
}
this._reminders = await this._loadFromDatabase();
if (!Array.isArray(this._reminders)) {
console.log(this._reminders);
Log.log(this._reminders);
devError('Something went wrong with the reminders');
this._reminders = [];
}
@ -87,7 +88,7 @@ export class ReminderService {
this._onReloadModel$.next(this._reminders);
this._reminders$.next(this._reminders);
if (environment.production) {
console.log('loaded reminders from database', this._reminders);
Log.log('loaded reminders from database', this._reminders);
}
}
@ -205,7 +206,7 @@ export class ReminderService {
const remindersWithData: Reminder[] = (await Promise.all(
reminders.map(async (reminder) => {
const relatedModel = await this._getRelatedDataForReminder(reminder);
// console.log('RelatedModel for Reminder', relatedModel);
// Log.log('RelatedModel for Reminder', relatedModel);
// only show when not currently syncing and related model still exists
if (!relatedModel) {
devError('No Reminder Related Data found, removing reminder...');
@ -241,7 +242,7 @@ export class ReminderService {
} else if (!this._isRemindersLoaded$.getValue()) {
throw new Error('Reminders not loaded initially when trying to save model');
}
console.log('saveReminders', reminders);
Log.log('saveReminders', reminders);
await this._pfapiService.m.reminders.save(reminders, {
isUpdateRevAndLastUpdate: true,
});
@ -254,7 +255,7 @@ export class ReminderService {
}
private _handleError(err: any): void {
console.error(err);
Log.err(err);
this._snackService.open({ type: 'ERROR', msg: T.F.REMINDER.S_REMINDER_ERR });
}

View file

@ -2,12 +2,13 @@
import { ReminderCopy } from './reminder.model';
import { lazySetInterval } from '../../../../electron/shared-with-frontend/lazy-set-interval';
import { Log } from '../../core/log';
const CHECK_INTERVAL_DURATION = 10000;
let cancelCheckInterval: (() => void) | undefined;
addEventListener('message', ({ data }) => {
// console.log('REMINDER WORKER', data);
// Log.log('REMINDER WORKER', data);
reInitCheckInterval(data);
});
@ -32,7 +33,7 @@ const reInitCheckInterval = (reminders: ReminderCopy[]): void => {
[oldest];
postMessage(remindersToSend);
console.log('Worker postMessage', remindersToSend);
Log.log('Worker postMessage', remindersToSend);
}
}, CHECK_INTERVAL_DURATION);
};

View file

@ -19,6 +19,7 @@ import { msLeftToday } from '../../../util/ms-left-today';
import { getTasksWithinAndBeyondBudget } from './get-tasks-within-and-beyond-budget';
import { dateStrToUtcDate } from '../../../util/date-str-to-utc-date';
import { selectTaskRepeatCfgsDueOnDayOnly } from '../../task-repeat-cfg/store/task-repeat-cfg.selectors';
import { Log } from '../../../core/log';
export const createScheduleDays = (
nonScheduledTasks: TaskWithoutReminder[],
@ -131,8 +132,8 @@ export const createScheduleDays = (
) {
viewEntriesPushedToNextDay.push(entry);
} else {
console.log('entry Start:', new Date(entry.start), { entry });
console.warn('Entry start time after next day start', entry);
Log.log('entry Start:', new Date(entry.start), { entry });
Log.err('Entry start time after next day start', entry);
}
} else {
if (
@ -149,7 +150,7 @@ export const createScheduleDays = (
}
});
// console.log({
// Log.log({
// dayDate,
// startTime: dateStrToUtcDate(startTime),
// viewEntriesPushedToNextDay,

View file

@ -11,7 +11,6 @@ import {
ScheduleWorkStartEndCfg,
} from '../schedule.model';
import { selectTaskRepeatCfgsDueOnDayOnly } from '../../task-repeat-cfg/store/task-repeat-cfg.selectors';
const PROJECTION_DAYS: number = 30;
export const createSortedBlockerBlocks = (
@ -40,7 +39,7 @@ export const createSortedBlockerBlocks = (
blockedBlocks = mergeBlocksRecursively(blockedBlocks);
blockedBlocks.sort((a, b) => a.start - b.start);
// console.log(
// Log.log(
// blockedBlocks.map(({ start, end }) => ({
// // start,
// // end,
@ -48,7 +47,7 @@ export const createSortedBlockerBlocks = (
// e: new Date(end),
// })),
// );
// console.log(blockedBlocks);
// Log.log(blockedBlocks);
return blockedBlocks;
};

View file

@ -13,7 +13,6 @@ import {
import { createScheduleViewEntriesForNormalTasks } from './create-schedule-view-entries-for-normal-tasks';
import { insertBlockedBlocksViewEntriesForSchedule } from './insert-blocked-blocks-view-entries-for-schedule';
import { SCHEDULE_VIEW_TYPE_ORDER, SVEType } from '../schedule.const';
export const createViewEntriesForDay = (
dayDate: string,
initialStartTime: number,
@ -77,7 +76,7 @@ export const createViewEntriesForDay = (
// viewEntries.splice(currentIndex + 1, 1);
// } else {
// debug(viewEntries);
// console.warn('View Entry for current not available');
// Log.err('View Entry for current not available');
// }
// }

View file

@ -32,6 +32,7 @@ import { IS_TOUCH_PRIMARY } from '../../../util/is-mouse-primary';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { MatTooltip } from '@angular/material/tooltip';
import { ShortcutService } from '../../../core-ui/shortcut/shortcut.service';
import { Log } from '../../../core/log';
const D_HOURS = 24;
const DRAG_CLONE_CLASS = 'drag-clone';
@ -201,7 +202,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
}
if (targetEl !== this.prevDragOverEl) {
console.log('dragMoved targetElChanged', targetEl);
Log.log('dragMoved targetElChanged', targetEl);
if (this.prevDragOverEl) {
this.prevDragOverEl.classList.remove(DRAG_OVER_CLASS);
@ -222,7 +223,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
}
dragStarted(ev: CdkDragStart<ScheduleEvent>): void {
console.log('dragStart', ev);
Log.log('dragStart', ev);
this.isDragging = this.isDraggingDelayed = true;
this.containerExtraClass = IS_DRAGGING_CLASS + ' ' + ev.source.data.type;
@ -238,7 +239,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
}
dragReleased(ev: CdkDragRelease): void {
console.log('dragReleased', {
Log.log('dragReleased', {
target: ev.event.target,
source: ev.source.element.nativeElement,
ev,
@ -271,7 +272,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
if (target.tagName.toLowerCase() === 'div' && target.classList.contains('col')) {
const isMoveToEndOfDay = target.classList.contains('end-of-day');
const targetDay = (target as any).day || target.getAttribute('data-day');
console.log({ targetDay });
Log.log({ targetDay });
if (targetDay) {
this._store.dispatch(
PlannerActions.planTaskForDay({
@ -284,7 +285,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
} else if (target.tagName.toLowerCase() === 'schedule-event') {
const sourceTaskId = ev.source.element.nativeElement.id.replace(T_ID_PREFIX, '');
const targetTaskId = target.id.replace(T_ID_PREFIX, '');
console.log(sourceTaskId === targetTaskId, sourceTaskId, targetTaskId);
Log.log(sourceTaskId === targetTaskId, sourceTaskId, targetTaskId);
if (
sourceTaskId &&
@ -292,7 +293,7 @@ export class ScheduleWeekComponent implements OnInit, OnDestroy {
targetTaskId &&
sourceTaskId !== targetTaskId
) {
console.log('sourceTaskId', sourceTaskId, 'targetTaskId', targetTaskId);
Log.log('sourceTaskId', sourceTaskId, 'targetTaskId', targetTaskId);
this._store.dispatch(
PlannerActions.moveBeforeTask({
fromTask: ev.source.data.data,

View file

@ -4,10 +4,11 @@ import { ShepherdService } from './shepherd.service';
import Step from 'shepherd.js/src/types/step';
import StepOptionsWhen = Step.StepOptionsWhen;
import { TourId } from './shepherd-steps.const';
import { Log } from '../../core/log';
export const waitForEl = (selector: string, cb: () => void): number => {
const int = window.setInterval(() => {
console.log('INT');
Log.log('INT');
if (document.querySelector(selector)) {
window.clearInterval(int);
@ -41,7 +42,7 @@ export const nextOnObs = (
.pipe(
tap((v) => {
if (debugTitle) {
console.log('nextOnObs', v, debugTitle);
Log.log('nextOnObs', v, debugTitle);
}
}),
first(),
@ -75,7 +76,7 @@ export const twoWayObs = (
onDestroy$ = new Subject();
fwd.obs.pipe(first(), takeUntil(onDestroy$)).subscribe((v) => {
if (debugTitle) {
console.log(debugTitle, 'fwd', v);
Log.log(debugTitle, 'fwd', v);
}
fwd.cbAfter?.();
shepherdService.next();
@ -83,7 +84,7 @@ export const twoWayObs = (
if (back) {
back.obs.pipe(first(), takeUntil(onDestroy$)).subscribe((v) => {
if (debugTitle) {
console.log(debugTitle, 'back', v);
Log.log(debugTitle, 'back', v);
}
back.cbAfter?.();
if (back.backToId) {

View file

@ -31,6 +31,7 @@ import { TranslateService } from '@ngx-translate/core';
import { PlannerService } from '../../planner/planner.service';
import { selectAllTasksDueToday } from '../../planner/store/planner.selectors';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { Log } from '../../../core/log';
@Injectable()
export class TagEffects {
@ -174,7 +175,7 @@ export class TagEffects {
),
),
filter(({ nullTasks }) => nullTasks.length > 0),
tap((arg) => console.log('Error INFO Today:', arg)),
tap((arg) => Log.log('Error INFO Today:', arg)),
tap(({ activeId, allTasks }) => {
const allIds = allTasks.map((t) => t && t.id);
const r = confirm(
@ -221,7 +222,7 @@ export class TagEffects {
newTaskIds.some((id, i) => id !== todayTagTaskIds[i]);
if (isChanged && (tasksWithParentInListIds.length || dueNotInListIds.length)) {
console.log('Preventing parent and subtask in today list', {
Log.log('Preventing parent and subtask in today list', {
isChanged,
tasksWithParentInListIds,
dueNotInListIds,

View file

@ -29,6 +29,7 @@ import { Update } from '@ngrx/entity';
import { getDateTimeFromClockString } from '../../../util/get-date-time-from-clock-string';
import { isToday } from '../../../util/is-today.util';
import { TaskArchiveService } from '../../time-tracking/task-archive.service';
import { Log } from '../../../core/log';
@Injectable()
export class TaskRepeatCfgEffects {
@ -122,8 +123,8 @@ export class TaskRepeatCfgEffects {
),
tap(([isConfirm, completeCfg]) => {
if (isConfirm) {
console.log(changes);
console.log(todayTasks, archiveTasks);
Log.log(changes);
Log.log(todayTasks, archiveTasks);
// NOTE: keep in mind that it's very likely that there will be only one task for today
// TODO update reminders if given
todayTasks.forEach((task) =>
@ -163,7 +164,7 @@ export class TaskRepeatCfgEffects {
) {
changesForArchiveTask.timeEstimate = changes.defaultEstimate;
}
console.log('updateArchiveTask', changesForArchiveTask);
Log.log('updateArchiveTask', changesForArchiveTask);
return { id: task.id, changes: changesForArchiveTask };
});
this._taskService.updateArchiveTasks(archiveUpdates);

View file

@ -30,6 +30,7 @@ import { T } from '../../../t.const';
import { IssueService } from '../../issue/issue.service';
import { assertTruthy } from '../../../util/assert-truthy';
import { DEFAULT_PROJECT_COLOR } from '../../work-context/work-context.const';
import { Log } from '../../../core/log';
@Injectable({
providedIn: 'root',
@ -184,7 +185,7 @@ export class AddTaskBarService {
return item.taskId;
} else if (item.taskId) {
if (!item.projectId) {
console.log(item);
Log.log(item);
throw new Error('Weird add task case1');
}
this._projectService.moveTaskToTodayList(item.taskId, item.projectId);
@ -204,7 +205,7 @@ export class AddTaskBarService {
item.issueType,
this._workContextService.activeWorkContextId as string,
);
console.log(res);
Log.log(res);
if (!res) {
return await this._issueService.addTaskFromIssue({
issueProviderKey: item.issueType,
@ -305,7 +306,7 @@ export class AddTaskBarService {
try {
return !!task.title.toLowerCase().match(searchText.toLowerCase());
} catch (e) {
console.warn('RegEx Error', e);
Log.err('RegEx Error', e);
return false;
}
}

View file

@ -5,7 +5,6 @@ import { stringToMs } from '../../ui/duration/string-to-ms.pipe';
import { Tag } from '../tag/tag.model';
import { Project } from '../project/project.model';
import { ShortSyntaxConfig } from '../config/global-config.model';
type ProjectChanges = {
title?: string;
projectId?: string;
@ -285,15 +284,15 @@ const parseTagChanges = (task: Partial<TaskCopy>, allTags?: Tag[]): TagChanges =
taskChanges.title = taskChanges.title.trim();
}
// console.log(task.title);
// console.log('newTagTitles', regexTagTitles);
// console.log('newTagTitlesTrimmed', regexTagTitlesTrimmedAndFiltered);
// console.log('allTags)', allTags.map(tag => `${tag.id}: ${tag.title}`));
// console.log('task.tagIds', task.tagIds);
// console.log('task.title', task.title);
// Log.log(task.title);
// Log.log('newTagTitles', regexTagTitles);
// Log.log('newTagTitlesTrimmed', regexTagTitlesTrimmedAndFiltered);
// Log.log('allTags)', allTags.map(tag => `${tag.id}: ${tag.title}`));
// Log.log('task.tagIds', task.tagIds);
// Log.log('task.title', task.title);
}
}
// console.log(taskChanges);
// Log.log(taskChanges);
return {
taskChanges,

View file

@ -57,6 +57,7 @@ import { PlannerActions } from '../../planner/store/planner.actions';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { TimeTrackingActions } from '../../time-tracking/store/time-tracking.actions';
import { Log } from '../../../core/log';
export const TASK_FEATURE_NAME = 'tasks';
@ -280,14 +281,14 @@ export const taskReducer = createReducer<TaskState>(
on(moveSubTaskUp, (state, { id, parentId }) => {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(`Parent task ${parentId} not found`);
Log.err(`Parent task ${parentId} not found`);
return state;
}
const parentSubTaskIds = parentTask.subTaskIds;
// Check if the subtask is actually in the parent's subtask list
if (!parentSubTaskIds.includes(id)) {
console.warn(`Subtask ${id} not found in parent ${parentId} subtasks`);
Log.err(`Subtask ${id} not found in parent ${parentId} subtasks`);
return state;
}
@ -305,14 +306,14 @@ export const taskReducer = createReducer<TaskState>(
on(moveSubTaskDown, (state, { id, parentId }) => {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(`Parent task ${parentId} not found`);
Log.err(`Parent task ${parentId} not found`);
return state;
}
const parentSubTaskIds = parentTask.subTaskIds;
// Check if the subtask is actually in the parent's subtask list
if (!parentSubTaskIds.includes(id)) {
console.warn(`Subtask ${id} not found in parent ${parentId} subtasks`);
Log.err(`Subtask ${id} not found in parent ${parentId} subtasks`);
return state;
}
@ -330,14 +331,14 @@ export const taskReducer = createReducer<TaskState>(
on(moveSubTaskToTop, (state, { id, parentId }) => {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(`Parent task ${parentId} not found`);
Log.err(`Parent task ${parentId} not found`);
return state;
}
const parentSubTaskIds = parentTask.subTaskIds;
// Check if the subtask is actually in the parent's subtask list
if (!parentSubTaskIds.includes(id)) {
console.warn(`Subtask ${id} not found in parent ${parentId} subtasks`);
Log.err(`Subtask ${id} not found in parent ${parentId} subtasks`);
return state;
}
@ -355,14 +356,14 @@ export const taskReducer = createReducer<TaskState>(
on(moveSubTaskToBottom, (state, { id, parentId }) => {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(`Parent task ${parentId} not found`);
Log.err(`Parent task ${parentId} not found`);
return state;
}
const parentSubTaskIds = parentTask.subTaskIds;
// Check if the subtask is actually in the parent's subtask list
if (!parentSubTaskIds.includes(id)) {
console.warn(`Subtask ${id} not found in parent ${parentId} subtasks`);
Log.err(`Subtask ${id} not found in parent ${parentId} subtasks`);
return state;
}

View file

@ -11,6 +11,7 @@ import { calcTotalTimeSpent } from '../util/calc-total-time-spent';
import { taskAdapter } from './task.adapter';
import { filterOutId } from '../../../util/filter-out-id';
import { Update } from '@ngrx/entity';
import { Log } from '../../../core/log';
export const getTaskById = (taskId: string, state: TaskState): Task => {
if (!state.entities[taskId]) {
@ -37,9 +38,7 @@ export const reCalcTimeSpentForParentIfParent = (
if (parentId) {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(
`Parent task ${parentId} not found in reCalcTimeSpentForParentIfParent`,
);
Log.err(`Parent task ${parentId} not found in reCalcTimeSpentForParentIfParent`);
return state;
}
@ -83,9 +82,7 @@ export const reCalcTimeEstimateForParentIfParent = (
): TaskState => {
const parentTask = state.entities[parentId];
if (!parentTask) {
console.warn(
`Parent task ${parentId} not found in reCalcTimeEstimateForParentIfParent`,
);
Log.err(`Parent task ${parentId} not found in reCalcTimeEstimateForParentIfParent`);
return state;
}
@ -97,9 +94,9 @@ export const reCalcTimeEstimateForParentIfParent = (
return upd && upd.id === id ? { ...task, ...upd.changes } : task;
})
.filter((task): task is Task => !!task);
// console.log(
// Log.log(
// subTasks.reduce((acc: number, st: Task) => {
// console.log(
// Log.log(
// (st.isDone ? 0 : Math.max(0, st.timeEstimate - st.timeSpent)) / 60 / 1000,
// );
//

View file

@ -70,6 +70,7 @@ import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actio
import { selectTodayTagTaskIds } from '../../../tag/store/tag.reducer';
import { isToday } from '../../../../util/is-today.util';
import { MenuTouchFixDirective } from '../menu-touch-fix.directive';
import { Log } from '../../../../core/log';
@Component({
selector: 'task-context-menu-inner',
@ -536,7 +537,7 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
private async _schedule(selectedDate: Date, isRemoveFromToday = false): Promise<void> {
if (!selectedDate) {
console.warn('no selected date');
Log.err('no selected date');
return;
}

View file

@ -85,7 +85,6 @@ import { MsToStringPipe } from '../../../ui/duration/ms-to-string.pipe';
import { IssueIconPipe } from '../../issue/issue-icon/issue-icon.pipe';
import { isToday } from '../../../util/is-today.util';
import { getWorklogStr } from '../../../util/get-work-log-str';
interface IssueAndType {
id?: string | number;
type?: IssueProviderKey;
@ -309,9 +308,9 @@ export class TaskDetailPanelComponent implements OnInit, AfterViewInit, OnDestro
}
});
}
// this.issueIdAndType$.subscribe((v) => console.log('issueIdAndType$', v));
// this.issueDataTrigger$.subscribe((v) => console.log('issueDataTrigger$', v));
// this.issueData$.subscribe((v) => console.log('issueData$', v));
// this.issueIdAndType$.subscribe((v) => Log.log('issueIdAndType$', v));
// this.issueDataTrigger$.subscribe((v) => Log.log('issueDataTrigger$', v));
// this.issueData$.subscribe((v) => Log.log('issueData$', v));
// NOTE: check work-view component for more info
}

View file

@ -37,6 +37,7 @@ import { MatIcon } from '@angular/material/icon';
import { TaskComponent } from '../task/task.component';
import { AsyncPipe } from '@angular/common';
import { TaskViewCustomizerService } from '../../task-view-customizer/task-view-customizer.service';
import { Log } from '../../../core/log';
export type TaskListId = 'PARENT' | 'SUB';
export type ListModelId = DropListModelSource | string;
@ -131,7 +132,7 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
// const targetModelId = drag.dropContainer.data.listModelId;
const targetModelId = drop.data.listModelId;
const isSubtask = !!task.parentId;
// console.log(drag.data.id, { isSubtask, targetModelId, drag, drop });
// Log.log(drag.data.id, { isSubtask, targetModelId, drag, drop });
// return true;
if (targetModelId === 'OVERDUE' || targetModelId === 'LATER_TODAY') {
return false;
@ -158,7 +159,7 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
const srcListData = ev.previousContainer.data;
const targetListData = ev.container.data;
const draggedTask = ev.item.data;
console.log({
Log.log({
ev,
srcListData,
targetListData,
@ -220,7 +221,7 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
...targetListData.filteredTasks.filter((t) => t.id !== draggedTask.id),
draggedTask,
];
console.log(srcListData.listModelId, '=>', targetListData.listModelId, {
Log.log(srcListData.listModelId, '=>', targetListData.listModelId, {
targetTask,
draggedTask,
newIds,

View file

@ -85,6 +85,7 @@ import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions'
import { environment } from '../../../../environments/environment';
import { TODAY_TAG } from '../../tag/tag.const';
import { GlobalTrackingIntervalService } from '../../../core/global-tracking-interval/global-tracking-interval.service';
import { Log } from '../../../core/log';
@Component({
selector: 'task',
@ -596,7 +597,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
focusTitleForEdit(): void {
const taskTitleEditEl = this.taskTitleEditEl();
if (!taskTitleEditEl || !taskTitleEditEl.textarea().nativeElement) {
console.log(taskTitleEditEl);
Log.log(taskTitleEditEl);
throw new Error('No el');
}
taskTitleEditEl.textarea().nativeElement.focus();
@ -710,7 +711,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
archiveInstances,
targetProject,
]) => {
console.log({
Log.log({
reminderCfg,
nonArchiveInstancesWithSubTasks,
archiveInstances,

View file

@ -1,4 +1,5 @@
import { SoundConfig } from '../../config/global-config.model';
import { Log } from '../../../core/log';
export const playDoneSound = (soundCfg: SoundConfig, nrOfDoneTasks: number = 0): void => {
const speed = 1;
@ -7,13 +8,13 @@ export const playDoneSound = (soundCfg: SoundConfig, nrOfDoneTasks: number = 0):
const file = `${BASE}/${soundCfg.doneSound}`;
// const speed = 0.5;
// const a = new Audio('/assets/snd/done4.mp3');
// console.log(a);
// Log.log(a);
// a.volume = .4;
// a.playbackRate = 1.5;
// (a as any).mozPreservesPitch = false;
// (a as any).webkitPreservesPitch = false;
// a.play();
console.log(file);
Log.log(file);
const pitchFactor = soundCfg.isIncreaseDoneSoundPitch
? // prettier-ignore

View file

@ -7,6 +7,7 @@ import { UI_LOCAL_HELPER_DEFAULT } from './ui-helper.const';
import { IS_ELECTRON } from '../../app.constants';
import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import { Log } from '../../core/log';
@Injectable({ providedIn: 'root' })
export class UiHelperService {
@ -18,7 +19,7 @@ export class UiHelperService {
zoomTo(zoomFactor: number): void {
if (Number.isNaN(zoomFactor)) {
console.error('Invalid zoom factor', zoomFactor);
Log.err('Invalid zoom factor', zoomFactor);
return;
}
@ -28,7 +29,7 @@ export class UiHelperService {
zoomBy(zoomBy: number): void {
if (Number.isNaN(zoomBy)) {
console.error('Invalid zoom factor', zoomBy);
Log.err('Invalid zoom factor', zoomBy);
return;
}
const currentZoom = window.ea.getZoomFactor();
@ -49,7 +50,7 @@ export class UiHelperService {
window.ea.showOrFocus();
} else {
console.error('Cannot execute focus app window in browser');
Log.err('Cannot execute focus app window in browser');
}
}

View file

@ -65,6 +65,7 @@ import { TaskArchiveService } from '../time-tracking/task-archive.service';
import { INBOX_PROJECT } from '../project/project.const';
import { selectProjectById } from '../project/store/project.selectors';
import { getWorklogStr } from '../../util/get-work-log-str';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -257,11 +258,11 @@ export class WorkContextService {
);
todaysTasks$: Observable<TaskWithSubTasks[]> = this.todaysTaskIds$.pipe(
// tap((taskIds: string[]) => console.log('[WorkContext] Today task IDs:', taskIds)),
// tap((taskIds: string[]) => Log.log('[WorkContext] Today task IDs:', taskIds)),
switchMap((taskIds: string[]) => this._getTasksByIds$(taskIds)),
// TODO find out why this is triggered so often
// tap((tasks: TaskWithSubTasks[]) =>
// console.log('[WorkContext] Today tasks loaded:', tasks.length, 'tasks'),
// Log.log('[WorkContext] Today tasks loaded:', tasks.length, 'tasks'),
// ),
// map(to => to.filter(t => !!t)),
shareReplay(1),
@ -645,7 +646,7 @@ export class WorkContextService {
// we don't want a circular dependency that's why we do it here...
private _getTasksByIds$(ids: string[]): Observable<TaskWithSubTasks[]> {
if (!Array.isArray(ids)) {
console.log({ ids });
Log.log({ ids });
throw new Error('Invalid param provided for getByIds$ :(');
}
return this._store$.select(selectTasksWithSubTasksByIds, { ids });
@ -654,7 +655,7 @@ export class WorkContextService {
// we don't want a circular dependency that's why we do it here...
private _getNotesByIds$(ids: string[]): Observable<Note[]> {
if (!Array.isArray(ids)) {
console.log({ ids });
Log.log({ ids });
throw new Error('Invalid param provided for getByIds$ :(');
}
return this._store$.select(selectNotesById, { ids });

View file

@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
import { CommonModule } from '@angular/common'; // For *ngIf, etc.
import { TranslateModule } from '@ngx-translate/core'; // For translate pipe
import { T } from '../../t.const';
import { Log } from '../../core/log';
export interface DialogConfirmUrlImportData {
domain: string;
@ -29,7 +30,7 @@ export class ConfirmUrlImportDialogComponent {
constructor() {
if (!this.data || !this.data.domain) {
console.error('ConfirmUrlImportDialogComponent: No URL provided in dialog data.');
Log.err('ConfirmUrlImportDialogComponent: No URL provided in dialog data.');
// Optionally close dialog or handle error, for now, it will show undefined in template
}
}

View file

@ -8,6 +8,7 @@ import { MatDialogModule } from '@angular/material/dialog'; // Import MatDialogM
import { T } from '../../t.const';
import { TranslatePipe } from '@ngx-translate/core';
import { NgIf } from '@angular/common'; // For potential translations
import { Log } from '../../core/log';
@Component({
selector: 'dialog-import-from-url',
@ -43,7 +44,7 @@ export class DialogImportFromUrlComponent {
// Basic validation: show error or prevent closing if URL is empty
// For now, we rely on the required attribute in HTML and button disable
// Or handle with a snackbar if more sophisticated feedback is needed
console.error('URL is required.');
Log.err('URL is required.');
}
}

View file

@ -27,6 +27,7 @@ import {
ConfirmUrlImportDialogComponent,
DialogConfirmUrlImportData,
} from '../dialog-confirm-url-import/dialog-confirm-url-import.component';
import { Log } from '../../core/log';
@Component({
selector: 'file-imex',
@ -62,7 +63,7 @@ export class FileImexComponent implements OnInit {
try {
decodedUrl = decodeURIComponent(importUrlParam);
} catch (e) {
console.error('Error decoding importFromUrl parameter:', e);
Log.err('Error decoding importFromUrl parameter:', e);
this._snackService.open({
type: 'ERROR',
msg: T.FILE_IMEX.S_IMPORT_FROM_URL_ERR_DECODE,
@ -134,7 +135,7 @@ export class FileImexComponent implements OnInit {
await this._processAndImportData(textData);
} catch (error) {
// Handle network errors and HTTP errors
console.error('Network error or HTTP error fetching from URL:', error);
Log.err('Network error or HTTP error fetching from URL:', error);
this._snackService.open({ type: 'ERROR', msg: T.FILE_IMEX.S_ERR_NETWORK });
}
}
@ -183,7 +184,7 @@ export class FileImexComponent implements OnInit {
// Optionally, add a success snackbar here if desired
// this._snackService.open({ type: 'SUCCESS', msg: 'Data imported successfully!' });
} catch (e) {
console.error('Import process failed', e);
Log.err('Import process failed', e);
this._snackService.open({
type: 'ERROR',
msg: T.FILE_IMEX.S_ERR_IMPORT_FAILED,

View file

@ -12,6 +12,7 @@ import { T } from '../../t.const';
import { TranslateService } from '@ngx-translate/core';
import { AppDataCompleteNew } from '../../pfapi/pfapi-config';
import { SnackService } from '../../core/snack/snack.service';
import { Log } from '../../core/log';
const DEFAULT_BACKUP_INTERVAL = 5 * 60 * 1000;
const ANDROID_DB_KEY = 'backup';
@ -72,7 +73,7 @@ export class LocalBackupService {
)
) {
const backupData = await this.loadBackupElectron(backupMeta.path);
console.log('backupData', backupData);
Log.log('backupData', backupData);
await this._importBackup(backupData);
}
@ -83,9 +84,9 @@ export class LocalBackupService {
confirm(this._translateService.instant(T.CONFIRM.RESTORE_FILE_BACKUP_ANDROID))
) {
const backupData = await this.loadBackupAndroid();
console.log('backupData', backupData);
Log.log('backupData', backupData);
const lineBreaksReplaced = backupData.replace(/\n/g, '\\n');
console.log('lineBreaksReplaced', lineBreaksReplaced);
Log.log('lineBreaksReplaced', lineBreaksReplaced);
await this._importBackup(lineBreaksReplaced);
}
}

View file

@ -19,6 +19,7 @@ import { SyncWrapperService } from '../sync-wrapper.service';
import { Subscription } from 'rxjs';
import { first } from 'rxjs/operators';
import { SyncProviderId } from '../../../pfapi/api';
import { SyncLog } from '../../../core/log';
@Component({
selector: 'dialog-sync-initial-cfg',
@ -82,7 +83,7 @@ export class DialogSyncInitialCfgComponent {
if (!this.form.valid) {
// Mark all fields as touched to show validation errors
this.form.markAllAsTouched();
console.warn('Sync form validation failed', this.form.errors);
SyncLog.err('Sync form validation failed', this.form.errors);
return;
}

View file

@ -6,6 +6,7 @@ import { SyncConfig } from '../../features/config/global-config.model';
import { switchMap, tap } from 'rxjs/operators';
import { PrivateCfgByProviderId, SyncProviderId } from '../../pfapi/api';
import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const';
import { SyncLog } from '../../core/log';
const PROP_MAP_TO_FORM: Record<SyncProviderId, keyof SyncConfig | null> = {
[SyncProviderId.LocalFile]: 'localFileSync',
@ -76,7 +77,7 @@ export class SyncConfigService {
return of(result);
}),
tap((v) => console.log('syncSettingsForm$', v)),
tap((v) => SyncLog.log('syncSettingsForm$', v)),
);
async updateEncryptionPassword(

View file

@ -16,6 +16,7 @@ import { takeUntil } from 'rxjs/operators';
import { T } from '../../../t.const';
import { CommonModule } from '@angular/common';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { SyncLog } from '../../../core/log';
@Component({
selector: 'sync-safety-backups',
@ -57,7 +58,7 @@ export class SyncSafetyBackupsComponent implements OnInit, OnDestroy {
const backups = await this._syncSafetyBackupService.getBackups();
this.backups.set(backups);
} catch (error) {
console.error('Failed to load backups:', error);
SyncLog.err('Failed to load backups:', error);
this._snackService.open({
type: 'ERROR',
msg: 'Failed to load safety backups',
@ -77,7 +78,7 @@ export class SyncSafetyBackupsComponent implements OnInit, OnDestroy {
msg: T.F.SYNC.SAFETY_BACKUP.CREATED_SUCCESS,
});
} catch (error) {
console.error('Failed to create manual backup:', error);
SyncLog.err('Failed to create manual backup:', error);
this._snackService.open({
type: 'ERROR',
msg: T.F.SYNC.SAFETY_BACKUP.CREATE_FAILED,
@ -98,7 +99,7 @@ export class SyncSafetyBackupsComponent implements OnInit, OnDestroy {
// Reload the page after restoration
setTimeout(() => window.location.reload(), 1000);
} catch (error) {
console.error('Failed to restore backup:', error);
SyncLog.err('Failed to restore backup:', error);
this._snackService.open({
type: 'ERROR',
msg: error instanceof Error ? error.message : 'Failed to restore backup',
@ -122,7 +123,7 @@ export class SyncSafetyBackupsComponent implements OnInit, OnDestroy {
msg: T.F.SYNC.SAFETY_BACKUP.DELETED_SUCCESS,
});
} catch (error) {
console.error('Failed to delete backup:', error);
SyncLog.err('Failed to delete backup:', error);
this._snackService.open({
type: 'ERROR',
msg: T.F.SYNC.SAFETY_BACKUP.DELETE_FAILED,
@ -145,7 +146,7 @@ export class SyncSafetyBackupsComponent implements OnInit, OnDestroy {
msg: T.F.SYNC.SAFETY_BACKUP.CLEARED_SUCCESS,
});
} catch (error) {
console.error('Failed to clear backups:', error);
SyncLog.err('Failed to clear backups:', error);
this._snackService.open({
type: 'ERROR',
msg: T.F.SYNC.SAFETY_BACKUP.CLEAR_FAILED,

View file

@ -36,6 +36,7 @@ import { PfapiService } from '../../pfapi/pfapi.service';
import { DataInitStateService } from '../../core/data-init/data-init-state.service';
import { Store } from '@ngrx/store';
import { selectCurrentTaskId } from '../../features/tasks/store/task.selectors';
import { SyncLog } from '../../core/log';
const MAX_WAIT_FOR_INITIAL_SYNC = 25000;
const USER_INTERACTION_SYNC_CHECK_THROTTLE_TIME = 15 * 60 * 10000;
@ -194,7 +195,7 @@ export class SyncTriggerService {
);
return merge(
// once immediately
_immediateSyncTrigger$.pipe(tap((v) => console.log('immediate sync trigger', v))),
_immediateSyncTrigger$.pipe(tap((v) => SyncLog.log('immediate sync trigger', v))),
// and once we reset the sync interval for all other triggers
// we do this to reset the audit time to avoid sync checks in short succession
@ -205,8 +206,8 @@ export class SyncTriggerService {
switchMap(() =>
// NOTE: interval changes are only ever executed, if local data was changed
this._onUpdateLocalDataTrigger$.pipe(
// tap((ev) => console.log('__trigger_sync__', ev.appDataKey, ev)),
// tap((ev) => console.log('__trigger_sync__', 'I_ON_UPDATE_LOCAL_DATA', ev)),
// tap((ev) => Log.log('__trigger_sync__', ev.appDataKey, ev)),
// tap((ev) => Log.log('__trigger_sync__', 'I_ON_UPDATE_LOCAL_DATA', ev)),
auditTime(Math.max(syncInterval, SYNC_MIN_INTERVAL)),
// tap((ev) => alert('__trigger_sync after auditTime__')),
),

View file

@ -32,6 +32,7 @@ import { DialogIncompleteSyncComponent } from './dialog-incomplete-sync/dialog-i
import { DialogHandleDecryptErrorComponent } from './dialog-handle-decrypt-error/dialog-handle-decrypt-error.component';
import { DialogIncoherentTimestampsErrorComponent } from './dialog-incoherent-timestamps-error/dialog-incoherent-timestamps-error.component';
import { devError } from '../../util/dev-error';
import { SyncLog } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -127,7 +128,7 @@ export class SyncWrapperService {
return r.status;
case SyncStatus.Conflict:
console.log('Sync conflict detected:', {
SyncLog.log('Sync conflict detected:', {
remote: r.conflictData?.remote.lastUpdate,
local: r.conflictData?.local.lastUpdate,
lastSync: r.conflictData?.local.lastSyncedUpdate,
@ -135,7 +136,7 @@ export class SyncWrapperService {
});
// Enhanced debugging for vector clock issues
console.log('CONFLICT DEBUG - Vector Clock Analysis:', {
SyncLog.log('CONFLICT DEBUG - Vector Clock Analysis:', {
localVectorClock: r.conflictData?.local.vectorClock,
remoteVectorClock: r.conflictData?.remote.vectorClock,
localLastSyncedVectorClock: r.conflictData?.local.lastSyncedVectorClock,
@ -147,21 +148,21 @@ export class SyncWrapperService {
).toPromise();
if (res === 'USE_LOCAL') {
console.log('User chose USE_LOCAL, calling uploadAll(true) with force');
SyncLog.log('User chose USE_LOCAL, calling uploadAll(true) with force');
// Use force upload to skip the meta file check and ensure lastUpdate is updated
await this._pfapiService.pf.uploadAll(true);
console.log('uploadAll(true) completed');
SyncLog.log('uploadAll(true) completed');
return SyncStatus.UpdateRemoteAll;
} else if (res === 'USE_REMOTE') {
await this._pfapiService.pf.downloadAll();
await this._reInitAppAfterDataModelChange();
}
console.log({ res });
SyncLog.log({ res });
return r.status;
}
} catch (error: any) {
console.error(error);
SyncLog.err(error);
if (error instanceof AuthFailSPError) {
this._snackService.open({
@ -191,7 +192,7 @@ export class SyncWrapperService {
error instanceof RevMismatchForModelError ||
error instanceof NoRemoteModelFile
) {
console.log(error, Object.keys(error));
SyncLog.log(error, Object.keys(error));
const modelId = error.additionalLog;
this._matDialog
.open(DialogIncompleteSyncComponent, {
@ -226,7 +227,7 @@ export class SyncWrapperService {
return 'HANDLED_ERROR';
} else if (error?.message === 'Sync already in progress') {
// Silently ignore concurrent sync attempts
console.log('Sync already in progress, skipping concurrent sync attempt');
SyncLog.log('Sync already in progress, skipping concurrent sync attempt');
return 'HANDLED_ERROR';
} else {
const errStr = getSyncErrorStr(error);
@ -307,7 +308,7 @@ export class SyncWrapperService {
}
}
} catch (error) {
console.error(error);
SyncLog.err(error);
this._snackService.open({
// TODO don't limit snack to dropbox
msg: T.F.DROPBOX.S.UNABLE_TO_GENERATE_PKCE_CHALLENGE,
@ -336,7 +337,7 @@ export class SyncWrapperService {
}
private async _reInitAppAfterDataModelChange(): Promise<void> {
console.log('Starting data re-initialization after sync...');
SyncLog.log('Starting data re-initialization after sync...');
try {
await Promise.all([
@ -344,11 +345,11 @@ export class SyncWrapperService {
this._reminderService.reloadFromDatabase(),
]);
console.log('Data re-initialization complete');
SyncLog.log('Data re-initialization complete');
// Signal that data reload is complete
this._dataReloadComplete$.next();
} catch (error) {
console.error('Error during data re-initialization:', error);
SyncLog.err('Error during data re-initialization:', error);
throw error;
}
}

View file

@ -31,6 +31,7 @@ import { SyncWrapperService } from './sync-wrapper.service';
import { getSyncErrorStr } from './get-sync-error-str';
import { InitialPwaUpdateCheckService } from '../../core/initial-pwa-update-check.service';
import { DataInitStateService } from '../../core/data-init/data-init-state.service';
import { SyncLog } from '../../core/log';
@Injectable()
export class SyncEffects {
@ -72,7 +73,7 @@ export class SyncEffects {
this._execBeforeCloseService.setDone(SYNC_BEFORE_CLOSE_ID);
})
.catch((e: unknown) => {
console.error(e);
SyncLog.err(e);
this._snackService.open({
msg: T.F.DROPBOX.S.SYNC_ERROR,
type: 'ERROR',
@ -132,7 +133,7 @@ export class SyncEffects {
// this._wasJustEnabled$.pipe(take(1), mapTo('SYNC_DBX_AFTER_ENABLE')),
),
),
tap((x) => console.log('sync(effect).....', x)),
tap((x) => SyncLog.log('sync(effect).....', x)),
withLatestFrom(isOnline$),
// don't run multiple after each other when dialog is open
exhaustMap(([trigger, isOnline]) => {

View file

@ -43,6 +43,7 @@ import { createPluginShortcutFormItems } from '../../features/config/form-cfgs/p
import { PluginService } from '../../plugins/plugin.service';
import { PluginShortcutCfg } from '../../plugins/plugin-api.model';
import { ThemeSelectorComponent } from '../../core/theme/theme-selector/theme-selector.component';
import { Log } from '../../core/log';
@Component({
selector: 'config-page',
@ -96,7 +97,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy {
};
}),
)
.pipe(tap((v) => console.log('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXA', v)));
.pipe(tap((v) => Log.log('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXA', v)));
private _subs: Subscription = new Subscription();
@ -131,7 +132,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy {
// Subscribe to plugin shortcuts changes for live updates
this._subs.add(
this._pluginBridgeService.shortcuts$.subscribe((shortcuts) => {
console.log('Plugin shortcuts changed:', { shortcuts });
Log.log('Plugin shortcuts changed:', { shortcuts });
this._updateKeyboardFormWithPluginShortcuts(shortcuts);
}),
);
@ -144,7 +145,7 @@ export class ConfigPageComponent implements OnInit, OnDestroy {
);
if (keyboardFormIndex === -1) {
console.warn('Keyboard form section not found');
Log.err('Keyboard form section not found');
return;
}
@ -172,9 +173,9 @@ export class ConfigPageComponent implements OnInit, OnDestroy {
if (shortcuts.length > 0) {
const pluginShortcutItems = createPluginShortcutFormItems(shortcuts);
newItems = [...filteredItems, ...pluginShortcutItems];
console.log(`Updated keyboard form with ${shortcuts.length} plugin shortcuts`);
Log.log(`Updated keyboard form with ${shortcuts.length} plugin shortcuts`);
} else {
console.log('No plugin shortcuts to add to keyboard form');
Log.log('No plugin shortcuts to add to keyboard form');
}
// Create a new keyboard section object to trigger change detection

View file

@ -1,4 +1,5 @@
import { CompressError, DecompressError } from '../errors/errors';
import { Log } from '../../../core/log';
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
export async function compressWithGzipToString(input: string): Promise<string> {
@ -24,7 +25,7 @@ export async function compressWithGzipToString(input: string): Promise<string> {
return base64;
} catch (error) {
console.error(error);
Log.err(error);
throw new CompressError(error);
}
}
@ -51,7 +52,7 @@ export async function decompressGzipFromString(
// SyncLog.normal( 'Decompression stats', { decompressedLength: decoded.length });
return decoded;
} catch (error) {
console.error(error);
Log.err(error);
throw new DecompressError(error);
}
}

View file

@ -1,6 +1,7 @@
import { DatabaseAdapter } from './database-adapter.model';
import { SyncLog } from '../../../core/log';
import { devError } from '../../../util/dev-error';
import { Log } from '../../../core/log';
export class Database {
private static readonly L = 'Database';
@ -76,27 +77,27 @@ export class Database {
async remove(key: string, isIgnoreDBLock = false): Promise<unknown> {
this._lastParams = { a: 'remove', key };
if (this._isLocked && !isIgnoreDBLock) {
console.warn('Blocking write during lock');
Log.err('Blocking write during lock');
return;
}
try {
return await this._adapter.remove(key);
} catch (e) {
console.warn('DB Remove Error: Last Params,', this._lastParams);
Log.err('DB Remove Error: Last Params,', this._lastParams);
return this._errorHandler(e as Error, this.remove, [key]);
}
}
async clearDatabase(isIgnoreDBLock = false): Promise<unknown> {
if (this._isLocked && !isIgnoreDBLock) {
console.warn('Blocking write during lock');
Log.err('Blocking write during lock');
return;
}
this._lastParams = { a: 'clearDatabase' };
try {
return await this._adapter.clearDatabase();
} catch (e) {
console.warn('DB Clear Error: Last Params,', this._lastParams);
Log.err('DB Clear Error: Last Params,', this._lastParams);
return this._errorHandler(e as Error, this.clearDatabase, []);
}
}

View file

@ -86,17 +86,17 @@ export async function decrypt(data: string, password: string): Promise<string> {
// TESTING CODE
// export const testCrypto = async (): Promise<void> => {
// const enc = await encrypt('HAHAHHA', '1234');
// console.log('enc', enc);
// Log.log('enc', enc);
// decrypt(enc, '1234')
// .then((r) => {
// console.log('YEAH', r);
// Log.log('YEAH', r);
// })
// .catch((r) => {
// console.log('NOOO', r);
// Log.log('NOOO', r);
// });
//
// const decrypted = await decrypt(enc, '1234');
// console.log('decrypted', decrypted);
// Log.log('decrypted', decrypted);
// };
//
// testCrypto();

View file

@ -1,5 +1,6 @@
import { IValidation } from 'typia';
import { AllModelData } from '../pfapi.model';
import { Log } from '../../../core/log';
class AdditionalLogErrorBase<T = unknown[]> extends Error {
additionalLog: T;
@ -10,11 +11,11 @@ class AdditionalLogErrorBase<T = unknown[]> extends Error {
if (additional.length > 0) {
// SyncLog.critical( this.name, ...additional);
console.log(this.name, ...additional);
Log.log(this.name, ...additional);
try {
console.log('additional error log: ' + JSON.stringify(additional));
Log.log('additional error log: ' + JSON.stringify(additional));
} catch (e) {
console.log('additional error log not stringified: ', additional, e);
Log.log('additional error log not stringified: ', additional, e);
}
}
this.additionalLog = additional as T;
@ -201,24 +202,24 @@ export class ModelValidationError extends Error {
e?: unknown;
}) {
super('ModelValidationError');
console.log(`ModelValidationError for model ${params.id}:`, params);
Log.log(`ModelValidationError for model ${params.id}:`, params);
if (params.validationResult) {
console.log('validation result: ', params.validationResult);
Log.log('validation result: ', params.validationResult);
try {
if ('errors' in params.validationResult) {
const str = JSON.stringify(params.validationResult.errors);
console.log('validation errors: ' + str);
Log.log('validation errors: ' + str);
this.additionalLog = `Model: ${params.id}, Errors: ${str.substring(0, 400)}`;
}
} catch (e) {
console.error('Error stringifying validation errors:', e);
Log.err('Error stringifying validation errors:', e);
}
}
if (params.e) {
console.log('Additional error:', params.e);
Log.log('Additional error:', params.e);
}
}
}
@ -229,17 +230,17 @@ export class DataValidationFailedError extends Error {
constructor(validationResult: IValidation<AllModelData<any>>) {
super('DataValidationFailedError');
console.log('validation result: ', validationResult);
Log.log('validation result: ', validationResult);
try {
if ('errors' in validationResult) {
const str = JSON.stringify(validationResult.errors);
console.log('validation errors_: ' + str);
Log.log('validation errors_: ' + str);
this.additionalLog = str.substring(0, 400);
}
console.log('validation result_: ' + JSON.stringify(validationResult));
Log.log('validation result_: ' + JSON.stringify(validationResult));
} catch (e) {
console.error('Failed to stringify validation errors:', e);
Log.err('Failed to stringify validation errors:', e);
}
}
}

View file

@ -36,6 +36,7 @@ import { promiseTimeout } from '../../util/promise-timeout';
import { PFEventEmitter } from './util/events';
import { MigrationService } from './migration/migration.service';
import { IValidation } from 'typia';
import { Log } from '../../core/log';
export class Pfapi<const MD extends ModelCfgs> {
private static _wasInstanceCreated = false;
@ -371,10 +372,10 @@ export class Pfapi<const MD extends ModelCfgs> {
await this.tmpBackupService.save(await this.getAllSyncModelData());
} catch (error) {
SyncLog.critical(this.importAllSycModelData.name, error);
console.warn(
Log.err(
'Could not create valid backup. Onwards on the highway throug the Danger Zone!',
);
console.error(error);
Log.err(error);
}
}
@ -386,7 +387,7 @@ export class Pfapi<const MD extends ModelCfgs> {
const modelData = data[modelId];
const modelCtrl = this.m[modelId];
if (!modelCtrl) {
console.warn('ModelId without Ctrl', modelId, modelData);
Log.err('ModelId without Ctrl', modelId, modelData);
if (
SKIPPED_MODEL_IDS.includes(modelId) ||
isSkipLegacyWarnings ||

View file

@ -1,5 +1,6 @@
/* eslint-disable */
import { Capacitor, registerPlugin } from '@capacitor/core';
import { Log } from '../../../../../../core/log';
// Define the plugin interface for SAF operations
export interface SafPlugin {
@ -70,7 +71,7 @@ export class SafService {
const result = await SafBridge.checkUriPermission({ uri });
return result.hasPermission;
} catch (error) {
console.error('Error checking SAF permission:', error);
Log.err('Error checking SAF permission:', error);
return false;
}
}
@ -109,7 +110,7 @@ export class SafService {
const result = await SafBridge.checkFileExists({ uri, fileName });
return result.exists;
} catch (error) {
console.error('Error checking file existence:', error);
Log.err('Error checking file existence:', error);
return false;
}
}

View file

@ -1,4 +1,5 @@
import { SyncLog } from '../../../core/log';
import { Log } from '../../../core/log';
/**
* Vector Clock implementation for distributed synchronization
@ -124,15 +125,15 @@ export const compareVectorClocks = (
): VectorClockComparison => {
// Handle null/undefined cases
if (isVectorClockEmpty(a) && isVectorClockEmpty(b)) {
console.warn('BOTH VECTOR CLOCKS EMPTY!!!');
Log.err('BOTH VECTOR CLOCKS EMPTY!!!');
return VectorClockComparison.CONCURRENT;
}
if (isVectorClockEmpty(a)) {
console.warn('EMPTY VECTOR CLOCK a !!!');
Log.err('EMPTY VECTOR CLOCK a !!!');
return VectorClockComparison.CONCURRENT;
}
if (isVectorClockEmpty(b)) {
console.warn('EMPTY VECTOR CLOCK b !!!');
Log.err('EMPTY VECTOR CLOCK b !!!');
return VectorClockComparison.CONCURRENT;
}

View file

@ -17,11 +17,12 @@ import {
initialBoardsState,
} from '../../features/boards/store/boards.reducer';
import { DEFAULT_BOARD_CFG, DEFAULT_PANEL_CFG } from '../../features/boards/boards.const';
import { Log } from '../../core/log';
export const crossModelMigration2: CrossModelMigrateFn = ((
fullData: AppDataCompleteLegacy,
): AppDataCompleteNew => {
console.log('____________________Migrate2__________________');
Log.log('____________________Migrate2__________________');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { lastLocalSyncModelChange, lastArchiveUpdate, taskArchive, ...copy } = fullData;
@ -33,10 +34,10 @@ export const crossModelMigration2: CrossModelMigrateFn = ((
Object.keys((fullData as any as AppDataCompleteNew).timeTracking.project).length
) {
// If time tracking is already migrated, return the original data
console.warn('already migrated despite old model version!!!');
Log.err('already migrated despite old model version!!!');
return fullData as any as AppDataCompleteNew;
}
console.log(':::::::::::crossModelMigration2::::::::::::::');
Log.log(':::::::::::crossModelMigration2::::::::::::::');
// Migrate project time tracking data
const projectTimeTracking: TTWorkContextSessionMap = Object.keys(
@ -126,7 +127,7 @@ export const crossModelMigration2: CrossModelMigrateFn = ((
},
{} as TTWorkContextSessionMap,
);
console.log('________________________________________________________', {
Log.log('________________________________________________________', {
copy,
projectTimeTracking,
tagTimeTracking,

View file

@ -13,13 +13,14 @@ import {
import { ProjectState } from '../../features/project/project.model';
import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const';
import { issueProviderInitialState } from '../../features/issue/store/issue-provider.reducer';
import { Log } from '../../core/log';
const LEGACY_INBOX_PROJECT_ID = 'INBOX' as const;
export const crossModelMigration3: CrossModelMigrateFn = ((
fullData: AppDataCompleteNew,
): AppDataCompleteNew => {
console.log('____________________Migrate3__________________');
Log.log('____________________Migrate3__________________');
const copy = fullData;
if (copy.planner) {
@ -153,7 +154,7 @@ export const crossModelMigration3: CrossModelMigrateFn = ((
}
});
console.log(copy);
Log.log(copy);
return copy;
}) as CrossModelMigrateFn;

View file

@ -3,12 +3,13 @@ import { CrossModelMigrateFn } from '../api';
import { TaskCopy } from '../../features/tasks/task.model';
import { EntityState } from '@ngrx/entity';
import { TODAY_TAG } from '../../features/tag/tag.const';
import { Log } from '../../core/log';
export const crossModelMigration4: CrossModelMigrateFn = ((
fullData: AppDataCompleteNew,
): AppDataCompleteNew => {
// throw new Error('Migration 4 is not implemented yet');
console.log('____________________Migrate4__________________');
Log.log('____________________Migrate4__________________');
const copy = fullData;
if (!Array.isArray(copy.improvement.hiddenImprovementBannerItems)) {
@ -22,7 +23,7 @@ export const crossModelMigration4: CrossModelMigrateFn = ((
// @ts-ignore
// copy.tag.entities[TODAY_TAG.id].taskIds = [];
console.log(copy);
Log.log(copy);
return copy;
}) as CrossModelMigrateFn;

View file

@ -1,13 +1,14 @@
import { AppDataCompleteNew } from '../pfapi-config';
import { CrossModelMigrateFn } from '../api';
import { TODAY_TAG } from '../../features/tag/tag.const';
import { Log } from '../../core/log';
// eslint-disable-next-line @typescript-eslint/naming-convention
export const crossModelMigration4_1: CrossModelMigrateFn = ((
fullData: AppDataCompleteNew,
): AppDataCompleteNew => {
// throw new Error('Migration 4 is not implemented yet');
console.log('____________________Migrate4.1__________________');
Log.log('____________________Migrate4.1__________________');
const copy = fullData;
Object.keys(copy.taskRepeatCfg.entities).forEach((id) => {
@ -21,6 +22,6 @@ export const crossModelMigration4_1: CrossModelMigrateFn = ((
// @ts-ignore
// copy.tag.entities[TODAY_TAG.id].taskIds = [];
console.log(copy);
Log.log(copy);
return copy;
}) as CrossModelMigrateFn;

View file

@ -55,6 +55,7 @@ import { CROSS_MODEL_MIGRATIONS } from './migrate/cross-model-migrations';
import { appDataValidators, validateAllData } from './validate/validation-fn';
import { fixEntityStateConsistency } from '../util/check-fix-entity-state-consistency';
import { IValidation } from 'typia';
import { Log } from '../core/log';
import {
initialPluginMetaDataState,
initialPluginUserDataState,
@ -268,7 +269,7 @@ export const PFAPI_CFG: PfapiBaseCfg<PfapiAllModelCfg> = {
return r;
},
onDbError: (err) => {
console.error(err);
Log.err(err);
alert('DB ERROR: ' + err);
},
repair: (data: any, errors: IValidation.IError[]) => {

View file

@ -33,6 +33,7 @@ import {
import { fromPfapiEvent, pfapiEventAndInitialAfter } from './pfapi-helper';
import { DataInitStateService } from '../core/data-init/data-init-state.service';
import { GlobalProgressBarService } from '../core-ui/global-progress-bar/global-progress-bar.service';
import { Log } from '../core/log';
@Injectable({
providedIn: 'root',
@ -59,7 +60,7 @@ export class PfapiService {
).pipe(
shareReplay(1),
distinctUntilChanged(),
// tap((v) => console.log(`isSyncProviderEnabledAndReady$`, v)),
// tap((v) => Log.log(`isSyncProviderEnabledAndReady$`, v)),
);
public readonly currentProviderPrivateCfg$ = pfapiEventAndInitialAfter(
@ -105,9 +106,9 @@ export class PfapiService {
constructor() {
// TODO check why it gets triggered twice always
// this.syncState$.subscribe((v) => console.log(`syncState$`, v));
// this.syncState$.subscribe((v) => Log.log(`syncState$`, v));
this.isSyncInProgress$.subscribe((v) => {
// console.log('isSyncInProgress$', v);
// Log.log('isSyncInProgress$', v);
if (v) {
this._globalProgressBarService.countUp('SYNC');
} else {
@ -127,7 +128,7 @@ export class PfapiService {
});
}
} catch (e) {
console.error(e);
Log.err(e);
alert('Unable to set sync provider. Please check your settings.');
}
});

View file

@ -1,6 +1,7 @@
import { AppDataCompleteNew } from '../pfapi-config';
import { IValidation } from 'typia';
import { DEFAULT_GLOBAL_CONFIG } from '../../features/config/default-global-config.const';
import { Log } from '../../core/log';
export const autoFixTypiaErrors = (
data: AppDataCompleteNew,
@ -15,7 +16,7 @@ export const autoFixTypiaErrors = (
const path = error.path.replace('$input.', '');
const keys = parsePath(path);
const value = getValueByPath(data, keys);
console.warn('Auto-fixing error:', error, keys, value);
Log.err('Auto-fixing error:', error, keys, value);
if (
error.expected.includes('number') &&
@ -24,7 +25,7 @@ export const autoFixTypiaErrors = (
) {
const parsedValue = parseFloat(value);
setValueByPath(data, keys, parsedValue);
console.warn(`Fixed: ${path} from string "${value}" to number ${parsedValue}`);
Log.err(`Fixed: ${path} from string "${value}" to number ${parsedValue}`);
} else if (keys[0] === 'globalConfig') {
const defaultValue = getValueByPath(DEFAULT_GLOBAL_CONFIG, keys.slice(1));
setValueByPath(data, keys, defaultValue);
@ -33,29 +34,27 @@ export const autoFixTypiaErrors = (
);
} else if (error.expected.includes('undefined') && value === null) {
setValueByPath(data, keys, undefined);
console.warn(`Fixed: ${path} from null to undefined`);
Log.err(`Fixed: ${path} from null to undefined`);
} else if (error.expected.includes('null') && value === 'null') {
setValueByPath(data, keys, null);
console.warn(`Fixed: ${path} from string null to null`);
Log.err(`Fixed: ${path} from string null to null`);
} else if (error.expected.includes('undefined') && value === 'null') {
setValueByPath(data, keys, undefined);
console.warn(`Fixed: ${path} from string null to null`);
Log.err(`Fixed: ${path} from string null to null`);
} else if (error.expected.includes('null') && value === undefined) {
setValueByPath(data, keys, null);
console.warn(`Fixed: ${path} from undefined to null`);
Log.err(`Fixed: ${path} from undefined to null`);
} else if (error.expected.includes('boolean') && !value) {
setValueByPath(data, keys, false);
console.warn(`Fixed: ${path} to false (was ${value})`);
Log.err(`Fixed: ${path} to false (was ${value})`);
} else if (keys[0] === 'task' && error.expected.includes('number')) {
// If the value is a string that can be parsed to a number, parse it
if (typeof value === 'string' && !isNaN(parseFloat(value))) {
setValueByPath(data, keys, parseFloat(value));
console.warn(
`Fixed: ${path} from string "${value}" to number ${parseFloat(value)}`,
);
Log.err(`Fixed: ${path} from string "${value}" to number ${parseFloat(value)}`);
} else {
setValueByPath(data, keys, 0);
console.warn(`Fixed: ${path} to 0 (was ${value})`);
Log.err(`Fixed: ${path} to 0 (was ${value})`);
}
} else if (
keys[0] === 'simpleCounter' &&
@ -67,7 +66,7 @@ export const autoFixTypiaErrors = (
) {
// Fix for issue #4593: simpleCounter countOnDay null value
setValueByPath(data, keys, 0);
console.warn(`Fixed: ${path} from null to 0 for simpleCounter`);
Log.err(`Fixed: ${path} from null to 0 for simpleCounter`);
}
}
});
@ -109,7 +108,7 @@ const setValueByPath = <T extends object>(
value: any,
): void => {
if (!Array.isArray(path) || path.length === 0) return;
console.warn('Auto-fixing error =>', path, value);
Log.err('Auto-fixing error =>', path, value);
let current: any = obj;
for (let i = 0; i < path.length - 1; i++) {

View file

@ -15,6 +15,7 @@ import { AppDataCompleteNew } from '../pfapi-config';
import { INBOX_PROJECT } from '../../features/project/project.const';
import { autoFixTypiaErrors } from './auto-fix-typia-errors';
import { IValidation } from 'typia';
import { Log } from '../../core/log';
// TODO improve later
const ENTITY_STATE_KEYS: (keyof AppDataCompleteLegacy)[] = ALL_ENTITY_MODEL_KEYS;
@ -123,7 +124,7 @@ const _removeDuplicatesFromArchive = (data: AppDataCompleteNew): AppDataComplete
}
});
if (duplicateIds.length > 0) {
console.log(duplicateIds.length + ' duplicates removed from archive.');
Log.log(duplicateIds.length + ' duplicates removed from archive.');
}
}
return data;
@ -153,7 +154,7 @@ const _moveArchivedSubTasksToUnarchivedParents = (
.map((id: string) => taskArchiveState.entities[id] as TaskCopy)
.filter((t: TaskCopy) => t.parentId && !taskArchiveState.ids.includes(t.parentId));
console.log('orphanArchivedSubTasks', orphanArchivedSubTasks);
Log.log('orphanArchivedSubTasks', orphanArchivedSubTasks);
orphanArchivedSubTasks.forEach((t: TaskCopy) => {
// delete archived if duplicate
if (taskState.ids.includes(t.id as string)) {
@ -197,7 +198,7 @@ const _moveUnArchivedSubTasksToArchivedParents = (
.map((id: string) => taskState.entities[id] as TaskCopy)
.filter((t: TaskCopy) => t.parentId && !taskState.ids.includes(t.parentId));
console.log('orphanUnArchivedSubTasks', orphanUnArchivedSubTasks);
Log.log('orphanUnArchivedSubTasks', orphanUnArchivedSubTasks);
orphanUnArchivedSubTasks.forEach((t: TaskCopy) => {
// delete un-archived if duplicate
if (taskArchiveState.ids.includes(t.id as string)) {
@ -275,9 +276,7 @@ const _removeMissingTasksFromListsOrRestoreFromArchive = (
);
if (taskIdsToRestoreFromArchive.length > 0) {
console.log(
taskIdsToRestoreFromArchive.length + ' missing tasks restored from archive.',
);
Log.log(taskIdsToRestoreFromArchive.length + ' missing tasks restored from archive.');
}
return data;
};
@ -326,7 +325,7 @@ const _addOrphanedTasksToProjectLists = (
});
if (orphanedTaskIds.length > 0) {
console.log(orphanedTaskIds.length + ' orphaned tasks found & restored.');
Log.log(orphanedTaskIds.length + ' orphaned tasks found & restored.');
}
return data;
@ -349,7 +348,7 @@ const _addInboxProjectIdIfNecessary = (data: AppDataCompleteNew): AppDataComplet
taskIds.forEach((id) => {
const t = task.entities[id] as TaskCopy;
if (!t.projectId) {
console.log('Set inbox project id for task ' + t.id);
Log.log('Set inbox project id for task ' + t.id);
// @ts-ignore
data.project.entities[INBOX_PROJECT.id].taskIds = [
...(data.project.entities[INBOX_PROJECT.id]!.taskIds as string[]),
@ -364,13 +363,13 @@ const _addInboxProjectIdIfNecessary = (data: AppDataCompleteNew): AppDataComplet
}
});
console.log(taskArchiveIds);
console.log(Object.keys(archiveYoung.task.entities));
Log.log(taskArchiveIds);
Log.log(Object.keys(archiveYoung.task.entities));
taskArchiveIds.forEach((id) => {
const t = archiveYoung.task.entities[id] as TaskCopy;
if (!t.projectId) {
console.log('Set inbox project for missing project id from archive task ' + t.id);
Log.log('Set inbox project for missing project id from archive task ' + t.id);
t.projectId = INBOX_PROJECT.id;
}
// while we are at it, we also cleanup the today tag
@ -406,19 +405,19 @@ const _removeNonExistentProjectIdsFromTasks = (
taskIds.forEach((id) => {
const t = task.entities[id] as TaskCopy;
if (t.projectId && !projectIds.includes(t.projectId)) {
console.log('Delete missing project id from task ' + t.projectId);
Log.log('Delete missing project id from task ' + t.projectId);
// @ts-ignore
delete t.projectId;
}
});
console.log(taskArchiveIds);
console.log(Object.keys(archiveYoung.task.entities));
Log.log(taskArchiveIds);
Log.log(Object.keys(archiveYoung.task.entities));
taskArchiveIds.forEach((id) => {
const t = archiveYoung.task.entities[id] as TaskCopy;
if (t.projectId && !projectIds.includes(t.projectId)) {
console.log('Delete missing project id from archive task ' + t.projectId);
Log.log('Delete missing project id from archive task ' + t.projectId);
// @ts-ignore
delete t.projectId;
}
@ -458,7 +457,7 @@ const _removeNonExistentTagsFromTasks = (
(tagId) => !tagIds.includes(tagId) && tagId !== TODAY_TAG.id,
);
if (removedTags.length > 0) {
console.log(
Log.log(
`Removing non-existent tags from task ${t.id}: ${removedTags.join(', ')}`,
);
removedCount += removedTags.length;
@ -478,7 +477,7 @@ const _removeNonExistentTagsFromTasks = (
(tagId) => !tagIds.includes(tagId) && tagId !== TODAY_TAG.id,
);
if (removedTags.length > 0) {
console.log(
Log.log(
`Removing non-existent tags from archive task ${t.id}: ${removedTags.join(', ')}`,
);
removedCount += removedTags.length;
@ -489,7 +488,7 @@ const _removeNonExistentTagsFromTasks = (
});
if (removedCount > 0) {
console.log(`Total non-existent tags removed from tasks: ${removedCount}`);
Log.log(`Total non-existent tags removed from tasks: ${removedCount}`);
}
return data;
@ -504,7 +503,7 @@ const _removeNonExistentProjectIdsFromIssueProviders = (
issueProviderIds.forEach((id) => {
const t = issueProvider.entities[id] as IssueProvider;
if (t.defaultProjectId && !projectIds.includes(t.defaultProjectId)) {
console.log('Delete missing project id from issueProvider ' + t.defaultProjectId);
Log.log('Delete missing project id from issueProvider ' + t.defaultProjectId);
t.defaultProjectId = null;
}
});
@ -522,18 +521,14 @@ const _removeNonExistentProjectIdsFromTaskRepeatCfg = (
const repeatCfg = taskRepeatCfg.entities[id] as TaskRepeatCfgCopy;
if (repeatCfg.projectId && !projectIds.includes(repeatCfg.projectId)) {
if (repeatCfg.tagIds.length) {
console.log(
'Delete missing project id from task repeat cfg ' + repeatCfg.projectId,
);
Log.log('Delete missing project id from task repeat cfg ' + repeatCfg.projectId);
repeatCfg.projectId = null;
} else {
taskRepeatCfg.ids = (taskRepeatCfg.ids as string[]).filter(
(rid: string) => rid !== repeatCfg.id,
);
delete taskRepeatCfg.entities[repeatCfg.id];
console.log(
'Delete task repeat cfg with missing project id' + repeatCfg.projectId,
);
Log.log('Delete task repeat cfg with missing project id' + repeatCfg.projectId);
}
}
});
@ -547,7 +542,7 @@ const _cleanupNonExistingTasksFromLists = (
projectIds.forEach((pid) => {
const projectItem = data.project.entities[pid];
if (!projectItem) {
console.log(data.project);
Log.log(data.project);
throw new Error('No project');
}
(projectItem as ProjectCopy).taskIds = projectItem.taskIds.filter(
@ -562,7 +557,7 @@ const _cleanupNonExistingTasksFromLists = (
.map((id) => data.tag.entities[id])
.forEach((tagItem) => {
if (!tagItem) {
console.log(data.tag);
Log.log(data.tag);
throw new Error('No tag');
}
(tagItem as TagCopy).taskIds = tagItem.taskIds.filter(
@ -579,7 +574,7 @@ const _cleanupNonExistingNotesFromLists = (
projectIds.forEach((pid) => {
const projectItem = data.project.entities[pid];
if (!projectItem) {
console.log(data.project);
Log.log(data.project);
throw new Error('No project');
}
(projectItem as ProjectCopy).noteIds = (projectItem as ProjectCopy).noteIds
@ -600,7 +595,7 @@ const _fixOrphanedNotes = (data: AppDataCompleteNew): AppDataCompleteNew => {
noteIds.forEach((nId) => {
const note = data.note.entities[nId];
if (!note) {
console.log(data.note);
Log.log(data.note);
throw new Error('No note');
}
// missing project case
@ -608,7 +603,7 @@ const _fixOrphanedNotes = (data: AppDataCompleteNew): AppDataCompleteNew => {
if (data.project.entities[note.projectId]) {
// @ts-ignore
if (!data.project.entities[note.projectId]!.noteIds.includes(note.id)) {
console.log(
Log.log(
'Add orphaned note back to project list ' + note.projectId + ' ' + note.id,
);
// @ts-ignore
@ -618,7 +613,7 @@ const _fixOrphanedNotes = (data: AppDataCompleteNew): AppDataCompleteNew => {
];
}
} else {
console.log('Delete missing project id from note ' + note.id);
Log.log('Delete missing project id from note ' + note.id);
note.projectId = null;
// @ts-ignore
if (!data.note.todayOrder.includes(note.id)) {
@ -627,7 +622,7 @@ const _fixOrphanedNotes = (data: AppDataCompleteNew): AppDataCompleteNew => {
}
} // orphaned note case
else if (!data.note.todayOrder.includes(note.id)) {
console.log('Add orphaned note to today list ' + note.id);
Log.log('Add orphaned note to today list ' + note.id);
// @ts-ignore
if (!data.note.todayOrder.includes(note.id)) {
data.note.todayOrder = [...data.note.todayOrder, note.id];
@ -644,7 +639,7 @@ const _fixInconsistentProjectId = (data: AppDataCompleteNew): AppDataCompleteNew
.map((id) => data.project.entities[id])
.forEach((projectItem) => {
if (!projectItem) {
console.log(data.project);
Log.log(data.project);
throw new Error('No project');
}
projectItem.taskIds.forEach((tid) => {
@ -689,7 +684,7 @@ const _fixInconsistentTagId = (data: AppDataCompleteNew): AppDataCompleteNew =>
.map((id) => data.tag.entities[id])
.forEach((tagItem) => {
if (!tagItem) {
console.log(data.tag);
Log.log(data.tag);
throw new Error('No tag');
}
tagItem.taskIds.forEach((tid) => {
@ -713,7 +708,7 @@ const _setTaskProjectIdAccordingToParent = (
.map((id) => data.task.entities[id])
.forEach((taskItem) => {
if (!taskItem) {
console.log(data.task);
Log.log(data.task);
throw new Error('No task');
}
if (taskItem.subTaskIds) {
@ -735,7 +730,7 @@ const _setTaskProjectIdAccordingToParent = (
.map((id) => data.archiveYoung.task.entities[id])
.forEach((taskItem) => {
if (!taskItem) {
console.log(data.archiveYoung.task);
Log.log(data.archiveYoung.task);
throw new Error('No archive task');
}
if (taskItem.subTaskIds) {
@ -762,7 +757,7 @@ const _cleanupOrphanedSubTasks = (data: AppDataCompleteNew): AppDataCompleteNew
.map((id) => data.task.entities[id])
.forEach((taskItem) => {
if (!taskItem) {
console.log(data.task);
Log.log(data.task);
throw new Error('No task');
}
@ -771,7 +766,7 @@ const _cleanupOrphanedSubTasks = (data: AppDataCompleteNew): AppDataCompleteNew
while (i >= 0) {
const sid = taskItem.subTaskIds[i];
if (!data.task.entities[sid]) {
console.log('Delete orphaned sub task for ', taskItem);
Log.log('Delete orphaned sub task for ', taskItem);
taskItem.subTaskIds.splice(i, 1);
}
i -= 1;
@ -784,7 +779,7 @@ const _cleanupOrphanedSubTasks = (data: AppDataCompleteNew): AppDataCompleteNew
.map((id) => data.archiveYoung.task.entities[id])
.forEach((taskItem) => {
if (!taskItem) {
console.log(data.archiveYoung.task);
Log.log(data.archiveYoung.task);
throw new Error('No archive task');
}
@ -793,7 +788,7 @@ const _cleanupOrphanedSubTasks = (data: AppDataCompleteNew): AppDataCompleteNew
while (i >= 0) {
const sid = taskItem.subTaskIds[i];
if (!data.archiveYoung.task.entities[sid]) {
console.log('Delete orphaned archive sub task for ', taskItem);
Log.log('Delete orphaned archive sub task for ', taskItem);
taskItem.subTaskIds.splice(i, 1);
}
i -= 1;

View file

@ -1,6 +1,7 @@
import { devError } from '../../util/dev-error';
import { environment } from '../../../environments/environment';
import { AppDataCompleteNew } from '../pfapi-config';
import { Log } from '../../core/log';
let errorCount = 0;
let lastValidityError: string;
@ -47,10 +48,10 @@ export const getLastValidityError = (): string | undefined => lastValidityError;
const _validityError = (errTxt: string, additionalInfo?: any): void => {
if (additionalInfo) {
console.log('Validity Error Info: ', additionalInfo);
Log.log('Validity Error Info: ', additionalInfo);
if (environment.production) {
try {
console.log('Validity Error Info string: ', JSON.stringify(additionalInfo));
Log.log('Validity Error Info string: ', JSON.stringify(additionalInfo));
} catch (e) {}
}
}
@ -58,9 +59,9 @@ const _validityError = (errTxt: string, additionalInfo?: any): void => {
devError(errTxt);
} else {
if (errorCount === 4) {
console.warn('too many validity errors, only logging from now on');
Log.err('too many validity errors, only logging from now on');
}
console.error(errTxt);
Log.err(errTxt);
}
lastValidityError = errTxt;
errorCount++;

View file

@ -20,6 +20,7 @@ import { ObstructionState } from '../../features/metric/obstruction/obstruction.
import { GlobalConfigState } from '../../features/config/global-config.model';
import { AppDataCompleteNew } from '../pfapi-config';
import { ValidationResult } from '../api/pfapi.model';
import { Log } from '../../core/log';
import {
PluginUserDataState,
PluginMetaDataState,
@ -110,7 +111,7 @@ export const appDataValidators: {
const validateArchiveModel = <R>(d: ArchiveModel | R): ValidationResult<ArchiveModel> => {
const r = _validateArchive(d);
if (!r.success) {
console.log('Validation failed', (r as any)?.errors, r.data);
Log.log('Validation failed', (r as any)?.errors, r.data);
}
if (!isEntityStateConsistent((d as ArchiveModel).task)) {
return {
@ -135,7 +136,7 @@ const _wrapValidate = <R>(
isEntityCheck = false,
): ValidationResult<R> => {
if (!result.success) {
console.log('Validation failed', (result as any)?.errors, result, d);
Log.log('Validation failed', (result as any)?.errors, result, d);
}
if (isEntityCheck && !isEntityStateConsistent(d as any)) {
return {

View file

@ -20,6 +20,7 @@ import {
PluginManifest,
} from '@super-productivity/plugin-api';
import { PluginBridgeService } from './plugin-bridge.service';
import { Log } from '../core/log';
import {
taskCopyToTaskData,
projectCopyToProjectData,
@ -66,7 +67,7 @@ export class PluginAPI implements PluginAPIInterface {
}
pluginHooks.get(hook)!.push(fn);
console.log(`Plugin ${this._pluginId} registered hook: ${hook}`);
Log.log(`Plugin ${this._pluginId} registered hook: ${hook}`);
// Register hook with bridge
this._pluginBridge.registerHook(this._pluginId, hook, fn);
@ -74,14 +75,14 @@ export class PluginAPI implements PluginAPIInterface {
registerHeaderButton(headerBtnCfg: PluginHeaderBtnCfg): void {
this._headerButtons.push({ ...headerBtnCfg, pluginId: this._pluginId });
console.log(`Plugin ${this._pluginId} registered header button`, headerBtnCfg);
Log.log(`Plugin ${this._pluginId} registered header button`, headerBtnCfg);
this._pluginBridge.registerHeaderButton(headerBtnCfg);
}
registerMenuEntry(menuEntryCfg: Omit<PluginMenuEntryCfg, 'pluginId'>): void {
const fullMenuEntry = { ...menuEntryCfg, pluginId: this._pluginId };
this._menuEntries.push(fullMenuEntry);
console.log(`Plugin ${this._pluginId} registered menu entry`, menuEntryCfg);
Log.log(`Plugin ${this._pluginId} registered menu entry`, menuEntryCfg);
this._pluginBridge.registerMenuEntry(menuEntryCfg);
}
@ -99,7 +100,7 @@ export class PluginAPI implements PluginAPIInterface {
};
this._shortcuts.push(shortcut);
console.log(`Plugin ${this._pluginId} registered shortcut`, shortcutCfg);
Log.log(`Plugin ${this._pluginId} registered shortcut`, shortcutCfg);
// Register shortcut with bridge
this._pluginBridge.registerShortcut(shortcut);
@ -109,58 +110,58 @@ export class PluginAPI implements PluginAPIInterface {
sidePanelBtnCfg: Omit<PluginSidePanelBtnCfg, 'pluginId'>,
): void {
this._sidePanelButtons.push({ ...sidePanelBtnCfg, pluginId: this._pluginId });
console.log(`Plugin ${this._pluginId} registered side panel button`, sidePanelBtnCfg);
Log.log(`Plugin ${this._pluginId} registered side panel button`, sidePanelBtnCfg);
this._pluginBridge.registerSidePanelButton(sidePanelBtnCfg);
}
showIndexHtmlAsView(): void {
console.log(`Plugin ${this._pluginId} requested to show index.html`);
Log.log(`Plugin ${this._pluginId} requested to show index.html`);
return this._pluginBridge.showIndexHtmlAsView(this._pluginId);
}
async getTasks(): Promise<Task[]> {
console.log(`Plugin ${this._pluginId} requested all tasks`);
Log.log(`Plugin ${this._pluginId} requested all tasks`);
const tasks = await this._pluginBridge.getTasks();
return tasks.map(taskCopyToTaskData);
}
async getArchivedTasks(): Promise<Task[]> {
console.log(`Plugin ${this._pluginId} requested archived tasks`);
Log.log(`Plugin ${this._pluginId} requested archived tasks`);
const tasks = await this._pluginBridge.getArchivedTasks();
return tasks.map(taskCopyToTaskData);
}
async getCurrentContextTasks(): Promise<Task[]> {
console.log(`Plugin ${this._pluginId} requested current context tasks`);
Log.log(`Plugin ${this._pluginId} requested current context tasks`);
const tasks = await this._pluginBridge.getCurrentContextTasks();
return tasks.map(taskCopyToTaskData);
}
async updateTask(taskId: string, updates: Partial<Task>): Promise<void> {
console.log(`Plugin ${this._pluginId} requested to update task ${taskId}:`, updates);
Log.log(`Plugin ${this._pluginId} requested to update task ${taskId}:`, updates);
const taskCopyUpdates = taskDataToPartialTaskCopy(updates);
return this._pluginBridge.updateTask(taskId, taskCopyUpdates);
}
async addTask(taskData: PluginCreateTaskData): Promise<string> {
console.log(`Plugin ${this._pluginId} requested to add task:`, taskData);
Log.log(`Plugin ${this._pluginId} requested to add task:`, taskData);
return this._pluginBridge.addTask(taskData);
}
async getAllProjects(): Promise<Project[]> {
console.log(`Plugin ${this._pluginId} requested all projects`);
Log.log(`Plugin ${this._pluginId} requested all projects`);
const projects = await this._pluginBridge.getAllProjects();
return projects.map(projectCopyToProjectData);
}
async addProject(projectData: Partial<Project>): Promise<string> {
console.log(`Plugin ${this._pluginId} requested to add project:`, projectData);
Log.log(`Plugin ${this._pluginId} requested to add project:`, projectData);
const projectCopyData = projectDataToPartialProjectCopy(projectData);
return this._pluginBridge.addProject(projectCopyData);
}
async updateProject(projectId: string, updates: Partial<Project>): Promise<void> {
console.log(
Log.log(
`Plugin ${this._pluginId} requested to update project ${projectId}:`,
updates,
);
@ -169,19 +170,19 @@ export class PluginAPI implements PluginAPIInterface {
}
async getAllTags(): Promise<Tag[]> {
console.log(`Plugin ${this._pluginId} requested all tags`);
Log.log(`Plugin ${this._pluginId} requested all tags`);
const tags = await this._pluginBridge.getAllTags();
return tags.map(tagCopyToTagData);
}
async addTag(tagData: Partial<Tag>): Promise<string> {
console.log(`Plugin ${this._pluginId} requested to add tag:`, tagData);
Log.log(`Plugin ${this._pluginId} requested to add tag:`, tagData);
const tagCopyData = tagDataToPartialTagCopy(tagData);
return this._pluginBridge.addTag(tagCopyData);
}
async updateTag(tagId: string, updates: Partial<Tag>): Promise<void> {
console.log(`Plugin ${this._pluginId} requested to update tag ${tagId}:`, updates);
Log.log(`Plugin ${this._pluginId} requested to update tag ${tagId}:`, updates);
const tagCopyUpdates = tagDataToPartialTagCopy(updates);
return this._pluginBridge.updateTag(tagId, tagCopyUpdates);
}
@ -191,7 +192,7 @@ export class PluginAPI implements PluginAPIInterface {
contextId: string,
contextType: 'project' | 'task',
): Promise<void> {
console.log(
Log.log(
`Plugin ${this._pluginId} requested to reorder tasks in ${contextType} ${contextId}:`,
taskIds,
);
@ -203,27 +204,27 @@ export class PluginAPI implements PluginAPIInterface {
}
async notify(notifyCfg: NotifyCfg): Promise<void> {
console.log(`Plugin ${this._pluginId} requested notification:`, notifyCfg);
Log.log(`Plugin ${this._pluginId} requested notification:`, notifyCfg);
return this._pluginBridge.notify(notifyCfg);
}
persistDataSynced(dataStr: string): Promise<void> {
console.log(`Plugin ${this._pluginId} requested to persist data:`, dataStr);
Log.log(`Plugin ${this._pluginId} requested to persist data:`, dataStr);
return this._pluginBridge.persistDataSynced(dataStr);
}
loadSyncedData(): Promise<string | null> {
console.log(`Plugin ${this._pluginId} requested to load persisted data:`);
Log.log(`Plugin ${this._pluginId} requested to load persisted data:`);
return this._pluginBridge.loadPersistedData();
}
async openDialog(dialogCfg: DialogCfg): Promise<void> {
console.log(`Plugin ${this._pluginId} requested to open dialog:`, dialogCfg);
Log.log(`Plugin ${this._pluginId} requested to open dialog:`, dialogCfg);
return this._pluginBridge.openDialog(dialogCfg);
}
async triggerSync(): Promise<void> {
console.log(`Plugin ${this._pluginId} requested to trigger sync`);
Log.log(`Plugin ${this._pluginId} requested to trigger sync`);
return this._pluginBridge.triggerSync();
}
@ -233,7 +234,7 @@ export class PluginAPI implements PluginAPIInterface {
*/
onMessage(handler: (message: any) => Promise<any>): void {
this._messageHandler = handler;
console.log(`Plugin ${this._pluginId} registered message handler`);
Log.log(`Plugin ${this._pluginId} registered message handler`);
}
/**
@ -265,7 +266,7 @@ export class PluginAPI implements PluginAPIInterface {
* Execute an NgRx action if it's in the allowed list
*/
dispatchAction(action: any): void {
console.log(`Plugin ${this._pluginId} requested to execute action:`, action);
Log.log(`Plugin ${this._pluginId} requested to execute action:`, action);
return this._pluginBridge.dispatchAction(action);
}
@ -274,7 +275,7 @@ export class PluginAPI implements PluginAPIInterface {
* Called when the plugin is being unloaded
*/
cleanup(): void {
console.log(`Cleaning up PluginAPI for plugin ${this._pluginId}`);
Log.log(`Cleaning up PluginAPI for plugin ${this._pluginId}`);
// Clear all hook handlers
this._hookHandlers.clear();

View file

@ -39,6 +39,7 @@ import { isAllowedPluginAction } from './allowed-plugin-actions.const';
import { TranslateService } from '@ngx-translate/core';
import { T } from '../t.const';
import { SyncWrapperService } from '../imex/sync/sync-wrapper.service';
import { Log } from '../core/log';
/**
* PluginBridge acts as an intermediary layer between plugins and the main application services.
@ -119,7 +120,7 @@ export class PluginBridgeService implements OnDestroy {
duration: 5000, // 5 seconds default duration
});
console.log('PluginBridge: Notification sent successfully', notifyCfg);
Log.log('PluginBridge: Notification sent successfully', notifyCfg);
}
/**
@ -142,11 +143,11 @@ export class PluginBridgeService implements OnDestroy {
});
dialogRef.afterClosed().subscribe((result) => {
console.log('PluginBridge: Dialog closed with result:', result);
Log.log('PluginBridge: Dialog closed with result:', result);
resolve();
});
} catch (error) {
console.error('PluginBridge: Failed to open dialog:', error);
Log.err('PluginBridge: Failed to open dialog:', error);
reject(error);
}
});
@ -163,7 +164,7 @@ export class PluginBridgeService implements OnDestroy {
this._translateService.instant(T.PLUGINS.NO_PLUGIN_ID_PROVIDED_FOR_HTML),
);
}
console.log('PluginBridge: Navigating to plugin index view', {
Log.log('PluginBridge: Navigating to plugin index view', {
pluginId: targetPluginId,
});
// Navigate to the plugin index route
@ -194,12 +195,12 @@ export class PluginBridgeService implements OnDestroy {
return task as TaskCopy;
});
console.log('PluginBridge: Retrieved archived tasks', {
Log.log('PluginBridge: Retrieved archived tasks', {
count: archivedTasks.length,
});
return archivedTasks;
} catch (error) {
console.error('PluginBridge: Failed to load archived tasks:', error);
Log.err('PluginBridge: Failed to load archived tasks:', error);
return [];
}
}
@ -231,7 +232,7 @@ export class PluginBridgeService implements OnDestroy {
// Update the task using TaskService (TaskCopy is compatible with Task)
this._taskService.update(taskId, updates);
console.log('PluginBridge: Task updated successfully', { taskId, updates });
Log.log('PluginBridge: Task updated successfully', { taskId, updates });
}
/**
@ -269,7 +270,7 @@ export class PluginBridgeService implements OnDestroy {
}),
);
console.log('PluginBridge: Subtask added successfully', {
Log.log('PluginBridge: Subtask added successfully', {
taskId: task.id,
taskData,
});
@ -292,7 +293,7 @@ export class PluginBridgeService implements OnDestroy {
false, // isAddToBottom
);
console.log('PluginBridge: Task added successfully', { taskId, taskData });
Log.log('PluginBridge: Task added successfully', { taskId, taskData });
return taskId;
}
}
@ -311,7 +312,7 @@ export class PluginBridgeService implements OnDestroy {
async addProject(projectData: Partial<ProjectCopy>): Promise<string> {
typia.assert<Partial<ProjectCopy>>(projectData);
console.log('PluginBridge: Project add', { projectData });
Log.log('PluginBridge: Project add', { projectData });
return this._projectService.add(projectData);
}
@ -325,7 +326,7 @@ export class PluginBridgeService implements OnDestroy {
// Update the project using ProjectService (ProjectCopy is compatible with Project)
this._projectService.update(projectId, updates);
console.log('PluginBridge: Project updated successfully', { projectId, updates });
Log.log('PluginBridge: Project updated successfully', { projectId, updates });
}
/**
@ -344,7 +345,7 @@ export class PluginBridgeService implements OnDestroy {
// Add the tag using TagService (TagCopy is compatible with Tag)
const tagId = this._tagService.addTag(tagData);
console.log('PluginBridge: Tag added successfully', { tagId, tagData });
Log.log('PluginBridge: Tag added successfully', { tagId, tagData });
return tagId;
}
@ -357,7 +358,7 @@ export class PluginBridgeService implements OnDestroy {
// Update the tag using TagService (TagCopy is compatible with Tag)
this._tagService.updateTag(tagId, updates);
console.log('PluginBridge: Tag updated successfully', { tagId, updates });
Log.log('PluginBridge: Tag updated successfully', { tagId, updates });
}
/**
@ -400,7 +401,7 @@ export class PluginBridgeService implements OnDestroy {
allTasks?.filter((t) => t.projectId === contextId && !t.parentId) || [];
const taskIdsInProject = tasksInProject.map((t) => t.id);
console.log('PluginBridge: Validating task reorder', {
Log.log('PluginBridge: Validating task reorder', {
requestedTaskIds: taskIds,
projectTaskIds: allProjectTaskIds,
actualTasksInProject: taskIdsInProject,
@ -426,7 +427,7 @@ export class PluginBridgeService implements OnDestroy {
// Note: This assumes all tasks are in the regular list, not backlog
this._projectService.update(contextId, { taskIds });
console.log('PluginBridge: Project tasks reordered successfully', {
Log.log('PluginBridge: Project tasks reordered successfully', {
projectId: contextId,
newOrder: taskIds,
});
@ -460,7 +461,7 @@ export class PluginBridgeService implements OnDestroy {
// Update the task with new subtask order
this._taskService.update(contextId, { subTaskIds: taskIds });
console.log('PluginBridge: Subtasks reordered successfully', {
Log.log('PluginBridge: Subtasks reordered successfully', {
parentTaskId: contextId,
newOrder: taskIds,
});
@ -484,11 +485,11 @@ export class PluginBridgeService implements OnDestroy {
this._currentPluginId,
dataStr,
);
console.log('PluginBridge: Plugin data persisted successfully', {
Log.log('PluginBridge: Plugin data persisted successfully', {
pluginId: this._currentPluginId,
});
} catch (error) {
console.error('PluginBridge: Failed to persist plugin data:', error);
Log.err('PluginBridge: Failed to persist plugin data:', error);
throw new Error(this._translateService.instant(T.PLUGINS.UNABLE_TO_PERSIST_DATA));
}
}
@ -508,7 +509,7 @@ export class PluginBridgeService implements OnDestroy {
this._currentPluginId,
);
} catch (error) {
console.error('PluginBridge: Failed to get persisted plugin data:', error);
Log.err('PluginBridge: Failed to get persisted plugin data:', error);
return null;
}
}
@ -522,11 +523,11 @@ export class PluginBridgeService implements OnDestroy {
}
try {
console.log('PluginBridge: Triggering sync for plugin', this._currentPluginId);
Log.log('PluginBridge: Triggering sync for plugin', this._currentPluginId);
await this._syncWrapperService.sync();
console.log('PluginBridge: Sync completed successfully');
Log.log('PluginBridge: Sync completed successfully');
} catch (error) {
console.error('PluginBridge: Sync failed:', error);
Log.err('PluginBridge: Sync failed:', error);
throw error;
}
}
@ -554,7 +555,7 @@ export class PluginBridgeService implements OnDestroy {
this._removePluginSidePanelButtons(pluginId);
this.unregisterPluginShortcuts(pluginId);
console.log('PluginBridge: All hooks unregistered for plugin', { pluginId });
Log.log('PluginBridge: All hooks unregistered for plugin', { pluginId });
}
/**
@ -576,7 +577,7 @@ export class PluginBridgeService implements OnDestroy {
const currentButtons = this._headerButtons$.value;
this._headerButtons$.next([...currentButtons, newButton]);
console.log('PluginBridge: Header button registered', {
Log.log('PluginBridge: Header button registered', {
pluginId: this._currentPluginId,
headerBtnCfg,
});
@ -621,7 +622,7 @@ export class PluginBridgeService implements OnDestroy {
);
if (isDuplicate) {
console.warn('PluginBridge: Duplicate menu entry detected, skipping registration', {
Log.err('PluginBridge: Duplicate menu entry detected, skipping registration', {
pluginId: this._currentPluginId,
label: menuEntryCfg.label,
});
@ -630,7 +631,7 @@ export class PluginBridgeService implements OnDestroy {
this._menuEntries$.next([...currentEntries, newMenuEntry]);
console.log('PluginBridge: Menu entry registered', {
Log.log('PluginBridge: Menu entry registered', {
pluginId: this._currentPluginId,
menuEntryCfg,
});
@ -646,7 +647,7 @@ export class PluginBridgeService implements OnDestroy {
);
this._headerButtons$.next(filteredButtons);
console.log('PluginBridge: Header buttons removed for plugin', { pluginId });
Log.log('PluginBridge: Header buttons removed for plugin', { pluginId });
}
/**
@ -657,7 +658,7 @@ export class PluginBridgeService implements OnDestroy {
const filteredEntries = currentEntries.filter((entry) => entry.pluginId !== pluginId);
this._menuEntries$.next(filteredEntries);
console.log('PluginBridge: Menu entries removed for plugin', { pluginId });
Log.log('PluginBridge: Menu entries removed for plugin', { pluginId });
}
/**
@ -697,7 +698,7 @@ export class PluginBridgeService implements OnDestroy {
);
if (isDuplicate) {
console.warn(
Log.err(
'PluginBridge: Duplicate side panel button detected, skipping registration',
{
pluginId: this._currentPluginId,
@ -709,7 +710,7 @@ export class PluginBridgeService implements OnDestroy {
this._sidePanelButtons$.next([...currentButtons, newButton]);
console.log('PluginBridge: Side panel button registered', {
Log.log('PluginBridge: Side panel button registered', {
pluginId: this._currentPluginId,
sidePanelBtnCfg,
});
@ -725,7 +726,7 @@ export class PluginBridgeService implements OnDestroy {
);
this._sidePanelButtons$.next(filteredButtons);
console.log('PluginBridge: Side panel buttons removed for plugin', { pluginId });
Log.log('PluginBridge: Side panel buttons removed for plugin', { pluginId });
}
/**
@ -746,7 +747,7 @@ export class PluginBridgeService implements OnDestroy {
const currentShortcuts = this.shortcuts$.value;
this.shortcuts$.next([...currentShortcuts, shortcutWithPluginId]);
console.log('PluginBridge: Shortcut registered', {
Log.log('PluginBridge: Shortcut registered', {
pluginId: this._currentPluginId,
shortcut: shortcutWithPluginId,
});
@ -762,12 +763,10 @@ export class PluginBridgeService implements OnDestroy {
if (shortcut) {
try {
await Promise.resolve(shortcut.onExec());
console.log(
`Executed shortcut "${shortcut.label}" from plugin ${shortcut.pluginId}`,
);
Log.log(`Executed shortcut "${shortcut.label}" from plugin ${shortcut.pluginId}`);
return true;
} catch (error) {
console.error(`Failed to execute shortcut "${shortcut.label}":`, error);
Log.err(`Failed to execute shortcut "${shortcut.label}":`, error);
return false;
}
}
@ -786,7 +785,7 @@ export class PluginBridgeService implements OnDestroy {
if (filteredShortcuts.length !== currentShortcuts.length) {
this.shortcuts$.next(filteredShortcuts);
console.log(
Log.log(
`Unregistered ${currentShortcuts.length - filteredShortcuts.length} shortcuts for plugin ${pluginId}`,
);
}
@ -864,9 +863,7 @@ export class PluginBridgeService implements OnDestroy {
// Check if the action is in the allowed list
if (!isAllowedPluginAction(action)) {
console.error(
`PluginBridge: Action type '${action.type}' is not allowed for plugins`,
);
Log.err(`PluginBridge: Action type '${action.type}' is not allowed for plugins`);
throw new Error(
this._translateService.instant(T.PLUGINS.ACTION_TYPE_NOT_ALLOWED, {
actionType: action.type,
@ -876,7 +873,7 @@ export class PluginBridgeService implements OnDestroy {
// Dispatch the action
this._store.dispatch(action);
console.log(`PluginBridge: Dispatched action for plugin ${this._currentPluginId}`, {
Log.log(`PluginBridge: Dispatched action for plugin ${this._currentPluginId}`, {
actionType: action.type,
payload: action,
});
@ -929,7 +926,7 @@ export class PluginBridgeService implements OnDestroy {
return result;
} catch (error) {
console.error('PluginBridge: Failed to execute Node.js script:', error);
Log.err('PluginBridge: Failed to execute Node.js script:', error);
return {
success: false,
error:
@ -955,7 +952,7 @@ export class PluginBridgeService implements OnDestroy {
* Clean up all resources when service is destroyed
*/
ngOnDestroy(): void {
console.log('PluginBridgeService: Cleaning up resources');
Log.log('PluginBridgeService: Cleaning up resources');
// Complete all BehaviorSubjects
this._headerButtons$.complete();
@ -963,6 +960,6 @@ export class PluginBridgeService implements OnDestroy {
this.shortcuts$.complete();
this._sidePanelButtons$.complete();
console.log('PluginBridgeService: Cleanup complete');
Log.log('PluginBridgeService: Cleanup complete');
}
}

View file

@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { Log } from '../core/log';
export interface CachedPlugin {
id: string;
@ -64,19 +65,18 @@ export class PluginCacheService {
};
const totalSizeKB = Object.values(sizes).reduce((sum, size) => sum + size, 0);
console.log(`[PluginCache] Storing plugin "${pluginId}":`);
console.log(`[PluginCache] - Manifest: ${sizes.manifest.toFixed(2)}KB`);
console.log(`[PluginCache] - Code: ${sizes.code.toFixed(2)}KB`);
if (indexHtml)
console.log(`[PluginCache] - IndexHtml: ${sizes.indexHtml.toFixed(2)}KB`);
if (icon) console.log(`[PluginCache] - Icon: ${sizes.icon.toFixed(2)}KB`);
console.log(
Log.log(`[PluginCache] Storing plugin "${pluginId}":`);
Log.log(`[PluginCache] - Manifest: ${sizes.manifest.toFixed(2)}KB`);
Log.log(`[PluginCache] - Code: ${sizes.code.toFixed(2)}KB`);
if (indexHtml) Log.log(`[PluginCache] - IndexHtml: ${sizes.indexHtml.toFixed(2)}KB`);
if (icon) Log.log(`[PluginCache] - Icon: ${sizes.icon.toFixed(2)}KB`);
Log.log(
`[PluginCache] - Total size: ${totalSizeKB.toFixed(2)}KB (${(totalSizeKB / 1024).toFixed(2)}MB)`,
);
if (totalSizeKB > 1024) {
// Warn if plugin is larger than 1MB
console.warn(
Log.err(
`[PluginCache] Large plugin detected: "${pluginId}" is ${(totalSizeKB / 1024).toFixed(2)}MB`,
);
}
@ -97,14 +97,11 @@ export class PluginCacheService {
return new Promise((resolve, reject) => {
const request = store.put(plugin);
request.onsuccess = () => {
console.log(`[PluginCache] Successfully stored plugin "${pluginId}"`);
Log.log(`[PluginCache] Successfully stored plugin "${pluginId}"`);
resolve();
};
request.onerror = () => {
console.error(
`[PluginCache] Failed to store plugin "${pluginId}":`,
request.error,
);
Log.err(`[PluginCache] Failed to store plugin "${pluginId}":`, request.error);
reject(new Error(`Failed to store plugin ${pluginId}`));
};
});
@ -114,7 +111,7 @@ export class PluginCacheService {
* Get a plugin from the cache
*/
async getPlugin(pluginId: string): Promise<CachedPlugin | null> {
console.log(`[PluginCache] Loading plugin "${pluginId}"`);
Log.log(`[PluginCache] Loading plugin "${pluginId}"`);
const db = await this._getDB();
const transaction = db.transaction([this.STORE_NAME], 'readonly');
const store = transaction.objectStore(this.STORE_NAME);
@ -145,7 +142,7 @@ export class PluginCacheService {
* Get all cached plugins
*/
async getAllPlugins(): Promise<CachedPlugin[]> {
console.log('[PluginCache] Loading all plugins from cache');
Log.log('[PluginCache] Loading all plugins from cache');
const db = await this._getDB();
const transaction = db.transaction([this.STORE_NAME], 'readonly');
const store = transaction.objectStore(this.STORE_NAME);

View file

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { Hooks, PluginHookHandler } from './plugin-api.model';
import { Log } from '../core/log';
/**
* Simplified plugin hooks service following KISS principles.
@ -36,7 +37,7 @@ export class PluginHooksService {
try {
await handler(payload);
} catch (error) {
console.error(`Plugin ${pluginId} ${hook} handler error:`, error);
Log.err(`Plugin ${pluginId} ${hook} handler error:`, error);
// Continue with other handlers
}
}

View file

@ -5,6 +5,7 @@ import { PluginManifest } from './plugin-api.model';
import { PluginCacheService } from './plugin-cache.service';
// KISS: No size checks in loader - trust the browser's limits
import { validatePluginManifest } from './util/validate-manifest.util';
import { Log } from '../core/log';
interface PluginAssets {
manifest: PluginManifest;
@ -69,7 +70,7 @@ export class PluginLoaderService {
.pipe(first())
.toPromise();
} catch (e) {
console.warn(`No index.html for plugin ${manifest.id}`);
Log.err(`No index.html for plugin ${manifest.id}`);
}
}
@ -81,7 +82,7 @@ export class PluginLoaderService {
.pipe(first())
.toPromise();
} catch (e) {
console.warn(`No icon for plugin ${manifest.id}`);
Log.err(`No icon for plugin ${manifest.id}`);
}
}

View file

@ -1,6 +1,7 @@
import { inject, Injectable } from '@angular/core';
import { PfapiService } from '../pfapi/pfapi.service';
import { PluginMetadata, PluginMetaDataState } from './plugin-persistence.model';
import { Log } from '../core/log';
/**
* Service for persisting plugin metadata using pfapi.
@ -27,7 +28,7 @@ export class PluginMetaPersistenceService {
// Deep compare the states
if (this._isDataEqual(currentState, newState)) {
console.log('PluginMetaPersistenceService: No changes detected, skipping write');
Log.log('PluginMetaPersistenceService: No changes detected, skipping write');
return;
}
@ -35,7 +36,7 @@ export class PluginMetaPersistenceService {
await this._pfapiService.pf.m.pluginMetadata.save(newState, {
isUpdateRevAndLastUpdate: true,
});
console.log('PluginMetaPersistenceService: Data updated');
Log.log('PluginMetaPersistenceService: Data updated');
}
/**

View file

@ -6,6 +6,7 @@ import { PluginSecurityService } from './plugin-security';
import { SnackService } from '../core/snack/snack.service';
import { IS_ELECTRON } from '../app.constants';
import { PluginCleanupService } from './plugin-cleanup.service';
import { Log } from '../core/log';
/**
* Simplified plugin runner following KISS principles.
@ -58,7 +59,7 @@ export class PluginRunner {
// Show warnings if any
if (analysis.warnings.length > 0) {
console.warn(`Plugin ${manifest.id} warnings:`, analysis.warnings);
Log.err(`Plugin ${manifest.id} warnings:`, analysis.warnings);
this._snackService.open({
msg: `Plugin "${manifest.name}" has warnings: ${analysis.warnings[0]}`,
type: 'CUSTOM',
@ -68,7 +69,7 @@ export class PluginRunner {
// Log info for transparency
if (analysis.info.length > 0) {
console.info(`Plugin ${manifest.id} info:`, analysis.info);
Log.info(`Plugin ${manifest.id} info:`, analysis.info);
}
try {
@ -101,13 +102,13 @@ export class PluginRunner {
} catch (error) {
pluginInstance.error =
error instanceof Error ? error.message : 'Failed to load plugin';
console.error(`Plugin ${manifest.id} error:`, error);
Log.err(`Plugin ${manifest.id} error:`, error);
}
this._loadedPlugins.set(manifest.id, pluginInstance);
return pluginInstance;
} catch (error) {
console.error(`Failed to load plugin ${manifest.id}:`, error);
Log.err(`Failed to load plugin ${manifest.id}:`, error);
throw error;
}
}

View file

@ -30,6 +30,7 @@ import { PluginLoaderService } from './plugin-loader.service';
import { validatePluginManifest } from './util/validate-manifest.util';
import { TranslateService } from '@ngx-translate/core';
import { T } from '../t.const';
import { Log } from '../core/log';
@Injectable({
providedIn: 'root',
@ -66,11 +67,11 @@ export class PluginService implements OnDestroy {
async initializePlugins(): Promise<void> {
if (this._isInitialized) {
console.warn(this._translateService.instant(T.PLUGINS.ALREADY_INITIALIZED));
Log.err(this._translateService.instant(T.PLUGINS.ALREADY_INITIALIZED));
return;
}
console.log('Initializing plugin system...');
Log.log('Initializing plugin system...');
try {
// Only load manifests, not the actual plugin code
@ -81,9 +82,9 @@ export class PluginService implements OnDestroy {
await this._loadEnabledPlugins();
this._isInitialized = true;
console.log('Plugin system initialized successfully');
Log.log('Plugin system initialized successfully');
} catch (error) {
console.error('Failed to initialize plugin system:', error);
Log.err('Failed to initialize plugin system:', error);
throw error;
}
}
@ -131,13 +132,13 @@ export class PluginService implements OnDestroy {
}
} catch (e) {
// Icon is optional - silently ignore 404s and other errors
console.debug(
Log.debug(
`Icon not found for plugin ${manifest.id}: ${path}/${manifest.icon || 'icon.svg'}`,
);
}
}
} catch (error) {
console.error(`Failed to discover plugin at ${path}:`, error);
Log.err(`Failed to discover plugin at ${path}:`, error);
}
}
@ -186,13 +187,13 @@ export class PluginService implements OnDestroy {
this._pluginIcons.set(cachedPlugin.id, cachedPlugin.icon);
}
} catch (error) {
console.error(`Failed to discover cached plugin ${cachedPlugin.id}:`, error);
Log.err(`Failed to discover cached plugin ${cachedPlugin.id}:`, error);
}
}
this._updatePluginStates();
} catch (error) {
console.error('Failed to discover cached plugins:', error);
Log.err('Failed to discover cached plugins:', error);
}
}
@ -202,11 +203,11 @@ export class PluginService implements OnDestroy {
(state) => state.isEnabled,
);
console.log(`Loading ${pluginsToLoad.length} enabled plugins...`);
Log.log(`Loading ${pluginsToLoad.length} enabled plugins...`);
// Log which plugins are being loaded
for (const state of pluginsToLoad) {
console.log(
Log.log(
`Loading plugin: ${state.manifest.id} (enabled: ${state.isEnabled}, hooks: ${state.manifest.hooks?.length || 0}, sidePanel: ${state.manifest.sidePanel})`,
);
}
@ -227,7 +228,7 @@ export class PluginService implements OnDestroy {
async activatePlugin(pluginId: string): Promise<PluginInstance | null> {
const state = this._pluginStates.get(pluginId);
if (!state) {
console.error(`Plugin ${pluginId} not found`);
Log.err(`Plugin ${pluginId} not found`);
return null;
}
@ -258,7 +259,7 @@ export class PluginService implements OnDestroy {
this._updatePluginStates();
try {
console.log(`Activating plugin: ${pluginId}`);
Log.log(`Activating plugin: ${pluginId}`);
const instance = await this._loadPluginLazy(state);
state.status = 'loaded';
@ -272,7 +273,7 @@ export class PluginService implements OnDestroy {
return instance;
} catch (error) {
console.error(`Failed to activate plugin ${pluginId}:`, error);
Log.err(`Failed to activate plugin ${pluginId}:`, error);
state.status = 'error';
state.error = error instanceof Error ? error.message : String(error);
this._updatePluginStates();
@ -310,7 +311,7 @@ export class PluginService implements OnDestroy {
const promises = cachedPlugins.map(async (cachedPlugin) => {
try {
console.log(`Loading cached plugin: ${cachedPlugin.id}`);
Log.log(`Loading cached plugin: ${cachedPlugin.id}`);
// Set the path for reload functionality
this._pluginPaths.set(cachedPlugin.id, `uploaded://${cachedPlugin.id}`);
@ -318,14 +319,14 @@ export class PluginService implements OnDestroy {
await this._loadUploadedPlugin(cachedPlugin.id);
// The plugin instance is already added to _loadedPlugins in _loadUploadedPlugin if loaded successfully
} catch (error) {
console.error(`Failed to load cached plugin ${cachedPlugin.id}:`, error);
Log.err(`Failed to load cached plugin ${cachedPlugin.id}:`, error);
// Continue loading other plugins even if one fails
}
});
await Promise.allSettled(promises);
} catch (error) {
console.error('Failed to load cached plugins:', error);
Log.err('Failed to load cached plugins:', error);
// Don't throw - this shouldn't prevent other plugins from loading
}
}
@ -350,9 +351,9 @@ export class PluginService implements OnDestroy {
if (pluginInstance.manifest && pluginInstance.manifest.id) {
this._pluginPaths.set(pluginInstance.manifest.id, pluginPath);
}
console.log(`${type} plugin loaded successfully from ${pluginPath}`);
Log.log(`${type} plugin loaded successfully from ${pluginPath}`);
} catch (error) {
console.error(`Failed to load ${type} plugin from ${pluginPath}:`, error);
Log.err(`Failed to load ${type} plugin from ${pluginPath}:`, error);
// Continue loading other plugins even if one fails
}
});
@ -401,9 +402,7 @@ export class PluginService implements OnDestroy {
error: this._translateService.instant(T.PLUGINS.NODE_ONLY_DESKTOP),
};
this._pluginPaths.set(manifest.id, pluginPath); // Store the path for potential reload
console.log(
`Plugin ${manifest.id} requires desktop version, creating placeholder`,
);
Log.log(`Plugin ${manifest.id} requires desktop version, creating placeholder`);
return placeholderInstance;
}
@ -421,10 +420,10 @@ export class PluginService implements OnDestroy {
// Analyze plugin code (informational only - KISS approach)
const codeAnalysis = this._pluginSecurity.analyzePluginCode(pluginCode, manifest);
if (codeAnalysis.warnings.length > 0) {
console.warn(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
Log.err(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
}
if (codeAnalysis.info.length > 0) {
console.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
Log.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
}
// If plugin is disabled, create a placeholder instance without loading code
@ -436,7 +435,7 @@ export class PluginService implements OnDestroy {
error: undefined,
};
this._pluginPaths.set(manifest.id, pluginPath); // Store the path for potential reload
console.log(`Plugin ${manifest.id} is disabled, skipping load`);
Log.log(`Plugin ${manifest.id} is disabled, skipping load`);
return placeholderInstance;
}
@ -466,14 +465,14 @@ export class PluginService implements OnDestroy {
// The enabled state will be persisted later when user explicitly enables/disables plugins
this._ensurePluginEnabledInMemory(manifest.id);
console.log(`Plugin ${manifest.id} loaded successfully`);
Log.log(`Plugin ${manifest.id} loaded successfully`);
} else {
console.error(`Plugin ${manifest.id} failed to load:`, pluginInstance.error);
Log.err(`Plugin ${manifest.id} failed to load:`, pluginInstance.error);
}
return pluginInstance;
} catch (error) {
console.error(`Failed to load plugin from ${pluginPath}:`, error);
Log.err(`Failed to load plugin from ${pluginPath}:`, error);
throw error;
}
}
@ -618,7 +617,7 @@ export class PluginService implements OnDestroy {
// Check if plugin exists in states
const state = this._pluginStates.get(pluginId);
if (!state) {
console.warn(`Plugin ${pluginId} not found`);
Log.err(`Plugin ${pluginId} not found`);
this._activeSidePanelPlugin$.next(null);
return;
}
@ -635,11 +634,11 @@ export class PluginService implements OnDestroy {
if (instance) {
this._activeSidePanelPlugin$.next(instance);
} else {
console.warn(`Failed to activate plugin ${pluginId}`);
Log.err(`Failed to activate plugin ${pluginId}`);
this._activeSidePanelPlugin$.next(null);
}
} catch (error) {
console.error(`Error activating plugin ${pluginId}:`, error);
Log.err(`Error activating plugin ${pluginId}:`, error);
this._activeSidePanelPlugin$.next(null);
}
}
@ -702,7 +701,7 @@ export class PluginService implements OnDestroy {
}
async loadPluginFromZip(file: File): Promise<PluginInstance> {
console.log(`Starting plugin load from ZIP: ${file.name}`);
Log.log(`Starting plugin load from ZIP: ${file.name}`);
// Import fflate dynamically for better bundle size
const { unzip } = await import('fflate');
@ -740,7 +739,7 @@ export class PluginService implements OnDestroy {
});
},
);
console.log({ extractedFiles });
Log.log({ extractedFiles });
// Find and extract manifest.json
if (!extractedFiles['manifest.json']) {
@ -821,7 +820,7 @@ export class PluginService implements OnDestroy {
iconContent = new TextDecoder().decode(iconBytes);
// Basic SVG validation
if (!iconContent.includes('<svg') || !iconContent.includes('</svg>')) {
console.warn(`Plugin icon ${manifest.icon} does not appear to be a valid SVG`);
Log.err(`Plugin icon ${manifest.icon} does not appear to be a valid SVG`);
iconContent = null;
}
}
@ -829,10 +828,10 @@ export class PluginService implements OnDestroy {
// Analyze plugin code (informational only - KISS approach)
const codeAnalysis = this._pluginSecurity.analyzePluginCode(pluginCode, manifest);
if (codeAnalysis.warnings.length > 0) {
console.warn(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
Log.err(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
}
if (codeAnalysis.info.length > 0) {
console.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
Log.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
}
// Check if plugin is enabled (default to true for new uploads)
@ -897,7 +896,7 @@ export class PluginService implements OnDestroy {
this._pluginStates.set(manifest.id, state);
this._updatePluginStates();
console.log(
Log.log(
`Uploaded plugin ${manifest.id} requires desktop version, creating placeholder`,
);
return placeholderInstance;
@ -935,7 +934,7 @@ export class PluginService implements OnDestroy {
this._pluginStates.set(manifest.id, state);
this._updatePluginStates();
console.log(`Uploaded plugin ${manifest.id} is disabled, skipping load`);
Log.log(`Uploaded plugin ${manifest.id} is disabled, skipping load`);
return placeholderInstance;
}
@ -974,12 +973,9 @@ export class PluginService implements OnDestroy {
this._pluginStates.set(manifest.id, state);
this._updatePluginStates();
console.log(`Uploaded plugin ${manifest.id} loaded successfully`);
Log.log(`Uploaded plugin ${manifest.id} loaded successfully`);
} else {
console.error(
`Uploaded plugin ${manifest.id} failed to load:`,
pluginInstance.error,
);
Log.err(`Uploaded plugin ${manifest.id} failed to load:`, pluginInstance.error);
// Add failed plugin to states as well
const state: PluginState = {
@ -997,7 +993,7 @@ export class PluginService implements OnDestroy {
return pluginInstance;
} catch (error) {
console.error('Failed to load plugin from ZIP:', error);
Log.err('Failed to load plugin from ZIP:', error);
// Create error instance for UI display
const errorInstance: PluginInstance = {
@ -1071,7 +1067,7 @@ export class PluginService implements OnDestroy {
this._pluginStates.delete(pluginId);
this._updatePluginStates();
console.log(`Uploaded plugin ${pluginId} removed completely`);
Log.log(`Uploaded plugin ${pluginId} removed completely`);
}
unloadPlugin(pluginId: string): boolean {
@ -1110,7 +1106,7 @@ export class PluginService implements OnDestroy {
// In lazy loading mode, unload and re-activate
const state = this._pluginStates.get(pluginId);
if (!state) {
console.error(`Cannot reload plugin ${pluginId}: not found`);
Log.err(`Cannot reload plugin ${pluginId}: not found`);
return false;
}
@ -1150,10 +1146,10 @@ export class PluginService implements OnDestroy {
// Analyze plugin code (informational only - KISS approach)
const codeAnalysis = this._pluginSecurity.analyzePluginCode(pluginCode, manifest);
if (codeAnalysis.warnings.length > 0) {
console.warn(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
Log.err(`Plugin ${manifest.id} warnings:`, codeAnalysis.warnings);
}
if (codeAnalysis.info.length > 0) {
console.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
Log.info(`Plugin ${manifest.id} info:`, codeAnalysis.info);
}
// Check if plugin is enabled
@ -1169,7 +1165,7 @@ export class PluginService implements OnDestroy {
isEnabled: false,
error: undefined,
};
console.log(`Uploaded plugin ${manifest.id} is disabled, skipping reload`);
Log.log(`Uploaded plugin ${manifest.id} is disabled, skipping reload`);
return placeholderInstance;
}
@ -1193,17 +1189,14 @@ export class PluginService implements OnDestroy {
// Replace existing instance
this._loadedPlugins[existingIndex] = pluginInstance;
}
console.log(`Uploaded plugin ${manifest.id} reloaded successfully`);
Log.log(`Uploaded plugin ${manifest.id} reloaded successfully`);
} else {
console.error(
`Uploaded plugin ${manifest.id} failed to reload:`,
pluginInstance.error,
);
Log.err(`Uploaded plugin ${manifest.id} failed to reload:`, pluginInstance.error);
}
return pluginInstance;
} catch (error) {
console.error(`Failed to reload uploaded plugin ${pluginId}:`, error);
Log.err(`Failed to reload uploaded plugin ${pluginId}:`, error);
throw error;
}
}
@ -1219,7 +1212,7 @@ export class PluginService implements OnDestroy {
// Only check consent in Electron environment
if (!IS_ELECTRON) {
console.warn(
Log.err(
`Plugin ${manifest.id} requires nodeExecution permission which is not available in web environment`,
);
return false;
@ -1276,13 +1269,13 @@ export class PluginService implements OnDestroy {
private _ensurePluginEnabledInMemory(pluginId: string): void {
// We only need to track this in memory for startup purposes
// The actual persistence will happen when user explicitly enables/disables plugins
console.log(
Log.log(
`Plugin ${pluginId} marked as enabled in memory (no pfapi write during startup)`,
);
}
ngOnDestroy(): void {
console.log('PluginService: Cleaning up all resources');
Log.log('PluginService: Cleaning up all resources');
// Complete the side panel subject
this._activeSidePanelPlugin$.complete();
@ -1293,7 +1286,7 @@ export class PluginService implements OnDestroy {
try {
this.unloadPlugin(pluginId);
} catch (error) {
console.error(`Error unloading plugin ${pluginId} during cleanup:`, error);
Log.err(`Error unloading plugin ${pluginId} during cleanup:`, error);
}
});
@ -1309,6 +1302,6 @@ export class PluginService implements OnDestroy {
// Clear loader caches
this._pluginLoader.clearAllCaches();
console.log('PluginService: Cleanup complete');
Log.log('PluginService: Cleanup complete');
}
}

View file

@ -33,6 +33,7 @@ import {
} from '@angular/material/card';
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
import { T } from '../../../t.const';
import { Log } from '../../../core/log';
@Component({
selector: 'plugin-index',
@ -102,7 +103,7 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
try {
await this._loadPluginIndex(this.directPluginId);
} catch (err) {
console.error('Failed to load plugin index:', err);
Log.err('Failed to load plugin index:', err);
this.error.set(
err instanceof Error
? err.message
@ -116,7 +117,7 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
// Subscribe to route parameter changes to handle navigation between plugins
this._routeSubscription = this._route.paramMap.subscribe(async (params) => {
const newPluginId = params.get('pluginId');
console.log(
Log.log(
'Route paramMap changed, newPluginId:',
newPluginId,
'currentPluginId:',
@ -131,13 +132,11 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
// Skip if it's the same plugin (prevent unnecessary reloads)
if (this.pluginId() === newPluginId) {
console.log('Same plugin ID, skipping reload');
Log.log('Same plugin ID, skipping reload');
return;
}
console.log(
`Navigating from plugin "${this.pluginId()}" to plugin "${newPluginId}"`,
);
Log.log(`Navigating from plugin "${this.pluginId()}" to plugin "${newPluginId}"`);
// Clean up previous iframe communication BEFORE setting new plugin ID
this._cleanupIframeCommunication();
@ -153,7 +152,7 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
try {
await this._loadPluginIndex(newPluginId);
} catch (err) {
console.error('Failed to load plugin index:', err);
Log.err('Failed to load plugin index:', err);
this.error.set(
err instanceof Error
? err.message
@ -171,7 +170,7 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
try {
await this._pluginService.initializePlugins();
} catch (error) {
console.error('Failed to initialize plugin system:', error);
Log.err('Failed to initialize plugin system:', error);
throw new Error(
this._translateService.instant(T.PLUGINS.PLUGIN_SYSTEM_FAILED_INIT),
);
@ -191,12 +190,12 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
}
private async _loadPluginIndex(pluginId: string): Promise<void> {
console.log(`Loading plugin index for: ${pluginId}`);
Log.log(`Loading plugin index for: ${pluginId}`);
// Get the plugin index.html content
const indexContent = this._pluginService.getPluginIndexHtml(pluginId);
if (!indexContent) {
console.warn(`No index.html content found for plugin: ${pluginId}`);
Log.err(`No index.html content found for plugin: ${pluginId}`);
// Try to get the plugin instance to check if it should have an index.html
const plugins = await this._pluginService.getAllPlugins();
const plugin = plugins.find((p) => p.manifest.id === pluginId);
@ -245,30 +244,30 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
// Create safe URL and set iframe source
const safeUrl = this._sanitizer.bypassSecurityTrustResourceUrl(iframeUrl);
console.log(
Log.log(
`Setting iframe src for plugin ${pluginId}:`,
iframeUrl.substring(0, 100) + '...',
);
this.iframeSrc.set(safeUrl);
this.isLoading.set(false);
console.log(`Plugin ${pluginId} iframe src set, loading complete`);
Log.log(`Plugin ${pluginId} iframe src set, loading complete`);
}
private _cleanupIframeCommunication(): void {
const currentPluginId = this.pluginId();
console.log(`Cleaning up iframe communication for plugin: ${currentPluginId}`);
Log.log(`Cleaning up iframe communication for plugin: ${currentPluginId}`);
// Remove message listener
if (this._messageListener) {
window.removeEventListener('message', this._messageListener);
this._messageListener = undefined;
console.log(`Removed message listener for plugin: ${currentPluginId}`);
Log.log(`Removed message listener for plugin: ${currentPluginId}`);
}
// Clear iframe reference from cleanup service (but don't remove from DOM)
if (currentPluginId) {
this._cleanupService.cleanupPlugin(currentPluginId);
console.log(`Cleaned up plugin references for: ${currentPluginId}`);
Log.log(`Cleaned up plugin references for: ${currentPluginId}`);
}
// Set iframe to empty data URL to stop execution but keep iframe in DOM
@ -277,11 +276,11 @@ export class PluginIndexComponent implements OnInit, OnDestroy {
'data:text/html,<html><body></body></html>',
),
);
console.log(`Set iframe to empty data URL for plugin: ${currentPluginId}`);
Log.log(`Set iframe to empty data URL for plugin: ${currentPluginId}`);
}
onIframeLoad(): void {
console.log('Plugin iframe loaded for plugin:', this.pluginId());
Log.log('Plugin iframe loaded for plugin:', this.pluginId());
// Register iframe with cleanup service
if (this.iframeRef?.nativeElement && this.pluginId()) {

View file

@ -31,6 +31,7 @@ import { PluginIconComponent } from '../plugin-icon/plugin-icon.component';
import { IS_ELECTRON } from '../../../app.constants';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DestroyRef } from '@angular/core';
import { Log } from '../../../core/log';
@Component({
selector: 'plugin-management',
@ -138,7 +139,7 @@ export class PluginManagementComponent implements OnInit {
}
private async enablePlugin(plugin: PluginInstance): Promise<void> {
console.log('Enabling plugin:', plugin.manifest.id);
Log.log('Enabling plugin:', plugin.manifest.id);
try {
// Check if plugin requires Node.js execution consent
@ -146,7 +147,7 @@ export class PluginManagementComponent implements OnInit {
plugin.manifest,
);
if (!hasConsent) {
console.log(
Log.log(
'User denied Node.js execution permission for plugin:',
plugin.manifest.id,
);
@ -164,18 +165,18 @@ export class PluginManagementComponent implements OnInit {
// Activate the plugin (lazy load if needed)
const instance = await this._pluginService.activatePlugin(plugin.manifest.id);
if (instance) {
console.log('Plugin activated successfully:', plugin.manifest.id);
Log.log('Plugin activated successfully:', plugin.manifest.id);
}
// Refresh UI
await this.loadPlugins();
} catch (error) {
console.error('Failed to enable plugin:', error);
Log.err('Failed to enable plugin:', error);
}
}
private async disablePlugin(plugin: PluginInstance): Promise<void> {
console.log('Disabling plugin:', plugin.manifest.id);
Log.log('Disabling plugin:', plugin.manifest.id);
try {
// Set plugin as disabled in persistence
@ -194,22 +195,22 @@ export class PluginManagementComponent implements OnInit {
// Reload plugins to get the updated state from the service
await this.loadPlugins();
} catch (error) {
console.error('Failed to disable plugin:', error);
Log.err('Failed to disable plugin:', error);
}
}
async reloadPlugin(plugin: PluginInstance): Promise<void> {
console.log('Reloading plugin:', plugin.manifest.id);
Log.log('Reloading plugin:', plugin.manifest.id);
try {
const success = await this._pluginService.reloadPlugin(plugin.manifest.id);
if (success) {
console.log('Plugin reloaded successfully:', plugin.manifest.id);
Log.log('Plugin reloaded successfully:', plugin.manifest.id);
} else {
console.error('Failed to reload plugin:', plugin.manifest.id);
Log.err('Failed to reload plugin:', plugin.manifest.id);
}
} catch (error) {
console.error('Failed to reload plugin:', error);
Log.err('Failed to reload plugin:', error);
}
// Refresh the UI
@ -298,7 +299,7 @@ export class PluginManagementComponent implements OnInit {
// Clear the input
input.value = '';
} catch (error) {
console.error('Failed to load plugin from ZIP:', error);
Log.err('Failed to load plugin from ZIP:', error);
this.uploadError.set(
error instanceof Error
? error.message
@ -317,9 +318,9 @@ export class PluginManagementComponent implements OnInit {
await this._pluginCacheService.clearCache();
await this.loadPlugins(); // Refresh the plugin list
console.log('Plugin cache cleared successfully');
Log.log('Plugin cache cleared successfully');
} catch (error) {
console.error('Failed to clear plugin cache:', error);
Log.err('Failed to clear plugin cache:', error);
this.uploadError.set(
error instanceof Error
? error.message
@ -357,9 +358,9 @@ export class PluginManagementComponent implements OnInit {
await this._pluginService.removeUploadedPlugin(plugin.manifest.id);
await this.loadPlugins(); // Refresh the plugin list
console.log(`Plugin ${plugin.manifest.id} removed successfully`);
Log.log(`Plugin ${plugin.manifest.id} removed successfully`);
} catch (error) {
console.error('Failed to remove plugin:', error);
Log.err('Failed to remove plugin:', error);
this.uploadError.set(
error instanceof Error
? error.message

View file

@ -15,6 +15,7 @@ import {
import { toSignal } from '@angular/core/rxjs-interop';
import { filter, map } from 'rxjs/operators';
import { BreakpointObserver } from '@angular/cdk/layout';
import { Log } from '../../core/log';
/**
* Component that renders side panel buttons for plugins in the main header.
@ -132,21 +133,21 @@ export class PluginSidePanelBtnsComponent {
});
onButtonClick(button: PluginSidePanelBtnCfg): void {
console.log('Side panel button clicked:', button.pluginId, button.label);
Log.log('Side panel button clicked:', button.pluginId, button.label);
// Prevent action if not in work view
if (!this.isWorkView()) {
console.log('Not in work view, ignoring click');
Log.log('Not in work view, ignoring click');
return;
}
console.log('Dispatching togglePluginPanel action for:', button.pluginId);
Log.log('Dispatching togglePluginPanel action for:', button.pluginId);
// Dispatch action to toggle the plugin panel
this._store.dispatch(togglePluginPanel(button.pluginId));
// Call the original onClick handler if provided
if (button.onClick) {
console.log('Calling plugin onClick handler for:', button.pluginId);
Log.log('Calling plugin onClick handler for:', button.pluginId);
button.onClick();
}
}

View file

@ -1,5 +1,6 @@
import { PluginBridgeService } from '../plugin-bridge.service';
import { PluginBaseCfg, PluginManifest } from '../plugin-api.model';
import { Log } from '../../core/log';
/**
* Simplified plugin iframe utilities following KISS principles.
@ -149,7 +150,7 @@ export const createPluginApiScript = (config: PluginIframeConfig): string => {
try {
handler(data.payload);
} catch (error) {
console.error('Hook handler error:', error);
Log.err('Hook handler error:', error);
}
});
}
@ -371,7 +372,7 @@ export const handlePluginMessage = async (
// Special handling for registerHook - it needs pluginId as first parameter
if (args.length >= 2) {
const [hook, handlerPlaceholder] = args;
console.log('Plugin iframe registerHook:', {
Log.log('Plugin iframe registerHook:', {
hook,
handlerPlaceholder,
pluginId: config.pluginId,
@ -523,6 +524,6 @@ export const handlePluginMessage = async (
// Handle plugin ready
if (data.type === 'plugin-ready' && data.pluginId === config.pluginId) {
console.log(`Plugin ${config.pluginId} is ready`);
Log.log(`Plugin ${config.pluginId} is ready`);
}
};

View file

@ -20,6 +20,7 @@ import { StringToMsPipe } from './string-to-ms.pipe';
import { MsToStringPipe } from './ms-to-string.pipe';
import { TranslateService } from '@ngx-translate/core';
import { T } from 'src/app/t.const';
import { Log } from '../../core/log';
@Directive({
selector: 'input[inputDuration]',
@ -160,7 +161,7 @@ export class InputDurationDirective implements ControlValueAccessor, Validator,
this._previousMsValue = this._msValue;
} catch (err) {
// If parsing fails, set to null
console.error('Error parsing duration:', err);
Log.err('Error parsing duration:', err);
this._msValue = null;
this._onChange(null);
}

View file

@ -1,5 +1,4 @@
import { AfterViewInit, Directive, ElementRef, OnDestroy, inject } from '@angular/core';
const DEFAULT_PINNED_CLASS = 'is-stuck';
@Directive({
@ -17,8 +16,8 @@ export class StuckDirective implements AfterViewInit, OnDestroy {
// ([e]) => e.target.classList.toggle(DEFAULT_PINNED_CLASS, e.intersectionRatio < 1),
([e]) => {
e.target.classList.toggle(DEFAULT_PINNED_CLASS, !e.isIntersecting);
// console.log(e.boundingClientRect.top, e);
// console.log('top', e.boundingClientRect.top < 0, e.isIntersecting);
// Log.log(e.boundingClientRect.top, e);
// Log.log('top', e.boundingClientRect.top < 0, e.isIntersecting);
// if (e.boundingClientRect.top < 0) {
// e.target.classList.toggle(DEFAULT_PINNED_CLASS, e.isIntersecting);
// }

View file

@ -11,6 +11,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { T } from 'src/app/t.const';
import { TranslateModule } from '@ngx-translate/core';
import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view';
import { Log } from '../../core/log';
@Component({
selector: 'task-title',
@ -31,7 +32,7 @@ export class TaskTitleComponent {
if (!this.isFocused && this.tmpValue !== this.lastExternalValue) {
// NOTE: this works because set value is called after this, for non-short syntax only changes
this.tmpValue = this.lastExternalValue;
console.log('new tmp', this.tmpValue);
Log.log('new tmp', this.tmpValue);
}
}
@ -64,7 +65,7 @@ export class TaskTitleComponent {
el.selectionStart = el.selectionEnd = el.value.length;
});
} catch (e) {
console.warn(e);
Log.err(e);
}
}
@ -88,7 +89,7 @@ export class TaskTitleComponent {
onTextInput(ev: Event): void {
// TODO not really clear if this is needed. was apparently added to prevent the android web view enter key from submitting
if (IS_ANDROID_WEB_VIEW && (ev as InputEvent)?.data?.slice(-1) === '\n') {
console.log('android enter key press');
Log.log('android enter key press');
this._forceBlur();
ev.preventDefault();
setTimeout(() => {

View file

@ -1,6 +1,7 @@
import { devError } from './dev-error';
import { arrayEquals } from './array-equals';
import { Dictionary } from '@ngrx/entity';
import { Log } from '../core/log';
export const isEntityStateConsistent = <T extends Dictionary<any>>(
data: T,
@ -13,7 +14,7 @@ export const isEntityStateConsistent = <T extends Dictionary<any>>(
Object.keys(data.entities).length !== data.ids.length ||
!arrayEquals(Object.keys(data.entities).sort(), [...data.ids].sort())
) {
console.log(data);
Log.log(data);
devError(`Inconsistent entity state "${additionalStr}"`);
return false;
}
@ -22,7 +23,7 @@ export const isEntityStateConsistent = <T extends Dictionary<any>>(
export const fixEntityStateConsistency = <T extends Dictionary<any>>(data: T): T => {
if (Object.keys(data.entities).length !== data.ids.length) {
console.warn('FIXING ENTITY STATE', {
Log.err('FIXING ENTITY STATE', {
...data,
ids: Object.keys(data.entities),
});
@ -39,7 +40,7 @@ export const fixEntityStateConsistencyOrError = <T extends Dictionary<any>>(
data: T,
): T => {
if (Object.keys(data.entities).length !== data.ids.length) {
console.log({
Log.log({
...data,
ids: Object.keys(data.entities),
});

View file

@ -1,6 +1,7 @@
import { Observable, Subject } from 'rxjs';
import { IS_ELECTRON } from '../app.constants';
import { devError } from './dev-error';
import { Log } from '../core/log';
const handlerMap: { [key: string]: Observable<any> } = {};
@ -11,19 +12,19 @@ export const ipcEvent$ = (evName: string): Observable<unknown[]> => {
const subject = new Subject<unknown[]>();
if (handlerMap[evName]) {
console.log(handlerMap);
Log.log(handlerMap);
devError(`ipcEvent$[${evName}] should only ever be registered once`);
return handlerMap[evName];
}
handlerMap[evName] = subject;
const handler: (...args: any[]) => void = (...args): void => {
console.log('ipcEvent$ trigger', evName);
Log.log('ipcEvent$ trigger', evName);
subject.next([...args]);
};
if (!window.ea) {
console.error('window.ea is not available. Make sure the preload script is loaded.');
Log.err('window.ea is not available. Make sure the preload script is loaded.');
return subject;
}
@ -32,7 +33,7 @@ export const ipcEvent$ = (evName: string): Observable<unknown[]> => {
return subject;
// return subject.pipe(
// // finalize(() => {
// // console.log('FINALIZE', evName);
// // Log.log('FINALIZE', evName);
// // // NOTE doesn't work due to the different contexts
// // // window.ea.off(evName, handler);
// // devError(`ipcEvent$[${evName}] observables live forever`);

Some files were not shown because too many files have changed in this diff Show more