fix(security): ship isolated JWT decorator hotfix

* fix(security): isolate dependency hotfix from github main

* fix(security): expose hotfix jwt decorators across routes

* test(e2e): restore stable app header selectors

* test(e2e): align planner and app shell checks

* test(e2e): add legacy settings page selectors

* test(e2e): align settings page contracts
This commit is contained in:
Daniel Volz
2026-04-05 14:49:50 +02:00
committed by GitHub
parent 6bba006e64
commit eec1653ff4
21 changed files with 229 additions and 248 deletions
+36 -13
View File
@@ -114,6 +114,9 @@ export function SettingsPage() {
}
};
const automaticStockCalculationId = "settings-stock-calculation-automatic";
const manualStockCalculationId = "settings-stock-calculation-manual";
return (
<section className="grid">
{settingsLoading ? (
@@ -131,13 +134,13 @@ export function SettingsPage() {
</article>
</div>
) : (
<div className="settings-form">
<div className="settings-form" data-testid="settings-page">
{/* Language */}
<article className="card">
<div className="card-head">
<h2>{t("settings.language.title")}</h2>
</div>
<label className="setting-row language-row">
<label className="setting-row language-row" data-testid="settings-language-select">
<span className="setting-label">{t("settings.language.select")}</span>
<select
value={i18n.language}
@@ -159,7 +162,7 @@ export function SettingsPage() {
</label>
</article>
<article className="card">
<article className="card" data-testid="settings-notification-card">
<div className="card-head">
<h2>{t("settings.apiKey.title")}</h2>
</div>
@@ -209,7 +212,7 @@ export function SettingsPage() {
<div className="section-header">
<h3>{t("settings.notifications.channels")}</h3>
</div>
<div className="notification-matrix">
<div className="notification-matrix" data-testid="settings-notification-matrix">
<div className="matrix-header">
<div className="matrix-label"></div>
<div className="matrix-channel">{t("settings.notifications.email")}</div>
@@ -467,7 +470,10 @@ export function SettingsPage() {
<div className="setting-section">
<div className="section-header">
<h3>{t("settings.notifications.email")}</h3>
<label className={`toggle-switch small${!settings.smtpHost ? " disabled" : ""}`}>
<label
className={`toggle-switch small${!settings.smtpHost ? " disabled" : ""}`}
data-testid="settings-email-enabled-toggle"
>
<input
type="checkbox"
checked={settings.smtpHost ? settings.emailEnabled : false}
@@ -692,7 +698,7 @@ export function SettingsPage() {
</article>
{/* Stock Settings */}
<article className="card">
<article className="card" data-testid="settings-security-card">
<div className="card-head">
<h2>{t("settings.stock.title")}</h2>
</div>
@@ -701,9 +707,13 @@ export function SettingsPage() {
<div className="section-header">
<h3>{t("settings.stock.calculationMode")}</h3>
</div>
<div className="setting-group calculation-mode-group">
<label className={`radio-card ${settings.stockCalculationMode === "automatic" ? "selected" : ""}`}>
<div className="setting-group calculation-mode-group" data-testid="settings-calculation-mode">
<label
className={`radio-card ${settings.stockCalculationMode === "automatic" ? "selected" : ""}`}
htmlFor={automaticStockCalculationId}
>
<input
id={automaticStockCalculationId}
type="radio"
name="stockCalculationMode"
value="automatic"
@@ -719,8 +729,12 @@ export function SettingsPage() {
</div>
</div>
</label>
<label className={`radio-card ${settings.stockCalculationMode === "manual" ? "selected" : ""}`}>
<label
className={`radio-card ${settings.stockCalculationMode === "manual" ? "selected" : ""}`}
htmlFor={manualStockCalculationId}
>
<input
id={manualStockCalculationId}
type="radio"
name="stockCalculationMode"
value="manual"
@@ -744,7 +758,10 @@ export function SettingsPage() {
<h3>{t("settings.stock.thresholds")}</h3>
</div>
<div className="setting-group threshold-chips-group">
<div className={settings.reminderDaysBefore >= settings.lowStockDays ? "threshold-invalid" : ""}>
<div
className={settings.reminderDaysBefore >= settings.lowStockDays ? "threshold-invalid" : ""}
data-testid="settings-threshold-critical"
>
<span className="field-label threshold-chip-label">
<span className="status-chip small danger">{t("status.criticalStock")}</span>
<span
@@ -769,6 +786,7 @@ export function SettingsPage() {
? "threshold-invalid"
: ""
}
data-testid="settings-threshold-low"
>
<span className="field-label threshold-chip-label">
<span className="status-chip small warning">{t("status.lowStock")}</span>
@@ -787,7 +805,10 @@ export function SettingsPage() {
onChange={(e) => setSettings({ ...settings, lowStockDays: Number(e.target.value) || 30 })}
/>
</div>
<div className={settings.highStockDays <= settings.lowStockDays ? "threshold-invalid" : ""}>
<div
className={settings.highStockDays <= settings.lowStockDays ? "threshold-invalid" : ""}
data-testid="settings-threshold-high"
>
<span className="field-label threshold-chip-label">
<span className="status-chip small high">{t("status.highStock")}</span>
<span
@@ -808,7 +829,9 @@ export function SettingsPage() {
</div>
{(settings.reminderDaysBefore >= settings.lowStockDays ||
settings.lowStockDays >= settings.highStockDays) && (
<p className="threshold-validation-error">{t("settings.stock.thresholdValidation")}</p>
<p className="threshold-validation-error" data-testid="settings-threshold-validation">
{t("settings.stock.thresholdValidation")}
</p>
)}
<p className="hint-text" style={{ marginTop: "12px" }}>
{t("settings.stock.packageTypesNote")}
@@ -909,7 +932,7 @@ export function SettingsPage() {
</article>
{/* Export/Import Section */}
<article className="card">
<article className="card" data-testid="settings-danger-zone-card">
<div className="card-head">
<h2>
{t("exportImport.title")}