Browse Source

feat(04-01): add provider icon buttons to FloatingActionBar

- Add modelSearchOpen/modelSearchProvider state to workflowStore
- Add setModelSearchOpen action to toggle dialog with provider filter
- Add ProviderIconButton component with Replicate (R) and fal.ai (lightning) icons
- Replicate icon only visible when API key is configured
- fal.ai icon always visible (works without key but rate limited)
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
88c6232e45
  1. 43
      src/components/FloatingActionBar.tsx
  2. 19
      src/store/workflowStore.ts

43
src/components/FloatingActionBar.tsx

@ -2,7 +2,7 @@
import { useRef, useState, useEffect, useMemo } from "react";
import { useWorkflowStore } from "@/store/workflowStore";
import { NodeType } from "@/types";
import { NodeType, ProviderType } from "@/types";
import { useReactFlow } from "@xyflow/react";
// Get the center of the React Flow pane in screen coordinates
@ -141,6 +141,28 @@ function GenerateComboButton() {
);
}
function ProviderIconButton({ provider, onClick }: { provider: ProviderType; onClick: () => void }) {
return (
<button
onClick={onClick}
title={`Browse ${provider === "replicate" ? "Replicate" : "fal.ai"} models`}
className="p-1.5 text-neutral-400 hover:text-neutral-100 hover:bg-neutral-700 rounded transition-colors"
>
{provider === "replicate" ? (
// Replicate icon - stylized "R"
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="currentColor">
<path d="M4 4h8c2.2 0 4 1.8 4 4s-1.8 4-4 4H8v8H4V4zm4 4v4h4c1.1 0 2-.9 2-2s-.9-2-2-2H8zm4 8l6 4V12l-6 4z" />
</svg>
) : (
// fal.ai icon - lightning bolt
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="currentColor">
<path d="M13 2L3 14h8l-1 8 10-12h-8l1-8z" />
</svg>
)}
</button>
);
}
export function FloatingActionBar() {
const {
nodes,
@ -151,6 +173,9 @@ export function FloatingActionBar() {
validateWorkflow,
edgeStyle,
setEdgeStyle,
providerSettings,
setModelSearchOpen,
modelSearchOpen,
} = useWorkflowStore();
const [runMenuOpen, setRunMenuOpen] = useState(false);
const runMenuRef = useRef<HTMLDivElement>(null);
@ -215,6 +240,22 @@ export function FloatingActionBar() {
<GenerateComboButton />
<NodeButton type="output" label="Output" />
{/* Provider model browser icons */}
<div className="w-px h-5 bg-neutral-600 mx-1.5" />
{/* Replicate icon - only show if API key is configured */}
{providerSettings.providers.replicate?.apiKey && (
<ProviderIconButton
provider="replicate"
onClick={() => setModelSearchOpen(true, "replicate")}
/>
)}
{/* fal.ai icon - always show (works without key but rate limited) */}
<ProviderIconButton
provider="fal"
onClick={() => setModelSearchOpen(true, "fal")}
/>
<div className="w-px h-5 bg-neutral-600 mx-1.5" />
<button

19
src/store/workflowStore.ts

@ -160,6 +160,13 @@ interface WorkflowStore {
updateProviderSettings: (settings: ProviderSettings) => void;
updateProviderApiKey: (providerId: ProviderType, apiKey: string | null) => void;
toggleProvider: (providerId: ProviderType, enabled: boolean) => void;
// Model search dialog state
modelSearchOpen: boolean;
modelSearchProvider: ProviderType | null;
// Model search dialog actions
setModelSearchOpen: (open: boolean, provider?: ProviderType | null) => void;
}
const createDefaultNodeData = (type: NodeType): WorkflowNodeData => {
@ -406,6 +413,10 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
// Provider settings initial state
providerSettings: getProviderSettings(),
// Model search dialog initial state
modelSearchOpen: false,
modelSearchProvider: null,
setEdgeStyle: (style: EdgeStyle) => {
set({ edgeStyle: style });
},
@ -2182,4 +2193,12 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
set({ providerSettings: updated });
saveProviderSettings(updated);
},
// Model search dialog actions
setModelSearchOpen: (open: boolean, provider?: ProviderType | null) => {
set({
modelSearchOpen: open,
modelSearchProvider: provider ?? null,
});
},
}));

Loading…
Cancel
Save