Commit graph

943 commits

Author SHA1 Message Date
Johannes Millan
857f2e3731 feat(task-repeat): improve repeat config dialog UX
- Wrap heatmap in collapsible "Activity" section, collapsed by default
- Lazy-load heatmap only when expanded to avoid loading full archive
- Disable autoFocus at all dialog call sites to prevent keyboard popup
- Icon-only action buttons on small screens with aria-labels
- Rename "Remove for" to "Skip for" with consistent confirmation dialog
- Save button raised, Remove button warn color
2026-03-24 17:26:07 +01:00
Mick Zijdel
e98f16ad6d
Clickable links in task titles (#6570)
* feat(benchmark): add task title link rendering benchmark

- Creates benchmark page at /benchmark route
- Generates 1000 test tasks (1/3 no links, 1/3 URLs, 1/3 markdown)
- Measures initial render time
- Measures scrolling FPS during 2s scroll animation
- Includes toggle for link rendering (not yet functional)
- Baseline for measuring performance impact of link rendering

* feat(benchmark): increase to 5000 tasks and improve results display

- Increase task count from 1000 to 5000 for more measurable differences
- Add copyable results display with pre-formatted text
- Add 'Copy Results' button for easy sharing
- Include link rendering state in results output
- Format results in monospace font for better readability

* feat(benchmark): measure initial render from blank state

- Start with empty task list instead of pre-generating on page load
- Generate tasks only when benchmark runs
- Clear existing tasks before each benchmark run
- Use double requestAnimationFrame to ensure complete render
- Provides accurate measurement of initial render performance
- Reset now clears tasks instead of regenerating them

* refactor(benchmark): remove redundant reset button

Run Benchmark now handles resetting state, making the separate
reset button unnecessary

* feat(task-title): render URLs and markdown links as clickable links

- Detect URLs (https://, http://, file://, www.) and markdown [title](url) syntax
- Render as <a> tags with target="_blank" rel="noopener noreferrer"
- XSS protection: HTML-escape all user content, validate URL schemes
- ReDoS protection: limit URL length to 2000 chars in regex
- ~0 perf cost when disabled via renderLinks signal input
- string.includes() pre-check skips regex for plain-text tasks
- Direct HTML escaping (4 replace calls) instead of DomSanitizer for speed
- readonly input disables editing and uses inherit cursor
- Add unit tests: XSS protection, ReDoS, readonly mode, click propagation

* feat(config): add isEnableLinkRendering setting to short syntax config

Add a checkbox in Settings → Short Syntax to toggle clickable link rendering
in task titles. Defaults to enabled. Wired to the renderLinks input of task-title.

* feat(task-title): render links in planner-task and schedule-event via pipe

Add RenderLinksPipe to convert URLs and markdown links to clickable <a> tags
without including the full task-title component. Use [innerHTML] with the pipe
in planner-task and schedule-event to keep their existing styling intact.

* refactor(task-title): use RenderLinksPipe to eliminate duplicate link-rendering code

Remove inline URL/markdown processing (URL_REGEX, MARKDOWN_LINK_REGEX,
_escapeHtml, _isUrlSchemeSafe, displayHtml computed) from task-title
component and delegate to the shared RenderLinksPipe instead.

The hasUrlsOrMarkdown() fast pre-check (includes() scan) is preserved as
a template guard so the pipe is only invoked for tasks that actually
contain URLs or markdown - plain text tasks still use cheap interpolation.

* fix(task-title): Better XSS protection when rendering links

* fix(task-title): Move XSS tests

* fix(task-title): fix parentheses counting in markdown links

* fix(task-tests): add signal in one place to compute if links should be rendered or not

* fix(task-title): prevent clicks from propagating when they shouldn't

* fix(task-title): convert readonly inputs on task title

* fix(task-title): Add aria-label to the urls

* fix(task-title): mock pipe in tests

* fix: focus mode test

* fix(task-title): add ocmment why we have duplicated content

* fix(task-title): exclude a few more schemes

* fix(task-title): harden link rendering security and performance

- Fix ReDoS in MARKDOWN_LINK_REGEX by using [^()]+ instead of [^()]*
  to break catastrophic backtracking (fixes CodeQL failure)
- Add single-quote escaping to _escapeHtml for defense-in-depth
- Replace permissive URL scheme fallback with strict /^[a-z]+:/
  detection to reject tel:, mailto:, and other non-browsable schemes
- Remove /benchmark route from production (component kept for dev use)
- Extract LINK_HINT_* constants shared between pipe and component
- Add fast-path optimization to planner-task to skip [innerHTML]
  for plain-text tasks

* perf(task-title): optimize link rendering hot path

- Replace 5 chained _escapeHtml regex calls with single-pass lookup table
- Replace new URL() in _ariaLabelForUrl with manual hostname extraction
- Hoist all regexes to module-level constants (SCHEME_RE, TRAILING_PUNCT_RE)
- Replace _stripUrlTrailing match() array allocations with charCode loop
- Replace _normalizeHref regex with startsWith checks
- Move helpers to module-level arrow consts (removes method dispatch overhead)

* refactor(task-title): extract hasLinkHints utility and add schedule fast-path

- Extract shared hasLinkHints() function from duplicated hint checks
- Add fast-path optimization to schedule-event (was missing, unlike
  planner-task and task-title which already had it)
- Optimize _stripUrlTrailing to use single substring instead of
  repeated slice allocations
- Simplify imports across consuming components

* fix(task-title): reject empty URLs and clean up benchmark component

- Reject empty markdown URLs [text]() that would produce broken
  href="http://" links
- Remove unnecessary CommonModule import from benchmark component
- Remove redundant standalone: true (default since Angular 19)

* fix(task-title): make links clickable on touch devices and schedule view

Links were unreachable in two contexts due to inherited pointer-events: none:
- task.component sets pointer-events: none on task-title for touch-primary
  devices (to allow drag-and-drop)
- schedule-event.component.scss sets pointer-events: none on all direct
  children of :host (so clicks bubble to the host handler)

Fix by adding pointer-events: auto on <a> tags in both task-title and
schedule-event styles. This overrides the inherited value so links are
clickable while preserving drag behavior on surrounding text.

* fix(task-title): use unrolled loop regex to fix CodeQL ReDoS warning

The previous [^()]+ fix wasn't sufficient — consecutive non-paren
characters could still be split across iterations of the outer *
in exponentially many ways when the match fails.

Restructure to [^()]*(?:\([^()]*\)[^()]*)* where each iteration
of * MUST start with a literal '(' — eliminating partition ambiguity.
Verified: pathological 50-char input completes in <0.1ms.

* fix(schedule): lift links above ::before overlay with z-index

The schedule-event ::before pseudo-element at z-index: 3 covers the
entire host, intercepting pointer events before they reach <a> tags
even with pointer-events: auto. Add position: relative and z-index: 4
to links so they stack above the overlay.

* refactor(task-title): remove link rendering toggle, always render links

Remove the isEnableLinkRendering config option and all plumbing:
- Delete config model field, default, form checkbox, service signal
- Delete translation key and string
- Remove renderLinks parameter from pipe (always renders)
- Remove renderLinks input from task-title component
- Remove GlobalConfigService injection from 3 components that only
  needed it for this setting
- Remove isLinkRenderingEnabled property from all 6 consuming components
- Remove mock setup from 3 test files
- Simplify hasLinkHints checks (no setting gate needed)

This eliminates ~100 lines of config threading code. The pipe's internal
fast-path still skips regex for plain-text tasks.

* chore: remove unused benchmark component

---------

Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-03-23 20:58:02 +01:00
Vedant Madane
df3729b3d3
fix: make sub-tasks visually distinct in search results (#6786)
* fix: make sub-tasks visually distinct in search results

- Add parentTitle to SearchItem for sub-task breadcrumb display
- Show subdirectory_arrow_right icon for sub-tasks
- Display parent task title as breadcrumb (Parent › Sub-task)
- Add indentation, italic styling for sub-task titles
- Update unit tests for parentTitle resolution

Fixes #6785

* fix(search): move subtask styles inside ::ng-deep and simplify CSS

- Move .subtask-icon, .subtask-breadcrumb, .task-subtask inside the
  ::ng-deep block so styles reach projected content in mat-list-item
- Replace hardcoded › character with chevron_right Material icon
- Remove unused search-result-subtask class from mat-list-item
- Simplify CSS: drop extra font-size overrides, use consistent units

* refactor(search): use [class.*] bindings and fix orphan subtask styling

- Replace [ngClass] with [class.*] bindings to match project convention
- Remove unused NgClass import
- Align italic condition with breadcrumb condition (use parentTitle
  instead of parentId) so orphan subtasks don't get unexplained italic

---------

Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-03-23 19:33:30 +01:00
Johannes Millan
31480a5fab feat(tasks): replace drag handle with done toggle circle and improve mobile UX
- Replace drag handle with SVG done-toggle circle with checkmark draw-on animation
- Improve mobile UX: cdkDragStartDelay for touch, bottom-sheet context menu
- Move issue/repeat indicators from drag handle to tag-list as chips
- Add isFinishDayEnabled config toggle
- Reorder context menu: add sub task before duplicate, deadline as own entry
- Fix context menu not opening on swipe left
- Fix race condition in done toggle animation timeout
2026-03-22 18:14:16 +01:00
Johannes Millan
5d037d51c7
feat(ui): improve empty state copy and add CTAs for better new user guidance (#6918)
* feat(ui): improve empty state copy and add CTAs for better new user guidance

- Backlog: clearer message explaining purpose of backlog
- Scheduled page: differentiate empty messages for time-scheduled vs day-scheduled tasks
- Scheduled page: add CTA button to create recurring task from empty state
- Quick history: explain what triggers data to appear

https://claude.ai/code/session_01YPeWY5g6DYdj5QP4XbvkTC

* chore: update package-lock.json

https://claude.ai/code/session_01YPeWY5g6DYdj5QP4XbvkTC

* chore: revert unintended package-lock.json changes

https://claude.ai/code/session_01YPeWY5g6DYdj5QP4XbvkTC

* refactor(schedule): remove recurring task CTA button from empty state

https://claude.ai/code/session_01YPeWY5g6DYdj5QP4XbvkTC

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-22 10:10:13 +01:00
Johannes Millan
a4c7ec892b fix(config): prevent settings page from scrolling up on focus
Override overflow:hidden/auto on nested containers (form-wrapper,
Material tab body) to prevent the browser's focus-scrolling algorithm
from resetting the config-page scroll position when form controls
receive focus.
2026-03-20 21:36:30 +01:00
Johannes Millan
114e5067a1 style: replace hardcoded z-index, media queries, and spacing with design tokens
Replace z-index: 333333 with var(--z-add-task-bar) and z-index: 44
with var(--z-right-panel). Standardize media queries to use @include
mq() mixins. Extend spacing variable replacements across the full
codebase for margin, padding, and gap properties.
2026-03-19 18:58:51 +01:00
Johannes Millan
ab5205e247 fix(search): guard against undefined tagIds in search page
Tasks arriving via sync/archive can have undefined tagIds, causing
a TypeError crash when mapping tasks to search items. Add optional
chaining to prevent the crash.

Closes #6864
2026-03-18 13:14:10 +01:00
Johannes Millan
a276ccb3f4 fix: resolve pre-existing lint and prettier errors blocking commits (#6840) 2026-03-15 16:47:52 +01:00
Johannes Millan
5c4035fb96 fix(tasks): only show deadlines section in schedule page when deadlines exist 2026-03-14 13:04:44 +01:00
Johannes Millan
c133725214 refactor(tasks): use flag icon for deadlines to distinguish from schedule
Replace event_busy with flag/flag_circle icons for all deadline-related UI
elements (task badge, detail panel, context menu, dialog, planner, schedule
page, snack notifications) to avoid confusion with the "unschedule" action.
2026-03-14 13:04:44 +01:00
Johannes Millan
9e8f45b1f8 feat(tasks): show deadlines in scheduled list page and planner task 2026-03-14 13:04:44 +01:00
Johannes Millan
eb5692becd test(config): fix async timing in WebDAV test connection spec
Wait for async sync form config to be built before accessing the
globalSyncConfigFormCfg signal, which is populated asynchronously
in the constructor.
2026-03-10 10:36:46 +01:00
Johannes Millan
7d27400d03 perf(sync): lazy-load sync providers and repair utilities to reduce bundle size
Convert sync providers from eagerly instantiated array to lazy-loaded
factories using dynamic imports. Make dataRepair and migrateLegacyBackup
dynamically imported at their call sites (error/migration paths only).

- getProviderById is now async with promise-cached instantiation
- _setActiveProvider guards against redundant re-activation
- Staleness counter prevents race conditions on rapid provider switches
2026-03-10 10:13:09 +01:00
Johannes Millan
3a352a022a test(config-page): fix signal access in spec file
Call globalSyncConfigFormCfg() as a function since it's a WritableSignal.
2026-03-09 21:20:03 +01:00
Johannes Millan
beb5f3425c perf: reduce initial bundle size by lazy-loading sync providers, validation, and jira2md 2026-03-09 20:51:54 +01:00
Johannes Millan
dc5c730cd2 refactor(scss): clean up duplicated and superfluous styles
- Delete 17 empty SCSS files and remove their styleUrl references
- Replace 14 manual text-truncation patterns with truncateText() mixin
- Remove redundant -webkit-user-select and -webkit-backdrop-filter
  vendor prefixes handled by autoprefixer
- Replace top/right/bottom/left: 0 with inset: 0 (14 instances)
2026-03-09 15:31:51 +01:00
Johannes Millan
3ad3e5ed09 fix(settings): point changelog link to latest GitHub release 2026-03-09 15:31:51 +01:00
jcuenca95
b22be78059
feat: added linethrough text-decoration for archived tasks when searching (#6759)
6747
2026-03-07 19:03:34 +01:00
Johannes Millan
93004d4859 feat(tasks): add dialog to view archived task details (#5425)
Add a read-only dialog to view archived task details including
subtasks, time spent/estimate, notes, attachments, issue links,
and repeat config. Accessible from:
- Search page (info icon for archived results)
- Worklog (clickable task titles)
- Quick history (clickable task titles)
- Daily summary worklog-week (clickable task titles)
- Daily summary task-summary-table (info button)
2026-03-06 16:13:25 +01:00
Johannes Millan
06113152c8 feat(i18n): add CLDR-aware plural form support via Intl.PluralRules
Add getPluralKey() utility that uses the browser-native Intl.PluralRules
API to select the correct CLDR plural category (one/few/many/other) for
any locale. This enables languages like Romanian, Russian, Polish, and
Arabic to provide proper plural forms beyond simple singular/plural.

Key changes:
- New getPluralKey() utility with locale-aware fallback via TranslateStore
- Rename translation keys: SINGULAR→ONE, PLURAL→OTHER (CLDR convention)
- Nest banner TXT_MULTIPLE keys into ONE/OTHER for proper English grammar
- Migrate all 27 locale files to new key structure
- Add 10 unit tests covering CLDR categories, fallback, and edge cases

Closes discussion #6698
2026-03-03 20:14:54 +01:00
Johannes Millan
56d1ff57be refactor: use existing mixins/utilities instead of duplicated code
- fix(issue): use issueProviderKey instead of hardcoded OPEN_PROJECT_TYPE
  in handleIssueProviderHttpError$ so error messages show the correct provider
- Replace duplicate _getDateStr with getDbDateStr utility (2 files)
- Replace duplicate _formatTime/formatMs with msToString utility (3 files)
- Fix direct uuidv7 import to use wrapper in clean-slate.service.ts
- Replace manual text truncation with @include truncateText() (10 files)
- Replace manual centering with @include center (10 files)
- Replace manual border with @include extraBorder() (19 files)
2026-03-03 11:27:20 +01:00
Johannes Millan
03572c3f2c
Feat/start of next day (#6565)
* feat: add label to heatmap for repeat task

* style(e2e): fix prettier formatting in planner spec

* fix(focus-mode): clear stale _isResumingBreak flag when isPauseTrackingDuringBreak is enabled (#6534)

When both isSyncSessionWithTracking and isPauseTrackingDuringBreak are
enabled, pausing and resuming a break left _isResumingBreak stale,
causing the next manual tracking start to dispatch clearResumingBreakFlag
instead of skipBreak. Refactor syncSessionResumeToTracking$ to explicitly
dispatch clearResumingBreakFlag in this case.

* refactor(sync): unify JWT expiry to 365 days for all auth methods

Replace separate JWT_EXPIRY_MAGIC_LINK (365d) and JWT_EXPIRY_PASSKEY (7d)
constants with a single JWT_EXPIRY (365d). The auth method only matters
during login — once a JWT is issued, it represents a verified session
regardless of how the user authenticated.

* feat(start-of-next-day): respect startOfNextDayDiff offset in today view

Thread startOfNextDayDiffMs through AppState, selectors, meta-reducers,
and task component so that "today" membership correctly accounts for the
user's configured day-start offset. When startOfNextDay=4 (4 AM), at
2:30 AM the app now correctly treats the previous calendar day as "today".

- Add isTodayWithOffset utility for offset-aware date comparison
- Store startOfNextDayDiffMs in AppState alongside todayStr
- Update all selectors (work-context, planner, task, overdue) to use offset
- Update meta-reducers with defensive fallbacks for state access
- Fix task component computed signals (isOverdue, isScheduledToday, etc.)
- Add 48 new tests covering offset boundary conditions

* style(planner): remove unused eslint-disable directive

* fix(start-of-next-day): use offset-aware date in ensureTasksDueTodayInTodayTag effect

Replace raw getDbDateStr() and getDateRangeForDay(Date.now()) with
store-derived todayStr and offset-adjusted range in task-due.effects.ts.
Without this, the effect would use the wrong day between midnight and
the configured startOfNextDay hour.

Also add selectOverdueTasks offset boundary tests.

* refactor(start-of-next-day): use DateService for offset-aware today checks

Add DateService.isToday() method that encapsulates the startOfNextDayDiff
offset logic, replacing scattered isToday()/getDbDateStr() calls across
effects, services, and components.

- Add isToday(date) to DateService for DRY offset-aware checks
- Fix task-repeat-cfg.effects.ts: 6 isToday/getDbDateStr calls
- Fix task-repeat-cfg.service.ts: isToday call
- Fix task-context-menu-inner.component.ts: 6 isToday/getDbDateStr calls
- Fix task-related-model.effects.ts: getDbDateStr call
- Fix work-context.service.ts: getDbDateStr call
- Remove duplicate planTaskForDay handler from tag.reducer.ts
  (already handled by planner-shared meta-reducer with offset)

* refactor(start-of-next-day): migrate remaining isToday() calls to offset-aware DateService

Replace 6 call sites still using the non-offset isToday()/isYesterday()
with DateService methods that respect startOfNextDayDiff. Also adds
isYesterday() to DateService and uses isTodayWithOffset in legacy backup
migration. Behavior is identical at offset=0 (default).

* fix(start-of-next-day): fix offset bugs, sync regression, and code quality issues

- Fix wrong config path in legacy backup migration (misc.startOfNextDay)
- Restore sync readiness check (filter+first instead of take(1))
- Restore SYNC_AFTER_ENABLE in setInitialSyncDone conditions
- Use offset-aware dates in addAllDueToday/addAllDueTomorrow
- Make isSameDay offset-aware and pass offset through planner selectors
- Fix TagSettingsPageComponent selector from 'project-settings' to 'tag-settings'
- Hide settings link for virtual TODAY tag
- Revert direct ru.json edits (only en.json should be edited)
- Add standalone:true and use takeUntilDestroyed in settings components
- Restore Math.max(duration,1) for zero-duration overlap detection
- Remove dead code, stale CSS, and commented-out HTML
- Add input validation clamping in DateService.setStartOfNextDayDiff

* fix(start-of-next-day): fix offset bugs in overdue detection, planner display, and LWW sync

- Fix isOverdue ignoring offset for dueWithTime tasks in task.component
- Remove duplicate moveBeforeTask handler from tag.reducer (handled by meta-reducer)
- Add skip(1) and hydration guard to setTodayStr$ effect to prevent race condition
- Move side effects from map() to tap() in global-config.effects
- Fix isSameDay double-offset bug in planner.selectors for scheduled tasks/events
- Replace unsafe `as any` casts with proper PlannerState types
- Use safe optional chaining for todayStr access in meta-reducers
- Refactor handlePlanTaskForDay to use helper functions with hasChanges optimization
- Extend syncTodayTagTaskIds in LWW meta-reducer to handle dueWithTime changes
- Fix absolute import path in global-config.effects
- Add @deprecated to isToday() in favor of offset-aware alternatives

* fix(config): migrate task dueDays when startOfNextDay offset changes

When the "start of next day" offset changes and causes todayStr to shift,
existing tasks with dueDay matching the old todayStr are now migrated to
the new todayStr so they remain classified as "today" tasks.

* refactor(config): use switchMap and document archive task exclusion

Replace mergeMap with switchMap in setStartOfNextDayDiffOnChange
effect to better communicate intent (only latest emission matters).
Add comment clarifying archived tasks are intentionally excluded
from dueDay migration.

* test(sync): add LWW tests for dueWithTime → TODAY_TAG sync

Cover the dueWithTime path in syncTodayTagTaskIds that was added
but had no test coverage. Tests verify TODAY_TAG membership updates
when dueWithTime changes via LWW sync.
2026-02-21 12:47:19 +01:00
Johannes Millan
0aa3a04a85
Fix/6580 (#6587)
* fix(side-nav): make settings button visible on Android mobile (#6561)

Change nav-list height to min-height so overflow enables scrolling,
and add safe-area padding for Android gesture navigation bar.

* build: add worktrees to gitignore

* fix(tasks): guard against undefined tagIds/subTaskIds on corrupted task data

Add _ensureTaskArrayProperties() as early data repair step to initialize
undefined tagIds, subTaskIds, and attachments to []. Add defensive optional
chaining in daily-summary and board-panel components to prevent TypeErrors
when tasks from legacy/corrupted data have missing array properties.

Closes #6580
2026-02-20 21:31:43 +01:00
novikov1337danil
66ec4d51b5
refactor(date-formatting): improve date formatting (#6539)
* refactor(date-formatting): improve date formatting

* fix(tests): change tests mock object for DateTimeFormatService

* refactor(date-adapter): implement custom date adapter for locale-aware formatting and parsing

* refactor(date-adapter): enhance date parsing and formatting logic for locale support

* refactor(test): remove redundant date format tests

* refactor(date-time-format): improve getting locale-specific format
2026-02-20 21:16:09 +01:00
Johannes Millan
a23af05759 fix(electron): prevent app from closing when cancel is clicked on quit confirmation
When the "finish day before exit" dialog appeared and the user clicked
Cancel, setDone() was called unconditionally, signaling Electron that
the before-close handler completed and causing the app to quit anyway.
Adding an early return skips setDone(), keeping the handler pending so
the app stays open. Fixes #6563.
2026-02-17 18:19:20 +01:00
Johannes Millan
08e8329f97 refactor(sync): consolidate LegacySyncProvider into SyncProviderId
Remove duplicate LegacySyncProvider enum and use SyncProviderId everywhere.
The two enums had identical values but were separate types for historical
reasons, making the "Legacy" name misleading since providers are actively used.
2026-02-15 11:19:22 +01:00
Johannes Millan
41027f3099 refactor(simple-counter): move habit management from config page to habits page
Add delete button to habit settings dialog with confirmation. Add
collapsible disabled habits section to the habits page with enable,
edit, and delete actions. Remove simple counter section from global
config page and delete the unused SimpleCounterCfgComponent.
2026-02-13 15:30:09 +01:00
Mick Zijdel
d6a6ea1f12
Fix Dropbox authentication (#6489)
* fix(sync): add button to authenticate with dropbox to sync settings

* fix(sync): add text to clarify if Dropbox is currently authenticated or not

* fix(sync): remove try-catch block that can prevent errors with the storage from bubbling up. It will now show a snackbar with a generic incomplete_cfg message

* fix(sync): allow forcing re-authentication of a sync provider (only used for Dropbox now)
2026-02-13 14:06:33 +01:00
Johannes Millan
6a6bf8c90d style(config): use standard text color for version footer links 2026-02-12 21:18:14 +01:00
Johannes Millan
d5e02222f4 perf(search): optimize search page filtering and mapping pipeline
Replace O(n) array lookups with Map-based O(1) lookups for parent tasks,
projects, and tags. Pre-compute lowercase search text once at mapping
time instead of on every keystroke. Memoize archive task mapping since
archive data never changes. Fix crash when subtask parent is missing
from the task array by using null-safe Map lookup with fallback.
2026-02-11 20:37:40 +01:00
Johannes Millan
7886c7095a refactor: replace explicit any types with proper types across 15 high-impact files
Replace ~130 `any` occurrences with proper types, `unknown`, or narrower
type assertions in issue providers (Jira, Linear, OpenProject), shepherd
steps, ical integration, worklog mapping, config components, legacy backup
migration, operation log hydrator, and LWW meta-reducer.
2026-02-10 14:41:16 +01:00
Johannes Millan
d4cd9a3575 fix: address 9 code review findings
- Change server-side pruning log from info to debug
- Increase vector clock sanitize limit from 3x to 5x MAX
- Add Formly hierarchy comment for WebDAV settings
- Add test documenting isLikelyPruningArtifact false positive limitation
- Replace `as any` with proper Partial<TaskRepeatCfgCopy> typing
- Add comment explaining `order` in SCHEDULE_AFFECTING_FIELDS
- Cache Intl.Collator instance, recreate only on locale change
- Document plugin management 30s timeout rationale
- Extract _isLikelyPruningArtifact as standalone pure function
2026-02-09 17:55:12 +01:00
Johannes Millan
273d1b7dc3 fix(sync): save WebDAV settings after successful Test Connection (#6345)
The Test Connection button validated and tested the connection but never
triggered a settings save, causing entered data to be lost on navigation.
2026-02-09 17:55:12 +01:00
Copilot
f46836fb2b
fix: replace deprecated substr(), add radix to parseInt(), fix silent catch (#6408)
* Initial plan

* Initial plan for fixing obvious code errors

Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>

* fix: replace deprecated substr() with slice(), add radix to parseInt(), fix empty catch block

Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>

* fix: revert unrelated package-lock.json changes

Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: johannesjo <1456265+johannesjo@users.noreply.github.com>
2026-02-08 13:50:54 +01:00
Johannes Millan
b2f57c80a5
fix: address root causes instead of treating symptoms (#6407)
- sync.effects.ts: Replace arbitrary delay(100) with event-loop yield
  (setTimeout 0) so NgRx persistence effects actually complete before
  sync runs, instead of hoping 100 ms is "enough"

- daily-summary.component.ts: Replace arbitrary delay(70) with
  event-loop yield for the same reason — let the archive persistence
  write finish before re-reading, instead of a magic timeout

- calendar-integration.service.ts: Log localStorage JSON parse errors
  instead of silently swallowing them in an empty catch block

- app.guard.ts: Log the actual error in ValidTagIdGuard and
  ValidProjectIdGuard before returning false, so failed lookups are
  diagnosable

- add-task-bar-issue-search.service.ts: Log issue-provider search
  errors instead of silently returning an empty array

- task-detail-panel.component.ts: Log failed issue-data fetches
  instead of silently returning null

- linear-common-interfaces.service.ts: Log Linear API connection-test
  failures instead of silently returning false

- insert-blocked-blocks-view-entries-for-schedule.ts: Replace vague
  "for some reason" comments with actual root-cause explanation —
  splice() operations scatter split-continued entries non-contiguously,
  requiring time-based (not index-based) movement

https://claude.ai/code/session_01RHxKdsHHtFiXs3qbtbPBQC

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-08 12:17:22 +01:00
Johannes Millan
b66b680e30
fix: address code review findings across sync, tasks, and UI (#6339)
- fix(tasks): preserve selectAllTasks memoization by only filtering when
  undefined entities exist, avoiding new array allocation on every call
- fix(sync): replace mutable ARGON2_PARAMS export with getter/setter to
  prevent test pollution across spec files
- fix(sync): convert tag-task-page from async pipe to toSignal pattern
  to fix OnPush change detection after bulk sync state updates
- fix(sync): remove E2E navigation workarounds that masked the rendering
  bug now fixed by the toSignal conversion
- fix(sync): add clarifying comments for archive-wins sibling conflict
  resolution and waitForSyncWindow switchMap concurrency semantics
- fix(ios): add hex preview of first 16 bytes to WebDAV UTF-8 decode
  error for easier debugging
- docs: add JSDoc to getDiffInWeeks noting negative diff behavior

https://claude.ai/code/session_01Y51QDFEdvrJ9VVgp9XfWLJ

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-03 12:13:57 +01:00
Lisontowind
6bc810f209
Add a management page for habits (#6265)
* feat: introduce habit tracking page and enhance simple counters with streak tracking and comprehensive configuration options.

* feat: add habit tracker for simple counters with navigation and internationalization.

* feat: Introduce habit tracker component and tests for simple counter streak duration calculation.

* Fix the dialog style that appears in the Habit interface

* bug fix

* Fixed translation and time zone issues

* habit icon

* app features

* Add a Settings button to the Habits page; clicking it opens the Settings interface and automatically expands the corresponding configuration section.
Clicking a habit icon allows you to configure that habit. To add a new habit, click the “Add” button.

* If a habit does not have a custom icon, its first character can be displayed inside a circular placeholder instead.

* The dialog box appears only after you release the button following a long press.

* Add the functionality to display names; clicking the button shows the habitual name. This can be persisted

* bug修复:Date adjustment (left/right) in shrink mode is not functioning as expected.

* Set Text Icon

* Fix abnormal icon size

* These development artifacts should not be committed to the repository.

* Lost Chinese translations

* Flaky Date-Dependent Tests

* Logic error in streak calculation

* Fix the icon issue

* Translation file violation
Use of any type

---------

Co-authored-by: Xinjie <xinjie_zhou@163.com>
2026-02-02 14:24:00 +01:00
Benjamin Hooper
2e20746fb8
feat: Copy Version Number #5108 (#6184)
* feat: Copy Version Number #5108

* Use Claude Code Review Suggestion

* Added Translation

* Refactor to use shared copyToClipboard function
2026-01-27 14:41:35 +01:00
Johannes Millan
be9697e288 refactor(sync): remove duplicate change encryption password button
The button was duplicated in both config-page.component.ts and
sync-form.const.ts. Keep the one in sync-form.const.ts as it's
properly placed in the Advanced Settings section.
2026-01-24 21:14:57 +01:00
Johannes Millan
f7bf3e554a fix(supersync): use npx tsx instead of global install in docker monitor
Replace slow/hanging global tsx installation with npx tsx which is faster
and doesn't require installation. Falls back to npx if tsx not found.
2026-01-23 14:58:59 +01:00
Johannes Millan
e673d74b55 test(schedule): add comprehensive unit tests for navigation
- Implement full test suite for ScheduleComponent covering:
  - Navigation state management (_selectedDate signal)
  - Week/month navigation (goToNextPeriod, goToPreviousPeriod, goToToday)
  - Today detection (isViewingToday computed)
  - Context-aware time calculations (_contextNow)
  - Schedule days computation with contextNow/realNow
  - Current time row display logic
  - Days to show calculations for week and month views

- Add ScheduleService tests for:
  - getDaysToShow with reference dates
  - getMonthDaysToShow with padding days
  - buildScheduleDays parameter handling
  - getDayClass with reference month support

- Fix test setup:
  - Use TranslateModule.forRoot() for proper i18n support
  - Add complete mock methods for ScheduleService
  - Handle timing-sensitive tests with appropriate tolerances
  - Use correct FH constant value (12) for time row calculations

- Remove unused CollapsibleComponent import from config-page

All 32 ScheduleComponent tests passing
2026-01-21 14:30:24 +01:00
Ivan Kalashnikov
7f61c638c3 fix: enhance Tasks tab with tooltip and section title 2026-01-20 00:47:55 +07:00
Johannes Millan
8734b7ef4c
Merge pull request #6053 from steindvart/task-settings
Move task-related settings to a dedicated Tasks Settings tab and fix technical issues
2026-01-19 16:46:44 +01:00
Johannes Millan
27f07e418a
Merge pull request #6058 from steindvart/tabs-style-small-devices
Improve settings tabs navigation on small screens
2026-01-19 16:20:25 +01:00
Michael Chang
a54e5f7fe8 style(sync): use proper button label for force upload 2026-01-19 14:56:05 +01:00
Ivan Kalashnikov
86be6872bf feat(config-page): add section titles to each tab in settings 2026-01-19 20:24:48 +07:00
Ivan Kalashnikov
d1f5045646 feat(config-page): hide tabs labes in 'md' size screens 2026-01-19 20:21:05 +07:00
Michael Chang
222b3474b8 fix(sync): restore missing force upload button in new config UI 2026-01-19 13:58:23 +01:00
Ivan Kalashnikov
b4bdf94040 Merge remote-tracking branch 'origin/master' into task-settings 2026-01-18 23:41:19 +07:00