forked from farhoodlabs/paperclip
d95968a9f8
## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - The board UI is the operator’s control surface for selecting the active company > - A company id stored in localStorage can become stale across resets, imports, or deleted companies > - Exposing that stale id before companies load can briefly put downstream UI in an invalid company scope > - This pull request defers selected-company exposure until the loaded company list validates the stored id > - The benefit is a cleaner company-selection bootstrap path and fewer transient invalid API requests ## What Changed - Initialized `CompanyProvider` selection as `null` until companies finish loading. - Reused a stored company id only when it exists in the loaded selectable company list. - Cleared storage and selected state when no companies are available. - Added jsdom regression coverage for stale stored ids before and after company loading. ## Verification - `pnpm exec vitest run --project @paperclipai/ui ui/src/context/CompanyContext.test.tsx` ## Risks - Low risk. The change only affects selection bootstrap and keeps valid stored selections intact. - There may be a slightly longer initial `null` selected-company state while the company list is loading. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5 coding agent, tool-enabled terminal/GitHub workflow, reasoning mode active. Context window not exposed in this environment. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { resolveBootstrapCompanySelection, shouldClearStoredCompanySelection } from "./CompanyContext";
|
|
|
|
const activeCompany = { id: "company-1" };
|
|
const secondActiveCompany = { id: "company-2" };
|
|
const archivedCompany = { id: "archived-company" };
|
|
|
|
describe("resolveBootstrapCompanySelection", () => {
|
|
it("does not expose a stale stored company id before companies load", () => {
|
|
expect(resolveBootstrapCompanySelection({
|
|
companies: [],
|
|
sidebarCompanies: [],
|
|
selectedCompanyId: null,
|
|
storedCompanyId: "stale-company",
|
|
})).toBeNull();
|
|
});
|
|
|
|
it("replaces a stale stored company id with the first loaded company", () => {
|
|
expect(resolveBootstrapCompanySelection({
|
|
companies: [activeCompany],
|
|
sidebarCompanies: [activeCompany],
|
|
selectedCompanyId: null,
|
|
storedCompanyId: "stale-company",
|
|
})).toBe("company-1");
|
|
});
|
|
|
|
it("keeps a valid selected company ahead of stored bootstrap state", () => {
|
|
expect(resolveBootstrapCompanySelection({
|
|
companies: [activeCompany],
|
|
sidebarCompanies: [activeCompany],
|
|
selectedCompanyId: "company-1",
|
|
storedCompanyId: "stale-company",
|
|
})).toBe("company-1");
|
|
});
|
|
|
|
it("keeps a valid stored company id instead of falling back to the first company", () => {
|
|
expect(resolveBootstrapCompanySelection({
|
|
companies: [activeCompany, secondActiveCompany],
|
|
sidebarCompanies: [activeCompany, secondActiveCompany],
|
|
selectedCompanyId: null,
|
|
storedCompanyId: "company-2",
|
|
})).toBe("company-2");
|
|
});
|
|
|
|
it("uses selectable sidebar companies before archived companies", () => {
|
|
expect(resolveBootstrapCompanySelection({
|
|
companies: [archivedCompany, activeCompany],
|
|
sidebarCompanies: [activeCompany],
|
|
selectedCompanyId: null,
|
|
storedCompanyId: "archived-company",
|
|
})).toBe("company-1");
|
|
});
|
|
});
|
|
|
|
describe("shouldClearStoredCompanySelection", () => {
|
|
it("does not clear the stored company selection during an unauthorized company list response", () => {
|
|
expect(shouldClearStoredCompanySelection({
|
|
companies: [],
|
|
isLoading: false,
|
|
unauthorized: true,
|
|
})).toBe(false);
|
|
});
|
|
|
|
it("clears the stored company selection when an authorized company list is empty", () => {
|
|
expect(shouldClearStoredCompanySelection({
|
|
companies: [],
|
|
isLoading: false,
|
|
unauthorized: false,
|
|
})).toBe(true);
|
|
});
|
|
});
|