forked from jappel/leistungsbilanz-ts
Harden authentication and put filter toggle and fields in one row
Security: per-username login throttling, constant-time unknown-user check, Sec-Fetch-Site CSRF guard for writes, session rotation on login and password change, absolute session lifetime, sessions ended on reset and deactivation, last-admin protection, input length caps, ASCII usernames, clickjacking headers. Covered by tests/authentication.test.ts. Filter panel: toggle, fields and count share one row to save space. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8d2948cdb1
commit
5073d9342a
18 changed files with 683 additions and 81 deletions
|
|
@ -55,9 +55,15 @@ export function CollapsibleFilterPanel({
|
|||
writeCollapsed(storageKey, next);
|
||||
}
|
||||
|
||||
// One row: toggle, then either the "Filter" label (collapsed) or the filter
|
||||
// fields themselves (expanded), and the count at the right edge.
|
||||
return (
|
||||
<div className="filter-panel">
|
||||
<div className="filter-panel-header">
|
||||
<div
|
||||
className={
|
||||
isCollapsed ? "filter-panel-row" : "filter-panel-row filter-panel-row-expanded"
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
ariaControls={barId}
|
||||
ariaExpanded={!isCollapsed}
|
||||
|
|
@ -66,29 +72,30 @@ export function CollapsibleFilterPanel({
|
|||
label={isCollapsed ? "Filter einblenden" : "Filter ausblenden"}
|
||||
onClick={toggleCollapsed}
|
||||
/>
|
||||
<span className="filter-panel-label">Filter</span>
|
||||
{isCollapsed && isFilterActive ? (
|
||||
<span className="filter-panel-badge">Filter aktiv</span>
|
||||
) : null}
|
||||
{isCollapsed ? (
|
||||
<>
|
||||
<span className="filter-panel-label">Filter</span>
|
||||
{isFilterActive ? <span className="filter-panel-badge">Filter aktiv</span> : null}
|
||||
</>
|
||||
) : (
|
||||
<div className="filter-bar" id={barId}>
|
||||
{children}
|
||||
{isFilterActive ? (
|
||||
<IconButton
|
||||
className="filter-bar-reset"
|
||||
icon={FilterX}
|
||||
label="Zurücksetzen"
|
||||
onClick={onReset}
|
||||
showLabel
|
||||
title="Alle Filter zurücksetzen"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
<span aria-live="polite" className="filter-panel-count">
|
||||
{visibleCount} von {totalCount}
|
||||
</span>
|
||||
</div>
|
||||
{isCollapsed ? null : (
|
||||
<div className="filter-bar" id={barId}>
|
||||
{children}
|
||||
{isFilterActive ? (
|
||||
<IconButton
|
||||
className="filter-bar-reset"
|
||||
icon={FilterX}
|
||||
label="Zurücksetzen"
|
||||
onClick={onReset}
|
||||
showLabel
|
||||
title="Alle Filter zurücksetzen"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue