Share cards cross-referencing to a different board open the board, but fail to open the card on the board #96

Closed
opened 2026-08-18 01:40:35 +00:00 by Grandiras · 2 comments
Owner

Saying the card doesn't exist anymore on that board.

Saying the card doesn't exist anymore on that board.
Collaborator

🤖 On it — follow along in the action run; the reply will link the full session transcript.

📜 Live transcript — updating every ~5 minutes while the task runs.

🤖 On it — follow along in [the action run](https://git.grandiras.net/Grandiras/claude-bot/actions/runs/264); the reply will link the full session transcript. <!-- claude-run:comment --> 📜 [Live transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/issue-96/run-264.md) — updating every ~5 minutes while the task runs.
Collaborator

Fixed and pushed as claude/issue-96.

What was wrong

Following a link card to a card on a different board is the only case that broke, and the reason is that it changes two things at once — the route parameter and the ?card= query — which reach the reused BoardPage as two separate parameter sets:

  1. The router re-renders the page for the new /board/{id}. OnParametersSetAsync tears down the outgoing board's state and starts await ReloadAsync().
  2. The framework's query-parameter supplier (SupplyParameterFromQueryValueProvider, whose LocationChanged handler deliberately runs after the router's) then notifies the same component that the query changed — and that notification lands inside step 1's await on the database.

At that moment the outgoing board is gone and the incoming board's cards have not arrived, so OpenSharedCard answered "that card isn't on this board", showed the toast, and — the part that made it unrecoverable — stripped ?card= off the URL. When the load finished a few milliseconds later, its own call had nothing left to open. A page.goto to the same link is a single parameter set, which is why the existing tests never saw it.

The fix

src/Ponente.Kanban/Components/Pages/BoardPage.razor: a _loadingBoard flag, and OpenSharedCard refuses to decide anything while a board is in flight — it leaves the query on the URL for the load's own call, which is the only one that can actually tell. Deliberately not a fetch-by-id or a redirect to the card's real board: "not here" still means not here, so a deleted card and a card on another board are still told the same thing.

Also added: the e2e case in tests/e2e/share.spec.js (follows a cross-board link from inside the app, creating and deleting its own second board the way boards.spec.js does), and a note in CLAUDE.md next to the existing ?card= rules, since the two-parameter-sets ordering is the kind of thing that gets re-broken.

No changelog entry: sharing itself is the unreleased 2.5.0 entry (latest tag is v2.3.0), so no member has seen the broken behaviour, and that entry's "a shared link goes straight to the card it names" already promises what this restores.

Verified

Reproduced and fixed against a real running instance — .NET 10 SDK + Postgres installed in this container, the app run in Development on 127.0.0.1:5000, driven with Playwright:

The board switched, the card is right there in To Do, and the toast says the card isn't on this board any more The same click on the fixed build: the other board's card dialog is open
Before — board switched, card visible in To Do, toast says it is gone After — the card the link named is open
  • New test fails on the unfixed build (element(s) not found for the target card's dialog), passes on the fixed one.
  • dotnet build Ponente.sln — clean (one pre-existing Calendar.razor warning).
  • dotnet test Ponente.sln273 passed.
  • share.spec.js board.spec.js boards.spec.js filter.spec.js locally — 45 passed, 2 failed, both environmental and both confirmed to fail identically on unmodified main here: one asserts the origin is literally http://localhost:8090/ (my instance is on :5000), the other is boards.spec.js's 3 s calendar-paint deadline missed by this non-containerised dev-mode server. Nothing PDS-dependent (pds.spec.js, access.spec.js) was run — there is no PDS container in this environment.

⏱ 15m 23s · 82 turns · tokens: 139.5k in / 38.2k out (+10044.4k cache-read)
📜 Full session transcript
→ Opened PR: #97

Fixed and pushed as **`claude/issue-96`**. ## What was wrong Following a link card to a card on a *different* board is the only case that broke, and the reason is that it changes **two** things at once — the route parameter and the `?card=` query — which reach the reused `BoardPage` as **two separate parameter sets**: 1. The router re-renders the page for the new `/board/{id}`. `OnParametersSetAsync` tears down the outgoing board's state and starts `await ReloadAsync()`. 2. The framework's query-parameter supplier (`SupplyParameterFromQueryValueProvider`, whose `LocationChanged` handler deliberately runs *after* the router's) then notifies the same component that the query changed — and that notification lands **inside** step 1's await on the database. At that moment the outgoing board is gone and the incoming board's cards have not arrived, so `OpenSharedCard` answered "that card isn't on this board", showed the toast, and — the part that made it unrecoverable — stripped `?card=` off the URL. When the load finished a few milliseconds later, its own call had nothing left to open. A `page.goto` to the same link is a single parameter set, which is why the existing tests never saw it. ## The fix `src/Ponente.Kanban/Components/Pages/BoardPage.razor`: a `_loadingBoard` flag, and `OpenSharedCard` refuses to decide anything while a board is in flight — it leaves the query on the URL for the load's own call, which is the only one that can actually tell. Deliberately *not* a fetch-by-id or a redirect to the card's real board: "not here" still means not here, so a deleted card and a card on another board are still told the same thing. Also added: the e2e case in `tests/e2e/share.spec.js` (follows a cross-board link from inside the app, creating and deleting its own second board the way `boards.spec.js` does), and a note in `CLAUDE.md` next to the existing `?card=` rules, since the two-parameter-sets ordering is the kind of thing that gets re-broken. No changelog entry: sharing itself is the unreleased `2.5.0` entry (latest tag is `v2.3.0`), so no member has seen the broken behaviour, and that entry's "a shared link goes straight to the card it names" already promises what this restores. ## Verified Reproduced and fixed against a real running instance — .NET 10 SDK + Postgres installed in this container, the app run in Development on `127.0.0.1:5000`, driven with Playwright: | | | |---|---| | ![The board switched, the card is right there in To Do, and the toast says the card isn't on this board any more](https://git.grandiras.net/attachments/0f891f7d-c0a1-4abb-9cf8-d662243b7c27) | ![The same click on the fixed build: the other board's card dialog is open](https://git.grandiras.net/attachments/da509ae6-35d3-402a-afed-4e66e47aeef0) | | **Before** — board switched, card visible in To Do, toast says it is gone | **After** — the card the link named is open | - New test fails on the unfixed build (`element(s) not found` for the target card's dialog), passes on the fixed one. - `dotnet build Ponente.sln` — clean (one pre-existing `Calendar.razor` warning). - `dotnet test Ponente.sln` — **273 passed**. - `share.spec.js board.spec.js boards.spec.js filter.spec.js` locally — **45 passed, 2 failed**, both environmental and both confirmed to fail identically on unmodified `main` here: one asserts the origin is literally `http://localhost:8090/` (my instance is on `:5000`), the other is `boards.spec.js`'s 3 s calendar-paint deadline missed by this non-containerised dev-mode server. Nothing PDS-dependent (`pds.spec.js`, `access.spec.js`) was run — there is no PDS container in this environment. --- ⏱ 15m 23s · 82 turns · tokens: 139.5k in / 38.2k out (+10044.4k cache-read) 📜 [Full session transcript](https://git.grandiras.net/Grandiras/claude-bot/src/branch/claude-logs/transcripts/Grandiras/Ponente/issue-96/run-264.md) → Opened PR: https://git.grandiras.net/Grandiras/Ponente/pulls/97
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Grandiras/Ponente#96
No description provided.