Skip to content

feat(extension): open the popup from the inline picker's more-logins row - #21

Merged
rendyuwu merged 1 commit into
devfrom
feat/inline-more-logins-popup
Oct 6, 2026
Merged

rendyuwu merged 1 commit into
devfrom
feat/inline-more-logins-popup

Conversation

@rendyuwu

@rendyuwu rendyuwu commented Oct 6, 2026

Copy link
Copy Markdown
Owner

What

The inline picker's N more logins on <domain> footer is now a row that opens
the Subclave popup through the service worker. Where the popup cannot open,
the footer turns into text naming the browser's Extensions menu and the
fill-login shortcut.

Why

Closes #20.

Following the old footer meant leaving the field for the browser's toolbar,
where the icon usually sits inside the Extensions menu until it is pinned, and
the footer never named the Ctrl+Shift+L command. The exact-host rule is
unchanged: the picker still lists this host's entries only, the row fills
nothing and releases nothing, and the wider matches show only in the popup.

How

  • New inline request inline-open-popup (extension/src/lib/messages.ts),
    accepted from the top-frame content script only, like every inline request.
    handleInline runs openPopup and nothing else, and reads neither the tab
    nor the URL. It answers { type: "popup", ok: true }, or ok: false with
    the fill-login shortcut from chrome.commands.getAll() ("" when
    unbound).
  • openPopup in extension/src/background.ts is now the only caller of
    chrome.action.openPopup; a missing member or a rejection reads as false.
    runFillCommand uses it too and keeps its newest-lastUsedAt fallback.
  • showReady (extension/src/content/inline.ts) adds the row last, after the
    entry rows and the generate and update rows. On success the picker closes.
    On failure popupFallback keeps the shortcut and the same picker is drawn
    again with the text in place of the row. close() leaves popupFallback
    set, so the rest of that page shows the text and never asks again.

Decisions on the open points in #20:

  • Wording: the row reads N more logins on <domain> / Open in Subclave popup.
    The fallback reads N more logins on <domain>: open Subclave from the browser's Extensions menu, or press <shortcut>, without the , or press
    part when the command is unbound.
  • Guards: the row needs event.isTrusted only, like Unlock and
    Pair with Subclave. It fills nothing and releases nothing, so a
    clickjacked click on it can only open the popup, where a fill still takes a
    click in browser-owned UI.
  • Firefox before 149 and Chrome before 127: no version check. The row shows,
    and its first failing click on a page turns it into the text for the rest of
    that page.
  • The guard refusal text in refuse is unchanged and gets no row. Under
    guard 2 the picker is inert behind a modal, so a row there could not be
    clicked.

Docs:

  • SECURITY.md: the row, what it can and cannot do, and its guard rule.
  • ARCHITECTURE.md: the new request in Browser fill > Inline.
  • KNOWN-LIMITS.md: the browsers where the row falls back to text.
  • README.md: new "Fill a login" section covering the picker, the
    more-logins row, Ctrl+Shift+L / Cmd+Shift+L, and where to set the
    shortcut when another extension holds it.
  • CHANGELOG.md: an ## [Unreleased] entry. scripts/release-notes.mjs
    reads versioned headings only, so the 0.1.1 notes are unchanged.

Testing

  • pnpm --filter subclave-extension test: 84/84 across chrome and
    chrome-inject.

  • Headless Chromium resolves the real openPopup without showing a popup and
    leaves fill-login unbound, so the new tests stub chrome.action.openPopup
    and chrome.commands.getAll in the service worker.

    • "the more-logins row opens the popup by pointer and by keyboard, and
      ignores an untrusted click": one other match in no-fields mode, by
      pointer; two in ok mode, reached past the entry rows with ArrowDown
      and Enter. An untrusted click opens nothing and shows no refusal, and no
      get-credential reaches the app.
    • "where the popup cannot open, the more-logins footer names the Extensions
      menu and the shortcut": a rejecting openPopup turns the row into the text
      ending in , or press Ctrl+Shift+L. Reopening the picker on the same page
      shows the text at once without calling openPopup again. With openPopup
      deleted and the command unbound, a fresh page shows the text without
      , or press.
  • Removed "the footer counts the logins left for the toolbar button", which
    checked the old footer text. "opens on a field click, on the icon and on
    ArrowDown, for this host only" now expects FAKE_ENTRIES.length + 1
    options: in ok mode the fake app reports two other matches, so the picker
    carries the row.

  • Each of these breaks, made one at a time and then reverted, fails one of the
    new tests:

    • no close() after the popup opened: the picker stays open;
    • the row guarded: true: the untrusted click is refused;
    • popupFallback never set, or reset in close(): the row stays, or comes
      back on reopen;
    • the shortcut looked up as "fill": the text lacks , or press Ctrl+Shift+L;
    • a missing or rejecting openPopup read as success: the picker closes and
      no text shows;
    • inline-open-popup missing from INLINE_REQUEST_TYPES: openPopup never
      runs.
  • pnpm run lint:imports, pnpm run typecheck:scripts,
    pnpm run format:check, pnpm run verify, pnpm exec tsc --noEmit and
    pnpm run typecheck:extension are clean. Both extension builds pass
    (content.js is 18 KB of the 30 KB budget), lint:webext reports 0 errors,
    and zip packs both zips.

  • 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)

No changes under src-tauri/ and no app UI change.

Not tested yet:

  • The real popup opening from the row in a headed Chrome 127 or later, with a
    github.com entry and a login field on gist.github.com.
  • Any Firefox, including whether Firefox before 149 accepts the call from a
    click relayed by the content script.

Screenshots / GIFs

None. The change is in the extension's inline picker, and it has not been run
in a headed browser yet.

Notes for reviewer

  • popupFallback lives per page. On a browser that can never open the popup,
    each new page shows the row until its first click there. KNOWN-LIMITS.md
    records this, and it changes once the service worker can tell before the
    first click that the popup cannot open.

When the page's host has no entries of its own but other hosts of the
domain do, the picker's last row now opens the toolbar popup through
the service worker (`inline-open-popup`, `chrome.action.openPopup`). It
fills nothing and releases nothing, so it needs a trusted click but not
the six guards. Where the popup cannot open, the footer turns into text
naming the Extensions menu and the `fill-login` shortcut for the rest of
the page.

Closes #20.
@rendyuwu
rendyuwu merged commit 66ef95e into dev Oct 6, 2026
7 checks passed
@rendyuwu
rendyuwu deleted the feat/inline-more-logins-popup branch October 6, 2026 03:17
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.

Inline picker: the "more logins" footer points at the toolbar button instead of opening it

1 participant