Skip to content

[pull] main from Stirling-Tools:main - #333

Merged
pull[bot] merged 2 commits into
5474312:mainfrom
Stirling-Tools:main
Sep 4, 2026
Merged

[pull] main from Stirling-Tools:main#333
pull[bot] merged 2 commits into
5474312:mainfrom
Stirling-Tools:main

Conversation

@pull

@pull pull Bot commented Sep 4, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

EthanHealy01 and others added 2 commits September 3, 2026 19:40
…#7762)

Review Flow PR 5b — the second half of #7479 (left open for reference),
stacked on #7761. That PR ranks a row's actions and gives the server a
resolve transition; this one adds the buttons that fix things: **Retry**
and **Decrypt and retry**, for editor failures and policy failures
alike. Merging both reproduces #7479's diff byte-for-byte — this
branch's tree is identical to #7479's head.

## What's added

**The retry stash** (`notificationRetry.ts`). When a tool run fails,
`useToolOperation` stashes what a retry needs — endpoint, parameters,
file ids — in its own IndexedDB database, keyed on the failing document.
Capped at 25 records, oldest evicted first. Password-shaped fields are
stripped at any depth on the way in, and the walk is depth-bounded so a
pathological or cyclic object fails closed rather than storing a subtree
it never examined. `hasLocalFile` moves in here from
`localFilePresence`, which this replaces.

**`Retry` on an editor failure** opens the failed tool with the document
selected, so the user sees the settings before it runs again.

**`Decrypt and retry` on an editor failure** opens the same unlock modal
the app uses for a locked upload. On submit it re-runs the stashed
operation with the password added, adopts the result into the workbench,
and reports the row resolved.

**`Retry` and `Decrypt and retry` on a policy failure.** The unlock goes
through `POST /api/v1/security/remove-password`, the result is adopted,
and the stored policy re-runs on it server-side. `RetryTarget` is a
discriminated union: the tool arm comes from the stash, the policy arm
is derived from the notification itself (`policyId` plus the document
reference), so no stash is needed for a policy failure.

**Run registration.** A policy re-run is recorded with the run store, so
it polls to terminal, imports its output honouring the policy's
`outputMode`, and continues the rest of the upload chain rather than
running one policy in isolation. The chain-eligibility ordering moves
into `uploadChain.ts`, shared between the auto-run and the retry.

**An upload's chain holds back until its unlock prompt is answered**
(`pendingUnlocks.ts`), so skipping the prompt is what creates the
failure, and answering it never races the policy run.

## Behaviour

- The unlocked document **versions the encrypted original in place**,
not a second copy beside it. Consumed rather than deleted, so the swap
cannot close the incident as a file removal.
- Exactly one policy run starts per click. Adoption is marked
`derivedFromTool` so the upload auto-run does not also fire on it, which
would bill the customer twice.
- Failures stop the sequence where they occur. A wrong password reports
in the unlock modal and nothing else runs. A failed adoption neither
re-runs nor resolves. A refused re-run leaves the document adopted and
does not resolve.
- **A re-run whose output cannot be delivered leaves the row open.** If
the local policy cache cannot place the policy, the run still fires but
nothing polls it, so the row stays open and says so rather than closing
on a result that never arrives.
- The password reaches the network from one place and is never stored,
logged, or put in an error message.
- A failure this browser did not report has no stash entry, so its Retry
is simply not offered on other devices.

## Not included

Unattended failures (folder, S3, webhook) still cannot be retried: no
browser holds the document. Those actions stay disabled with a reason.
Re-running from the source needs a ledger requeue transition that does
not exist yet.

`ToolType.custom` tools (Convert, OCR) have no single endpoint to
re-submit to, so they get no Retry.

## How to test

Needs a proprietary or SaaS build with login enabled, and a stored
policy that will fail on a locked document. `task dev:all`, then sign
in.

1. **Create the failure.** Add a password-protected PDF to the editor
and choose **Skip for now**. The upload's policy run fails on it.
2. **Open the bell** once the badge appears. The row's primary button is
now **Decrypt and retry** — on #7761 alone it was View file, because the
slot ranking arrived there but the handler arrives here.
3. **Press it.** The unlock modal opens. Enter the wrong password first:
the modal shows the server's message and stays open.
4. **Enter the correct password.** The unlocked document replaces the
encrypted original in the workbench (versioned, not deleted), the policy
re-runs on it, and the row leaves the list.
5. **Check the run is tracked.** The activity feed shows the re-run
progressing to completion and its output arriving in the workbench,
rather than a run that never reports.
6. **Confirm only one run per click.** In DevTools there is exactly one
`POST /api/v1/policies/{id}/run` for the retry. Two would mean the
adopted document also triggered the upload policy.
7. **Confirm nothing leaks the password.** Search the request log and
IndexedDB (`stirling-pdf-retry`) for what you typed. It should appear
only in the one unlock request body.
8. **Editor retry.** Fail a plain tool run (rotate a corrupted file),
open the bell, press **Retry**: the failed tool opens with that document
selected.
9. **Confirm the stash strips secrets.** After a remove-password
failure, inspect IndexedDB `stirling-pdf-retry`: the stashed parameters
contain no password-shaped field.

## Migration

None.
## What this changes

- **Big folders don't lag.** The file list only draws the rows you can
actually see, so a folder with thousands of files feels the same as one
with ten. Selecting a file redraws that file, not the whole folder.

- **The 500-file limit is gone.** A mounted disk folder used to list
only its 500 newest files and quietly hide the rest. You now see
everything in it.

- **Back and the breadcrumbs work.** Walking into folders now leaves
proper history, so Back steps up one folder. Before, every folder
overwrote the same history entry, so Back dumped you out of the library
entirely.

- **Deep links to a folder work.** Opening a link to a folder that
hadn't finished loading used to bounce you to the top of the library. It
now waits for the folder to appear.

- **"New folder" is one button.** The version on an empty folder was a
different button, with a different name, that guessed where to put the
folder and greyed itself out when it couldn't. It's now the same menu as
the one in the top right.

- **"Local" in the left bar is just a filter.** Clicking it filters the
list by source. It used to switch you into a separate view with its own
rules for what counted as a file, its own empty screen, and its own
exceptions everywhere folders were involved.

- **Folders obey the source filter.** Picking Cloud or Local now filters
folders too, not just files, so mounted folders stop appearing under
every setting.

- **Opening a file that's already open** takes you to it, instead of
trying to add it a second time.

- **Opening a cloud file keeps it in its folder** instead of dropping it
at the top of the library.
@pull pull Bot locked and limited conversation to collaborators Sep 4, 2026
@pull pull Bot added the ⤵️ pull label Sep 4, 2026
@pull
pull Bot merged commit 153da23 into 5474312:main Sep 4, 2026
7 of 8 checks passed
@github-actions github-actions Bot added Front End Issues or pull requests related to front-end development Java Pull requests that update Java code Translation Issues or pull requests related to translation Test Testing-related issues or pull requests labels Sep 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

⤵️ pull Front End Issues or pull requests related to front-end development Java Pull requests that update Java code Test Testing-related issues or pull requests Translation Issues or pull requests related to translation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants