mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-22 18:30:09 +00:00
chore(deps): upgrade ESLint to v9 with flat config
- Upgrade eslint from v8 to v9.39.2 - Upgrade typescript-eslint to v8.52.0 (unified package) - Add angular-eslint package for flat config support - Migrate from .eslintrc.json to eslint.config.js (flat config) - Update package configs for sync-md, automations, boilerplate-solid-js - Remove unused eslint-disable directives - Fix lint errors (empty interface, template eqeqeq) BREAKING: Requires Node.js 18.18+ (ESLint 9 requirement)
This commit is contained in:
parent
cd22f8018b
commit
e6da7ced37
74 changed files with 1025 additions and 1041 deletions
|
|
@ -1 +0,0 @@
|
|||
docs/**/*.md
|
||||
140
.eslintrc.json
140
.eslintrc.json
|
|
@ -1,140 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"app-builds/**/*",
|
||||
"dist/**",
|
||||
"node_modules/**/*",
|
||||
"src/app/t.const.ts",
|
||||
"src/assets/bundled-plugins/**/*",
|
||||
"src/app/config/env.generated.ts"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"excludedFiles": [],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"plugins": ["@typescript-eslint", "prettier", "prefer-arrow"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||
"prettier/prettier": "error",
|
||||
"@angular-eslint/component-selector": ["off"],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{
|
||||
"allowExpressions": true,
|
||||
"allowTypedFunctionExpressions": true,
|
||||
"allowHigherOrderFunctions": true,
|
||||
"allowDirectConstAssertionInArrowFunctions": true,
|
||||
"allowConciseArrowFunctionExpressionsStartingWithVoid": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/explicit-member-accessibility": [
|
||||
"off",
|
||||
{
|
||||
"accessibility": "explicit"
|
||||
}
|
||||
],
|
||||
"arrow-parens": ["off", "always"],
|
||||
"import/order": "off",
|
||||
"@typescript-eslint/member-ordering": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"arrow-body-style": "off",
|
||||
"@angular-eslint/no-input-rename": "off",
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
"selector": "default",
|
||||
"format": ["camelCase", "snake_case", "UPPER_CASE", "PascalCase"],
|
||||
"leadingUnderscore": "allowSingleOrDouble",
|
||||
"trailingUnderscore": "allow",
|
||||
"filter": {
|
||||
"regex": "(should)|@tags",
|
||||
"match": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"selector": "variable",
|
||||
"format": ["camelCase", "snake_case", "UPPER_CASE", "PascalCase"],
|
||||
"leadingUnderscore": "allowSingleOrDouble",
|
||||
"trailingUnderscore": "allow"
|
||||
},
|
||||
{
|
||||
"selector": "enum",
|
||||
"format": ["PascalCase", "UPPER_CASE"]
|
||||
},
|
||||
{
|
||||
"selector": "typeLike",
|
||||
"format": ["PascalCase"]
|
||||
}
|
||||
],
|
||||
"prefer-const": "error",
|
||||
"@typescript-eslint/no-unused-expressions": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"ignorePattern": "^import \\{.+;$",
|
||||
"ignoreRegExpLiterals": true,
|
||||
"ignoreStrings": true,
|
||||
"ignoreUrls": true,
|
||||
"code": 150
|
||||
}
|
||||
],
|
||||
"id-blacklist": "error",
|
||||
"@typescript-eslint/member-delimiter-style": "error",
|
||||
"no-shadow": "off",
|
||||
"@typescript-eslint/no-shadow": ["error"],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"no-mixed-operators": "error",
|
||||
"prefer-arrow/prefer-arrow-functions": "error",
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/ban-types": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"processor": "@angular-eslint/template/extract-inline-html",
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"@angular-eslint/template/no-negated-async": "off",
|
||||
"prettier/prettier": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ const _invoke: (channel: IPCEventValue, ...args: unknown[]) => Promise<unknown>
|
|||
...args
|
||||
) => ipcRenderer.invoke(channel, ...args);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const ea: ElectronAPI = {
|
||||
on: (
|
||||
channel: string,
|
||||
|
|
|
|||
127
eslint.config.js
Normal file
127
eslint.config.js
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// @ts-check
|
||||
const tseslint = require('typescript-eslint');
|
||||
const angular = require('angular-eslint');
|
||||
const prettierRecommended = require('eslint-plugin-prettier/recommended');
|
||||
const preferArrow = require('eslint-plugin-prefer-arrow');
|
||||
|
||||
module.exports = tseslint.config(
|
||||
// Global ignores
|
||||
{
|
||||
ignores: [
|
||||
'app-builds/**/*',
|
||||
'dist/**',
|
||||
'node_modules/**/*',
|
||||
'src/app/t.const.ts',
|
||||
'src/assets/bundled-plugins/**/*',
|
||||
'src/app/config/env.generated.ts',
|
||||
'.tmp/**/*',
|
||||
'packages/**/*',
|
||||
],
|
||||
},
|
||||
// TypeScript files
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
extends: [
|
||||
...tseslint.configs.recommended,
|
||||
...angular.configs.tsRecommended,
|
||||
prettierRecommended,
|
||||
],
|
||||
processor: angular.processInlineTemplates,
|
||||
plugins: {
|
||||
'prefer-arrow': preferArrow,
|
||||
},
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// Disabled rules
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@angular-eslint/component-selector': 'off',
|
||||
'@angular-eslint/no-input-rename': 'off',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'arrow-body-style': 'off',
|
||||
'@typescript-eslint/member-ordering': 'off',
|
||||
'import/order': 'off',
|
||||
'arrow-parens': 'off',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'off',
|
||||
|
||||
// Enabled rules
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ args: 'none', caughtErrors: 'none' },
|
||||
],
|
||||
'@typescript-eslint/explicit-function-return-type': [
|
||||
'error',
|
||||
{
|
||||
allowExpressions: true,
|
||||
allowTypedFunctionExpressions: true,
|
||||
allowHigherOrderFunctions: true,
|
||||
allowDirectConstAssertionInArrowFunctions: true,
|
||||
allowConciseArrowFunctionExpressionsStartingWithVoid: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'default',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allow',
|
||||
filter: { regex: '(should)|@tags', match: false },
|
||||
},
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allow',
|
||||
},
|
||||
{ selector: 'enum', format: ['PascalCase', 'UPPER_CASE'] },
|
||||
{ selector: 'typeLike', format: ['PascalCase'] },
|
||||
],
|
||||
'prefer-const': 'error',
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
'@typescript-eslint/no-empty-object-type': 'error',
|
||||
'max-len': [
|
||||
'error',
|
||||
{
|
||||
ignorePattern: '^import \\{.+;$',
|
||||
ignoreRegExpLiterals: true,
|
||||
ignoreStrings: true,
|
||||
ignoreUrls: true,
|
||||
code: 150,
|
||||
},
|
||||
],
|
||||
'id-blacklist': 'error',
|
||||
// @typescript-eslint/member-delimiter-style removed in v8 - Prettier handles this
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'no-mixed-operators': 'error',
|
||||
'prefer-arrow/prefer-arrow-functions': 'error',
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{ type: 'attribute', prefix: '', style: 'camelCase' },
|
||||
],
|
||||
// @typescript-eslint/ban-types replaced by specific rules in v8
|
||||
'@typescript-eslint/no-unsafe-function-type': 'error',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'error',
|
||||
},
|
||||
},
|
||||
// HTML files
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
extends: [...angular.configs.templateRecommended, prettierRecommended],
|
||||
rules: {
|
||||
'@angular-eslint/template/no-negated-async': 'off',
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
},
|
||||
);
|
||||
1393
package-lock.json
generated
1393
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -173,6 +173,7 @@
|
|||
"@csstools/stylelint-formatter-github": "^1.0.0",
|
||||
"@dotenv-run/cli": "^1.3.6",
|
||||
"@electron/notarize": "^3.1.1",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@fontsource/open-sans": "^5.2.6",
|
||||
"@nextcloud/cdav-library": "^1.5.3",
|
||||
"@ngrx/effects": "^21.0.1",
|
||||
|
|
@ -194,10 +195,9 @@
|
|||
"@types/node": "^22.19.5",
|
||||
"@types/node-fetch": "^2.6.6",
|
||||
"@types/object-path": "^0.11.4",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "7.18.0",
|
||||
"@typescript-eslint/types": "^8.17.0",
|
||||
"@typescript-eslint/utils": "^8.51.0",
|
||||
"angular-eslint": "^21.1.0",
|
||||
"angular-material-css-vars": "^9.1.1",
|
||||
"baseline-browser-mapping": "^2.9.11",
|
||||
"canvas-confetti": "^1.9.4",
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
"detect-it": "^4.0.1",
|
||||
"electron": "37.10.3",
|
||||
"electron-builder": "^26.3.3",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jsdoc": "61.4.1",
|
||||
|
|
@ -254,6 +254,7 @@
|
|||
"ts-patch": "^3.3.0",
|
||||
"tslib": "^2.7.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.52.0",
|
||||
"typia": "^11.0.0"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["solid", "@typescript-eslint", "prettier"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:solid/typescript",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn"
|
||||
},
|
||||
"ignorePatterns": ["dist", "node_modules"]
|
||||
}
|
||||
16
packages/plugin-dev/automations/eslint.config.js
Normal file
16
packages/plugin-dev/automations/eslint.config.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// @ts-check
|
||||
const tseslint = require('typescript-eslint');
|
||||
const solid = require('eslint-plugin-solid/configs/typescript');
|
||||
const prettierRecommended = require('eslint-plugin-prettier/recommended');
|
||||
|
||||
module.exports = tseslint.config(
|
||||
{ ignores: ['dist', 'node_modules'] },
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
extends: [...tseslint.configs.recommended, solid, prettierRecommended],
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["solid", "@typescript-eslint", "prettier"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:solid/typescript",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn"
|
||||
},
|
||||
"ignorePatterns": ["dist", "node_modules"]
|
||||
}
|
||||
16
packages/plugin-dev/boilerplate-solid-js/eslint.config.js
Normal file
16
packages/plugin-dev/boilerplate-solid-js/eslint.config.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// @ts-check
|
||||
const tseslint = require('typescript-eslint');
|
||||
const solid = require('eslint-plugin-solid/configs/typescript');
|
||||
const prettierRecommended = require('eslint-plugin-prettier/recommended');
|
||||
|
||||
module.exports = tseslint.config(
|
||||
{ ignores: ['dist', 'node_modules'] },
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
extends: [...tseslint.configs.recommended, solid, prettierRecommended],
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"extends": "../../../.eslintrc.json",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
}
|
||||
}
|
||||
11
packages/plugin-dev/sync-md/eslint.config.js
Normal file
11
packages/plugin-dev/sync-md/eslint.config.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// @ts-check
|
||||
const tseslint = require('typescript-eslint');
|
||||
const rootConfig = require('../../../eslint.config.js');
|
||||
|
||||
module.exports = tseslint.config(...rootConfig, {
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -28,7 +28,6 @@ export class GlobalErrorHandler implements ErrorHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
let simpleStack = '';
|
||||
if (
|
||||
err &&
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const DEFAULT_GLOBAL_CONFIG: GlobalConfigState = {
|
|||
isTimedFullScreenBlocker: false,
|
||||
timedFullScreenBlockerDuration: 8000,
|
||||
isFocusWindow: false,
|
||||
/* eslint-disable-next-line */
|
||||
|
||||
takeABreakMessage:
|
||||
'You have been working for ${duration} without one. Go away from the computer! Take a short walk! Makes you more productive in the long run!',
|
||||
takeABreakMinWorkingTime: 60 * minute,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, LocalBackupConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, DominaModeConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
import { speak } from '../../../util/speak';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, EvaluationConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, IdleConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
import { HelperClasses } from '../../../app.constants';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, LimitedFormlyFieldConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
import { IS_ELECTRON } from '../../../app.constants';
|
||||
|
|
@ -392,4 +391,3 @@ export const KEYBOARD_SETTINGS_FORM_CFG: ConfigFormSection<KeyboardConfig> = {
|
|||
},
|
||||
],
|
||||
};
|
||||
/* eslint-enable max-len */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import {
|
||||
ConfigFormSection,
|
||||
LimitedFormlyFieldConfig,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection } from '../global-config.model';
|
||||
import {
|
||||
SimpleCounterConfig,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, SoundConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
import { playDoneSound } from '../../tasks/util/play-done-sound';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { T } from '../../../t.const';
|
||||
import { ConfigFormSection, SyncConfig } from '../global-config.model';
|
||||
import { LegacySyncProvider } from '../../../imex/sync/legacy-sync-provider.model';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection } from '../global-config.model';
|
||||
|
||||
export const SYNC_SAFETY_BACKUPS_FORM: ConfigFormSection<{ [key: string]: any }> = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, TakeABreakConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-len */
|
||||
import { ConfigFormSection, TimeTrackingConfig } from '../global-config.model';
|
||||
import { T } from '../../../t.const';
|
||||
|
||||
|
|
|
|||
|
|
@ -111,13 +111,12 @@ export class GlobalConfigEffects {
|
|||
this._actions$.pipe(
|
||||
ofType(updateGlobalConfigSection),
|
||||
filter(({ sectionKey, sectionCfg }) => sectionKey === 'misc'),
|
||||
// eslint-disable-next-line
|
||||
|
||||
filter(
|
||||
({ sectionKey, sectionCfg }) =>
|
||||
sectionCfg && !!(sectionCfg as MiscConfig).startOfNextDay,
|
||||
),
|
||||
tap(({ sectionKey, sectionCfg }) => {
|
||||
// eslint-disable-next-line
|
||||
this._dateService.setStartOfNextDayDiff((sectionCfg as any)['startOfNextDay']);
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -163,9 +163,9 @@ export class CaldavClientService {
|
|||
}
|
||||
for (i = 0; i < etag.length; i++) {
|
||||
chr = etag.charCodeAt(i);
|
||||
hash = (hash << 5) - hash + chr; //eslint-disable-line no-bitwise
|
||||
hash = (hash << 5) - hash + chr;
|
||||
// Convert to 32bit integer
|
||||
hash |= 0; //eslint-disable-line no-bitwise
|
||||
hash |= 0;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
|
@ -295,7 +295,7 @@ export class CaldavClientService {
|
|||
const oldOpen = xhr.open;
|
||||
|
||||
// override open() method to add headers
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
|
||||
xhr.open = function (): void {
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export type GithubOriginalMileStone = Readonly<{
|
|||
labels_url: string;
|
||||
id: number;
|
||||
node_id: string;
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
||||
number: number;
|
||||
state: GithubOriginalState;
|
||||
title: string;
|
||||
|
|
@ -150,7 +150,7 @@ export type GithubOriginalIssue = Readonly<{
|
|||
comments_url: string;
|
||||
events_url: string;
|
||||
html_url: string;
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
||||
number: number;
|
||||
state: GithubOriginalState;
|
||||
title: string;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ export const GITHUB_CONFIG_FORM: LimitedFormlyFieldConfig<IssueProviderGithub>[]
|
|||
key: 'filterUsernameForIssueUpdates',
|
||||
type: 'input',
|
||||
expressions: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
// 'props.disabled': '!model.filterUsername',
|
||||
hide: '!model.isAutoPoll',
|
||||
},
|
||||
|
|
@ -75,7 +74,6 @@ export const GITHUB_CONFIG_FORM: LimitedFormlyFieldConfig<IssueProviderGithub>[]
|
|||
key: 'backlogQuery',
|
||||
type: 'input',
|
||||
expressions: {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
// 'props.disabled': '!model.filterUsername',
|
||||
hide: '!model.isAutoAddToBacklog || !model.defaultProjectId',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const mapGithubIssue = (issue: GithubOriginalIssue): GithubIssue => {
|
|||
comments_url: issue.comments_url,
|
||||
events_url: issue.events_url,
|
||||
html_url: issue.html_url,
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
||||
number: issue.number,
|
||||
state: issue.state,
|
||||
title: issue.title,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ export type GithubPullRequest = GithubOriginalPullRequest;
|
|||
export type GithubComment = GithubOriginalComment;
|
||||
|
||||
export type GithubIssueReduced = Readonly<{
|
||||
// eslint-disable-next-line id-blacklist
|
||||
state: GithubState;
|
||||
title: string;
|
||||
// to make it consistent with non reduced issue
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export const mapGitlabIssue = (
|
|||
): GitlabIssue => {
|
||||
return {
|
||||
html_url: issue.web_url,
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
||||
number: issue.iid,
|
||||
// iid: issue.iid,
|
||||
state: issue.state,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export type GitlabIssue = Readonly<{
|
|||
// comments_url: string;
|
||||
// events_url: string;
|
||||
html_url: string;
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
||||
number: number;
|
||||
state: GitlabState;
|
||||
title: string;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export const JIRA_CONFIG_FORM_SECTION: ConfigFormSection<IssueProviderJira> = {
|
|||
type: 'input',
|
||||
templateOptions: {
|
||||
type: 'url',
|
||||
/* eslint-disable-next-line */
|
||||
|
||||
pattern:
|
||||
/^(http(s)?:\/\/)?(localhost|[\w.\-]+(?:\.[\w\.\-]+)+)(:\d+)?(\/[^\s]*)?$/i,
|
||||
required: true,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ export class NoteComponent implements OnChanges {
|
|||
private readonly _projectService = inject(ProjectService);
|
||||
private readonly _workContextService = inject(WorkContextService);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
note!: Note;
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ export const CREATE_PROJECT_BASIC_CONFIG_FORM_CONFIG: ConfigFormSection<Project>
|
|||
// TODO translate
|
||||
title: 'Project Settings & Theme',
|
||||
key: 'basic',
|
||||
/* eslint-disable */
|
||||
|
||||
help: `Very basic settings for your project.`,
|
||||
/* eslint-enable */
|
||||
|
||||
items: [
|
||||
{
|
||||
key: 'title',
|
||||
|
|
|
|||
|
|
@ -348,7 +348,6 @@ const convertVEventToCalendarIntegrationEvent = (
|
|||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const getAllPossibleEventsAfterStartFromIcal = (
|
||||
ICAL: any,
|
||||
icalData: string,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
* The ical.js library is ~76KB and only needed for calendar integration.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let icalModule: any = null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
let loadingPromise: Promise<any> | null = null;
|
||||
|
||||
/**
|
||||
|
|
@ -13,7 +12,7 @@ let loadingPromise: Promise<any> | null = null;
|
|||
* Subsequent calls return the cached module.
|
||||
* Concurrent calls share the same loading promise to prevent race conditions.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
export const loadIcalModule = async (): Promise<any> => {
|
||||
if (icalModule) {
|
||||
return icalModule;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { createBlockedBlocksByDayMap } from './create-blocked-blocks-by-day-map';
|
||||
import { TaskCopy, TaskWithDueTime } from '../../tasks/task.model';
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
const NDS = '1970-01-01';
|
||||
const H = 60 * 60 * 1000;
|
||||
const TZ_OFFSET = new Date(NDS).getTimezoneOffset() * 60000;
|
||||
|
|
@ -16,7 +14,7 @@ const FAKE_TASK: Partial<TaskCopy> = {
|
|||
|
||||
const h = (hr: number): number => hr * 60 * 1000 * 60;
|
||||
// const hTz = (hr: number): number => h(hr) + TZ_OFFSET;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-mixed-operators
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
const dh = (d: number = 0, hr: number): number => hr * H + d * h(24);
|
||||
const dhTz = (d: number = 0, hr: number): number => dh(d, hr) + TZ_OFFSET;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export const mapScheduleDaysToScheduleEvents = (
|
|||
|
||||
days.forEach((day, dayIndex) => {
|
||||
beyondBudgetDays[dayIndex] = day.beyondBudgetTasks.map((taskPlannedForDay) => {
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
const timeLeft = getTimeLeftForTask(taskPlannedForDay);
|
||||
const timeLeftInHours = timeLeft / 1000 / 60 / 60;
|
||||
const rowSpan = Math.max(Math.round(timeLeftInHours * FH), 1);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { mapToScheduleDays } from './map-to-schedule-days';
|
||||
import { getDbDateStr } from '../../../util/get-db-date-str';
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
// Helper function to conditionally skip tests that are timezone-dependent
|
||||
// These tests were written with hardcoded expectations for Europe/Berlin timezone
|
||||
const TZ_OFFSET = new Date('1970-01-01').getTimezoneOffset() * 60000;
|
||||
|
|
|
|||
|
|
@ -33,11 +33,10 @@ const FAKE_TASK: Partial<TaskCopy> = {
|
|||
|
||||
const h = (hr: number): number => hr * 60 * 1000 * 60;
|
||||
const hTz = (hr: number): number => h(hr) + TZ_OFFSET;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-mixed-operators
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
const dh = (d: number = 0, hr: number): number => hr * H + d * h(24);
|
||||
const dhTz = (d: number = 0, hr: number): number => dh(d, hr) + TZ_OFFSET;
|
||||
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
const minAfterNow = (min: number): Date => new Date(1970, 0, 1, 0, min, 0, 0);
|
||||
|
||||
const minAfterNowTs = (min: number): number => minAfterNow(min).getTime();
|
||||
|
|
@ -404,7 +403,7 @@ describe('mapToScheduleDays()', () => {
|
|||
id: 'N1',
|
||||
// NOTE: the 24h stuff only works if we count from 0 of the current timezone
|
||||
start: h(0),
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
duration: h(23) - 60000,
|
||||
type: 'Task',
|
||||
},
|
||||
|
|
@ -418,7 +417,7 @@ describe('mapToScheduleDays()', () => {
|
|||
{
|
||||
data: jasmine.any(Object),
|
||||
id: 'N2',
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
start: hTz(24),
|
||||
duration: h(1),
|
||||
type: 'SplitTask',
|
||||
|
|
@ -426,7 +425,7 @@ describe('mapToScheduleDays()', () => {
|
|||
{
|
||||
data: jasmine.any(Object),
|
||||
id: 'R1_1970-01-02',
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
start: hTz(25),
|
||||
duration: h(1),
|
||||
type: 'ScheduledRepeatProjection',
|
||||
|
|
@ -434,7 +433,7 @@ describe('mapToScheduleDays()', () => {
|
|||
{
|
||||
data: jasmine.any(Object),
|
||||
id: 'N2_1970-01-02_0',
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
start: hTz(26),
|
||||
duration: h(1),
|
||||
type: 'SplitTaskContinuedLast',
|
||||
|
|
@ -482,7 +481,7 @@ describe('mapToScheduleDays()', () => {
|
|||
data: jasmine.any(Object),
|
||||
id: 'N1',
|
||||
start: hTz(0),
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
duration: h(23) - 60000,
|
||||
type: 'Task',
|
||||
},
|
||||
|
|
@ -496,7 +495,7 @@ describe('mapToScheduleDays()', () => {
|
|||
{
|
||||
data: jasmine.any(Object),
|
||||
id: 'R1_1970-01-02',
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
start: hTz(24),
|
||||
duration: h(2),
|
||||
type: 'RepeatProjection',
|
||||
|
|
@ -550,7 +549,7 @@ describe('mapToScheduleDays()', () => {
|
|||
data: jasmine.any(Object),
|
||||
id: 'N1',
|
||||
start: dhTz(0, 9),
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
duration: h(8),
|
||||
type: 'SplitTask',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ export class ScheduleComponent {
|
|||
const now = new Date();
|
||||
const hours = now.getHours();
|
||||
const minutes = now.getMinutes();
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
|
||||
const hoursToday = hours + minutes / 60;
|
||||
return Math.round(hoursToday * FH);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ export const SHEPHERD_STEPS = (
|
|||
},
|
||||
{
|
||||
title: 'Moving around',
|
||||
// eslint-disable-next-line max-len
|
||||
|
||||
text: `<p>When a task is focused you can navigate to other tasks by pressing the arrow keys <kbd>↑</kbd> and <kbd>↓</kbd>.</p>`,
|
||||
when: {
|
||||
show: () => taskService.focusFirstTaskIfVisible(),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('getSimpleCounterStreakDuration()', () => {
|
|||
countOnDay: { [getDbDateStr()]: 1 },
|
||||
isTrackStreaks: true,
|
||||
streakMinValue: 2,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
||||
streakWeekDays: { 0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true },
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export const isEqualSimpleCounterCfg = (
|
|||
}
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let j = 0; j < FIELDS_TO_COMPARE.length; j++) {
|
||||
const field = FIELDS_TO_COMPARE[j];
|
||||
if (a[field] !== b[field]) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import { getNextRepeatOccurrence } from './get-next-repeat-occurrence.util';
|
|||
import { DEFAULT_TASK_REPEAT_CFG, TaskRepeatCfg } from '../task-repeat-cfg.model';
|
||||
import { getDbDateStr } from '../../../util/get-db-date-str';
|
||||
|
||||
/* eslint-disable no-mixed-operators */
|
||||
|
||||
const FAKE_MONDAY_THE_10TH = new Date(2022, 0, 10).getTime();
|
||||
|
||||
const DUMMY_REPEATABLE_TASK: TaskRepeatCfg = {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ describe('selectTaskRepeatCfgsDueOnDay', () => {
|
|||
});
|
||||
|
||||
[
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH + DAY,
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH + DAY * 11,
|
||||
|
|
@ -150,7 +149,6 @@ describe('selectTaskRepeatCfgsDueOnDay', () => {
|
|||
});
|
||||
|
||||
[
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH,
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH + DAY * 2,
|
||||
|
|
@ -539,7 +537,6 @@ describe('selectAllUnprocessedTaskRepeatCfgs', () => {
|
|||
});
|
||||
|
||||
[
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH,
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
FAKE_MONDAY_THE_10TH + DAY * 2,
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ export enum SORT_ORDER {
|
|||
|
||||
// === GROUP ===
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GroupOption extends BaseOption<GROUP_OPTION_TYPE> {}
|
||||
export type GroupOption = BaseOption<GROUP_OPTION_TYPE>;
|
||||
|
||||
export enum GROUP_OPTION_TYPE {
|
||||
tag = 'tag',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Task, TaskState } from '../task.model';
|
||||
import { initialTaskState, taskReducer } from './task.reducer';
|
||||
import * as fromActions from './task.actions';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention,@typescript-eslint/explicit-function-return-type */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { Task, TaskState } from '../task.model';
|
||||
import { initialTaskState, taskReducer } from './task.reducer';
|
||||
import { PlannerActions } from '../../planner/store/planner.actions';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable one-var */
|
||||
import { WorkStartEnd } from 'src/app/features/work-context/work-context.model';
|
||||
import { WorklogGrouping } from '../worklog.model';
|
||||
import { createRows } from './worklog-export.util';
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ const maskString = (key: string, val: string, counter: number): string => {
|
|||
const recurse = (obj: unknown): void => {
|
||||
if (typeof obj !== 'object' || obj === null) return;
|
||||
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const val = (obj as Record<string, unknown>)[key];
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ import {
|
|||
} from '../../../errors/errors';
|
||||
import { WebDavHttpHeader, WebDavHttpMethod, WebDavHttpStatus } from './webdav.const';
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
export class WebdavApi {
|
||||
private static readonly L = 'WebdavApi';
|
||||
private xmlParser: WebdavXmlParser;
|
||||
|
|
|
|||
|
|
@ -141,9 +141,7 @@ const parsePath = (path: string): (string | number)[] => {
|
|||
const getValueByPath = <T, R = unknown>(
|
||||
obj: T,
|
||||
path: (string | number)[],
|
||||
): R | undefined =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
path.reduce<any>((acc, key) => acc?.[key], obj);
|
||||
): R | undefined => path.reduce<any>((acc, key) => acc?.[key], obj);
|
||||
|
||||
const setValueByPath = <T extends object>(
|
||||
obj: T,
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
expect(action.type).toBe('[SimpleCounter] Upsert SimpleCounter');
|
||||
expect(action.simpleCounter.id).toBe('new-counter');
|
||||
|
|
@ -166,7 +166,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
expect(action.type).toBe('[SimpleCounter] Upsert SimpleCounter');
|
||||
expect(action.simpleCounter.id).toBe('zero-counter');
|
||||
|
|
@ -177,7 +177,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
await service.setCounter('full-counter', 5);
|
||||
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
const counter = action.simpleCounter;
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
expect(action.type).toBe('[SimpleCounter] Update SimpleCounter');
|
||||
expect(action.simpleCounter.id).toBe('existing-counter');
|
||||
|
|
@ -223,7 +223,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
const countOnDay = action.simpleCounter.changes.countOnDay;
|
||||
expect(countOnDay['2024-01-01']).toBe(5);
|
||||
|
|
@ -241,7 +241,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
|
||||
expect(store.dispatch).toHaveBeenCalled();
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
expect(action.simpleCounter.changes.countOnDay[today]).toBe(100);
|
||||
});
|
||||
|
|
@ -253,7 +253,7 @@ describe('PluginBridgeService.setCounter()', () => {
|
|||
await service.setCounter('check-action', 1);
|
||||
|
||||
const call = store.dispatch.calls.mostRecent();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const action = call.args[0] as any;
|
||||
expect(action.type).toBe('[SimpleCounter] Update SimpleCounter');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// TODO: Fix plugin tests after stabilizing task model changes
|
||||
/* eslint-disable */
|
||||
|
||||
/*
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// TODO: Fix plugin tests after stabilizing task model changes
|
||||
/* eslint-disable */
|
||||
|
||||
// TODO: These tests are disabled due to module resolution issues with @super-productivity/plugin-api
|
||||
describe('PluginService', () => {
|
||||
it('should pass placeholder test', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { plannerSharedMetaReducer } from './planner-shared.reducer';
|
||||
import { RootState } from '../../root-state';
|
||||
import { Task } from '../../../features/tasks/task.model';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
import { tagSharedMetaReducer } from './tag-shared.reducer';
|
||||
import { TaskSharedActions } from '../task-shared.actions';
|
||||
import { RootState } from '../../root-state';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { taskBatchUpdateMetaReducer } from './task-batch-update.reducer';
|
||||
import { TaskSharedActions } from '../task-shared.actions';
|
||||
import { RootState } from '../../root-state';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
import { taskBatchUpdateMetaReducer } from './task-batch-update.reducer';
|
||||
import { TaskSharedActions } from '../task-shared.actions';
|
||||
import { RootState } from '../../root-state';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { taskBatchUpdateMetaReducer } from './task-batch-update.reducer';
|
||||
import { TaskSharedActions } from '../task-shared.actions';
|
||||
import { RootState } from '../../root-state';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { taskSharedLifecycleMetaReducer } from './task-shared-lifecycle.reducer';
|
||||
import { TaskSharedActions } from '../task-shared.actions';
|
||||
import { RootState } from '../../root-state';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { RootState } from '../../root-state';
|
||||
import { TASK_FEATURE_NAME } from '../../../features/tasks/store/task.reducer';
|
||||
import { TAG_FEATURE_NAME } from '../../../features/tag/store/tag.reducer';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
import { validateAndFixDataConsistencyAfterBatchUpdate } from './validate-and-fix-data-consistency-after-batch-update';
|
||||
import { RootState } from '../../root-state';
|
||||
import { TASK_FEATURE_NAME } from '../../../features/tasks/store/task.reducer';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type,@typescript-eslint/naming-convention */
|
||||
import { undoTaskDeleteMetaReducer } from './undo-task-delete.meta-reducer';
|
||||
import { TaskSharedActions } from './task-shared.actions';
|
||||
import { undoDeleteTask } from '../../features/tasks/store/task.actions';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ const observableProto = (Observable as unknown as { prototype: ObservablePrototy
|
|||
.prototype;
|
||||
|
||||
if (!observableProto.toPromise) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
observableProto.toPromise = function <T>(this: Observable<T>): Promise<T> {
|
||||
return lastValueFrom(this);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -151,4 +151,180 @@ describe('InlineMarkdownComponent', () => {
|
|||
expect(component.changed.emit).toHaveBeenCalledWith(changedValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_handleCheckboxClick', () => {
|
||||
let mockPreviewEl: { element: { nativeElement: HTMLElement } };
|
||||
|
||||
beforeEach(() => {
|
||||
mockPreviewEl = {
|
||||
element: {
|
||||
nativeElement: document.createElement('div'),
|
||||
},
|
||||
};
|
||||
spyOn(component, 'previewEl').and.returnValue(mockPreviewEl as any);
|
||||
spyOn(component.changed, 'emit');
|
||||
});
|
||||
|
||||
it('should toggle first checkbox in simple checklist', () => {
|
||||
// Arrange
|
||||
component.model = '- [ ] Task 1\n- [ ] Task 2';
|
||||
fixture.detectChanges();
|
||||
|
||||
// Create mock checkbox wrappers
|
||||
const wrapper1 = document.createElement('li');
|
||||
wrapper1.className = 'checkbox-wrapper';
|
||||
wrapper1.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 1';
|
||||
|
||||
const wrapper2 = document.createElement('li');
|
||||
wrapper2.className = 'checkbox-wrapper';
|
||||
wrapper2.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 2';
|
||||
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper1);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper2);
|
||||
|
||||
// Act
|
||||
component['_handleCheckboxClick'](wrapper1);
|
||||
|
||||
// Assert
|
||||
expect(component.changed.emit).toHaveBeenCalledWith('- [x] Task 1\n- [ ] Task 2');
|
||||
});
|
||||
|
||||
it('should toggle checkbox after blank line', () => {
|
||||
// Arrange - this is the bug scenario from issue #5950
|
||||
component.model = '- [ ] Task 1\n\n- [ ] Task 2';
|
||||
fixture.detectChanges();
|
||||
|
||||
// Create mock checkbox wrappers (blank line doesn't create a wrapper)
|
||||
const wrapper1 = document.createElement('li');
|
||||
wrapper1.className = 'checkbox-wrapper';
|
||||
wrapper1.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 1';
|
||||
|
||||
const wrapper2 = document.createElement('li');
|
||||
wrapper2.className = 'checkbox-wrapper';
|
||||
wrapper2.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 2';
|
||||
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper1);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper2);
|
||||
|
||||
// Act - click the second checkbox (Task 2)
|
||||
component['_handleCheckboxClick'](wrapper2);
|
||||
|
||||
// Assert - Task 2 should be toggled, not Task 1
|
||||
expect(component.changed.emit).toHaveBeenCalledWith('- [ ] Task 1\n\n- [x] Task 2');
|
||||
});
|
||||
|
||||
it('should toggle checkbox with multiple blank lines', () => {
|
||||
// Arrange
|
||||
component.model = '- [ ] Task 1\n\n\n- [ ] Task 2\n\n- [ ] Task 3';
|
||||
fixture.detectChanges();
|
||||
|
||||
const wrapper1 = document.createElement('li');
|
||||
wrapper1.className = 'checkbox-wrapper';
|
||||
wrapper1.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 1';
|
||||
|
||||
const wrapper2 = document.createElement('li');
|
||||
wrapper2.className = 'checkbox-wrapper';
|
||||
wrapper2.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 2';
|
||||
|
||||
const wrapper3 = document.createElement('li');
|
||||
wrapper3.className = 'checkbox-wrapper';
|
||||
wrapper3.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 3';
|
||||
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper1);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper2);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper3);
|
||||
|
||||
// Act - click the third checkbox (Task 3)
|
||||
component['_handleCheckboxClick'](wrapper3);
|
||||
|
||||
// Assert
|
||||
expect(component.changed.emit).toHaveBeenCalledWith(
|
||||
'- [ ] Task 1\n\n\n- [ ] Task 2\n\n- [x] Task 3',
|
||||
);
|
||||
});
|
||||
|
||||
it('should uncheck a checked checkbox', () => {
|
||||
// Arrange
|
||||
component.model = '- [x] Task 1\n- [ ] Task 2';
|
||||
fixture.detectChanges();
|
||||
|
||||
const wrapper1 = document.createElement('li');
|
||||
wrapper1.className = 'checkbox-wrapper';
|
||||
wrapper1.innerHTML = '<span class="checkbox material-icons">check_box</span>Task 1';
|
||||
|
||||
const wrapper2 = document.createElement('li');
|
||||
wrapper2.className = 'checkbox-wrapper';
|
||||
wrapper2.innerHTML =
|
||||
'<span class="checkbox material-icons">check_box_outline_blank</span>Task 2';
|
||||
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper1);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper2);
|
||||
|
||||
// Act
|
||||
component['_handleCheckboxClick'](wrapper1);
|
||||
|
||||
// Assert
|
||||
expect(component.changed.emit).toHaveBeenCalledWith('- [ ] Task 1\n- [ ] Task 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('clickPreview with loose lists (blank lines)', () => {
|
||||
let mockPreviewEl: { element: { nativeElement: HTMLElement } };
|
||||
|
||||
beforeEach(() => {
|
||||
mockPreviewEl = {
|
||||
element: {
|
||||
nativeElement: document.createElement('div'),
|
||||
},
|
||||
};
|
||||
spyOn(component, 'previewEl').and.returnValue(mockPreviewEl as any);
|
||||
spyOn(component.changed, 'emit');
|
||||
});
|
||||
|
||||
it('should handle checkbox click when checkbox is wrapped in <p> tag (loose list)', () => {
|
||||
// Arrange - simulates loose list HTML: <li class="checkbox-wrapper"><p><span class="checkbox">...</span>Task</p></li>
|
||||
component.model = '- [ ] Task 1\n\n- [ ] Task 2';
|
||||
fixture.detectChanges();
|
||||
|
||||
// Build DOM structure for loose list (with <p> wrapper)
|
||||
const wrapper1 = document.createElement('li');
|
||||
wrapper1.className = 'checkbox-wrapper undone';
|
||||
const p1 = document.createElement('p');
|
||||
const checkbox1 = document.createElement('span');
|
||||
checkbox1.className = 'checkbox material-icons';
|
||||
checkbox1.textContent = 'check_box_outline_blank';
|
||||
p1.appendChild(checkbox1);
|
||||
p1.appendChild(document.createTextNode('Task 1'));
|
||||
wrapper1.appendChild(p1);
|
||||
|
||||
const wrapper2 = document.createElement('li');
|
||||
wrapper2.className = 'checkbox-wrapper undone';
|
||||
const p2 = document.createElement('p');
|
||||
const checkbox2 = document.createElement('span');
|
||||
checkbox2.className = 'checkbox material-icons';
|
||||
checkbox2.textContent = 'check_box_outline_blank';
|
||||
p2.appendChild(checkbox2);
|
||||
p2.appendChild(document.createTextNode('Task 2'));
|
||||
wrapper2.appendChild(p2);
|
||||
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper1);
|
||||
mockPreviewEl.element.nativeElement.appendChild(wrapper2);
|
||||
|
||||
// Act - simulate clicking the second checkbox
|
||||
const mockEvent = {
|
||||
target: checkbox2,
|
||||
} as unknown as MouseEvent;
|
||||
component.clickPreview(mockEvent);
|
||||
|
||||
// Assert - Task 2 should be toggled
|
||||
expect(component.changed.emit).toHaveBeenCalledWith('- [ ] Task 1\n\n- [x] Task 2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ import { Log } from '../../core/log';
|
|||
>
|
||||
@for (item of items; track item; let i = $index) {
|
||||
<li
|
||||
[class.active]="activeIndex == i"
|
||||
[class.mention-active]="!styleOff && activeIndex == i"
|
||||
[class.active]="activeIndex === i"
|
||||
[class.mention-active]="!styleOff && activeIndex === i"
|
||||
>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ import { Log } from '../core/log';
|
|||
|
||||
export const observeWidth = (target: HTMLElement): Observable<number> => {
|
||||
return new Observable((observer: Subscriber<number>) => {
|
||||
// eslint-disable-next-line
|
||||
if ((window as any).ResizeObserver) {
|
||||
// eslint-disable-next-line
|
||||
const resizeObserver = new (window as any).ResizeObserver(
|
||||
(entries: ResizeObserverEntry[]) => {
|
||||
observer.next(entries[0].contentRect.width);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue