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:
@@ -72,7 +72,7 @@ export type RolePermissions = {
|
||||
* an interest). Carved out from `invoices.record_payment` so a port
|
||||
* that does not use the invoicing module at all can still grant
|
||||
* payment-recording rights to sales reps. `view` follows interests.view
|
||||
* at the route level — this gate only governs the UI affordance.
|
||||
* at the route level - this gate only governs the UI affordance.
|
||||
*/
|
||||
payments: {
|
||||
view: boolean;
|
||||
@@ -166,7 +166,7 @@ export type RolePermissions = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Per-table column visibility — drives the `<ColumnPicker>` and the
|
||||
* Per-table column visibility - drives the `<ColumnPicker>` and the
|
||||
* DataTable `columnVisibility` state. `hiddenColumns` is the source of
|
||||
* truth; an entry's absence means "show this column" (so newly-added
|
||||
* columns show by default for existing users without us having to
|
||||
@@ -198,20 +198,27 @@ export type UserPreferences = {
|
||||
/**
|
||||
* Dashboard widget visibility, keyed by widget id from the registry
|
||||
* in `src/components/dashboard/widget-registry.ts`. Missing keys fall
|
||||
* back to `defaultVisible` from the registry — so adding a new widget
|
||||
* back to `defaultVisible` from the registry - so adding a new widget
|
||||
* surfaces it for everyone without a migration. `false` hides it.
|
||||
*/
|
||||
dashboardWidgets?: Record<string, boolean>;
|
||||
/**
|
||||
* Ordered list of widget ids — drives the dashboard render order so a
|
||||
* rep can drag tiles around and have the layout persist. Missing
|
||||
* widgets (ids not in the array) render after the listed ones in
|
||||
* registry order, so adding a new widget always surfaces it without
|
||||
* a migration. Order is scoped per widget group implicitly — the
|
||||
* shell groups by `widget.group` first (chart / rail / feed) then
|
||||
* sorts within the group by this array.
|
||||
* Ordered list of widget ids for the **desktop / xl layout** (charts
|
||||
* column + rails aside + feed row, side-by-side). Drives the render
|
||||
* order at viewport widths >= 1280px. Missing widgets fall through to
|
||||
* registry order so newly-added widgets always surface.
|
||||
*/
|
||||
dashboardWidgetOrder?: string[];
|
||||
/**
|
||||
* Ordered list of widget ids for the **stacked layout** (single
|
||||
* column at < xl). Reps reasonably want a different order on mobile
|
||||
* vs desktop - Reminders + Activity top on the phone, Pipeline Funnel
|
||||
* top on a 27" monitor. When unset, the dashboard falls back to
|
||||
* `dashboardWidgetOrder` (then registry order) so a rep who only
|
||||
* customized desktop sees the same order on a phone until they
|
||||
* customize there too.
|
||||
*/
|
||||
dashboardWidgetOrderMobile?: string[];
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
@@ -274,7 +281,7 @@ export const userProfiles = pgTable(
|
||||
userId: text('user_id').notNull().unique(), // references Better Auth user ID
|
||||
/**
|
||||
* Canonical first/last name pair. Added 2026-05-09 as the primary
|
||||
* source for greetings, invoicing, and DocSign field-merging — the
|
||||
* source for greetings, invoicing, and DocSign field-merging - the
|
||||
* older `displayName` is now kept around as a derived/optional
|
||||
* override (e.g. for nicknames or vanity formatting). When migrating
|
||||
* production, backfill these columns from displayName by splitting
|
||||
@@ -293,7 +300,7 @@ export const userProfiles = pgTable(
|
||||
*/
|
||||
username: text('username'),
|
||||
avatarUrl: text('avatar_url'),
|
||||
/** FK into the polymorphic `files` table — the avatar is stored
|
||||
/** FK into the polymorphic `files` table - the avatar is stored
|
||||
* via getStorageBackend() so an S3↔filesystem swap carries it
|
||||
* without breaking the URL. The legacy `avatarUrl` column is
|
||||
* kept for any external photo sources but the file pointer wins
|
||||
@@ -330,7 +337,7 @@ export const roles = pgTable('roles', {
|
||||
* Per-user permission overrides layered on top of the role's baseline for
|
||||
* a specific port. Each row carries a `Partial<RolePermissions>` map; any
|
||||
* explicitly-set leaf wins over the role + port-role-override chain. Most
|
||||
* users will never have a row here — it exists for the rare "give Alice
|
||||
* users will never have a row here - it exists for the rare "give Alice
|
||||
* the same role as her team but let her run permanent deletes" case.
|
||||
*
|
||||
* Effective permission resolution lives in `getEffectivePermissions` in
|
||||
@@ -344,7 +351,7 @@ export const userPermissionOverrides = pgTable(
|
||||
.$defaultFn(() => crypto.randomUUID()),
|
||||
// onDelete: 'cascade' is intentional here (not 'set null' as a stale 2026-05-12
|
||||
// audit item suggested). A permission override has no semantic value without
|
||||
// the user it grants permissions to — preserving a row with user_id=NULL
|
||||
// the user it grants permissions to - preserving a row with user_id=NULL
|
||||
// would be an orphan with no audit value, since the override is per-user
|
||||
// additive permissions, not a historical event we need to retain.
|
||||
userId: text('user_id')
|
||||
|
||||
Reference in New Issue
Block a user