mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 20:57:42 +02:00
[Haik]: round 1 of browser use animations (glowing links) (auto spawn in position set)
This commit is contained in:
@@ -42,7 +42,7 @@ import ApprovalBar, { BatchApprovalBar } from './ApprovalBar';
|
||||
import ChatInput, { ChatInputHandle } from './ChatInput';
|
||||
import { ContextPath } from '@/app/components/DirectoryBrowser';
|
||||
import DiffViewer from './DiffViewer';
|
||||
import { setGlowingBrowserCards, clearGlowingBrowserCards } from '@/shared/state/dashboardLayoutSlice';
|
||||
import { setGlowingBrowserCards, fadeGlowingBrowserCards, clearGlowingBrowserCards } from '@/shared/state/dashboardLayoutSlice';
|
||||
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
|
||||
|
||||
const CONTEXT_WINDOWS: Record<string, number> = {
|
||||
@@ -204,13 +204,13 @@ const AgentChat: React.FC<AgentChatProps> = ({ sessionId: sessionIdProp, onClose
|
||||
const realId = action.payload.session.id;
|
||||
dispatch(generateTitle({ sessionId: realId, prompt: msg.prompt }));
|
||||
if (msg.selectedBrowserIds?.length) {
|
||||
dispatch(setGlowingBrowserCards({ browserIds: msg.selectedBrowserIds, sessionId: realId }));
|
||||
dispatch(setGlowingBrowserCards({ browserIds: msg.selectedBrowserIds, sessionId: realId, label: 'Use Browser' }));
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (msg.selectedBrowserIds?.length) {
|
||||
dispatch(setGlowingBrowserCards({ browserIds: msg.selectedBrowserIds, sessionId: id }));
|
||||
dispatch(setGlowingBrowserCards({ browserIds: msg.selectedBrowserIds, sessionId: id, label: 'Use Browser' }));
|
||||
}
|
||||
dispatch(sendMessageThunk({ sessionId: id, prompt: msg.prompt, mode, model, images: msg.images, contextPaths: msg.contextPaths, forcedTools: msg.forcedTools, attachedSkills: msg.attachedSkills, selectedBrowserIds: msg.selectedBrowserIds }))
|
||||
.then((action) => {
|
||||
@@ -234,7 +234,10 @@ const AgentChat: React.FC<AgentChatProps> = ({ sessionId: sessionIdProp, onClose
|
||||
const isTerminal = curr === 'completed' || curr === 'stopped' || curr === 'error';
|
||||
|
||||
if (wasActive && isTerminal) {
|
||||
if (id) dispatch(clearGlowingBrowserCards(id));
|
||||
if (id) {
|
||||
dispatch(fadeGlowingBrowserCards(id));
|
||||
setTimeout(() => dispatch(clearGlowingBrowserCards(id)), 2800);
|
||||
}
|
||||
|
||||
const nextQueued = messageQueueRef.current.shift();
|
||||
if (nextQueued) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
removeBrowserCard,
|
||||
pasteBrowserCard,
|
||||
placeCard,
|
||||
setCardPosition,
|
||||
removeCard,
|
||||
bringToFront,
|
||||
setGlowingAgentCard,
|
||||
@@ -103,6 +104,7 @@ const DashboardInner: React.FC = () => {
|
||||
const autoRevealSubAgents = useAppSelector((state) => state.settings.data.auto_reveal_sub_agents);
|
||||
const outputs = useAppSelector((state) => state.outputs.items);
|
||||
const glowingAgentCards = useAppSelector((state) => state.dashboardLayout.glowingAgentCards);
|
||||
const glowingBrowserCards = useAppSelector((state) => state.dashboardLayout.glowingBrowserCards);
|
||||
const sessionList = Object.values(sessions);
|
||||
|
||||
const canvas = useCanvasControls(zoomSensitivity);
|
||||
@@ -752,7 +754,18 @@ const DashboardInner: React.FC = () => {
|
||||
const realId = action.payload.session.id;
|
||||
dispatch(generateTitle({ sessionId: realId, prompt }));
|
||||
if (selectedBrowserIds?.length) {
|
||||
dispatch(setGlowingBrowserCards({ browserIds: selectedBrowserIds, sessionId: realId }));
|
||||
dispatch(setGlowingBrowserCards({ browserIds: selectedBrowserIds, sessionId: realId, label: 'Use Browser' }));
|
||||
|
||||
if (selectedBrowserIds.length === 1) {
|
||||
const bc = store.getState().dashboardLayout.browserCards[selectedBrowserIds[0]];
|
||||
if (bc) {
|
||||
dispatch(setCardPosition({
|
||||
sessionId: realId,
|
||||
x: bc.x - DEFAULT_CARD_W - GRID_GAP * 12,
|
||||
y: bc.y,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
spawnOriginsRef.current[realId] = spawnOriginsRef.current[draftId];
|
||||
delete spawnOriginsRef.current[draftId];
|
||||
@@ -919,7 +932,7 @@ const DashboardInner: React.FC = () => {
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
return Object.entries(glowingAgentCards).map(([copyId, { sourceId, fading, sourceYRatio, label }]) => {
|
||||
const agentTethers = Object.entries(glowingAgentCards).map(([copyId, { sourceId, fading, sourceYRatio, label }]) => {
|
||||
const src = cards[sourceId];
|
||||
const dst = cards[copyId];
|
||||
if (!src || !dst) return null;
|
||||
@@ -957,8 +970,46 @@ const DashboardInner: React.FC = () => {
|
||||
fading,
|
||||
};
|
||||
}).filter(Boolean) as Array<{ key: string; path: string; labelX: number; labelY: number; label: string; fading: boolean }>;
|
||||
|
||||
const browserTethers = Object.entries(glowingBrowserCards).map(([browserId, { sourceId, fading, label }]) => {
|
||||
const src = cards[sourceId];
|
||||
const dst = browserCards[browserId];
|
||||
if (!src || !dst) return null;
|
||||
|
||||
let srcX = src.x, srcY = src.y;
|
||||
let dstX = dst.x, dstY = dst.y;
|
||||
if (liveDragInfo) {
|
||||
if (liveDragInfo.cardId === sourceId) { srcX += liveDragInfo.dx; srcY += liveDragInfo.dy; }
|
||||
if (liveDragInfo.cardId === browserId) { dstX += liveDragInfo.dx; dstY += liveDragInfo.dy; }
|
||||
}
|
||||
|
||||
const srcMeasured = measuredHeightsRef.current[sourceId];
|
||||
const srcH = srcMeasured ?? (expandedSessionIds.includes(sourceId)
|
||||
? Math.max(EXPANDED_CARD_MIN_H, src.height)
|
||||
: src.height);
|
||||
const dstH = dst.height;
|
||||
|
||||
const x1 = srcX + src.width;
|
||||
const y1 = srcY + srcH * 0.54;
|
||||
const x2 = dstX;
|
||||
const y2 = dstY + dstH * 0.54;
|
||||
const midX = x1 + (x2 - x1) / 2;
|
||||
const labelX = midX + (x2 - midX) * 0.15;
|
||||
const labelY = y2;
|
||||
|
||||
return {
|
||||
key: `browser-${browserId}`,
|
||||
path: elbowPath(x1, y1, x2, y2),
|
||||
labelX,
|
||||
labelY,
|
||||
label: label || '',
|
||||
fading,
|
||||
};
|
||||
}).filter(Boolean) as Array<{ key: string; path: string; labelX: number; labelY: number; label: string; fading: boolean }>;
|
||||
|
||||
return [...agentTethers, ...browserTethers];
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [glowingAgentCards, cards, expandedSessionIds, liveDragInfo, measuredHeightsTick]);
|
||||
}, [glowingAgentCards, glowingBrowserCards, cards, browserCards, expandedSessionIds, liveDragInfo, measuredHeightsTick]);
|
||||
|
||||
const dotSize = Math.max(1, 1.5 * canvas.zoom);
|
||||
const dotSpacing = 24 * canvas.zoom;
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface DashboardLayoutState {
|
||||
viewCards: Record<string, ViewCardPosition>;
|
||||
browserCards: Record<string, BrowserCardPosition>;
|
||||
closedCardPositions: Record<string, CardPosition>;
|
||||
glowingBrowserCards: Record<string, string>;
|
||||
glowingBrowserCards: Record<string, { sourceId: string; fading: boolean; label?: string }>;
|
||||
glowingAgentCards: Record<string, { sourceId: string; fading: boolean; sourceYRatio?: number; label?: string }>;
|
||||
persistedExpandedSessionIds: string[];
|
||||
nextZOrder: number;
|
||||
@@ -632,18 +632,25 @@ const dashboardLayoutSlice = createSlice({
|
||||
|
||||
setGlowingBrowserCards(
|
||||
state,
|
||||
action: PayloadAction<{ browserIds: string[]; sessionId: string }>
|
||||
action: PayloadAction<{ browserIds: string[]; sessionId: string; label?: string }>
|
||||
) {
|
||||
const { browserIds, sessionId } = action.payload;
|
||||
const { browserIds, sessionId, label } = action.payload;
|
||||
for (const id of browserIds) {
|
||||
state.glowingBrowserCards[id] = sessionId;
|
||||
state.glowingBrowserCards[id] = { sourceId: sessionId, fading: false, label };
|
||||
}
|
||||
},
|
||||
|
||||
fadeGlowingBrowserCards(state, action: PayloadAction<string>) {
|
||||
const sessionId = action.payload;
|
||||
for (const entry of Object.values(state.glowingBrowserCards)) {
|
||||
if (entry.sourceId === sessionId) entry.fading = true;
|
||||
}
|
||||
},
|
||||
|
||||
clearGlowingBrowserCards(state, action: PayloadAction<string>) {
|
||||
const sessionId = action.payload;
|
||||
for (const [browserId, sid] of Object.entries(state.glowingBrowserCards)) {
|
||||
if (sid === sessionId) delete state.glowingBrowserCards[browserId];
|
||||
for (const [browserId, entry] of Object.entries(state.glowingBrowserCards)) {
|
||||
if (entry.sourceId === sessionId) delete state.glowingBrowserCards[browserId];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -751,6 +758,7 @@ export const {
|
||||
reorderBrowserTab,
|
||||
moveCards,
|
||||
setGlowingBrowserCards,
|
||||
fadeGlowingBrowserCards,
|
||||
clearGlowingBrowserCards,
|
||||
clearAllGlowingBrowserCards,
|
||||
setGlowingAgentCard,
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
closeSessionFromWs,
|
||||
trackAgentNotification,
|
||||
} from '../state/agentsSlice';
|
||||
import { addBrowserCardFromBackend, setBrowserCardPosition, GRID_GAP } from '../state/dashboardLayoutSlice';
|
||||
import { addBrowserCardFromBackend, setBrowserCardPosition, setGlowingBrowserCards, GRID_GAP } from '../state/dashboardLayoutSlice';
|
||||
|
||||
type WSEvent = {
|
||||
event: string;
|
||||
@@ -249,6 +249,11 @@ class WebSocketManager {
|
||||
x: parentCard.x + parentCard.width + GRID_GAP * 12,
|
||||
y: parentCard.y,
|
||||
}));
|
||||
store.dispatch(setGlowingBrowserCards({
|
||||
browserIds: [data.browser_card.browser_id],
|
||||
sessionId: parentId,
|
||||
label: 'Use Browser',
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user