Commit graph

129 commits

Author SHA1 Message Date
Stefan Hynst
18472e86b9
fix(macOS): gracefully quit app (#7733)
* fix(macOS): gracefully quit app

When macOS App is closed via menu item "Quit", make sure that IPC flow completes first.

- close main window instead of directly invoking `quitApp()`

* fix(macOS): use quit-intent flag

- do not touch "minimizeToTray" setting
- instead set "quitRequested" flag to indicate quit intent
- set timeout to cancel quit request, if app fails to respond within 5 seconds

* refactor(macOS): split quit-intent state and add timeout rationale

- Separate the dual-purpose timer handle into an explicit boolean +
  named timer to make the semantics obvious.
- Extract the 5s window as a named constant with a comment on why this
  particular trade-off (long enough for sync/finish-day, short enough
  to not block a subsequent tray-hide click after cancel).
- Fix the misleading "set flag" comment in the no-window branch
  (no flag is set there; none is needed).
- Note that the `closed` reset clears the pending timer so it doesn't
  keep the event loop alive.

Pure cleanup, no behavior change.

---------

Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-05-27 17:13:43 +02:00
Johannes Millan
c1d14d501c
Experiment right side action bar (#7594)
* feat(layout): experimental vertical action strip on right edge

Teleports main-header's action-nav-right to document.body on desktop so
it escapes any ancestor containing-block, then pins it as a vertical strip
at the viewport's right edge via fixed positioning. Reserves the column
with padding-right on .app-container so the right-panel ends to its left.

* feat(layout): right-panel spans full viewport height

Restructure app shell so right-panel is a direct flex child of
.app-container (wrapping main-content via ng-content), letting its
.side extend over the full height of the viewport — including the
header area — rather than starting below the header.

* style(layout): give vertical action strip an elevated surface bg

* style(layout): match vertical action strip styling to left side nav

* fix(layout): stack play/focus buttons vertically in action strip

* style(layout): use solid surface bg for vertical action strip

* fix(layout): keep current-task title visible beside the action strip

In the teleported vertical action strip the current-task title pill was
positioned right:100% of the play button and clipped by the strip's
overflow, and the 48px mini-fab overflowed the 48px rail and got
side-clipped.

Render the title as a position:fixed flyout to the left of the strip
(the strip has no transform/filter so it is not a containing block for
fixed descendants), aligned to the play button across the web /
mac-titlebar / obsidian-header / RTL variants, and drop the play button
wrapper's horizontal margin so it fits the rail.

* fix(layout): stop tooltip overlay from blocking action strip clicks

A tooltip shown 'below' a button in the vertical action strip lands
directly over the next button. The tooltip's cdk-overlay-pane wrapper
(unlike the inner mat-tooltip-component) had no pointer-events:none, so
it intercepted clicks for real users and for Playwright actionability —
breaking ~20 focus-mode/break e2e tests.

* test(focus-mode): use teleport-robust focus-button locator

The action nav is teleported out of <main-header> into a body-level
strip, so 'main-header focus-button button' no longer matches. Drop the
main-header ancestor; 'focus-button button' is unique either way.

* fix(layout): polish vertical action strip (flyout, spacing, bg)

- Current-task title is now a hover-reveal flyout: hidden until the play
  button (or the flyout itself) is hovered. Mobile (< 1080px) unchanged
  (component still display:none's it there).
- Drop the position:fixed + magic top calc; keep the component's own
  absolute + translateY(-50%) so the flyout is pixel-perfectly centred
  on the play button regardless of theme/Material density.
- Strip now overflow: visible so the flyout can extend past the 48px
  rail (overflow-x can't be visible while overflow-y is auto).
- Re-declare --header-nav-button-gap on the strip: it is scoped to
  <main-header>'s :host but the strip is teleported to <body>, so the
  var was undefined => every strip button had gap: 0 (cramped).
- Extra margin between the play button and the focus button.
- Strip background now matches the left sidenav (--sidenav-bg).

* fix(layout): uniform vertical spacing between strip buttons

Drop the extra play-button and counters-group bottom margins; one
--header-nav-button-gap (var(--s)) now drives the spacing between every
button in the strip. Measured: all consecutive gaps = 8px.

* feat(layout): make vertical action bar a configurable opt-in

Adds misc.isVerticalActionBar (default off). The right-edge vertical
action strip was previously an unconditional experiment; it is now an
opt-in toggle in Settings > Misc that switches the layout live without
reload:

- app.component: @if branches the DOM between classic (horizontal
  header) and vertical (right-panel hoisted to full viewport height);
  .app-container gets .has-vertical-action-bar to gate CSS.
- main-header: one-shot ngAfterViewInit teleport replaced with an
  effect() that teleports/restores the action nav reactively to the
  config flag and the desktop/mobile breakpoint.
- app/right-panel SCSS: strip padding and full-height right-panel are
  now scoped to .has-vertical-action-bar; classic layout restored as
  the default.

* fix(layout): even vertical-strip spacing for panel-button wrappers

plugin-header-btns, plugin-side-panel-btns, desktop-panel-buttons and
user-profile-button are zero-height wrapper custom-elements. As direct
flex children of the vertical action strip the column gap landed on the
collapsed wrapper instead of the button(s) inside, so their icons were
unevenly spaced next to real buttons like the add button. Make each
wrapper a centered column flex item that stacks its button(s) with the
same gap, and hide truly-empty wrappers so they don't reserve a phantom
gap slot. Verified: all 7 visible strip buttons now 8px apart.

* fix(right-panel): clip transient content overflow during slide animation

.side animates width 0<->* while .side-inner keeps its min-width, so
content briefly spills past the (intentionally overflow:visible) .side
during open/close. Add an isPanelAnimating host class driven by the
@slideRightPanel start/done callbacks and clip :host for that window
only (overflow: clip — no scroll container). Mirrors the existing
resizing/windowResizing transient-state pattern. Verified: class +
clip present only during the ~200ms animation, visible when idle.

* refactor(layout): drop dual DOM for vertical action bar

Single classic layout for both modes; strip is teleported and offset by
--bar-height so the horizontal header keeps owning the title-bar zone
(native drag region + WCO + Mac traffic lights). Drops the 40px
title-bar-collision padding and the right-panel full-height override.

* feat(layout): right-panel side spans full viewport height

Move the header into right-panel's projected .content slot and make
right-panel host full-height. The panel column now starts at viewport
top with the header band only spanning the .content width, similar to
Obsidian / Linear / VS Code.

* fix(layout): only offset vertical strip below WCO band on Win/Linux

Default top inset is now 0 (web, Mac hiddenInset, native-frame Electron
all let the strip start at viewport top — none of them have a window-
control overlay clashing with the right edge). Push the strip down by
--bar-height only on Win/Linux Electron with custom title bar, where
the WCO buttons would otherwise sit on top of the strip's first row.

* style(electron): use compact 32px WCO band on Win/Linux

Shrinks the Windows Controls Overlay height from 44px to 32px so the
native min/max/close buttons sit in a slimmer band — matches VS Code /
Edge slim title bar conventions and frees more of the header zone for
app content. Width stays OS-controlled (~138px); only height is
configurable.

* style(layout): tighten WCO band to 24px and pull strip up to match

Drops WCO_HEIGHT to 24px on Win/Linux and introduces a --wco-height CSS
var mirroring it. The vertical action strip now clears the WCO band by
exactly --wco-height instead of --bar-height (48px), reclaiming the
newly-freed top zone on the right edge.

* style(layout): add breathing room above strip below WCO band

Strip top inset moves from --wco-height to --wco-height + --s so the
first action button isn't flush against the bottom of the window
controls overlay on Win/Linux.

* fix(styles): scope vertical-action-bar tooltip rule to the experiment

The pane-level `pointer-events: none` was needed only because tooltips
in the teleported vertical strip can land over the next button. Apply
it via a new `body.isVerticalActionBar` body class (toggled from
`misc.isVerticalActionBar` in GlobalThemeService, alongside the existing
`isObsidianStyleHeader` effect) so unrelated app tooltips keep their
default pane behaviour.

* refactor(styles): extract vertical-action-bar CSS to its own partial

Move the 130-line experimental strip block out of `src/styles.scss` and
into `src/styles/components/_vertical-action-bar.scss`. Wired via
`_components.scss`. No CSS rules change — pure code organisation.

* merge(master): resolve _components.scss conflict in right action bar branch

Agent-Logs-Url: https://github.com/super-productivity/super-productivity/sessions/1941dd45-72e1-4a3e-92da-912fcfcb9bed

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-05-23 16:11:37 +02:00
Johannes Millan
e7454ea6b9 fix(window): preserve maximized state for shortcut hide 2026-05-11 14:31:19 +02:00
johannesjo
a6b8159d5b feat(screenshots): liquid-glass-ready electron pipeline + diagnostics
Round of robustness fixes for the store-screenshot pipeline so the
Liquid Glass captures actually ship MAS-compliant PNGs:

Capture & dimensions:
- Capture by CGWindowID on macOS (`screencapture -l <id>` resolved via
  desktopCapturer.getSources matched on window title) instead of by
  screen rect. Survives small displays clipping the window and grabs
  the full hiddenInset titlebar including traffic-lights regardless of
  off-screen position.
- `enableLargerThanScreen: true` on the BrowserWindow when launched in
  screenshot mode (gated on a new SP_SCREENSHOT_MODE=1 env var). Keeps
  the configured 1280×800 outer from being clamped down to fit the area
  below the menu bar / dock — without this, captures came out 20pt
  short and Mac App Store rejected the dimensions.
- Drop `--no-sandbox` / `--disable-dev-shm-usage` from the Electron
  launch on macOS. They're Linux/CI helpers; on Mac `--no-sandbox`
  empirically suppresses the hiddenInset traffic-lights even though the
  same SP build launched via `npm start` shows them.

Configurability:
- `SCREENSHOT_CUSTOM_THEME` env var feeds the fixture's `customTheme`
  option, so a one-off pipeline run under e.g. liquid-glass / dracula
  doesn't require editing spec files.
- New `scrollScheduleUp` helper called from every schedule capture
  (desktop slots 03 + 06, mobile 05, tablet 03) — nudges the schedule
  scroll-wrapper up ~80px so the captured frame shows context before
  work-start instead of being flush against it.
- New slot-02 light variants for desktop (eisenhower) and mobile
  (planner-expanded) so both light and dark land at slot 02.

Diagnostics:
- Surface execFile stderr/stdout in the capture-failed Error so
  permission failures name the actual cause (`could not create image
  from rect`, `not authorized`, etc.) instead of just "Command failed".
- Loud banner on first OS-capture failure plus an end-of-run summary
  (via the existing globalTeardown) re-surfacing the warning so it
  isn't lost in long log scrollback. Marker file in MASTER_DIR
  bridges fixture → globalTeardown.
- Per-capture `[screenshot] <name> → <bin> <args>` log line, plus an
  `setBounds requested=… achieved outer=…; content=…` line right after
  the resize, so a "missing chrome" run is debuggable from the test
  output alone.
- README: macOS Screen Recording permission requirement documented.
2026-05-09 11:17:13 +02:00
johannesjo
21472356c7 fix(theme): polish liquid-glass — readability, parity, wallpaper, badges
Round of refinements on top of the Liquid Glass theme to take it from
"works" to "ships":

- Default to Liquid Glass on Apple Silicon Macs. Web / Intel / Linux /
  Windows still default to the system theme. Adds an `isAppleSilicon()`
  preload bridge + `IS_APPLE_SILICON` constant, and a CustomTheme
  default selector that picks Liquid Glass when both Electron and arm64
  are detected.
- macOS title-bar inset for the floating side-nav (titleBarStyle
  switched to 'hiddenInset' so AppKit positions traffic-lights at the
  standard inset other native apps use).
- Wallpaper handling: blur `.bg-image` directly so the whole page sees
  one out-of-focus image (no seam at the side-nav edge), drop
  `.main-content` / side-nav backdrop-filters under `body.hasBgImage`
  so the source-blur isn't re-blurred at different strengths, and hide
  the white/black `.bg-overlay` scrim that was washing out the glass.
- Surface opacity: bump every Tier-A fill (tasks, sub-tasks,
  schedule-events, planner-tasks, cards, banner, right-panel, notes,
  task-detail, attachments, sidenav) to 0.78–0.95 alpha so text reads
  cleanly whether the background is the soft primary-radial gradient
  or a user-selected photo. Light + dark aligned to the same alpha.
- Dark-mode further: tasks / sub-tasks / schedule-events / task-detail
  go fully opaque (deep RGB stepped ~10 units toward black) so content
  surfaces stay legible against the wallpaper while chrome / containers
  keep the soft glass material.
- Schedule weekday / week-column headers: bind to a solid --surface-2
  fill instead of the translucent --bg-lighter / transparent --bg the
  defaults used.
- Task time-badge / repeat-date-badge: solid surface (white in light,
  surface-4 in dark, slightly brighter than the task fill so the badge
  reads as a raised label rather than a recessed hole). Defaults bound
  it to translucent tokens, and the icon underneath bled through.
- Two stylelint suppressions for the new layered-token sections in
  _css-variables.scss (Cat B follows Layer 1 primitives on the same
  body / body.isDarkTheme selector — intentional duplicate).
2026-05-09 11:16:25 +02:00
Florian Bachmann
6c1a0b54f9
Caldav subtask import (#7409)
* fix(electron): disable webSecurity in dev mode to suppress CORS preflights

* feat(CalDAV): Option to import sub-tasks along with parent

* test(CalDAV): Adds specs for option to import subtasks along with parent

* doc(CalDAV): Adds notion on automatic sub-task import

* feat(CalDAV): Handles grandchildren and ignores subtasks of archived tasks.

* fix(setup): removes policy violating code

* fix(caldav):_resolve N+1 issue

* test(caldav):_adds more tests

* fix(electron):_fix task-widget mock in electron test
2026-05-01 13:07:03 +02:00
Johannes Millan
b642415702 fix(sync): improve Dropbox auth dialog UX on sandboxed Linux (#7139)
The "Get Authorization Code" button silently failed on Flatpak because
shell.openExternal rejects without renderer feedback when the
org.freedesktop.portal.Desktop talk-name isn't granted. After the user
gave up and reopened the dialog, the second attempt failed again with
`invalid_grant: invalid code verifier` because each call to
Dropbox.getAuthHelper() generated a fresh PKCE verifier that no longer
matched the originally-shown URL's challenge.

Three changes:

- Cache the in-flight PKCE Promise on the Dropbox provider so concurrent
  callers and consecutive dialog opens share one verifier+URL pair.
  Cleared on successful exchange, on clearAuthCredentials(), and on a
  rejected generation (so a one-time crypto failure doesn't poison the
  session). Five regression tests cover reuse, success-clear, explicit
  clear, concurrent calls, and rejection-recovery.

- Render the auth URL as user-selectable text under a <details>
  disclosure. Escape hatch when both shell.openExternal and the
  clipboard portal are denied — the user can triple-click to select and
  Ctrl+C the URL into a manually-opened browser. Adds
  D_AUTH_CODE.MANUAL_URL_HINT translation key.

- Pipe shell.openExternal rejections through
  errorHandlerWithFrontendInform so the existing IPC.ERROR snack
  channel surfaces a "Could not open the link in your browser" message
  instead of swallowing the failure to electron-log. Wrapped in a
  try/catch since errorHandlerWithFrontendInform throws synchronously
  if the renderer isn't ready.

The Flathub manifest also needs --talk-name=org.freedesktop.portal.Desktop
and --socket=wayland to fully fix the user-reported issue, but that
change lives in the flathub repo.
2026-04-25 22:36:14 +02:00
Johannes Millan
0f99f38ca9 fix(window): persist maximized state across tray-quit (#7276)
electron-window-state reads isMaximized() on an already-hidden window in
its `closed` handler, which returns false (electron#27838). Patch the
persisted state file in will-quit using our own wasMaximizedBeforeHide
flag, which is kept accurate by the maximize/unmaximize event listeners.
2026-04-21 15:03:41 +02:00
Johannes Millan
cbf3eb15d4 fix(electron): add GPU startup guard for confined Linux packages
Defense-in-depth against GPU init failures on Snap/Flatpak Linux where
the main process stays alive but the GPU process crashes at init and
the window never renders. Field data in #7270 (two post-v18.2.4
reports) shows this happens on Ubuntu 24.04+/25.10 regardless of GPU
vendor — the driver is core22 Mesa/libgbm drifted from the host Mesa.
See §12–§17 in docs/research/snap-wayland-gpu-fix-research.md.

Mechanism (electron/gpu-startup-guard.ts):

- Content-based crash marker in userData with {ts, electronVersion}.
  Written before app.whenReady() on confined Linux; cleared via
  IPC.APP_READY after Angular boot — not ready-to-show, which fires
  on blank/broken renderers too.
- Previous-crash detection: marker present AND recent (<5 min) AND
  matching Electron version. Staleness bound + version gating drop
  systemd-SIGKILL-mid-boot and post-upgrade-residue false-negatives.
- Env overrides SP_DISABLE_GPU=1 / SP_ENABLE_GPU=1 work on all
  platforms; auto-detection is Linux+Snap/Flatpak-only.
- Non-ENOENT fs errors logged at warn — a swallowed write-fail
  previously meant the guard could re-enter the loop with no
  diagnostic trail; a swallowed unlink-fail meant a successful boot
  could get permanently stuck in crash-recovery.

Fallback flag bundle (start-app.ts):
  --disable-gpu
  --disable-software-rasterizer
  --ozone-platform=x11

The pair matches Chromium's GPU integration tests' "no GPU process"
invariant; DisplayCompositor handles 2D in the browser process
without spawning a GPU child. app.disableHardwareAcceleration()
alone does NOT — verified against electron/electron#17180/#20702.
The extra --ozone-platform=x11 closes the Chromium 140+
browser-side Wayland/libgbm-dlopen gap on Flatpak (redundant with
the existing Snap X11 widening branch; last flag wins).

Novelty: R3 survey of VS Code, Slack, Insomnia, LosslessCut,
Obsidian flatpak, Firefox snap, and Canonical's gpu-2404-wrapper
found no peer Electron-snap implementing an equivalent reactive
crash-detection + auto-fallback. Prevailing patterns are manual
--ozone-platform=x11, proactive env-sniff, or do-nothing.

Review: §14–§15 multi-agent verification on the original PR #7273;
re-reviewed via 7-agent multi-review (6 Claude focus-agents + Codex
CLI) + 5 research agents here (§17). Live-tested with
SP_DISABLE_GPU=1 on a KDE/X11 dev host — window rendered normally
via DisplayCompositor.

Refs: #7270
2026-04-20 18:35:31 +02:00
Johannes Millan
01e30b9c7e
Feat/to me it looks like there are lots of 60dd04 (#7280)
* fix(issue): prevent crash from orphan issueProviderId (#7135)

The Jira image-headers effect in task-detail-panel subscribed to
selectIssueProviderById without an error handler, so a task with an
issueProviderId pointing at a deleted provider (e.g. after sync
convergence where taskIdsToUnlink didn't cover all local tasks)
propagated the selector throw to Zone.js as a crash dialog. Wrap the
inner selector observable in catchError that logs and falls back to
of(null); the downstream jiraCfg?.isEnabled guard handles the fallback.

Also drop IssueLog.log(issueProviderKey, issueProvider) from the
throwing variant of the selector: providers may carry credentials
(host, token, apiKey) and IssueLog history is exportable.

* fix(focus-mode): sync tray countdown with in-app timer during breaks

Tray title was rebuilt from a cached currentFocusSessionTime that only
refreshed when CURRENT_TASK_UPDATED fired. addTimeSpent is gated on an
active current task, so during focus-mode breaks or task-less focus
sessions the cache froze while the in-app timer kept ticking.

Add the tick action to taskChangeElectron$ so the cache refreshes every
second whenever the focus timer is running.

Fixes #7278

* fix(ci): restore GitHub Actions SHA pins undone by 0e9218bd68

Commit 0e9218bd68 silently reverted PR #7212 (github-actions-minor group
bump) along with its stated sync/client-id work. This restores the 15
workflow files to their pre-revert state.

Actions restored to newer pinned SHAs:
- actions/upload-artifact v7.0.0 -> v7.0.1
- step-security/harden-runner v2.16.1 -> v2.17.0
- softprops/action-gh-release v2.6.1 -> v3.0.0
- signpath/github-action-submit-signing-request v2.0 -> v2.1
- anthropics/claude-code-action v1.0.89 -> v1.0.93
- docker/build-push-action v7.0.0 -> v7.1.0
- easingthemes/ssh-deploy v5.1.1 -> v6.0.3

* fix: restore i18n, UI, and docs work undone by 0e9218bd68

Commit 0e9218bd68 silently reverted the following work alongside its stated
sync/client-id changes. Files where later master commits (fec7b25f23, etc.)
already re-applied the reverted work are intentionally left untouched.

Restored:
- #7232 docs/long-term-plans/location-based-reminders.md (513 lines)
- #7199 Romanian i18n phase 3 (ro.json + ro-md.json, ~1168 lines)
- #7049 Polish translation improvements
- #7143 planner component styling (4 scss files)
- #7211 add-task-bar preserve time estimate when typing title
- #7208 task.reducer roll-up estimates for added subtasks
- #6767 focus-mode pomodoro reset button
- #7205 plugin-dev github-issue-provider TOKEN description
- #7231 mobile-bottom-nav FAB fix
- a4fe03272 iOS keyboard accessory bar (global-theme + dialog-fullscreen-markdown)
- 309670db3 ShortSyntaxEffects undefined guard
- 667a7986f Dropbox PKCE auth comment/behavior

* fix(electron): restore electron + e2e work undone by 0e9218bd68

Commit 0e9218bd68 silently reverted the following electron/e2e work.
Files already re-fixed by later master commits are left as-is:
- e2e/tests/sync/supersync-archive-conflict.spec.ts (de33234976 + 191d129ff3)

Restored:
- e8a3e156eb fix(electron): Linux autostart IDB backing-store recovery
  (re-adds electron/clear-stale-idb-locks.ts + start-app.ts wiring)
- 5ce78a5b63 fix(electron): macOS Cmd+Q / Dock > Quit hang
  (setIsQuiting + before-quit delegate to close-handler)
- 46e0fa2d01 fix(sync): FILE_SYNC_LIST_FILES IPC contract
  (electronAPI.d.ts + local-file-sync + preload + ipc-events)
- ea1ef16307 fix(android): session-only SAF permissions on OEM devices
- 8865dc0a50 test(e2e): supersync parallel-worker stampede guard
  (SUPERSYNC_SERVER_HEALTHY env-var fallback + goto retry loop)
- af7c7687e2 test(e2e): block WS-triggered downloads in non-WS specs
- 265b44db5d test(e2e): premature waitForURL on daily-summary
  (this is literally the fix the bad commit's message claimed to add)

Conflict resolutions:
- e2e/utils/supersync-helpers.ts: kept the refined getDoneTaskElement
  checks from d64014d086 (later than c558bcab5e) while restoring the
  goto retry loop from 8865dc0a50.
- electron/start-app.ts: unioned imports (setIsQuiting +
  clearStaleLevelDbLocks from theirs, fs from ours).

* fix(sync): restore sync-core work undone by 0e9218bd68

Commit 0e9218bd68 silently reverted parts of several sync fixes. Most
sync-core reverts have already been re-addressed differently on master
by later commits (1f5184f6e7, 05cd875dd6, 09f5ced2c9, 7df43358ab,
d9158d6adb, 32dbc95ed9, 8c3b08e016, f89fe1ebc3) — those files are
intentionally left untouched to avoid reverting master's newer work.

This PR restores only the pieces that are genuinely still missing:

- e8a3e156eb fix(electron): IDB backing-store autoreload (in-app piece)
  operation-log-hydrator.service.ts + .spec.ts (the electron/clear-
  stale-idb-locks.ts piece was restored in the prior commit)

Plus three low-risk documentation/cleanup restorations:
- operation-sync.util.ts — add "Nextcloud" to isFileBasedProvider JSDoc
- dropbox.ts — restore improved _getRedirectUri JSDoc (667a7986fb)
- dialog-get-and-enter-auth-code.component.ts — restore isNativePlatform
  comment explaining why manual code entry flow is used (667a7986fb)
- file-adapter.interface.ts — remove stray "// NEW" comment (46e0fa2d01)

Intentionally NOT restored (master's newer work covers or supersedes):
- sync-trigger.service.ts / sync.effects.ts (05cd875dd6)
- sync-wrapper.service.ts (1f5184f6e7)
- sync-errors.ts (1f5184f6e7 re-added LegacySyncFormatDetectedError)
- file-based-sync-adapter.service.ts + spec (1f5184f6e7 + d9158d6adb)
- file-based-sync.types.ts (1f5184f6e7)
- operation-log.const.ts (32dbc95ed9 bumped IDB_OPEN_RETRIES to 5)
- dialog-sync-initial-cfg.component.ts (f89fe1ebc3)
2026-04-20 12:04:38 +02:00
Symon Baikov
3c75b527cd
fix(electron): recreate tray indicator before minimize to tray (#7072)
* fix(electron): recreate tray indicator before minimize to tray

* fix(electron): handle missing tray indicator gracefully
2026-04-18 22:05:16 +02:00
Leandro Marques
179700ccda
chore: update electron to v41.x (#7097)
* chore: update electron to v41.1.1

* feat(start-app): clear GPU cache on Electron version change for Linux

* fix(window-decorators): disable custom window title bar for GNOME

This fixes some issues when moving and resizing the window

* refactor: Migrate url.format() (DEP0116) to file:// path approach

* refactor(start-app): remove deprecated protocol.registerFileProtocol in start-app.ts

* feat(electron-builder): update gnome content snap to gnome-42-2204 for improved compatibility and update flatpak permissions

* fix(window-decorators): improve handling of custom window title bar for GNOME

* feat(start-app): implement fallback to X11 in Snap if gnome-42-2204 runtime is unavailable

* chore: update electron to v41.1.1

* chore(package-lock): remove unused dependencies from package-lock.json

* fix(electron): move snap ozone-platform switch before app ready event

app.commandLine.appendSwitch() must be called before Chromium
initializes — after the ready event fires the GPU backend is already
running and the switch is a no-op. Move the Snap X11 fallback (defense-
in-depth for missing gnome-42-2204 runtime) to run synchronously at
startup, alongside the existing gtk-version and speech-dispatcher
switches.

* fix(electron): align IS_GNOME_DESKTOP detection with preload.ts logic

The original implementation only matched Ubuntu's GNOME session
(XDG_CURRENT_DESKTOP contains both 'gnome' AND 'ubuntu'), missing plain
GNOME on Fedora, Arch, etc. The preload.ts isGnomeDesktop() already
used the correct approach: check four environment variables with OR
logic. Align common.const.ts to match, preventing a split-brain where
the main process and renderer disagree on whether the user is on GNOME
— which would produce no title bar at all on non-Ubuntu GNOME desktops.

* fix(electron): restore v41 bump lost in merge and gate title-bar toggle

- Re-apply electron 41.2.0 + minimatch 10.2.5 override (master's 0e9218bd
  reverted the dependabot bump back to 37.10.3 while this branch's
  merge-base still contained 41.2.0, so the pre-merge diff was empty).
- Regenerate root package-lock.json accordingly.
- Drop unrelated esbuild additions from plugin-dev sub-lockfiles.
- misc-settings-form: gate isUseCustomWindowTitleBar on IS_ELECTRON &&
  !IS_GNOME_DESKTOP so the toggle does not appear in the web/PWA build.

---------

Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-04-17 18:12:43 +02:00
Johannes Millan
8c3b08e016 fix(sync): add copy-URL fallback for Dropbox auth dialog (#7139)
The "Get Authorization Code" button silently fails on some Linux
packagings (Flatpak, AUR) because shell.openExternal() can reject
without visible feedback — the wasOpened boolean check in
openUrlInBrowser has been dead code since the call was migrated from
shell.openPath to shell.openExternal (which returns Promise<void>).

- Add a "Copy URL" button to the auth dialog as a reliable fallback
  users can paste into a manually-opened browser.
- Replace the dead wasOpened check with a .catch() that logs the
  rejection reason, so future portal failures surface in electron logs.
- Add regression tests documenting the PKCE verifier/challenge
  invariants that make stale auth codes fail with "invalid code
  verifier" when the dialog is reopened.
2026-04-16 19:47:52 +02:00
Johannes Millan
0e9218bd68 fix(sync): handle data validation errors and improve client ID management
- Separate JsonParseError and SyncDataCorruptedError handlers in sync wrapper
- Handle corrupted remote data gracefully instead of throwing
- Add getOrGenerateClientId() as unified entry point, eliminating dual injection
  of ClientIdService + CLIENT_ID_PROVIDER in snapshot-upload, file-based-encryption,
  and sync-hydration services
- Use crypto.getRandomValues() instead of Math.random() for client ID generation
- Warn user when stored client ID is invalid and must be regenerated
- Fix flaky e2e supersync tests (premature waitForURL match on daily-summary URL)
2026-04-16 17:41:39 +02:00
Johannes Millan
5ce78a5b63 fix(electron): prevent app hang on macOS native quit (Cmd+Q, Dock > Quit)
On macOS, native quit fires before-quit BEFORE window close events. The
before-quit handler was calling ipcMain.removeAllListeners(), which destroyed
the BEFORE_CLOSE_DONE IPC listener. The close handler then sent NOTIFY_ON_CLOSE
to the renderer (for sync/finish-day callbacks), the renderer responded with
BEFORE_CLOSE_DONE, but the listener was gone — causing a permanent hang.

Fix: intercept before-quit when isQuiting=false and delegate to win.close(),
which re-enters the existing close handler and runs before-close callbacks
normally. Move ipcMain.removeAllListeners() to will-quit, which fires after
all windows are closed and all IPC flows are guaranteed complete.

Also improves close event log to include pending before-close handler IDs.
2026-04-15 18:17:57 +02:00
Johannes Millan
1ee9d7f566 refactor: rename overlay-indicator to task-widget
Rename the "overlay indicator" feature to "task widget" across the
entire codebase for clearer naming. Includes file renames, config key
migration, IPC event rename, and translation key updates.

Migration handles old persisted data from both the `overlayIndicator`
config key and the deprecated `misc.isOverlayIndicatorEnabled` field.
The `taskWidget` type is made optional in GlobalConfigState to prevent
Typia auto-fix from overwriting migrated values during upgrade.
2026-03-30 22:00:47 +02:00
Johannes Millan
25051d2899 fix(plugins): use loopback redirect and system browser for Google OAuth
Google's Desktop OAuth client requires loopback redirect URIs
(http://127.0.0.1:<port>) and blocks embedded webviews. This replaces
the custom URI scheme + BrowserWindow approach with a temporary loopback
HTTP server and shell.openExternal for the system browser.

- Add PLUGIN_OAUTH_PREPARE IPC to start loopback server and return port
- Open auth URL in system browser instead of Electron BrowserWindow
- Make getRedirectUri() async to support IPC port retrieval
- Validate OAuth config before starting loopback server to prevent leaks
- Force 200 status on OPTIONS preflight responses in CORS bypass
2026-03-26 17:43:04 +01:00
Johannes Millan
6faca760f0
fix: address review findings from daily changes (#6944)
* fix: address review findings from daily changes

- Add setPermissionCheckHandler alongside setPermissionRequestHandler
  for defense-in-depth in Electron (permission queries now also denied)
- Fix tagIds merge ordering in issue service: provider adapter tags are
  now merged with default tags instead of being silently overwritten
- Execute deleteTask action last in automations to prevent subsequent
  actions from failing on a deleted task
- Add unit tests for getTaskDefaults logic (TODAY_TAG filtering,
  defaultNote, tagIds merging, deduplication, context tags)
- Add test for deleteTask execution ordering in ActionExecutor

https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS

* refactor: revert YAGNI changes from review fixes

- Revert tagIds merge in issue.service.ts: no provider currently sets
  tagIds in getAddTaskData, so merging solves a hypothetical problem
- Revert deleteTask sort in action-executor: the automations feature is
  new and nobody has hit this edge case yet
- Remove tests for reverted behavior, keep tests for existing features
  (TODAY_TAG filtering, defaultNote, note override prevention)

https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-24 12:11:47 +01:00
Johannes Millan
caf85a1b57 fix(electron): enable webSecurity, add permission handler, improve cert logging
Enable webSecurity (same-origin policy) since CORS is already handled at
the session level via onBeforeSendHeaders and onHeadersReceived. Add
setPermissionRequestHandler to deny unnecessary permissions (webcam,
microphone, geolocation). Improve certificate-error logging with warn
level and URL context.
2026-03-23 10:52:43 +01:00
Johannes Millan
a118f65d54 refactor(electron): bundle preload script with esbuild to support sandbox mode
Bundle preload.ts into a single file so all local imports (e.g.
ipc-events.const) are inlined at build time. This allows removing
sandbox: false since the bundled preload only requires the built-in
electron module, which is allowed in sandboxed preloads.
2026-03-22 19:38:21 +01:00
Johannes Millan
815341d5e8 fix(electron): explicitly disable sandbox for preload script compatibility
The preload script uses require() for local modules which is not
supported in Electron's sandboxed preload environment (default since
Electron 20). This only affects Electron's preload API restrictions,
not Chromium's OS-level process sandbox which remains active.
2026-03-22 19:16:32 +01:00
Johannes Millan
6b9ef0dee2 feat(overlay): resizable responsive overlay with opacity and always-show
- Make overlay window resizable with persisted bounds via simpleStore
- Add new OverlayIndicatorConfig section (isEnabled, isAlwaysShow, opacity)
- Move setting from misc.isOverlayIndicatorEnabled to overlayIndicator
  with migration in reducer
- Add responsive CSS with scale variable (full/tiny modes)
- Add always-show mode that keeps overlay visible when main window is open
- Add opacity slider (10-100%) applied as CSS variable
- Consolidate overlay init into single updateOverlayEnabled path
- Remove dead code: updateOverlayTheme, setIgnoreMouseEvents, unused
  shortcut param
2026-03-20 21:36:30 +01:00
Johannes Millan
78ef3c39d5 fix(electron): always show app border unless in fullscreen
Previously the 1px border only appeared with the custom title bar
enabled. Now it shows for all Electron windows and is hidden during
fullscreen via IPC-driven body class toggling.
2026-03-10 18:57:49 +01:00
Johannes Millan
8d41a79150 fix(electron): address review feedback for keyboard focus fix
- Gate blur() to Windows only (not supported on Wayland, limited on macOS)
- Add setTimeout delay in ready-to-show to match showOrFocus pattern
- Add webContents.focus() in ready-to-show for renderer-level focus
- Add isDestroyed() guards in setTimeout callbacks
- Only restore focus on resume/unlock if window was visible before
  suspend/lock to avoid surfacing hidden/minimized windows
2026-03-01 13:03:01 +01:00
Johannes Millan
d29d5b1a24 fix(electron): restore keyboard focus on Windows after reboot
On Windows, BrowserWindow.show() can silently fail to acquire keyboard
focus after a system reboot (electron#20464). This leaves the window in
a "phantom focus" state where clicks work but typing does not.

- Add blur()+focus() cycle after show() in ready-to-show handler
- Add webContents.focus() in showOrFocus() delayed callback
- Add showOrFocus() call in resume/unlock-screen power monitor handlers

Fixes #6663
2026-03-01 12:54:13 +01:00
Johannes Millan
cba5ba3f12 fix: apply code review fixes across sync, electron, and issue panel
- Fix isLoading staying true after search results arrive in issue panel
- Use getPayloadKey() for correct entity key derivation in conflict resolution
- Update archive-wins comments/logs to reflect all op types, not just updates
- Add archive-wins unit tests for local/remote archive vs UPDATE/DELETE
- Tighten WebDAV archive E2E assertion to deterministic archive-wins check
- Add @deprecated JSDoc to legacy pfapi meta-model-ctrl.js
- Refactor wasMaximizedBeforeHide from exported let to getter/setter
2026-01-30 17:45:33 +01:00
Johannes Millan
b6de071636 fix(electron): remove duplicate lines in main-window close/minimize handlers 2026-01-30 17:06:47 +01:00
Garrett04
4167633a62
fix(window): restore maximized window state from startup/minimized/tray (#6268)
* fix(window): restore maximized window state from startup/minimized/tray

Changes:
Call `win.restore()` before `win.show()` to ensure the window returns to its previous state when restored from startup/minimized/tray.

Fixes #5466

* fix(window): add manual tracking of maximized window state before hide

Changes:
add wasMaximizedBeforeHide flag to manually track and handle maximized window state reliably across all platforms

* fix(window): add manual tracking of maximized window state before hide

Changes:
add wasMaximizedBeforeHide flag to manually track and handle maximized window state reliably across all platforms
2026-01-30 16:40:57 +01:00
Benjamin Hooper
5a2b675383
feat(ui): Desktop Full Screen Mode (F11) #5851 (#6183) 2026-01-26 13:22:32 +01:00
Johannes Millan
d578beb52b style(electron): make custom window title bar fully transparent 2026-01-21 20:45:52 +01:00
johannesjo
09d86d8afb fix(electron): resolve macOS app quit not responding
- Replace deprecated `selector:` properties with proper Electron `role:` in macOS menu
- Add standard macOS menu items (hide, hideOthers, unhide)
- Ensure before-close handlers always call setDone() to prevent app hanging
- Change sync error dialog from confirm() to alert() since result was ignored
2026-01-21 16:54:11 +01:00
Johannes Millan
52fd0dfc75 fix(electron): use includes() instead of in operator for hostname check
The `in` operator checks for array indices, not values, so the condition
was always false. This prevented User-Agent header removal for GitHub,
Office365, and Outlook requests.
2025-12-15 10:02:13 +01:00
Johannes Millan
a3d65e021c fix(electron): improve window controls overlay for Windows/Linux (#5713)
- Use CSS env(titlebar-area-width) for dynamic DPI-aware spacing
- Increase fallback width from 96px to 140px to prevent button overlap
- Add theme-aware semi-transparent background to window controls
2025-12-12 19:00:12 +01:00
johannesjo
eefbc7135a fix(electron): sync title bar button colors with app theme
Update window control buttons (minimize, maximize, close) to match
the app's dark/light theme setting instead of always using white.

Fixes #5676
2025-12-07 09:52:20 +01:00
Johannes Millan
c5625de6f1 feat(customWindowTitleBar): add sexy custom window title bar <3 2025-12-02 13:30:36 +01:00
Johannes Millan
f13ad58e9d fix: minimize to tray not restoring #5581
# Conflicts:
#	electron/ipc-handler.ts
2025-11-28 18:51:15 +01:00
Johannes Millan
67337684e6 feat: change window title for dev 2025-11-21 11:47:25 +01:00
Johannes Millan
c0453bc708 build: change window title for dev 2025-11-21 11:47:25 +01:00
Johannes Millan
6350a7249f fix: app not closing on MacOS
Closes #5327
2025-10-23 15:12:12 +02:00
Johannes Millan
911e82bea5 fix: spell checker phoning home #5314 2025-10-19 11:01:20 +02:00
Johannes Millan
c23788ab79 fix: improve emoji detection and remove unnecessary code
- Fix regex pattern inconsistency between isEmoji and extractFirstEmoji functions
- Remove redundant conditional logic in icon-input component
- Add proper validation to paste handler for consistent emoji handling
- Remove unused side-nav-item component files
- Revert unnecessary type assertions in main-window.ts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 17:56:57 +02:00
Harshita
3696d62fba fix: properly handle single emoji as project icon 2025-09-20 20:14:06 +05:30
Johannes Millan
7417cd9b65 fix(mentions): resolve TypeScript compilation errors
- Remove duplicate MentionItem interface definition from mention-config.ts
- Fix TemplateRef type to match Angular's expected template context structure
- Update type casting for TagCopy and ProjectCopy arrays in add-task-bar component
- Remove unused CustomEvent interface from mention directive
- Fix syntax error in electron main-window.ts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

# Conflicts:
#	electron/main-window.ts
2025-09-16 18:05:32 +02:00
burned65
56af1fa748 fix: fixed URL sanitization 2025-09-16 17:47:33 +02:00
Burned65
e731d1af44 fix: added missing ) 2025-09-16 15:56:16 +02:00
Burned65
e74fe601e3
added User-Agent Header to outlook.live.com requests 2025-09-15 17:00:16 +02:00
Johannes Millan
34ac3dd757 refactor: improve typing 2 2025-08-12 15:27:48 +02:00
Johann Janosch
0fbb25fd10 fix: Send User-Agent to office365.com as it appearently needs it since a
few weeks #4677
2025-07-30 12:59:08 +02:00
Johannes Millan
c08c40140f fix: overlay-indicator.ts not being cleaned up 2025-06-29 21:00:44 +02:00
Johannes Millan
fcf5e5fe30 feat: improve shutdown cleanup 2025-06-29 17:31:28 +02:00