From 941612c15428a38ab3fa931f467b675edd9be2f7 Mon Sep 17 00:00:00 2001 From: mrzmyr Date: Sat, 11 Apr 2026 12:32:29 +0200 Subject: [PATCH] refactor(react): restructure sources list and sources-add container - pages/sources.tsx: restructures the list to use CardStack entries with title cards, moves connected sources to the top, and drops the old built-in section header (built-ins live exclusively in the sidebar now). - pages/sources-add.tsx: wraps the add-source container in a relative positioning wrapper so FloatActions can render as a sticky bottom bar inside the form without escaping the layout. --- packages/react/src/pages/sources-add.tsx | 6 +- packages/react/src/pages/sources.tsx | 298 ++++++++++++----------- 2 files changed, 155 insertions(+), 149 deletions(-) diff --git a/packages/react/src/pages/sources-add.tsx b/packages/react/src/pages/sources-add.tsx index 954c9ba8a8..e566da59ad 100644 --- a/packages/react/src/pages/sources-add.tsx +++ b/packages/react/src/pages/sources-add.tsx @@ -25,7 +25,7 @@ export function SourcesAddPage(props: { if (!plugin) { return ( -
+

@@ -49,8 +49,8 @@ export function SourcesAddPage(props: { const AddComponent = plugin.add; return ( -

-
+
+
Loading…

}> = { openapi: "openapi", @@ -72,7 +85,7 @@ export function SourcesPage(props: { sourcePlugins: readonly SourcePlugin[] }) {

Sources

-

+

Tool providers available in this workspace.

@@ -80,55 +93,63 @@ export function SourcesPage(props: { sourcePlugins: readonly SourcePlugin[] }) { {/* URL detection input */}
-
- { - setUrl((e.target as HTMLInputElement).value); - setError(null); - }} - onKeyDown={(e) => { - if (e.key === "Enter") handleDetect(); - }} - placeholder="Paste a URL to auto-detect source type..." - disabled={detecting} - className="flex-1" - /> - -
- {error &&

{error}

} -
- Or add manually: - {sourcePlugins.map((p) => ( - + + - {p.label} - - ))} -
+
+ { + setUrl((e.target as HTMLInputElement).value); + setError(null); + }} + onKeyDown={(e) => { + if (e.key === "Enter") handleDetect(); + }} + placeholder="https://..." + disabled={detecting} + className="flex-1" + /> + +
+
+ Or add manually:{" "} + {sourcePlugins.map((p) => ( + + {p.label} + + ))} +
+ + +
- - - +
+ +
{Result.match(sources, { onInitial: () =>

Loading…

, onFailure: () =>

Failed to load sources

, onSuccess: ({ value }) => { - const builtInSources = value.filter((source) => source.runtime); const connectedSources = value.filter((source) => !source.runtime); return value.length === 0 ? ( -
+
-

No sources yet

-

+

No sources yet

+

Add a source to get started.

) : ( -
- {builtInSources.length > 0 && ( -
-
-

Built-in

-

- Runtime sources exposed by the loaded executor plugins. -

-
- -
- )} - +
{connectedSources.length > 0 && (
-
-

Connected

-

- User-configured sources available in this workspace. -

-
)} @@ -173,6 +176,10 @@ export function SourcesPage(props: { sourcePlugins: readonly SourcePlugin[] }) { ); }, })} + +
+ +
); @@ -182,47 +189,22 @@ export function SourcesPage(props: { sourcePlugins: readonly SourcePlugin[] }) { // Preset grid // --------------------------------------------------------------------------- -type PresetEntry = { preset: SourcePreset; pluginKey: string; pluginLabel: string }; - -function PresetCard({ preset, pluginKey, pluginLabel }: PresetEntry) { - const search: Record = { preset: preset.id }; - if (preset.url) search.url = preset.url; - - return ( - -
- {preset.icon ? ( - - ) : ( - - - - )} -
-
-
- {preset.name} - - {pluginLabel} - -
-

{preset.summary}

-
- - ); -} +type PresetEntry = { + preset: SourcePreset; + pluginKey: string; + pluginLabel: string; +}; function PresetGrid(props: { plugins: readonly SourcePlugin[] }) { const allPresets = useMemo(() => { const entries: PresetEntry[] = []; for (const plugin of props.plugins) { for (const preset of plugin.presets ?? []) { - entries.push({ preset, pluginKey: plugin.key, pluginLabel: plugin.label }); + entries.push({ + preset, + pluginKey: plugin.key, + pluginLabel: plugin.label, + }); } } return entries; @@ -232,17 +214,46 @@ function PresetGrid(props: { plugins: readonly SourcePlugin[] }) { return (
-
-

Popular sources

-

- One-click setup for common APIs and services. -

-
-
- {allPresets.map((entry) => ( - - ))} -
+ + Popular sources + + {allPresets.map(({ preset, pluginKey, pluginLabel }) => { + const search: Record = { preset: preset.id }; + if (preset.url) search.url = preset.url; + return ( + + + + {preset.icon ? ( + + ) : ( + + + + )} + + + {preset.name} + {preset.summary} + + + {pluginLabel} + + + + ); + })} + +
); } @@ -252,48 +263,43 @@ function PresetGrid(props: { plugins: readonly SourcePlugin[] }) { // --------------------------------------------------------------------------- function SourceGrid(props: { - sources: readonly { id: string; name: string; kind: string; runtime?: boolean }[]; + sources: readonly { + id: string; + name: string; + kind: string; + runtime?: boolean; + }[]; }) { return ( -
- {props.sources.map((s) => ( - -
-
- - - - -
-
-
-
{s.name}
-
- {s.runtime && ( - - built-in - - )} - - {s.kind} - -
-
-
{s.id}
-
-
- - ))} -
+ + Connected + + {props.sources.map((s) => ( + + + + + + + + + + {s.name} + {s.id} + + + {s.runtime && built-in} + {s.kind} + + + + ))} + + ); }