Skip to content

fix(vault): let the join form follow the window and accept a blank Region - #23

Merged
rendyuwu merged 1 commit into
devfrom
fix/join-form-layout-gate
Oct 6, 2026
Merged

rendyuwu merged 1 commit into
devfrom
fix/join-form-layout-gate

Conversation

@rendyuwu

@rendyuwu rendyuwu commented Oct 6, 2026

Copy link
Copy Markdown
Owner

What

The Join a synced vault screen now scrolls as a whole, and its form widens
with the window up to the Settings content width, with no horizontal scrollbar.
Join vault accepts a blank S3 Region, and while it is disabled a list under
it names every field that is still empty or invalid.

Why

Closes #22.

The form was a fixed 384px column and its own scroll container, so the wheel
did nothing outside that column. A 3px horizontal scrollbar sat under the
button. Join vault also required a Region that Settings > Sync saves blank and
provider_config passes through as typed, and nothing on screen said why the
button was disabled.

How

Layout:

  • JoinSyncScreen.tsx: the outer div is the scroll container
    (flex h-full flex-1 overflow-y-auto p-6). The form is
    m-auto flex w-full max-w-3xl flex-col gap-4. Auto margins centre a short
    form and collapse to 0 on a tall one, so the heading stays reachable, which
    items-center on an overflowing child did not guarantee. max-w-3xl is the
    width of the Settings content (SettingsApp.tsx), so the rows the two forms
    share wrap the same in both.
  • PasswordField.tsx: the eye button's addon gets
    className="pr-2 has-[>button]:mr-0". cn runs twMerge, which drops the
    base pr-3 has-[>button]:-mr-1. The button's right edge stays 8px inside the
    group (12px padding minus the 4px overhang before, 8px padding now), and the
    addon no longer ends 3px past the group. input-group.tsx is generated by
    shadcn and stays untouched.

Gate:

  • src/modules/sync/types.ts: connectionFieldsReady(config, credentialsReady)
    becomes missingConnectionFields(config), which returns the labels of the
    blank connection fields: Endpoint, plus Bucket for S3. Region is never
    listed. Bucket stays required for S3: a blank one builds {endpoint}//{key}
    request paths, and Join screen: the form doesn't follow the window size, and Join vault stays disabled on a blank Region that Settings accepts #22 shows no server that works with one.
  • MasterPasswordFields.tsx: useMasterPassword also returns problems, one
    sentence per rule the password still fails. ready is problems.length === 0
    and means what it did before, so CreateVaultScreen.tsx is unchanged.
  • useJoinSync.ts: a file-private missingCredentials replaces the exported
    credentialsReady and returns the selected provider's blank credential
    labels. The hook takes masterPasswordProblems and returns blockers: one
    Still empty: … line for the blank fields, in render order, then the
    master-password sentences. canSubmit is blockers.length === 0 && !busy.
  • JoinSyncScreen.tsx: the blockers render as a muted <ul id="join-blockers">
    under the button, which points at it with aria-describedby. Muted rather
    than destructive, because an untouched form is not an error. On an untouched
    S3 form it reads:
    • Still empty: Endpoint, Bucket, Access key ID, Secret access key, Sync passphrase.
    • Master password needs at least 8 characters.
    • The no-recovery box isn't ticked.
  • src-tauri/src/modules/sync/engine/types.rs: the region doc comment no
    longer says the S3 form requires it. Comment only.
  • CHANGELOG.md: two entries under [Unreleased] → Fixed.

Testing

  • pnpm run verify sync: the join-gate block in scripts/sync-verify.ts now
    checks that a WebDAV connection needs no Region or Bucket, a complete S3
    connection is ready, a blank Region is ready, a blank Bucket names Bucket,
    and a blank Endpoint names Endpoint. Each of these breaks in
    missingConnectionFields, made one at a time and then reverted, fails a
    check:

    • Region required for S3: the blank-Region check fails with "Region";
    • the Bucket line deleted: the blank-Bucket check fails with "";
    • .trim() dropped from the Endpoint test: the blank-Endpoint check fails
      with "";
    • Bucket required for every provider: the WebDAV check fails with
      "Bucket".
  • A one-off Playwright script (not committed) against pnpm dev in Chromium,
    with invoke stubbed for vault_status, vault_list and sync_join:

    Window Form width Horizontal overflow Addon past its group
    640×480 580px none none
    800×600 740px none none
    1280×800 768px none none
    1920×1080 768px none none

    At every size the form itself does not scroll and the heading is visible at
    the top. At 1280×800 the wheel scrolls the screen with the pointer left of
    the form. The gate flow: an untouched form lists the three lines above; with
    every field filled and Region blank the button is enabled and the list is
    gone; a blank Bucket, a mismatched confirmation, a 6-character master
    password and an unticked box are each named; WebDAV lists
    Still empty: Username, Password.; and the submitted sync_join call
    carries region: "". With the old layout classes back, the width,
    form-scroll and wheel checks fail. Without the addon className, the addon
    ends 3px past its group at every size.

  • pnpm run lint:imports, pnpm run typecheck:scripts,
    pnpm exec tsc --noEmit, pnpm run verify (17/17), pnpm run format:check
    and cargo fmt --all -- --check are clean.

  • pnpm exec tsc --noEmit clean

  • Manual smoke-test of the affected feature

  • (If you touched src-tauri/) cargo check clean

  • (If UI) tested in pnpm tauri:dev (isolated dev data dir)

Under src-tauri/ only a doc comment changed, so cargo check was not run.

Not tested yet:

Screenshots / GIFs

None. The layout was measured in the pnpm dev preview (table above) and has
not been run in pnpm tauri:dev yet.

Notes for reviewer

  • With the new p-6 scroller, the 3px addon overhang no longer produces a
    scrollbar on this screen even without the PasswordField override. The
    override still keeps the shared field inside its group wherever it sits
    against a scrolling edge.
  • While a join runs the button is disabled with an empty list and shows the
    spinner; busy is the only reason Submit is disabled that the list does not
    name.
  • The blocker composition (missingCredentials, the Still empty: line,
    problems) has no permanent check, as credentialsReady and ready had
    none before. useJoinSync.ts imports @tauri-apps/api/event at module
    scope, so pnpm run verify cannot load it.

…gion

The join screen was a fixed 384px column that scrolled on its own, so
the wheel worked only over that column. The eye button's addon in
PasswordField hung 3px past its input group, and the scrolling form
turned that into a horizontal scrollbar. The screen is now the scroll
container and the form is m-auto up to max-w-3xl, the Settings content
width. The addon overrides pr-3 has-[>button]:-mr-1 with
pr-2 has-[>button]:mr-0, so the button stays where it was and nothing
hangs past the group.

Join vault no longer requires an S3 Region. provider_config passes the
region through as typed, Settings > Sync saves it blank, and a server
that takes an empty one works with it (Cloudflare R2 reads it as auto).
Bucket stays required for S3: a blank one builds {endpoint}//{key}
paths.

connectionFieldsReady becomes missingConnectionFields, which returns the
labels of the blank fields, and useMasterPassword also returns problems,
one sentence per rule the password still fails. useJoinSync builds
blockers from both, the credential pair and the passphrase, and derives
canSubmit from it. The screen lists the blockers under the button in
muted text.

scripts/sync-verify.ts checks the new connection gate, including the
blank Region.

Closes #22
@rendyuwu
rendyuwu merged commit 81a1276 into dev Oct 6, 2026
7 checks passed
@rendyuwu
rendyuwu deleted the fix/join-form-layout-gate branch October 6, 2026 04:27
This was referenced Oct 6, 2026
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.

Join screen: the form doesn't follow the window size, and Join vault stays disabled on a blank Region that Settings accepts

1 participant