Skip to content

Commit da8d3fd

Browse files
fix(ui): restore gittensory_ legacy localStorage keys destroyed by rebrand (#7782)
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent cf0cc6f commit da8d3fd

5 files changed

Lines changed: 44 additions & 4 deletions

File tree

apps/loopover-ui/src/components/site/app-panels/onboarding-preview-card.test.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,20 @@ describe("OnboardingPreviewCard", () => {
145145
expect(screen.queryByText(/Here's what LoopOver would have flagged/)).toBeNull();
146146
expect(apiFetch).not.toHaveBeenCalled();
147147
});
148+
149+
it("migrates a pre-rebrand gittensory_ dismiss flag so the card stays hidden (#7782)", async () => {
150+
window.localStorage.setItem(
151+
"gittensory_maintainer_onboarding_preview_dismissed",
152+
JSON.stringify({ dismissed: true }),
153+
);
154+
apiFetch.mockResolvedValue({ ok: true, data: preview() });
155+
render(<OnboardingPreviewCard reviewability={REVIEWABILITY} />);
156+
await waitFor(() =>
157+
expect(window.localStorage.getItem("loopover_maintainer_onboarding_preview_dismissed")).toBe(
158+
JSON.stringify({ dismissed: true }),
159+
),
160+
);
161+
expect(screen.queryByText(/Here's what LoopOver would have flagged/)).toBeNull();
162+
expect(apiFetch).not.toHaveBeenCalled();
163+
});
148164
});

apps/loopover-ui/src/components/site/app-panels/onboarding-preview-card.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ type ReviewabilityRow = { pr: string; title: string; reason: string };
1919

2020
const DISMISS_KEY = "loopover_maintainer_onboarding_preview_dismissed";
2121
// One-time rebrand migration fallback -- see useLocalStorage's legacyKey param.
22-
const LEGACY_DISMISS_KEY = "loopover_maintainer_onboarding_preview_dismissed";
22+
// Must stay as the pre-rebrand `gittensory_...` literal (distinct from DISMISS_KEY); #7782.
23+
const LEGACY_DISMISS_KEY = "gittensory_maintainer_onboarding_preview_dismissed";
2324

2425
/** Builds a settings-preview form from a REAL cached PR (title, and a linked-issue number scraped from
2526
* `reason` when present) — everything else (author identity, labels, body) isn't in the reviewability

apps/loopover-ui/src/components/site/notification-readiness-card.test.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { fireEvent, render, screen } from "@testing-library/react";
2-
import { describe, expect, it, vi } from "vitest";
1+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
33

44
// #6985: a real fetch failure used to render the same generic text as "still loading" — these tests
55
// pin the three render paths (loading / error / success) now that LoadingState/ErrorState replace it.
@@ -31,6 +31,10 @@ const notificationModelFixture = {
3131
};
3232

3333
describe("NotificationReadinessCard loading/error states (#6985)", () => {
34+
beforeEach(() => {
35+
window.localStorage.clear();
36+
});
37+
3438
it("shows a LoadingState (not the generic spinner-free text) while the model loads", () => {
3539
useApiResource.mockReturnValue({
3640
status: "loading",
@@ -94,4 +98,20 @@ describe("NotificationReadinessCard loading/error states (#6985)", () => {
9498
expect(container.textContent).toContain("No content leaves the browser without consent.");
9599
expect(screen.queryByText("Loading notification model…")).toBeNull();
96100
});
101+
102+
it("migrates a pre-rebrand gittensory_ opt-in flag so the pill shows enabled (#7782)", async () => {
103+
window.localStorage.setItem("gittensory_notification_opt_in", JSON.stringify(true));
104+
useApiResource.mockReturnValue({
105+
status: "ready",
106+
data: notificationModelFixture,
107+
error: null,
108+
loadedAt: Date.now(),
109+
reload: () => {},
110+
});
111+
112+
render(<NotificationReadinessCard />);
113+
await waitFor(() => expect(screen.getByText("opt-in enabled")).toBeTruthy());
114+
expect(window.localStorage.getItem("loopover_notification_opt_in")).toBe(JSON.stringify(true));
115+
expect(screen.queryByText("opt-in required")).toBeNull();
116+
});
97117
});

apps/loopover-ui/src/components/site/notification-readiness-card.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ export function NotificationReadinessCard() {
3030
"/v1/app/notification-model",
3131
"Notification model",
3232
);
33+
// Legacy key must stay as the pre-rebrand `gittensory_...` literal (distinct from the current key); #7782.
3334
const [optIn, setOptIn] = useLocalStorage<boolean>(
3435
"loopover_notification_opt_in",
3536
false,
36-
"loopover_notification_opt_in",
37+
"gittensory_notification_opt_in",
3738
);
3839
const [busy, setBusy] = useState(false);
3940

scripts/branding-drift-baseline.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"apps/loopover-ui/src/components/site/api/try-it.tsx": 1,
3+
"apps/loopover-ui/src/components/site/app-panels/onboarding-preview-card.tsx": 2,
4+
"apps/loopover-ui/src/components/site/notification-readiness-card.tsx": 2,
35
"apps/loopover-ui/src/routes/app.index.tsx": 1,
46
"apps/loopover-ui/src/routes/app.runs.tsx": 1,
57
"apps/loopover-ui/src/routes/app.workbench.tsx": 1,

0 commit comments

Comments
 (0)