Skip to content

Fix ten usability problems found in an end-user walkthrough - #93

Merged
xiaomi7732 merged 20 commits into
mainfrom
fix/ux-audit-findings
Sep 30, 2026
Merged

xiaomi7732 merged 20 commits into
mainfrom
fix/ux-audit-findings

Conversation

@xiaomi7732

Copy link
Copy Markdown
Owner

Ten usability problems found by walking the app as an end user, each fixed in its own commit, plus the review fixes that followed.

Closes #82, closes #83, closes #84, closes #85, closes #86, closes #87, closes #89, closes #90, closes #91, closes #92.

(#88 was closed as not reproducible - the reported tab order was a Chrome sequential-focus artefact, not the app - and #92 was filed in its place.)

The ten fixes

Issue Problem Fix
#82 A failed save left the optimistic change on screen, so the board showed a value the backend had rejected Every write path snapshots first and reverts on failure, guarded against a book switch or a newer mutation landing in between
#83 On a narrow screen the top bar actions were unreachable The bar wraps and keeps its actions reachable
#84 Dialogs were divs: no role, no focus trap, no restore, Escape did nothing A shared useModalDialog gives them real dialog semantics, a two-way focus trap and focus restore
#85 Items auto-bumped into range were labelled as though the user had set those dates, and the label never went away The bump is disclosed on the card, and the original dates are cleared per field once the user sets them - terminal items are never labelled
#86 Three different date formats across the app One format everywhere
#87 Screen readers announced the result count twice The visible count is aria-hidden; the role="status" string is the single announcement
#89 Items hidden by the default status filters were invisible and unexplained - the count just did not add up The count explains what is hidden and offers Show hidden, and states what the board loads
#90 Book cards printed raw backend IDs The ID is a tooltip on the book name
#91 Scrum lanes were not in workflow order, and Cancelled had no way back to a board Lanes run New, In Progress, Blocked, Finished; Cancelled shows the board switcher
#92 The error banner could not be dismissed A dismissable ErrorBanner component, used by all three pages

What the review rounds changed

The rollback in #82 exposed a subtler problem: a rejected bulk write may still have partly landed, so the restored list is a guess until a read confirms it. That took several rounds to get right, and the result is:

  • the write failure is stored with the book it happened in, and the banner is always derived from it - never rebuilt from itself, so repeated failed refreshes replace their sentence instead of stacking;
  • a successful read of the same book retracts the "could not be verified" part and keeps the failure itself, because a read confirms rather than refutes that the write was rejected;
  • a manual refresh no longer clears it, a book switch drops it along with its banner, and dismissing it is final.

Also from review: Matrix cards are no longer role="button" containers wrapping their own status buttons, and the board's date-window note is exposed to assistive tech instead of living in a hover-only title on an aria-hidden span.

Verification

  • 171 tests pass across 32 suites, 8 of the suites new on this branch (optimisticUpdate, useModalDialog, statusTimestamps, bumpNotice, hiddenSummary, reconcileMessage, plus additions to dateUtils)
  • tsc --noEmit clean, npm run build clean, lint unchanged from main
  • Each fix was checked live in a signed-in browser, including forcing writes to fail by request interception to exercise the rollback and banner paths
  • Reviewed by two models over nine rounds, ending in two consecutive clean rounds from both

xiaomi7732 and others added 18 commits September 30, 2026 14:26
Failed writes left the board showing state that was never persisted: the
only recovery was a deferred refetch, which cannot succeed in exactly the
case that caused the failure (offline). Snapshot the affected rows before
the optimistic update and restore them when the write is rejected, guarded
by the existing mutation version and book id so a rollback can never
clobber a newer edit.

Covers Matrix drag/status/field/tag mutations, the Scrum equivalents, and
the Cancelled bulk delete.

Closes #82

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The top bar was a non-wrapping flex row with a flex-growing spacer, so on a
390px viewport the Add TODO and Refresh buttons were laid out past the right
edge. The page does not scroll horizontally, which made them unreachable.

Below 640px the bar now wraps, the spacer is dropped, and the book switcher
is capped so it cannot push the actions off-screen.

Closes #83

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The add and detail overlays were plain divs: no role, no accessible name,
and focus stayed on the page behind them, so a screen reader or keyboard
user was never told a dialog had opened and could tab straight out of it.

Both now expose role=dialog with aria-modal and a name, take focus on open,
trap Tab, and return focus to whatever opened them. Matrix cards also gain
keyboard activation, which they lacked entirely.

Closes #84

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The same instant was spelled four ways: a short absolute date on Matrix
cards, a relative one on Scrum cards, a locale numeric date on Cancelled,
and a medium date-time in the detail view. One card even read
'Planned: Sep 30 -> tomorrow', mixing two scales inside a single range.

Inline dates now all go through formatRelativeDate, and every absolute
rendering - tooltips and the detail view alike - goes through a single
formatAbsoluteDateTime helper.

Closes #86

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Two problems in one place. Stale non-terminal tasks have their dates moved
forward automatically, but nothing said so, and the pre-bump plan was never
shown - so the card presented an app-invented date as the user's plan.

Separately, sending a task back to New or reopening a finished one cleared
its lifecycle timestamps on screen but never persisted the clear: the
payload used undefined, which the stores read as 'no change'. The stale
Started/Finished value came back on the next refresh, which is what made a
never-started task look like it had begun.

Cards and the detail overlay now show the original dates under an
'Originally planned' label with a tooltip explaining the move, and the
cleared timestamps are sent as explicit nulls.

Closes #85

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The visible result count and the delayed live region carry the same
sentence, so a screen reader read it once as static text and again as an
announcement. The visible copy is now hidden from assistive technology.

Closes #87

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The error banner was rendered inline on each board page with no way to
close it, so a transient failure stayed on screen until the next
navigation. Extract a shared ErrorBanner component with a dismiss
button and wire Matrix, Scrum and Cancelled to clear both the page
error and the book error when it is dismissed.

Closes #92

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
A first visit reported "Showing 2 of 3 items" with no hint that the
default filters hide cancelled work and all but today's finished work,
and with the preset controls disabled there was nothing to act on.

Add summarizeHiddenByStatus, which counts only the items a status
filter removed - items dropped by the text, tag or priority criteria
are not miscounted - and name the responsible statuses. The search bar
appends that sentence to the count, includes it in the live-region
announcement, and offers a Show hidden button that switches just those
statuses back to All.

Closes #89

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Every Books card showed the storage identifier as primary content -
a long opaque string that means nothing to the user and that leaks the
spreadsheet id for a Google Sheets book. Drop the line and keep the id
as a tooltip on the book name for support purposes.

Closes #90

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The board read New, Blocked, In Progress, Finished, so the normal
left-to-right progression skipped a column and then went backwards.
Blocked is an exception state entered from In Progress, so the lanes
now read New, In Progress, Blocked, Finished.

Cancelled is a task view like the boards but showed only the hamburger
button, making a return to a board two interactions. It now renders the
same Matrix/Scrum switcher.

Closes #91

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
- Matrix cards no longer claim role="button" around their own status
  buttons; the title is a real button, so the nested controls stay
  reachable and the drag preview stops injecting a tab stop.
- The bump notice is suppressed for terminal items, and the calendar
  store clears the remembered pre-bump date for any field the caller
  reschedules, so a card can no longer claim Arrange moved dates the
  user chose.
- Result and hidden counts share one clock, so they cannot straddle
  midnight and disagree.
- The Cancelled bulk-delete failure path sets its message before the
  reconciling refetch and preserves it, since a partial delete makes
  the refetch the authoritative answer.
- Dropped the unused ErrorBanner action prop and the dead card focus
  style; documented why the update overlay still closes on failure and
  that the hidden count is scoped to loaded items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
A multi-item calendar write can partly succeed and still reject, so the
snapshot restored after a failure is provisional until a refresh
confirms it. The refresh that follows such a failure was replacing the
write error with its own, leaving the user with restored rows and no
sign that the deletion or reorder had failed. Matrix, Scrum and
Cancelled now keep the original message and append the refresh failure
to it, so an unverified board says so.

Also surface the load window behind the item count as a tooltip, since
"Show hidden" cannot reveal work outside the fetched range.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
preserveError also covers the routine refresh that runs when a tab
regains focus, so composing on it meant every failed activation refresh
appended another sentence to the banner - unbounded, and claiming a
write could not be verified when none was attempted.

Add a distinct reconciling flag, set only by the paths that roll back a
failed write and carried through the deferred-fetch queue, and move the
composition into composeReconcileFailure, which collapses a repeated or
identical message instead of stacking it.

Also replace the hover-only load-window tooltip, which sat on an
aria-hidden span, with a scopeNote the page supplies: shown next to the
hidden-item notice and announced with it, and omitted on Cancelled,
which loads every item.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
A rollback after a failed write leaves the list provisional, because a
bulk write can partly succeed and still reject. The previous round
signalled that through an option threaded into the pending-fetch queue,
so only the very next refresh knew; a later failed refresh silently
dropped the warning. A ref that lives until a read succeeds is both
simpler and correct for every subsequent attempt.

Clearing it on success also clears the error, since an authoritative
read makes any message about an unverified write stale.

The scope note now renders and is announced with the count at all times,
not only beside a hidden-item notice, and says what the board actually
loads: 30 days either side of today.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The banner was being rebuilt from itself, which made it fragile in three
ways: a successful reconciliation erased the write failure the user had
not necessarily read yet, a manual refresh cleared it before reading and
so lost it if that read also failed, and a run of refreshes that failed
for different reasons appended a sentence each time.

The rollback now stores the write failure itself, and every banner is
derived from that fixed text: a failed read composes one refresh
sentence onto it, a successful read strips the sentence and keeps the
failure, and a manual refresh no longer clears it. Only a successful
read or the dismiss button retracts it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
The stored write failure had no book, so switching book while a rollback
was still unreconciled showed the other book's message and let a read
that verified nothing retract it.

The failure now carries its book id. A read only composes onto it, or
retracts it, when it is reading that same book; any other book drops it,
because the message belongs to work the user has navigated away from.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Dropping a foreign book's unverified failure left its message on screen
whenever the read that dropped it was preserving errors, and nothing
after that could retract it: the ref it was derived from was gone.

The fetch now clears the banner it is abandoning, but only when the
banner still starts with that failure - a message the user raised some
other way is left alone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Retracting an abandoned failure matched on its text, which misses the
shape the composer returns when the write and the refresh failed for the
same reason - it keeps none of the write text. Offline is exactly that
case, and the two were only kept apart by which fetch happens to run
first after a book switch.

The test now lives with the composer as bannerDerivesFrom, covering all
three shapes it can produce and leaving unrelated messages alone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Copilot AI balanced review requested due to automatic review settings September 30, 2026 22:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Dismissed reconciliation errors can reappear, and successful date or status edits can leave stale board state until refresh.

Review effort: Balanced
Findings: 6 Medium severity · 1 Low severity

Open (7)
What changed in this PR

Improves board usability, accessibility, date clarity, filtering, navigation, and failure recovery.

Changes:

  • Adds modal focus management, dismissible errors, mobile wrapping, and clearer navigation.
  • Adds optimistic rollback/reconciliation and lifecycle timestamp handling.
  • Standardizes dates and explains bumped or status-hidden tasks.
File Description
src/​arrange-v4/​package.json Runs the expanded test suite.
src/​arrange-v4/​tsconfig.test.json Includes new test modules.
src/​arrange-v4/​lib/​store/​calendar/​CalendarStore.ts Clears superseded pre-bump dates.
src/​arrange-v4/​lib/​statusTimestamps.ts Centralizes lifecycle timestamps.
src/​arrange-v4/​lib/​statusTimestamps.test.ts Tests timestamp transitions.
src/​arrange-v4/​lib/​search/​useTaskQuery.ts Adds status reveal support.
src/​arrange-v4/​lib/​search/​hiddenSummary.ts Explains status-hidden items.
src/​arrange-v4/​lib/​search/​hiddenSummary.test.ts Tests hidden summaries.
src/​arrange-v4/​lib/​reconcileMessage.ts Composes reconciliation errors.
src/​arrange-v4/​lib/​reconcileMessage.test.ts Tests reconciliation messages.
src/​arrange-v4/​lib/​optimisticUpdate.ts Adds snapshot rollback helpers.
src/​arrange-v4/​lib/​optimisticUpdate.test.ts Tests rollback helpers.
src/​arrange-v4/​lib/​hooks/​useModalDialog.ts Implements modal focus trapping.
src/​arrange-v4/​lib/​hooks/​useModalDialog.test.ts Tests focus wrapping.
src/​arrange-v4/​lib/​dateUtils.ts Centralizes date formatting.
src/​arrange-v4/​lib/​dateUtils.test.ts Tests absolute formatting.
src/​arrange-v4/​lib/​bumpNotice.ts Describes automatic date bumps.
src/​arrange-v4/​lib/​bumpNotice.test.ts Tests bump notices.
src/​arrange-v4/​components/​ViewTodoItem.tsx Adds dialog semantics and bump details.
src/​arrange-v4/​components/​TaskSearchBar.tsx Adds hidden-item explanations.
src/​arrange-v4/​components/​TaskSearchBar.module.css Styles reveal controls.
src/​arrange-v4/​components/​ScrumCard.tsx Displays bump notices.
src/​arrange-v4/​components/​ScrumCard.module.css Styles bump badges.
src/​arrange-v4/​components/​HamburgerMenu.tsx Adds Cancelled view switching.
src/​arrange-v4/​components/​HamburgerMenu.module.css Makes mobile actions wrap.
src/​arrange-v4/​components/​ErrorBanner.tsx Adds dismissible error UI.
src/​arrange-v4/​components/​ErrorBanner.module.css Styles the shared banner.
src/​arrange-v4/​components/​CalendarList.tsx Moves book IDs to tooltips.
src/​arrange-v4/​components/​CalendarList.module.css Removes obsolete ID styling.
src/​arrange-v4/​components/​AddTodoItem.tsx Adds accessible modal behavior.
src/​arrange-v4/​components/​AddTodoItem.module.css Adds hint styling.
src/​arrange-v4/​app/​scrum/​page.tsx Adds rollback, ordering, and filtering fixes.
src/​arrange-v4/​app/​scrum/​page.module.css Removes duplicated error styles.
src/​arrange-v4/​app/​matrix/​page.tsx Adds rollback and card accessibility fixes.
src/​arrange-v4/​app/​matrix/​page.module.css Styles accessible titles and bump notices.
src/​arrange-v4/​app/​cancelled/​page.tsx Adds delete recovery and shared errors.
src/​arrange-v4/​app/​cancelled/​page.module.css Removes duplicated error styles.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/arrange-v4/app/cancelled/page.tsx Outdated
Comment thread src/arrange-v4/app/matrix/page.tsx
Comment thread src/arrange-v4/app/matrix/page.tsx Outdated
Comment thread src/arrange-v4/app/scrum/page.tsx
Comment thread src/arrange-v4/app/scrum/page.tsx Outdated
Comment thread src/arrange-v4/lib/store/calendar/CalendarStore.ts
Comment thread src/arrange-v4/components/ErrorBanner.tsx
Four findings, all real:

Dismissing the banner did not survive a read that was already in flight:
its failure reopened what the user had just closed. Reads started before
a dismissal no longer report.

Editing through the dialog left the board stale. Status changes made
there skipped the lifecycle timestamps the status buttons apply, and
setting a date did not drop the pre-bump original the store clears, so
the moved notice lingered. Both are now applied optimistically, in step
with what the store will do.

Errors said only what the backend said, so an offline save read as
"Failed to fetch" with no hint of which action failed. Every failure now
names its action first, with the technical detail after it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Copilot AI balanced review requested due to automatic review settings September 30, 2026 22:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Google Sheets does not persist bump-metadata clearing, and new date tests depend on the host locale.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (7)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Make date range and tooltip expectations locale-independent

src/​arrange-v4/​lib/​bumpNotice.test.ts:35

These expectations are also tied to an English/US default locale even though the production formatters use the host locale. With de_DE, the text becomes 10. Sept. → 11. Sept. and the tooltip uses a different date/time order, so this suite fails outside an English locale. Derive locale-aware expectations or inject a fixed locale for the test.

Medium severity Make date-time formatting test independent of host locale

src/​arrange-v4/​lib/​dateUtils.test.ts:64

This assertion depends on the host's default locale, but formatAbsoluteDateTime intentionally calls toLocaleString(undefined, ...). For example, under de_DE the same value is 30.09.2026, 11:23, so npm test fails even though the formatter is behaving correctly. Make the test locale-independent (or make the formatter accept an explicit locale for deterministic tests).

Comment thread src/arrange-v4/lib/store/calendar/CalendarStore.ts
The per-field reset lived only in the calendar store, so on Sheets a
rescheduled item lost its moved notice locally and got it back on the
next read.

The Sheets update path now clears the original for whichever date the
caller set, and marks it changed so the append records the clear rather
than leaving it to be read as untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 112ac087-b7da-45a3-a00b-6ca9d06df52b
Copilot AI balanced review requested due to automatic review settings September 30, 2026 22:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Backend scope messaging is inaccurate for Sheets, and Matrix ranges can still mix relative and absolute date formats.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Use one date format for both endpoints in a range

src/​arrange-v4/​app/​matrix/​page.tsx:137

formatRelativeDate chooses relative versus absolute text independently for each endpoint, so ranges crossing its ±14-day cutoff still mix formats (for example, in 14d → Oct 15); the Actual range below has the same problem. This leaves the range inconsistency from #86 unresolved. Format each pair through a shared range formatter that chooses one mode for both endpoints.

Medium severity Make the scope note backend-specific for Google Sheets

src/​arrange-v4/​app/​matrix/​page.tsx:1136

This scope note is inaccurate for Google Sheets books. GoogleSheetsStore.listItems returns every non-terminal item regardless of the requested window (lib/store/sheets/GoogleSheetsStore.ts:369-373), so the count can include active work older than 30 days while the UI says it cannot. Make the note backend-specific.

Medium severity Make the scope note backend-specific for Google Sheets

src/​arrange-v4/​app/​scrum/​page.tsx:838

This scope note is inaccurate for Google Sheets books. GoogleSheetsStore.listItems returns every non-terminal item regardless of the requested window (lib/store/sheets/GoogleSheetsStore.ts:369-373), so the count can include active work older than 30 days while the UI says it cannot. Make the note backend-specific.

@xiaomi7732

Copy link
Copy Markdown
Owner Author

PR Review Loop Summary

  • 3 review rounds completed
  • 8 issues raised across all rounds - all fixed with code changes:
    • Round 1 (7 comments, 4 distinct issues): dismissing the banner did not survive a read already in flight (3 threads, one per page); dialog edits skipped the lifecycle timestamps the status buttons apply (2 threads); setting a date did not drop the pre-bump original, so the "moved" notice lingered until a refresh; failures showed only the backend's text, so an offline save read as "Failed to fetch" with no hint of which action failed. Fixed in 1c27a8a.
    • Round 2 (1 issue): the per-field original-date reset existed only in the calendar backend, so on Sheets the notice came back on the next read. Fixed in 1525723.
    • Round 3: clean - zero unresolved comments
  • Final status: all review threads resolved

Before the PR was opened, the branch also went through nine rounds with two independent reviewing models, ending in two consecutive clean rounds from both. 175 tests pass, tsc --noEmit and npm run build are clean, and lint is unchanged from main.

@xiaomi7732
xiaomi7732 merged commit 1eb7a9f into main Sep 30, 2026
1 check passed
@xiaomi7732
xiaomi7732 requested a balanced review from Copilot October 1, 2026 19:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Reconciled write failures can still be cleared by a later refresh, and the displayed window scope is inaccurate for Sheets books.

Review effort: Balanced
Findings: 5 Medium severity

Open (5)

Comment on lines +144 to +148
if (unverifiedWriteRef.current) {
// This read is authoritative, so the board is no longer a guess. The
// write failure itself stays: the user still needs to know it failed.
setError(unverifiedWriteRef.current.message);
unverifiedWriteRef.current = null;
Comment on lines +442 to +446
if (unverifiedWriteRef.current) {
// This read is authoritative, so the board is no longer a guess. The
// write failure itself stays: the user still needs to know it failed.
setError(unverifiedWriteRef.current.message);
unverifiedWriteRef.current = null;
Comment on lines +1135 to +1137
hiddenSummary={hiddenByStatus.label}
scopeNote="loads 30 days either side of today"
onRevealHidden={() => taskQuery.revealStatuses(hiddenByStatus.statuses)}
Comment on lines +276 to +280
if (unverifiedWriteRef.current) {
// This read is authoritative, so the board is no longer a guess. The
// write failure itself stays: the user still needs to know it failed.
setError(unverifiedWriteRef.current.message);
unverifiedWriteRef.current = null;
Comment on lines +837 to +839
hiddenSummary={hiddenByStatus.label}
scopeNote="loads 30 days either side of today"
onRevealHidden={() => taskQuery.revealStatuses(hiddenByStatus.statuses)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment