improved a lot of things

This commit is contained in:
SinachPat
2026-04-30 16:56:27 +01:00
parent 42ba668399
commit e98fbb31f7
6 changed files with 132 additions and 76 deletions
@@ -3,7 +3,7 @@
// Authentication: Bearer <workspace_token> (HMAC-SHA256, issued by issueWorkspaceToken).
import { NextRequest, NextResponse } from 'next/server';
import { verifyWorkspaceToken, TOOL_MAP } from '@originmain/agent-bridge';
import { verifyWorkspaceToken, TOOL_MAP, getToolList } from '@originmain/agent-bridge';
import type { JsonRpcRequest, ToolContext } from '@originmain/agent-bridge';
import {
getDiffsByStatus,
@@ -47,12 +47,10 @@ export async function POST(req: NextRequest) {
}
// tools/list — meta-endpoint; return available tools without executing one.
// MCP spec requires each entry to include inputSchema so clients can
// construct valid tool calls without out-of-band documentation.
if (body.method === 'tools/list') {
const tools = [...TOOL_MAP.values()].map(t => ({
name: t.name,
description: t.description,
}));
return NextResponse.json({ jsonrpc: '2.0', id: body.id, result: { tools } });
return NextResponse.json({ jsonrpc: '2.0', id: body.id, result: { tools: getToolList() } });
}
// ── Dispatch ────────────────────────────────────────────────────────────────
@@ -17,7 +17,7 @@ export async function GET(req: NextRequest) {
try {
const db = serverClient();
const file = await getActiveDesignLanguageFile(db, workspaceId);
if (!file) return NextResponse.json(null, { status: 204 });
if (!file) return NextResponse.json(null);
return NextResponse.json(file);
} catch (err) {
const message = err instanceof Error ? err.message : 'Unknown error';
@@ -55,8 +55,12 @@ export function Artboard({ id, label, x, y, width, height, renderUrl }: Artboard
}, [localFiberRoot, selectComponent]);
// ── Drag to reposition ─────────────────────────────────────────────────────
const isDragging = useRef(false);
const dragStart = useRef({ mouseX: 0, mouseY: 0, artX: 0, artY: 0 });
const isDragging = useRef(false);
const dragStart = useRef({ mouseX: 0, mouseY: 0, artX: 0, artY: 0 });
// dragOffsetRef carries the live offset into the onUp closure, avoiding the
// stale-state problem that occurs when useCallback captures dragOffset before
// any mousemove events have fired.
const dragOffsetRef = useRef({ dx: 0, dy: 0 });
const [dragOffset, setDragOffset] = useState({ dx: 0, dy: 0 });
const onLabelMouseDown = useCallback((e: React.MouseEvent) => {
@@ -65,6 +69,7 @@ export function Artboard({ id, label, x, y, width, height, renderUrl }: Artboard
e.stopPropagation();
e.preventDefault();
isDragging.current = true;
dragOffsetRef.current = { dx: 0, dy: 0 };
const { zoom, panX, panY } = useViewport.getState();
dragStart.current = {
mouseX: (e.clientX - panX) / zoom,
@@ -79,10 +84,13 @@ export function Artboard({ id, label, x, y, width, height, renderUrl }: Artboard
const { zoom: z, panX: px, panY: py } = useViewport.getState();
const curX = (mv.clientX - px) / z;
const curY = (mv.clientY - py) / z;
setDragOffset({
const offset = {
dx: curX - dragStart.current.mouseX,
dy: curY - dragStart.current.mouseY,
});
};
// Update the ref first so onUp always reads the final position.
dragOffsetRef.current = offset;
setDragOffset(offset);
};
const onUp = () => {
@@ -91,8 +99,10 @@ export function Artboard({ id, label, x, y, width, height, renderUrl }: Artboard
window.removeEventListener('mousemove', onMove);
window.removeEventListener('mouseup', onUp);
const newX = Math.round(dragStart.current.artX + dragOffset.dx);
const newY = Math.round(dragStart.current.artY + dragOffset.dy);
// Read the final offset from the ref — never stale regardless of when
// useCallback last reconstructed onLabelMouseDown.
const newX = Math.round(dragStart.current.artX + dragOffsetRef.current.dx);
const newY = Math.round(dragStart.current.artY + dragOffsetRef.current.dy);
// Persist position
fetch(`/api/artboards/${id}`, {
@@ -104,12 +114,13 @@ export function Artboard({ id, label, x, y, width, height, renderUrl }: Artboard
}).then(() => {
queryClient.invalidateQueries({ queryKey: ['artboards', workspaceId, projectId ?? undefined] });
setDragOffset({ dx: 0, dy: 0 });
dragOffsetRef.current = { dx: 0, dy: 0 };
}).catch(console.error);
};
window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onUp);
}, [id, x, y, width, height, renderUrl, workspaceId, projectId, queryClient, dragOffset.dx, dragOffset.dy]);
}, [id, x, y, width, height, renderUrl, workspaceId, projectId, queryClient]);
// ── Inline rename ──────────────────────────────────────────────────────────
const [renaming, setRenaming] = useState(false);
@@ -62,7 +62,7 @@ export function ProjectSettingsForm({
memberRole,
}: ProjectSettingsFormProps) {
const router = useRouter();
const isOwnerOrDev = memberRole === 'OWNER' || memberRole === 'DEVELOPER' || memberRole === 'DESIGNER';
const isOwnerOrDev = memberRole === 'OWNER' || memberRole === 'ENGINEER' || memberRole === 'DESIGNER';
/* ── Form state ── */
const [name, setName] = useState(initialName);
@@ -229,7 +229,7 @@ export function ProjectSettingsForm({
border: '1px solid rgba(239,68,68,0.35)', background: 'transparent',
color: '#EF4444', cursor: deleteConfirm.trim() === initialName.trim() ? 'pointer' : 'not-allowed',
flexShrink: 0,
opacity: deleteConfirm.trim() !== name.trim() || deleting ? 0.4 : 1,
opacity: deleteConfirm.trim() !== initialName.trim() || deleting ? 0.4 : 1,
}}
>
{deleting ? 'Deleting…' : 'Delete project'}