mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 13:20:08 +03:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a243056c3e | ||
|
|
aa6ac5c7a3 | ||
|
|
71ef9dcde8 | ||
|
|
b9d3a3128b | ||
|
|
0bf35a98c0 | ||
|
|
10d9127d29 |
@@ -32,7 +32,7 @@ vs `main`. Flags: `--html` (also emit a rendered HTML twin), `--no-screens`.
|
||||
- Read the PR description / commit messages for stated intent. Do **not** invent
|
||||
history or motivation that isn't evidenced (state current behavior in present tense).
|
||||
- Classify touched files by layer:
|
||||
- **Frontend**: tools (`frontend/editor/src/core/components/tools/*` or `.../core/tools/*`),
|
||||
- **Frontend**: tools (`frontend/src/editor/core/components/tools/*` or `.../core/tools/*`),
|
||||
hooks (`core/hooks/tools/*`, `useToolOperation`), contexts, routes, i18n
|
||||
(`public/locales/en-US`).
|
||||
- **Java backend**: controllers (`.../controller/api/...`), services, models, config.
|
||||
|
||||
@@ -53,11 +53,11 @@ gh pr diff <pr> --name-only # or: git diff --name-only <base>...HEAD
|
||||
Map changed frontend files to URLs generically:
|
||||
- **Tools**: a changed `components/tools/<toolDir>/…` or `hooks/tools/<tool>/…` →
|
||||
toolId → URL via the repo's own rule `getToolUrlPath` in
|
||||
[toolsTaxonomy.ts:200](frontend/editor/src/core/data/toolsTaxonomy.ts): `/` + the
|
||||
[toolsTaxonomy.ts:200](frontend/src/editor/core/data/toolsTaxonomy.ts): `/` + the
|
||||
id kebab-cased (`addPageNumbers` → `/add-page-numbers`).
|
||||
- **Pages/routes**: changed `filesPage/*` → `/files`, etc.
|
||||
- `--all`: enumerate every tool in the registry instead of just changed ones.
|
||||
Write `frontend/editor/screenshots/ui-diff/targets.json` =
|
||||
Write `frontend/screenshots/ui-diff/targets.json` =
|
||||
`[{ "id":"compress", "url":"/compress", "name":"Compress" }]`. This is what makes
|
||||
it generic - the spec never names a tool.
|
||||
|
||||
@@ -69,12 +69,12 @@ the full viewport - or the `--scope` container if given). Ensure the harness is
|
||||
(node_modules + icons).
|
||||
```
|
||||
# after = current head
|
||||
cd frontend/editor && PR_SHOT_SIDE=after PR_SHOT_THEME=light \
|
||||
cd frontend && PR_SHOT_SIDE=after PR_SHOT_THEME=light \
|
||||
npx playwright test --project=stubbed ui-before-after.spec.ts
|
||||
# before = base, in an isolated worktree (copy the spec + targets.json in)
|
||||
git worktree add ../ba-base origin/<baseRefName> # or the merge-base
|
||||
# set up its frontend, copy spec + screenshots/ui-diff/targets.json across, then:
|
||||
cd ../ba-base/frontend/editor && PR_SHOT_SIDE=before PR_SHOT_THEME=light \
|
||||
cd ../ba-base/frontend && PR_SHOT_SIDE=before PR_SHOT_THEME=light \
|
||||
npx playwright test --project=stubbed ui-before-after.spec.ts
|
||||
# copy its screenshots/ui-diff/before/ back next to after/. Repeat with
|
||||
# PR_SHOT_THEME=dark if --theme includes dark. Remove worktree when done.
|
||||
@@ -82,7 +82,7 @@ cd ../ba-base/frontend/editor && PR_SHOT_SIDE=before PR_SHOT_THEME=light \
|
||||
|
||||
### 4. Auto-diff (surface what changed)
|
||||
```
|
||||
cd frontend/editor && node <skill>/diff-shots.mjs \
|
||||
cd frontend && node <skill>/diff-shots.mjs \
|
||||
screenshots/ui-diff/before screenshots/ui-diff/after screenshots/ui-diff
|
||||
```
|
||||
Produces `diff-report.json` classifying each view `unchanged | changed | added |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// unchanged | changed | added | removed, and CROP each changed pair to the
|
||||
// affected region (bounding box of differing pixels + padding) - unless the
|
||||
// change spans most of the page, in which case the full frame is kept.
|
||||
// Run from frontend/editor (so deps resolve):
|
||||
// Run from frontend (so deps resolve):
|
||||
// node <skill>/diff-shots.mjs <beforeDir> <afterDir> [outDir]
|
||||
// Env:
|
||||
// DIFF_THRESHOLD min fraction of differing pixels to count as changed (default 0.001)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Render each .tab-section of a montage HTML into its own PNG (the PR-ready image).
|
||||
// Run from frontend/editor (so @playwright/test resolves):
|
||||
// Run from frontend (so @playwright/test resolves):
|
||||
// node <skill>/shoot-sections.mjs <montage.html> <outDir>
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
@@ -28,13 +28,13 @@ current branch diff. Flags: `--fix`, `--theme light|dark|both` (default both),
|
||||
## What this repo gives you (use it, don't reinvent)
|
||||
|
||||
- **Stubbed Playwright project** = backend-free screenshots via `page.route()` mocks.
|
||||
Reference implementation: `frontend/editor/src/core/tests/stubbed/files-page-screenshots.spec.ts`.
|
||||
Reference implementation: `frontend/src/editor/core/tests/stubbed/files-page-screenshots.spec.ts`.
|
||||
It already shows the light / **dark** / **RTL** passes, JWT seeding, IndexedDB
|
||||
seeding, and dumping PNGs to a `screenshots/<area>/` folder. Copy its shape.
|
||||
- Helpers: `frontend/editor/src/core/tests/helpers/ui-helpers.ts`
|
||||
- Helpers: `frontend/src/editor/core/tests/helpers/ui-helpers.ts`
|
||||
(`uploadFiles`, `openSettings`, `waitForModalOpen`, `dismissTourTooltip`, …)
|
||||
and the `stub-test-base` fixtures (`autoGoto`, `seedJwt`, `viewport`).
|
||||
- Config: `frontend/editor/playwright.config.ts` (run from `frontend/editor/`).
|
||||
- Config: `frontend/playwright.config.ts` (run from `frontend/`).
|
||||
- Report template: [report-template.html](report-template.html) - self-contained,
|
||||
one big image at a time, a global light/dark slider that flips every shot,
|
||||
thumbnail rail, prev/next + arrow keys, and a Findings tab.
|
||||
@@ -54,13 +54,13 @@ current branch diff. Flags: `--fix`, `--theme light|dark|both` (default both),
|
||||
Worktrees have no `node_modules` and no generated icons. From repo root:
|
||||
```
|
||||
cd frontend && npm ci # or junction main's node_modules (see memory)
|
||||
cd frontend/editor && node scripts/generate-icons.js
|
||||
cd frontend && node scripts/generate-icons.js
|
||||
```
|
||||
Kill any stale dev server first (it serves old modules):
|
||||
`Get-NetTCPConnection -LocalPort 5173 -State Listen | %{ Stop-Process -Id $_.OwningProcess -Force }`
|
||||
|
||||
### 3. Write the capture spec
|
||||
Create `frontend/editor/src/core/tests/stubbed/<feature>-walkthrough.spec.ts`,
|
||||
Create `frontend/src/editor/core/tests/stubbed/<feature>-walkthrough.spec.ts`,
|
||||
modeled on `files-page-screenshots.spec.ts`. For each enumerated view:
|
||||
- stub the APIs it needs, drive the UI to that state, wait on a real locator
|
||||
(not a fixed sleep), `await settle(page)` for Mantine portals, then
|
||||
@@ -71,7 +71,7 @@ modeled on `files-page-screenshots.spec.ts`. For each enumerated view:
|
||||
- Name shots `NN_<view>_<theme>.png` so light/dark pair up by suffix.
|
||||
- Prefer **stable test-ids** over translated accessible names (RTL/i18n breaks text locators).
|
||||
|
||||
Run it: `cd frontend/editor && npx playwright test --project=stubbed <feature>-walkthrough.spec.ts`.
|
||||
Run it: `cd frontend && npx playwright test --project=stubbed <feature>-walkthrough.spec.ts`.
|
||||
Add `--project=stubbed-firefox`/`-webkit` only if cross-browser layout matters.
|
||||
|
||||
### 4. Build the report
|
||||
|
||||
+4
-4
@@ -26,16 +26,16 @@ version_builds/
|
||||
node_modules/
|
||||
**/node_modules/
|
||||
frontend/node_modules/
|
||||
frontend/editor/dist/
|
||||
frontend/editor/playwright-report/
|
||||
frontend/dist/
|
||||
frontend/playwright-report/
|
||||
.npm/
|
||||
.yarn/
|
||||
|
||||
# Tauri/desktop builds
|
||||
src-tauri/target/
|
||||
src-tauri/dist/
|
||||
frontend/editor/src-tauri/target/
|
||||
frontend/editor/src-tauri/dist/
|
||||
frontend/src-tauri/target/
|
||||
frontend/src-tauri/dist/
|
||||
|
||||
# IDE and editor
|
||||
.idea/
|
||||
|
||||
+10
-10
@@ -92,12 +92,12 @@ frontend: &frontend
|
||||
# job on changes to any of these.
|
||||
tauri: &tauri
|
||||
- *ci
|
||||
- frontend/editor/src-tauri/**
|
||||
- frontend/editor/src/desktop/**
|
||||
- frontend/editor/tsconfig.desktop.vite.json
|
||||
- frontend/src-tauri/**
|
||||
- frontend/src/editor/desktop/**
|
||||
- frontend/tsconfig.desktop.vite.json
|
||||
- frontend/package.json
|
||||
- frontend/package-lock.json
|
||||
- frontend/editor/vite.config.ts
|
||||
- frontend/vite.config.ts
|
||||
- .github/workflows/tauri-build.yml
|
||||
- Taskfile.yml
|
||||
- .taskfiles/desktop.yml
|
||||
@@ -121,9 +121,9 @@ engine: &engine
|
||||
generated-models: &generated-models
|
||||
- *ci
|
||||
- *openapi
|
||||
- frontend/editor/scripts/generate-tool-api-types.mts
|
||||
- frontend/editor/src/core/types/toolApiTypes.ts
|
||||
- frontend/editor/src/core/types/toolIO.ts
|
||||
- frontend/scripts/generate-tool-api-types.mts
|
||||
- frontend/src/editor/core/types/toolApiTypes.ts
|
||||
- frontend/src/editor/core/types/toolIO.ts
|
||||
- engine/scripts/generate_tool_models.py
|
||||
- engine/src/stirling/models/tool_models.py
|
||||
- engine/src/stirling/models/tool_io.py
|
||||
@@ -135,7 +135,7 @@ licenses-frontend: &licenses-frontend
|
||||
- ".github/workflows/frontend-backend-licenses-update.yml"
|
||||
- "frontend/package.json"
|
||||
- "frontend/package-lock.json"
|
||||
- "frontend/editor/scripts/generate-licenses.js"
|
||||
- "frontend/scripts/generate-licenses.js"
|
||||
|
||||
licenses-backend: &licenses-backend
|
||||
- ".github/workflows/frontend-backend-licenses-update.yml"
|
||||
@@ -146,8 +146,8 @@ licenses-backend: &licenses-backend
|
||||
proprietary: &proprietary
|
||||
- *ci
|
||||
- app/proprietary/**
|
||||
- frontend/editor/src/proprietary/**
|
||||
- frontend/editor/src/core/tests/enterprise/**
|
||||
- frontend/src/editor/proprietary/**
|
||||
- frontend/src/editor/core/tests/enterprise/**
|
||||
- testing/compose/docker-compose-keycloak-oauth.yml
|
||||
- testing/compose/docker-compose-keycloak-saml.yml
|
||||
- testing/compose/keycloak-realm-oauth.json
|
||||
|
||||
@@ -128,9 +128,9 @@ updates:
|
||||
|
||||
- package-ecosystem: cargo
|
||||
directories:
|
||||
- /frontend/editor/src-tauri
|
||||
- /frontend/editor/src-tauri/thumbnail-handler
|
||||
- /frontend/editor/src-tauri/provisioner
|
||||
- /frontend/src-tauri
|
||||
- /frontend/src-tauri/thumbnail-handler
|
||||
- /frontend/src-tauri/provisioner
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
cooldown:
|
||||
|
||||
@@ -51,7 +51,7 @@ labels:
|
||||
|
||||
- label: 'Translation'
|
||||
files:
|
||||
- 'frontend/editor/public/locales/[a-zA-Z]{2}-[a-zA-Z\-]{2,7}/translation.toml'
|
||||
- 'frontend/public/locales/[a-zA-Z]{2}-[a-zA-Z\-]{2,7}/translation.toml'
|
||||
- 'scripts/ignore_translation.toml'
|
||||
- 'scripts/remove_translation_keys.sh'
|
||||
- 'scripts/replace_translation_line.sh'
|
||||
@@ -70,8 +70,8 @@ labels:
|
||||
|
||||
- label: 'Tauri'
|
||||
files:
|
||||
- 'frontend/editor/src-tauri/**'
|
||||
- 'frontend/editor/src-tauri/.*'
|
||||
- 'frontend/src-tauri/**'
|
||||
- 'frontend/src-tauri/.*'
|
||||
|
||||
- label: 'engine'
|
||||
files:
|
||||
|
||||
@@ -13,7 +13,7 @@ Usage:
|
||||
"""
|
||||
|
||||
# Sample for Windows:
|
||||
# python .github/scripts/check_language_toml.py --reference-file frontend/editor/public/locales/en-US/translation.toml --branch "" --files frontend/editor/public/locales/de-DE/translation.toml frontend/editor/public/locales/fr-FR/translation.toml
|
||||
# python .github/scripts/check_language_toml.py --reference-file frontend/public/locales/en-US/translation.toml --branch "" --files frontend/public/locales/de-DE/translation.toml frontend/public/locales/fr-FR/translation.toml
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
@@ -308,7 +308,7 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
||||
report.append("## ❌ Overall Check Status: **_Failed_**")
|
||||
report.append("")
|
||||
report.append(
|
||||
f"@{actor} please check your translation if it conforms to the standard. Follow the format of [en-US/translation.toml](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/editor/public/locales/en-US/translation.toml)"
|
||||
f"@{actor} please check your translation if it conforms to the standard. Follow the format of [en-US/translation.toml](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/public/locales/en-US/translation.toml)"
|
||||
)
|
||||
else:
|
||||
report.append("## ✅ Overall Check Status: **_Success_**")
|
||||
|
||||
@@ -14,9 +14,7 @@ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
|
||||
ART_ROOT = Path(sys.argv[1])
|
||||
CONF = Path(
|
||||
sys.argv[2] if len(sys.argv) > 2 else "frontend/editor/src-tauri/tauri.conf.json"
|
||||
)
|
||||
CONF = Path(sys.argv[2] if len(sys.argv) > 2 else "frontend/src-tauri/tauri.conf.json")
|
||||
|
||||
|
||||
def load_pubkey():
|
||||
|
||||
@@ -294,7 +294,7 @@ jobs:
|
||||
if: always()
|
||||
working-directory: frontend
|
||||
run: >
|
||||
npx tsx editor/scripts/report-flaky-tests.mts
|
||||
npx tsx scripts/report-flaky-tests.mts
|
||||
"${{ github.workspace }}/frontend/playwright-report/results-oauth.json"
|
||||
"${{ github.workspace }}/frontend/playwright-report/results-saml.json"
|
||||
"${{ github.workspace }}/frontend/playwright-report/results-feature.json"
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths:
|
||||
- "frontend/editor/public/locales/*/translation.toml"
|
||||
- "frontend/public/locales/*/translation.toml"
|
||||
- ".github/scripts/check_language_toml.py"
|
||||
- ".github/workflows/check_toml.yml"
|
||||
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
# Get changed files and filter for TOML translation files
|
||||
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^frontend/editor/public/locales/[a-zA-Z-]+/translation\.toml$' > changed_files.txt || echo "No matching TOML files found in PR"
|
||||
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^frontend/public/locales/[a-zA-Z-]+/translation\.toml$' > changed_files.txt || echo "No matching TOML files found in PR"
|
||||
# Check if any files were found
|
||||
if [ ! -s changed_files.txt ]; then
|
||||
echo "No TOML translation files changed in this PR"
|
||||
@@ -166,12 +166,12 @@ jobs:
|
||||
|
||||
// Determine reference file
|
||||
let referenceFilePath;
|
||||
if (changedFiles.includes("frontend/editor/public/locales/en-US/translation.toml")) {
|
||||
if (changedFiles.includes("frontend/public/locales/en-US/translation.toml")) {
|
||||
console.log("Using PR branch reference file.");
|
||||
const { data: fileContent } = await github.rest.repos.getContent({
|
||||
owner: prRepoOwner,
|
||||
repo: prRepoName,
|
||||
path: "frontend/editor/public/locales/en-US/translation.toml",
|
||||
path: "frontend/public/locales/en-US/translation.toml",
|
||||
ref: branch,
|
||||
});
|
||||
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
const { data: fileContent } = await github.rest.repos.getContent({
|
||||
owner: repoOwner,
|
||||
repo: repoName,
|
||||
path: "frontend/editor/public/locales/en-US/translation.toml",
|
||||
path: "frontend/public/locales/en-US/translation.toml",
|
||||
ref: "main",
|
||||
});
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
# ::warning:: annotations + a job summary; never fails the job.
|
||||
if: always()
|
||||
working-directory: frontend
|
||||
run: npx tsx editor/scripts/report-flaky-tests.mts "$PLAYWRIGHT_JSON_OUTPUT_FILE"
|
||||
run: npx tsx scripts/report-flaky-tests.mts "$PLAYWRIGHT_JSON_OUTPUT_FILE"
|
||||
env:
|
||||
PLAYWRIGHT_JSON_OUTPUT_FILE: ${{ github.workspace }}/frontend/playwright-report/results.json
|
||||
- name: Generate JaCoCo report from e2e:live .exec
|
||||
@@ -230,8 +230,8 @@ jobs:
|
||||
run: |
|
||||
echo "::group::Playwright output dirs"
|
||||
# Playwright anchors its default outputDir + HTML report to the
|
||||
# nearest package.json, which is frontend/ (frontend/editor has
|
||||
# none), so artifacts land under frontend/, not frontend/editor/.
|
||||
# nearest package.json, which is frontend/ (frontend has
|
||||
# none), so artifacts land under frontend/, not frontend/.
|
||||
ls -la frontend/playwright-report 2>/dev/null \
|
||||
|| echo "no playwright-report at frontend/"
|
||||
ls -la frontend/test-results 2>/dev/null \
|
||||
@@ -246,7 +246,7 @@ jobs:
|
||||
# test-results/ holds the per-test trace.zip (with browser console
|
||||
# logs) + screenshots/video; playwright-report/ is the HTML report.
|
||||
# Both live under frontend/ (Playwright anchors them to the nearest
|
||||
# package.json, which is frontend/; frontend/editor has none).
|
||||
# package.json, which is frontend/; frontend has none).
|
||||
path: |
|
||||
frontend/playwright-report/
|
||||
frontend/test-results/
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
# ::warning:: annotations + a job summary; never fails the job.
|
||||
if: always()
|
||||
working-directory: frontend
|
||||
run: npx tsx editor/scripts/report-flaky-tests.mts "$PLAYWRIGHT_JSON_OUTPUT_FILE"
|
||||
run: npx tsx scripts/report-flaky-tests.mts "$PLAYWRIGHT_JSON_OUTPUT_FILE"
|
||||
env:
|
||||
PLAYWRIGHT_JSON_OUTPUT_FILE: ${{ github.workspace }}/frontend/playwright-report/results.json
|
||||
- name: Upload Playwright report
|
||||
|
||||
@@ -113,31 +113,31 @@ jobs:
|
||||
NPM_CONFIG_IGNORE_SCRIPTS: "true"
|
||||
working-directory: frontend
|
||||
run: |
|
||||
mkdir -p editor/src/assets
|
||||
npx --yes license-report --only=prod --output=json > editor/src/assets/3rdPartyLicenses.json
|
||||
mkdir -p src/assets
|
||||
npx --yes license-report --only=prod --output=json > src/assets/3rdPartyLicenses.json
|
||||
|
||||
- name: Postprocess with project script (BASE version)
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true
|
||||
env:
|
||||
PR_IS_FORK: "true"
|
||||
run: |
|
||||
node base/frontend/editor/scripts/generate-licenses.js \
|
||||
--input frontend/editor/src/assets/3rdPartyLicenses.json
|
||||
node base/frontend/scripts/generate-licenses.js \
|
||||
--input frontend/src/assets/3rdPartyLicenses.json
|
||||
|
||||
- name: Copy postprocessed artifacts back (fork PRs)
|
||||
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true
|
||||
run: |
|
||||
mkdir -p frontend/editor/src/assets
|
||||
if [ -f "base/frontend/editor/src/assets/3rdPartyLicenses.json" ]; then
|
||||
cp base/frontend/editor/src/assets/3rdPartyLicenses.json frontend/editor/src/assets/3rdPartyLicenses.json
|
||||
mkdir -p frontend/src/assets
|
||||
if [ -f "base/frontend/src/assets/3rdPartyLicenses.json" ]; then
|
||||
cp base/frontend/src/assets/3rdPartyLicenses.json frontend/src/assets/3rdPartyLicenses.json
|
||||
fi
|
||||
if [ -f "base/frontend/editor/src/assets/license-warnings.json" ]; then
|
||||
cp base/frontend/editor/src/assets/license-warnings.json frontend/editor/src/assets/license-warnings.json
|
||||
if [ -f "base/frontend/src/assets/license-warnings.json" ]; then
|
||||
cp base/frontend/src/assets/license-warnings.json frontend/src/assets/license-warnings.json
|
||||
fi
|
||||
|
||||
- name: Check for license warnings
|
||||
run: |
|
||||
if [ -f "frontend/editor/src/assets/license-warnings.json" ]; then
|
||||
if [ -f "frontend/src/assets/license-warnings.json" ]; then
|
||||
echo "LICENSE_WARNINGS_EXIST=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "LICENSE_WARNINGS_EXIST=false" >> $GITHUB_ENV
|
||||
@@ -185,10 +185,10 @@ jobs:
|
||||
echo ""
|
||||
if [ "${LICENSE_WARNINGS_EXIST}" = "true" ]; then
|
||||
echo "❌ **Failed** – incompatible or unknown licenses found."
|
||||
if [ -f "frontend/editor/src/assets/license-warnings.json" ]; then
|
||||
if [ -f "frontend/src/assets/license-warnings.json" ]; then
|
||||
echo ""
|
||||
echo "### Warnings"
|
||||
jq -r '.warnings[] | "- \(.message)"' frontend/editor/src/assets/license-warnings.json || true
|
||||
jq -r '.warnings[] | "- \(.message)"' frontend/src/assets/license-warnings.json || true
|
||||
fi
|
||||
else
|
||||
echo "✅ **Passed** – no license warnings detected."
|
||||
@@ -214,7 +214,7 @@ jobs:
|
||||
const fs = require('fs');
|
||||
let warningDetails = '';
|
||||
try {
|
||||
const warnings = JSON.parse(fs.readFileSync('frontend/editor/src/assets/license-warnings.json', 'utf8'));
|
||||
const warnings = JSON.parse(fs.readFileSync('frontend/src/assets/license-warnings.json', 'utf8'));
|
||||
warningDetails = warnings.warnings.map(w => `- ${w.message}`).join('\n');
|
||||
} catch (e) {
|
||||
warningDetails = 'Unable to read warning details';
|
||||
@@ -254,7 +254,7 @@ jobs:
|
||||
- name: Commit changes (Push only)
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
git add frontend/editor/src/assets/3rdPartyLicenses.json
|
||||
git add frontend/src/assets/3rdPartyLicenses.json
|
||||
# Note: Do NOT commit license-warnings.json - it's only for PR review
|
||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||
|
||||
@@ -272,7 +272,7 @@ jobs:
|
||||
|
||||
The following licenses may require review for corporate compatibility:
|
||||
|
||||
$(cat frontend/editor/src/assets/license-warnings.json | jq -r '.warnings[].message')
|
||||
$(cat frontend/src/assets/license-warnings.json | jq -r '.warnings[].message')
|
||||
|
||||
Please review these licenses to ensure they are acceptable for your use case."
|
||||
fi
|
||||
|
||||
@@ -130,19 +130,19 @@ jobs:
|
||||
run: |
|
||||
python scripts/coverage-summary.py \
|
||||
--title "Frontend Vitest coverage" \
|
||||
--vitest frontend/editor/coverage/coverage-summary.json \
|
||||
--vitest frontend/coverage/coverage-summary.json \
|
||||
--github-step-summary
|
||||
- name: Upload vitest coverage report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: frontend-coverage
|
||||
path: frontend/editor/coverage/
|
||||
path: frontend/coverage/
|
||||
retention-days: 7
|
||||
if-no-files-found: warn
|
||||
- name: Upload frontend build artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: frontend-build
|
||||
path: frontend/editor/dist/
|
||||
path: frontend/dist/
|
||||
retention-days: 3
|
||||
|
||||
@@ -441,7 +441,7 @@ jobs:
|
||||
env:
|
||||
KEYPAIR_ALIAS: ${{ secrets.SM_KEYPAIR_ALIAS }}
|
||||
run: |
|
||||
cat > ./frontend/editor/src-tauri/tauri.windows.conf.json <<EOF
|
||||
cat > ./frontend/src-tauri/tauri.windows.conf.json <<EOF
|
||||
{
|
||||
"bundle": {
|
||||
"windows": {
|
||||
@@ -454,7 +454,7 @@ jobs:
|
||||
}
|
||||
EOF
|
||||
echo "Generated tauri.windows.conf.json (alias masked):"
|
||||
sed "s/${KEYPAIR_ALIAS}/***/g" ./frontend/editor/src-tauri/tauri.windows.conf.json
|
||||
sed "s/${KEYPAIR_ALIAS}/***/g" ./frontend/src-tauri/tauri.windows.conf.json
|
||||
|
||||
- name: Import release GPG signing key (Linux)
|
||||
if: matrix.platform == 'ubuntu-22.04' && env.RELEASE_GPG_PRIVATE_KEY != '' && (github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.sign != 'false') || github.ref == 'refs/heads/V2-master')
|
||||
@@ -502,7 +502,7 @@ jobs:
|
||||
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
|
||||
CI: true
|
||||
with:
|
||||
projectPath: ./frontend/editor
|
||||
projectPath: ./frontend
|
||||
tauriScript: npx tauri
|
||||
args: ${{ matrix.args }}
|
||||
updaterJsonKeepUniversal: true
|
||||
@@ -522,7 +522,7 @@ jobs:
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: ${{ secrets.RELEASE_GPG_PASSPHRASE }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
AI=$(find "$PWD/frontend/editor/src-tauri/target" -name "*.AppImage" | head -1)
|
||||
AI=$(find "$PWD/frontend/src-tauri/target" -name "*.AppImage" | head -1)
|
||||
if [ -z "$AI" ]; then echo "No AppImage found - skipping"; exit 0; fi
|
||||
chmod +x "$AI"
|
||||
WORK=$(mktemp -d)
|
||||
@@ -579,7 +579,7 @@ jobs:
|
||||
# inner exe before packing and the setup exe after, so verifying the setup
|
||||
# exe is the arm64 equivalent of the MSI + inner-exe check below.
|
||||
if ("${{ matrix.platform }}" -eq "windows-11-arm") {
|
||||
$setupExes = Get-ChildItem -Path "./frontend/editor/src-tauri/target" -Filter "*-setup.exe" -Recurse -File
|
||||
$setupExes = Get-ChildItem -Path "./frontend/src-tauri/target" -Filter "*-setup.exe" -Recurse -File
|
||||
if ($setupExes.Count -eq 0) {
|
||||
Write-Host "[ERROR] No NSIS installer found under target/"
|
||||
exit 1
|
||||
@@ -599,7 +599,7 @@ jobs:
|
||||
$allSigned = $true
|
||||
|
||||
# Check MSI installer (outer wrapper - what users download)
|
||||
$msiFiles = Get-ChildItem -Path "./frontend/editor/src-tauri/target" -Filter "*.msi" -Recurse -File
|
||||
$msiFiles = Get-ChildItem -Path "./frontend/src-tauri/target" -Filter "*.msi" -Recurse -File
|
||||
if ($msiFiles.Count -eq 0) {
|
||||
Write-Host "[ERROR] No MSI found under target/"
|
||||
exit 1
|
||||
@@ -682,7 +682,7 @@ jobs:
|
||||
# Absolute dist path so the cd below can't break the copy targets.
|
||||
DIST="$GITHUB_WORKSPACE/dist"
|
||||
mkdir -p "$DIST"
|
||||
cd ./frontend/editor/src-tauri/target
|
||||
cd ./frontend/src-tauri/target
|
||||
|
||||
echo "=== tauri bundle artifacts ==="
|
||||
find . -path "*/bundle/*" \( -name "*.msi" -o -name "*.deb" \
|
||||
@@ -743,7 +743,7 @@ jobs:
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/scripts/verify-updater-signatures.py
|
||||
frontend/editor/src-tauri/tauri.conf.json
|
||||
frontend/src-tauri/tauri.conf.json
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Download all Tauri artifacts
|
||||
@@ -892,7 +892,7 @@ jobs:
|
||||
run: |
|
||||
python3 -m pip install --quiet 'cryptography==44.0.0'
|
||||
python3 .github/scripts/verify-updater-signatures.py \
|
||||
./artifacts/tauri frontend/editor/src-tauri/tauri.conf.json
|
||||
./artifacts/tauri frontend/src-tauri/tauri.conf.json
|
||||
|
||||
# workflow_dispatch path requires platform=='all' so a single-platform
|
||||
# dispatch can't overwrite an existing release's full latest.json with a
|
||||
|
||||
@@ -84,12 +84,12 @@ jobs:
|
||||
body: |
|
||||
Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot].
|
||||
|
||||
Regenerates `frontend/editor/src/portal/generated/docsManifest.json`
|
||||
Regenerates `frontend/src/processor/proprietary/generated/docsManifest.json`
|
||||
from the Stirling docs repo via `npm run docs:sync`.
|
||||
labels: |
|
||||
Documentation
|
||||
github-actions
|
||||
Front End
|
||||
add-paths: frontend/editor/src/portal/generated/docsManifest.json
|
||||
add-paths: frontend/src/processor/proprietary/generated/docsManifest.json
|
||||
delete-branch: true
|
||||
sign-commits: true
|
||||
|
||||
@@ -12,7 +12,7 @@ on:
|
||||
- "app/proprietary/build.gradle"
|
||||
- "gradle/spotless.gradle"
|
||||
- "README.md"
|
||||
- "frontend/editor/public/locales/*/translation.toml"
|
||||
- "frontend/public/locales/*/translation.toml"
|
||||
- "app/core/src/main/resources/static/3rdPartyLicenses.json"
|
||||
- "scripts/ignore_translation.toml"
|
||||
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
- name: Sync translation TOML files
|
||||
run: |
|
||||
python .github/scripts/check_language_toml.py --reference-file "frontend/editor/public/locales/en-US/translation.toml" --branch main
|
||||
python .github/scripts/check_language_toml.py --reference-file "frontend/public/locales/en-US/translation.toml" --branch main
|
||||
|
||||
- name: Sort translation TOML files
|
||||
run: |
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Commit translation files
|
||||
run: |
|
||||
git add frontend/editor/public/locales/*/translation.toml
|
||||
git add frontend/public/locales/*/translation.toml
|
||||
git diff --staged --quiet || git commit -m ":memo: Sync translation files (TOML)" || echo "No changes detected"
|
||||
|
||||
- name: Sync README.md
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
This Pull Request was automatically generated to synchronize updates to translation files and documentation. Below are the details of the changes made:
|
||||
|
||||
#### **1. Synchronization of Translation Files**
|
||||
- Updated translation files (`frontend/editor/public/locales/*/translation.toml`) to reflect changes in the reference file `en-US/translation.toml`.
|
||||
- Updated translation files (`frontend/public/locales/*/translation.toml`) to reflect changes in the reference file `en-US/translation.toml`.
|
||||
- Ensured consistency and synchronization across all supported language files.
|
||||
- Highlighted any missing or incomplete translations.
|
||||
- **Format**: TOML
|
||||
@@ -135,5 +135,5 @@ jobs:
|
||||
sign-commits: true
|
||||
add-paths: |
|
||||
README.md
|
||||
frontend/editor/public/locales/*/translation.toml
|
||||
frontend/public/locales/*/translation.toml
|
||||
scripts/ignore_translation.toml
|
||||
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
- name: Cache Rust build
|
||||
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
workspaces: frontend/editor/src-tauri
|
||||
workspaces: frontend/src-tauri
|
||||
# Stable key shared across workflows so the nightly warmer.
|
||||
# rust-cache still appends OS + rustc + Cargo.lock.
|
||||
shared-key: tauri-${{ matrix.name }}
|
||||
@@ -353,7 +353,7 @@ jobs:
|
||||
env:
|
||||
KEYPAIR_ALIAS: ${{ secrets.SM_KEYPAIR_ALIAS }}
|
||||
run: |
|
||||
cat > ./frontend/editor/src-tauri/tauri.windows.conf.json <<EOF
|
||||
cat > ./frontend/src-tauri/tauri.windows.conf.json <<EOF
|
||||
{
|
||||
"bundle": {
|
||||
"windows": {
|
||||
@@ -412,7 +412,7 @@ jobs:
|
||||
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
|
||||
CI: true
|
||||
with:
|
||||
projectPath: ./frontend/editor
|
||||
projectPath: ./frontend
|
||||
tauriScript: npx tauri
|
||||
# Linux: build deb+rpm only here (deb-only on minimal smoke builds).
|
||||
# AppImage runs in its own continue-on-error step below so its
|
||||
@@ -432,7 +432,7 @@ jobs:
|
||||
VITE_SAAS_BACKEND_API_URL: ${{ secrets.VITE_SAAS_BACKEND_API_URL || 'https://api.stirlingpdf.com' }}
|
||||
CI: true
|
||||
with:
|
||||
projectPath: ./frontend/editor
|
||||
projectPath: ./frontend
|
||||
tauriScript: npx tauri
|
||||
# Linux: build deb+rpm only here (deb-only on minimal smoke builds).
|
||||
# AppImage runs in its own continue-on-error step below so its
|
||||
@@ -460,7 +460,7 @@ jobs:
|
||||
VITE_SAAS_BACKEND_API_URL: ${{ secrets.VITE_SAAS_BACKEND_API_URL || 'https://api.stirlingpdf.com' }}
|
||||
CI: true
|
||||
with:
|
||||
projectPath: ./frontend/editor
|
||||
projectPath: ./frontend
|
||||
tauriScript: npx tauri
|
||||
args: --bundles appimage
|
||||
|
||||
@@ -472,7 +472,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set -euo pipefail
|
||||
AI=$(find "$PWD/frontend/editor/src-tauri/target" -name "*.AppImage" | head -1)
|
||||
AI=$(find "$PWD/frontend/src-tauri/target" -name "*.AppImage" | head -1)
|
||||
if [ -z "$AI" ]; then echo "No AppImage found - skipping"; exit 0; fi
|
||||
chmod +x "$AI"
|
||||
WORK=$(mktemp -d)
|
||||
@@ -509,7 +509,7 @@ jobs:
|
||||
if: env.SIGN_BUNDLE == 'true' && matrix.platform == 'macos-15'
|
||||
run: |
|
||||
echo "🔍 Verifying notarization status..."
|
||||
cd ./frontend/editor/src-tauri/target
|
||||
cd ./frontend/src-tauri/target
|
||||
DMG_FILE=$(find . -name "*.dmg" | head -1)
|
||||
if [ -n "$DMG_FILE" ]; then
|
||||
echo "Found DMG: $DMG_FILE"
|
||||
@@ -526,7 +526,7 @@ jobs:
|
||||
# Absolute dist path so the cd below can't break the copy targets.
|
||||
DIST="$GITHUB_WORKSPACE/dist"
|
||||
mkdir -p "$DIST"
|
||||
cd ./frontend/editor/src-tauri/target
|
||||
cd ./frontend/src-tauri/target
|
||||
|
||||
# Find and rename artifacts based on platform
|
||||
if [ "${{ matrix.platform }}" = "windows-latest" ]; then
|
||||
@@ -638,7 +638,7 @@ jobs:
|
||||
- name: Verify build artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./frontend/editor/src-tauri/target
|
||||
cd ./frontend/src-tauri/target
|
||||
|
||||
# Check for expected artifacts based on platform
|
||||
if [ "${{ matrix.platform }}" = "windows-latest" ] || [ "${{ matrix.platform }}" = "windows-11-arm" ]; then
|
||||
@@ -669,7 +669,7 @@ jobs:
|
||||
- name: Test artifact sizes
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./frontend/editor/src-tauri/target
|
||||
cd ./frontend/src-tauri/target
|
||||
echo "Artifact sizes for ${{ matrix.name }}:"
|
||||
find . -name "*.exe" -o -name "*.dmg" -o -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" -o -name "*.msi" | while read file; do
|
||||
if [ -f "$file" ]; then
|
||||
|
||||
+7
-4
@@ -22,6 +22,9 @@ pipeline/
|
||||
customFiles/
|
||||
configs/
|
||||
watchedFolders/
|
||||
# The rule above targets the app's runtime watched-folders working dir, but it
|
||||
# also matches this frontend source component dir; keep the source tracked.
|
||||
!frontend/src/editor/proprietary/components/watchedFolders/
|
||||
clientWebUI/
|
||||
# Scratch dir used by local fixture-regeneration runs (see
|
||||
# app/proprietary/src/test/resources/db-migration-fixtures/README.md).
|
||||
@@ -171,7 +174,7 @@ app/proprietary/build
|
||||
common/build
|
||||
proprietary/build
|
||||
stirling-pdf/build
|
||||
frontend/editor/src-tauri/provisioner/target
|
||||
frontend/src-tauri/provisioner/target
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
@@ -222,7 +225,7 @@ out/
|
||||
*.asc
|
||||
|
||||
# Allow test fixture certificates (synthetic, no real credentials)
|
||||
!frontend/editor/src/core/tests/test-fixtures/certs/**
|
||||
!frontend/src/editor/core/tests/test-fixtures/certs/**
|
||||
|
||||
# SSH Keys
|
||||
*.pub
|
||||
@@ -264,7 +267,7 @@ node_modules/
|
||||
*compact*.json
|
||||
test_batch.json
|
||||
*.backup.*.json
|
||||
frontend/editor/public/locales/*/translation.backup*.json
|
||||
frontend/public/locales/*/translation.backup*.json
|
||||
|
||||
# Development/build artifacts
|
||||
.gradle-cache/
|
||||
@@ -289,4 +292,4 @@ docs/type3/signatures/
|
||||
*.playwright-mcp.png
|
||||
|
||||
# Local screenshot artifacts from *-screenshots.spec.ts
|
||||
frontend/editor/screenshots/
|
||||
frontend/screenshots/
|
||||
|
||||
+2
-2
@@ -15,10 +15,10 @@ testing/compose/validate-mcp-test.sh:curl-auth-header:92
|
||||
testing/compose/validate-mcp-test.sh:curl-auth-header:116
|
||||
|
||||
# Storybook example showing curl with a fake Bearer token placeholder (sk_live_a3f8...).
|
||||
frontend/editor/src/proprietary/ui/CodeBlock.stories.tsx:curl-auth-header:5
|
||||
frontend/src/editor/proprietary/ui/CodeBlock.stories.tsx:curl-auth-header:5
|
||||
|
||||
# Truncated placeholder API key in portal docs example (sk_live_8f2c...e10) - not a real secret.
|
||||
frontend/editor/src/portal/components/docs/GettingStartedSection.tsx:generic-api-key:30
|
||||
frontend/src/processor/proprietary/components/docs/GettingStartedSection.tsx:generic-api-key:30
|
||||
|
||||
# False positive: generic-api-key matches the Java type name "X509Certificate"
|
||||
# in a method signature (CreateSignatureBase.resolveSignatureAlgorithm) - not a secret.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"ignoredFiles": [
|
||||
"frontend/editor/src-tauri/icons/icon.png"
|
||||
"frontend/src-tauri/icons/icon.png"
|
||||
]
|
||||
}
|
||||
|
||||
+6
-16
@@ -39,7 +39,6 @@ tasks:
|
||||
provisioner:
|
||||
desc: "Build installer provisioner"
|
||||
platforms: [windows]
|
||||
dir: editor
|
||||
cmds:
|
||||
- node scripts/build-provisioner.mjs
|
||||
|
||||
@@ -47,55 +46,48 @@ tasks:
|
||||
desc: "Start Tauri desktop dev mode"
|
||||
deps: [prepare]
|
||||
ignore_error: true
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri dev --no-watch
|
||||
|
||||
build:
|
||||
desc: "Build Tauri desktop app (production)"
|
||||
deps: [prepare]
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri build
|
||||
|
||||
build:dev:
|
||||
desc: "Build Tauri desktop app (dev, no bundling)"
|
||||
deps: [prepare]
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri build --no-bundle
|
||||
|
||||
build:dev:mac:
|
||||
desc: "Build Tauri desktop .app bundle (macOS)"
|
||||
deps: [prepare]
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri build --bundles app --config '{"bundle":{"createUpdaterArtifacts":false}}'
|
||||
|
||||
build:dev:windows:
|
||||
desc: "Build Tauri desktop NSIS installer (Windows)"
|
||||
deps: [prepare]
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri build --bundles nsis --config '{"bundle":{"createUpdaterArtifacts":false}}'
|
||||
|
||||
build:dev:linux:
|
||||
desc: "Build Tauri desktop AppImage (Linux)"
|
||||
deps: [prepare]
|
||||
dir: editor
|
||||
cmds:
|
||||
- npx tauri build --bundles appimage --config '{"bundle":{"createUpdaterArtifacts":false}}'
|
||||
|
||||
test:
|
||||
desc: "Run Tauri/Cargo tests"
|
||||
deps: [prepare]
|
||||
dir: editor/src-tauri
|
||||
dir: src-tauri
|
||||
cmds:
|
||||
- cargo test
|
||||
|
||||
clean:
|
||||
desc: "Clean Tauri/Cargo build artifacts"
|
||||
dir: editor
|
||||
cmds:
|
||||
- task: jlink:clean
|
||||
- cd src-tauri && cargo clean
|
||||
@@ -117,7 +109,6 @@ tasks:
|
||||
|
||||
jlink:verify:
|
||||
desc: "Fail the build if the bundled JRE is older than the app JAR requires"
|
||||
dir: editor
|
||||
env:
|
||||
REQUIRED_JAVA: "{{.REQUIRED_JAVA}}"
|
||||
cmds:
|
||||
@@ -135,15 +126,15 @@ tasks:
|
||||
platforms: [windows]
|
||||
- cmd: ./gradlew bootJar --no-daemon -PjpdfiumPlatforms={{.JPDFIUM_PLATFORMS}}
|
||||
platforms: [linux, darwin]
|
||||
- mkdir -p frontend/editor/src-tauri/libs
|
||||
- cp app/core/build/libs/stirling-pdf-*.jar frontend/editor/src-tauri/libs/
|
||||
- mkdir -p frontend/src-tauri/libs
|
||||
- cp app/core/build/libs/stirling-pdf-*.jar frontend/src-tauri/libs/
|
||||
status:
|
||||
- test -f frontend/editor/src-tauri/libs/stirling-pdf-*.jar
|
||||
- test -f frontend/src-tauri/libs/stirling-pdf-*.jar
|
||||
|
||||
jlink:runtime:
|
||||
desc: "Create custom JRE with jlink"
|
||||
deps: [jlink:jar]
|
||||
dir: editor/src-tauri
|
||||
dir: src-tauri
|
||||
cmds:
|
||||
- rm -rf runtime/jre
|
||||
- mkdir -p runtime
|
||||
@@ -202,7 +193,7 @@ tasks:
|
||||
|
||||
jlink:clean:
|
||||
desc: "Remove JLink runtime and bundled JARs"
|
||||
dir: editor/src-tauri
|
||||
dir: src-tauri
|
||||
cmds:
|
||||
- rm -rf libs runtime
|
||||
|
||||
@@ -215,7 +206,6 @@ tasks:
|
||||
desc: "Create universal (arm64+x86_64) JRE for the macOS Tauri build"
|
||||
deps: [jlink:jar]
|
||||
platforms: [darwin]
|
||||
dir: editor
|
||||
env:
|
||||
JLINK_MODULES: "{{.JLINK_MODULES}}"
|
||||
OUTPUT_DIR: src-tauri/runtime/jre
|
||||
|
||||
+5
-5
@@ -3,14 +3,14 @@ version: '3'
|
||||
tasks:
|
||||
install:
|
||||
desc: "Install Playwright browsers"
|
||||
dir: frontend/editor
|
||||
dir: frontend
|
||||
deps: [ ':frontend:install' ]
|
||||
cmds:
|
||||
- npx playwright install {{.CLI_ARGS}} --with-deps
|
||||
|
||||
stubbed:
|
||||
desc: "Run stubbed E2E tests"
|
||||
dir: frontend/editor
|
||||
dir: frontend
|
||||
deps: [ ':frontend:prepare' ]
|
||||
cmds:
|
||||
- npx playwright test --project=stubbed {{.CLI_ARGS}}
|
||||
@@ -82,7 +82,7 @@ tasks:
|
||||
live:runner:
|
||||
internal: true
|
||||
deps: [ ':frontend:prepare' ]
|
||||
dir: frontend/editor
|
||||
dir: frontend
|
||||
vars:
|
||||
BASE_DIR: '{{.ROOT_DIR}}/.test-state/playwright'
|
||||
cmds:
|
||||
@@ -151,14 +151,14 @@ tasks:
|
||||
up first with:
|
||||
task e2e:oauth:up
|
||||
task e2e:saml:up
|
||||
dir: frontend/editor
|
||||
dir: frontend
|
||||
deps: [ ':frontend:prepare' ]
|
||||
cmds:
|
||||
- npx playwright test --project=enterprise {{.CLI_ARGS}}
|
||||
|
||||
cross-browser:
|
||||
desc: "Run stubbed E2E tests on Chromium, Firefox, and WebKit"
|
||||
dir: frontend/editor
|
||||
dir: frontend
|
||||
deps: [ ':frontend:prepare' ]
|
||||
cmds:
|
||||
- npx playwright test --project=stubbed --project=stubbed-firefox --project=stubbed-webkit {{.CLI_ARGS}}
|
||||
|
||||
+49
-49
@@ -3,7 +3,7 @@ version: '3'
|
||||
# Tasks operate from the workspace root (frontend/). Editor commands pass
|
||||
# `editor` as the vite project root (positional after `build` / before the
|
||||
# mode flag) or use `--project editor/...` for tsc — so the editor lives
|
||||
# under frontend/editor/ without each task needing a cd.
|
||||
# under frontend/ without each task needing a cd.
|
||||
|
||||
tasks:
|
||||
install:
|
||||
@@ -26,34 +26,34 @@ tasks:
|
||||
vars:
|
||||
MODE: '{{.MODE | default ""}}'
|
||||
cmds:
|
||||
- npx tsx editor/scripts/setup-env.mts{{if .MODE}} --{{.MODE}}{{end}}
|
||||
- npx tsx scripts/setup-env.mts{{if .MODE}} --{{.MODE}}{{end}}
|
||||
sources:
|
||||
- editor/scripts/setup-env.mts
|
||||
- scripts/setup-env.mts
|
||||
generates:
|
||||
- editor/.env.local
|
||||
- editor/.env{{if .MODE}}.{{.MODE}}{{end}}.local
|
||||
- .env.local
|
||||
- .env{{if .MODE}}.{{.MODE}}{{end}}.local
|
||||
|
||||
prepare:icons:
|
||||
internal: true
|
||||
run: once
|
||||
deps: [install]
|
||||
cmds:
|
||||
- node editor/scripts/generate-icons.js
|
||||
- node scripts/generate-icons.js
|
||||
|
||||
prepare:og:
|
||||
internal: true
|
||||
run: when_changed
|
||||
desc: "Regenerate OG/social-preview metadata from the tool registry"
|
||||
cmds:
|
||||
- node editor/scripts/generate-og-metadata.mjs
|
||||
- node scripts/generate-og-metadata.mjs
|
||||
sources:
|
||||
- editor/src/core/types/toolId.ts
|
||||
- editor/src/core/utils/urlMapping.ts
|
||||
- editor/src/core/data/useTranslatedToolRegistry.tsx
|
||||
- editor/public/og_images/*.png
|
||||
- src/editor/core/types/toolId.ts
|
||||
- src/editor/core/utils/urlMapping.ts
|
||||
- src/editor/core/data/useTranslatedToolRegistry.tsx
|
||||
- public/og_images/*.png
|
||||
generates:
|
||||
- editor/src/core/data/ogImageMap.json
|
||||
- editor/public/og-metadata.json
|
||||
- src/editor/core/data/ogImageMap.json
|
||||
- public/og-metadata.json
|
||||
|
||||
prepare:
|
||||
desc: "Set up dev environment"
|
||||
@@ -88,7 +88,7 @@ tasks:
|
||||
sh: >-
|
||||
{{if eq OS "windows"}}powershell -NoProfile -Command '$root = git rev-parse --show-toplevel 2>$null; if (-not $root) { $root = (Get-Location).Path }; Split-Path -Leaf $root'{{else}}basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"{{end}}
|
||||
cmds:
|
||||
- npx vite editor --mode {{.MODE}} --port {{.PORT}}{{if .OPEN}} --open{{end}}
|
||||
- npx vite --mode {{.MODE}} --port {{.PORT}}{{if .OPEN}} --open{{end}}
|
||||
|
||||
dev:
|
||||
desc: "Start frontend dev server"
|
||||
@@ -143,13 +143,13 @@ tasks:
|
||||
desc: "Production build (default mode)"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- npx vite build editor
|
||||
- npx vite build
|
||||
|
||||
build:core:
|
||||
desc: "Build for core mode"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- npx vite build editor --mode core
|
||||
- npx vite build --mode core
|
||||
|
||||
build:proprietary:
|
||||
desc: "Build for proprietary mode"
|
||||
@@ -157,7 +157,7 @@ tasks:
|
||||
vars:
|
||||
PREVIEW: '{{.PREVIEW | default ""}}'
|
||||
cmds:
|
||||
- '{{if .PREVIEW}}VITE_BUILD_FOR_PREVIEW=1 {{end}}npx vite build editor --mode proprietary'
|
||||
- '{{if .PREVIEW}}VITE_BUILD_FOR_PREVIEW=1 {{end}}npx vite build --mode proprietary'
|
||||
|
||||
build:saas:
|
||||
desc: "Build for SaaS mode"
|
||||
@@ -165,7 +165,7 @@ tasks:
|
||||
- task: prepare
|
||||
vars: { MODE: saas }
|
||||
cmds:
|
||||
- npx vite build editor --mode saas
|
||||
- npx vite build --mode saas
|
||||
|
||||
build:desktop:
|
||||
desc: "Build for desktop mode"
|
||||
@@ -173,13 +173,13 @@ tasks:
|
||||
- task: prepare
|
||||
vars: { MODE: desktop }
|
||||
cmds:
|
||||
- npx vite build editor --mode desktop
|
||||
- npx vite build --mode desktop
|
||||
|
||||
build:prototypes:
|
||||
desc: "Build for prototypes mode"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- npx vite build editor --mode prototypes
|
||||
- npx vite build --mode prototypes
|
||||
|
||||
|
||||
storybook:
|
||||
@@ -272,23 +272,23 @@ tasks:
|
||||
# Covers the whole editor tree, including the portal/processor layer and
|
||||
# public/css. Vendored CSS and build output are excluded via ignoreFiles
|
||||
# in stylelint.config.mjs.
|
||||
- npx stylelint "editor/**/*.css"
|
||||
- npx stylelint "src/**/*.css"
|
||||
|
||||
lint:colors:
|
||||
desc: "Enforce theme tokens — no hardcoded colours or raw primitives in components"
|
||||
aliases: [lint:colours]
|
||||
deps: [install]
|
||||
cmds:
|
||||
- node editor/scripts/lint/theme-lint.mjs
|
||||
- node editor/scripts/lint/theme-lint.mjs css-colors
|
||||
- node editor/scripts/lint/theme-lint.mjs code-colors
|
||||
- node editor/scripts/lint/theme-lint.mjs no-primitives
|
||||
- node scripts/lint/theme-lint.mjs
|
||||
- node scripts/lint/theme-lint.mjs css-colors
|
||||
- node scripts/lint/theme-lint.mjs code-colors
|
||||
- node scripts/lint/theme-lint.mjs no-primitives
|
||||
|
||||
contrast:
|
||||
desc: "Report low-contrast theme token pairs (warning only, never blocks)"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- node editor/scripts/lint/theme-lint.mjs contrast
|
||||
- node scripts/lint/theme-lint.mjs contrast
|
||||
|
||||
lint:eslint:
|
||||
desc: "Run ESLint linting"
|
||||
@@ -302,7 +302,7 @@ tasks:
|
||||
cmds:
|
||||
# Globs so dpdm walks the whole tree. dpdm expands the braces itself, so this is
|
||||
# shell-agnostic. Covers the whole editor tree, including the portal layer.
|
||||
- npx dpdm "editor/src/**/*.{ts,tsx}" --circular --no-warning --no-tree --exit-code circular:1
|
||||
- npx dpdm "src/**/*.{ts,tsx}" --circular --no-warning --no-tree --exit-code circular:1
|
||||
|
||||
lint:fix:
|
||||
desc: "Auto-fix lint issues"
|
||||
@@ -343,14 +343,14 @@ tasks:
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/core/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/core/tsconfig.json }
|
||||
|
||||
typecheck:proprietary:
|
||||
desc: "Typecheck proprietary build variant"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/proprietary/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/proprietary/tsconfig.json }
|
||||
|
||||
typecheck:saas:
|
||||
desc: "Typecheck SaaS build variant"
|
||||
@@ -359,7 +359,7 @@ tasks:
|
||||
vars: { MODE: saas }
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/saas/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/saas/tsconfig.json }
|
||||
|
||||
typecheck:desktop:
|
||||
desc: "Typecheck desktop build variant"
|
||||
@@ -368,35 +368,35 @@ tasks:
|
||||
vars: { MODE: desktop }
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/desktop/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/desktop/tsconfig.json }
|
||||
|
||||
typecheck:cloud:
|
||||
desc: "Typecheck cloud shared layer (standalone)"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/cloud/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/cloud/tsconfig.json }
|
||||
|
||||
typecheck:scripts:
|
||||
desc: "Typecheck scripts"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/scripts/tsconfig.json }
|
||||
vars: { PROJECT: scripts/tsconfig.json }
|
||||
|
||||
typecheck:prototypes:
|
||||
desc: "Typecheck prototypes build variant"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/prototypes/tsconfig.json }
|
||||
vars: { PROJECT: src/editor/prototypes/tsconfig.json }
|
||||
|
||||
typecheck:portal:
|
||||
desc: "Typecheck developer portal build variant"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- task: typecheck:_run
|
||||
vars: { PROJECT: editor/src/portal/tsconfig.json }
|
||||
vars: { PROJECT: src/processor/proprietary/tsconfig.json }
|
||||
|
||||
typecheck:storybook:
|
||||
desc: "Typecheck Storybook config and stories"
|
||||
@@ -433,7 +433,7 @@ tasks:
|
||||
og:check:
|
||||
desc: "Fail if committed OG/social-preview metadata is out of date"
|
||||
cmds:
|
||||
- node editor/scripts/generate-og-metadata.mjs --check
|
||||
- node scripts/generate-og-metadata.mjs --check
|
||||
|
||||
check:all:
|
||||
desc: "Full CI quality gate"
|
||||
@@ -461,13 +461,13 @@ tasks:
|
||||
desc: "Run editor tests"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- npx vitest run --root editor
|
||||
- npx vitest run --root .
|
||||
|
||||
test:watch:
|
||||
desc: "Run tests in watch mode"
|
||||
deps: [prepare]
|
||||
cmds:
|
||||
- npx vitest --watch --root editor
|
||||
- npx vitest --watch --root .
|
||||
|
||||
test:coverage:
|
||||
desc: "Run tests with coverage (one-shot; CI-friendly)."
|
||||
@@ -478,12 +478,12 @@ tasks:
|
||||
# coverage-summary.py helper consumes; html/text are kept for humans.
|
||||
#
|
||||
# reportsDirectory is pinned to ./coverage relative to vitest's root
|
||||
# (--root editor), so output lands at frontend/editor/coverage/. The
|
||||
# (--root .), so output lands at frontend/coverage/. The
|
||||
# CI upload step reads from that path. An earlier attempt with
|
||||
# `./editor/coverage` double-nested into frontend/editor/editor/coverage;
|
||||
# `./editor/coverage` double-nested into frontend/coverage;
|
||||
# pinning future-proofs against vitest changing the default.
|
||||
- >
|
||||
npx vitest run --root editor --coverage
|
||||
npx vitest run --root . --coverage
|
||||
--coverage.provider=v8
|
||||
--coverage.reporter=text-summary
|
||||
--coverage.reporter=json-summary
|
||||
@@ -498,25 +498,25 @@ tasks:
|
||||
desc: "Generate tool API types from the Java OpenAPI spec"
|
||||
deps: [install, ":backend:swagger"]
|
||||
cmds:
|
||||
- npx tsx editor/scripts/generate-tool-api-types.mts --spec ../SwaggerDoc.json --output editor/src/core/types/toolApiTypes.ts --io-output editor/src/core/types/toolIO.ts
|
||||
- npx tsx scripts/generate-tool-api-types.mts --spec ../SwaggerDoc.json --output src/editor/core/types/toolApiTypes.ts --io-output src/editor/core/types/toolIO.ts
|
||||
sources:
|
||||
- editor/scripts/generate-tool-api-types.mts
|
||||
- scripts/generate-tool-api-types.mts
|
||||
- ../SwaggerDoc.json
|
||||
generates:
|
||||
- editor/src/core/types/toolApiTypes.ts
|
||||
- editor/src/core/types/toolIO.ts
|
||||
- src/editor/core/types/toolApiTypes.ts
|
||||
- src/editor/core/types/toolIO.ts
|
||||
|
||||
tool-models:check:
|
||||
desc: "Fail if committed tool API types are out of date"
|
||||
deps: [install, ":backend:swagger"]
|
||||
cmds:
|
||||
- npx tsx editor/scripts/generate-tool-api-types.mts --spec ../SwaggerDoc.json --output editor/src/core/types/toolApiTypes.ts --io-output editor/src/core/types/toolIO.ts --check
|
||||
- npx tsx scripts/generate-tool-api-types.mts --spec ../SwaggerDoc.json --output src/editor/core/types/toolApiTypes.ts --io-output src/editor/core/types/toolIO.ts --check
|
||||
|
||||
licenses:generate:
|
||||
desc: "Generate frontend license report"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- node editor/scripts/generate-licenses.js
|
||||
- node scripts/generate-licenses.js
|
||||
|
||||
# ============================================================
|
||||
# Clean
|
||||
@@ -525,7 +525,7 @@ tasks:
|
||||
clean:
|
||||
desc: "Clean build artifacts and caches"
|
||||
cmds:
|
||||
- cmd: powershell rm -Recurse -Force -ErrorAction SilentlyContinue node_modules/.vite, editor/dist, dist
|
||||
- cmd: powershell rm -Recurse -Force -ErrorAction SilentlyContinue node_modules/.vite, dist, dist
|
||||
platforms: [windows]
|
||||
- cmd: rm -rf node_modules/.vite editor/dist dist
|
||||
- cmd: rm -rf node_modules/.vite dist dist
|
||||
platforms: [linux, darwin]
|
||||
|
||||
@@ -21,7 +21,7 @@ vars:
|
||||
':(exclude).devcontainer/*'
|
||||
':(exclude)app/core/src/main/resources/*'
|
||||
':(exclude)app/proprietary/src/main/resources/*'
|
||||
':(exclude)frontend/editor/public/vendor/*'
|
||||
':(exclude)frontend/public/vendor/*'
|
||||
':(exclude)*Dockerfile*'
|
||||
':(exclude)*pdfjs*'
|
||||
':(exclude)*thirdParty*'
|
||||
@@ -39,7 +39,7 @@ vars:
|
||||
':(exclude)*.min.*'
|
||||
':(exclude)*diff.js'
|
||||
':(exclude).github/workflows/*'
|
||||
LOCALE_TOML: 'frontend/editor/public/locales/*/translation.toml'
|
||||
LOCALE_TOML: 'frontend/public/locales/*/translation.toml'
|
||||
|
||||
# gitleaks is pinned + checksum-verified by scripts/pre-commit/install_gitleaks.py,
|
||||
# which owns the version and caches the binary here.
|
||||
|
||||
+6
-6
@@ -10,14 +10,14 @@ When adding tools, follow this systematic approach using the established pattern
|
||||
|
||||
Create these files in the correct directories:
|
||||
```
|
||||
frontend/editor/src/hooks/tools/[toolName]/
|
||||
frontend/src/hooks/tools/[toolName]/
|
||||
├── use[ToolName]Parameters.ts # Parameter definitions and validation
|
||||
└── use[ToolName]Operation.ts # Tool operation logic using useToolOperation
|
||||
|
||||
frontend/editor/src/components/tools/[toolName]/
|
||||
frontend/src/components/tools/[toolName]/
|
||||
└── [ToolName]Settings.tsx # Settings UI component (if needed)
|
||||
|
||||
frontend/editor/src/tools/
|
||||
frontend/src/tools/
|
||||
└── [ToolName].tsx # Main tool component
|
||||
```
|
||||
|
||||
@@ -128,7 +128,7 @@ export default [ToolName] as ToolComponent;
|
||||
## 3. Register Tool in System
|
||||
Update these files to register your new tool:
|
||||
|
||||
**Tool Registry** (`frontend/editor/src/data/useTranslatedToolRegistry.tsx`):
|
||||
**Tool Registry** (`frontend/src/data/useTranslatedToolRegistry.tsx`):
|
||||
1. Add imports at the top:
|
||||
```typescript
|
||||
import [ToolName] from "../tools/[ToolName]";
|
||||
@@ -155,7 +155,7 @@ import [ToolName]Settings from "../components/tools/[toolName]/[ToolName]Setting
|
||||
## 4. Add Tooltips (Optional but Recommended)
|
||||
Create user-friendly tooltips to help non-technical users understand your tool. **Use simple, clear language - avoid technical jargon:**
|
||||
|
||||
**Tooltip Hook** (`frontend/editor/src/components/tooltips/use[ToolName]Tips.ts`):
|
||||
**Tooltip Hook** (`frontend/src/components/tooltips/use[ToolName]Tips.ts`):
|
||||
```typescript
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TooltipContent } from '../../types/tips';
|
||||
@@ -202,7 +202,7 @@ const [ToolName] = (props: BaseToolProps) => {
|
||||
## 5. Add Translations
|
||||
Update translation files. **Important: Only update `en-US` files** - other languages are handled separately.
|
||||
|
||||
**File to update:** `frontend/editor/public/locales/en-US/translation.toml`
|
||||
**File to update:** `frontend/public/locales/en-US/translation.toml`
|
||||
|
||||
**Required Translation Keys**:
|
||||
```toml
|
||||
|
||||
@@ -139,10 +139,10 @@ The project structure is defined in `engine/pyproject.toml`. Any new dependencie
|
||||
|
||||
#### Environment Variables
|
||||
- All `VITE_*` variables must be declared in the appropriate committed env file:
|
||||
- `frontend/editor/.env` — core and shared vars (base, loaded in every mode)
|
||||
- `frontend/editor/.env.proprietary` — proprietary-only vars, e.g. the admin portal's SaaS/account-link keys (layered on top of `.env` in proprietary mode)
|
||||
- `frontend/editor/.env.saas` — SaaS-only vars (layered on top of `.env` in SaaS mode)
|
||||
- `frontend/editor/.env.desktop` — desktop (Tauri)-only vars (layered on top of `.env` in desktop mode)
|
||||
- `frontend/.env` — core and shared vars (base, loaded in every mode)
|
||||
- `frontend/.env.proprietary` — proprietary-only vars, e.g. the admin portal's SaaS/account-link keys (layered on top of `.env` in proprietary mode)
|
||||
- `frontend/.env.saas` — SaaS-only vars (layered on top of `.env` in SaaS mode)
|
||||
- `frontend/.env.desktop` — desktop (Tauri)-only vars (layered on top of `.env` in desktop mode)
|
||||
- These files are committed to Git and must not contain private keys
|
||||
- Local overrides (API keys, machine-specific settings) go in uncommitted sibling `.env.local` / `.env.saas.local` / `.env.desktop.local` files — Vite automatically layers them on top
|
||||
- Never use `|| 'hardcoded-fallback'` inline — put defaults in the committed env files
|
||||
@@ -153,9 +153,9 @@ The project structure is defined in `engine/pyproject.toml`. Any new dependencie
|
||||
#### Import Paths - CRITICAL
|
||||
**ALWAYS use `@app/*` for imports.** Do not use `@core/*` or `@proprietary/*` unless explicitly wrapping/extending a lower layer implementation.
|
||||
|
||||
For a broader explanation of the frontend layering and override architecture, read @frontend/editor/DeveloperGuide.md
|
||||
For a broader explanation of the frontend layering and override architecture, read @frontend/DeveloperGuide.md
|
||||
|
||||
Before touching colours or theming (tokens, dark mode, accent colours), read @frontend/editor/src/core/theme/README.md — it explains the palette/`--c-*` token system and the rule that literal colours live only in `primitives.css`.
|
||||
Before touching colours or theming (tokens, dark mode, accent colours), read @frontend/src/editor/core/theme/README.md — it explains the palette/`--c-*` token system and the rule that literal colours live only in `primitives.css`.
|
||||
|
||||
```typescript
|
||||
// ✅ CORRECT - Use @app/* for all imports
|
||||
@@ -270,7 +270,7 @@ Frontend designed for **stateful document processing**:
|
||||
- No file reloading between tools - performance critical for large PDFs (up to 100GB+)
|
||||
|
||||
#### FileContext - Central State Management
|
||||
**Location**: `frontend/editor/src/core/contexts/FileContext.tsx`
|
||||
**Location**: `frontend/src/editor/core/contexts/FileContext.tsx`
|
||||
- **Active files**: Currently loaded PDFs and their variants
|
||||
- **Tool navigation**: Current mode (viewer/pageEditor/fileEditor/toolName)
|
||||
- **Memory management**: PDF document cleanup, blob URL lifecycle, Web Worker management
|
||||
@@ -295,7 +295,7 @@ Without cleanup: browser crashes with memory leaks.
|
||||
|
||||
**Architecture**: Modular hook-based system with clear separation of concerns:
|
||||
|
||||
- **useToolOperation** (`frontend/editor/src/core/hooks/tools/shared/useToolOperation.ts`): Main orchestrator hook
|
||||
- **useToolOperation** (`frontend/src/editor/core/hooks/tools/shared/useToolOperation.ts`): Main orchestrator hook
|
||||
- Coordinates all tool operations with consistent interface
|
||||
- Integrates with FileContext for operation tracking
|
||||
- Handles validation, error handling, and UI state management
|
||||
@@ -383,7 +383,7 @@ return useToolOperation({
|
||||
### Frontend Directory Structure
|
||||
The frontend is organized with a clear separation of concerns:
|
||||
|
||||
- **`frontend/editor/src/core/`**: Main application code (shared, production-ready components)
|
||||
- **`frontend/src/editor/core/`**: Main application code (shared, production-ready components)
|
||||
- **`core/components/`**: React components organized by feature
|
||||
- `core/components/tools/`: Individual PDF tool implementations
|
||||
- `core/components/viewer/`: PDF viewer components
|
||||
@@ -401,17 +401,17 @@ The frontend is organized with a clear separation of concerns:
|
||||
- **`core/data/`**: Static data (tool taxonomy, etc.)
|
||||
- **`core/services/`**: Business logic services (PDF processing, storage, etc.)
|
||||
|
||||
- **`frontend/editor/src/desktop/`**: Desktop-specific (Tauri) code
|
||||
- **`frontend/editor/src/proprietary/`**: Proprietary/licensed features
|
||||
- **`frontend/editor/src-tauri/`**: Tauri (Rust) native desktop application code
|
||||
- **`frontend/editor/public/`**: Static assets served directly
|
||||
- **`frontend/src/editor/desktop/`**: Desktop-specific (Tauri) code
|
||||
- **`frontend/src/editor/proprietary/`**: Proprietary/licensed features
|
||||
- **`frontend/src-tauri/`**: Tauri (Rust) native desktop application code
|
||||
- **`frontend/public/`**: Static assets served directly
|
||||
- `public/locales/`: Translation JSON files
|
||||
|
||||
### Component Architecture
|
||||
- **Static Assets**: CSS, JS, and resources in `src/main/resources/static/` (legacy) + `frontend/editor/public/` (modern)
|
||||
- **Static Assets**: CSS, JS, and resources in `src/main/resources/static/` (legacy) + `frontend/public/` (modern)
|
||||
- **Internationalization**:
|
||||
- Backend: `messages_*.properties` files
|
||||
- Frontend: JSON files in `frontend/editor/public/locales/` (converted from .properties)
|
||||
- Frontend: JSON files in `frontend/public/locales/` (converted from .properties)
|
||||
- Conversion Script: `scripts/convert_properties_to_json.py`
|
||||
|
||||
### Configuration Modes
|
||||
@@ -436,7 +436,7 @@ The frontend is organized with a clear separation of concerns:
|
||||
4. **Code Style**: Spotless enforces Google Java Format automatically (`task backend:format`)
|
||||
5. **Translations**:
|
||||
- Backend: Use helper scripts in `/scripts` for multi-language updates
|
||||
- Frontend: Update JSON files in `frontend/editor/public/locales/` or use conversion script
|
||||
- Frontend: Update JSON files in `frontend/public/locales/` or use conversion script
|
||||
6. **Documentation**: API docs auto-generated and available at `/swagger-ui/index.html`
|
||||
|
||||
## Frontend Architecture Status
|
||||
@@ -454,7 +454,7 @@ The frontend is organized with a clear separation of concerns:
|
||||
## Translation Rules
|
||||
|
||||
- **CRITICAL**: Always update translations in `en-US` only - all other languages (including `en-GB`) are handled separately
|
||||
- Translation files are located in `frontend/editor/public/locales/`
|
||||
- Translation files are located in `frontend/public/locales/`
|
||||
- After changing any translation file, run `task pre-commit:fix`
|
||||
|
||||
## Important Notes
|
||||
|
||||
+1
-1
@@ -458,7 +458,7 @@ For Stirling 2.0, new features are built as React components:
|
||||
|
||||
1. **Create the React Component:**
|
||||
```typescript
|
||||
// frontend/editor/src/tools/NewTool.tsx
|
||||
// frontend/src/tools/NewTool.tsx
|
||||
import { useState } from 'react';
|
||||
import { Button, FileInput, Container } from '@mantine/core';
|
||||
|
||||
|
||||
@@ -10,20 +10,18 @@ if that directory exists, is licensed under the license defined in "app/propriet
|
||||
if that directory exists, is licensed under the license defined in "app/saas/LICENSE".
|
||||
* All content that resides under the "engine/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "engine/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/proprietary/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/proprietary/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/desktop/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/desktop/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/saas/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/saas/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/cloud/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/cloud/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/prototypes/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/prototypes/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/portal/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/portal/LICENSE".
|
||||
* All content that resides under the "frontend/editor/src/portal-saas/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/editor/src/portal-saas/LICENSE".
|
||||
* All content that resides under the "frontend/src/editor/proprietary/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/editor/proprietary/LICENSE".
|
||||
* All content that resides under the "frontend/src/editor/desktop/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/editor/desktop/LICENSE".
|
||||
* All content that resides under the "frontend/src/editor/saas/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/editor/saas/LICENSE".
|
||||
* All content that resides under the "frontend/src/editor/cloud/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/editor/cloud/LICENSE".
|
||||
* All content that resides under the "frontend/src/editor/prototypes/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/editor/prototypes/LICENSE".
|
||||
* All content that resides under the "frontend/src/processor/" directory of this repository,
|
||||
if that directory exists, is licensed under the license defined in "frontend/src/processor/LICENSE".
|
||||
* Content outside of the above mentioned directories or restrictions above is
|
||||
available under the MIT License as defined below.
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ If you're using Tauri's built-in updater feature:
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### 1. Tauri Configuration (frontend/editor/src-tauri/tauri.conf.json)
|
||||
### 1. Tauri Configuration (frontend/src-tauri/tauri.conf.json)
|
||||
|
||||
The Windows signing configuration is already set up:
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ if (buildWithPortal) {
|
||||
}
|
||||
// Workspace root holds package.json and node_modules (shared across editor /
|
||||
// future portal). Editor-specific paths (src, public, dist, tauri) live one
|
||||
// level deeper under frontend/editor/.
|
||||
// level deeper under frontend/.
|
||||
|
||||
// Vite mode: -PprototypesMode > -PfrontendMode > enableSaas > disableAdditional > proprietary.
|
||||
def frontendModeOverride = project.findProperty('frontendMode')?.toString()?.toLowerCase()
|
||||
@@ -176,11 +176,11 @@ def frontendBuildTask = "frontend:build:${frontendMode}"
|
||||
|
||||
// Workspace root holds package.json and node_modules (shared across editor /
|
||||
// future portal). Editor-specific paths (src, public, dist, tauri) live one
|
||||
// level deeper under frontend/editor/. When the portal lands as an embedded
|
||||
// level deeper under frontend/. When the portal lands as an embedded
|
||||
// app, add a sibling frontendPortalDir / frontendPortalDistDir alongside.
|
||||
def frontendDir = file('../../frontend')
|
||||
def frontendEditorDir = file('../../frontend/editor')
|
||||
def frontendEditorDistDir = file('../../frontend/editor/dist')
|
||||
def frontendEditorDir = file('../../frontend')
|
||||
def frontendEditorDistDir = file('../../frontend/dist')
|
||||
def resourcesStaticDir = file('src/main/resources/static')
|
||||
def generatedFrontendPaths = [
|
||||
'assets',
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package stirling.software.proprietary.access.model;
|
||||
|
||||
/** Types of resources whose access can be gated by {@link ResourceGrant}. */
|
||||
public enum ResourceType {
|
||||
// The admin portal / processor (frontend/editor/src/portal). Singleton resource (empty
|
||||
// The admin portal / processor (frontend/src/processor/proprietary). Singleton resource (empty
|
||||
// resourceId).
|
||||
PORTAL,
|
||||
// A stored S3/MCP/API integration configuration.
|
||||
|
||||
+3
-3
@@ -110,9 +110,9 @@ allprojects {
|
||||
}
|
||||
|
||||
def appVersionStr = project.version.toString()
|
||||
def tauriConfigPath = layout.projectDirectory.file('frontend/editor/src-tauri/tauri.conf.json').asFile.path
|
||||
def sim1Path = layout.projectDirectory.file('frontend/editor/src/core/testing/serverExperienceSimulations.ts').asFile.path
|
||||
def sim2Path = layout.projectDirectory.file('frontend/editor/src/proprietary/testing/serverExperienceSimulations.ts').asFile.path
|
||||
def tauriConfigPath = layout.projectDirectory.file('frontend/src-tauri/tauri.conf.json').asFile.path
|
||||
def sim1Path = layout.projectDirectory.file('frontend/src/editor/core/testing/serverExperienceSimulations.ts').asFile.path
|
||||
def sim2Path = layout.projectDirectory.file('frontend/src/editor/proprietary/testing/serverExperienceSimulations.ts').asFile.path
|
||||
def aurDesktopPkgbuildPath = layout.projectDirectory.file('.github/aur/stirling-pdf-desktop/PKGBUILD').asFile.path
|
||||
def aurServerPkgbuildPath = layout.projectDirectory.file('.github/aur/stirling-pdf-server-bin/PKGBUILD').asFile.path
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ Fork Stirling-PDF and create a new branch out of `main`.
|
||||
|
||||
### Add Language Directory and Translation File
|
||||
|
||||
1. Create a new language directory in `frontend/editor/public/locales/`
|
||||
1. Create a new language directory in `frontend/public/locales/`
|
||||
- Use hyphenated format: `pl-PL` (not underscore)
|
||||
|
||||
2. Copy the reference translation file:
|
||||
- Source: `frontend/editor/public/locales/en-US/translation.toml`
|
||||
- Destination: `frontend/editor/public/locales/pl-PL/translation.toml`
|
||||
- Source: `frontend/public/locales/en-US/translation.toml`
|
||||
- Destination: `frontend/public/locales/pl-PL/translation.toml`
|
||||
|
||||
3. Translate all entries in the TOML file
|
||||
- Keep the TOML structure intact
|
||||
@@ -49,7 +49,7 @@ ignore = [
|
||||
> [!IMPORTANT]
|
||||
> If you add any new translation tags, they must first be added to the `en-US/translation.toml` file. This ensures consistency across all language files.
|
||||
|
||||
- New translation tags **must be added** to `frontend/editor/public/locales/en-US/translation.toml` to maintain a reference for other languages.
|
||||
- New translation tags **must be added** to `frontend/public/locales/en-US/translation.toml` to maintain a reference for other languages.
|
||||
- After adding the new tags to `en-US/translation.toml`, add and translate them in the respective language file (e.g., `pl-PL/translation.toml`).
|
||||
- Use the scripts in `scripts/translations/` to validate and manage translations (see `scripts/translations/README.md`)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ RUN npm ci
|
||||
COPY frontend .
|
||||
|
||||
# Generate material-symbols icon subset (normally done by task prepare:icons).
|
||||
RUN node editor/scripts/generate-icons.js
|
||||
RUN node scripts/generate-icons.js
|
||||
|
||||
# Defaults match prior behaviour. Supabase values are client-publishable build args.
|
||||
ARG STIRLING_FLAVOR=proprietary
|
||||
@@ -21,7 +21,7 @@ ARG VITE_SUPABASE_URL=""
|
||||
# pragma: allowlist secret
|
||||
ARG VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY=""
|
||||
|
||||
# Build vite from editor/, output lands in editor/dist/.
|
||||
# Build vite from editor/, output lands in dist/.
|
||||
RUN set -eu; \
|
||||
export STIRLING_FLAVOR="${STIRLING_FLAVOR}"; \
|
||||
if [ -n "${VITE_SUPABASE_URL}" ]; then export VITE_SUPABASE_URL="${VITE_SUPABASE_URL}"; fi; \
|
||||
@@ -31,7 +31,7 @@ RUN set -eu; \
|
||||
# Stage 2: nginx
|
||||
FROM nginx:alpine@sha256:b0f7830b6bfaa1258f45d94c240ab668ced1b3651c8a222aefe6683447c7bf55
|
||||
|
||||
COPY --from=build /app/editor/dist /usr/share/nginx/html
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
COPY docker/frontend/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY docker/frontend/entrypoint.sh /entrypoint.sh
|
||||
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
/storybook-static
|
||||
|
||||
/editor/build
|
||||
/editor/dist
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
@@ -40,12 +40,12 @@ playwright-report
|
||||
test-results
|
||||
|
||||
# auto-generated files
|
||||
/editor/src/assets/material-symbols-icons.json
|
||||
/editor/src/assets/material-symbols-icons.d.ts
|
||||
/src/assets/material-symbols-icons.json
|
||||
/src/assets/material-symbols-icons.d.ts
|
||||
|
||||
# dev update testing - keys, built bundles, screenshots, and generated config override
|
||||
/scripts/dev-update-test/.keys/
|
||||
/scripts/dev-update-test/.update-dist/
|
||||
/scripts/dev-update-test/screenshots/
|
||||
/editor/src-tauri/tauri.conf.dev-update.json
|
||||
/src-tauri/tauri.conf.dev-update.json
|
||||
.a11y-scan/
|
||||
|
||||
+15
-15
@@ -1,30 +1,30 @@
|
||||
dist/
|
||||
editor/dist/
|
||||
dist/
|
||||
# Tauri/Cargo build output (binary assets named *.js etc. confuse Prettier).
|
||||
# Match nested target/ dirs too - provisioner/ and thumbnail-handler/ each
|
||||
# have their own Cargo workspace under src-tauri/.
|
||||
editor/src-tauri/**/target/
|
||||
editor/src-tauri/gen/
|
||||
src-tauri/**/target/
|
||||
src-tauri/gen/
|
||||
node_modules/
|
||||
editor/public/vendor/
|
||||
public/vendor/
|
||||
# Auto-generated by MSW (`msw init`); regenerated verbatim, not hand-formatted.
|
||||
editor/public/mockServiceWorker.js
|
||||
public/mockServiceWorker.js
|
||||
# Auto-generated OG/social-preview metadata (scripts/generate-og-metadata.mjs); regenerated verbatim.
|
||||
editor/public/og-metadata.json
|
||||
editor/public/og-metadata.saas.json
|
||||
editor/src/core/data/ogImageMap.json
|
||||
public/og-metadata.json
|
||||
public/og-metadata.saas.json
|
||||
src/editor/core/data/ogImageMap.json
|
||||
# Auto-generated portal docs manifest (scripts/sync-portal-docs.mts); regenerated verbatim.
|
||||
editor/src/portal/generated/docsManifest.json
|
||||
editor/public/pdfjs*/
|
||||
editor/public/js/thirdParty/
|
||||
editor/public/css/cookieconsent.css
|
||||
src/processor/proprietary/generated/docsManifest.json
|
||||
public/pdfjs*/
|
||||
public/js/thirdParty/
|
||||
public/css/cookieconsent.css
|
||||
# Build / test artifacts that may exist locally even though they're gitignored
|
||||
storybook-static/
|
||||
playwright-report/
|
||||
editor/playwright-report/
|
||||
playwright-report/
|
||||
test-results/
|
||||
test-results/
|
||||
editor/test-results/
|
||||
*.min.*
|
||||
*.md
|
||||
*.wxs
|
||||
editor/src/output.css
|
||||
src/output.css
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,19 +59,14 @@ if (args.length > 0) {
|
||||
// checked before it is added to the index.
|
||||
files = [
|
||||
...new Set([
|
||||
...git(
|
||||
"ls-files",
|
||||
"--",
|
||||
"editor/src/**/*.stories.ts",
|
||||
"editor/src/**/*.stories.tsx",
|
||||
),
|
||||
...git("ls-files", "--", "src/**/*.stories.ts", "src/**/*.stories.tsx"),
|
||||
...git(
|
||||
"ls-files",
|
||||
"--others",
|
||||
"--exclude-standard",
|
||||
"--",
|
||||
"editor/src/**/*.stories.ts",
|
||||
"editor/src/**/*.stories.tsx",
|
||||
"src/**/*.stories.ts",
|
||||
"src/**/*.stories.tsx",
|
||||
),
|
||||
]),
|
||||
].sort();
|
||||
|
||||
+25
-15
@@ -6,14 +6,14 @@ import tsconfigPaths from "vite-tsconfig-paths";
|
||||
* Storybook 9 ships essentials, interactions, and docs as built-ins, so the
|
||||
* addon list is just the extras we want: theme switching + a11y auditing.
|
||||
*
|
||||
* Story files live next to their components under editor/src/ (which includes
|
||||
* the portal layer at editor/src/portal/). MDX docs pages live in
|
||||
* editor/src/portal/docs/.
|
||||
* Story files live next to their components under src/editor/ (which includes
|
||||
* the portal layer at src/processor/proprietary/). MDX docs pages live in
|
||||
* src/processor/proprietary/docs/.
|
||||
*/
|
||||
const config: StorybookConfig = {
|
||||
stories: [
|
||||
"../editor/src/portal/**/*.mdx",
|
||||
"../editor/src/**/*.stories.@(ts|tsx)",
|
||||
"../src/processor/proprietary/**/*.mdx",
|
||||
"../src/**/*.stories.@(ts|tsx)",
|
||||
],
|
||||
addons: [
|
||||
"@storybook/addon-themes",
|
||||
@@ -29,35 +29,45 @@ const config: StorybookConfig = {
|
||||
},
|
||||
// Serve the MSW worker file from the portal's public dir so Storybook can
|
||||
// intercept network calls the same way the dev portal does.
|
||||
staticDirs: ["../editor/public"],
|
||||
staticDirs: ["../public"],
|
||||
viteFinal: async (config) => {
|
||||
// Wire the @portal/* alias directly on the Storybook bundler so portal
|
||||
// Wire the @processor/* alias directly on the Storybook bundler so portal
|
||||
// story imports resolve without needing the portal's vite config.
|
||||
config.resolve = config.resolve ?? {};
|
||||
config.resolve.alias = {
|
||||
...(config.resolve.alias ?? {}),
|
||||
"@portal": resolve(__dirname, "../editor/src/portal"),
|
||||
"@processor": resolve(__dirname, "../src/processor/proprietary"),
|
||||
// Direct layer aliases so .storybook config files (preview.tsx), which sit
|
||||
// outside src/ and so aren't covered by tsconfigPaths, can import layer
|
||||
// modules (e.g. the auth supabase client that moved into proprietary).
|
||||
"@proprietary": resolve(__dirname, "../editor/src/proprietary"),
|
||||
"@core": resolve(__dirname, "../editor/src/core"),
|
||||
"@proprietary": resolve(__dirname, "../src/editor/proprietary"),
|
||||
"@core": resolve(__dirname, "../src/editor/core"),
|
||||
// Public assets (e.g. the en-US translation TOML loaded ?raw by preview.tsx).
|
||||
// No src alias covers public/, so this lets the config use an alias rather
|
||||
// than a relative path.
|
||||
"@public": resolve(__dirname, "../editor/public"),
|
||||
"@public": resolve(__dirname, "../public"),
|
||||
};
|
||||
// Editor stories import via @app/* (proprietary→core fallback), @core/* and
|
||||
// Editor stories import via @editor/* (proprietary→core fallback), @core/* and
|
||||
// @proprietary/*. Resolve them exactly the way the editor's own build does —
|
||||
// through vite-tsconfig-paths against the proprietary vite tsconfig — so the
|
||||
// shared Storybook can host editor components without duplicating the alias
|
||||
// map here.
|
||||
config.plugins = config.plugins ?? [];
|
||||
// Storybook's builder-vite auto-loads the app's vite.config.ts and merges in
|
||||
// its plugins, but a Storybook build is not an app build. Drop the app's
|
||||
// build-only plugins that emit deploy artifacts against a dist/ that a
|
||||
// Storybook build never produces (prerender-og would otherwise throw ENOENT).
|
||||
const APP_BUILD_ONLY = new Set(["prerender-og", "compress-static-copy"]);
|
||||
config.plugins = config.plugins.filter((p) => {
|
||||
const name =
|
||||
p && typeof p === "object" && "name" in p
|
||||
? (p as { name?: unknown }).name
|
||||
: undefined;
|
||||
return typeof name !== "string" || !APP_BUILD_ONLY.has(name);
|
||||
});
|
||||
config.plugins.push(
|
||||
tsconfigPaths({
|
||||
projects: [
|
||||
resolve(__dirname, "../editor/tsconfig.proprietary.vite.json"),
|
||||
],
|
||||
projects: [resolve(__dirname, "../tsconfig.proprietary.vite.json")],
|
||||
}),
|
||||
);
|
||||
// Point apiClient.saas at a mock origin so the SaaS-backed billing stories
|
||||
|
||||
@@ -14,12 +14,12 @@ import { withThemeByDataAttribute } from "@storybook/addon-themes";
|
||||
void React;
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { TierProvider, type Tier } from "@portal/contexts/TierContext";
|
||||
import { LinkProvider, type LinkState } from "@portal/contexts/LinkContext";
|
||||
import { ThemeProvider, useTheme } from "@portal/contexts/ThemeContext";
|
||||
import { UIProvider } from "@portal/contexts/UIContext";
|
||||
import { SuiProvider } from "@portal/theme/SuiProvider";
|
||||
import { handlers } from "@portal/mocks/handlers";
|
||||
import { TierProvider, type Tier } from "@processor/contexts/TierContext";
|
||||
import { LinkProvider, type LinkState } from "@processor/contexts/LinkContext";
|
||||
import { ThemeProvider, useTheme } from "@processor/contexts/ThemeContext";
|
||||
import { UIProvider } from "@processor/contexts/UIContext";
|
||||
import { SuiProvider } from "@processor/theme/SuiProvider";
|
||||
import { handlers } from "@processor/mocks/handlers";
|
||||
import { configureSupabase } from "@proprietary/auth/supabase/supabaseClient";
|
||||
import i18next from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
@@ -36,7 +36,7 @@ import "@core/tokens/base.css";
|
||||
// async fetch (Storybook has no backend to serve /locales/). t(key) then renders
|
||||
// the shipped copy (e.g. "No sources connected yet") rather than the raw key.
|
||||
const localeModules = import.meta.glob<string>(
|
||||
"../editor/public/locales/*/translation.toml",
|
||||
"../public/locales/*/translation.toml",
|
||||
{ query: "?raw", import: "default", eager: true },
|
||||
);
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
// Extends the same tsconfig main.ts feeds to vite-tsconfig-paths, so the
|
||||
// alias map can't drift from the one Storybook actually bundles with, and
|
||||
// stories are checked under that resolution (@app/* = proprietary -> core).
|
||||
// stories are checked under that resolution (@editor/* = proprietary -> core).
|
||||
// The per-layer typecheck projects also cover story files, but each resolves
|
||||
// @app/* its own way - not the way the single Storybook build renders them.
|
||||
"extends": "../editor/tsconfig.proprietary.vite.json",
|
||||
// @editor/* its own way - not the way the single Storybook build renders them.
|
||||
"extends": "../tsconfig.proprietary.vite.json",
|
||||
"exclude": [],
|
||||
"include": [
|
||||
"./**/*",
|
||||
"../editor/src/global.d.ts",
|
||||
"../editor/src/**/*.stories.ts",
|
||||
"../editor/src/**/*.stories.tsx"
|
||||
"../src/global.d.ts",
|
||||
"../src/**/*.stories.ts",
|
||||
"../src/**/*.stories.tsx"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
|
||||
* Dedicated Vitest config that turns every story into a browser test: it mounts
|
||||
* the story in real Chromium and runs axe against it, so a story fails if it
|
||||
* throws on mount or trips an accessibility rule. Kept separate from
|
||||
* editor/vitest.config.ts (the jsdom unit tests) so the two suites don't collide.
|
||||
* vitest.config.ts (the jsdom unit tests) so the two suites don't collide.
|
||||
*
|
||||
* The storybook test must live in a `test.projects[]` entry (not a flat config)
|
||||
* so Vitest wires up the browser test runner correctly.
|
||||
@@ -17,7 +17,7 @@ export default defineConfig({
|
||||
optimizeDeps: {
|
||||
// Pre-scan every story + the preview so Vite discovers the story set's large
|
||||
// dep surface (embedpdf plugins, @mui icons, …) in one pass up front.
|
||||
entries: ["editor/src/**/*.stories.@(ts|tsx)", ".storybook/preview.tsx"],
|
||||
entries: ["src/**/*.stories.@(ts|tsx)", ".storybook/preview.tsx"],
|
||||
// `entries` alone does not catch deps reached through a transformed JSX
|
||||
// runtime import, nor the preview's own dependency graph (the test plugin
|
||||
// injects the preview in a way the entry scanner doesn't crawl). Vite then
|
||||
|
||||
@@ -10,7 +10,7 @@ Refer to the various `tsconfig.*.json` files to see the specific path alias orde
|
||||
|
||||
The vast majority of the code is in the `src/core` folder, which is the open-source app.
|
||||
Other builds, such as the desktop app, use `src/core` as the base layer, and then override various files to change behaviour.
|
||||
If an import is `from '@app/a/b'`, this will refer to `src/core/a/b.ts` in the core build of the app, but may refer to `src/desktop/a/b.ts` in the desktop app if that file exists.
|
||||
If an import is `from '@editor/a/b'`, this will refer to `src/editor/core/a/b.ts` in the core build of the app, but may refer to `src/editor/desktop/a/b.ts` in the desktop app if that file exists.
|
||||
|
||||
It is important to try to minimise the amount of overridden code in the app.
|
||||
Often, just one function needs to behave differently in a specific mode.
|
||||
@@ -27,7 +27,7 @@ In cases like this, instead of duplicating the entire file, create a new extensi
|
||||
|
||||
```ts
|
||||
// core/file1.ts
|
||||
import { f2 } from '@app/file1Extensions';
|
||||
import { f2 } from '@editor/file1Extensions';
|
||||
|
||||
function f1() { /* ... */ }
|
||||
function f3() { /* ... */ }
|
||||
@@ -102,7 +102,7 @@ export function getToolbarButtons(): ToolbarButton[] {
|
||||
|
||||
```tsx
|
||||
// core/Toolbar.tsx
|
||||
import { getToolbarButtons } from '@app/toolbarExtensions';
|
||||
import { getToolbarButtons } from '@editor/toolbarExtensions';
|
||||
|
||||
export function Toolbar() {
|
||||
return (
|
||||
@@ -123,7 +123,7 @@ This pattern works well for things like menu items or toolbar actions - anything
|
||||
|
||||
### Import aliases
|
||||
|
||||
In general, all imports for app code should come via `@app` because it allows for other builds of the app to override behaviour if necessary.
|
||||
In general, all imports for app code should come via `@editor` because it allows for other builds of the app to override behaviour if necessary.
|
||||
The only time that it is beneficial to import via a specific folder (e.g. `@core`) is when you want to reduce duplication **in the file you are overriding**. For example:
|
||||
|
||||
```ts
|
||||
+2
-2
@@ -16,7 +16,7 @@ For desktop app development, see the [Tauri](#tauri) section below.
|
||||
## Layout
|
||||
|
||||
`frontend/` is a workspace containing one or more apps. Today it holds the
|
||||
PDF editor under `frontend/editor/`; new apps (the developer portal, etc.)
|
||||
PDF editor under `frontend/`; new apps (the developer portal, etc.)
|
||||
will sit alongside it as siblings. Shared tooling — `package.json`, `node_modules`,
|
||||
`.storybook/`, ESLint, Prettier — lives at `frontend/` so every app installs
|
||||
once and lints with the same config.
|
||||
@@ -24,7 +24,7 @@ once and lints with the same config.
|
||||
## Environment Variables
|
||||
|
||||
The editor's environment variables live in committed `.env` files at
|
||||
`frontend/editor/`:
|
||||
`frontend/`:
|
||||
|
||||
- `.env` — used by all builds (core, proprietary, and as the base for desktop/SaaS)
|
||||
- `.env.desktop` — additional vars loaded in desktop (Tauri) mode
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"../../src/cloud/*",
|
||||
"../../src/proprietary/*",
|
||||
"../../src/core/*"
|
||||
],
|
||||
"@portal/*": ["../../src/portal/*"],
|
||||
"@cloud/*": ["../../src/cloud/*"],
|
||||
"@proprietary/*": ["../../src/proprietary/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../global.d.ts",
|
||||
"../*.js",
|
||||
"../*.ts",
|
||||
"../*.tsx",
|
||||
"../core/setupTests.ts",
|
||||
"."
|
||||
]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
export {
|
||||
FormFillProvider,
|
||||
useFormFill,
|
||||
useFieldValue,
|
||||
useAllFormValues,
|
||||
} from "@app/tools/formFill/FormFillContext";
|
||||
export { FormFieldSidebar } from "@app/tools/formFill/FormFieldSidebar";
|
||||
export { FormFieldOverlay } from "@app/tools/formFill/FormFieldOverlay";
|
||||
export { FormSaveBar } from "@app/tools/formFill/FormSaveBar";
|
||||
export { default as FormFill } from "@app/tools/formFill/FormFill";
|
||||
export { FieldInput } from "@app/tools/formFill/FieldInput";
|
||||
export {
|
||||
FIELD_TYPE_ICON,
|
||||
FIELD_TYPE_COLOR,
|
||||
} from "@app/tools/formFill/fieldMeta";
|
||||
export type {
|
||||
FormField,
|
||||
FormFieldType,
|
||||
FormFillState,
|
||||
WidgetCoordinates,
|
||||
} from "@app/tools/formFill/types";
|
||||
export type { IFormDataProvider } from "@app/tools/formFill/providers/types";
|
||||
export { PdfiumFormProvider } from "@app/tools/formFill/providers/PdfiumFormProvider";
|
||||
export { PdfBoxFormProvider } from "@app/tools/formFill/providers/PdfBoxFormProvider";
|
||||
@@ -1,3 +0,0 @@
|
||||
export type { IFormDataProvider } from "@app/tools/formFill/providers/types";
|
||||
export { PdfiumFormProvider } from "@app/tools/formFill/providers/PdfiumFormProvider";
|
||||
export { PdfBoxFormProvider } from "@app/tools/formFill/providers/PdfBoxFormProvider";
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": ["../global.d.ts", "../*.js", "../*.ts", "../*.tsx", "."]
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
export * from "@app/ui/Button";
|
||||
export * from "@app/ui/ActionIcon";
|
||||
export * from "@app/ui/Logo";
|
||||
export * from "@app/ui/FilePicker";
|
||||
export * from "@app/ui/SegmentedControl";
|
||||
export * from "@app/ui/StatusBadge";
|
||||
export * from "@app/ui/MethodBadge";
|
||||
export * from "@app/ui/ToggleSwitch";
|
||||
export * from "@app/ui/ProgressBar";
|
||||
export * from "@app/ui/MetricCard";
|
||||
export * from "@app/ui/NavItem";
|
||||
export * from "@app/ui/NavSurface";
|
||||
export * from "@app/ui/PanelHeader";
|
||||
export * from "@app/ui/CodeBlock";
|
||||
export * from "@app/ui/SectionDivider";
|
||||
export * from "@app/ui/CarouselDots";
|
||||
export * from "@app/ui/Card";
|
||||
export * from "@app/ui/Modal";
|
||||
export * from "@app/ui/SettingsShell";
|
||||
|
||||
// Layout
|
||||
export * from "@app/ui/Stack";
|
||||
export * from "@app/ui/Inline";
|
||||
export * from "@app/ui/MetricStrip";
|
||||
export * from "@app/ui/StatTile";
|
||||
|
||||
// Feedback
|
||||
export * from "@app/ui/Spinner";
|
||||
export * from "@app/ui/Skeleton";
|
||||
export * from "@app/ui/Avatar";
|
||||
export * from "@app/ui/Chip";
|
||||
export * from "@app/ui/EmptyState";
|
||||
export * from "@app/ui/Banner";
|
||||
export * from "@app/ui/Toast";
|
||||
|
||||
// Compound
|
||||
export * from "@app/ui/Collapsible";
|
||||
export * from "@app/ui/Tabs";
|
||||
export * from "@app/ui/Dropdown";
|
||||
export * from "@app/ui/Drawer";
|
||||
export * from "@app/ui/Table";
|
||||
|
||||
// Forms
|
||||
export * from "@app/ui/FormField";
|
||||
export * from "@app/ui/Input";
|
||||
export * from "@app/ui/Select";
|
||||
export * from "@app/ui/Checkbox";
|
||||
export * from "@app/ui/Radio";
|
||||
export * from "@app/ui/Slider";
|
||||
|
||||
// Mantine-backed form elements (SUI-styled)
|
||||
export * from "@app/ui/MultiSelect";
|
||||
export * from "@app/ui/NumberInput";
|
||||
export * from "@app/ui/ColorInput";
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"../../src/desktop/*",
|
||||
"../../src/cloud/*",
|
||||
"../../src/proprietary/*",
|
||||
"../../src/core/*"
|
||||
],
|
||||
"@cloud/*": ["../../src/cloud/*"],
|
||||
"@proprietary/*": ["../../src/proprietary/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../global.d.ts",
|
||||
"../*.js",
|
||||
"../*.ts",
|
||||
"../*.tsx",
|
||||
"../core/setupTests.ts",
|
||||
"."
|
||||
]
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { assistantHandlers } from "@portal/mocks/handlers/assistant";
|
||||
import { authHandlers } from "@portal/mocks/handlers/auth";
|
||||
import { notificationsHandlers } from "@portal/mocks/handlers/notifications";
|
||||
import { searchHandlers } from "@portal/mocks/handlers/search";
|
||||
import { pipelinesHandlers } from "@portal/mocks/handlers/pipelines";
|
||||
import { sourcesHandlers } from "@portal/mocks/handlers/sources";
|
||||
import { infrastructureHandlers } from "@portal/mocks/handlers/infrastructure";
|
||||
import { procurementSaasHandlers } from "@portal/mocks/handlers/procurementSaas";
|
||||
import { docsHandlers } from "@portal/mocks/handlers/docs";
|
||||
import { usersHandlers } from "@portal/mocks/handlers/users";
|
||||
import { teamSaasHandlers } from "@portal/mocks/handlers/teamSaas";
|
||||
import { policiesHandlers } from "@portal/mocks/handlers/policies";
|
||||
import { classificationHandlers } from "@portal/mocks/handlers/classification";
|
||||
import { documentsHandlers } from "@portal/mocks/handlers/documents";
|
||||
import { editorDeployHandlers } from "@portal/mocks/handlers/editorDeploy";
|
||||
import { linkHandlers } from "@portal/mocks/handlers/link";
|
||||
import { integrationsHandlers } from "@portal/mocks/handlers/integrations";
|
||||
|
||||
export const handlers = [
|
||||
...authHandlers,
|
||||
...notificationsHandlers,
|
||||
...assistantHandlers,
|
||||
...searchHandlers,
|
||||
...pipelinesHandlers,
|
||||
...sourcesHandlers,
|
||||
...infrastructureHandlers,
|
||||
...docsHandlers,
|
||||
...procurementSaasHandlers,
|
||||
...usersHandlers,
|
||||
...teamSaasHandlers,
|
||||
...policiesHandlers,
|
||||
...classificationHandlers,
|
||||
...documentsHandlers,
|
||||
...editorDeployHandlers,
|
||||
...linkHandlers,
|
||||
...integrationsHandlers,
|
||||
];
|
||||
|
||||
export { resetNotificationsStore } from "@portal/mocks/handlers/notifications";
|
||||
export { resetTeamSaasStore } from "@portal/mocks/handlers/teamSaas";
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"../../src/cloud/*",
|
||||
"../../src/proprietary/*",
|
||||
"../../src/core/*"
|
||||
],
|
||||
"@portal/*": ["../../src/portal/*"],
|
||||
"@cloud/*": ["../../src/cloud/*"],
|
||||
"@proprietary/*": ["../../src/proprietary/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": ["../global.d.ts", "."]
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export { default as StripeCheckout } from "@app/components/shared/stripeCheckout/StripeCheckout";
|
||||
export type {
|
||||
StripeCheckoutProps,
|
||||
CheckoutStage,
|
||||
CheckoutState,
|
||||
PollingStatus,
|
||||
SavingsCalculation,
|
||||
} from "@app/components/shared/stripeCheckout/types/checkout";
|
||||
@@ -1,5 +0,0 @@
|
||||
import { useServerExperienceContext } from "@app/contexts/ServerExperienceContext";
|
||||
|
||||
export function useServerExperience() {
|
||||
return useServerExperienceContext();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["../../src/proprietary/*", "../../src/core/*"],
|
||||
"@portal/*": ["../../src/portal/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../global.d.ts",
|
||||
"../*.js",
|
||||
"../*.ts",
|
||||
"../*.tsx",
|
||||
"../core/setupTests.ts",
|
||||
"."
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"../../src/prototypes/*",
|
||||
"../../src/proprietary/*",
|
||||
"../../src/core/*"
|
||||
],
|
||||
"@proprietary/*": ["../../src/proprietary/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../global.d.ts",
|
||||
"../*.js",
|
||||
"../*.ts",
|
||||
"../*.tsx",
|
||||
"../core/setupTests.ts",
|
||||
"."
|
||||
]
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
Stirling PDF User License
|
||||
|
||||
Copyright (c) 2025 Stirling PDF Inc.
|
||||
|
||||
License Scope & Usage Rights
|
||||
|
||||
Production use of the Stirling PDF Software is only permitted with a valid Stirling PDF User License.
|
||||
|
||||
For purposes of this license, “the Software” refers to the Stirling PDF application and any associated documentation files
|
||||
provided by Stirling PDF Inc. You or your organization may not use the Software in production, at scale, or for business-critical
|
||||
processes unless you have agreed to, and remain in compliance with, the Stirling PDF Subscription Terms of Service
|
||||
(https://www.stirlingpdf.com/terms) or another valid agreement with Stirling PDF, and hold an active User License subscription
|
||||
covering the appropriate number of licensed users.
|
||||
|
||||
Trial and Minimal Use
|
||||
|
||||
You may use the Software without a paid subscription for the sole purposes of internal trial, evaluation, or minimal use, provided that:
|
||||
* Use is limited to the capabilities and restrictions defined by the Software itself;
|
||||
* You do not copy, distribute, sublicense, reverse-engineer, or use the Software in client-facing or commercial contexts.
|
||||
|
||||
Continued use beyond this scope requires a valid Stirling PDF User License.
|
||||
|
||||
Modifications and Derivative Works
|
||||
|
||||
You may modify the Software only for development or internal testing purposes. Any such modifications or derivative works:
|
||||
|
||||
* May not be deployed in production environments without a valid User License;
|
||||
* May not be distributed or sublicensed;
|
||||
* Remain the intellectual property of Stirling PDF and/or its licensors;
|
||||
* May only be used, copied, or exploited in accordance with the terms of a valid Stirling PDF User License subscription.
|
||||
|
||||
Prohibited Actions
|
||||
|
||||
Unless explicitly permitted by a paid license or separate agreement, you may not:
|
||||
|
||||
* Use the Software in production environments;
|
||||
* Copy, merge, distribute, sublicense, or sell the Software;
|
||||
* Remove or alter any licensing or copyright notices;
|
||||
* Circumvent access restrictions or licensing requirements.
|
||||
|
||||
Third-Party Components
|
||||
|
||||
The Stirling PDF Software may include components subject to separate open source licenses. Such components remain governed by
|
||||
their original license terms as provided by their respective owners.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"../../src/saas/*",
|
||||
"../../src/cloud/*",
|
||||
"../../src/proprietary/*",
|
||||
"../../src/core/*"
|
||||
],
|
||||
"@portal/*": ["../../src/portal-saas/*", "../../src/portal/*"],
|
||||
"@portal-proprietary/*": ["../../src/portal/*"],
|
||||
"@cloud/*": ["../../src/cloud/*"],
|
||||
"@proprietary/*": ["../../src/proprietary/*"],
|
||||
"@core/*": ["../../src/core/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"../global.d.ts",
|
||||
"../*.js",
|
||||
"../*.ts",
|
||||
"../*.tsx",
|
||||
".",
|
||||
"../portal-saas"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["./src/core/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["src/proprietary", "src/desktop"]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.proprietary.vite.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"./src/desktop/*",
|
||||
"./src/cloud/*",
|
||||
"./src/proprietary/*",
|
||||
"./src/core/*"
|
||||
],
|
||||
"@cloud/*": ["./src/cloud/*"],
|
||||
"@proprietary/*": ["./src/proprietary/*"],
|
||||
"@core/*": ["./src/core/*"]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"src/core/**/*.test.ts*",
|
||||
"src/core/**/*.spec.ts*",
|
||||
"src/proprietary/**/*.test.ts*",
|
||||
"src/proprietary/**/*.spec.ts*",
|
||||
"src/cloud/**/*.test.ts*",
|
||||
"src/cloud/**/*.spec.ts*"
|
||||
]
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"comment": "Path resolution for the portal's vitest project (referenced by vitest.config.ts). Broad include ('src', via the base) so vite-tsconfig-paths rewrites @app/* in every editor/src file the portal tests pull in (e.g. core/ui), not just the portal layer. The portal's own typecheck uses src/portal/tsconfig.json.",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["./src/cloud/*", "./src/proprietary/*", "./src/core/*"],
|
||||
"@portal/*": ["./src/portal/*"],
|
||||
"@cloud/*": ["./src/cloud/*"],
|
||||
"@proprietary/*": ["./src/proprietary/*"],
|
||||
"@core/*": ["./src/core/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["./src/proprietary/*", "./src/core/*"],
|
||||
"@portal/*": ["./src/portal/*"],
|
||||
"@proprietary/*": ["./src/proprietary/*"],
|
||||
"@core/*": ["./src/core/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["src/core/**/*.test.ts*", "src/core/**/*.spec.ts*", "src/desktop"]
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.proprietary.vite.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": ["./src/prototypes/*", "./src/proprietary/*", "./src/core/*"],
|
||||
"@proprietary/*": ["./src/proprietary/*"],
|
||||
"@core/*": ["./src/core/*"]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"src/core/**/*.test.ts*",
|
||||
"src/core/**/*.spec.ts*",
|
||||
"src/proprietary/**/*.test.ts*",
|
||||
"src/proprietary/**/*.spec.ts*",
|
||||
"src/desktop",
|
||||
"src/saas"
|
||||
]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@app/*": [
|
||||
"./src/saas/*",
|
||||
"./src/cloud/*",
|
||||
"./src/proprietary/*",
|
||||
"./src/core/*"
|
||||
],
|
||||
"@portal/*": ["./src/portal-saas/*", "./src/portal/*"],
|
||||
"@portal-proprietary/*": ["./src/portal/*"],
|
||||
"@cloud/*": ["./src/cloud/*"],
|
||||
"@proprietary/*": ["./src/proprietary/*"],
|
||||
"@core/*": ["./src/core/*"]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"src/core/**/*.test.ts*",
|
||||
"src/core/**/*.spec.ts*",
|
||||
"src/proprietary/**/*.test.ts*",
|
||||
"src/proprietary/**/*.spec.ts*",
|
||||
"src/cloud/**/*.test.ts*",
|
||||
"src/cloud/**/*.spec.ts*",
|
||||
"src/desktop"
|
||||
]
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
setupFiles: ["./src/core/setupTests.ts"],
|
||||
css: false,
|
||||
exclude: [
|
||||
"node_modules/",
|
||||
"src/**/*.spec.ts", // Exclude Playwright E2E tests
|
||||
"src/tests/test-fixtures/**",
|
||||
],
|
||||
testTimeout: 10000,
|
||||
hookTimeout: 10000,
|
||||
coverage: {
|
||||
reporter: ["text", "json", "html"],
|
||||
exclude: [
|
||||
"node_modules/",
|
||||
"src/core/setupTests.ts",
|
||||
"src/proprietary/setupTests.ts",
|
||||
"src/saas/setupTests.ts",
|
||||
"**/*.d.ts",
|
||||
"src/tests/test-fixtures/**",
|
||||
"src/**/*.spec.ts",
|
||||
],
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
test: {
|
||||
name: "core",
|
||||
include: ["src/core/**/*.test.{ts,tsx}"],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/core/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: ["./tsconfig.core.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: "portal",
|
||||
include: ["src/portal/**/*.test.{ts,tsx}"],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/portal/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
// Broad project so @app/@portal resolve in every editor file the
|
||||
// portal tests pull in (core/ui, core, ...).
|
||||
projects: ["./tsconfig.portal.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: "proprietary",
|
||||
include: ["src/proprietary/**/*.test.{ts,tsx}"],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/core/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: ["./tsconfig.proprietary.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: "desktop",
|
||||
include: ["src/desktop/**/*.test.{ts,tsx}"],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/core/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: ["./tsconfig.desktop.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: "saas",
|
||||
// src/saas = editor-saas layer; src/portal-saas = the portal's saas
|
||||
// overrides (sibling to src/portal). Both build under the saas flavor,
|
||||
// so both resolve @portal via the saas cascade (tsconfig.saas.vite.json).
|
||||
include: [
|
||||
"src/saas/**/*.test.{ts,tsx}",
|
||||
"src/portal-saas/**/*.test.{ts,tsx}",
|
||||
],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/saas/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: ["./tsconfig.saas.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: "prototypes",
|
||||
include: ["src/prototypes/**/*.test.{ts,tsx}"],
|
||||
environment: "jsdom",
|
||||
globals: true,
|
||||
setupFiles: ["./src/core/setupTests.ts"],
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths({
|
||||
projects: ["./tsconfig.prototypes.vite.json"],
|
||||
}),
|
||||
],
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
esbuild: {
|
||||
target: "es2020",
|
||||
},
|
||||
});
|
||||
+72
-72
@@ -6,15 +6,15 @@ import { defineConfig } from "eslint/config";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
const srcGlobs = [
|
||||
// The portal layers live under editor/src/portal (base) and
|
||||
// editor/src/portal-saas (saas override), so editor/src/** covers them.
|
||||
"editor/src/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
// The portal layers live under src/processor/proprietary (base) and
|
||||
// src/processor/saas (saas override), so src/** covers them.
|
||||
"src/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
];
|
||||
const nodeGlobs = [
|
||||
"scripts/**/*.{js,ts,mjs,mts}",
|
||||
"editor/scripts/**/*.{js,ts,mjs,mts}",
|
||||
"scripts/**/*.{js,ts,mjs,mts}",
|
||||
// Covers editor/vite.config.ts and editor/vitest.config.ts.
|
||||
"editor/*.config.{js,ts,mjs}",
|
||||
"*.config.{js,ts,mjs}",
|
||||
"*.config.{js,ts,mjs}",
|
||||
".storybook/*.{js,ts,mjs,mts,tsx}",
|
||||
];
|
||||
@@ -23,7 +23,7 @@ const baseRestrictedImportPatterns = [
|
||||
{
|
||||
regex: "^\\.",
|
||||
message:
|
||||
"Use a workspace alias (@app/* for editor, @portal/* for portal) instead of relative imports.",
|
||||
"Use a workspace alias (@editor/* for editor, @processor/* for portal) instead of relative imports.",
|
||||
},
|
||||
{
|
||||
regex: "^src/",
|
||||
@@ -31,26 +31,26 @@ const baseRestrictedImportPatterns = [
|
||||
},
|
||||
];
|
||||
|
||||
// Button/SegmentedControl/Chip must come from the shared DS (@app/ui), not Mantine.
|
||||
// If no variant fits, extend @app/ui — that layer (editor/src/core/ui) is exempt below.
|
||||
// Button/SegmentedControl/Chip must come from the shared DS (@editor/ui), not Mantine.
|
||||
// If no variant fits, extend @editor/ui — that layer (src/editor/core/ui) is exempt below.
|
||||
const mantineComponentImportRestrictions = [
|
||||
{
|
||||
selector:
|
||||
"ImportDeclaration[source.value='@mantine/core'] > ImportSpecifier[imported.name=/^(Button|ActionIcon|UnstyledButton|CloseButton|FileButton)$/]",
|
||||
message:
|
||||
'Use the shared Button (@app/ui/Button) instead of the Mantine button family. variant=primary|secondary|tertiary, accent=default|neutral|brand|ai|premium|danger|success|warning; an icon-only button is `<Button leftSection={…} aria-label="…" />`. If no variant fits, extend the shared Button rather than importing Mantine.',
|
||||
'Use the shared Button (@editor/ui/Button) instead of the Mantine button family. variant=primary|secondary|tertiary, accent=default|neutral|brand|ai|premium|danger|success|warning; an icon-only button is `<Button leftSection={…} aria-label="…" />`. If no variant fits, extend the shared Button rather than importing Mantine.',
|
||||
},
|
||||
{
|
||||
selector:
|
||||
"ImportDeclaration[source.value='@mantine/core'] > ImportSpecifier[imported.name='SegmentedControl']",
|
||||
message:
|
||||
"Use the shared SegmentedControl (@app/ui/SegmentedControl) instead of Mantine's.",
|
||||
"Use the shared SegmentedControl (@editor/ui/SegmentedControl) instead of Mantine's.",
|
||||
},
|
||||
{
|
||||
selector:
|
||||
"ImportDeclaration[source.value='@mantine/core'] > ImportSpecifier[imported.name=/^(Chip|Pill)$/]",
|
||||
message:
|
||||
"Use the shared Chip (@app/ui/Chip) instead of Mantine's Chip/Pill.",
|
||||
"Use the shared Chip (@editor/ui/Chip) instead of Mantine's Chip/Pill.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -59,7 +59,7 @@ const mantineComponentImportRestrictions = [
|
||||
const rawButtonSyntaxRestriction = {
|
||||
selector: "JSXOpeningElement[name.name='button']",
|
||||
message:
|
||||
"Use the shared Button (@app/ui/Button) instead of a raw <button> element. If no variant fits, extend the shared Button.",
|
||||
"Use the shared Button (@editor/ui/Button) instead of a raw <button> element. If no variant fits, extend the shared Button.",
|
||||
};
|
||||
|
||||
const sharedComponentSyntaxRestrictions = [
|
||||
@@ -77,11 +77,11 @@ export default defineConfig(
|
||||
"playwright-report",
|
||||
"storybook-static",
|
||||
"test-results",
|
||||
"editor/dist",
|
||||
"editor/public",
|
||||
"editor/src-tauri",
|
||||
"editor/playwright-report",
|
||||
"editor/test-results",
|
||||
"dist",
|
||||
"public",
|
||||
"src-tauri",
|
||||
"playwright-report",
|
||||
"test-results",
|
||||
],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
@@ -117,10 +117,10 @@ export default defineConfig(
|
||||
},
|
||||
},
|
||||
// Desktop-only packages must not be imported from core or proprietary code.
|
||||
// Use the stub/shadow pattern instead: define a stub in editor/src/core/ and override in editor/src/desktop/.
|
||||
// Use the stub/shadow pattern instead: define a stub in src/editor/core/ and override in src/editor/desktop/.
|
||||
{
|
||||
files: srcGlobs,
|
||||
ignores: ["editor/src/desktop/**"],
|
||||
ignores: ["src/editor/desktop/**"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
@@ -130,7 +130,7 @@ export default defineConfig(
|
||||
{
|
||||
regex: "^@tauri-apps/",
|
||||
message:
|
||||
"Tauri APIs are desktop-only. Review frontend/editor/DeveloperGuide.md for structure advice.",
|
||||
"Tauri APIs are desktop-only. Review frontend/DeveloperGuide.md for structure advice.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -141,10 +141,10 @@ export default defineConfig(
|
||||
// saas and desktop leaves, so it must stay platform-portable. It must not
|
||||
// reach platform-specific things directly (Supabase, Tauri, raw fetch,
|
||||
// window.location, web storage, or import.meta.env.VITE_*) — those arrive via
|
||||
// @app/* seams (services/apiClient, auth/session, platform/openExternal, ...)
|
||||
// @editor/* seams (services/apiClient, auth/session, platform/openExternal, ...)
|
||||
// that each leaf provides for its own platform.
|
||||
{
|
||||
files: ["editor/src/cloud/**/*.{js,mjs,jsx,ts,tsx}"],
|
||||
files: ["src/editor/cloud/**/*.{js,mjs,jsx,ts,tsx}"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
@@ -154,12 +154,12 @@ export default defineConfig(
|
||||
{
|
||||
regex: "^@supabase/",
|
||||
message:
|
||||
"cloud/ must stay platform-portable. Reach Supabase via an @app/* seam (e.g. @app/auth/supabase, @app/auth/session) provided per-platform in saas/ and desktop/.",
|
||||
"cloud/ must stay platform-portable. Reach Supabase via an @editor/* seam (e.g. @editor/auth/supabase, @editor/auth/session) provided per-platform in saas/ and desktop/.",
|
||||
},
|
||||
{
|
||||
regex: "^@tauri-apps/",
|
||||
message:
|
||||
"cloud/ must stay platform-portable. Tauri APIs are desktop-only — reach native features via an @app/* seam (e.g. @app/platform/openExternal).",
|
||||
"cloud/ must stay platform-portable. Tauri APIs are desktop-only — reach native features via an @editor/* seam (e.g. @editor/platform/openExternal).",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -169,17 +169,17 @@ export default defineConfig(
|
||||
{
|
||||
name: "fetch",
|
||||
message:
|
||||
"cloud/ must not call raw fetch — use @app/services/apiClient so each platform supplies its own transport.",
|
||||
"cloud/ must not call raw fetch — use @editor/services/apiClient so each platform supplies its own transport.",
|
||||
},
|
||||
{
|
||||
name: "localStorage",
|
||||
message:
|
||||
"cloud/ must not touch localStorage — use an @app/* storage seam so desktop/web can differ.",
|
||||
"cloud/ must not touch localStorage — use an @editor/* storage seam so desktop/web can differ.",
|
||||
},
|
||||
{
|
||||
name: "sessionStorage",
|
||||
message:
|
||||
"cloud/ must not touch sessionStorage — use an @app/* storage seam so desktop/web can differ.",
|
||||
"cloud/ must not touch sessionStorage — use an @editor/* storage seam so desktop/web can differ.",
|
||||
},
|
||||
],
|
||||
"no-restricted-syntax": [
|
||||
@@ -189,26 +189,26 @@ export default defineConfig(
|
||||
selector:
|
||||
"MemberExpression[object.name='window'][property.name='location']",
|
||||
message:
|
||||
"cloud/ must not touch window.location — use an @app/* seam (e.g. @app/platform/openExternal) so desktop/web can differ.",
|
||||
"cloud/ must not touch window.location — use an @editor/* seam (e.g. @editor/platform/openExternal) so desktop/web can differ.",
|
||||
},
|
||||
{
|
||||
selector:
|
||||
"MemberExpression[property.name='env'][object.type='MetaProperty'][object.meta.name='import'][object.property.name='meta']",
|
||||
message:
|
||||
"cloud/ must not read import.meta.env — use @app/constants/app / @app/platform seams so config is supplied per-platform.",
|
||||
"cloud/ must not read import.meta.env — use @editor/constants/app / @editor/platform seams so config is supplied per-platform.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// app code must use shared DS Button/SegmentedControl/Chip; cloud/ covered above.
|
||||
{
|
||||
files: ["editor/src/**/*.{js,mjs,jsx,ts,tsx}"],
|
||||
files: ["src/**/*.{js,mjs,jsx,ts,tsx}"],
|
||||
ignores: [
|
||||
"editor/src/cloud/**/*.{js,mjs,jsx,ts,tsx}", // covered by cloud/ block above
|
||||
"editor/src/core/ui/**/*.{js,mjs,jsx,ts,tsx}", // the shared DS itself — wraps Mantine/raw elements
|
||||
"src/editor/cloud/**/*.{js,mjs,jsx,ts,tsx}", // covered by cloud/ block above
|
||||
"src/editor/core/ui/**/*.{js,mjs,jsx,ts,tsx}", // the shared DS itself — wraps Mantine/raw elements
|
||||
"**/*.stories.{js,mjs,jsx,ts,tsx}", // stories may demo Mantine directly
|
||||
"**/*.test.{js,mjs,jsx,ts,tsx}", // tests may use raw elements as fixtures
|
||||
"editor/src/prototypes/**/*.{js,mjs,jsx,ts,tsx}", // not shipped
|
||||
"src/editor/prototypes/**/*.{js,mjs,jsx,ts,tsx}", // not shipped
|
||||
],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", ...sharedComponentSyntaxRestrictions],
|
||||
@@ -219,9 +219,9 @@ export default defineConfig(
|
||||
// Do NOT add ordinary buttons here.
|
||||
{
|
||||
files: [
|
||||
"editor/src/core/components/shared/FileSelectorPicker.tsx",
|
||||
"editor/src/core/components/filesPage/FileManagerView.tsx",
|
||||
"editor/src/core/pages/HomePage.tsx",
|
||||
"src/editor/core/components/shared/FileSelectorPicker.tsx",
|
||||
"src/editor/core/components/filesPage/FileManagerView.tsx",
|
||||
"src/editor/core/pages/HomePage.tsx",
|
||||
],
|
||||
rules: {
|
||||
"no-restricted-syntax": "off",
|
||||
@@ -234,7 +234,7 @@ export default defineConfig(
|
||||
// Button in a follow-up PR. Do NOT add other folders to this block.
|
||||
{
|
||||
files: [
|
||||
"editor/src/portal/components/procurement/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/processor/proprietary/components/procurement/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", ...mantineComponentImportRestrictions],
|
||||
@@ -246,7 +246,7 @@ export default defineConfig(
|
||||
// without heavy overrides. Exempt ONLY the raw-<button> rule — the Mantine
|
||||
// import bans stay in force — and migrate these in a follow-up PR.
|
||||
{
|
||||
files: ["editor/src/portal/components/users/UsersDirectory.tsx"],
|
||||
files: ["src/processor/proprietary/components/users/UsersDirectory.tsx"],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", ...mantineComponentImportRestrictions],
|
||||
},
|
||||
@@ -258,7 +258,7 @@ export default defineConfig(
|
||||
// can't represent. Exempt ONLY the raw-<button> rule; the Mantine import bans
|
||||
// stay. Migrate these alongside the procurement buttons.
|
||||
{
|
||||
files: ["editor/src/portal/components/DownloadEditorModal.tsx"],
|
||||
files: ["src/processor/proprietary/components/DownloadEditorModal.tsx"],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", ...mantineComponentImportRestrictions],
|
||||
},
|
||||
@@ -269,10 +269,10 @@ export default defineConfig(
|
||||
// Raw-<button> rule only; migrate later.
|
||||
{
|
||||
files: [
|
||||
"editor/src/portal/components/sources/ConnectionTypePicker.tsx",
|
||||
"editor/src/portal/components/sources/SourceModal.tsx",
|
||||
"editor/src/portal/components/policies/PolicyExternalApiConfig.tsx",
|
||||
"editor/src/portal/views/Integrations.tsx",
|
||||
"src/processor/proprietary/components/sources/ConnectionTypePicker.tsx",
|
||||
"src/processor/proprietary/components/sources/SourceModal.tsx",
|
||||
"src/processor/proprietary/components/policies/PolicyExternalApiConfig.tsx",
|
||||
"src/processor/proprietary/views/Integrations.tsx",
|
||||
],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", ...mantineComponentImportRestrictions],
|
||||
@@ -282,35 +282,35 @@ export default defineConfig(
|
||||
{
|
||||
files: srcGlobs,
|
||||
ignores: [
|
||||
"editor/src/core/components/annotation/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/commands/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/config/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/config/configSections/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/addStamp/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/automate/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/bookletImposition/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/certSign/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/pdfTextEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/file/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/signing/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/adjustContrast/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/convert/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/removePassword/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/services/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/tools/annotate/useAnnotationSelection.ts",
|
||||
"editor/src/core/types/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/utils/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/annotation/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/pageEditor/commands/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/pageEditor/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/shared/config/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/shared/config/configSections/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/shared/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/addStamp/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/automate/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/bookletImposition/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/certSign/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/pdfTextEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/components/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/contexts/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/contexts/file/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/contexts/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/signing/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/tools/adjustContrast/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/tools/convert/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/tools/removePassword/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/hooks/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/services/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/tools/annotate/useAnnotationSelection.ts",
|
||||
"src/editor/core/types/*.{js,mjs,jsx,ts,tsx}",
|
||||
"src/editor/core/utils/*.{js,mjs,jsx,ts,tsx}",
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"web-vitals": "^5.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"docs:sync": "tsx editor/scripts/sync-portal-docs.mts",
|
||||
"docs:sync": "tsx scripts/sync-portal-docs.mts",
|
||||
"update:minor": "node scripts/update-minor.js",
|
||||
"update:major": "npx npm-check-updates -u && npm install",
|
||||
"update:interactive": "npx npm-check-updates -i",
|
||||
@@ -93,7 +93,7 @@
|
||||
"tauri:serve-dev-update": "bash scripts/dev-update-test/serve-update.sh",
|
||||
"tauri:test-update-e2e": "bash scripts/dev-update-test/test-update-e2e.sh",
|
||||
"tauri:test-update-e2e:install": "bash scripts/dev-update-test/test-update-e2e.sh --install",
|
||||
"tauri:dev-with-update": "cd editor && npx tsx scripts/setup-env.mts --desktop && node scripts/generate-icons.js && npx tauri dev --config src-tauri/tauri.conf.dev-update.json"
|
||||
"tauri:dev-with-update": "npx tsx scripts/setup-env.mts --desktop && node scripts/generate-icons.js && npx tauri dev --config src-tauri/tauri.conf.dev-update.json"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -182,7 +182,7 @@
|
||||
},
|
||||
"msw": {
|
||||
"workerDirectory": [
|
||||
"editor/public"
|
||||
"public"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import { defineConfig, devices } from "@playwright/test";
|
||||
* The suite is split into two projects:
|
||||
* - `stubbed` - backend-free specs that mock `/api/v1/*` via `page.route()`.
|
||||
* Safe to run in CI without the Spring Boot server. Lives in
|
||||
* `src/core/tests/stubbed/**`.
|
||||
* `src/editor/core/tests/stubbed/**`.
|
||||
* - `live` - specs that require a real backend on `localhost:8080`
|
||||
* (auth, admin mutation, real tool round-trips). Lives in
|
||||
* `src/core/tests/live/**`.
|
||||
* `src/editor/core/tests/live/**`.
|
||||
*
|
||||
* Run one:
|
||||
* npx playwright test --project=stubbed
|
||||
@@ -23,7 +23,7 @@ const chromiumViewport = {
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
testDir: "./src/core/tests",
|
||||
testDir: "./src/editor/core/tests",
|
||||
testMatch: "**/*.spec.ts",
|
||||
|
||||
fullyParallel: true,
|
||||
@@ -58,7 +58,7 @@ export default defineConfig({
|
||||
// Stubbed - no backend required, chromium-only for CI speed
|
||||
{
|
||||
name: "stubbed",
|
||||
testDir: "./src/core/tests/stubbed",
|
||||
testDir: "./src/editor/core/tests/stubbed",
|
||||
use: chromiumViewport,
|
||||
},
|
||||
|
||||
@@ -67,7 +67,7 @@ export default defineConfig({
|
||||
// backend. The live project depends on it.
|
||||
{
|
||||
name: "live-setup",
|
||||
testDir: "./src/core/tests/live-setup",
|
||||
testDir: "./src/editor/core/tests/live-setup",
|
||||
testMatch: /.*\.setup\.ts$/,
|
||||
use: chromiumViewport,
|
||||
},
|
||||
@@ -75,7 +75,7 @@ export default defineConfig({
|
||||
// Live backend - auth + admin-mutation + real-tool smoke
|
||||
{
|
||||
name: "live",
|
||||
testDir: "./src/core/tests/live",
|
||||
testDir: "./src/editor/core/tests/live",
|
||||
use: chromiumViewport,
|
||||
dependencies: ["live-setup"],
|
||||
},
|
||||
@@ -86,7 +86,7 @@ export default defineConfig({
|
||||
// because the OAuth/SAML callback URLs are registered against 8080.
|
||||
{
|
||||
name: "enterprise",
|
||||
testDir: "./src/core/tests/enterprise",
|
||||
testDir: "./src/editor/core/tests/enterprise",
|
||||
use: {
|
||||
...chromiumViewport,
|
||||
baseURL: "http://localhost:8080",
|
||||
@@ -96,12 +96,12 @@ export default defineConfig({
|
||||
// Cross-browser coverage for the stubbed suite (opt-in locally)
|
||||
{
|
||||
name: "stubbed-firefox",
|
||||
testDir: "./src/core/tests/stubbed",
|
||||
testDir: "./src/editor/core/tests/stubbed",
|
||||
use: { ...devices["Desktop Firefox"] },
|
||||
},
|
||||
{
|
||||
name: "stubbed-webkit",
|
||||
testDir: "./src/core/tests/stubbed",
|
||||
testDir: "./src/editor/core/tests/stubbed",
|
||||
use: { ...devices["Desktop Safari"] },
|
||||
},
|
||||
],
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user