Fix settings toggles layout and add processing-log retention controls

This commit is contained in:
2026-02-21 12:09:01 -03:00
parent 4beab4bc09
commit a18545fb18
4 changed files with 165 additions and 8 deletions

View File

@@ -12,6 +12,7 @@ import type {
DisplaySettings,
HandwritingStyleClusteringSettings,
OcrTaskSettings,
ProcessingLogRetentionSettings,
PredefinedPathEntry,
PredefinedTagEntry,
ProviderSettings,
@@ -47,6 +48,24 @@ function parseCardsPerPageInput(input: string, fallback: number): number {
return clampCardsPerPage(parsed);
}
const DEFAULT_PROCESSING_LOG_RETENTION: ProcessingLogRetentionSettings = {
keep_document_sessions: 2,
keep_unbound_entries: 80,
};
const PROCESSING_LOG_SESSION_MIN = 0;
const PROCESSING_LOG_SESSION_MAX = 20;
const PROCESSING_LOG_UNBOUND_MIN = 0;
const PROCESSING_LOG_UNBOUND_MAX = 400;
function clampProcessingLogDocumentSessions(value: number): number {
return Math.max(PROCESSING_LOG_SESSION_MIN, Math.min(PROCESSING_LOG_SESSION_MAX, value));
}
function clampProcessingLogUnboundEntries(value: number): number {
return Math.max(PROCESSING_LOG_UNBOUND_MIN, Math.min(PROCESSING_LOG_UNBOUND_MAX, value));
}
/**
* Renders compact human-oriented settings controls.
*/
@@ -69,6 +88,7 @@ export default function SettingsScreen({
const [newPredefinedTag, setNewPredefinedTag] = useState<string>('');
const [uploadDefaults, setUploadDefaults] = useState<UploadDefaultsSettings | null>(null);
const [displaySettings, setDisplaySettings] = useState<DisplaySettings | null>(null);
const [processingLogRetention, setProcessingLogRetention] = useState<ProcessingLogRetentionSettings | null>(null);
const [cardsPerPageInput, setCardsPerPageInput] = useState<string>('12');
const [error, setError] = useState<string | null>(null);
@@ -92,6 +112,15 @@ export default function SettingsScreen({
setPredefinedTags(settings.predefined_tags);
setUploadDefaults(settings.upload_defaults);
setDisplaySettings(settings.display);
setProcessingLogRetention({
keep_document_sessions: clampProcessingLogDocumentSessions(
settings.processing_log_retention?.keep_document_sessions ??
DEFAULT_PROCESSING_LOG_RETENTION.keep_document_sessions,
),
keep_unbound_entries: clampProcessingLogUnboundEntries(
settings.processing_log_retention?.keep_unbound_entries ?? DEFAULT_PROCESSING_LOG_RETENTION.keep_unbound_entries,
),
});
setCardsPerPageInput(String(settings.display.cards_per_page));
setError(null);
}, [settings]);
@@ -163,7 +192,15 @@ export default function SettingsScreen({
};
const handleSave = useCallback(async (): Promise<void> => {
if (!ocrTask || !summaryTask || !routingTask || !handwritingStyle || !uploadDefaults || !displaySettings) {
if (
!ocrTask ||
!summaryTask ||
!routingTask ||
!handwritingStyle ||
!uploadDefaults ||
!displaySettings ||
!processingLogRetention
) {
setError('Settings are not fully loaded yet');
return;
}
@@ -175,7 +212,12 @@ export default function SettingsScreen({
setError(null);
try {
const resolvedCardsPerPage = parseCardsPerPageInput(cardsPerPageInput, displaySettings.cards_per_page);
const resolvedProcessingLogRetention: ProcessingLogRetentionSettings = {
keep_document_sessions: clampProcessingLogDocumentSessions(processingLogRetention.keep_document_sessions),
keep_unbound_entries: clampProcessingLogUnboundEntries(processingLogRetention.keep_unbound_entries),
};
setDisplaySettings({ ...displaySettings, cards_per_page: resolvedCardsPerPage });
setProcessingLogRetention(resolvedProcessingLogRetention);
setCardsPerPageInput(String(resolvedCardsPerPage));
await onSave({
@@ -187,6 +229,7 @@ export default function SettingsScreen({
cards_per_page: resolvedCardsPerPage,
log_typing_animation_enabled: displaySettings.log_typing_animation_enabled,
},
processing_log_retention: resolvedProcessingLogRetention,
predefined_paths: predefinedPaths,
predefined_tags: predefinedTags,
handwriting_style_clustering: {
@@ -252,21 +295,51 @@ export default function SettingsScreen({
routingTask,
summaryTask,
uploadDefaults,
processingLogRetention,
]);
useEffect(() => {
if (!onRegisterSaveAction) {
return;
}
if (!settings || !ocrTask || !summaryTask || !routingTask || !handwritingStyle || !uploadDefaults || !displaySettings) {
if (
!settings ||
!ocrTask ||
!summaryTask ||
!routingTask ||
!handwritingStyle ||
!uploadDefaults ||
!displaySettings ||
!processingLogRetention
) {
onRegisterSaveAction(null);
return;
}
onRegisterSaveAction(() => handleSave());
return () => onRegisterSaveAction(null);
}, [displaySettings, handleSave, handwritingStyle, ocrTask, onRegisterSaveAction, routingTask, settings, summaryTask, uploadDefaults]);
}, [
displaySettings,
handleSave,
handwritingStyle,
ocrTask,
onRegisterSaveAction,
processingLogRetention,
routingTask,
settings,
summaryTask,
uploadDefaults,
]);
if (!settings || !ocrTask || !summaryTask || !routingTask || !handwritingStyle || !uploadDefaults || !displaySettings) {
if (
!settings ||
!ocrTask ||
!summaryTask ||
!routingTask ||
!handwritingStyle ||
!uploadDefaults ||
!displaySettings ||
!processingLogRetention
) {
return (
<section className="settings-layout">
<div className="settings-card">
@@ -313,6 +386,42 @@ export default function SettingsScreen({
onChange={(event) => setCardsPerPageInput(event.target.value)}
/>
</label>
<label className="settings-field">
Keep document sessions
<input
type="number"
min={PROCESSING_LOG_SESSION_MIN}
max={PROCESSING_LOG_SESSION_MAX}
value={processingLogRetention.keep_document_sessions}
onChange={(event) => {
const nextValue = Number.parseInt(event.target.value, 10);
if (!Number.isNaN(nextValue)) {
setProcessingLogRetention({
...processingLogRetention,
keep_document_sessions: clampProcessingLogDocumentSessions(nextValue),
});
}
}}
/>
</label>
<label className="settings-field">
Keep unbound entries
<input
type="number"
min={PROCESSING_LOG_UNBOUND_MIN}
max={PROCESSING_LOG_UNBOUND_MAX}
value={processingLogRetention.keep_unbound_entries}
onChange={(event) => {
const nextValue = Number.parseInt(event.target.value, 10);
if (!Number.isNaN(nextValue)) {
setProcessingLogRetention({
...processingLogRetention,
keep_unbound_entries: clampProcessingLogUnboundEntries(nextValue),
});
}
}}
/>
</label>
<label className="inline-checkbox settings-checkbox-field">
<input
type="checkbox"
@@ -323,6 +432,9 @@ export default function SettingsScreen({
/>
Processing log typing animation enabled
</label>
<p className="small settings-helper-text">
Processing-log retention values are used by backend trim routines when pruning historical entries.
</p>
</div>
</div>