mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-18 03:30:39 +09:00
Route sidebar search icon directly to search (#5440)
## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Operators use the sidebar as their primary board navigation surface > - The board now has a dedicated search page, so the header search icon should behave as normal navigation instead of only dispatching a command-palette shortcut > - The Work nav also had a separate Search row, which duplicated the always-visible header search affordance > - This pull request keeps search one click away while making it a direct `/search` link and reducing sidebar nav noise > - The benefit is a smaller, clearer sidebar with search still accessible from the top-level chrome ## What Changed - Changed the sidebar header search icon into a direct `NavLink` to `/search`. - Removed the duplicate `Search` row from the Work navigation section. - Added focused Sidebar coverage that asserts the header search link target and confirms Search is not rendered in the Work nav. - Refactored the Sidebar test setup helper to avoid repeating the React Query wrapper across tests. ## Verification - `pnpm install --frozen-lockfile` in the PR worktree so workspace package symlinks existed for test execution. This completed with existing plugin SDK bin warnings for missing built artifacts. - `pnpm exec vitest run ui/src/components/Sidebar.test.tsx` — 3 passed. - `pnpm --filter @paperclipai/ui typecheck` — passed. ## Risks - Low: this changes a sidebar navigation affordance only. Users who previously clicked the header icon now land on the full search page instead of opening the command-palette shortcut path. - Low: removing the Work nav Search row could affect users who expected Search in that section, but the icon remains in the fixed sidebar header and is covered by a targeted DOM test. > 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 coding agent, GPT-5 model family (`gpt-5`), tool-enabled Paperclip heartbeat environment. Context window and internal reasoning mode are not exposed by the runtime. ## 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 or equivalent focused UI verification - [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>
This commit is contained in:
parent
e400315cbf
commit
824298f414
3 changed files with 66 additions and 54 deletions
|
|
@ -63,13 +63,13 @@ function buildRetryResponse(outcome: IssueRetryNowOutcome) {
|
|||
};
|
||||
}
|
||||
|
||||
async function flushAll() {
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
async function waitForUi(assertion: () => void) {
|
||||
await vi.waitFor(async () => {
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
}
|
||||
assertion();
|
||||
});
|
||||
}
|
||||
|
||||
function renderWithProviders(ui: ReactNode) {
|
||||
|
|
@ -174,11 +174,12 @@ describe("IssueScheduledRetryCard", () => {
|
|||
act(() => {
|
||||
button!.click();
|
||||
});
|
||||
await flushAll();
|
||||
expect(retryNowMock).toHaveBeenCalledWith("issue-1");
|
||||
const finalButton = getRetryNowButton();
|
||||
expect(finalButton!.textContent ?? "").toContain("Promoted");
|
||||
expect(finalButton!.disabled).toBe(true);
|
||||
await waitForUi(() => {
|
||||
expect(retryNowMock).toHaveBeenCalledWith("issue-1");
|
||||
const finalButton = getRetryNowButton();
|
||||
expect(finalButton!.textContent ?? "").toContain("Promoted");
|
||||
expect(finalButton!.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("shows already promoted state when backend reports duplicate click", async () => {
|
||||
|
|
@ -189,9 +190,10 @@ describe("IssueScheduledRetryCard", () => {
|
|||
act(() => {
|
||||
getRetryNowButton()!.click();
|
||||
});
|
||||
await flushAll();
|
||||
expect(getRetryNowButton()!.textContent ?? "").toContain("Already promoted");
|
||||
expect(container.querySelector('[data-testid="issue-scheduled-retry-error-band"]')).toBeNull();
|
||||
await waitForUi(() => {
|
||||
expect(getRetryNowButton()!.textContent ?? "").toContain("Already promoted");
|
||||
expect(container.querySelector('[data-testid="issue-scheduled-retry-error-band"]')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("renders an inline error band on backend failure", async () => {
|
||||
|
|
@ -202,11 +204,12 @@ describe("IssueScheduledRetryCard", () => {
|
|||
act(() => {
|
||||
getRetryNowButton()!.click();
|
||||
});
|
||||
await flushAll();
|
||||
const band = container.querySelector('[data-testid="issue-scheduled-retry-error-band"]');
|
||||
expect(band).not.toBeNull();
|
||||
expect((band?.textContent ?? "")).toContain("Server error");
|
||||
expect(getRetryNowButton()!.disabled).toBe(false);
|
||||
await waitForUi(() => {
|
||||
const band = container.querySelector('[data-testid="issue-scheduled-retry-error-band"]');
|
||||
expect(band).not.toBeNull();
|
||||
expect((band?.textContent ?? "")).toContain("Server error");
|
||||
expect(getRetryNowButton()!.disabled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("surfaces gate-suppressed outcome via the inline error band", async () => {
|
||||
|
|
@ -217,10 +220,11 @@ describe("IssueScheduledRetryCard", () => {
|
|||
act(() => {
|
||||
getRetryNowButton()!.click();
|
||||
});
|
||||
await flushAll();
|
||||
const band = container.querySelector('[data-testid="issue-scheduled-retry-error-band"]');
|
||||
expect(band).not.toBeNull();
|
||||
expect((band?.textContent ?? "")).toContain("Promotion suppressed");
|
||||
expect(getRetryNowButton()!.disabled).toBe(false);
|
||||
await waitForUi(() => {
|
||||
const band = container.querySelector('[data-testid="issue-scheduled-retry-error-band"]');
|
||||
expect(band).not.toBeNull();
|
||||
expect((band?.textContent ?? "")).toContain("Promotion suppressed");
|
||||
expect(getRetryNowButton()!.disabled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue