feat(FN-1813): merge fusion/fn-1813

This commit is contained in:
Fusion
2026-04-16 05:23:10 -07:00
committed by gsxdsm
parent 72842d8687
commit 6e784c3700
5 changed files with 86 additions and 11 deletions

View File

@@ -538,7 +538,6 @@ export async function runServe(
const settingsStore = new GlobalSettingsStore(globalDir);
const tokenManager = new DaemonTokenManager(settingsStore);
daemonToken = await tokenManager.generateToken();
await tokenManager.storeToken(daemonToken);
}
}

View File

@@ -45,9 +45,9 @@ function useDraggable(projectId?: string, externalDidDragRef?: React.MutableRefO
// Default positions
const getDefaultPosition = useCallback((): Position => {
// Mobile uses smaller default offset (16px vs 24px)
// Mobile uses tighter default offset (4px vs 24px) to maximize screen space
if (typeof window !== "undefined" && window.innerWidth <= 768) {
return { x: 16, y: 16 + getFooterHeight() };
return { x: 4, y: 4 + getFooterHeight() };
}
return { x: 24, y: 24 + getFooterHeight() };
}, [getFooterHeight]);
@@ -82,7 +82,8 @@ function useDraggable(projectId?: string, externalDidDragRef?: React.MutableRefO
if (typeof window === "undefined") return pos;
const fabSize = 48; // FAB is 48x48px
const edgeMargin = 48; // Keep at least 48px from viewport edges
// Mobile uses tighter margin (4px) to maximize screen space on small devices
const edgeMargin = window.innerWidth <= 768 ? 4 : 48;
// Account for mobile nav height when clamping bottom
const mobileNavHeight = window.innerWidth <= 768 ? 44 : 0;
// Account for executor footer height on desktop

View File

@@ -2322,7 +2322,7 @@ describe("GitManagerModal", () => {
fireEvent.click(screen.getByRole("tab", { name: /remotes/i }));
await waitFor(() => {
expect(screen.getByText("origin")).toBeInTheDocument();
expect(screen.getByTestId("remote-detail-card")).toBeInTheDocument();
});
const editButton = screen.getByTitle("Edit remote URL");

View File

@@ -533,6 +533,7 @@ describe("QuickChatFAB", () => {
});
it("FAB position is clamped to viewport boundaries", async () => {
// Desktop viewport (jsdom default 1024px > 768px): 48px edge margin
render(<QuickChatFAB addToast={addToast} projectId="proj-123" />);
const fab = screen.getByTestId("quick-chat-fab");
@@ -559,7 +560,81 @@ describe("QuickChatFAB", () => {
pointerId: 1,
});
// Position should be clamped to at least 48px from edges
// Desktop: position should be clamped to at least 48px from edges
const savedPosition = JSON.parse(localStorageMock.setItem.mock.calls[0]?.[1] || "{}");
expect(savedPosition.x).toBeGreaterThanOrEqual(48);
expect(savedPosition.y).toBeGreaterThanOrEqual(48);
});
it("on mobile viewport, FAB can be dragged to within 4px of the edge", async () => {
// Mock mobile viewport (375px wide, which is <= 768px)
Object.defineProperty(window, "innerWidth", { value: 375, writable: true });
Object.defineProperty(window, "innerHeight", { value: 812, writable: true });
render(<QuickChatFAB addToast={addToast} projectId="proj-123" />);
const fab = screen.getByTestId("quick-chat-fab");
// Simulate drag to extreme position (off viewport)
fireEvent.pointerDown(fab, {
clientX: 100,
clientY: 100,
button: 0,
pointerId: 1,
});
// Try to drag way off screen (negative coordinates)
fireEvent.pointerMove(fab, {
clientX: -1000,
clientY: -1000,
pointerId: 1,
});
fireEvent.pointerUp(fab, {
clientX: -1000,
clientY: -1000,
button: 0,
pointerId: 1,
});
// Mobile (375px <= 768px): position should be clamped to at least 4px from edges
const savedPosition = JSON.parse(localStorageMock.setItem.mock.calls[0]?.[1] || "{}");
expect(savedPosition.x).toBeGreaterThanOrEqual(4);
expect(savedPosition.y).toBeGreaterThanOrEqual(4);
});
it("on desktop viewport, FAB edge margin remains 48px", async () => {
// Explicitly set desktop viewport (1024px wide, which is > 768px)
Object.defineProperty(window, "innerWidth", { value: 1024, writable: true });
Object.defineProperty(window, "innerHeight", { value: 768, writable: true });
render(<QuickChatFAB addToast={addToast} projectId="proj-123" />);
const fab = screen.getByTestId("quick-chat-fab");
// Simulate drag to extreme position (off viewport)
fireEvent.pointerDown(fab, {
clientX: 100,
clientY: 100,
button: 0,
pointerId: 1,
});
// Try to drag way off screen (negative coordinates)
fireEvent.pointerMove(fab, {
clientX: -1000,
clientY: -1000,
pointerId: 1,
});
fireEvent.pointerUp(fab, {
clientX: -1000,
clientY: -1000,
button: 0,
pointerId: 1,
});
// Desktop: position should be clamped to at least 48px from edges
const savedPosition = JSON.parse(localStorageMock.setItem.mock.calls[0]?.[1] || "{}");
expect(savedPosition.x).toBeGreaterThanOrEqual(48);
expect(savedPosition.y).toBeGreaterThanOrEqual(48);

View File

@@ -29006,15 +29006,15 @@ html .column.drag-over * {
@media (max-width: 768px) {
.quick-chat-fab {
right: 16px;
bottom: calc(16px + var(--executor-footer-height-mobile, var(--executor-footer-height, 0px)) + var(--mobile-nav-height, 44px) + env(safe-area-inset-bottom, 0px));
right: 4px;
bottom: calc(4px + var(--executor-footer-height-mobile, var(--executor-footer-height, 0px)) + var(--mobile-nav-height, 44px) + env(safe-area-inset-bottom, 0px));
}
.quick-chat-panel {
right: 16px;
left: 16px;
right: 4px;
left: 4px;
width: auto;
bottom: calc(72px + var(--executor-footer-height-mobile, var(--executor-footer-height, 0px)) + var(--mobile-nav-height, 44px) + env(safe-area-inset-bottom, 0px));
bottom: calc(60px + var(--executor-footer-height-mobile, var(--executor-footer-height, 0px)) + var(--mobile-nav-height, 44px) + env(safe-area-inset-bottom, 0px));
height: min(420px, calc(100dvh - 160px));
}
}