Skip to content

Rotate remote stacks via the server#83

Open
sjg20 wants to merge 3 commits into
masterfrom
remote-transform
Open

Rotate remote stacks via the server#83
sjg20 wants to merge 3 commits into
masterfrom
remote-transform

Conversation

@sjg20

@sjg20 sjg20 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Remote stacks open on the client as Fileother stubs (the client can't reach their pages), so rotating or flipping a remote stack had nowhere to run — transformPage() hit not_impl(). The server already links the file code, so it's the natural place to do the transform. This makes remote rotation work end to end.

ServerPOST /v1/repos/{repo}/stacks/{path}/transform, body {page, op} (page 1-based, below 1 means every page; op is rotate90/rotate180/rotate270/hflip/vflip). It resolves the file, loads it and calls File::transformPage() — the same code the GUI uses locally. Auth required, per-user repo allowlist enforced, path checked for traversal. The file's mtime changes so cached thumbnails (keyed by mtime) miss and re-render. handleRequest() is restructured so POST routes other than login run after the auth check.

Client backendRemoteBackend::transformPage(repo, path, page, op) POSTs to it.

Desktop wiringopTransformPage() detects a stack whose desk has a RemoteBackend and dispatches there (single page and whole stack), then re-fetches the thumbnail and emits pageContentChanged(). Undo/redo go through the same path with the inverse op, so they reach the server for free. File::transformName()/transformFromName() are the single home for the wire op names, shared by client and server.

Tests — endpoint (rotate one/every page, check disk), error cases (unknown op, missing file, traversal), RemoteBackend round-trip, and testDesktopRemoteTransform which drives the whole path through a Desktopmodel against an in-process server and checks the disk file rotates then restores on undo. Full suite green (175).

🤖 Generated with Claude Code

sjg20 added 3 commits June 13, 2026 18:08
Remote stacks are opened on the client as Fileother stubs, since the
client cannot reach their pages directly, so rotating or flipping a
remote stack has nowhere to run.  The server already links the file
code and renders thumbnails from it, so it is the natural place to
transform a remote page.

Add POST /v1/repos/{repo}/stacks/{path}/transform.  The body is JSON
{page, op}: page is 1-based (a value below 1 means every page) and op
is one of rotate90/rotate180/rotate270/hflip/vflip.  The handler
resolves the file, loads it and calls File::transformPage(), the same
code the GUI uses locally.  Authentication is required, the per-user
repo allowlist is enforced and the path is checked for traversal.  The
file's mtime changes, so cached thumbnails (keyed by mtime) miss and
re-render with no explicit invalidation.

Restructure handleRequest() so POST routes other than login run after
the auth check rather than bypassing it.

testTransformEndpoint() rotates one page and every page and checks the
file on disk; testTransformEndpointErrors() covers an unknown op, a
missing file and a path-traversal attempt.

Co-developed-by: Claude Fable 5 <noreply@anthropic.com>
Give the client a way to rotate or flip a remote page by POSTing to
the server's new transform endpoint.  transformPage() takes the wire
op name (rotate90/rotate180/rotate270/hflip/vflip) so RemoteBackend
stays decoupled from file.h; the GUI maps File::e_transform to the
name.  page is 1-based, with a value below 1 meaning every page, and
the call blocks until the server responds, matching the other sync
methods.

testRemoteBackendTransform() rotates a page through RemoteBackend
against an in-process server and checks the file on disk turned, and
that an unknown op reports an error.

Co-developed-by: Claude Fable 5 <noreply@anthropic.com>
With the server transform endpoint in place, wire the desktop so
rotating or flipping a remote stack asks the server to do it instead
of failing.  opTransformPage() now detects a stack whose desk has a
RemoteBackend and, for both a single page and the whole stack, posts
to RemoteBackend::transformPage() rather than calling the local (stub)
File.  On success it re-fetches the stack's thumbnail from the server
and emits pageContentChanged(), so the grid and any open page view
refresh.  Undo and redo go through opTransformPage() with the inverse
op, so they reach the server the same way for free.

Add File::transformName()/transformFromName() as the single home for
the wire op names, used by both the client wiring and the server
handler (replacing the server's private copy).  Add
ERR_remote_transform_failed1 to surface a server-side failure.

testDesktopRemoteTransform() drives the whole path: it shows a remote
repo in a Desktopmodel, rotates a page via transformPage(), and checks
the file the server holds on disk turned, then that undo restores it.

Co-developed-by: Claude Fable 5 <noreply@anthropic.com>
@sjg20 sjg20 changed the title Server-side page transform for remote stacks Rotate remote stacks via the server Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant