@k2b/cloud
Cloud resource picker
Choose a permission-filtered Cloud resource through Universal Search and keep its stable reference.
Backend-required resource selection through the authenticated Universal Search catalog.
Real search providers and permissions required
The picker discovers live resources and tag filters through authenticated Universal Search. Choose a result, inspect its preview, then confirm with Add. On small screens, Details opens the preview. The catalog shows this contract without inventing authorized resources.
TSX
Copyimport { openCloudResourcePicker } from "@k2b/cloud/browser/resource-picker"; const selected = await openCloudResourcePicker({ title: "Add Cloud reference", excludeRefs: currentReferences, requireReader: true,}); if (selected) { await saveReference(selected.ref, selected.title);}The Cloud resource picker lets a user choose one permission-filtered Universal Search result and returns the result with its stable CloudResourceRef. The application decides what the selection means and how to persist it.
Use the Cloud resource picker
Use the picker when a browser interaction needs a reference to a resource owned by any searchable Cloud application. Use requireReader when the consumer must later resolve the selected ref through its canonical reader. Use initialAppId to start within one application and excludeRefs to prevent duplicate selections.
Do not use it for application-local exhaustive browsing or as an authorization check. The owning search provider authorizes every result, and the consuming service must still authorize later reads or mutations.
Import
import { openCloudResourcePicker } from "@k2b/cloud/browser/resource-picker";Selection ownership
The picker owns its dialog, search input, tag filters, loading, error states, and result selection. A click or Enter selects a result; Add confirms it. It returns the selected search item or undefined when the dialog closes without a selection.
Store selected.ref as the durable identity. Treat the returned title, preview, metadata, and links as presentation data that may change.
Available options are:
titleandplaceholderfor task-specific copy;initialAppIdto start within one searchable application, shown as a removable scope chip;scope: { appId, tag?, label, icon? }to narrow the search on the server by app and optional search tag, shown as a removable chip with its label and icon; takes precedence overinitialAppId;queryto prefill the search text;excludeRefsto hide resources already selected;requireReaderto show only Types with a canonical reader.
An app scope starts searching at once, even with empty text. Scope filtering
happens before the per-app result limit, so other resource kinds cannot crowd
out matches as they can with the browser-only resourceType filter.
requireReader still applies within the scope.
Presentation
The picker starts with a search field and a few tag suggestions. All filters
or typing # opens the full filter list in the result area. Aliases remain
searchable without appearing as duplicate filters. No application dropdown or
nested autocomplete menu is shown.
While a request starts, the spinner replaces the search icon. Quiet tag placeholders reserve the suggestion row so opening the dialog does not shift its layout.
Desktop results share the dialog with a preview that starts at its top edge.
From the first search character until the input is cleared, the dialog keeps
its width, top position, and height; arriving results scroll inside it instead
of resizing it.
Small screens show one column with an optional Details view. Below 48rem
the picker is a full-screen sheet: the whole width, from below the status bar
to the bottom edge, rounded at the top, while global search keeps its floating
card. The result list
uses ScrollArea fades. Each application's results appear as it answers and
are appended below earlier ones; a quiet line below the results names the
applications still searching or one that did not answer, with Try again
for that application alone. “No matches” appears only after every
application has answered; a picker narrowed to one application says
Mail: no matches for “invoice”. Previous results remain visible until the
new search shows its first results, but cannot be added for the new query.
Accessibility
The dialog provides its title as its accessible name, moves focus into the search interaction, and supports closing with Escape. Arrow keys navigate results or tag suggestions. Enter selects, Tab moves focus normally, and Add confirms the resource. Escape first leaves tag discovery or mobile details, then closes the dialog. Use a task-specific title when the surrounding workflow needs more context than “Choose Cloud resource.”
Runtime
Call the picker from browser code. It uses the authenticated /api/search route and discovers the current application catalog from the running Cloud installation. Search providers remain responsible for permission-filtering every result. requireReader filters capabilities; it does not grant access or replace authorization.
Example
const selected = await openCloudResourcePicker({
title: "Add Cloud reference",
excludeRefs: currentReferences,
requireReader: true,
});
if (selected) {
await saveReference(selected.ref, selected.title);
}See Universal Search for provider registration, resource refs, tags, readers, and authorization.