refactor: complete migration from console.* to Log methods

- Replaced remaining 100 console.* calls across 100 files
- Fixed all console.log, console.error, console.warn calls
- Removed unused Log imports from 18 files
- Created force migration script to handle all edge cases
- All non-test files now use centralized Log class

Benefits:
- All application logs are now recorded for export
- Consistent log level filtering
- Better debugging with log history
- Centralized logging configuration
This commit is contained in:
Johannes Millan 2025-07-10 14:25:02 +02:00
parent 97f96f2393
commit 581d41cc0c
103 changed files with 407 additions and 127 deletions

View file

@ -0,0 +1,189 @@
#!/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: /\bconsole\.log\(/g, replacement: 'Log.log(', logMethod: 'log' },
{ pattern: /\bconsole\.info\(/g, replacement: 'Log.info(', logMethod: 'info' },
{ pattern: /\bconsole\.error\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /\bconsole\.warn\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /\bconsole\.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 {
// Check if there's already a Log import from core/log
return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"][^'"]*\/core\/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,
dryRun: boolean = false,
): { modified: boolean; changes: number } {
try {
let content = fs.readFileSync(filePath, 'utf8');
const originalContent = content;
let changeCount = 0;
// Apply replacements - this will replace even in comments, which is what we want
for (const { pattern, replacement } of replacements) {
const matches = content.match(pattern);
if (matches) {
changeCount += matches.length;
content = content.replace(pattern, replacement);
}
}
// If we made changes and don't have the correct Log import, add it
if (changeCount > 0 && !hasLogImport(content)) {
const importPath = calculateImportPath(filePath);
content = addLogImport(content, importPath);
}
const modified = content !== originalContent;
if (modified && !dryRun) {
fs.writeFileSync(filePath, content, 'utf8');
}
return { modified, changes: changeCount };
} catch (error) {
console.error(`Error processing ${filePath}:`, error);
return { modified: false, changes: 0 };
}
}
function main() {
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
console.log('Starting FORCED console to Log migration...');
console.log('This will replace ALL console.* calls, including those in comments.');
if (dryRun) {
console.log('Running in DRY RUN mode - no files will be modified\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: { path: string; changes: number }[] = [];
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 (with word boundary)
const logCount = (content.match(/\bconsole\.log\(/g) || []).length;
const infoCount = (content.match(/\bconsole\.info\(/g) || []).length;
const errorCount = (content.match(/\bconsole\.error\(/g) || []).length;
const warnCount = (content.match(/\bconsole\.warn\(/g) || []).length;
const debugCount = (content.match(/\bconsole\.debug\(/g) || []).length;
stats.log += logCount;
stats.info += infoCount;
stats.error += errorCount;
stats.warn += warnCount;
stats.debug += debugCount;
const result = processFile(file, dryRun);
if (result.modified) {
modifiedFiles.push({ path: file, changes: result.changes });
}
}
stats.total = stats.log + stats.info + stats.error + stats.warn + stats.debug;
console.log('\nMigration 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(
`\n${dryRun ? 'Would modify' : 'Modified'} ${modifiedFiles.length} files:\n`,
);
modifiedFiles
.sort((a, b) => b.changes - a.changes)
.forEach(({ path: filePath, changes }) => {
console.log(` - ${path.relative(process.cwd(), filePath)} (${changes} changes)`);
});
if (modifiedFiles.length === 0) {
console.log(' No files needed modification.');
}
}
// Run the migration
main();

View file

@ -11,11 +11,11 @@ interface Replacement {
}
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' },
{ pattern: /\bconsole\.log\(/g, replacement: 'Log.log(', logMethod: 'log' },
{ pattern: /\bconsole\.info\(/g, replacement: 'Log.info(', logMethod: 'info' },
{ pattern: /\bconsole\.error\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /\bconsole\.warn\(/g, replacement: 'Log.err(', logMethod: 'err' },
{ pattern: /\bconsole\.debug\(/g, replacement: 'Log.debug(', logMethod: 'debug' },
];
// Files to exclude
@ -48,7 +48,8 @@ function calculateImportPath(filePath: string): string {
}
function hasLogImport(content: string): boolean {
return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"].*\/log['"]/.test(content);
// More flexible pattern that matches any Log import
return /import\s+{[^}]*\bLog\b[^}]*}\s+from\s+['"].*['"]/.test(content);
}
function addLogImport(content: string, importPath: string): string {
@ -72,20 +73,20 @@ function addLogImport(content: string, importPath: string): string {
}
}
function processFile(filePath: string): boolean {
function processFile(filePath: string, dryRun: boolean = false): boolean {
try {
let content = fs.readFileSync(filePath, 'utf8');
const originalContent = content;
let hasChanges = false;
// Check if file uses any console methods
// Check if file uses any console methods (including in comments)
const usesConsole = replacements.some((r) => r.pattern.test(content));
if (!usesConsole) {
return false;
}
// Apply replacements
// Apply replacements - this will replace even in comments, which is what we want
for (const { pattern, replacement } of replacements) {
if (pattern.test(content)) {
content = content.replace(pattern, replacement);
@ -99,7 +100,9 @@ function processFile(filePath: string): boolean {
}
if (content !== originalContent) {
fs.writeFileSync(filePath, content, 'utf8');
if (!dryRun) {
fs.writeFileSync(filePath, content, 'utf8');
}
return true;
}
@ -111,7 +114,13 @@ function processFile(filePath: string): boolean {
}
function main() {
console.log('Starting console to Log migration...\n');
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
console.log('Starting console to Log migration...');
if (dryRun) {
console.log('Running in DRY RUN mode - no files will be modified\n');
}
// Find all TypeScript files
const files = glob.sync('src/**/*.ts', {
@ -134,21 +143,22 @@ function main() {
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;
// Count occurrences before processing (with word boundary)
stats.log += (content.match(/\bconsole\.log\(/g) || []).length;
stats.info += (content.match(/\bconsole\.info\(/g) || []).length;
stats.error += (content.match(/\bconsole\.error\(/g) || []).length;
stats.warn += (content.match(/\bconsole\.warn\(/g) || []).length;
stats.debug += (content.match(/\bconsole\.debug\(/g) || []).length;
if (processFile(file)) {
const willModify = processFile(file, dryRun);
if (willModify) {
modifiedFiles.push(file);
}
}
stats.total = stats.log + stats.info + stats.error + stats.warn + stats.debug;
console.log('Migration complete!\n');
console.log('\nMigration complete!\n');
console.log('Statistics:');
console.log(` Total console calls found: ${stats.total}`);
console.log(` - console.log: ${stats.log}`);
@ -156,7 +166,7 @@ function main() {
console.log(` - console.error: ${stats.error}`);
console.log(` - console.warn: ${stats.warn}`);
console.log(` - console.debug: ${stats.debug}`);
console.log(`\nModified ${modifiedFiles.length} files:`);
console.log(`\n${dryRun ? 'Would modify' : 'Modified'} ${modifiedFiles.length} files:`);
modifiedFiles.forEach((file) => {
console.log(` - ${path.relative(process.cwd(), file)}`);

View file

@ -4,14 +4,24 @@ 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/core-ui/drop-list/drop-list.service.ts',
'src/app/core-ui/side-nav/side-nav.component.ts',
'src/app/core/banner/banner.service.ts',
'src/app/features/config/form-cfgs/domina-mode-form.const.ts',
'src/app/features/focus-mode/focus-mode.service.ts',
'src/app/features/schedule/create-task-placeholder/create-task-placeholder.component.ts',
'src/app/features/schedule/map-schedule-data/create-blocked-blocks-by-day-map.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',
'src/app/features/schedule/map-schedule-data/insert-blocked-blocks-view-entries-for-schedule.ts',
'src/app/features/schedule/map-schedule-data/map-to-schedule-days.ts',
'src/app/features/task-repeat-cfg/sort-repeatable-task-cfg.ts',
'src/app/features/tasks/dialog-task-detail-panel/dialog-task-detail-panel.component.ts',
'src/app/features/work-context/store/work-context-meta.helper.ts',
'src/app/root-store/index.ts',
'src/app/ui/duration/input-duration-formly/input-duration-formly.component.ts',
'src/app/ui/inline-markdown/inline-markdown.component.ts',
'src/app/util/is-touch-only.ts',
'src/app/util/watch-object.ts',
];
function removeUnusedLogImport(filePath: string): void {

View file

@ -20,7 +20,7 @@ export class DropListService {
} else {
this.dropLists.next([...this.dropLists.getValue(), dropList]);
}
// console.log(this.dropLists.getValue());
// Log.log(this.dropLists.getValue());
}
unregisterDropList(dropList: CdkDropList): void {

View file

@ -10,6 +10,7 @@ import {
} from 'rxjs/operators';
import { PROGRESS_BAR_LABEL_MAP } from './global-progress-bar.const';
import { T } from '../../t.const';
import { Log } from '../../core/log';
const DELAY = 100;
@ -32,7 +33,7 @@ export class GlobalProgressBarService {
return isShow
? timer(60 * 1000).pipe(
tap(() => {
console.error('Global spinner was shown forever (60s). Forcing countDown!');
Log.err('Global spinner was shown forever (60s). Forcing countDown!');
this.countDown();
}),
)

View file

@ -9,6 +9,7 @@ import { Task } from '../../features/tasks/task.model';
import { getWorklogStr } from '../../util/get-work-log-str';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -36,7 +37,7 @@ export class NavigateToTaskService {
await this._router.navigate([location], { queryParams });
}
} catch (err) {
console.error(err);
Log.err(err);
this._snackService.open({
type: 'ERROR',
msg: T.GLOBAL_SNACK.NAVIGATE_TO_TASK_ERR,

View file

@ -166,7 +166,7 @@ export class SideNavComponent implements OnDestroy {
this.keyboardFocusTimeout = window.setTimeout(() => {
this.keyManager?.setFirstItemActive();
}, 100);
// this.keyManager.change.subscribe((v) => console.log('this.keyManager.change', v));
// this.keyManager.change.subscribe((v) => Log.log('this.keyManager.change', v));
} else if (!isShow) {
this._taskService.focusFirstTaskIfVisible();
}

View file

@ -124,7 +124,7 @@ export class BannerService {
dismiss(bannerId: BannerId): void {
const bannerIndex = this._banners.findIndex((bannerIN) => bannerIN.id === bannerId);
// console.log('BannerService -> dismissing Banner', bannerId);
// Log.log('BannerService -> dismissing Banner', bannerId);
if (bannerIndex > -1) {
// NOTE splice mutates
this._banners.splice(bannerIndex, 1);

View file

@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { ExtensionInterfaceEventName } from './chrome-extension-interface';
import { Observable, ReplaySubject } from 'rxjs';
import { first, startWith } from 'rxjs/operators';
import { Log } from '../log';
const interfaceEl = window;
@ -20,7 +21,7 @@ export class ChromeExtensionInterfaceService {
interfaceEl.addEventListener('SP_EXTENSION_READY', () => {
// we only want to show the notification once
if (!this._isInterfaceReady) {
console.log('SUCCESS', 'Super Productivity Extension found and loaded.');
Log.log('SUCCESS', 'Super Productivity Extension found and loaded.');
this._isInterfaceReady = true;
this._onReady$.next(true);
}

View file

@ -6,6 +6,7 @@ import { isDataRepairPossible } from '../../pfapi/repair/is-data-repair-possible
import { getLastValidityError } from '../../pfapi/validate/is-related-model-data-valid';
import { IS_ELECTRON } from '../../app.constants';
import { AppDataCompleteNew } from '../../pfapi/pfapi-config';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -17,7 +18,7 @@ export class DataRepairService {
dataIn: AppDataCompleteLegacy | AppDataCompleteNew,
): boolean {
if (!isDataRepairPossible(dataIn)) {
console.log({ dataIn });
Log.log({ dataIn });
alert('Data damaged, repair not possible.');
return false;
}

View file

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

View file

@ -14,6 +14,7 @@ import {
import { Tick } from './tick.model';
import { DateService } from 'src/app/core/date/date.service';
import { GlobalConfigService } from 'src/app/features/config/global-config.service';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -46,7 +47,7 @@ export class GlobalTrackingIntervalService {
startWith(this._dateService.todayStr()),
concatMap(() => of(this._dateService.todayStr())),
distinctUntilChanged(),
tap((v) => console.log('DAY_CHANGE ' + v)),
tap((v) => Log.log('DAY_CHANGE ' + v)),
// needs to be shareReplay otherwise some instances will never receive an update until a change occurs
shareReplay(1),
);

View file

@ -6,6 +6,7 @@ import { T } from '../t.const';
import { SwUpdate } from '@angular/service-worker';
import { isOnline } from '../util/is-online';
import { TranslateService } from '@ngx-translate/core';
import { Log } from './log';
@Injectable({
providedIn: 'root',
@ -19,7 +20,7 @@ export class InitialPwaUpdateCheckService {
!IS_ELECTRON && this._swUpdate.isEnabled && isOnline()
? from(this._swUpdate.checkForUpdate()).pipe(
concatMap((isUpdateAvailable) => {
console.log(
Log.log(
'___________isServiceWorkerUpdateAvailable____________',
isUpdateAvailable,
);

View file

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

View file

@ -6,6 +6,7 @@ import { IS_MOBILE } from '../../util/is-mobile';
import { TranslateService } from '@ngx-translate/core';
import { UiHelperService } from '../../features/ui-helper/ui-helper.service';
import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -79,7 +80,7 @@ export class NotifyService {
return instance;
}
}
console.warn('No notifications supported');
Log.err('No notifications supported');
return undefined;
}

View file

@ -5,6 +5,7 @@ import { filter, shareReplay, take } from 'rxjs/operators';
import { DBSchema, openDB } from 'idb';
import { DBAdapter } from './db-adapter.model';
import { Log } from '../log';
import { Log } from '../log';
const DB_NAME = 'SUP';
const DB_MAIN_NAME = 'SUP_STORE';
@ -35,7 +36,7 @@ export class IndexedDBAdapterService implements DBAdapter {
// upgrade(db: IDBPDatabase<MyDb>, oldVersion: number, newVersion: number | null, transaction: IDBPTransaction<MyDb>) {
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
upgrade(db: IDBPDatabase<MyDb>, oldVersion: number, newVersion: number | null) {
console.log('IDB UPGRADE', oldVersion, newVersion);
Log.log('IDB UPGRADE', oldVersion, newVersion);
db.createObjectStore(DB_MAIN_NAME);
},
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions

View file

@ -44,6 +44,7 @@ import { PersistenceLocalService } from './persistence-local.service';
import { PlannerState } from '../../features/planner/store/planner.reducer';
import { IssueProvider, IssueProviderState } from '../../features/issue/issue.model';
import { BoardsState } from '../../features/boards/store/boards.reducer';
import { Log } from '../log';
@Injectable({
providedIn: 'root',
@ -282,7 +283,7 @@ export class PersistenceLegacyService {
return r;
} else {
console.warn('BLOCKED SAVING for ', dbKey);
Log.err('BLOCKED SAVING for ', dbKey);
return Promise.reject('Data import currently in progress. Saving disabled');
}
}

View file

@ -1,5 +1,6 @@
import { inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Log } from '../log';
export interface CustomTheme {
id: string;
@ -56,7 +57,7 @@ export class CustomThemeService {
const theme = AVAILABLE_CUSTOM_THEMES.find((t) => t.id === themeId);
if (!theme) {
console.error(`Theme with id ${themeId} not found`);
Log.err(`Theme with id ${themeId} not found`);
return;
}

View file

@ -30,6 +30,7 @@ import { HttpClient } from '@angular/common/http';
import { LS } from '../persistence/storage-keys.const';
import { CustomThemeService } from './custom-theme.service';
import { Log } from '../log';
import { Log } from '../log';
export type DarkModeCfg = 'dark' | 'light' | 'system';
@ -221,7 +222,7 @@ export class GlobalThemeService {
if (IS_ANDROID_WEB_VIEW) {
androidInterface.isKeyboardShown$.subscribe((isShown) => {
console.log('isShown', isShown);
Log.log('isShown', isShown);
this.document.body.classList.remove(BodyClass.isAndroidKeyboardHidden);
this.document.body.classList.remove(BodyClass.isAndroidKeyboardShown);

View file

@ -17,6 +17,7 @@ import { getWorklogStr } from '../../util/get-work-log-str';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { selectTodayTaskIds } from '../work-context/store/work-context.selectors';
import { selectTasksForPlannerDay } from '../planner/store/planner.selectors';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -105,7 +106,7 @@ export class AddTasksForTomorrowService {
const allDueSorted = this._sortAll([
...allDue.filter((t) => !todaysTaskIds.includes(t.id)),
]);
console.log({ allDue, allDueSorted });
Log.log({ allDue, allDueSorted });
this._movePlannedTasksToToday(allDueSorted);

View file

@ -6,6 +6,7 @@ import { ProjectCfgFormKey } from '../../project/project.model';
import { T } from '../../../t.const';
import { exists } from '../../../util/exists';
import { adjustToLiveFormlyForm } from '../../../util/adjust-to-live-formly-form';
import { Log } from '../../../core/log';
@Component({
selector: 'config-form',
@ -60,7 +61,7 @@ export class ConfigFormComponent {
} else {
// Update validity to ensure error messages are shown
this.form.updateValueAndValidity();
console.warn('Form is invalid, not saving config:', this.form.errors);
Log.err('Form is invalid, not saving config:', this.form.errors);
}
}
}

View file

@ -68,7 +68,7 @@ export const DOMINA_MODE_FORM: ConfigFormSection<DominaModeConfig> = {
onInit: (field) => {
let voices: SpeechSynthesisVoice[] = getAvailableVoices() || [];
voices = getAvailableVoices();
//console.log(voices);
//Log.log(voices);
if (field.templateOptions) {
field.templateOptions.options = voices.map((voiceName) => ({

View file

@ -13,6 +13,7 @@ import { KeyboardConfig } from '../keyboard-config.model';
import { updateGlobalConfigSection } from './global-config.actions';
import { MiscConfig } from '../global-config.model';
import { selectMiscConfig } from './global-config.reducer';
import { Log } from '../../../core/log';
@Injectable()
export class GlobalConfigEffects {
@ -137,7 +138,7 @@ export class GlobalConfigEffects {
pairwise(),
filter(([a, b]) => a.isUseMinimalNav !== b.isUseMinimalNav),
tap(() => {
console.log('AA');
Log.log('AA');
// this._store.dispatch(hideSideNav());
// this._store.dispatch(toggleSideNav());
window.dispatchEvent(new Event('resize'));

View file

@ -1,7 +1,9 @@
import { Log } from '../../core/log';
export const getAvailableVoices = (): SpeechSynthesisVoice[] => {
const synth = window.speechSynthesis;
if (!synth) {
console.warn('window.speechSynthesis not available');
Log.err('window.speechSynthesis not available');
return [];
}

View file

@ -60,7 +60,7 @@ export class FocusModeService {
scan((acc, value) => {
// NOTE: to prevent initial negative acc values
const accValMinZero = acc < 0 ? 0 : acc;
// console.log('VALUPD currentSessionTime', value, value < 0, accValMinZero);
// Log.log('VALUPD currentSessionTime', value, value < 0, accValMinZero);
return value < 0 ? accValMinZero - value : value;
}),
shareReplay(1),

View file

@ -60,7 +60,7 @@ export class IssuePanelCalendarAgendaComponent implements OnInit {
throw new Error('Issue Provider and Search Result Type dont match');
}
console.log('Add issue', item);
Log.log('Add issue', item);
this._issueService.addTaskFromIssue({
issueDataReduced: item.issueData,

View file

@ -256,7 +256,7 @@ export class IssueProviderTabComponent implements OnDestroy, AfterViewInit {
throw new Error('Issue Provider and Search Result Type dont match');
}
console.log('Add issue', item);
Log.log('Add issue', item);
this._issueService.addTaskFromIssue({
issueDataReduced: item.issueData,

View file

@ -48,6 +48,7 @@ import { MatButton } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { IS_ANDROID_WEB_VIEW } from '../../../util/is-android-web-view';
import { devError } from '../../../util/dev-error';
import { Log } from '../../../core/log';
@Component({
selector: 'dialog-edit-issue-provider',
@ -148,7 +149,7 @@ export class DialogEditIssueProviderComponent {
}
customCfgCmpSave(cfgUpdates: IssueIntegrationCfg): void {
console.log('customCfgCmpSave()', cfgUpdates);
Log.log('customCfgCmpSave()', cfgUpdates);
this.updateModel(cfgUpdates);
}

View file

@ -6,13 +6,14 @@ import { HANDLED_ERROR_PROP_STR } from '../../app.constants';
import { IssueProviderKey } from './issue.model';
import { getErrorTxt } from '../../util/get-error-text';
import { SnackService } from '../../core/snack/snack.service';
import { Log } from '../../core/log';
export const handleIssueProviderHttpError$ = <T>(
issueProviderKey: IssueProviderKey,
snackService: SnackService,
error: HttpErrorResponse,
): ObservableInput<T> => {
console.log(error);
Log.log(error);
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
snackService.open({

View file

@ -547,7 +547,7 @@ export class IssueService {
// this.ISSUE_SERVICE_MAP[issueProviderKey].getAddTaskData(freshIssueData);
// this._taskService.update(taskId, {});
// } catch (e) {
// console.error(e);
// Log.err(e);
// this._taskService.remove(taskId);
// // TODO show error msg
// }

View file

@ -115,7 +115,7 @@ export class CaldavClientService {
const todo = comp.getFirstSubcomponent('vtodo');
if (!todo) {
console.log(task);
Log.log(task);
throw new Error('No todo found for task');
}

View file

@ -23,6 +23,7 @@ import { HANDLED_ERROR_PROP_STR } from '../../../../app.constants';
import { T } from '../../../../t.const';
import { throwHandledError } from '../../../../util/throw-handled-error';
import { GITHUB_TYPE, ISSUE_PROVIDER_HUMANIZED } from '../../issue.const';
import { Log } from '../../../../core/log';
const BASE = GITHUB_API_BASE_URL;
@ -144,7 +145,7 @@ query Issues {
try {
return mapGithubGraphQLSearchResult(res);
} catch (e) {
console.error(e);
Log.err(e);
this._snackService.open({
type: 'ERROR',
msg: T.F.GITHUB.S.CONFIG_ERROR,

View file

@ -39,6 +39,7 @@ import { MsToClockStringPipe } from '../../../../../ui/duration/ms-to-clock-stri
import { MatTooltip } from '@angular/material/tooltip';
import { InlineInputComponent } from '../../../../../ui/inline-input/inline-input.component';
import { MatButton } from '@angular/material/button';
import { Log } from '../../../../../core/log';
interface TmpTask {
id: string;
@ -209,7 +210,7 @@ export class DialogGitlabSubmitWorklogForDayComponent {
});
this.close();
} catch (e) {
console.error(e);
Log.err(e);
this._snackService.open({
type: 'ERROR',
// TODO translate

View file

@ -148,7 +148,7 @@ export class JiraIssueContentComponent {
try {
this.description = i && i.description && j2m.to_markdown(i.description);
} catch (e) {
console.log(i);
Log.log(i);
devError(e);
this.description = (i && i.description) || undefined;
}

View file

@ -13,6 +13,7 @@ import { isJiraEnabled } from './is-jira-enabled.util';
import { JIRA_POLL_INTERVAL } from './jira.const';
import { IssueProviderService } from '../../issue-provider.service';
import { assertTruthy } from '../../../../util/assert-truthy';
import { Log } from '../../../../core/log';
@Injectable({
providedIn: 'root',
@ -63,7 +64,7 @@ export class JiraCommonInterfacesService implements IssueServiceInterface {
this.isEnabled(jiraCfg)
? this._jiraApiService
.issuePicker$(searchTerm, jiraCfg)
.pipe(tap((v) => console.log('jira.issuePicker$', v)))
.pipe(tap((v) => Log.log('jira.issuePicker$', v)))
: of([]),
),
)

View file

@ -19,6 +19,7 @@ import {
} from './format-open-project-work-package-subject.util';
import { IssueProviderService } from '../../issue-provider.service';
import { getWorklogStr } from '../../../../util/get-work-log-str';
import { Log } from '../../../../core/log';
@Injectable({
providedIn: 'root',
@ -167,7 +168,7 @@ export class OpenProjectCommonInterfacesService implements IssueServiceInterface
allExistingIssueIds: number[] | string[],
): Promise<OpenProjectWorkPackageReduced[]> {
const cfg = await this._getCfgOnce$(issueProviderId).toPromise();
console.log(
Log.log(
await this._openProjectApiService
.getLast100WorkPackagesForCurrentOpenProjectProject$(cfg)
.toPromise(),

View file

@ -10,6 +10,7 @@ import {
IssueProviderState,
} from '../issue.model';
import { ICAL_TYPE } from '../issue.const';
import { Log } from '../../../core/log';
export const selectIssueProviderState = createFeatureSelector<IssueProviderState>(
ISSUE_PROVIDER_FEATURE_KEY,
@ -48,7 +49,7 @@ export const selectIssueProviderById = <T extends IssueProvider>(
throw new Error(`No issueProvider found for id ${id}`);
}
if (issueProviderKey && issueProvider.issueProviderKey !== issueProviderKey) {
console.log(issueProviderKey, issueProvider);
Log.log(issueProviderKey, issueProvider);
throw new Error(
`IssueProvider found for id ${id} is not of type ${issueProviderKey} but ${issueProvider.issueProviderKey}`,
);

View file

@ -72,7 +72,7 @@ export class PollToBacklogEffects {
this._issueService.getPollInterval(provider.issueProviderKey),
).pipe(
takeUntil(this.pollToBacklogActions$),
tap(() => console.log('POLL ' + provider.issueProviderKey)),
tap(() => Log.log('POLL ' + provider.issueProviderKey)),
switchMap(() =>
this._issueService.checkAndImportNewIssuesToBacklogForProject(
provider.issueProviderKey,

View file

@ -9,6 +9,7 @@ import { Update } from '@ngrx/entity/src/models';
import { Store } from '@ngrx/store';
import { __updateMultipleTaskSimple } from '../../tasks/store/task.actions';
import { TaskArchiveService } from '../../time-tracking/task-archive.service';
import { Log } from '../../../core/log';
@Injectable()
export class UnlinkAllTasksOnProviderDeletionEffects {
@ -71,7 +72,7 @@ export class UnlinkAllTasksOnProviderDeletionEffects {
await this._taskArchiveService.updateTasks(archiveTaskUpdates);
console.log('unlinkAllTasksOnProviderDeletion$', {
Log.log('unlinkAllTasksOnProviderDeletion$', {
regularTasks,
archiveTasks,
taskUpdates,

View file

@ -30,6 +30,7 @@ import { InlineInputComponent } from '../../../ui/inline-input/inline-input.comp
import { MsToStringPipe } from '../../../ui/duration/ms-to-string.pipe';
import { IssueIconPipe } from '../../issue/issue-icon/issue-icon.pipe';
import { ShortDate2Pipe } from '../../../ui/pipes/short-date2.pipe';
import { Log } from '../../../core/log';
@Component({
selector: 'planner-task',
@ -149,7 +150,7 @@ export class PlannerTaskComponent extends BaseComponent implements OnInit, OnDes
}
updateTimeEstimate(val: number): void {
console.log(val);
Log.log(val);
this._taskService.update(this.task.id, {
timeEstimate: val,
});

View file

@ -1,6 +1,7 @@
import { ScheduleConfig } from '../../config/global-config.model';
import { getDateTimeFromClockString } from '../../../util/get-date-time-from-clock-string';
import { dateStrToUtcDate } from '../../../util/date-str-to-utc-date';
import { Log } from '../../../core/log';
export const DEFAULT_WORK_HOURS = 8 * 60 * 60 * 1000; // 8 hours in milliseconds
@ -36,7 +37,7 @@ export const calculateAvailableHours = (
return Math.max(0, availableTime);
} catch (error) {
// If there's an error parsing time strings, return default
console.error('Error calculating available hours:', error);
Log.err('Error calculating available hours:', error);
return DEFAULT_WORK_HOURS;
}
};

View file

@ -37,6 +37,7 @@ import { getRandomWorkContextColor } from '../../../work-context/work-context-co
import { removeDebounceFromFormItems } from '../../../../util/remove-debounce-from-form-items';
import { MatButton } from '@angular/material/button';
import { TranslatePipe } from '@ngx-translate/core';
import { Log } from '../../../../core/log';
@Component({
selector: 'dialog-create-project',
@ -138,7 +139,7 @@ export class DialogCreateProjectComponent implements OnInit, OnDestroy {
// Mark all fields as touched to show validation errors
this.formBasic.markAllAsTouched();
this.formTheme.markAllAsTouched();
console.warn('Form validation failed', {
Log.err('Form validation failed', {
basicFormErrors: this.formBasic.errors,
themeFormErrors: this.formTheme.errors,
});

View file

@ -79,7 +79,7 @@ const _fixIds = (projectState: ProjectState): ProjectState => {
if (!currentIds) {
Log.err('Project Ids not defined');
console.log('Attempting to fix...');
Log.log('Attempting to fix...');
return {
...projectState,
ids: allIds,

View file

@ -28,6 +28,7 @@ import { ProjectService } from '../../project/project.service';
import { Router } from '@angular/router';
import { DataInitStateService } from '../../../core/data-init/data-init-state.service';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { Log } from '../../../core/log';
const UPDATE_PERCENTAGE_INTERVAL = 250;
// since the reminder modal doesn't show instantly we adjust a little for that
@ -136,7 +137,7 @@ export class ReminderCountdownEffects {
) as string;
const nrOfAllBanners = dueRemindersAndTasks.length;
console.log({
Log.log({
firstDueTask,
firstDue,
dueRemindersAndTasks,

View file

@ -29,6 +29,7 @@ import {
} from '../../core-ui/layout/store/layout.reducer';
import { hidePluginPanel } from '../../core-ui/layout/store/layout.actions';
import { fastArrayCompare } from '../../util/fast-array-compare';
import { Log } from '../../core/log';
@Component({
selector: 'right-panel',
@ -113,7 +114,7 @@ export class RightPanelComponent implements OnDestroy {
map(([isShowPluginPanel, activePluginId]) => {
const keys =
isShowPluginPanel && activePluginId ? [`plugin-${activePluginId}`] : [];
console.log('RightPanel: pluginPanelKeys$ emitted:', {
Log.log('RightPanel: pluginPanelKeys$ emitted:', {
isShowPluginPanel,
activePluginId,
keys,

View file

@ -40,7 +40,7 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
isForDayMode = signal<boolean>(false);
due: Signal<number> = computed(() => {
if (this.date() && this.time()) {
// console.log(this.date(), this.time());
// Log.log(this.date(), this.time());
const formattedTime = this._formatTimeWithLeadingZero(this.time() as string);
return new Date(`${this.date()}T${formattedTime}`).getTime();
}

View file

@ -33,7 +33,7 @@ export const createBlockedBlocksByDayMap = (
now,
nrOfDays,
);
// console.log(allBlockedBlocks);
// Log.log(allBlockedBlocks);
const blockedBlocksByDay: BlockedBlockByDayMap = {};

View file

@ -13,6 +13,7 @@ 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,
@ -132,7 +133,7 @@ const createViewEntriesForNonScheduledRepeatProjections = (
const lastEntry = viewEntries[viewEntries.length - 1];
// console.log(viewEntries);
// Log.log(viewEntries);
return {
entries: viewEntries,

View file

@ -17,7 +17,7 @@ import {
} from './is-schedule-types-type';
import { createViewEntriesForBlock } from './create-view-entries-for-block';
// const debug = (...args: any): void => console.log(...args);
// const debug = (...args: any): void => Log.log(...args);
const debug = (...args: any): void => undefined;
export const insertBlockedBlocksViewEntriesForSchedule = (

View file

@ -42,7 +42,7 @@ export const mapToScheduleDays = (
// workStartEndCfg,
// lunchBreakCfg,
// };
// console.log(JSON.stringify(params));
// Log.log(JSON.stringify(params));
const plannerDayKeys = Object.keys(plannerDayMap);
// const plannerDayTasks = plannerDayKeys

View file

@ -33,6 +33,7 @@ import {
} from './tag.actions';
import { PlannerActions } from '../../planner/store/planner.actions';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { Log } from '../../../core/log';
export const TAG_FEATURE_NAME = 'tag';
const WORK_CONTEXT_TYPE: WorkContextType = WorkContextType.TAG;
@ -343,7 +344,7 @@ export const tagReducer = createReducer<TagState>(
on(updateTagOrder, (state: TagState, { ids }) => {
if (ids.length !== state.ids.length) {
console.log({ state, ids });
Log.log({ state, ids });
throw new Error('Tag length should not change on re-order');
}

View file

@ -43,6 +43,7 @@ import { ChipListInputComponent } from '../../../ui/chip-list-input/chip-list-in
import { MatButton } from '@angular/material/button';
import { AsyncPipe } from '@angular/common';
import { MatIcon } from '@angular/material/icon';
import { Log } from '../../../core/log';
// TASK_REPEAT_CFG_FORM_CFG
@Component({
@ -192,7 +193,7 @@ export class DialogEditTaskRepeatCfgComponent implements OnInit, OnDestroy {
// Mark all fields as touched to show validation errors
this.formGroup1.markAllAsTouched();
this.formGroup2.markAllAsTouched();
console.warn('Form validation failed', {
Log.err('Form validation failed', {
form1Errors: this.formGroup1.errors,
form2Errors: this.formGroup2.errors,
});

View file

@ -14,4 +14,4 @@ export const sortRepeatableTaskCfgs = (a: TaskRepeatCfg, b: TaskRepeatCfg): numb
// arr.push({ order: 0 });
// arr.push({ order: 0 });
// arr.push({ order: 0 });
// console.log(arr.sort(sortRepeatableTaskCfgs as any));
// Log.log(arr.sort(sortRepeatableTaskCfgs as any));

View file

@ -47,6 +47,7 @@ import { TranslatePipe } from '@ngx-translate/core';
import { IssueIconPipe } from '../../issue/issue-icon/issue-icon.pipe';
import { TagComponent } from '../../tag/tag/tag.component';
import { TaskCopy } from '../task.model';
import { Log } from '../../../core/log';
@Component({
selector: 'add-task-bar',
@ -306,7 +307,7 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
const task = await this._taskService
.getByIdOnce$(this._lastAddedTaskId)
.toPromise();
console.log(additionalFields, tagsToRemove, task);
Log.log(additionalFields, tagsToRemove, task);
this._taskService.updateTags(
task,

View file

@ -9,6 +9,7 @@ import { Tag } from '../../tag/tag.model';
import { Project } from '../../project/project.model';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { ShortSyntaxConfig } from '../../config/global-config.model';
import { Log } from '../../../core/log';
export interface ShortSyntaxTag {
title: string;
@ -66,7 +67,7 @@ export const shortSyntaxToTags = ({
if (r.taskChanges.timeSpentOnDay && r.taskChanges.timeSpentOnDay[getWorklogStr()]) {
time = msToString(r.taskChanges.timeSpentOnDay[getWorklogStr()]) + '/' + time;
}
console.log(time);
Log.log(time);
shortSyntaxTags.push({
title: time,

View file

@ -42,7 +42,7 @@ export class DialogTaskDetailPanelComponent implements OnDestroy {
isSkipToggle: true,
}),
);
// this.task$.subscribe((v) => console.log(`task$`, v));
// this.task$.subscribe((v) => Log.log(`task$`, v));
}
// close(): void {

View file

@ -34,6 +34,7 @@ import { WorkContextService } from '../../work-context/work-context.service';
import { INBOX_PROJECT } from '../../project/project.const';
import { devError } from '../../../util/dev-error';
import { Log } from '../../../core/log';
@Injectable()
export class ShortSyntaxEffects {
@ -109,7 +110,7 @@ export class ShortSyntaxEffects {
projects,
);
if (environment.production) {
console.log('shortSyntax', r);
Log.log('shortSyntax', r);
}
const isAddDefaultProjectIfNecessary: boolean =
!!defaultProjectId &&

View file

@ -19,6 +19,7 @@ import { selectTodayTaskIds } from '../../work-context/store/work-context.select
import { AddTasksForTomorrowService } from '../../add-tasks-for-tomorrow/add-tasks-for-tomorrow.service';
import { getWorklogStr } from '../../../util/get-work-log-str';
import { environment } from '../../../../environments/environment';
import { Log } from '../../../core/log';
@Injectable()
export class TaskDueEffects {
@ -98,7 +99,7 @@ export class TaskDueEffects {
.map((task) => task.id);
if (!environment.production && missingTaskIds.length > 0) {
console.warn(
Log.err(
'[TaskDueEffects] Found tasks due today missing from TODAY tag:',
{
tasksDueToday: tasksDueToday.length,

View file

@ -12,6 +12,7 @@ import {
} from './task-attachment.actions';
import { TaskState } from '../task.model';
import { createFromDrop } from 'src/app/core/drop-paste-input/drop-paste-input';
import { Log } from '../../../core/log';
@Injectable({
providedIn: 'root',
@ -22,7 +23,7 @@ export class TaskAttachmentService {
addAttachment(taskId: string, taskAttachment: TaskAttachment): void {
if (!taskAttachment) {
console.error('No valid attachment passed');
Log.err('No valid attachment passed');
return;
}

View file

@ -404,7 +404,7 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
archiveInstances,
targetProject,
]) => {
console.log({
Log.log({
reminderCfg,
nonArchiveInstancesWithSubTasks,
archiveInstances,

View file

@ -87,6 +87,7 @@ import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { getWorklogStr } from '../../util/get-work-log-str';
import { INBOX_PROJECT } from '../project/project.const';
import { GlobalConfigService } from '../config/global-config.service';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -284,7 +285,7 @@ export class TaskService {
workContextId,
});
console.log(task, additional);
Log.log(task, additional);
this._store.dispatch(
TaskSharedActions.addTask({

View file

@ -1,5 +1,6 @@
import { TaskReminderOptionId } from '../task.model';
import { devError } from '../../../util/dev-error';
import { Log } from '../../../core/log';
export const remindOptionToMilliseconds = (
due: number,
@ -54,7 +55,7 @@ export const millisecondsDiffToRemindOption = (
} else if (diff <= 0) {
return TaskReminderOptionId.AtStart;
} else {
console.log(due, remindAt);
Log.log(due, remindAt);
devError('Cannot determine remind option. Invalid params');
return TaskReminderOptionId.DoNotRemind;
}

View file

@ -11,6 +11,7 @@ import {
import { Store } from '@ngrx/store';
import { TimeTrackingActions } from './store/time-tracking.actions';
import { getWorklogStr } from '../../util/get-work-log-str';
import { Log } from '../../core/log';
/*
# Considerations for flush architecture:
@ -136,7 +137,7 @@ export class ArchiveService {
isUpdateRevAndLastUpdate: true,
},
);
console.log(
Log.log(
'______________________\nFLUSHED ALL FROM ARCHIVE YOUNG TO OLD\n_______________________',
);
}

View file

@ -10,6 +10,7 @@ import { WorkContextType, WorkStartEnd } from '../work-context/work-context.mode
import { ImpossibleError } from '../../pfapi/api';
import { toLegacyWorkStartEndMaps } from './to-legacy-work-start-end-maps';
import { TimeTrackingActions } from './store/time-tracking.actions';
import { Log } from '../../core/log';
@Injectable({
providedIn: 'root',
@ -72,7 +73,7 @@ export class TimeTrackingService {
const archiveYoung = await this._pfapiService.m.archiveYoung.load();
const archiveOld = await this._pfapiService.m.archiveOld.load();
console.log({ current, archiveYoung, archiveOld });
Log.log({ current, archiveYoung, archiveOld });
if (projectId in current.project) {
const newProject = { ...current.project };

View file

@ -33,7 +33,7 @@ export class UiHelperService {
return;
}
const currentZoom = window.ea.getZoomFactor();
console.log({ currentZoom });
Log.log({ currentZoom });
const zoomFactor = currentZoom + zoomBy;

View file

@ -26,7 +26,7 @@ export const moveItemInList = (
partialList: string[],
emptyListVal = 0,
): string[] => {
// console.log(itemId, completeList, partialList);
// Log.log(itemId, completeList, partialList);
let newIndex;
const curInUpdateListIndex = partialList.indexOf(itemId);

View file

@ -8,6 +8,7 @@ import { ProjectCopy } from '../../project/project.model';
import { TagCopy } from '../../tag/tag.model';
import { WorklogTask } from '../../tasks/task.model';
import { WorklogExportSettingsCopy, WorklogGrouping } from '../worklog.model';
import { Log } from '../../../core/log';
import {
ItemsByKey,
RowItem,
@ -254,7 +255,7 @@ export const formatRows = (
0,
);
const timeSpentPart = row.timeSpent / timeSpentTotal;
console.log(`${row.timeSpent} / ${timeSpentTotal} = ${timeSpentPart}`);
Log.log(`${row.timeSpent} / ${timeSpentTotal} = ${timeSpentPart}`);
timeEstimate = timeEstimate * timeSpentPart;
}

View file

@ -36,6 +36,7 @@ import { NumberToMonthPipe } from '../../ui/pipes/number-to-month.pipe';
import { TranslatePipe } from '@ngx-translate/core';
import { PfapiService } from '../../pfapi/pfapi.service';
import { TaskArchiveService } from '../time-tracking/task-archive.service';
import { Log } from '../../core/log';
@Component({
selector: 'worklog',
@ -141,7 +142,7 @@ export class WorklogComponent implements AfterViewInit, OnDestroy {
.filter((v) => !!v);
}
console.log('RESTORE', task, subTasks);
Log.log('RESTORE', task, subTasks);
this._taskService.restoreTask(task, (subTasks || []) as Task[]);
this._router.navigate(['/active/tasks']);
}

View file

@ -28,6 +28,7 @@ import { TranslatePipe } from '@ngx-translate/core';
import { TagComponent } from '../../features/tag/tag/tag.component';
import { MatList, MatListItem } from '@angular/material/list';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { Log } from '../../core/log';
const MAX_RESULTS = 50;
@ -116,7 +117,7 @@ export class SearchPageComponent implements OnInit {
: (tags.find((tag) => tag.id === tagId) as Tag);
if (!context) {
console.warn(`Could not find context for task: ${task.title}`);
Log.err(`Could not find context for task: ${task.title}`);
context = { ...DEFAULT_TAG, icon: 'help_outline', color: 'black' };
}

View file

@ -106,7 +106,7 @@ export class Database {
try {
await this._adapter.init();
} catch (e) {
console.error(e);
Log.err(e);
SyncLog.critical('Database initialization failed', {
lastParams: this._lastParams,
error: e,

View file

@ -2,6 +2,7 @@ import { IDBPDatabase } from 'idb/build';
import { DBSchema, openDB } from 'idb';
import { DatabaseAdapter } from './database-adapter.model';
import { MiniObservable } from '../util/mini-observable';
import { Log } from '../../../core/log';
// otherwise the typing of idb dependency won't work
const FAKE = 'FAAAAAKE' as const;
@ -35,7 +36,7 @@ export class IndexedDbAdapter implements DatabaseAdapter {
// upgrade(db: IDBPDatabase<MyDb>, oldVersion: number, newVersion: number | null, transaction: IDBPTransaction<MyDb>) {
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
upgrade(db: IDBPDatabase<MyDb>, oldVersion: number, newVersion: number | null) {
console.log('IDB UPGRADE', oldVersion, newVersion);
Log.log('IDB UPGRADE', oldVersion, newVersion);
// TODO
db.createObjectStore(that._dbMainName as typeof FAKE);
// db.createObjectStore(FAKE_DB_MAIN_NAME);

View file

@ -3,6 +3,7 @@ import { Database } from '../db/database';
import { MetaModelCtrl } from './meta-model-ctrl';
import { SyncLog } from '../../../core/log';
import { ModelValidationError } from '../errors/errors';
import { Log } from '../../../core/log';
// type ExtractModelType<T extends ModelCfg<unknown>> = T extends ModelCfg<infer U> ? U : never;
@ -53,7 +54,7 @@ export class ModelCtrl<MT extends ModelBase> {
try {
data = this.modelCfg.repair(data);
} catch (e) {
console.error(e);
Log.err(e);
throw new ModelValidationError({
id: this.modelId,
data,

View file

@ -177,7 +177,7 @@ export class Pfapi<const MD extends ModelCfgs> {
if (activeProviderId) {
const provider = this.syncProviders.find((sp) => sp.id === activeProviderId);
if (!provider) {
console.log(provider, activeProviderId);
Log.log(provider, activeProviderId);
throw new InvalidSyncProviderError();
}
this._activeSyncProvider$.next(provider);

View file

@ -10,6 +10,7 @@ import {
decompressGzipFromString,
} from '../compression/compression-handler';
import { EncryptAndCompressCfg } from '../pfapi.model';
import { Log } from '../../../core/log';
export class EncryptAndCompressHandlerService {
private static readonly L = 'EncryptAndCompressHandlerService';
@ -76,7 +77,7 @@ export class EncryptAndCompressHandlerService {
}
if (isEncrypt) {
if (!encryptKey) {
console.log(encryptKey);
Log.log(encryptKey);
throw new Error('No encryption password provided');
}

View file

@ -25,6 +25,7 @@ import { cleanRev } from '../util/clean-rev';
import { getModelIdsToUpdateFromRevMaps } from '../util/get-model-ids-to-update-from-rev-maps';
import { Pfapi } from '../pfapi';
import { SyncProviderId } from '../pfapi.const';
import { Log } from '../../../core/log';
export class ModelSyncService<MD extends ModelCfgs> {
private static readonly L = 'ModelSyncService';
@ -328,7 +329,7 @@ export class ModelSyncService<MD extends ModelCfgs> {
*/
private _isSameRev(a: string | null, b: string | null): boolean {
if (!a || !b) {
console.warn(`Invalid revs a:${a} and b:${b} given`);
Log.err(`Invalid revs a:${a} and b:${b} given`);
return false;
}
if (a === b) {

View file

@ -1,5 +1,6 @@
import { FileAdapter } from '../file-adapter.interface';
import { SafService } from './saf.service';
import { Log } from '../../../../../../core/log';
export class SafFileAdapter implements FileAdapter {
constructor(private getUri: () => Promise<string | undefined>) {}
@ -37,7 +38,7 @@ export class SafFileAdapter implements FileAdapter {
} catch (error) {
// Ignore file not found errors
if (error?.toString?.().includes('File not found')) {
console.error(`File not found for deletion: ${filePath}`);
Log.err(`File not found for deletion: ${filePath}`);
return;
}
throw error;

View file

@ -3,6 +3,7 @@ import { LocalFileSyncBase } from './local-file-sync-base';
import { LocalFileSyncPrivateCfg } from '../../../pfapi.model';
import { SafService } from './droid-saf/saf.service';
import { SafFileAdapter } from './droid-saf/saf-file-adapter';
import { Log } from '../../../../../core/log';
export class LocalFileSyncAndroid extends LocalFileSyncBase {
constructor(public directory = Directory.Documents) {
@ -39,7 +40,7 @@ export class LocalFileSyncAndroid extends LocalFileSyncBase {
});
return uri;
} catch (error) {
console.error('Failed to setup SAF:', error);
Log.err('Failed to setup SAF:', error);
return undefined;
}
}

View file

@ -1,3 +1,5 @@
import { Log } from '../../../core/log';
export class MiniObservable<T, E extends typeof Error = typeof Error> {
private _value: T;
private _listeners: Array<(value: T) => void> = [];
@ -33,7 +35,7 @@ export class MiniObservable<T, E extends typeof Error = typeof Error> {
subscribe(listener: (value: T) => void): () => void {
if (this._closed) {
console.warn('Cannot subscribe to a closed observable');
Log.err('Cannot subscribe to a closed observable');
return () => {};
}

View file

@ -246,7 +246,7 @@ export const PFAPI_CFG: PfapiBaseCfg<PfapiAllModelCfg> = {
const r = validateAllData(data);
if (!environment.production && !r.success) {
console.log(r);
Log.log(r);
alert('VALIDATION ERROR ');
}

View file

@ -20,7 +20,7 @@ export class PluginHooksService {
this._handlers.set(hook, new Map());
}
this._handlers.get(hook)!.set(pluginId, handler);
console.log(`Plugin ${pluginId} registered for ${hook}`);
Log.log(`Plugin ${pluginId} registered for ${hook}`);
}
/**

View file

@ -88,7 +88,7 @@ export class PluginLoaderService {
return { manifest, code, indexHtml, icon };
} catch (error) {
console.error(`Failed to load plugin from ${pluginPath}:`, error);
Log.err(`Failed to load plugin from ${pluginPath}:`, error);
throw error;
}
}

View file

@ -173,7 +173,7 @@ export class PluginRunner {
// Unregister hooks
this._pluginBridge.unregisterPluginHooks(pluginId);
console.log(`Plugin ${pluginId} unloaded`);
Log.log(`Plugin ${pluginId} unloaded`);
return true;
}
return false;

View file

@ -13,6 +13,7 @@ import { DialogButtonCfg, DialogCfg } from '../../plugin-api.model';
import { PluginSecurityService } from '../../plugin-security';
import { TranslateService } from '@ngx-translate/core';
import { T } from '../../../t.const';
import { Log } from '../../../core/log';
@Component({
selector: 'plugin-dialog',
@ -114,7 +115,7 @@ export class PluginDialogComponent {
this._dialogRef.close(button.label);
}
} catch (error) {
console.error('Plugin dialog button action failed:', error);
Log.err('Plugin dialog button action failed:', error);
this._dialogRef.close('error');
}
}

View file

@ -12,6 +12,7 @@ import { Store } from '@ngrx/store';
import { selectActivePluginId } from '../../../core-ui/layout/store/layout.reducer';
import { PluginIndexComponent } from '../plugin-index/plugin-index.component';
import { CommonModule } from '@angular/common';
import { Log } from '../../../core/log';
/**
* Container component for rendering plugin iframes in the right panel.
@ -56,7 +57,7 @@ export class PluginPanelContainerComponent implements OnInit, OnDestroy {
.select(selectActivePluginId)
.pipe(filter((pluginId): pluginId is string => !!pluginId))
.subscribe((pluginId) => {
console.log('Plugin panel container received active plugin ID:', pluginId);
Log.log('Plugin panel container received active plugin ID:', pluginId);
this.activePluginId.set(pluginId);
}),
);

View file

@ -2,7 +2,7 @@ import { ActionReducerMap } from '@ngrx/store';
export const reducers: ActionReducerMap<any> = {
// test: (state, action) => {
// console.log(state, action);
// Log.log(state, action);
// return state;
// }
};

View file

@ -3,6 +3,7 @@ import { actionLogger } from '../../util/action-logger';
import { ActionReducer } from '@ngrx/store/src/models';
import { IS_ELECTRON } from '../../app.constants';
import { environment } from '../../../environments/environment';
import { Log } from '../../core/log';
export const actionLoggerReducer = (
reducer: ActionReducer<any, any>,
@ -10,7 +11,7 @@ export const actionLoggerReducer = (
return (state: RootState, action: any) => {
// if (environment.production) {
if (environment.production || IS_ELECTRON) {
console.log(action.type, (action as any)?.payload || action);
Log.log(action.type, (action as any)?.payload || action);
}
actionLogger(action);
return reducer(state, action);

View file

@ -13,6 +13,7 @@ import { taskAdapter } from '../../features/tasks/store/task.adapter';
import { Project } from '../../features/project/project.model';
import { Action, ActionReducer } from '@ngrx/store/src/models';
import { TODAY_TAG } from '../../features/tag/tag.const';
import { Log } from '../../core/log';
interface UndoTaskDeleteState {
// Project context
@ -121,7 +122,7 @@ const captureProjectData = (
}
if (!project.taskIds || !project.backlogTaskIds) {
console.error('Invalid project data:', { projectId, project });
Log.err('Invalid project data:', { projectId, project });
throw new Error('Invalid project data');
}

View file

@ -42,6 +42,7 @@ import { TaskSharedActions } from '../meta/task-shared.actions';
import { loadAllData } from '../meta/load-all-data.action';
import { clearHiddenImprovements } from '../../features/metric/improvement/store/improvement.actions';
import { selectTaskRepeatCfgFeatureState } from '../../features/task-repeat-cfg/store/task-repeat-cfg.selectors';
import { Log } from '../../core/log';
const ALWAYS_IGNORED_ACTIONS = [loadAllData.type];
@ -198,7 +199,7 @@ export class SaveToDbEffects {
),
),
tap(([state, action]) =>
console.log(
Log.log(
`__DB_S_${modelKey}__`,
!ignoredActionTypesToUse.includes(action.type),
action.type,

View file

@ -36,7 +36,7 @@ export class InputDurationFormlyComponent
// @ViewChild(MatInput, {static: true}) formFieldControl?: MatInput;
onInputValueChange(ev: Event): void {
const val = (ev.target as HTMLInputElement).value;
// console.log('formly onInputValueChange', val);
// Log.log('formly onInputValueChange', val);
// this.formControl.setValue(val);
this._updateValue(val);
}

View file

@ -113,7 +113,7 @@ export class InputDurationDirective implements ControlValueAccessor, Validator,
// Apply external validator if available
// if (this._validator) {
// console.log(this._validator(control), this._validator);
// Log.log(this._validator(control), this._validator);
// return this._validator(control);
// }

View file

@ -3,6 +3,7 @@ import { FormlyFieldConfig, FormlyModule } from '@ngx-formly/core';
import { FieldType } from '@ngx-formly/material';
import { MatButton } from '@angular/material/button';
import { TranslatePipe } from '@ngx-translate/core';
import { Log } from '../../core/log';
@Component({
selector: 'formly-btn',
@ -17,7 +18,7 @@ export class FormlyBtnComponent extends FieldType<FormlyFieldConfig> {
const r = this.to.onClick(this.field, this.form, this.model);
if ('then' in r) {
r.then((v) => {
console.log('update', v, this);
Log.log('update', v, this);
this.formControl.setValue(v);
this.form.markAsDirty();
});

View file

@ -10,6 +10,7 @@ import {
import { FieldType } from '@ngx-formly/core';
import { Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { Log } from '../../core/log';
@Component({
selector: 'formly-translated-template',
@ -36,7 +37,7 @@ export class FormlyTranslatedTemplateComponent
const translationId = this.field.templateOptions.text;
if (!translationId) {
console.warn('No translation id provided');
Log.err('No translation id provided');
return;
}

View file

@ -312,7 +312,7 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
.filter((i) => i !== null);
// Find all to-do items in the markdown string
// console.log(checkIndex, todoAllLinesIndexes, allLines);
// Log.log(checkIndex, todoAllLinesIndexes, allLines);
const itemIndex = todoAllLinesIndexes[checkIndex];
if (typeof itemIndex === 'number' && itemIndex > -1) {

View file

@ -1,5 +1,6 @@
import { loadFromRealLs, saveToRealLs } from '../core/persistence/local-storage';
import { LS } from '../core/persistence/storage-keys.const';
import { Log } from '../core/log';
const NUMBER_OF_ACTIONS_TO_SAVE = 30;
@ -36,7 +37,7 @@ export const actionLogger = (action: any): void => {
export const saveBeforeLastErrorActionLog = (): void => {
const current = getActionLog();
console.log('Last actions before error:', current);
Log.log('Last actions before error:', current);
saveToRealLs(LS.ACTION_BEFORE_LAST_ERROR_LOG, current);
};

View file

@ -1,10 +1,11 @@
import { environment } from '../../environments/environment';
import { Log } from '../core/log';
let isShowAlert = true;
export const devError = (errStr: any): void => {
if (environment.production) {
console.error(errStr);
Log.err(errStr);
// TODO add super simple snack message if possible
} else {
if (isShowAlert) {

View file

@ -1,6 +1,7 @@
import { saveAs } from 'file-saver';
import { Directory, Encoding, Filesystem, WriteFileResult } from '@capacitor/filesystem';
import { IS_ANDROID_WEB_VIEW } from './is-android-web-view';
import { Log } from '../core/log';
export const download = (filename: string, stringData: string): void => {
const blob = new Blob([stringData], { type: 'text/plain;charset=utf-8' });
@ -27,6 +28,6 @@ const saveStringAsFile = async (
encoding: Encoding.UTF8,
recursive: true,
});
console.log(r);
Log.log(r);
return r;
};

View file

@ -1,4 +1,5 @@
import { DatePipe } from '@angular/common';
import { Log } from '../core/log';
/**
* Formats a date to show only month and day in locale-aware format.
@ -44,7 +45,7 @@ export const formatMonthDay = (date: Date, locale: string): string => {
return result;
} catch (error) {
// Fallback to basic formatting if locale data is missing
console.warn(`formatMonthDay failed for locale ${locale}:`, error);
Log.err(`formatMonthDay failed for locale ${locale}:`, error);
const month = date.getMonth() + 1;
const day = date.getDate();
return `${month}/${day}`;

View file

@ -10,6 +10,7 @@
import { primaryInput } from 'detect-it';
import { IS_TOUCH_ONLY } from './is-touch-only';
import { environment } from '../../environments/environment';
import { Log } from '../core/log';
// @see https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/
@ -17,5 +18,5 @@ export const IS_MOUSE_PRIMARY = primaryInput === 'mouse';
export const IS_TOUCH_PRIMARY = IS_TOUCH_ONLY || primaryInput === 'touch';
if (environment.production) {
console.log({ IS_MOUSE_PRIMARY, IS_TOUCH_PRIMARY });
Log.log({ IS_MOUSE_PRIMARY, IS_TOUCH_PRIMARY });
}

View file

@ -1,11 +1,12 @@
import { isValidDate } from './is-valid-date';
import { Log } from '../core/log';
export const isSameDay = (date1: number | Date, date2: number | Date): boolean => {
const d1 = new Date(date1);
const d2 = new Date(date2);
const isValid = isValidDate(d1) && isValidDate(d2);
if (!isValid) {
console.log(date1, date2);
Log.log(date1, date2);
throw new Error('Invalid dates passed');
}
return (

View file

@ -26,5 +26,5 @@ export const IS_TOUCH_ONLY = IS_ANDROID_WEB_VIEW || isTouchOnly();
// 'hover: hover',
// 'hover: none',
// ].forEach((v) => {
// console.log(v, window.matchMedia('(' + v + ')').matches);
// Log.log(v, window.matchMedia('(' + v + ')').matches);
// });

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