Three new REEL_VARIANT branches for the marketing video pipeline:
- shorts: 9:16 portrait 1080x1920 for TikTok / YouTube Shorts /
Instagram Reels. Skips the side-panel drag beat (no horizontal room)
and tightens holds for portrait capture.
- keyboard: keyboard-first reel demonstrating SP shortcuts. Five beats
driven by real page.keyboard.press() so cause-and-effect is honest
(Shift+A capture, J/K navigate, F focus mode).
- mobile: 19.5:9 phone aspect 1080x2340 with hasTouch + isMobile UA.
Fixture installs a tap-ripple on touchstart/pointerdown in lieu of
the cursor highlight; tap-driven choreography.
Fixture gains a getVideoProfile() selector that returns the right
viewport, DPR, and touch flags per variant. Overlays grow new
primitives needed by the keyboard and mobile choreographies.
* refactor(sync): extract framework-agnostic sync types into @sp/sync-core
Stand up packages/sync-core/ as the new home for sync types and
constants that have no Angular/NgRx coupling. This is the thin first
slice of separating sync engine, configuration, and provider concerns
into distinct packages.
Files moved (sources now live in packages/sync-core/src/):
- core/operation.types.ts
- core/action-types.enum.ts
- core/lww-update-action-types.ts
- core/sync-state-corrupted.error.ts
- core/types/apply.types.ts
- sync-providers/provider.const.ts
- util/entity-key.util.ts
Original paths in src/app/op-log/ keep working as thin re-export stubs
so existing callers don't change. op-log/sync-exports.ts now sources
provider.const exports directly from @sp/sync-core.
Files with transitive Angular dependencies (encryption, sync-errors,
provider.interface, vector-clock util) stay in the app for now — moving
them requires introducing a logger port and is part of the next slice.
* refactor(sync): keep @sp/sync-core domain-agnostic
The first slice landed too much Super Productivity-specific content in
@sp/sync-core. The lib should expose generic sync primitives; the host
app supplies the SP-specific config.
Pulled out of the lib (now app-side only):
- ActionType enum (NgRx action strings for SP features)
- ENTITY_TYPES / EntityType union (SP domain entities)
- SyncImportReason union (SP import flows)
- RepairSummary / RepairPayload (SP repair shape)
- WrappedFullStatePayload + appDataComplete helpers (SP wire format)
- SyncProviderId / SyncStatus / ConflictReason / OAUTH_SYNC_PROVIDERS
/ REMOTE_FILE_CONTENT_PREFIX / PRIVATE_CFG_PREFIX (SP providers/keys)
- The @sp/shared-schema dep (also SP-coupled)
Generic-ized in the lib:
- Operation.actionType: string and Operation.entityType: string (lib
carries opaque strings; host narrows in app code)
- Operation.syncImportReason removed; app extends Operation with it
- VectorClock now defined locally as Record<string, number>
- LWW helpers replaced by createLwwUpdateActionTypeHelpers(entityTypes)
factory; the app instantiates it with SP's ENTITY_TYPES
- entity-key.util uses string for entityType
App stubs now redeclare the SP-narrowed Operation, EntityChange,
EntityConflict, ConflictResult, MultiEntityPayload, ApplyOperationsResult
on top of the lib generic types via Omit-and-extend, and re-host all the
SP-specific helpers (WrappedFullStatePayload, extractFullStateFromPayload,
assertValidFullStatePayload, RepairSummary, RepairPayload).
Also added @sp/sync-core to src/tsconfig.spec.json paths so the spec
build uses the source, not the dist (matching shared-schema).
* docs(sync): add @sp/sync-core extraction plan
Roadmap for carving the sync engine out of src/app/op-log/ into a
reusable, framework-agnostic AND domain-agnostic @sp/sync-core package
plus a sibling @sp/sync-providers.
Documents:
- The three-concern split (engine / config / providers) target
- The domain rule: nothing SP-specific lands in the lib (ActionType,
ENTITY_TYPES, SyncImportReason, RepairPayload, SyncProviderId, the
appDataComplete wire format, @sp/shared-schema all stay app-side)
- PR 1 (landed): generic primitives only; app stubs preserve every
pre-existing call site via Omit-and-extend
- PR 2: SyncLogger port + parameterize entity-registry
- PR 3a: pure algorithmic core (vector-clock client wrapper, conflict
detection, op validation, encryption, sync-errors) — needs only the
SyncLogger port
- PR 3b: orchestrators behind ports (OperationStorePort,
ActionDispatchPort, ConflictUiPort, SyncConfigPort) — the high-risk
step where the app/lib boundary becomes load-bearing
- PR 4: lift providers into @sp/sync-providers
- PR 5: ESLint boundary rule
* refactor(sync): address sync-core extraction review
* docs(sync): refine extraction plan follow-ups
---------
Co-authored-by: Claude <noreply@anthropic.com>
The "feat(video): Playwright-driven marketing reel pipeline" commit
1d52843c was rebased on a stale base and silently reverted unrelated
work landed earlier the same day. The follow-up 3acdcd47 only
restored Lines and Velvet themes; this commit restores the rest.
Restored:
- task.service.ts focusTaskById prefers in-panel instance again (#7120
mobile sub-task focus regression)
- Schedule responsive header: BREAKPOINTS.XS/XXS, WEEK_NR_SHORT
translation key, _isCompact/_isVeryCompact computeds
- Calendar visibility mat-menu form (fff1ee15) instead of the older
mat-chip-listbox bar
- import.page.ts no_dialog fallback + second-chance importCompletePromise
- sharp devDependency (build-store-assets.ts still imports it)
- Drop --disable-software-rasterizer from playwright.store-screenshots
config to match fdb84c0f's stated intent
Adds an end-to-end pipeline for generating the marketing reel via
Playwright, including tight/full variants, drag ghost, integrations
layout, animated stats, brand-color logos, fade-to-black scene cuts,
and a handover CLAUDE.md for the reel pipeline.
Iterates the store-screenshot pipeline to ship-ready quality. Squashed
from a series of capture/build/UX changes that all live in
e2e/store-screenshots and form a coherent set.
Pipeline UX
- Print master capture path via Playwright globalTeardown.
- Declare sharp as devDep (was imported by build-store-assets but
never listed) so a fresh install runs the build cleanly.
- Open dist/ folder when build finishes; opt out via
SP_SCREENSHOTS_NO_OPEN=1.
- Emit dist/screenshots/_preview.html contact sheet for one-click QA
across every per-store layout.
Capture content
- New slot 00 hero across desktop / mobile / tablet specs:
showMarketingOverlay paints a gradient caption strip on top of the
live app. Position is orientation-aware (bottom for landscape, top
for portrait). Copy lives in marketing-copy.ts as a single source
of truth.
- Desktop slot 05 captures the running focus timer instead of the
duration picker (skip the rocket countdown via clock.runFor).
- Desktop slot 07 = plain dark project view (no wallpaper) instead
of catppuccin; slot 08 = desktop planner.
- Mobile slots 02 and 04 use signal-based planner expansion (the
component is gesture-only, so flip isExpanded via ng.getComponent).
- Side nav collapsed for desktop slots 01 (schedule day-panel) and
04 (notes panel) so the right panel can breathe.
- Mobile hides the per-task play column via
appFeatures.isTimeTrackingEnabled.
- Seed: drop Morning yoga (the only top-level done task on today),
flip the remaining done subtask back to undone, trim the PR
review tag chips down to the two EM tags that drive Eisenhower.
Viewports
- desktopMaster: 1280x800 CSS at 2x -> 2560x1600 (smaller MAS Retina
size = more apparent zoom than the prior 1440x900 baseline).
- androidPhone: 412x915 CSS at 3x -> 1236x2745, matching modern
flagships (Pixel 7/8, Galaxy S22+).
- Tablet rotations: 7" -> landscape, 10" -> portrait. android7Tablet
moves from PHONE_VIEWPORTS to TABLET_VIEWPORTS.
Test infra
- Bump per-test timeout to 8 minutes for multi-locale single-session
specs (12+ captures per locale overran the 180s default on slow
viewports).
- Scope LOCALES to ['en'] for now until German strings catch up.
- ImportPage race tolerates slow imports without an encryption
dialog: catch the 15s waitFor rejection so the 60s import-complete
promise is the real ceiling. A cold dev server would otherwise
abort here at 15s.
Fold the iterative work from this session into one commit:
- Single-session capture across locales / themes / customTheme. Drives
variant switches via NgRx dispatch through `__e2eTestHelpers.store`
(re-enabled for non-prod/non-stage builds in src/main.ts), so one
Chromium / Electron session covers every desktop and mobile permutation
without relaunching the app or re-importing the seed. Replaces the
per-(locale,theme) split specs with consolidated `desktop/all.spec.ts`
and `mobile/all.spec.ts`.
- Dedicated tablet spec (`scenarios/tablet/all.spec.ts`) for the iPad 13"
and Android 10" tablet viewports, which render SP's desktop layout (≥
768 mobile-breakpoint) but on a narrower / taller canvas than
desktopMaster. Added PHONE_VIEWPORTS / TABLET_VIEWPORTS in matrix.ts and
routed each viewport class to the right spec via testMatch in the
playwright config. Tablet scenes are panel-free and hover-free so they
fit a 960/1032-wide canvas under emulated touch.
- Helpers for in-session theme / locale / customTheme flips
(`applyTheme`, `applyLocale`, `applyCustomTheme`). screenshotMaster
reads the live theme from `localStorage.DARK_MODE` and the live locale
from `window.__spCurrentLocale` so captures land in the correct
`<locale>/<theme>/` subdir.
- Suppress Material tooltips via injected CSS, park the cursor at (0, 0)
before each capture, and gracefully fall back to `page.screenshot()`
when OS-level capture fails (e.g. macOS Screen Recording permission
missing). Switch the Electron launch to `NODE_ENV=PROD` so DevTools
doesn't auto-open on dom-ready.
- Catppuccin scene now navigates to a project view
(`desktop-07-project-catppuccin`) so the custom palette reads against
the project primary, not a wallpaper. Seed builder no longer forces a
bg image onto project themes — only tag themes get one, and the
"Darken/lighten background image for better contrast" slider
(`backgroundOverlayOpacity`) defaults to 80 (was 20). Override via
`SP_SCREENSHOT_BG_OVERLAY_OPACITY` (0–99).
- Seed polish: soften EM_URGENT/EM_IMPORTANT colors, drop the '@' prefix
from tag titles, remove tag-waiting, trim noisy urgent/important tags
from most tasks, give the deep-work tag a hue distinct from work and
open source, flip `isConfirmBeforeExitWithoutFinishDay` to false so
Electron closes cleanly between runs, and enable the bg tint on the
TODAY tag (was disabled by default).
- matrix.ts: rename `msstore` → `microsoft-store` output to avoid
confusion with `macappstore`; wire flathub rule sourcing from the
Electron pipeline; add `maxBytes` for Snap (2 MB JPEG re-encode).
- Add `npm run screenshots:electron` umbrella script that chains
`screenshots:capture:electron && screenshots:build` so the macappstore
/ flathub deliverables land in `dist/screenshots/` in one go.
Playwright-driven pipeline that captures recognizable app states across all
target storefront viewports, locales, and themes from a single curated seed
dataset. Web Chromium pipeline feeds MS Store / Snap / Play / iOS / F-Droid
/ web; an Electron pipeline (with OS-level region capture for native window
chrome) feeds Mac App Store and is wired for Flathub.
Five grouped spec files capture multiple scenarios per (locale, theme,
customTheme) tuple in one session; transient UI state is reset between
scenes via page.reload() rather than relaunching contexts.
Outputs:
.tmp/screenshots/_master/<viewport>/<locale>/<theme>/<scenario>/...
.tmp/screenshots/_master_electron/...
dist/screenshots/{macappstore,msstore,snap,web,ios,play,fdroid}/...
Run:
npm run screenshots # web pipeline + per-store layout
npm run screenshots:capture:electron # Mac App Store / Flathub source
Paired migration:
- stylelint 16.26 -> 17.9
- stylelint-config-recommended-scss 14.1 -> 17.0
- @csstools/stylelint-formatter-github 1.0 -> 2.0 (requires stylelint 17)
Fix the 26 violations from new deprecation rules:
- 'word-wrap' replaced with 'overflow-wrap' (autofix; word-wrap is a
legacy alias in CSS3, only matters that stylelint now flags it)
- 'word-break: break-word' (deprecated keyword) replaced with
'overflow-wrap: anywhere' (the spec-defined equivalent), with stale
duplicate 'overflow-wrap' declarations consolidated
- cross-env 7→10 (CLI-compatible, Node 20+ engine — already met)
- eslint 9→10 + @eslint/js 9→10 (all active plugins support v10;
fix local rule require-hydration-guard to use context.sourceCode
instead of removed context.getSourceCode())
- jasmine-core 5→6 (forbidDuplicateNames default flipped; no duplicates
in our suite — verified by running the full test:once)
- typia 11→12 (public API surface unchanged; validation specs pass)
Lint, build and the typia/auto-fix specs verified green. The 5 pre-existing
failures in immediate-upload.service.spec.ts are unrelated — also fail on
master with the same package.json that has been shipping.
Deferred from this round: stylelint 16→17 (paired migration with
@csstools/stylelint-formatter-github 1→2, separate work),
electron-dl 3→4 (forces full electron-main CJS→ESM migration),
marked 17→18 (ngx-markdown@21.2.0 peer-locks marked at ^17).
Patch/minor updates across tooling and runtime:
electron 41.2→41.4, electron-builder 26.7→26.8, prettier 3.7→3.8,
playwright 1.57→1.59, typescript-eslint 8.52→8.59, karma 6.4.2→6.4.4,
core-js 3.47→3.49, nanoid 5.1.6→5.1.11, dotenv 17.3→17.4, glob 13.0→13.0.6,
fs-extra 11.3→11.3.4, tslib 2.7→2.8, baseline-browser-mapping 2.9→2.10,
plus type defs and native binaries (@lmdb/*, @rollup/*).
Build, lint and a sample unit test all pass.
* ci(electron): verify packaged app.asar and smoke-test launch
Adds coverage for the gap that let #7320 ship: CI built electron TS
and ran electron-builder on release, but never exercised the packaged
binary. A stray relative import reaching out of electron/** was
compiled by tsc into src/app/util/*.js, fell outside the files glob
in electron-builder.yaml, and was missing from app.asar — the main
process crashed on launch for every 18.2.7 user.
Two new checks, both running on ubuntu-latest:
1. tools/verify-electron-requires.js extracts app.asar and re-resolves
every relative require() under electron/** against the packaged
tree. Runs on every PR that touches electron/**, electron-builder
config, package.json, or the workflow itself. ~10s after the build.
2. A launch-under-xvfb smoke test starts the packaged binary, waits
30s for a crash, and greps stderr for 'Cannot find module' /
'Uncaught Exception'. Runs on push to master, release tags, and
manual dispatch (not every PR — needs xvfb setup + idle wait).
Exposed as npm run electron:verify-asar for local use after dist.
* ci(electron): harden smoke workflow and verify script from review
Review feedback on the previous commit surfaced a handful of real
defects. Addressed here:
verify-electron-requires.js
- Guard resolved paths against escaping the extracted asar tree.
Without this, a relative require with enough `..` climbs above the
temp dir and Node's resolver hits the host filesystem, masking a
genuinely missing module behind a stray file on the CI runner.
- Walk .cjs and .mjs files too. electron/simple-store.test.cjs ships
via the `electron/**/*` glob and was being skipped.
- Move cleanup out of the path where `process.exit(1)` runs inside a
`try/finally` (synchronous exit does not guarantee `finally`), so
the temp dir is reliably removed.
- Code comment noting that esbuild-bundled preload.js is opaque to
this walker — that coverage comes from the launch smoke test.
electron-smoke.yml
- Broaden pull_request paths filter. The previous filter only matched
electron/**, which is exactly the wrong answer: #7320's root cause
was a file under src/app/util/ that electron/ imported. Now uses a
negative list — docs, translations, android/, ios/, other workflows.
- Explicit Xvfb screen geometry (`-screen 0 1280x720x24`) and
`--disable-dev-shm-usage` on the Electron side. Both known CI
flake preventers.
- Expanded crash-marker regex: SIGSEGV, Segmentation fault,
TypeError:, ReferenceError:, FATAL ERROR, Check failed. Also scan
the log during the liveness loop, not just at the end — catches
main-process exceptions that get logged without killing the
process.
- Move the launch log under .tmp/smoke/ so upload-artifact@v7 reliably
finds it on failure; /tmp paths are fragile across runner images.
- Sweep stray electron worker processes on teardown via pkill.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Follow-up to #7297: the simple-store regression test only ran via
local invocation. Add a test:electron npm script and run it in the
CI Tests job so simple-store fixes stay regression-guarded.
* test(e2e): update Show/hide task panel button label
The TOGGLE_DETAIL_PANEL translation was renamed from "Show/Hide
additional info" to "Show/hide task panel" in dd789d2, but e2e
selectors still referenced the old string, causing every test that
opens the task detail panel to time out.
https://claude.ai/code/session_011mX4Pr24S42svmA5j7fRux
* 18.2.1
---------
Co-authored-by: Claude <noreply@anthropic.com>
* 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>
- 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)
When a full-state op (SYNC_IMPORT/BACKUP_IMPORT) arrived from another
client, mergeRemoteOpClocks reset the local clock to a "minimal" form
but only preserved the current client's counter from the incoming op's
clock. If the current client had issued ops (e.g. GLOBAL_CONFIG) not
reflected in the incoming full-state op's clock, its counter was dropped,
causing subsequent ops to reuse the same counter value. Downstream clients
then saw these ops as EQUAL (duplicate) and skipped them silently.
Fix: take max(mergedClock[clientId], currentClock[clientId]) when
rebuilding the clock after a full-state op reset.
Also add __SP_E2E_BLOCK_WS_DOWNLOAD flag to WsTriggeredDownloadService
to allow E2E tests to block automatic WS-triggered downloads during
concurrent conflict scenarios.
Fix archive conflict test by blocking WS downloads on Client A during
the concurrent edit phase so it doesn't auto-receive B's rename via
WebSocket before archiving (restoring the intended conflict scenario).
Fix LWW singleton test to assert convergence rather than specific winner.
Fix renameTask helper to avoid Playwright/Angular re-render races.
Fix shepherd.js import paths that broke the Angular dev server build.