Commit Graph
650 Commits
Author SHA1 Message Date
Anthony StirlingandGitHub 611d7577a3 Version bump to 2.10.0 (#6168) 2026-04-23 11:54:47 +01:00
Anthony StirlingandGitHub 1d5b47fa9b fix edge translation bug (#6158) 2026-04-22 16:31:43 +01:00
Anthony StirlingandGitHub d71a2c3d81 FixThumbnailRegeneration (#6134) 2026-04-22 14:33:38 +01:00
LudyandGitHub 97e2dc2c68 chore(frontend): replace platform-specific update:minor script with cross-platform Node.js implementation (#6155) 2026-04-22 11:50:01 +01:00
James BruntonandGitHub 2a856fbc19 Allow chat history to be sent to AI engine (#6128)
# Description of Changes
Add an extra parameter to every agent to receive the conversation
history in addition to the current message. This will make it possible
to answer followup questions from the AI without needing to give full
context in your message.
2026-04-21 15:03:10 +00:00
66a75b1f28 Add pixel comparison mode to Compare tool (#6109)
Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
2026-04-20 19:31:07 +01:00
e5767ed58b Change AI engine to execute tools in Java instead of on frontend (#6116)
# Description of Changes
Redesign AI engine so that it autogenerates the `tool_models.py` file
from the OpenAPI spec so the Python has access to the Java API
parameters and the full list of Java tools that it can run. CI ensures
that whenever someone modifies a tool endpoint that the AI enigne tool
models get updated as well (the dev gets told to run `task
engine:tool-models`).

There's loads of advantages to having the Java be the one that actually
executes the tools, rather than the frontend as it was previously set up
to theoretically use:
- The AI gets much better descriptions of the params from the API docs
- It'll be usable headless in the future so a Java daemon could run to
execute ops on files in a folder without the need for the UI to run
- The Java already has all the logic it needs to execute the tools 
- We don't need to parse the TypeScript to find the API (which is hard
because the TS wasn't designed to be computer-read to extract the API)

I've also hooked up the prototype frontend to ensure it's working
properly, and have built it in a way that all the tool names can be
translated properly, which was always an issue with previous prototypes
of this.

---------

Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
2026-04-20 15:57:11 +01:00
James BruntonandGitHub cc9650e7a3 Fix any type usage in desktop/ (#6033)
# Description of Changes
Follow on from #5949, expanding any type usage ban to the `desktop/`
folder

Also gets rid of a bunch of really verbose desktop logging that I don't
think we really need anymore (or ever needed tbh, most of it doesn't
make sense) because it was using a bunch of `any` typing and wasn't
worth fixing.
2026-04-20 12:42:38 +00:00
Anthony StirlingandGitHub 4e7f435016 Swap thumbnail rendering from PDF.js to PDFium (#6135) 2026-04-20 12:53:56 +01:00
Anthony StirlingandGitHub b4b196556d Fix compare tool file selection and other files improvements (#6133) 2026-04-20 12:53:37 +01:00
Anthony StirlingandGitHub 3eefabd44b enable AppImage and rpm distrobutions (#6127) 2026-04-17 22:19:16 +01:00
EthanHealy01andGitHub bad92a9eae Chore/remove usage of mantine color scheme (#6108)
Remove instances of `colorScheme === "dark" ?` in the app and rely on
the theme.css' light and dark variables instead.
2026-04-17 14:29:37 +01:00
James BruntonandGitHub 8ab060a4be Prettier 2: Electric Boogaloo (#6113)
# Description of Changes
When I added Prettier formatting in #6052, my aim was to use just the
default settings in Prettier. Turns out, Prettier looks _really hard_
for any config files if it's not explicitly given one, which means that
if a developer has some sort of Prettier config file lying around on
their system, Prettier might find it and use it. Also, Prettier changes
its defaults based on stuff in `.editorconfig` without any good way of
disabling that behaviour explicitly in its config file.

To solve both of these issues, I've introduced a `.prettierrc` file
which sets Prettier's defaults explicitly, and then reformatted all our
code _again_ in Prettier's actual default settings. This should achieve
the aim of #6052 and remove the possibility for it breaking on different
dev computers.
2026-04-17 09:50:16 +00:00
James BruntonandGitHub 688f7f2013 Add streaming to Engine orchestrator (#6094)
# Description of Changes
Adds a streaming endpoint to the Java AI orchestrator
(`/api/v1/ai/orchestrate/stream` in addition to the existing
`/api/v1/ai/orchestrate`). This allows the caller to get updates of what
stage of orchestration is being run at the time so UIs can give the user
feedback.

Also contains some dubious Gradle changes to suppress errors coming from
Spotless, when it crashes in Google stuff. I'm not sure if that's
appropriate to add, feel free to ask for changes in review.
2026-04-17 10:01:08 +01:00
Orel YosupovandGitHub 97ca85d878 Fix terms and privacy URLs links in Footer component (#6124)
Fix the issue #6104
2026-04-16 15:55:53 +01:00
Anthony StirlingandGitHub 60c036e980 thumbnail preview fixes windows (#6074) 2026-04-15 23:25:38 +01:00
702f4e5c2c Add Taskfile for unified dev workflow across all components (#6080)
## Add Taskfile for unified dev workflow

### Summary
- Introduces [Taskfile](https://taskfile.dev/) as the single CLI entry
point for all development workflows across backend, frontend, engine,
Docker, and desktop
- ~80 tasks organized into 6 namespaces: `backend:`, `frontend:`,
`engine:`, `docker:`, `desktop:`, plus root-level composites
- All CI workflows migrated to use Task
- Deletes `engine/Makefile` and `scripts/build-tauri-jlink.{sh,bat}` —
replaced by Task equivalents
- Removes redundant npm scripts (`dev`, `build`, `prep`, `lint`, `test`,
`typecheck:all`) from `package.json`
- Smart dependency caching: `sources`/`status`/`generates`
fingerprinting, CI-aware `npm ci` vs `npm install`, `run: once` for
parallel dep deduplication

### What this does NOT do
- Does not replace Gradle, npm, or Docker — Taskfile is a thin
orchestration wrapper
- Does not change application code or behavior

### Install
```
npm install -g @go-task/cli    # or: brew install go-task, winget install Task.Task
```

### Quick start
```
task --list       # discover all tasks
task install      # install all deps
task dev          # start backend + frontend
task dev:all      # also start AI engine
task test         # run all tests
task check        # quick quality gate (local dev)
task check:all    # full CI quality gate
```

### Test plan
- [ ] Install `task` CLI and run `task --list` — verify all tasks
display
- [ ] Run `task install` — verify frontend + engine deps install
- [ ] Run `task dev` — verify backend + frontend start, Ctrl+C exits
cleanly
- [ ] Run `task frontend:check` — verify typecheck + lint + test pass
- [ ] Run `task desktop:dev` — verify jlink builds are cached on second
run
- [ ] Verify CI passes on all workflows

---------

Co-authored-by: James Brunton <[email protected]>
2026-04-15 14:16:57 +00:00
plindandGitHub 4ada46ca56 Fix encrypted PDF unlock modal missing on IndexedDB restore and large files (#6099) 2026-04-14 00:38:42 +01:00
Reece BrowneandGitHub 76aa5c7e2f Fix encrypted pdf handling (#6088)
Fix and improve encrypted pdf handling
2026-04-13 13:20:43 +01:00
d53beb9bce Remove duplicate isPanning state (#6086)
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-04-13 11:49:09 +01:00
James BruntonandGitHub a3e45bc182 Add frontend autoformatting and set CI to require formatted code for all languages (#6052)
# Description of Changes
Changes the strategy for autoformatting to reject PRs if they are not
formatted correctly instead of allowing them to merge and then spawning
a new PR to fix the formatting. The old strategy just caused more work
for us because we'd have to manually approve the followup PR and get it
merged, which required 2 reviewers so in practice it rarely got done and
just meant everyone's PRs ended up containing reformatting for unrelated
files, which makes code review unnecessarily difficult. If the PR's code
is not formatted correctly after this PR, a comment will be added
automatically to tell the author how to run the formatter script to fix
their code so it can go in.

This also enables autoformatting for the frontend code, using Prettier.
I've enabled it for pretty much everything in the frontend folder, other
than 3rd party files and files it doesn't make sense for. I also
excluded Markdown because it sounds likely to be more annoying to have
to autoformat the Markdown in the frontend folder but nowhere else. Open
to changing this though if people disagree.

> [!note]
> 
> Advice to reviewers: The first commit contains all of the actual logic
I've introduced (CI changes, Prettier config, etc.)
> The second commit is just the reformatting of the entire frontend
folder.
> The first commit needs proper review, the second one just give it a
spot-check that it's doing what you'd expect.
2026-04-10 17:41:19 +01:00
aikido-autofix[bot]GitHubaikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
60cc749e6a [Aikido] Fix critical issue in axios via minor version upgrade from 1.13.6 to 1.15.0 in frontend (#6092)
Upgrade axios to fix critical proxy bypass and SSRF vulnerabilities in
hostname normalization that could allow attackers to reach protected
internal services.

 There are no breaking changes

<details>
<summary> 1 CVE resolved by this upgrade, including 1 critical 🚨
CVE</summary>

<br>


This PR will resolve the following CVEs:
| Issue |
Severity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
Description |
| --- | --- | --- |
|
<pre>[CVE-2025-62718](https://app.aikido.dev/issues/26490690/detail?groupId=70007#CVE-2025-62718)</pre>
| <pre>🚨 CRITICAL</pre> | [axios] Axios fails to properly normalize
hostnames when checking NO_PROXY rules, allowing requests to loopback
addresses (localhost., [::1]) to bypass proxy protections and reach
internal services. This enables proxy bypass and SSRF attacks against
protected loopback or internal endpoints. |


</details>

Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com>
2026-04-10 09:50:05 +01:00
EthanHealy01andGitHub 11b26755a4 use clean 3 card design for landing page (#6084)
<img width="2056" height="1080" alt="Screenshot 2026-04-08 at 1 26
58 PM"
src="https://github.com/user-attachments/assets/e834988b-c3ab-4633-bf15-9fe0457d0029"
/>

<img width="2056" height="1080" alt="Screenshot 2026-04-08 at 1 27
12 PM"
src="https://github.com/user-attachments/assets/adfebd95-ca59-4de0-9336-b1e2dc1dc5fe"
/>
2026-04-09 12:38:46 +00:00
Vibe StackandGitHub a5b259b453 feat(settings): add default startup view and reader zoom preferences (#6073)
## Description of Changes

Adds two new user preferences to the General settings panel, addressing
#5908.

**Default view on launch** - a segmented control (Tools / Reader /
Automate) that controls which left-column tab is active when the app
starts. Previously the app always opened on the Tools tab with no way to
change this. Users who spend most of their time reading PDFs had to
manually switch to the Reader tab on every launch.

**Default reader zoom** - a dropdown (Auto / Fit width / Fit page /
50%–200%) that sets the initial zoom level whenever a PDF is opened in
the reader. Previously the app always applied an automatic
fit-to-viewport calculation.

Both settings are non-breaking. The defaults (`Tools` and `Auto`)
reproduce the existing behaviour exactly, so existing users see no
difference until they change a preference.

### What changed
- `preferencesService.ts` - added `StartupView` and `ViewerZoomSetting`
types plus the two new fields to `UserPreferences` with safe defaults
- `ToolWorkflowContext.tsx` - one-time startup effect that navigates to
the preferred tab on first render (mirrors the existing
`defaultToolPanelMode` sync pattern)
- `ZoomAPIBridge.tsx` - respects the zoom preference before falling back
to auto-zoom logic when a document loads
- `GeneralSection.tsx` - two new controls added below "Default tool
picker mode"; the Select uses `comboboxProps={{ withinPortal: true }}`
so the dropdown renders above the settings modal
- `en-GB/translation.toml` - new keys for labels, descriptions, and
option values

Closes #5908 

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [x] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [x] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
<img width="1023" height="747" alt="Screenshot 2026-04-05 185718"
src="https://github.com/user-attachments/assets/6a8bc35a-d813-4ab8-b303-55bdce747a6a"
/>
<img width="1026" height="755" alt="Screenshot 2026-04-05 185620"
src="https://github.com/user-attachments/assets/d2c45134-ed32-4332-a193-1a96837ba2a3"
/>


### Testing (if applicable)

- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2026-04-09 10:30:19 +00:00
James BruntonandGitHub cc1604a802 Add prototypes folder to test new functionality in (#6081)
# Description of Changes
Add prototypes folder to test new functionality in. This build of the
app is spawnable with `npm run dev:prototypes`.

Currently just contains a very developer-y chat interface to help us
develop & explore the AI backend before we make the frontend for it for
real.
2026-04-09 08:21:07 +00:00
fbae819d7c Fix/desktop open with tool access (#6056)
## Description

Fixes #6029 - Additional selection in windows client no longer necessary

## Problem
When opening PDF files in the Windows desktop client using "Open with",
the file displays properly but users had to manually select it again in
the workbench before any PDF tools (merge, compress, crop, compare,
etc.) become functional.

## Root Cause
Files opened via "Open with" were added to FileContext but **not
selected** (missing `selectFiles: true`). Without selection, the file
wasn't marked as active, preventing tool access.

Additionally, `AppInitializer` was placed outside
`ToolWorkflowProvider`, causing a context error.

## Solution

### Changes:
1. **frontend/src/desktop/hooks/useAppInitialization.ts**
   - Added `{ selectFiles: true }` when calling `addFiles()`
   - Files now immediately marked as active in FileContext

2. **frontend/src/core/components/AppProviders.tsx**
   - Moved `AppInitializer` inside `ToolWorkflowProvider`
   - Ensures context availability for initialization

## Testing
- Open PDF via "Open with" on Windows
- File now immediately usable with all tools
- No manual reselection needed

## Screenshot
<img width="1920" height="1080" alt="Screenshot (3)"
src="https://github.com/user-attachments/assets/9ceacadf-eb12-42a6-86f9-bca6188bfbb9"
/>

---------

Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: EthanHealy01 <[email protected]>
Co-authored-by: Reece Browne <[email protected]>
2026-04-08 20:39:20 +05:30
ebab5a4456 pipeline fixes (#6068)
Co-authored-by: a <a>
2026-04-04 10:19:38 +01:00
Anthony StirlingandGitHub 81dc90cd6d possible fix permission issues and fix thread timing issues (#6061)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2026-04-03 16:49:16 +01:00
917edc43b3 Add specific View Scope For Selected Files (#6050)
## Fix 1 — Viewer bug (8 tools)

8 tools called `useFileSelection()` directly instead of routing through
`useBaseTool`. In the viewer, this meant they operated on **all selected
files**
instead of only the one being viewed. For example: 10 files loaded,
viewing
file 3, running Add Stamp — all 10 files got stamped.

**Root cause:** These tools had no view-scope awareness.
`useFileSelection()`
returns the raw workbench selection with no knowledge of which file is
active in
the viewer.

**Fix:** A new hook `useViewScopedFiles` was introduced:

```ts
// Viewer → only the active file
// Everywhere else → all loaded files
const selectedFiles = useViewScopedFiles();
```

The 8 tools were updated to call this instead of `useFileSelection()`.

**Tools fixed:** Add Stamp, Add Watermark, Add Password, Add Page
Numbers,
Add Attachments, Reorganize Pages, OCR, Convert

---

## Fix 2 — Page selector / active files context (all tools)

`useBaseTool` returned `selectedFiles` (checked files only) in
non-viewer
contexts. In the page selector this is typically empty or stale — not
the full
set of loaded files that tools should operate on.

**Fix:** `useBaseTool` was updated to use `useViewScopedFiles`, which
returns
all loaded files in non-viewer contexts. This affected every tool via
`useBaseTool`.

---

## Workarounds for Compare & Merge

Two tools intentionally need all loaded files regardless of view, so
they use
`ignoreViewerScope: true` in `useBaseTool`.

**Compare** — needs exactly 2 files for its Original/Edited slots.
Scoping to
one file would break the comparison entirely. `ignoreViewerScope: true`
is set
and `disableScopeHints: true` hides the "(this file)" button label hint.
The
slot auto-mapping logic was also improved alongside this fix.

**Merge** — needs 2+ files; merging a single file is meaningless. Rather
than
leaving the button silently disabled, Merge now:
- Auto-redirects to the active files view on first open from the viewer
- If the user navigates back to the viewer, shows a disabled button with
a hint
  and a "Go to active files view" shortcut button

---

## How to Test

---

## Fix 1 — 8 tools (viewer scoping)

### Test steps (same for each)
1. Load 3 PDFs into workbench
2. Open viewer, navigate to file 2
3. Open the tool, configure settings, run
4.  Only file 2 is in the results
5.  Button label shows **"[Action] (this file)"**
6.  A note below the button reads **"Only applying to: [filename]"**

| Tool | What to configure |
|---|---|
| **Add Stamp** | Enter any text stamp or upload an image stamp |
| **Add Watermark** | Select text watermark, enter any text |
| **Add Page Numbers** | Leave defaults |
| **Add Password** | Enter any owner + user password |
| **Add Attachments** | Attach any small file |
| **Reorganize Pages** | Enter a page range e.g. `1,2` |
| **OCR** | Leave default language |
| **Convert** | Convert PDF → any format |

---

## Fix 2 — All tools (page selector context)

### Test steps
1. Load 3 PDFs into workbench
2. Open the page selector view 
3. Open any tool from the sidebar, run it
4.  All 3 files are processed (not zero or a stale subset)

---

## Compare (intentionally ignores view scope)

**A — Auto-fill with exactly 2 files**
1. Load exactly 2 PDFs
2. Open Compare from either the viewer or active files view
3.  Both slots are filled automatically (Original + Edited)
4.  No scope hint appears on the button

**B — Manual selection with 3+ files**
1. Load 3+ PDFs
2. Open Compare
3.  The first 2 files fill the slots
4.  A 3rd file does not add a 3rd slot (capped at 2)

**C — File removed mid-session**
1. Load 2 PDFs, let Compare auto-fill both slots
2. Remove one file from the workbench
3.  The corresponding slot clears; the other slot is unchanged

**D — Viewer mode**
1. Load 2 PDFs, open viewer
2. Open Compare from the viewer sidebar
3.  Both files are still available for slot selection (not scoped to
current file)

---

## Merge (intentionally ignores view scope, disabled in viewer)

**A — Auto-redirect on first open from viewer**
1. Load 2+ PDFs, open the viewer
2. Open Merge from the viewer sidebar
3.  Immediately redirected to the active files view

**B — Viewer mode disabled state (after navigating back)**
1. From the active files view, open Merge, then navigate back to the
viewer
2.  Execute button is **disabled** with tooltip "Switch to the file
editor to select multiple files"
3.  A note appears: *"Merge needs 2 or more files. Head to the file
editor to select them."*
4.  A **"Go to active files view"** button is shown; clicking it
navigates back

**C — Active files view works normally**
1. Load 3 PDFs, open Merge from the active files view
2.  All 3 files appear in the merge list
3.  Button shows **"Merge (3 files)"**
4. Run the merge
5.  Output is a single PDF containing all 3 files

---

## Button label behaviour (all tools)

| Context | Expected button text |
|---|---|
| Viewer, 1 file loaded | `[Action]` (no suffix) |
| Viewer, 2+ files loaded | `[Action] (this file)` |
| Active files view, 1 file loaded | `[Action]` (no suffix) |
| Active files view, 2+ files loaded | `[Action] (N files)` |
| Merge in viewer | disabled — no suffix |
| Compare | never shows scope suffix (`disableScopeHints: true`) |

---------

Co-authored-by: Reece Browne <[email protected]>
2026-04-03 16:04:38 +01:00
stirlingbot[bot]GitHubstirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>Anthony Stirling
2c940569d1 🤖 format everything with pre-commit by stirlingbot (#6000)
Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <[email protected]>
2026-04-02 18:47:52 +01:00
Thomas BERNARDandGitHub 7bbb04b594 translate more messages to fr-FR (#6042) 2026-04-02 17:55:17 +01:00
DexterityandGitHub fca40e5544 Fix image stamp cropping and align preview with PDF output for add-stamp (#6013) 2026-04-02 17:54:13 +01:00
Reece BrowneandGitHub 0adcbeedf1 Fix/redact bug (#6048) 2026-04-02 17:39:45 +01:00
de9625942b Pipeline changes and version bump (#6047)
# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: a <a>
2026-04-02 12:52:22 +01:00
Peter Dave HelloandGitHub da9327ab1c Restore English search aliases in zh-TW tags (#6039)
# Description of Changes

Preserve the translated zh-TW tags while restoring the English aliases
used by frontend tool search.

This keeps common English technical queries such as permissions or
access control discoverable in the zh-TW locale.
---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [x] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

## GitHub Copilot Pull Reuqest summary

> This pull request significantly expands the keyword tags for a wide
range of PDF-related tools and actions in the Traditional Chinese
(`zh-TW`) translation file. The main goal is to improve searchability
and discoverability of features by including a comprehensive set of
English and Chinese keywords, synonyms, and related phrases for each
tool.
> 
> The most important changes include:
> 
> **Localization and Search Optimization:**
> 
> * Expanded the `tags` fields for all tools and actions under the
`[home.*]` sections in `frontend/public/locales/zh-TW/translation.toml`
to include a broad set of English and Chinese keywords, synonyms, and
common search phrases. This enhances feature discoverability for users
searching in either language.
[[1]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3885-R3925)
[[2]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3934-R4039)
[[3]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4054-R4209)
[[4]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4218-R4218)
> 
> **Consistency and Coverage:**
> 
> * Ensured that each tool/action now has a rich set of tags that cover
various ways users might refer to the feature, including technical
terms, synonyms, and related concepts (e.g., "merge", "combine", "join"
for PDF merging).
[[1]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3885-R3925)
[[2]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3934-R4039)
[[3]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4054-R4209)
[[4]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4218-R4218)
> 
> **Internationalization Improvements:**
> 
> * Added English keywords alongside Chinese ones to support bilingual
search and better serve users who may search using English terms in a
localized interface.
[[1]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3885-R3925)
[[2]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L3934-R4039)
[[3]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4054-R4209)
[[4]](diffhunk://#diff-5979ec7aabfd804ffe625390faee80bfc5b97bdb00f72cc3ce27359f82450e87L4218-R4218)
> 
> These changes collectively make it easier for users to find the
features they need, regardless of the language or terminology they use.
2026-04-02 08:35:38 +00:00
EthanHealy01andGitHub 61280f758a bump deps (#6041)
bump deps and add a one week buffer to releases that we merge in to
allow for vulnerabilities to be caught.
2026-04-01 18:08:45 +01:00
ConnorYohandGitHub 801cc8a5f4 Alpha flag for file storage settings (#6044)
## Summary
- Added "Alpha" badge to the File Storage & Sharing nav item in the
settings sidebar
- Added "Alpha" badge to the File Storage & Sharing page title
- Removed the old inline "(Alpha)" text from the Enable Group Signing
label
- Restructured all toggle cards so the switch is anchored to the right
of each row
- Tightened spacing between cards for a more compact layout
- Extended `ConfigNavItem` interface with optional `badge` and
`badgeColor` fields for reuse elsewhere
<img width="1696" height="1057" alt="image"
src="https://github.com/user-attachments/assets/77ac8276-ed65-4cae-8470-65de8f56dd74"
/>
2026-04-01 17:18:48 +01:00
EthanHealy01andGitHub 74153b6deb Bug/connection mode fixes (#5998) 2026-04-01 15:33:46 +01:00
Anthony StirlingandGitHub 0a098cf7b7 idle cpu fix test (#6015) 2026-04-01 11:58:10 +01:00
Matheus SaitoandGitHub 212f12a81f Added back ctrl+r as rotate if on desktop (#5982) (#5993)
Fix #5982

Behaviour of ctrl+r altered to support rotate on desktop, while the web
version continue to use refresh as default.
2026-04-01 11:48:53 +01:00
James BruntonandGitHub c31e4253dd Fix any type usage in proprietary/ (#5949)
# Description of Changes
Follow on from #5934, expanding `any` type usage ban to the
`proprietary/` folder
2026-04-01 08:21:26 +00:00
Peter Dave HelloandGitHub a96b95e198 Update and improve zh-TW Traditional Chinese locale (#6034) 2026-03-30 21:10:49 +01:00
Anthony StirlingandGitHub a06b6a4bac pdf layer toggle (#6028) 2026-03-30 17:04:53 +01:00
cdc288e78d nonpdf-viewer (#6024)
Co-authored-by: a <a>
2026-03-30 16:39:11 +01:00
Anthony StirlingandGitHub 82a3b8c770 Unlock account (#5984) 2026-03-30 16:07:57 +01:00
ConnorYohandGitHub 1e97a32d4b feat(desktop): gate shared signing behind self-hosted auth (#6002)
## Summary

This PR adds full desktop (Tauri) support for the shared signing feature
when connected to a self-hosted server, and fixes several bugs
discovered during that work.

### Feature gating

Shared signing, file sharing, and share links are proprietary server
features that require an authenticated self-hosted session. Previously
these were read directly from `config` with no awareness of connection
mode or auth state, meaning the UI could appear in SaaS/local mode or
when logged out.

- Introduce `useGroupSigningEnabled` and `useSharingEnabled` hooks with
core implementations (web behaviour unchanged) and desktop overrides
that require `selfhosted` mode + an active authenticated session
- Extract shared subscription logic into `useSelfHostedAuth` (connection
mode + auth state + config refetch)
- `QuickAccessBar` now derives all three flags from the hooks instead of
raw config

### Config timing fix

When a user logs in via the SetupWizard, the `jwt-available` event fires
a config fetch *before* the mode is switched to `selfhosted`. This meant
the config was fetched from the local bundled backend (port ~59567)
which has no knowledge of `storageGroupSigningEnabled`, causing the
group signing button to stay hidden until a full page refresh.
`useSelfHostedAuth` detects the mode transition and triggers a fresh
config fetch at the correct moment, after the self-hosted URL is active.

### Bug fixes

**`SignPopout.tsx`** — Manually setting `Content-Type:
multipart/form-data` on two `FormData` POST requests stripped the
auto-generated boundary, causing a `400 bad multipart` from the server.
Removed the explicit headers so Axios sets them correctly.

**`tauriHttpClient.ts`** — `response.json()` was called before
`response.ok` was checked. A plain-text error body from the server (e.g.
`"Cannot sign..."`) caused a `SyntaxError` that fell into the network
error catch block and was reported as `ERR_NETWORK`, hiding the real
failure. The fix checks `response.ok` first, reads error bodies as text,
and handles empty 200 bodies (returning `null` instead of throwing).

---

## Testing

### Prerequisites
- Desktop app running in self-hosted mode pointed at a local
Stirling-PDF instance (`http://localhost:8080`)
- The self-hosted instance has group signing and storage enabled in
settings
- At least two user accounts on the self-hosted instance

### 1. Feature gating — group signing button

| Step | Expected |
|---|---|
| Open the desktop app in **local mode** (no server configured) | Group
signing button absent from QuickAccessBar |
| Switch to self-hosted mode but **do not log in** | Group signing
button absent |
| Log in to the self-hosted server | Group signing button appears
without requiring a page refresh |
| Log out | Group signing button disappears immediately |
| Log back in | Group signing button reappears without a page refresh |

### 2. Feature gating — file sharing

Repeat the same steps above, verifying the share and share-link buttons
in the file manager follow the same visibility rules.

### 3. Create a signing session

1. Log in, open the group signing panel from QuickAccessBar
2. Select a PDF, add a participant, configure signature defaults and
submit
3. Verify the session is created successfully (no `400 bad multipart`
error)

### 4. Participant signing

1. As the invited participant, open the signing request from
QuickAccessBar
2. Upload or draw a signature and submit
3. Verify signing completes successfully (no `ERR_NETWORK` error)

### 5. Error surfacing

1. Attempt an action that the server rejects (e.g. sign a document with
an invalid certificate)
2. Verify the actual server error message is shown rather than a generic
network error
2026-03-30 14:37:45 +00:00
James BruntonandGitHub 4a6b426651 Only allow Tauri imports in the desktop app (#5995)
# Description of Changes
Adds an eslint rule to disallow importing any Tauri APIs outside the
desktop folder to help hint to developers that they should be following
the frontend architecture.

While doing this, I also discovered that you can provide a custom
message in the `no-restricted-imports` rule, which is nicer than the
comments that I'd previously added to the eslint config file to explain
why they weren't allowed:

```text
/Users/jamesbrunton/Dev/spdf1/frontend/src/core/components/shared/config/configSections/GeneralSection.tsx
  19:1  error  'src/core/contexts/PreferencesContext' import is restricted from being used by a pattern. Use @app/* imports instead of absolute src/ imports              no-restricted-imports
  20:1  error  '../../../../../core/contexts/AppConfigContext' import is restricted from being used by a pattern. Use @app/* imports instead of relative imports          no-restricted-imports
  21:1  error  '@tauri-apps/core' import is restricted from being used by a pattern. Tauri APIs are desktop-only. Review frontend/DeveloperGuide.md for structure advice  no-restricted-imports
```
2026-03-30 14:24:16 +00:00
ConnorYohandGitHub 0e29640766 fix: get all Playwright E2E tests loading and expand CI to run full suite (#6009)
## Fix Playwright E2E tests and expand CI to run full suite

### Problem

The full Playwright suite was broken in two ways:

1. **`ConvertE2E.spec.ts` crashed at import time** —
`conversionEndpointDiscovery.ts` imported a React hook at the top level,
which pulled in the entire component tree. That chain eventually
required `material-symbols-icons.json` (a generated file that didn't
exist), crashing module resolution before any tests ran.

2. **CI only ran cert validation tests** — both `build.yml` and
`nightly.yml` hardcoded `src/core/tests/certValidation` as the test
path, silently ignoring everything else.

### Changes

**`ConvertE2E.spec.ts` — complete rewrite**
The old tests were useless in practice: all 9 dynamic conversion tests
were permanently skipped unless a real Spring Boot backend was running
(they called a live `/api/v1/config/endpoints-enabled` endpoint at
module load time). Replaced with 4 focused tests that use `page.route()`
mocking — no backend required, same pattern as
`CertificateValidationE2E`.

New tests cover:
- Convert button absent before a format pair is selected
- Successful PDF→PNG conversion shows a download button (mocked API
response)
- API error surfaces as an error notification
- Convert button appears and is enabled after selecting valid formats

**`conversionEndpointDiscovery.ts` — deleted**
Only existed to support the old tests. The `useConversionEndpoints`
React hook it exported was never imported anywhere else.

**`ReviewToolStep.tsx`**
Added `data-testid="download-result-button"` to the download button —
required for the happy-path test assertion.

**CI workflows (`build.yml`, `nightly.yml`)**
- Added a `Generate icons` step before Playwright runs (`node
scripts/generate-icons.js`) — the icon JSON is generated by `npm run
dev` locally but skipped by `npm ci` in CI
- Removed the `src/core/tests/certValidation` path filter so the full
suite runs
2026-03-30 11:27:55 +01:00
albanobattistellaandGitHub 05b4255751 Update Italian translations (#6014) 2026-03-30 11:04:11 +01:00
ConnorYohandGitHub dd44de349c Shared Sign Cert Validation (#5996)
## PR: Certificate Pre-Validation for Document Signing

### Problem

When a participant uploaded a certificate to sign a document, there was
no validation at submission time. If the certificate had the wrong
password, was expired, or was incompatible with the signing algorithm,
the error only surfaced during **finalization** — potentially days
later, after all other participants had signed. At that point the
session is stuck with no way to recover.

Additionally, `buildKeystore` in the finalization service only
recognised `"P12"` as a cert type, causing a `400 Invalid certificate
type: PKCS12` error when the **owner** signed using the standard
`PKCS12` identifier.

---

### What this PR does

#### Backend — Certificate pre-validation service

Adds `CertificateSubmissionValidator`, which validates a keystore before
it is stored by:
1. Loading the keystore with the provided password (catches wrong
password / corrupt file)
2. Checking the certificate's validity dates (catches expired and
not-yet-valid certs)
3. Test-signing a blank PDF using the same `PdfSigningService` code path
as finalization (catches algorithm incompatibilities)

This runs on both the participant submission endpoint
(`WorkflowParticipantController`) and the owner signing endpoint
(`SigningSessionController`), so both flows are protected.

#### Backend — Bug fix

`SigningFinalizationService.buildKeystore` now accepts `"PKCS12"` and
`"PFX"` as aliases for `"P12"`, consistent with how the validator
already handles them. This fixes a `400` error when the owner signed
using the `PKCS12` cert type.

#### Frontend — Real-time validation feedback

`ParticipantView` gains a debounced validation call (600ms) triggered
whenever the cert file or password changes. The UI shows:
- A spinner while validating
- Green "Certificate valid until [date] · [subject name]" on success
- Red error message on failure (wrong password, expired, not yet valid)
- The submit button is disabled while validation is in flight

#### Tests — Three layers

| Layer | File | Coverage |
|---|---|---|
| Service unit | `CertificateSubmissionValidatorTest` | 11 tests — valid
P12/JKS, wrong password, corrupt bytes, expired, not-yet-valid, signing
failure, cert type aliases |
| Controller unit | `WorkflowParticipantValidateCertificateTest` | 4
tests — valid cert, invalid cert, missing file, invalid token |
| Controller integration | `CertificateValidationIntegrationTest` | 6
tests — real `.p12`/`.jks` files through the full controller → validator
stack |
| Frontend E2E | `CertificateValidationE2E.spec.ts` | 7 Playwright tests
— all feedback states, button behaviour, SERVER type bypass |

#### CI

- **PR**: Playwright runs on chromium when frontend files change (~2-3
min)
- **Nightly / on-demand**: All three browsers (chromium, firefox,
webkit) at 2 AM UTC, also manually triggerable via `workflow_dispatch`
2026-03-27 14:01:10 +00:00