Skip to content

UI and UX improvements to the "Connect an Integration" modal. - #1714

Draft
NWylynko wants to merge 15 commits into
UsefulSoftwareCo:mainfrom
NWylynko:feat/connect-integration-picker
Draft

UI and UX improvements to the "Connect an Integration" modal.#1714
NWylynko wants to merge 15 commits into
UsefulSoftwareCo:mainfrom
NWylynko:feat/connect-integration-picker

Conversation

@NWylynko

Copy link
Copy Markdown

Currently the add integration modal is hard to discover the quick to setup integrations, its a small list making it hard to scroll, limiting discoverability and its unfilterable.
Screenshot 2026-08-20 at 5 08 22 PM

This pr makes it taller, two columns, grouping together integrations from the same provider, and filter down to api, mcp or graphql. making it easier to discover the available options.
image

The Connect dialog listed every preset flat in a 560px dialog with a fixed
224px scroll area. Two providers contribute 48 of those 85 rows as bare
service names ("Users", "Directory", "Profile"), so the list was mostly
context-free noise and the only way through it was the search box.

- Group each multi-service provider into one card that opens into its
  services, so browsing shows 39 cards instead of 85 rows.
- Searching ungroups: typing "outlook" returns the three Outlook services
  rather than the Microsoft card they were trying to see past.
- Add protocol facets (All/OpenAPI/MCP/GraphQL) counting the cards each
  reveals for the active query.
- Lead with the curated `featured` presets so the providers hiding half the
  library are on the first screen rather than row 12.
- Widen the dialog and lay the catalog out in two columns; move the manual
  add-by-protocol links to the footer.

Catalog behavior is pure and unit-tested; the dialog moves out of the page
into its own component. Extracts the kind-to-plugin-key map that the picker,
the grid, and the favicon resolver each had a private copy of.
Asserts the behavior the redesign turns on, in a browser against a real
instance: a provider browses as one card with its services hidden, opening
it reveals them, back re-collapses, searching returns the services rather
than the card, a protocol facet excludes other protocols, and a picked
service lands on its add flow with the preset applied.
Keeps the picker's markup next to the page that owns it rather than in a
component module of its own. Behavior is unchanged: the catalog logic stays
in lib/preset-catalog.ts, and ConnectIntegrationDialog is file-local again.
Analytics already calls this surface the connect dialog
(integration_connect_dialog_opened); the new event introduced a second noun
for the same thing.
The dialog stayed mounted, so a URL detection the user walked away from still
landed in its state. Abandoning one that then failed left the error banner
waiting in the next open, under an empty search box; abandoning one that then
succeeded navigated the app to that URL's add flow, whatever the user was
doing by then. Both are in the new scenario, which fails on the old shape.

ConnectIntegrationDialog is now a wrapper that renders its view only while
open, so the query, facet, open provider and in-flight detection die with it
instead of being hand-reset. Unmounting cannot stop handleDetect's
continuation, which navigates, so a cleanup marks the withdrawn answer
unwanted and it returns early.
One rule for "browses as a provider card": the picker collapsed any family
with two or more presets while the integrations grid gated on
MULTI_SERVICE_FAMILIES, so a plugin tagging presets with an uncurated family
would get a card the rest of the app won't group behind. Both now ask
curatedFamily(). No behavior change today — google and microsoft are the only
families shipped.

The protocol facets stand down inside a provider, where they counted the whole
catalog over a list that isn't it and read "All" as selected over 21 of 39
cards. The add-manually links drop the pill shape they shared with those
facets, so the same three protocol names stop meaning two things.

Also: PresetIcon's unused alt and dead className defaults, a redundant
empty-array check bestDetection already makes, and a protocol-filter sentinel
no plugin key can collide with.
Making the links plain text to tell them apart from the protocol facets
demoted a common way in to a footnote. They are three full buttons in a
bordered footer now, each led by a plus and the verb — "Add MCP" cannot be
mistaken for the "MCP 13" chip above, and it no longer reads as fine print.
The results box already ends in a border and the buttons draw their own, so
the divider was a third line in forty pixels.
The results box was flex-1, so filtering to three results shrank the dialog
and walked the facet chips out from under the cursor that had just clicked
one. It has a fixed height now — min(36rem, 55vh), a window of eight or nine
rows that a search cannot resize. The dialog's own 46rem cap goes with it, or
it would have compressed that window back on a tall screen; 92vh still guards
a short one.
The results grid draws its separators as gaps over a border-coloured
background, so the last row had nothing under it and a short list ended in
mid-air. A pixel of bottom padding exposes the same line.

On a phone the protocol facets wrapped the last one onto its own row and the
three add buttons wrapped onto a second, both pushing the dialog around. The
facets scroll sideways now instead of wrapping, and below `sm` the add
buttons collapse into one "Add manually" menu holding the same links. The
scenario checks both at 390px: every facet chip shares a row, and the desktop
buttons are gone in favour of the menu.
Measured at 390px: the add menu's items and the protocol chips were 32px
tall, the search field 36, and every dialog's close button a bare 16x16 icon
— that last one misses even the 24px WCAG 2.2 floor, let alone the 44px that
WCAG 2.5.5, Apple, and Material all ask of a touch target.

Phones now get 44px on the chips, the field, the manual-add trigger, and its
menu items; wider viewports keep the tighter mouse-sized versions. The close
button gets a 44px hit area at every width, grown with padding and pulled
back by an equal negative margin so the glyph does not move. The scenario
asserts no control in the dialog or its menu measures under 44px on a phone.
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.

1 participant