-
Notifications
You must be signed in to change notification settings - Fork 0
feat: improve PWA version visibility and updates #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 50 commits
Commits
Show all changes
80 commits
Select commit
Hold shift + click to select a range
edf766f
docs: design safe PWA version updates
absolutepraya 88212ff
docs: tighten PWA update design contract
absolutepraya 90c30b8
docs: add PWA version update implementation plan
absolutepraya c8c0f4f
docs: tighten PWA update implementation plan
absolutepraya e03a4be
test: define PWA update lifecycle behavior
absolutepraya 8cdb1ab
test: define safe PWA update activation
absolutepraya 72f3815
ci: add temporary PWA TDD check
absolutepraya 9398459
feat: discover and stage PWA updates
absolutepraya 9db4f5c
feat: activate PWA updates only when safe
absolutepraya 1a19dde
test: define PWA lifecycle state and foreground checks
absolutepraya 42354ab
feat: expose PWA lifecycle state
absolutepraya d2007e2
feat: provide PWA lifecycle to web UI
absolutepraya bc47235
fix: keep React in PWA provider scope
absolutepraya ddb98df
test: use native text assertions in PWA lifecycle test
absolutepraya f9c8363
test: define controlled PWA handoff reload
absolutepraya 031ea55
feat: reload after safe PWA update handoff
absolutepraya d163f9f
ci: extend temporary PWA UI TDD check
absolutepraya 521ed36
test: define shared PWA build presentation
absolutepraya 711836d
test: define Marka profile future features
absolutepraya c41018c
test: keep React in sidebar version scope
absolutepraya ee043b6
test: keep React in profile menu scope
absolutepraya 74dfe05
test: isolate profile menu primitives
absolutepraya 922b1bd
test: isolate sidebar version links
absolutepraya 89ddd4b
feat: show running PWA build state
absolutepraya 703dca2
feat: replace upstream profile actions with Marka features
absolutepraya 6c05d3e
feat: use browser PWA build in sidebar
absolutepraya d3679b1
feat: add profile menu translations
absolutepraya db14a58
feat: type profile menu translations
absolutepraya f3bd87e
feat: use typed profile menu translations
absolutepraya 2743b41
feat: use typed Marka profile translations
absolutepraya 9f59b23
test: align shared build copy namespace
absolutepraya d57e487
test: align Marka profile translation namespace
absolutepraya f150dd3
test: clean up profile menu renders
absolutepraya 008e921
fix: satisfy PWA lifecycle lint rules
absolutepraya 9f5a855
test: satisfy PWA lifecycle lint rules
absolutepraya 2370ae1
ci: diagnose PWA React Doctor findings
absolutepraya 09b0c72
test: preserve an already waiting PWA update
absolutepraya 905e338
test: clean up installing worker listeners
absolutepraya c53fc08
fix: preserve waiting PWA updates and clean listeners
absolutepraya a8ac939
docs: align offline PWA update lifecycle
absolutepraya 374e1d2
fix: avoid nested service worker listener subscriptions
absolutepraya b64863f
test: cover installing worker handler cleanup
absolutepraya 21c140d
ci: run full web and format diagnostics
absolutepraya 35a07e4
test: track readiness for the deployed worker
absolutepraya 54098db
fix: match PWA readiness to the deployed worker
absolutepraya dea2963
test: format profile menu regressions
absolutepraya 9988a45
test: identify installing worker build in cleanup case
absolutepraya d9b0077
test: clean up PWA lifecycle renders
absolutepraya 2c1600b
test: reject stale waiting PWA handoffs
absolutepraya ab5f62f
fix: reject stale waiting PWA handoffs
absolutepraya b0c6ad2
test: model sequential deployed PWA updates
absolutepraya 5f3fc7c
test: require bounded PWA version checks
absolutepraya 4a95977
fix: localize PWA build link title
absolutepraya 8faa482
fix: localize PWA build link title
absolutepraya 9944d8d
fix: keep default translations narrowly typed
absolutepraya ffdc665
chore: remove temporary PWA diagnostics workflow
absolutepraya 699af9e
fix: bound PWA version checks
absolutepraya 510b9de
test: make PWA timeout callback assertion safe
absolutepraya fea0088
style: format PWA lifecycle provider
absolutepraya 7d50c5f
test: account for bounded PWA version fetches
absolutepraya b2700ca
docs: align PWA update plan with implementation
absolutepraya 689e604
chore: add temporary PWA verification workflow
absolutepraya 407db42
chore: remove temporary PWA verification workflow
absolutepraya a44bda3
fix: use top-level React type import
absolutepraya 66d77c1
fix: preserve default translation namespace typing
absolutepraya 7a6c8bc
style: format translation overload implementation
absolutepraya 0bb674b
fix(i18n): preserve default server namespace
absolutepraya df8dde1
test(pwa): reproduce installed-worker readiness race
absolutepraya 3d19221
ci: add temporary PWA readiness regression check
absolutepraya bac137b
fix(pwa): close installed-worker readiness race
absolutepraya dcc3ef2
refactor(i18n): use native client translation typing
absolutepraya 4c8d56a
test(web): cover non-SHA build display
absolutepraya 98d8e24
docs: align PWA plan with final fixes
absolutepraya 0f993d3
ci: broaden temporary PWA web verification
absolutepraya e8fec23
fix(i18n): preserve server namespace through getFixedT
absolutepraya fedad54
fix(i18n): keep server translations on default namespace
absolutepraya 36a7769
refactor(i18n): reuse configured default namespace
absolutepraya dec1011
docs: describe final PWA i18n contract
absolutepraya 60425ed
chore: remove temporary PWA verification workflow
absolutepraya 3773b29
Merge main into feat/pwa-version-updates
absolutepraya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| name: PWA TDD | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: ["*"] | ||
| paths: | ||
| - "apps/web/components/pwa/**" | ||
| - "apps/web/components/shared/sidebar/SidebarVersion*" | ||
| - "apps/web/components/dashboard/header/ProfileOptions*" | ||
| - "apps/web/public/sw.js" | ||
| - "apps/web/lib/i18n/**" | ||
| - ".github/workflows/pwa-tdd.yml" | ||
|
|
||
| jobs: | ||
| focused-web-tests: | ||
| runs-on: ubuntu-latest | ||
|
absolutepraya marked this conversation as resolved.
Outdated
|
||
| steps: | ||
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Setup | ||
| uses: ./tooling/github/setup | ||
|
|
||
| - name: Focused PWA tests | ||
| run: >- | ||
| pnpm --filter @karakeep/web test --run | ||
| components/pwa/ServiceWorkerRegistration.test.tsx | ||
| components/pwa/sw.test.ts | ||
| components/shared/sidebar/SidebarVersion.test.tsx | ||
| components/dashboard/header/ProfileOptions.test.tsx | ||
|
|
||
| - name: Full web tests | ||
| run: pnpm --filter @karakeep/web test --run | ||
|
|
||
| - name: React Doctor diagnostics | ||
| if: always() | ||
| run: | | ||
| pnpm exec react-doctor --project @karakeep/web --scope full --blocking none --json > /tmp/react-doctor.json || true | ||
| cat /tmp/react-doctor.json | ||
|
|
||
| - name: Format diagnostics | ||
| if: always() | ||
| run: | | ||
| pnpm --filter @karakeep/web format:fix | ||
| git diff -- apps/web/components/dashboard/header/ProfileOptions.test.tsx apps/web/components/pwa/ServiceWorkerRegistration.tsx | ||
|
absolutepraya marked this conversation as resolved.
Outdated
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
apps/web/components/dashboard/header/ProfileOptions.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| // @vitest-environment jsdom | ||
|
|
||
| import React from "react"; | ||
| import { cleanup, render, screen } from "@testing-library/react"; | ||
| import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; | ||
|
|
||
| import ProfileOptions from "./ProfileOptions"; | ||
|
|
||
| const mocks = vi.hoisted(() => ({ | ||
| push: vi.fn(), | ||
| toggleTheme: vi.fn(), | ||
| })); | ||
|
|
||
| vi.mock("next/navigation", () => ({ | ||
| redirect: vi.fn(), | ||
| useRouter: () => ({ push: mocks.push }), | ||
| })); | ||
|
|
||
| vi.mock("@/components/theme-provider", () => ({ | ||
| useToggleTheme: () => mocks.toggleTheme, | ||
| })); | ||
|
|
||
| vi.mock("@teispace/next-themes", () => ({ | ||
| useTheme: () => ({ theme: "light" }), | ||
| })); | ||
|
|
||
| vi.mock("@/lib/auth/client", () => ({ | ||
| useSession: () => ({ | ||
| data: { | ||
| user: { | ||
| email: "daffa@example.com", | ||
| name: "Daffa", | ||
| role: "user", | ||
| }, | ||
| }, | ||
| }), | ||
| })); | ||
|
|
||
| vi.mock("@karakeep/shared-react/hooks/users", () => ({ | ||
| useWhoAmI: () => ({ data: { image: null } }), | ||
| })); | ||
|
|
||
| vi.mock("@/lib/i18n/client", () => ({ | ||
| useTranslation: (namespace?: string) => ({ | ||
| t: (key: string) => { | ||
| if (namespace === "profile_menu") { | ||
| const profileTranslations: Record<string, string> = { | ||
| apps_extensions: "Apps & extensions", | ||
| coming_soon: "Coming soon", | ||
| documentation: "Documentation", | ||
| }; | ||
| return profileTranslations[key] ?? key; | ||
| } | ||
|
|
||
| const translations: Record<string, string> = { | ||
| "actions.sign_out": "Sign out", | ||
| "cleanups.cleanups": "Cleanups", | ||
| "options.dark_mode": "Dark mode", | ||
| "options.light_mode": "Light mode", | ||
| "settings.user_settings": "Settings", | ||
| }; | ||
| return translations[key] ?? key; | ||
| }, | ||
| }), | ||
| })); | ||
|
|
||
| vi.mock("../../admin/AdminNotices", () => ({ | ||
| AdminNoticeBadge: () => null, | ||
| })); | ||
|
|
||
| vi.mock("@/components/shared/sidebar/SidebarVersion", () => ({ | ||
| default: ({ placement }: { placement?: string }) => ( | ||
| <div data-placement={placement} data-testid="sidebar-version" /> | ||
| ), | ||
| })); | ||
|
|
||
| vi.mock("@/components/ui/button", () => ({ | ||
| Button: ({ children }: { children: React.ReactNode }) => ( | ||
| <button type="button">{children}</button> | ||
| ), | ||
| })); | ||
|
|
||
| vi.mock("@/components/ui/separator", () => ({ | ||
| Separator: ({ className }: { className?: string }) => ( | ||
| <div className={className} role="separator" /> | ||
| ), | ||
| })); | ||
|
|
||
| vi.mock("@/components/ui/user-avatar", () => ({ | ||
| UserAvatar: ({ name }: { name?: string | null }) => ( | ||
| <div data-testid="user-avatar">{name}</div> | ||
| ), | ||
| })); | ||
|
|
||
| vi.mock("@/components/ui/dropdown-menu", () => ({ | ||
| DropdownMenu: ({ children }: { children: React.ReactNode }) => ( | ||
| <div>{children}</div> | ||
| ), | ||
| DropdownMenuContent: ({ children }: { children: React.ReactNode }) => ( | ||
| <div>{children}</div> | ||
| ), | ||
| DropdownMenuItem: ({ | ||
| children, | ||
| disabled, | ||
| }: { | ||
| children: React.ReactNode; | ||
| disabled?: boolean; | ||
| }) => <div data-disabled={disabled ? "true" : "false"}>{children}</div>, | ||
| DropdownMenuTrigger: ({ children }: { children: React.ReactNode }) => ( | ||
| <div>{children}</div> | ||
| ), | ||
| })); | ||
|
|
||
| describe("ProfileOptions", () => { | ||
| beforeEach(() => { | ||
| mocks.push.mockReset(); | ||
| mocks.toggleTheme.mockReset(); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| cleanup(); | ||
| }); | ||
|
|
||
| it("replaces upstream actions with disabled Marka coming-soon features", () => { | ||
| const { container } = render(<ProfileOptions />); | ||
|
|
||
| expect(container.textContent).toContain("Apps & extensions"); | ||
| expect(container.textContent).toContain("Documentation"); | ||
| expect(container.textContent?.match(/Coming soon/g)?.length).toBe(2); | ||
|
|
||
| const hrefs = [...container.querySelectorAll("a")].map((link) => | ||
| link.getAttribute("href"), | ||
| ); | ||
| expect(hrefs).not.toContain("https://karakeep.app/apps"); | ||
| expect(hrefs).not.toContain("https://docs.karakeep.app"); | ||
| expect(hrefs).not.toContain("https://x.com/karakeep_app"); | ||
| expect(container.textContent).not.toContain( | ||
| "Follow upstream Karakeep on X", | ||
| ); | ||
|
|
||
| const disabledItems = container.querySelectorAll('[data-disabled="true"]'); | ||
| expect(disabledItems).toHaveLength(2); | ||
| }); | ||
|
|
||
| it("shows the shared build footer only in the mobile profile layout", () => { | ||
| render(<ProfileOptions />); | ||
|
|
||
| const version = screen.getByTestId("sidebar-version"); | ||
| expect(version.getAttribute("data-placement")).toBe("profile"); | ||
| expect(version.parentElement?.className).toContain("sm:hidden"); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.