refactor(inbox): derive from snapshot; delete getInbox IPC chain
Sibling refactor to the sidebar-badges cleanup. The inbox aggregates five item categories (pending approvals, failed runs, budget warnings, blocked/review tasks, unread company/incident/urgent messages) — every row is already in `ProfileSnapshot`. The server-side `getInbox` aggregation (180 lines of SQL + projection) was a redundant second path. New: `src/shared/inbox-items.ts::deriveInboxItems(snapshot, companyId)` produces the same InboxItem[] shape with the same severity ordering and 24h failed-run window. Pure function, no IPC, no state. Deleted: - database/company-crud.ts::getInbox (180-line aggregation) - database-base.ts::getInbox pass-through - ipc-core-read-handlers.ts: handler - preload/index.ts: bridge binding - shared/contracts/channels.ts: channel name - shared/contracts/desktop-api/companies.ts: API signature - state/slices/company.ts: `inboxItems` field, `setInboxItems` action - useDataLoader.ts: both getInbox call sites (initial snapshot load and section-change effect) - useCompanyController.ts: inbox reset on company switch OperationsSections now computes `inboxItems` via `useMemo` off the current snapshot + company id. The snapshot is already company-scoped at the main/database/snapshot.ts layer when `currentCompanyId` is non-null; the derivation re-filters defensively so the function works correctly even for unscoped snapshots. Tests: 603/603 green. No new tests added — the derivation is a pure function whose shape is exercised end-to-end by the existing Inbox component integration.
This commit is contained in:
1 parent
487f2456ff
commit
6abc1a823f
11 files changed
+180
-220
No files matched your search
@@ -4,17 +4,17 @@ import type {
|
||||
AgentRecord,
|
||||
ApprovalRecord,
|
||||
CompanyMetrics,
|
||||
InboxItem,
|
||||
ProfileSnapshot,
|
||||
RunRecord,
|
||||
StandupReport,
|
||||
TaskRecord,
|
||||
} from "@shared/types";
|
||||
|
||||
// Sidebar badge counts live in the renderer — derived from the
|
||||
// snapshot on every read via `deriveSidebarBadges` rather than cached
|
||||
// on this slice. One source of truth is the snapshot; adding a
|
||||
// separate `badges` field here is what let the counters drift.
|
||||
// Sidebar badge counts and inbox items both live in the renderer —
|
||||
// derived on every read from the snapshot (see `@shared/sidebar-badges`
|
||||
// and `@shared/inbox-items`). The snapshot is the only source of
|
||||
// truth; caching a separate `badges` or `inboxItems` field on this
|
||||
// slice is what let the counters drift against the rendered content.
|
||||
export interface CompanySlice {
|
||||
snapshot: ProfileSnapshot | null;
|
||||
/**
|
||||
@@ -26,12 +26,10 @@ export interface CompanySlice {
|
||||
snapshotRevision: number;
|
||||
companyMetrics: CompanyMetrics | null;
|
||||
standupReport: StandupReport | null;
|
||||
inboxItems: InboxItem[];
|
||||
error: string | null;
|
||||
setSnapshot: (snapshot: ProfileSnapshot | null) => void;
|
||||
setCompanyMetrics: (metrics: CompanyMetrics | null) => void;
|
||||
setStandupReport: (report: StandupReport | null) => void;
|
||||
setInboxItems: (items: InboxItem[]) => void;
|
||||
setError: (error: string | null) => void;
|
||||
refreshSnapshot: () => Promise<void>;
|
||||
patchTask: (task: TaskRecord) => void;
|
||||
@@ -54,7 +52,6 @@ export const createCompanySlice: StateCreator<
|
||||
snapshotRevision: 0,
|
||||
companyMetrics: null,
|
||||
standupReport: null,
|
||||
inboxItems: [],
|
||||
error: null,
|
||||
setSnapshot: (snapshot) =>
|
||||
set((state) => {
|
||||
@@ -69,10 +66,6 @@ export const createCompanySlice: StateCreator<
|
||||
set((state) => {
|
||||
state.standupReport = report;
|
||||
}),
|
||||
setInboxItems: (items) =>
|
||||
set((state) => {
|
||||
state.inboxItems = items;
|
||||
}),
|
||||
setError: (error) =>
|
||||
set((state) => {
|
||||
state.error = error;
|
||||
|
||||
Reference in new issue
Block a user