refactor(renderer): split snapshot state sections
This commit is contained in:
1 parent
236714e17a
commit
1383805d66
12 files changed
+1030
-899
No files matched your search
@@ -16,6 +16,11 @@ import {
|
||||
type AppErrorInput,
|
||||
type AppErrorNotice,
|
||||
} from "../../lib/desktop";
|
||||
import {
|
||||
assembleProfileSnapshot,
|
||||
splitProfileSnapshot,
|
||||
type ProfileSnapshotSections,
|
||||
} from "../snapshot-sections";
|
||||
|
||||
// Sidebar badge counts and inbox items both live in the renderer —
|
||||
// derived on every read from the snapshot (see `@shared/sidebar-badges`
|
||||
@@ -24,6 +29,7 @@ import {
|
||||
// slice is what let the counters drift against the rendered content.
|
||||
export interface CompanySlice {
|
||||
snapshot: ProfileSnapshot | null;
|
||||
snapshotSections: ProfileSnapshotSections | null;
|
||||
/**
|
||||
* Bumps only on full-snapshot replacements (setSnapshot / refreshSnapshot).
|
||||
* Granular patch/remove methods DO NOT bump this counter so that
|
||||
@@ -49,6 +55,14 @@ export interface CompanySlice {
|
||||
removeApproval: (approvalId: string) => void;
|
||||
}
|
||||
|
||||
function applySnapshotSections(
|
||||
state: CompanySlice,
|
||||
sections: ProfileSnapshotSections | null,
|
||||
) {
|
||||
state.snapshotSections = sections;
|
||||
state.snapshot = sections ? assembleProfileSnapshot(sections) : null;
|
||||
}
|
||||
|
||||
export const createCompanySlice: StateCreator<
|
||||
AppState,
|
||||
[["zustand/immer", never]],
|
||||
@@ -56,13 +70,14 @@ export const createCompanySlice: StateCreator<
|
||||
CompanySlice
|
||||
> = (set) => ({
|
||||
snapshot: null,
|
||||
snapshotSections: null,
|
||||
snapshotRevision: 0,
|
||||
companyMetrics: null,
|
||||
standupReport: null,
|
||||
error: null,
|
||||
setSnapshot: (snapshot) =>
|
||||
set((state) => {
|
||||
state.snapshot = snapshot;
|
||||
applySnapshotSections(state, snapshot ? splitProfileSnapshot(snapshot) : null);
|
||||
state.snapshotRevision += 1;
|
||||
}),
|
||||
setCompanyMetrics: (metrics) =>
|
||||
@@ -82,7 +97,7 @@ export const createCompanySlice: StateCreator<
|
||||
const result = await window.agentCompany.loadSnapshot();
|
||||
if (result.ok) {
|
||||
set((state) => {
|
||||
state.snapshot = result.data;
|
||||
applySnapshotSections(state, splitProfileSnapshot(result.data));
|
||||
state.snapshotRevision += 1;
|
||||
});
|
||||
} else {
|
||||
@@ -101,65 +116,85 @@ export const createCompanySlice: StateCreator<
|
||||
|
||||
patchTask: (task) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
const idx = state.snapshot.tasks.findIndex((t) => t.id === task.id);
|
||||
if (!state.snapshotSections) return;
|
||||
const tasks = state.snapshotSections.company.tasks;
|
||||
const idx = tasks.findIndex((t) => t.id === task.id);
|
||||
if (idx >= 0) {
|
||||
state.snapshot.tasks[idx] = task;
|
||||
tasks[idx] = task;
|
||||
} else {
|
||||
state.snapshot.tasks.unshift(task);
|
||||
tasks.unshift(task);
|
||||
}
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
removeTask: (taskId) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
state.snapshot.tasks = state.snapshot.tasks.filter((t) => t.id !== taskId);
|
||||
if (!state.snapshotSections) return;
|
||||
state.snapshotSections.company.tasks = state.snapshotSections.company.tasks.filter(
|
||||
(t) => t.id !== taskId,
|
||||
);
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
|
||||
patchRun: (run) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
const idx = state.snapshot.runs.findIndex((r) => r.id === run.id);
|
||||
if (!state.snapshotSections) return;
|
||||
const runs = state.snapshotSections.company.runs;
|
||||
const idx = runs.findIndex((r) => r.id === run.id);
|
||||
if (idx >= 0) {
|
||||
state.snapshot.runs[idx] = run;
|
||||
runs[idx] = run;
|
||||
} else {
|
||||
state.snapshot.runs.unshift(run);
|
||||
runs.unshift(run);
|
||||
}
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
removeRun: (runId) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
state.snapshot.runs = state.snapshot.runs.filter((r) => r.id !== runId);
|
||||
if (!state.snapshotSections) return;
|
||||
state.snapshotSections.company.runs = state.snapshotSections.company.runs.filter(
|
||||
(r) => r.id !== runId,
|
||||
);
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
|
||||
patchAgent: (agent) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
const idx = state.snapshot.agents.findIndex((a) => a.id === agent.id);
|
||||
if (!state.snapshotSections) return;
|
||||
const agents = state.snapshotSections.company.agents;
|
||||
const idx = agents.findIndex((a) => a.id === agent.id);
|
||||
if (idx >= 0) {
|
||||
state.snapshot.agents[idx] = agent;
|
||||
agents[idx] = agent;
|
||||
} else {
|
||||
state.snapshot.agents.unshift(agent);
|
||||
agents.unshift(agent);
|
||||
}
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
removeAgent: (agentId) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
state.snapshot.agents = state.snapshot.agents.filter((a) => a.id !== agentId);
|
||||
if (!state.snapshotSections) return;
|
||||
state.snapshotSections.company.agents = state.snapshotSections.company.agents.filter(
|
||||
(a) => a.id !== agentId,
|
||||
);
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
|
||||
patchApproval: (approval) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
const idx = state.snapshot.approvals.findIndex((a) => a.id === approval.id);
|
||||
if (!state.snapshotSections) return;
|
||||
const approvals = state.snapshotSections.company.approvals;
|
||||
const idx = approvals.findIndex((a) => a.id === approval.id);
|
||||
if (idx >= 0) {
|
||||
state.snapshot.approvals[idx] = approval;
|
||||
approvals[idx] = approval;
|
||||
} else {
|
||||
state.snapshot.approvals.unshift(approval);
|
||||
approvals.unshift(approval);
|
||||
}
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
removeApproval: (approvalId) =>
|
||||
set((state) => {
|
||||
if (!state.snapshot) return;
|
||||
state.snapshot.approvals = state.snapshot.approvals.filter((a) => a.id !== approvalId);
|
||||
if (!state.snapshotSections) return;
|
||||
state.snapshotSections.company.approvals = state.snapshotSections.company.approvals.filter(
|
||||
(a) => a.id !== approvalId,
|
||||
);
|
||||
applySnapshotSections(state, state.snapshotSections);
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,116 @@
|
||||
import type { ProfileSnapshot } from "@shared/types";
|
||||
|
||||
export interface ProfileMetadataSection {
|
||||
currentCompanyId: ProfileSnapshot["currentCompanyId"];
|
||||
profilePath: ProfileSnapshot["profilePath"];
|
||||
updatesEnabled: ProfileSnapshot["updatesEnabled"];
|
||||
theme: ProfileSnapshot["theme"];
|
||||
locale: ProfileSnapshot["locale"];
|
||||
backend: ProfileSnapshot["backend"];
|
||||
}
|
||||
|
||||
export interface ProfileCatalogSection {
|
||||
companies: ProfileSnapshot["companies"];
|
||||
connectors: ProfileSnapshot["connectors"];
|
||||
}
|
||||
|
||||
export interface CompanyCollectionsSection {
|
||||
workspaces: ProfileSnapshot["workspaces"];
|
||||
agents: ProfileSnapshot["agents"];
|
||||
goals: ProfileSnapshot["goals"];
|
||||
projects: ProfileSnapshot["projects"];
|
||||
tasks: ProfileSnapshot["tasks"];
|
||||
approvals: ProfileSnapshot["approvals"];
|
||||
runs: ProfileSnapshot["runs"];
|
||||
costs: ProfileSnapshot["costs"];
|
||||
activity: ProfileSnapshot["activity"];
|
||||
secrets: ProfileSnapshot["secrets"];
|
||||
comments: ProfileSnapshot["comments"];
|
||||
socialAccounts: ProfileSnapshot["socialAccounts"];
|
||||
meetings: ProfileSnapshot["meetings"];
|
||||
documents: ProfileSnapshot["documents"];
|
||||
workProducts: ProfileSnapshot["workProducts"];
|
||||
knowledgeBase: ProfileSnapshot["knowledgeBase"];
|
||||
sprints: ProfileSnapshot["sprints"];
|
||||
automationRules: ProfileSnapshot["automationRules"];
|
||||
agentMessages: ProfileSnapshot["agentMessages"];
|
||||
workflows: ProfileSnapshot["workflows"];
|
||||
}
|
||||
|
||||
export interface ProfileSnapshotSections {
|
||||
metadata: ProfileMetadataSection;
|
||||
catalog: ProfileCatalogSection;
|
||||
company: CompanyCollectionsSection;
|
||||
}
|
||||
|
||||
export function splitProfileSnapshot(snapshot: ProfileSnapshot): ProfileSnapshotSections {
|
||||
return {
|
||||
metadata: {
|
||||
currentCompanyId: snapshot.currentCompanyId,
|
||||
profilePath: snapshot.profilePath,
|
||||
updatesEnabled: snapshot.updatesEnabled,
|
||||
theme: snapshot.theme,
|
||||
locale: snapshot.locale,
|
||||
backend: snapshot.backend,
|
||||
},
|
||||
catalog: {
|
||||
companies: snapshot.companies,
|
||||
connectors: snapshot.connectors,
|
||||
},
|
||||
company: {
|
||||
workspaces: snapshot.workspaces,
|
||||
agents: snapshot.agents,
|
||||
goals: snapshot.goals,
|
||||
projects: snapshot.projects,
|
||||
tasks: snapshot.tasks,
|
||||
approvals: snapshot.approvals,
|
||||
runs: snapshot.runs,
|
||||
costs: snapshot.costs,
|
||||
activity: snapshot.activity,
|
||||
secrets: snapshot.secrets,
|
||||
comments: snapshot.comments,
|
||||
socialAccounts: snapshot.socialAccounts,
|
||||
meetings: snapshot.meetings,
|
||||
documents: snapshot.documents,
|
||||
workProducts: snapshot.workProducts,
|
||||
knowledgeBase: snapshot.knowledgeBase,
|
||||
sprints: snapshot.sprints,
|
||||
automationRules: snapshot.automationRules,
|
||||
agentMessages: snapshot.agentMessages,
|
||||
workflows: snapshot.workflows,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function assembleProfileSnapshot(sections: ProfileSnapshotSections): ProfileSnapshot {
|
||||
return {
|
||||
currentCompanyId: sections.metadata.currentCompanyId,
|
||||
profilePath: sections.metadata.profilePath,
|
||||
updatesEnabled: sections.metadata.updatesEnabled,
|
||||
theme: sections.metadata.theme,
|
||||
locale: sections.metadata.locale,
|
||||
backend: sections.metadata.backend,
|
||||
companies: sections.catalog.companies,
|
||||
connectors: sections.catalog.connectors,
|
||||
workspaces: sections.company.workspaces,
|
||||
agents: sections.company.agents,
|
||||
goals: sections.company.goals,
|
||||
projects: sections.company.projects,
|
||||
tasks: sections.company.tasks,
|
||||
approvals: sections.company.approvals,
|
||||
runs: sections.company.runs,
|
||||
costs: sections.company.costs,
|
||||
activity: sections.company.activity,
|
||||
secrets: sections.company.secrets,
|
||||
comments: sections.company.comments,
|
||||
socialAccounts: sections.company.socialAccounts,
|
||||
meetings: sections.company.meetings,
|
||||
documents: sections.company.documents,
|
||||
workProducts: sections.company.workProducts,
|
||||
knowledgeBase: sections.company.knowledgeBase,
|
||||
sprints: sections.company.sprints,
|
||||
automationRules: sections.company.automationRules,
|
||||
agentMessages: sections.company.agentMessages,
|
||||
workflows: sections.company.workflows,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user