Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/web/src/rightPanelStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ async function reloadRightPanelStore() {
}

describe("rightPanelStore", () => {
it("reuses an open issue tab when the same issue is reopened without its host", () => {
const store = useRightPanelStore.getState();
const issue = {
environmentId: "env-1",
projectId: "project-a",
tracker: "github",
scope: "xgooz3x/tolarian-academy",
key: "53",
};
store.openIssue(refA, { ...issue, host: "github.com", url: "https://github.com/x/53" });
store.openIssue(refA, issue);
const state = selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA);
expect(state.surfaces.filter((surface) => surface.kind === "issue")).toHaveLength(1);
expect(state.activeSurfaceId).toBe(state.surfaces[0]!.id);
});

it("records single and bulk tab closes, newest first", () => {
const store = useRightPanelStore.getState();
const pr = pullRequestSurface({
Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/rightPanelStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,20 @@ export const useRightPanelStore = create<RightPanelStoreState>()(
openIssue: (ref, target) =>
set((state) =>
userAction(state, scopedThreadKey(ref), (current) => {
// A link (the page URL) names an issue without its host; reuse the tab a row opened.
const existing =
target.host === undefined
? current.surfaces.find(
(entry) =>
entry.kind === "issue" &&
entry.environmentId === target.environmentId &&
entry.projectId === target.projectId &&
entry.tracker === target.tracker &&
entry.scope.toLowerCase() === target.scope.toLowerCase() &&
entry.key === target.key,
)
: undefined;
if (existing) return { ...current, isOpen: true, activeSurfaceId: existing.id };
const surface = issueSurface(target);
const next = upsertSurface(current, surface);
return target.url
Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/routes/_chat.issues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,9 @@ function IssuesRoute() {
options={INVOLVEMENT_TABS}
onChange={(who) => updateSearch({ who })}
/>
{hostOptions.length > 2 ? (
{/* The server filters by host, so a filtered page only knows its own tracker; keep
the menu while filtered so "All trackers" stays reachable. */}
{hostOptions.length > 2 || search.host ? (
<FilterMenu
label="Filter by tracker"
value={search.host ?? ""}
Expand Down
Loading