mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[aidan] ux/workflows: open New workflow in agent build chat instead of empty card
When creating a new workflow from the hub, open it in edit_agent view (with the agent builder chat) instead of a preview card. The workflow is created on the backend first so the embedded session has a real ID.
This commit is contained in:
@@ -10,7 +10,7 @@ export interface SelectedElement {
|
||||
computedStyles: Record<string, string>;
|
||||
screenshot?: string;
|
||||
boundingRect: { x: number; y: number; width: number; height: number };
|
||||
semanticType?: 'agent-card' | 'message' | 'tool-call' | 'tool-group' | 'view-card' | 'browser-card' | 'dom-element';
|
||||
semanticType?: 'agent-card' | 'message' | 'tool-call' | 'tool-group' | 'view-card' | 'browser-card' | 'workflow-card' | 'workflows-hub-card' | 'dom-element';
|
||||
semanticLabel?: string;
|
||||
semanticData?: Record<string, any>;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ const SELECT_ATTR = 'data-select-type';
|
||||
const SELECT_ID_ATTR = 'data-select-id';
|
||||
const SELECT_META_ATTR = 'data-select-meta';
|
||||
|
||||
const DRAG_SELECT_TYPES = ['agent-card', 'view-card', 'browser-card'] as const;
|
||||
const DRAG_SELECT_TYPES = ['agent-card', 'view-card', 'browser-card', 'workflow-card', 'workflows-hub-card'] as const;
|
||||
const DRAG_SELECTOR = DRAG_SELECT_TYPES.map((t) => `[${SELECT_ATTR}="${t}"]`).join(',');
|
||||
|
||||
export interface OverlayState {
|
||||
@@ -38,6 +38,8 @@ const SEMANTIC_LABELS: Record<string, string> = {
|
||||
'tool-group': 'Tool Group',
|
||||
'view-card': 'View',
|
||||
'browser-card': 'Browser',
|
||||
'workflow-card': 'Workflow',
|
||||
'workflows-hub-card': 'Workflows',
|
||||
};
|
||||
|
||||
function findSelectableAncestor(target: Element, excludeId?: string | null): Element | null {
|
||||
|
||||
@@ -289,6 +289,8 @@ const DashboardCanvas: React.FC<DashboardCanvasProps> = ({
|
||||
cards={cards}
|
||||
viewCards={viewCards}
|
||||
browserCards={browserCards}
|
||||
workflowCards={workflowCards}
|
||||
workflowsHub={workflowsHub}
|
||||
focusedCardId={focusedCardId}
|
||||
shakeDirection={shakeDirection}
|
||||
neighborDirections={neighborDirections}
|
||||
|
||||
@@ -273,6 +273,14 @@ const DashboardCardLayer: React.FC<DashboardCardLayerProps> = ({
|
||||
zoom={zoom}
|
||||
panX={panX}
|
||||
panY={panY}
|
||||
isSelected={selection.isSelected('workflows-hub')}
|
||||
isHighlighted={highlightedCardId === 'workflows-hub'}
|
||||
multiDragDelta={selection.isSelected('workflows-hub') ? multiDragDelta : null}
|
||||
onCardSelect={onCardSelect}
|
||||
onDragStart={onDragStart}
|
||||
onDragMove={onDragMove}
|
||||
onDragEnd={onDragEnd}
|
||||
onBringToFront={onBringToFront}
|
||||
/>
|
||||
)}
|
||||
{Object.values(workflowCards).map((wc) => (
|
||||
|
||||
@@ -9,6 +9,8 @@ import type {
|
||||
CardPosition,
|
||||
ViewCardPosition,
|
||||
BrowserCardPosition,
|
||||
WorkflowCardPosition,
|
||||
WorkflowsHubPosition,
|
||||
} from '@/shared/state/dashboardLayoutSlice';
|
||||
import type { useCanvasControls } from '../hooks/interaction/useCanvasControls';
|
||||
|
||||
@@ -23,6 +25,8 @@ interface DashboardOverlaysProps {
|
||||
cards: Record<string, CardPosition>;
|
||||
viewCards: Record<string, ViewCardPosition>;
|
||||
browserCards: Record<string, BrowserCardPosition>;
|
||||
workflowCards: Record<string, WorkflowCardPosition>;
|
||||
workflowsHub: WorkflowsHubPosition | null;
|
||||
focusedCardId: string | null;
|
||||
shakeDirection: Direction | null;
|
||||
neighborDirections: NeighborDirections;
|
||||
@@ -52,6 +56,8 @@ const DashboardOverlays: React.FC<DashboardOverlaysProps> = ({
|
||||
cards,
|
||||
viewCards,
|
||||
browserCards,
|
||||
workflowCards,
|
||||
workflowsHub,
|
||||
focusedCardId,
|
||||
shakeDirection,
|
||||
neighborDirections,
|
||||
@@ -121,6 +127,8 @@ const DashboardOverlays: React.FC<DashboardOverlaysProps> = ({
|
||||
cards,
|
||||
viewCards,
|
||||
browserCards,
|
||||
workflowCards,
|
||||
workflowsHub,
|
||||
}}
|
||||
onMinimapPan={(px, py) => canvas.actions.setState({ panX: px, panY: py, zoom: canvas.zoom })}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useRef, useCallback, useMemo } from 'react';
|
||||
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
|
||||
import type { CardPosition, ViewCardPosition, BrowserCardPosition } from '@/shared/state/dashboardLayoutSlice';
|
||||
import type { CardPosition, ViewCardPosition, BrowserCardPosition, WorkflowCardPosition, WorkflowsHubPosition } from '@/shared/state/dashboardLayoutSlice';
|
||||
|
||||
const MINIMAP_W = 200;
|
||||
const MINIMAP_H = 140;
|
||||
@@ -14,6 +14,8 @@ export interface MinimapProps {
|
||||
cards: Record<string, CardPosition>;
|
||||
viewCards: Record<string, ViewCardPosition>;
|
||||
browserCards: Record<string, BrowserCardPosition>;
|
||||
workflowCards: Record<string, WorkflowCardPosition>;
|
||||
workflowsHub: WorkflowsHubPosition | null;
|
||||
onPan: (panX: number, panY: number) => void;
|
||||
}
|
||||
|
||||
@@ -22,12 +24,12 @@ interface CardRect {
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
type: 'agent' | 'view' | 'browser';
|
||||
type: 'agent' | 'view' | 'browser' | 'workflow' | 'workflows-hub';
|
||||
}
|
||||
|
||||
const Minimap: React.FC<MinimapProps> = ({
|
||||
panX, panY, zoom, viewportRef,
|
||||
cards, viewCards, browserCards,
|
||||
cards, viewCards, browserCards, workflowCards, workflowsHub,
|
||||
onPan,
|
||||
}) => {
|
||||
const c = useClaudeTokens();
|
||||
@@ -45,8 +47,20 @@ const Minimap: React.FC<MinimapProps> = ({
|
||||
for (const bc of Object.values(browserCards)) {
|
||||
result.push({ x: bc.x, y: bc.y, width: bc.width, height: bc.height, type: 'browser' });
|
||||
}
|
||||
for (const wc of Object.values(workflowCards)) {
|
||||
result.push({ x: wc.x, y: wc.y, width: wc.width, height: wc.height, type: 'workflow' });
|
||||
}
|
||||
if (workflowsHub) {
|
||||
result.push({
|
||||
x: workflowsHub.x,
|
||||
y: workflowsHub.y,
|
||||
width: workflowsHub.width,
|
||||
height: workflowsHub.height,
|
||||
type: 'workflows-hub',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}, [cards, viewCards, browserCards]);
|
||||
}, [cards, viewCards, browserCards, workflowCards, workflowsHub]);
|
||||
|
||||
const layout = useMemo(() => {
|
||||
const vp = viewportRef.current;
|
||||
@@ -128,11 +142,13 @@ const Minimap: React.FC<MinimapProps> = ({
|
||||
window.addEventListener('mouseup', onUp);
|
||||
}, [minimapToCanvas]);
|
||||
|
||||
const typeColor = (type: 'agent' | 'view' | 'browser') => {
|
||||
const typeColor = (type: CardRect['type']) => {
|
||||
switch (type) {
|
||||
case 'agent': return c.accent.primary;
|
||||
case 'view': return c.status.info;
|
||||
case 'browser': return c.status.success;
|
||||
case 'workflow': return c.status.warning;
|
||||
case 'workflows-hub': return c.status.warning;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ export function getCardRect(id: string, type: CardType):
|
||||
const wc = layoutState.workflowCards[id];
|
||||
if (!wc) return undefined;
|
||||
return { x: wc.x, y: wc.y, width: wc.width, height: wc.height };
|
||||
} else if (type === 'workflows-hub') {
|
||||
const hub = layoutState.workflowsHub;
|
||||
if (!hub) return undefined;
|
||||
return { x: hub.x, y: hub.y, width: hub.width, height: hub.height };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ export function useDashboardController(dashboardId: string, isActive: boolean) {
|
||||
browserCards,
|
||||
notes,
|
||||
workflowCards,
|
||||
workflowsHub,
|
||||
);
|
||||
const {
|
||||
toolbarRef, toolbarOpen, setToolbarOpen, searchPaletteOpen, setSearchPaletteOpen,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useCallback, useRef, useEffect, RefObject } from 'react';
|
||||
import type { CardPosition, ViewCardPosition, BrowserCardPosition, NotePosition, WorkflowCardPosition } from '@/shared/state/dashboardLayoutSlice';
|
||||
import type { CardPosition, ViewCardPosition, BrowserCardPosition, NotePosition, WorkflowCardPosition, WorkflowsHubPosition } from '@/shared/state/dashboardLayoutSlice';
|
||||
|
||||
export type { CardType } from '@/shared/state/dashboardLayoutSlice';
|
||||
import type { CardType } from '@/shared/state/dashboardLayoutSlice';
|
||||
@@ -44,6 +44,7 @@ export function useDashboardSelection(
|
||||
browserCards: Record<string, BrowserCardPosition> = {},
|
||||
notes: Record<string, NotePosition> = {},
|
||||
workflowCards: Record<string, WorkflowCardPosition> = {},
|
||||
workflowsHub: WorkflowsHubPosition | null = null,
|
||||
) {
|
||||
const [selectedIds, setSelectedIds] = useState<Map<string, CardType>>(new Map());
|
||||
const [marquee, setMarquee] = useState<MarqueeRect | null>(null);
|
||||
@@ -79,8 +80,9 @@ export function useDashboardSelection(
|
||||
for (const bc of Object.values(browserCards)) next.set(bc.browser_id, 'browser');
|
||||
for (const n of Object.values(notes)) next.set(n.note_id, 'note');
|
||||
for (const wc of Object.values(workflowCards)) next.set(wc.workflow_id, 'workflow');
|
||||
if (workflowsHub) next.set('workflows-hub', 'workflows-hub');
|
||||
setSelectedIds(next);
|
||||
}, [cards, viewCards, browserCards, notes, workflowCards]);
|
||||
}, [cards, viewCards, browserCards, notes, workflowCards, workflowsHub]);
|
||||
|
||||
const selectCard = useCallback(
|
||||
(id: string, type: CardType, shiftKey: boolean) => {
|
||||
@@ -176,6 +178,18 @@ export function useDashboardSelection(
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
workflowsHub &&
|
||||
rectsIntersect(rect, {
|
||||
x: workflowsHub.x,
|
||||
y: workflowsHub.y,
|
||||
width: workflowsHub.width,
|
||||
height: workflowsHub.height,
|
||||
})
|
||||
) {
|
||||
intersecting.set('workflows-hub', 'workflows-hub');
|
||||
}
|
||||
|
||||
if (shiftKey) {
|
||||
const base = selectionBeforeMarqueeRef.current;
|
||||
const next = new Map(base);
|
||||
@@ -191,7 +205,7 @@ export function useDashboardSelection(
|
||||
|
||||
return intersecting;
|
||||
},
|
||||
[cards, viewCards, browserCards, notes, workflowCards],
|
||||
[cards, viewCards, browserCards, notes, workflowCards, workflowsHub],
|
||||
);
|
||||
|
||||
const handleCanvasMouseDown = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user