Compare commits

...
4 Commits
Author SHA1 Message Date
Anthony StirlingandGitHub bef83d80a1 Patch CVEs in engine Python dependencies (#6804)
# Description of Changes

- Patch CVEs in engine Python dependencies (43 alerts): `starlette`
1.3.1, `cryptography` 49.0.0, `pyjwt` 2.13.0, `urllib3` 2.7.0, `aiohttp`
3.14.1, `python-multipart` 0.0.32, `langchain-core` 1.4.8, `langsmith`
0.9.1, `authlib` 1.7.2, `requests` 2.34.2, `idna` 3.18, `pytest` 9.1.1,
`pygments` 2.20.0, `pydantic-settings` 2.14.2
- Cap `pydantic-ai` `<2.0.0` and bump to 1.107.0 (1.99.0 patches
CVE-2026-46678; 2.0 is a separate major migration)

---

## Checklist

### General

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

### Documentation

- [ ] I have updated relevant docs (if functionality has heavily
changed)
- [ ] I have read the section Add New Translation Tags (for new
translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached

### Testing (if applicable)

- [ ] I have run `task check` to verify linters, typechecks, and tests
pass
- [ ] I have tested my changes locally
2026-07-15 14:49:33 +00:00
Anthony StirlingandGitHub 8ed1ff152b Hide processor pipelines stat boxes during loading/empty state (#6983)
# Description of Changes

Gate the processor Pipelines KPI strip on having real pipelines, so the
loading and empty states no longer flash a row of empty `—` stat boxes.
Matches the Policies view; Sources is intentionally left as-is.

---

## Checklist

### General

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

### Documentation

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

### Translations (if applicable)

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

### UI Changes (if applicable)

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

### Testing (if applicable)

- [x] I have run `task check` to verify linters, typechecks, and tests
pass
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.
2026-07-15 14:49:25 +00:00
Anthony StirlingandGitHub d2c8bbfcb2 Portal Sources: consistent SVG source icons (#6995)
# Description of Changes

Replaces the odd glyph icons in the Sources connect flow with centred
stroke SVGs, and fixes the connect-modal type-tile alignment and the
inconsistent Folder chip width.

Part of a portal (processor) UI-consistency pass, split into small
focused PRs.

## Before / after

<img width="2816" height="1224" alt="before-sources-light"
src="https://github.com/user-attachments/assets/22814817-8123-4bc7-b40b-5c2ba2881415"
/>
<img width="2880" height="2000" alt="after-connect-modal"
src="https://github.com/user-attachments/assets/0e51ca78-cda0-4909-bff3-912ecd7925a3"
/>
<img width="2816" height="1224" alt="after-sources-light"
src="https://github.com/user-attachments/assets/b9fd4b8a-c45a-4518-9676-e871bbabd9b8"
/>
<img width="2880" height="2000" alt="before-connect-modal"
src="https://github.com/user-attachments/assets/55058c40-d152-4c5e-a8a0-1ca5549a121c"
/>


---

## Checklist

### General

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

### Documentation

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

### Translations (if applicable)

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

### UI Changes (if applicable)

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

### Testing (if applicable)

- [ ] I have run `task check` to verify linters, typechecks, and tests
pass
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.
2026-07-15 14:49:21 +00:00
Anthony StirlingandGitHub da1be650ea Portal Billing: use design tokens for colours (#6996)
# Description of Changes

Swaps off-palette hard-coded blues/cyans on the usage & billing page for
shared design tokens, so button and meter colours match the rest of the
portal in both themes.

Part of a portal (processor) UI-consistency pass, split into small
focused PRs.

## Before / after
<img width="2816" height="1000" alt="after-billing-free"
src="https://github.com/user-attachments/assets/1f6acad3-56a1-47a8-b5f5-8cc25565492b"
/>
<img width="2816" height="2048" alt="after-billing-subscribed-dark"
src="https://github.com/user-attachments/assets/35a75057-bdf5-4143-bdfa-4dbe94b5429e"
/>
<img width="2816" height="2048" alt="after-billing-subscribed-light"
src="https://github.com/user-attachments/assets/f9e7eab8-7d01-4d29-b842-b5d38adf7780"
/>
<img width="2816" height="1000" alt="before-billing-free"
src="https://github.com/user-attachments/assets/c7e5eca6-a57a-4959-9781-fd664dbca576"
/>
<img width="2816" height="2004" alt="before-billing-subscribed-dark"
src="https://github.com/user-attachments/assets/d7fc08be-7b91-4803-bd50-3301b886e1c0"
/>
<img width="2816" height="2004" alt="before-billing-subscribed-light"
src="https://github.com/user-attachments/assets/ff430ec1-c3bb-4517-b6b5-2150c566eca4"
/>


---

## Checklist

### General

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

### Documentation

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

### Translations (if applicable)

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

### UI Changes (if applicable)

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

### Testing (if applicable)

- [ ] I have run `task check` to verify linters, typechecks, and tests
pass
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.
2026-07-15 14:49:15 +00:00
8 changed files with 603 additions and 390 deletions
+3 -2
View File
@@ -8,8 +8,9 @@ dependencies = [
"pgvector>=0.3.6",
"psycopg[binary,pool]>=3.2",
"pydantic>=2.0.0",
"pydantic-ai>=1.67.0",
"pydantic-ai-slim[voyageai]>=1.67.0",
# <2 cap: 1.99.0 patches CVE-2026-46678; 2.0 is an untested major migration
"pydantic-ai>=1.99.0,<2.0.0",
"pydantic-ai-slim[voyageai]>=1.99.0,<2.0.0",
"pydantic-settings>=2.0.0",
"python-dotenv>=1.2.1",
"sqlite-vec>=0.1.6",
+469 -332
View File
File diff suppressed because it is too large Load Diff
@@ -35,7 +35,11 @@ export function EnterpriseUpsell({ bare = false }: Props) {
)}
</p>
</div>
<Button size="sm" onClick={() => setActiveView("procurement")}>
<Button
size="sm"
variant="secondary"
onClick={() => setActiveView("procurement")}
>
{t("portal.billing.enterpriseUpsell.cta", "Explore Enterprise")}
</Button>
</div>
@@ -119,7 +119,7 @@
/* Free grant still offsetting spend — reads as a positive credit note, pulled up
under the "PDFs processed" line. */
.portal-billing__free-remaining {
color: var(--color-green-600, var(--color-green));
color: var(--color-green);
margin-top: -0.5rem;
}
@@ -171,7 +171,7 @@
}
.portal-billing__error {
color: var(--color-red, #b91c1c);
color: var(--color-red, var(--color-red-dark));
font-size: 0.875rem;
margin: 0.5rem 0;
}
@@ -228,11 +228,7 @@
.portal-billing__meter-fill {
height: 100%;
background: linear-gradient(
90deg,
var(--color-blue, #0a8bff),
var(--color-purple, #8b5cf6)
);
background: linear-gradient(90deg, var(--color-blue), var(--color-purple));
border-radius: 999px;
transition: width 200ms ease;
}
@@ -308,28 +304,28 @@
border-radius: 999px;
}
.payg-status[data-state="FULL"] {
background: #dcfce7;
color: #15803d;
background: var(--color-green-light);
color: var(--color-green-dark);
}
.payg-status[data-state="FULL"] .payg-status__dot {
background: #22c55e;
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18);
background: var(--color-green);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-green) 18%, transparent);
}
.payg-status[data-state="WARNED"] {
background: #fef3c7;
color: #a16207;
background: var(--color-amber-light);
color: var(--color-amber-dark);
}
.payg-status[data-state="WARNED"] .payg-status__dot {
background: #eab308;
box-shadow: 0 0 0 3px rgba(234, 179, 8, 0.2);
background: var(--color-amber);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-amber) 20%, transparent);
}
.payg-status[data-state="DEGRADED"] {
background: #fee2e2;
color: #b91c1c;
background: var(--color-red-light);
color: var(--color-red-dark);
}
.payg-status[data-state="DEGRADED"] .payg-status__dot {
background: #ef4444;
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
background: var(--color-red);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-red) 20%, transparent);
}
/* Segmented usage bar */
@@ -347,13 +343,13 @@
transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.payg-bar__fill[data-state="FULL"] {
background: linear-gradient(90deg, #0a8bff, #38bdf8);
background: var(--color-blue);
}
.payg-bar__fill[data-state="WARNED"] {
background: linear-gradient(90deg, #f59e0b, #fbbf24);
background: var(--color-amber);
}
.payg-bar__fill[data-state="DEGRADED"] {
background: linear-gradient(90deg, #dc2626, #f87171);
background: var(--color-red);
}
/* ── Plan card (free state) ─────────────────────────────────────────────── */
@@ -394,7 +390,7 @@
.portal-billing__plan-features li::before {
content: "✓";
color: var(--color-green, #10b981);
color: var(--color-green);
position: absolute;
left: 0;
font-weight: 600;
@@ -457,15 +453,15 @@
}
.portal-billing__breakdown-fill--blue {
background: #0a8bff;
background: var(--color-blue);
}
.portal-billing__breakdown-fill--purple {
background: #8b5cf6;
background: var(--color-purple);
}
.portal-billing__breakdown-fill--teal {
background: #06b6d4;
background: var(--color-cat-extraction);
}
/* ── Cap control ────────────────────────────────────────────────────────── */
@@ -570,10 +566,10 @@
Same class names + structure so the visual is identical to the SaaS Plan
page; when the shared-component move lands, these dedupe to one stylesheet. */
.scc {
--scc-accent: #0a8bff;
--scc-accent-text: #0a8bff;
--scc-accent-soft: rgba(10, 139, 255, 0.12);
--scc-accent-border: rgba(10, 139, 255, 0.25);
--scc-accent: var(--color-blue);
--scc-accent-text: var(--color-blue);
--scc-accent-soft: color-mix(in srgb, var(--color-blue) 12%, transparent);
--scc-accent-border: color-mix(in srgb, var(--color-blue) 25%, transparent);
--scc-chip-bg: var(--color-bg-muted, #f8fafc);
--scc-chip-border: var(--color-border, #e2e8f0);
--scc-text-primary: var(--color-text-1, #0f172a);
@@ -585,11 +581,11 @@
gap: 14px;
margin-top: 0.75rem;
}
[data-mantine-color-scheme="dark"] .scc {
--scc-accent-text: #66b8ff;
--scc-accent-soft: rgba(10, 139, 255, 0.16);
--scc-chip-bg: #272d35;
--scc-chip-border: #3d444e;
[data-theme="dark"] .scc {
--scc-accent-text: var(--color-blue);
--scc-accent-soft: color-mix(in srgb, var(--color-blue) 16%, transparent);
--scc-chip-bg: var(--color-bg-muted);
--scc-chip-border: var(--color-border);
}
.scc-row {
@@ -736,9 +732,9 @@
white-space: nowrap;
}
.portal-billing__role-pill[data-leader="true"] {
background: rgba(10, 139, 255, 0.12);
color: #0a8bff;
border: 1px solid rgba(10, 139, 255, 0.25);
background: color-mix(in srgb, var(--color-blue) 12%, transparent);
color: var(--color-blue);
border: 1px solid color-mix(in srgb, var(--color-blue) 25%, transparent);
}
.portal-billing__role-pill[data-leader="false"] {
background: var(--color-bg-muted);
@@ -768,10 +764,10 @@
margin-bottom: 8px;
}
.portal-billing__planhead-lbl--free {
color: #10b981;
color: var(--color-green);
}
.portal-billing__planhead-lbl--meter {
color: #0a8bff;
color: var(--color-blue);
}
.portal-billing__planhead-title {
margin: 0;
@@ -839,7 +835,7 @@
.portal-billing__invoice-link:focus-visible {
outline: none;
border-color: var(--color-blue, #0a8bff);
border-color: var(--color-blue);
background: var(--color-bg-muted, #f1f5f9);
}
@@ -953,6 +949,12 @@
align-items: flex-start;
gap: 1rem;
}
/* Keep the CTA on one line at its natural width — in the narrow subscribed
column it was shrinking and clipping its label. */
.portal-billing__enterprise-head > .sui-btn {
flex-shrink: 0;
white-space: nowrap;
}
/* Bare variant — embeds in another card's column without its own surface. */
.portal-billing__enterprise-bare {
display: block;
@@ -988,13 +990,13 @@
height: 100%;
}
.portal-billing__segbar-seg--blue {
background: #0a8bff;
background: var(--color-blue);
}
.portal-billing__segbar-seg--purple {
background: #8b5cf6;
background: var(--color-purple);
}
.portal-billing__segbar-seg--teal {
background: #06b6d4;
background: var(--color-cat-extraction);
}
.portal-billing__seglegend {
display: flex;
@@ -1016,13 +1018,13 @@
flex-shrink: 0;
}
.portal-billing__dot--blue {
background: #0a8bff;
background: var(--color-blue);
}
.portal-billing__dot--purple {
background: #8b5cf6;
background: var(--color-purple);
}
.portal-billing__dot--teal {
background: #06b6d4;
background: var(--color-cat-extraction);
}
.portal-billing__seglegend-label {
font-weight: 600;
@@ -0,0 +1,34 @@
/**
* Stroke-SVG icons for source types, replacing the black Unicode glyphs
* (⛁ ☁ ✏ ◇) that rendered off-style and mis-centred inside the type tiles and
* table badges. Keyed by the backend source `type`; unknown types fall back to
* a neutral document mark.
*/
const PATHS: Record<string, string> = {
folder: "M3 7h6l2 2h10v9a1 1 0 01-1 1H4a1 1 0 01-1-1V7z",
s3: "M7 18a4 4 0 010-8 5 5 0 019.6-1.3A3.5 3.5 0 0117 18H7z",
editor: "M4 20h16M14 4l6 6-9 9H5v-6l9-9z",
_default:
"M14 3H7a1 1 0 00-1 1v16a1 1 0 001 1h10a1 1 0 001-1V7l-4-4zM14 3v4h4",
};
export function SourceTypeIcon({ type }: { type: string }) {
const d = PATHS[type] ?? PATHS._default;
return (
<svg
className="portal-sources__type-svg"
viewBox="0 0 24 24"
fill="none"
aria-hidden
>
<path
d={d}
stroke="currentColor"
strokeWidth="1.7"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
@@ -13,6 +13,7 @@ import {
EDITOR_SOURCE_TYPE,
sourceTypeMeta,
} from "@portal/components/sources/sourceTypes";
import { SourceTypeIcon } from "@portal/components/sources/SourceTypeIcon";
import "@portal/views/Sources.css";
const STATUS_TONE: Record<SourceStatus, StatusTone> = {
@@ -45,7 +46,7 @@ export function SourcesTable({ sources, onRowClick }: SourcesTableProps) {
className={`portal-sources__type-dot portal-sources__type-dot--${meta.accent}`}
aria-hidden
>
{meta.icon}
<SourceTypeIcon type={s.type} />
</span>
<div className="portal-sources__name-text">
<strong>{isEditor ? t(meta.labelKey) : s.name}</strong>
@@ -22,10 +22,12 @@ export function Pipelines() {
const { isLoading } = useSectionFlags(state);
const pipelines = data?.pipelines ?? [];
// Empty once the fetch settles with no pipelines (or fails → no data). Gates
// both the KPI strip and the empty panel so no placeholder stat boxes sit
// above an empty page.
// Empty once the fetch settles with no pipelines (or fails → no data); gates
// the empty panel below.
const showEmpty = !isLoading && pipelines.length === 0;
// The KPI strip is pure stat boxes: show it only once real pipelines exist, so
// the loading and empty states don't flash a row of placeholder cards.
const hasPipelines = pipelines.length > 0;
const openCreate = () =>
navigate(`${toPortalPath(VIEW_PATHS.pipelines)}/new`);
@@ -54,7 +56,7 @@ export function Pipelines() {
</Button>
</header>
{!showEmpty && <KpiStrip data={data} loading={loading} />}
{hasPipelines && <KpiStrip data={data} loading={loading} />}
{isLoading && (
<div className="portal-pipelines__table-skeleton" aria-hidden>
+35 -3
View File
@@ -49,6 +49,7 @@
.portal-sources__name-text {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.25rem;
min-width: 0;
}
@@ -366,7 +367,7 @@
.portal-sources__type-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
gap: 0.625rem;
}
@@ -376,6 +377,17 @@
}
}
/* The shared Button lays its children out in a flex-row label; force the type
tile back to a centred icon-over-label column so the SVG sits above the name
with real spacing (not jammed against it). */
.portal-sources__type-card .mantine-Button-label {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
width: 100%;
}
.portal-sources__type-card {
display: flex;
flex-direction: column;
@@ -402,9 +414,29 @@
box-shadow: 0 0 0 1px var(--color-blue) inset;
}
/* Icon inside the type picker: a plain stroke icon above the label (no badge
box — the tinted box read as an extra bordered chip floating on the tile). */
.portal-sources__type-icon {
font-size: 1.25rem;
color: var(--color-text-2);
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--color-text-3);
}
.portal-sources__type-card.is-selected .portal-sources__type-icon {
color: var(--color-blue);
}
.portal-sources__type-icon .portal-sources__type-svg {
width: 1.6rem;
height: 1.6rem;
}
/* Sized to sit centred inside the 1.875rem table badge / picker dot. */
.portal-sources__type-svg {
width: 1.05rem;
height: 1.05rem;
display: block;
}
.portal-sources__type-name {