feat(extension): wire history sidebar slot + #history/<id> route normalization

This commit is contained in:
adlee-was-taken
2026-05-30 10:44:58 -04:00
parent 32e1632c42
commit 88d7228570

View File

@@ -12,7 +12,7 @@ import { registerHost } from '../shared/state';
import { lookupErrorCopy, type ErrorCta } from '../shared/error-copy'; import { lookupErrorCopy, type ErrorCta } from '../shared/error-copy';
import { relativeTime } from '../shared/relative-time'; import { relativeTime } from '../shared/relative-time';
import { import {
GLYPH_TRASH, GLYPH_DEVICES, GLYPH_SETTINGS, GLYPH_LOCK, GLYPH_TRASH, GLYPH_DEVICES, GLYPH_SETTINGS, GLYPH_LOCK, GLYPH_HISTORY,
GLYPH_TYPE_LOGIN, GLYPH_TYPE_SECURE_NOTE, GLYPH_TYPE_TOTP, GLYPH_TYPE_LOGIN, GLYPH_TYPE_SECURE_NOTE, GLYPH_TYPE_TOTP,
GLYPH_TYPE_CARD, GLYPH_TYPE_IDENTITY, GLYPH_TYPE_KEY, GLYPH_TYPE_DOCUMENT, GLYPH_TYPE_CARD, GLYPH_TYPE_IDENTITY, GLYPH_TYPE_KEY, GLYPH_TYPE_DOCUMENT,
} from '../shared/glyphs'; } from '../shared/glyphs';
@@ -23,6 +23,7 @@ import { renderDevices, teardown as teardownDevices } from '../popup/components/
import { renderSettings, teardownSettings } from '../popup/components/settings'; import { renderSettings, teardownSettings } from '../popup/components/settings';
import { renderVaultSettings as renderVaultSettingsView } from '../popup/components/settings-vault'; import { renderVaultSettings as renderVaultSettingsView } from '../popup/components/settings-vault';
import { renderFieldHistory, teardown as teardownFieldHistory } from '../popup/components/field-history'; import { renderFieldHistory, teardown as teardownFieldHistory } from '../popup/components/field-history';
import { renderItemHistoryIndex, teardown as teardownHistoryIndex } from '../popup/components/item-history-index';
import { renderBackupPanel, teardown as teardownBackup } from './components/backup-panel'; import { renderBackupPanel, teardown as teardownBackup } from './components/backup-panel';
import { renderImportPanel, teardown as teardownImport } from './components/import-panel'; import { renderImportPanel, teardown as teardownImport } from './components/import-panel';
import { applyColorScheme } from '../shared/color-scheme'; import { applyColorScheme } from '../shared/color-scheme';
@@ -127,7 +128,7 @@ function typeLabel(t: ItemType): string {
// Hash routing // Hash routing
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
type VaultView = 'list' | 'detail' | 'add' | 'edit' | 'trash' | 'devices' | 'settings' | 'settings-vault' | 'field-history' | 'backup' | 'import'; type VaultView = 'list' | 'detail' | 'add' | 'edit' | 'trash' | 'devices' | 'settings' | 'settings-vault' | 'field-history' | 'history' | 'backup' | 'import';
interface HashRoute { interface HashRoute {
view: VaultView; view: VaultView;
@@ -136,9 +137,15 @@ interface HashRoute {
} }
function parseHash(): HashRoute { function parseHash(): HashRoute {
const raw = window.location.hash.replace(/^#\/?/, ''); let raw = window.location.hash.replace(/^#\/?/, '');
if (!raw) return { view: 'list' }; if (!raw) return { view: 'list' };
// Normalize legacy bookmarks: #field-history/<id> → #history/<id>
if (raw.startsWith('field-history/')) {
raw = 'history/' + raw.slice('field-history/'.length);
window.location.hash = raw;
}
const parts = raw.split('/'); const parts = raw.split('/');
const view = parts[0] as VaultView; const view = parts[0] as VaultView;
@@ -148,6 +155,10 @@ function parseHash(): HashRoute {
return { view, id: parts[1] }; return { view, id: parts[1] };
case 'add': case 'add':
return { view, type: parts[1] }; return { view, type: parts[1] };
case 'history':
return parts[1]
? { view: 'field-history', id: parts[1] }
: { view: 'history' };
case 'trash': case 'trash':
case 'devices': case 'devices':
case 'settings': case 'settings':
@@ -317,6 +328,7 @@ function renderShell(app: HTMLElement): void {
<button class="vault-sidebar__nav-item" data-nav="trash" title="Trash">${GLYPH_TRASH} <span class="vault-sidebar__nav-label">trash</span></button> <button class="vault-sidebar__nav-item" data-nav="trash" title="Trash">${GLYPH_TRASH} <span class="vault-sidebar__nav-label">trash</span></button>
<button class="vault-sidebar__nav-item" data-nav="devices" title="Devices">${GLYPH_DEVICES} <span class="vault-sidebar__nav-label">devices</span></button> <button class="vault-sidebar__nav-item" data-nav="devices" title="Devices">${GLYPH_DEVICES} <span class="vault-sidebar__nav-label">devices</span></button>
<button class="vault-sidebar__nav-item" data-nav="settings" title="Settings">${GLYPH_SETTINGS} <span class="vault-sidebar__nav-label">settings</span></button> <button class="vault-sidebar__nav-item" data-nav="settings" title="Settings">${GLYPH_SETTINGS} <span class="vault-sidebar__nav-label">settings</span></button>
<button class="vault-sidebar__nav-item" data-nav="history" title="History">${GLYPH_HISTORY} <span class="vault-sidebar__nav-label">history</span></button>
<button class="vault-sidebar__nav-item" data-nav="lock" title="Lock">${GLYPH_LOCK} <span class="vault-sidebar__nav-label">lock</span></button> <button class="vault-sidebar__nav-item" data-nav="lock" title="Lock">${GLYPH_LOCK} <span class="vault-sidebar__nav-label">lock</span></button>
</div> </div>
</div> </div>
@@ -580,7 +592,7 @@ function wireSidebar(): void {
openTypePanel(); openTypePanel();
return; return;
} }
if (nav === 'trash' || nav === 'devices' || nav === 'settings') { if (nav === 'trash' || nav === 'devices' || nav === 'settings' || nav === 'history') {
state.selectedId = null; state.selectedId = null;
state.selectedItem = null; state.selectedItem = null;
state.newType = null; state.newType = null;
@@ -808,6 +820,7 @@ function teardownPaneComponents(): void {
teardownDevices(); teardownDevices();
teardownSettings(); teardownSettings();
teardownFieldHistory(); teardownFieldHistory();
teardownHistoryIndex();
teardownBackup(); teardownBackup();
teardownImport(); teardownImport();
} }
@@ -865,6 +878,9 @@ function renderPane(): void {
case 'field-history': case 'field-history':
renderFieldHistory(pane); renderFieldHistory(pane);
break; break;
case 'history':
renderItemHistoryIndex(pane);
break;
case 'backup': case 'backup':
renderBackupPanel(pane); renderBackupPanel(pane);
break; break;