Skip to content

feat(web): implement share link creation with loading state - #577

Merged
Maxerns merged 2 commits into
mainfrom
fix/share-link-loading
Oct 13, 2026
Merged

Maxerns merged 2 commits into
mainfrom
fix/share-link-loading

Conversation

@Maxerns

@Maxerns Maxerns commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Summary: Disable the one-time share button and guard the request in-flight so duplicate clicks cannot mint extra burn-after-reading links.

Closes #243
References #331

Why

Clicking "Create one-time share link" dispatches api.createShare(...) asynchronously. Without an in-flight guard or disabled button state, rapid clicks (such as double-clicking or clicking while on a high-latency connection) dispatch multiple concurrent requests.
Because one-time share links are ephemeral zero-knowledge fragments designed to burn after reading, duplicate requests create orphaned burn links on the server and race against the client state.

What it does

  • Introduces creatingShareRef and creatingShare state in VaultView.tsx, matching the existing concurrency protection patterns used by environment rotation (rotatingEnvRef) and environment sharing (sharingEnvRef).
  • Guards the entry to share(current): subsequent clicks while a request is in flight return immediately.
  • Replaces the button label with "Creating…" and sets disabled={creatingShare} during request processing.
  • Safely resets both creatingShareRef.current = false and setCreatingShare(false) in a finally block, ensuring the button re-enables if the request fails so the user can retry.
  • Preserves the revealGeneration.current check introduced on main so that late-resolving or stale share completions do not corrupt the view if the user switched or hid secrets.

Decisions worth arguing with

  • Combining creatingShareRef with revealGeneration:
    PR Web: prevent duplicate one-time share-link creation #331 originally added creatingShareRef / creatingShare before main introduced the revealGeneration guard. During rebase onto current main, both guards are preserved: the ref guard rejects concurrent clicks before request dispatch, while the generation check discards completions if the user navigated away.
  • Ref + State redundancy:
    React state updates (setCreatingShare) are asynchronous and do not prevent multiple clicks occurring in the same microtask/event turn. creatingShareRef.current synchronously gates re-entry, while creatingShare drives the UI disabled/loading state.

Proving tests have teeth

  • Tested with npm --prefix web test -- src/__tests__/VaultView.test.tsx. All 44 tests pass.
  • Falsification check: Bypassing if (creatingShareRef.current) return; causes the double-click test in VaultView.test.tsx to fail immediately:
    FAIL src/__tests__/VaultView.test.tsx > VaultView selection loading > sends only one createShare request when the one-time link button is clicked twice
    AssertionError: expected "vi.fn()" to be called 1 times, but got 2 times
      579| expect(api.createShare).toHaveBeenCalledTimes(1);
    
    Restoring the guard restores green status (44/44 passing).
  • Failure recovery is also covered: a rejected createShare promise asserts that the error is surfaced in an alert role and the button returns to the enabled state.

What is tested and what is not

  • Tested:

    • Vitest unit tests: 44/44 tests passing in VaultView.test.tsx, 160/160 tests passing across all 17 test suites in web/.
    • Double-click concurrent submission prevention in a single act().
    • Button recovery to enabled state upon request failure.
    • Full web build (npm --prefix web run build).
  • What is not tested:

    • Real network latency round-trip against a deployed server backend (exercised via mock fetch deferred promise).
  • I signed off every commit (git commit -s / Developer Certificate of Origin).

Added functionality to prevent multiple submissions of the share link creation request by introducing a loading state. The button is disabled during the request, and the UI reflects the loading status. Updated tests to ensure only one request is sent when the button is clicked multiple times and to restore the button state after a failed request.

Signed-off-by: Okiri Gabriel <okirigabriel24@gmail.com>
Signed-off-by: Maxerns <maksafk@gmail.com>
@Maxerns
Maxerns force-pushed the fix/share-link-loading branch from a4b55a9 to 316d82c Compare October 13, 2026 10:05
@Maxerns
Maxerns merged commit 817e26d into main Oct 13, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web: prevent duplicate one-time share-link creation

2 participants