Commit graph

14206 commits

Author SHA1 Message Date
cocojojo5213
ee45bc8d35 fix(issue): clear synced issue values on unlink #7135 2026-06-08 22:29:02 +09:00
cocojojo5213
e232e08925 fix(issue): clear stale provider references #7135 2026-06-08 22:15:57 +09:00
Johannes Millan
eff41c041d
feat(project): project completion experience (#8036)
* feat(project): add project completion with celebration + trophy view

Completing a project marks it done and archives it, with a celebration
dialog (confetti + live stats) and a prompt to resolve unfinished tasks
(move to Inbox / mark done). Completed projects show a trophy badge and
a Reopen action on the archived-projects page.

isDone stays distinct from isArchived; selectArchivedProjects is left
intact so completed projects' tasks stay filtered out of Today/Overdue.
Append/merge deferred to #8032. Plan: docs/plans/2026-06-05-project-completion.md

* refactor(project): drop Archive menu item; Complete is the retire path

Archive and Complete produced near-identical end states; collapse to one
user-facing action. Removes the 'Archive project' menu item and handler so
Complete is the single way to retire a project. The archiveProject action,
reducer and ProjectService.archive() stay (needed for op-log replay of
historical archive ops and the legacy unarchive/restore path). Wiki updated;
menu specs cover the Complete flow.

* fix(project): keep completion dialog open for the active project

MatDialog closeOnNavigation (default true) dismissed the celebration the
moment completing the currently-active project navigated to '/'. Navigate
first, then open the dialog.

* test(project): e2e for completion flow (complete, celebrate, reopen)

Covers the resolve-unfinished-tasks prompt, the celebration dialog with
stats, the trophy badge on the archived page, and reopening. Adds an
openProjectContextMenu page-object helper.

* feat(project): confirm project completion

* feat(project): show completion celebration fullscreen

* fix(project): harden completion celebration flow

* style(project): use spacing tokens in completion dialog

* fix(project): align completion screen with project context

* style(project): soften completion screen coloring

* style(project): reuse completion screen surfaces

* fix: refine project completion dialog actions

* fix: complete projects with atomic task resolution

* fix: restore archive path in project completion UI

* refactor(project): remove dead completion code

The project-level completeProject action (OpType.Update) was never
dispatched — completion goes exclusively through the atomic
TaskSharedActions.completeProject (OpType.Batch) meta-reducer. Drop the
dead action, its reducer case, the PROJECT_COMPLETE enum member and the
immutable 'PCO' op-log code (which would otherwise be permanently
reserved for an op that can never be produced); enum count 147->146.

Also remove the unused selectCompletedProjects / selectPlainArchivedProjects
selectors (no consumers) and the misspelled, unused 'angel' confetti
field, keeping the regression tests that guard selectArchivedProjects.

* fix(project): make project completion non-reversible

Completion resolves a project's open tasks (move-to-inbox / mark-done),
which reopen cannot truly restore, so the "Reopen"/"Undo" affordances on
the completion path were misleading. Drop the celebration dialog's Reopen
button and the post-complete undo snack; the fullscreen celebration is
the feedback and deliberate reactivation still lives on the
archived-projects page (Project.reopen kept for it).

Also restore the project title param on the archive confirm dialog (it
was rendering a raw {{title}} placeholder), remove the now-unused
moveTasksToInbox / markTasksDone resolution helpers (the meta-reducer
resolves tasks atomically), and drop the orphaned UNDO / S.COMPLETED
i18n keys. Updates the completion e2e to the close flow and asserts the
resolution props are forwarded to the atomic action.

* fix(tasks): cancel native reminders for project-completed tasks

Completing a project marks its unfinished tasks done inside the
meta-reducer (no per-task updateTask), so unscheduleDoneTask$'s
native-reminder cancellation is bypassed and an OS-scheduled Android
notification could still fire for a now-done task. Add a local-only
effect that cancels native reminders for the force-completed task ids.

Local-only by design: it dispatches no actions (the persistent
dismissReminderOnly/clearDeadlineReminder would each be an extra synced
op), and done tasks are already filtered from reminders$ on all
platforms — only the native Android notification needs explicit removal.

* test(project): drop TaskService spies orphaned by helper removal

getByIdWithSubTaskData$/moveToProject/setDone/setUnDone were only used
by the removed moveTasksToInbox/markTasksDone helpers and their deleted
tests.

* feat(sync): affectedEntities multi-entity conflict detection for atomic completion

WIP checkpoint of the atomic completeProject approach. The Batch op declares
every touched entity (PROJECT, INBOX, TASKs, TODAY_TAG) via a new
affectedEntities field threaded through op-log capture, conflict detection,
the sync server (+Prisma migration) and shared-schema. Per-effect
completeProject handlers (issue two-way-sync, time-block, repeat-cfg)
re-derive the task changes the atomic op bypasses.

* revert(sync): remove affectedEntities multi-entity conflict detection

Reverts 0893a86162. The affectedEntities feature existed solely to make the
atomic completeProject Batch op sync-correct (its only producer). Decoupling
project completion into normal per-task ops (next commit) makes the existing
per-entity conflict detection and effects fire naturally, so this entire
layer — sync-core, super-sync-server, shared-schema, op-log plumbing, the
Prisma migration, and the per-effect completeProject listeners — is no longer
needed. Preserved in history via the checkpoint commit.

* refactor(project): decouple completion from task resolution (Option C)

Completion was an atomic multi-entity Batch op (completeProject) that marked
tasks done / moved them to Inbox inside the project-shared meta-reducer.
Because it bypassed the normal per-task actions, every downstream consumer had
to be taught about it separately — conflict detection (the affectedEntities
feature, reverted in the previous commit), native-reminder cancellation, issue
two-way-sync, time-block and repeat-cfg effects.

Decouple instead: completion is now a plain single-entity PROJECT flag flip
(completeProject = OpType.Update, mirroring archiveProject). Unfinished-task
resolution runs first as the normal per-task actions (moveToOtherProject /
updateTask isDone) from the completion flow, so the existing effects and
per-entity conflict detection fire naturally — no special-casing anywhere.

- project.actions/reducer: restore plain completeProject action + on() handler
- project.service: complete() is a flag dispatch; restore moveTasksToInbox /
  markTasksDone (normal per-task dispatch + Rule #6 flush)
- work-context-menu: resolve unfinished work before the flag flip
- drop the completeProject meta-reducer block, the Batch action, the
  TASK_SHARED_COMPLETE_PROJECT op code, and the reminder-cancel effect
  (unscheduleDoneTask$ already cancels native reminders on the normal path);
  current-task clearing is covered by the existing task-internal effect

Net: ~190 LOC removed here on top of ~1565 (affectedEntities + a Prisma
migration) in the revert. Completion's task resolution is not undone either
way, so the atomic bundle never bought a clean reversal.

* docs(project): record decoupled-completion decision (ADR #5)

Document why project completion uses decoupled per-task resolution + a plain
single-entity flag flip instead of an atomic multi-entity op: the atomic op
forced a cross-stack affectedEntities conflict-detection feature and per-effect
listeners, for an undo guarantee it never delivered. Adds ARCHITECTURE-DECISIONS
#5 and a revision note + corrected undo/bulk-mechanic notes in the plan doc.

* test(project): pin completion ordering + resolution edge cases

Address multi-agent review of the decoupled-completion refactor:
- assert resolution (moveTasksToInbox / markTasksDone) runs BEFORE the
  completeProject flag flip (toHaveBeenCalledBefore) — the core invariant of
  the decoupled design that was previously not pinned
- cover the not-done branch of moveTasksToInbox (no setUnDone) and assert
  markTasksDone dispatches exactly the passed set
- add explicit PCO encode/decode round-trip assertions
- document the inbox-path current-task carry-forward nuance in ADR #5

Composition is covered end-to-end by e2e/tests/project/project-completion.spec.ts.

* refactor(project): tighten completion flow per review

- collapse 3x getCompletionInfo() to <=2: gate the resolve prompt once,
  recompute only after a resolution; each call now wrapped with an error
  snack so a failed archive load no longer aborts silently
- drop the dead post-confirm re-prompt branch (unreachable between two
  sequential single-user modals)
- reuse getDiffInDays + dateStrToUtcDate in completion-stats util instead
  of hand-rolled local-midnight/duration helpers
- use a Set for the top-level-task membership check (was O(n*m))
- drop redundant inline dialog sizing; the panelClass owns fullscreen
- remove dead --project-complete-accent test assertion

* refactor(project): finish review follow-ups for completion flow

- W3: reset the celebration confetti instance on dialog destroy so its
  rAF loop + window resize listener are torn down when the dialog closes
  before the animation ends (ConfettiService now returns the handle and
  fires without awaiting completion)
- S2: extract resolveBgImageToDataUrl() shared by app.component and the
  celebration dialog (was duplicated file://->data-url resolution)
- S3: split completeProject() into _getCompletionInfoOrNotify (dedupes the
  error handling), _promptResolveUnfinishedTasks and _confirmCompletion
- W2: keep prefers-reduced-motion gating app-wide (a11y) + document intent

* fix(project): close confetti teardown race on early dialog close

If the celebration dialog is dismissed while canvas-confetti is still
loading, the instance was assigned after ngOnDestroy ran, so reset() never
fired and the rAF loop + resize listener leaked. Guard with an _isDestroyed
flag and reset the instance immediately if it arrives post-destroy.

Also drop the now-dead CanvasConfetti type alias (superseded by
ConfettiInstance, zero references).

* docs(project): drop non-existent undo-snack from completion wiki

* refactor(project): extract completion task-tree and dialog helpers

* refactor(project): hide Archive menu item; Complete is the retire path

* refactor(project): drop dead archive(), reuse resolve-choice type

Multi-review follow-ups on the completion feature:
- Remove orphaned ProjectService.archive() (+ unused import, spec) — the
  menu collapsed Archive into Complete, leaving no caller. The
  archiveProject action/reducer stay for op-log decode of historical ops.
- Reuse the exported ResolveUnfinishedTasksChoice type instead of
  re-spelling the union three times in work-context-menu.
- Fix misleading moveTasksToInbox comment (setUnDone re-opens, not move).
- Note the as-shipped deviations (no extra selectors, no celebration
  effect) in the design plan so they aren't hunted for later.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-08 13:43:38 +02:00
Puneet Dixit
59c785c72b
fix(metric): use worklog totals for activity heatmap (#8013)
* fix(metric): use worklog totals for activity heatmap (#7993)

* fix(metric): refresh heatmap year after worklog load

* test(calendar): use flush() to drain dynamic-import promise

requestEvents$ awaits loadIcalModule(), which does a one-time
`await import('ical.js')`. With fakeAsync, `tick(0)` after `req.flush()`
isn't guaranteed to settle the import promise on the first invocation,
making the test order-dependent and flaky in CI.

Replace tick(0) with flush() in the requestEvents$ describe block to
drain the full microtask/macrotask queue.

---------

Co-authored-by: Deepak kudi <deepakkudi23@adsl-172-10-9-116.dsl.sndg02.sbcglobal.net>
Co-authored-by: johannesjo <johannes.millan@gmail.com>
2026-06-08 13:38:50 +02:00
felix bear
3c9dc68647
fix(trello): avoid logging raw picker results (#8130)
* fix(trello): avoid logging raw picker results #7870

* fix(trello): avoid logging issue key lists #7870

* chore(ci): rerun electron packaging for #8130

* chore(ci): rerun checks for #8130

---------

Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:46:41 +02:00
felix bear
df5f7f6d57
fix(open-project): avoid logging backlog work packages (#8126)
* fix(open-project): avoid logging backlog work packages #7870

* fix(open-project): avoid logging work package id lists #7870

* chore(ci): rerun electron packaging for #8126

* chore(ci): rerun checks for #8126

---------

Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:46:27 +02:00
Johannes Millan
f7c6bd4737 test(karma): guard against leaked rxjs scheduler action crash
A time-based operator (debounceTime/delay/timer/interval) whose
subscription is torn down before its timer fires leaves a closed
AsyncAction whose pending setInterval still runs scheduler.flush().
rxjs then rethrows Error('executing a cancelled action') synchronously
inside the timer callback, surfacing in an unrelated spec's afterAll,
wedging Chrome and disconnecting the whole Karma session
(order-dependent master flake, e.g. run 27128353155 at ~test 2824).

Patch AsyncAction.prototype.execute in src/test.ts to no-op a cancelled
action instead of returning the Error flush rethrows. A cancelled action
must not run anyway, so this is semantically correct; only the diagnostic
is dropped (warn-once breadcrumb retained). Live actions delegate to the
original execute unchanged. Covers async/asap/animationFrame schedulers
(QueueAction is synchronous, cannot leak a timer).

Add test-harness-async-action-guard.spec.ts: disabling the patch makes
it throw the exact error; with it the flush is a no-op.
2026-06-08 12:38:51 +02:00
Johannes Millan
0d1869263f docs: remove outdated and implemented plan docs
Delete 29 plan/design docs whose work has shipped or been superseded
(SuperSync slices, sync-core extraction, encryption-at-rest drafts,
document-mode/Stage-A persistence, calendar/CalDAV concepts, focus-mode
time-tracking sync, etc.).

Kept the still-forward-looking docs (e.g. supersync-encryption-at-rest,
sync-core-simplification-roadmap, calendar-two-way-sync-technical-analysis).

Source comments that cited deleted docs are rewritten into self-contained
inline rationale so no "see docs/..." reference dangles.
2026-06-08 12:38:51 +02:00
felix bear
71f4ca484c
fix(plugins): return dialog result #5239 (#8106)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:14:08 +02:00
felix bear
00cd665e1a
feat(backup): configure automatic backup file limit #6690 (#8094)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:09:49 +02:00
felix bear
01183111dc
refactor(core): share markdown task parsing setup #7918 (#8115)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:09:40 +02:00
felix bear
cb53bb97ff
fix(jira): skip transition for target status #5940 (#8102)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 12:07:03 +02:00
Johannes Millan
e9a7b3e7db
fix(reminder): dismiss reminder dialog when reminders vanish after sync (#8105)
* fix(reminder): dismiss reminder dialog when reminders vanish after sync

The reminder dialog's displayed list was only updated by explicit user
actions or by the worker emitting active reminders. The worker only ever
signals reminders that ARE due, never that one has disappeared, so when a
reminder was dismissed, completed or deleted on another device and synced
in, the open dialog kept showing the now-stale entry indefinitely.

Reconcile the displayed reminders against the live store: drop a reminder
once its task loses the relevant remindAt/deadlineRemindAt, is completed,
or is deleted, and close the dialog when nothing is left.

To avoid re-introducing the open-time race (worker snapshot briefly ahead
of the store) that an earlier fix relaxed, a reminder is only auto-dismissed
if it was confirmed present in the store at least once and then vanished.
The reconcile subscription is cancelled eagerly on close, mirroring the
existing onRemindersActive$ handling.

* refactor(reminder): gate dialog reconcile watcher and broaden tests

Follow-up to the reminder-dialog sync-dismiss change, addressing review
feedback:

- getByIdsLive$ (selectTasksById) emits a fresh array on every task
  mutation app-wide, so the reconcile watcher ran far more often than
  needed. Add a distinctUntilChanged that only lets through changes to the
  watched tasks' id/isDone/remindAt/deadlineRemindAt.
- Add tests for: a future-rescheduled reminder is kept (not dropped),
  all reminders vanishing at once closes exactly once, isAllDeadline
  recomputes on partial drop, redundant re-emission after a partial drop
  is a no-op, a dropped reminder does not reappear if the store re-adds it,
  and no further close after the dialog is already closed. Strengthen the
  destroy test to assert the reconcile path closed the dialog first.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-08 11:41:08 +02:00
felix bear
128fd73342
fix(jira): fill yesterday worklog time #4384 (#8101)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:41 +02:00
felix bear
db9f605ab7
fix(tasks): focus context submenus for typeahead #7987 (#8098)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:36 +02:00
felix bear
95fc91e185
fix(tasks): keep cleared Today add-task date #5339 (#8091)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:32 +02:00
felix bear
16735dbf05
fix(notes): wrap long inline markdown words #7482 (#8088)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:27 +02:00
felix bear
3221cf001c
fix(work-context): align settings dialog size #8048 (#8087)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:23 +02:00
felix bear
667e8c3aa0
fix(azure-devops): simplify host setup #7672 (#8086)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:19 +02:00
felix bear
c0146e2307
feat(help): add create task how-to #8015 (#8079)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:14 +02:00
felix bear
3dd328ba80
fix(tasks): plan started tasks for today #8031 (#8076)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:09 +02:00
felix bear
03644e8234
fix(core): refresh day stream after next-day start changes #7720 (#8075)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:05 +02:00
felix bear
9ca4d49693
fix(daily-summary): exclude future recurring tasks #5488 (#8099)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:40:00 +02:00
Johannes Millan
4bd4a4636b
fix(tasks): hide paste image hint on touch devices (#8103)
* fix(tasks): hide paste image hint on touch devices

* fix(tasks): remove paste image hint from task detail panel

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-08 11:35:10 +02:00
felix bear
b0ccaf0425
fix(tasks): support emoji project menu typeahead #8085 (#8089)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:50 +02:00
felix bear
321f4fb503
fix(boards): translate board modal labels #8070 (#8084)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:45 +02:00
felix bear
dd8eaf712e
fix(util): support technical symbol emojis #7896 (#8080)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:36 +02:00
felix bear
b38d105549
fix(projects): color visibility menu project icons #8029 (#8074)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:31 +02:00
felix bear
6a39785f6e
fix(issue): avoid logging provider config updates (#8129)
* fix(issue): avoid logging provider config updates #7870

* fix(issue): harden provider config log metadata #7870

---------

Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:27 +02:00
felix bear
2f4f9ebdb6
fix(core): avoid logging crash user data #7870 (#8128)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:23 +02:00
felix bear
18823a68f5
fix(issue): avoid logging raw http errors #7870 (#8125)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:18 +02:00
felix bear
09469e64e5
fix(jira): avoid logging raw issue payloads #7870 (#8124)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:14 +02:00
felix bear
06a17b4b9b
fix(tasks): avoid logging issue search task result #7870 (#8123)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:09 +02:00
felix bear
eb5f353021
fix(tag): avoid logging tag state on reorder #7870 (#8122)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:27:04 +02:00
felix bear
5808b779ac
fix(plugins): avoid logging extracted zip data #7870 (#8121)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:26:59 +02:00
felix bear
8adaa345ca
fix(tasks): avoid logging short syntax result #7870 (#8119)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:26:54 +02:00
felix bear
9b2104a391
fix(nav): avoid logging dragged task objects #7870 (#8118)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-08 11:26:50 +02:00
摇摆熊
645797f0bd
fix(reminder): require action for reminder popup #8051 (#8057)
* fix(reminder): require action for reminder popup #8051

* test(reminder): update deadline reminder e2e expectation

---------

Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-06 17:34:06 +02:00
Maikel Hajiabadi
2ac8cf03a2
feat(tasks): add keyboard shortcut to set task deadlines (#8042)
* feat(tasks): add keyboard shortcut to set task deadlines

* fix(shortcuts): gate togglePlay to focused tasks and fix delegation visibility

* revert(i18n): remove manual translation in de.json

* docs(wiki): align shortcut labels and precedence note wording

* test(shortcuts): update TaskShortcutService tests to align with new precedence and delegation logic

* fix(shortcut): consume events on match to prevent fall-through when task focused

* test(shortcut): add regression test for ShortcutService precedence

* docs(wiki): correct Schedule view shortcut label

* style(i18n): remove accidental blank line in de.json

* test(op-log): stabilize lock reentry regression tests with robust timeouts
2026-06-06 16:15:49 +02:00
Johannes Millan
24a691bed5
fix(sync): surface native WebDAV errors (#8058) 2026-06-06 15:09:46 +02:00
摇摆熊
9ae3fdd6e0
fix(focus-mode): constrain long task titles #8012 (#8056)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-06 14:44:31 +02:00
摇摆熊
0dd53c775c
fix(markdown): preserve soft line breaks #8054 (#8055)
Co-authored-by: cocojojo5213 <cocojojo5213@users.noreply.github.com>
2026-06-06 14:29:04 +02:00
Joshua Lutgendorff
a4f5673652
fix(habits): add translucent background to mobile dropdown #7933 (#8016)
* fix(habits): add translucent background to mobile dropdown #7933

* fix(habits): use standard background for mobile dropdown #7933
2026-06-06 13:26:06 +02:00
Johannes Millan
724e1a6293
fix(daily-summary): handle exit after sync failure (#8047) 2026-06-06 00:01:56 +02:00
johannesjo
2708244578 Merge branch 'task/discussion-8022-f22960' 2026-06-05 23:07:22 +02:00
johannesjo
d41e0f9c0c fix(op-log): auto-fix missing taskRepeatCfg.quickSetting and tag.created
Post-sync validation looped on "State still invalid after repair" for
legacy / imported data (discussion #8022) when taskRepeatCfg entities
were missing the required `quickSetting` field or built-in tags were
missing the required `created` timestamp. data-repair couldn't recover
either: _fixTaskRepeatCfgInvalidQuickSetting short-circuits on falsy
quickSetting, and no rule covered tag.created.

Default undefined quickSetting to 'CUSTOM' (never auto-picks a date or
weekday without explicit user intent) and undefined tag.created to
Date.now().
2026-06-05 23:05:28 +02:00
johannesjo
1f24d5572d 18.9.1 2026-06-05 22:45:35 +02:00
Johannes Millan
2aacba1c98
fix(ci): repair v18.9.0 release pipeline (MAS build, iOS submit, flaky lock test) (#8040)
* fix(build): keep @electron/asar on minimatch v3 for MAS universal build

The `overrides.app-builder-lib.minimatch` pin to v10 cascaded into
@electron/asar (a child of both app-builder-lib and @electron/universal),
which only works with minimatch v3. minimatch v9/v10 ship as ESM with
`__esModule: true` and no `default` export, so @electron/asar's compiled
default import (`minimatch_1.default(...)`) resolved to undefined and threw
`TypeError: (0 , minimatch_1.default) is not a function` during the
universal-app asar merge (makeUniversalApp -> mergeASARs -> shouldUnpackPath),
failing `dist:mac:mas:buildOnly` in the Mac Store release workflow.

Carve @electron/asar back to minimatch 3.1.2 via nested overrides while
app-builder-lib (and @electron/universal) keep minimatch v10 as intended.

* fix(ci): declare export compliance for iOS App Store submission

The iOS release build, upload and processing all succeed, but
`upload_to_app_store` fails at submit-for-review with:

  [!] Export compliance is required to submit
      Example: submission_information: { export_compliance_uses_encryption: false }

Super Productivity only relies on exempt encryption (HTTPS / standard OS
crypto), so declare that the app does not use non-exempt encryption:

- ios/App/App/Info.plist: ITSAppUsesNonExemptEncryption=false (canonical,
  build-time declaration; also covers TestFlight, auto-resolved by ASC).
- fastlane/Fastfile: export_compliance_uses_encryption: false in
  submission_information, so the submit-for-review API call carries the
  declaration regardless of the binary.

* refactor(build): simplify @electron/asar minimatch override to top-level

Follow-up to the minimatch carve-out. Hoisting a top-level
`overrides["@electron/asar"].minimatch` pin produces a byte-identical
package-lock.json to the previous nested form, but is simpler and covers
every @electron/asar consumer (app-builder-lib, @electron/universal,
electron-winstaller) regardless of which parent wins hoisting — rather than
relying on a nested branch under app-builder-lib (whose @electron/universal
sub-branch was dead config given asar dedupes to a single instance).

* test(op-log): de-flake LockService mutex-invariant timeout test

"should preserve mutex invariant after timeout" flaked on the macOS CI
runner (TZ=America/Los_Angeles leg): it asserted that C always times out
waiting for the lock, but on a slow/loaded runner A can release the lock
before C's 50ms timeout fires, so C legitimately acquires it and runs —
after A has finished. The observed `['a-start','a-end','c-start']` actually
satisfies the invariant (C ran after A, never concurrently); only the
brittle "C must time out" assertion failed.

Assert the real no-concurrent-execution invariant instead: C must never
start before A ends. This still catches the original regression (concurrent
C would push 'c-start' before 'a-end') but is independent of runner timing.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-05 22:26:42 +02:00
Johannes Millan
920071f5ce 18.9.0 2026-06-05 20:30:11 +02:00
Johannes Millan
8e08b48a98
fix(task-repeat-cfg): keep custom weekdays interactive (#8034) 2026-06-05 20:12:34 +02:00