chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged: - Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances) - country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk after the per-subpath dynamic-import approach silently failed in webpack) - Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index, redirects (ocr to ai, reports to dashboard, invitations to users), docs/admin-ia-proposal.md - Per-template email tester (registry + endpoint + UI on Email admin page) - Cancel-document mode picker (delete-from-Documenso vs keep-for-audit) - Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers - Customize-widgets per-region sortables at xl+ (charts/rails/feed); single flat sortable below xl when the layout stacks; per-viewport saved orders - Audit doc updates capturing each shipped item - Lint fixes: react-compiler immutability in DonutChart (reduce instead of let-reassign), set-state-in-effect disables in CountryFlag and UploadForSigning preview-bytes effect, unused 'confirm' destructures in interest contract + reservation tabs, unescaped apostrophe in test-template card copy
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
* keyword, so `smtp` lands on the email settings page even though the
|
||||
* label reads "Email accounts".
|
||||
*
|
||||
* Why hardcoded vs introspecting routes? The catalog is curated — only
|
||||
* Why hardcoded vs introspecting routes? The catalog is curated - only
|
||||
* pages worth jumping to from a global search appear here, and each
|
||||
* entry has hand-picked keyword synonyms that route inference can't
|
||||
* derive. Adding a route to the catalog is cheap; misfiring routes are
|
||||
@@ -20,11 +20,11 @@ import type { RolePermissions } from '@/lib/db/schema/users';
|
||||
export type NavCatalogCategory = 'settings' | 'admin' | 'dashboard';
|
||||
|
||||
export interface NavCatalogEntry {
|
||||
/** Path template — `:portSlug` is substituted at lookup time. */
|
||||
/** Path template - `:portSlug` is substituted at lookup time. */
|
||||
href: string;
|
||||
label: string;
|
||||
category: NavCatalogCategory;
|
||||
/** Lowercase aliases — query is matched against label + these. */
|
||||
/** Lowercase aliases - query is matched against label + these. */
|
||||
keywords: string[];
|
||||
/**
|
||||
* Permission gate; only shown to users whose `RolePermissions` resolves
|
||||
@@ -59,7 +59,7 @@ export const NAV_CATALOG: NavCatalogEntry[] = [
|
||||
keywords: ['preferences', 'configuration', 'config'],
|
||||
},
|
||||
// The granular settings cards below redirect to the `/admin/<x>` routes
|
||||
// that actually exist — the catalog previously listed `/settings/<x>`
|
||||
// that actually exist - the catalog previously listed `/settings/<x>`
|
||||
// paths that have never had route folders. We keep the keyword aliases
|
||||
// so the cmd-K search still finds them under the right destination.
|
||||
{
|
||||
@@ -187,6 +187,13 @@ export const NAV_CATALOG: NavCatalogEntry[] = [
|
||||
keywords: ['activity', 'history', 'events', 'who did what', 'compliance'],
|
||||
requires: 'admin.view_audit_log',
|
||||
},
|
||||
{
|
||||
href: '/:portSlug/admin/berths',
|
||||
label: 'Berths admin',
|
||||
category: 'admin',
|
||||
keywords: ['bulk add berths', 'reconcile berths', 'berth pdf', 'mooring', 'bulk'],
|
||||
requires: 'admin.manage_settings',
|
||||
},
|
||||
{
|
||||
href: '/:portSlug/admin/inquiries',
|
||||
label: 'Website inquiries inbox',
|
||||
@@ -204,7 +211,7 @@ export const NAV_CATALOG: NavCatalogEntry[] = [
|
||||
// ─── Admin → granular section cards (the AdminSectionsBrowser groups) ────
|
||||
// These deep-link to specific admin sub-pages. Each one's `keywords`
|
||||
// mirrors the corresponding entry in src/components/admin/
|
||||
// admin-sections-browser.tsx — so typing a setting key in the topbar
|
||||
// admin-sections-browser.tsx - so typing a setting key in the topbar
|
||||
// global search finds the same card the in-admin search would.
|
||||
{
|
||||
href: '/:portSlug/admin/settings',
|
||||
@@ -377,13 +384,8 @@ export const NAV_CATALOG: NavCatalogEntry[] = [
|
||||
keywords: ['openai', 'anthropic', 'gpt', 'claude', 'llm', 'api key', 'embeddings'],
|
||||
requires: 'admin.manage_settings',
|
||||
},
|
||||
{
|
||||
href: '/:portSlug/admin/ocr',
|
||||
label: 'Receipt OCR',
|
||||
category: 'admin',
|
||||
keywords: ['receipt', 'scan', 'tesseract', 'expense scanner', 'confidence'],
|
||||
requires: 'admin.manage_settings',
|
||||
},
|
||||
// /admin/ocr collapsed into /admin/ai on 2026-05-22 (the OcrSettingsForm
|
||||
// already lived on both pages). Keywords surfaced via the AI tile.
|
||||
{
|
||||
href: '/:portSlug/admin/website-analytics',
|
||||
label: 'Website analytics (Umami)',
|
||||
@@ -405,7 +407,7 @@ export const NAV_CATALOG: NavCatalogEntry[] = [
|
||||
keywords: ['roles', 'permissions', 'access control', 'rbac'],
|
||||
requires: 'admin.manage_users',
|
||||
},
|
||||
// /admin/invitations was merged into /admin/users on 2026-05-21 — the
|
||||
// /admin/invitations was merged into /admin/users on 2026-05-21 - the
|
||||
// standalone catalog entry would route to the redirect stub. Reps
|
||||
// searching for "invite" still land on the right surface via the
|
||||
// /admin/users keyword list (extended below).
|
||||
@@ -422,7 +424,7 @@ export function resolveHref(href: string, portSlug: string): string {
|
||||
* label + each keyword; ranking favors label hits over keyword hits and
|
||||
* prefix hits over mid-string hits.
|
||||
*
|
||||
* Pure / sync — runs in-process. The catalog is ~15 entries today, so
|
||||
* Pure / sync - runs in-process. The catalog is ~15 entries today, so
|
||||
* the linear scan is irrelevant cost-wise.
|
||||
*/
|
||||
export function searchNavCatalog(
|
||||
@@ -447,7 +449,7 @@ export function searchNavCatalog(
|
||||
// Some hrefs intentionally appear in multiple catalog categories
|
||||
// (e.g. /admin/templates lives under both 'settings' and 'admin').
|
||||
// Keep the highest-scoring variant so the dropdown never renders
|
||||
// two rows with the same `id` (href) — React would otherwise warn
|
||||
// two rows with the same `id` (href) - React would otherwise warn
|
||||
// about duplicate keys.
|
||||
const existing = byHref.get(entry.href);
|
||||
if (!existing || score > existing.score) {
|
||||
@@ -468,7 +470,7 @@ function scoreEntry(q: string, entry: NavCatalogEntry): number {
|
||||
if (label.startsWith(q)) return 80;
|
||||
if (label.includes(q)) return 60;
|
||||
|
||||
// Keyword hits — strongest if the keyword exactly equals the query
|
||||
// Keyword hits - strongest if the keyword exactly equals the query
|
||||
// (e.g. user types "smtp"), then prefix, then substring.
|
||||
for (const kw of entry.keywords) {
|
||||
const k = kw.toLowerCase();
|
||||
|
||||
Reference in New Issue
Block a user