feat(ext/settings): retention section (trash + field history)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { sendMessage, escapeHtml } from '../../shared/state';
|
||||
import type { VaultSettings, DeviceSettings } from '../../shared/types';
|
||||
import type { VaultSettings, DeviceSettings, TrashRetention, HistoryRetention } from '../../shared/types';
|
||||
import type { ColorScheme } from '../../shared/color-scheme';
|
||||
import {
|
||||
loadColorScheme, saveColorScheme, resetColorScheme,
|
||||
@@ -285,7 +285,103 @@ async function renderGeneratorSection(content: HTMLElement): Promise<void> {
|
||||
}
|
||||
|
||||
async function renderRetentionSection(content: HTMLElement): Promise<void> {
|
||||
content.innerHTML = '<p class="muted" style="padding:20px;font-size:12px;">Retention — coming soon</p>';
|
||||
content.innerHTML = '<p class="muted" style="padding:20px;font-size:12px;">Loading…</p>';
|
||||
const resp = await sendMessage({ type: 'get_vault_settings' });
|
||||
if (!resp.ok) {
|
||||
content.innerHTML = `<p class="muted" style="padding:20px;">Failed to load: ${escapeHtml(resp.error ?? 'unknown')}</p>`;
|
||||
return;
|
||||
}
|
||||
const settings = (resp.data as { settings: VaultSettings }).settings;
|
||||
pendingVaultSettings = { ...settings };
|
||||
|
||||
content.innerHTML = `
|
||||
<h3 class="settings-section-title">Trash retention</h3>
|
||||
<div class="setting-row">
|
||||
<div class="setting-row__info">
|
||||
<div class="setting-row__title">Keep deleted items for</div>
|
||||
<div class="setting-row__desc">Items in trash older than this are permanently deleted on the next sync.</div>
|
||||
</div>
|
||||
<div class="setting-row__control">
|
||||
<select id="trash-retention" style="font-size:12px;">
|
||||
<option value="days:7">7 days</option>
|
||||
<option value="days:30">30 days</option>
|
||||
<option value="days:90">90 days</option>
|
||||
<option value="forever">Forever</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="settings-section-title" style="margin-top:20px;">Field history retention</h3>
|
||||
<div class="setting-row">
|
||||
<div class="setting-row__info">
|
||||
<div class="setting-row__title">Keep password history for</div>
|
||||
<div class="setting-row__desc">History entries older than this are pruned on save.</div>
|
||||
</div>
|
||||
<div class="setting-row__control">
|
||||
<select id="history-retention" style="font-size:12px;">
|
||||
<option value="last_n:5">Last 5</option>
|
||||
<option value="last_n:10">Last 10</option>
|
||||
<option value="days:90">90 days</option>
|
||||
<option value="days:365">1 year</option>
|
||||
<option value="forever">Forever</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:12px;">
|
||||
<button class="btn btn-primary" id="save-retention" style="font-size:11px;">Save retention settings</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Set current select values
|
||||
(document.getElementById('trash-retention') as HTMLSelectElement).value =
|
||||
trashRetentionToValue(settings.trash_retention);
|
||||
(document.getElementById('history-retention') as HTMLSelectElement).value =
|
||||
historyRetentionToValue(settings.field_history_retention);
|
||||
|
||||
document.getElementById('trash-retention')?.addEventListener('change', (e) => {
|
||||
if (pendingVaultSettings) {
|
||||
pendingVaultSettings.trash_retention = valueToTrashRetention((e.target as HTMLSelectElement).value);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('history-retention')?.addEventListener('change', (e) => {
|
||||
if (pendingVaultSettings) {
|
||||
pendingVaultSettings.field_history_retention = valueToHistoryRetention((e.target as HTMLSelectElement).value);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('save-retention')?.addEventListener('click', async () => {
|
||||
if (!pendingVaultSettings) return;
|
||||
const r = await sendMessage({ type: 'update_vault_settings', settings: pendingVaultSettings });
|
||||
if (!r.ok) alert(`Save failed: ${r.error}`);
|
||||
});
|
||||
}
|
||||
|
||||
function trashRetentionToValue(r: TrashRetention): string {
|
||||
if (r.kind === 'forever') return 'forever';
|
||||
return `days:${r.value}`;
|
||||
}
|
||||
|
||||
function valueToTrashRetention(v: string): TrashRetention {
|
||||
if (v === 'forever') return { kind: 'forever' };
|
||||
const m = /^days:(\d+)$/.exec(v);
|
||||
if (m) return { kind: 'days', value: Number(m[1]) };
|
||||
return { kind: 'forever' };
|
||||
}
|
||||
|
||||
function historyRetentionToValue(r: HistoryRetention): string {
|
||||
if (r.kind === 'forever') return 'forever';
|
||||
if (r.kind === 'last_n') return `last_n:${r.value}`;
|
||||
return `days:${r.value}`;
|
||||
}
|
||||
|
||||
function valueToHistoryRetention(v: string): HistoryRetention {
|
||||
if (v === 'forever') return { kind: 'forever' };
|
||||
const mLast = /^last_n:(\d+)$/.exec(v);
|
||||
if (mLast) return { kind: 'last_n', value: Number(mLast[1]) };
|
||||
const mDays = /^days:(\d+)$/.exec(v);
|
||||
if (mDays) return { kind: 'days', value: Number(mDays[1]) };
|
||||
return { kind: 'forever' };
|
||||
}
|
||||
|
||||
function renderBackupSection(content: HTMLElement): void {
|
||||
|
||||
Reference in New Issue
Block a user