From 39701459b499d54f07f8af12a1f4d42f0370825e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:50:32 +0000 Subject: [PATCH 1/2] feat: reset branch to bf6043b Reset the branch feature/radial-drawing-tool-15881425069546006738 to commit bf6043b, discarding subsequent commits 9dbf4f0, a83e0d2, and e78d174. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com> --- components/chat.tsx | 39 ++++++++------ components/header-search-button.tsx | 38 +++---------- components/map/map-query-handler.tsx | 60 ++++++++++++--------- components/mobile-icons-bar.tsx | 7 ++- components/resolution-image.tsx | 4 +- lib/agents/researcher.tsx | 5 +- lib/agents/tools/drawing.tsx | 80 ++++++++++++---------------- lib/schema/drawing.tsx | 32 ++++++----- lib/types/tools.ts | 20 ------- lib/utils/index.ts | 16 +----- lib/utils/mcp.ts | 17 ++---- 11 files changed, 125 insertions(+), 193 deletions(-) delete mode 100644 lib/types/tools.ts diff --git a/components/chat.tsx b/components/chat.tsx index c5864d75..79c7bb13 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -17,8 +17,8 @@ import { useProfileToggle, ProfileToggleEnum } from "@/components/profile-toggle import { useUsageToggle } from "@/components/usage-toggle-context"; import SettingsView from "@/components/settings/settings-view"; import { UsageView } from "@/components/usage-view"; -import { MapDataProvider, useMapData } from './map/map-data-context'; -import { updateDrawingContext } from '@/lib/actions/chat'; +import { MapDataProvider, useMapData } from './map/map-data-context'; // Add this and useMapData +import { updateDrawingContext } from '@/lib/actions/chat'; // Import the server action import dynamic from 'next/dynamic' import { HeaderSearchButton } from './header-search-button' @@ -41,9 +41,6 @@ export function Chat({ id }: ChatProps) { const [suggestions, setSuggestions] = useState(null) const chatPanelRef = useRef(null); - // Ref to track the last message ID we refreshed the router for, to prevent infinite loops - const lastRefreshedMessageIdRef = useRef(null); - const handleAttachment = () => { chatPanelRef.current?.handleAttachmentClick(); }; @@ -57,11 +54,18 @@ export function Chat({ id }: ChatProps) { }, [messages]) useEffect(() => { + // Check if device is mobile const checkMobile = () => { setIsMobile(window.innerWidth < 768) } + + // Initial check checkMobile() + + // Add event listener for window resize window.addEventListener('resize', checkMobile) + + // Cleanup return () => window.removeEventListener('resize', checkMobile) }, []) @@ -72,16 +76,13 @@ export function Chat({ id }: ChatProps) { }, [id, path, messages]) useEffect(() => { - // Check if there is a 'response' message in the history - const responseMessage = aiState.messages.findLast(m => m.type === 'response'); - - if (responseMessage && responseMessage.id !== lastRefreshedMessageIdRef.current) { - console.log('Chat.tsx: refreshing router for message:', responseMessage.id); - lastRefreshedMessageIdRef.current = responseMessage.id; - router.refresh(); + if (aiState.messages[aiState.messages.length - 1]?.type === 'response') { + // Refresh the page to chat history updates + router.refresh() } - }, [aiState.messages, router]) + }, [aiState, router]) + // Get mapData to access drawnFeatures const { mapData } = useMapData(); useEffect(() => { @@ -91,8 +92,10 @@ export function Chat({ id }: ChatProps) { } }, [isSubmitting]) + // useEffect to call the server action when drawnFeatures changes useEffect(() => { if (id && mapData.drawnFeatures && mapData.cameraState) { + console.log('Chat.tsx: drawnFeatures changed, calling updateDrawingContext', mapData.drawnFeatures); updateDrawingContext(id, { drawnFeatures: mapData.drawnFeatures, cameraState: mapData.cameraState, @@ -109,6 +112,7 @@ export function Chat({ id }: ChatProps) { onSelect={query => { setInput(query) setSuggestions(null) + // Use a small timeout to ensure state update before submission setIsSubmitting(true) }} onClose={() => setSuggestions(null)} @@ -118,9 +122,10 @@ export function Chat({ id }: ChatProps) { ); }; + // Mobile layout if (isMobile) { return ( - + {/* Add Provider */}
@@ -164,10 +169,12 @@ export function Chat({ id }: ChatProps) { ); } + // Desktop layout return ( - + {/* Add Provider */}
+ {/* This is the new div for scrolling */}
{isCalendarOpen ? ( @@ -199,7 +206,7 @@ export function Chat({ id }: ChatProps) {
{activeView ? : isUsageOpen ? : }
diff --git a/components/header-search-button.tsx b/components/header-search-button.tsx index 4b7add6e..69fda09a 100644 --- a/components/header-search-button.tsx +++ b/components/header-search-button.tsx @@ -9,7 +9,7 @@ import { useActions, useUIState } from 'ai/rsc' import { AI } from '@/app/actions' import { nanoid } from 'nanoid' import { UserMessage } from './user-message' -import { toast } from 'sonner' +import { toast } from 'react-toastify' import { useSettingsStore } from '@/lib/store/settings' import { useMapData } from './map/map-data-context' @@ -22,35 +22,17 @@ export function HeaderSearchButton() { const { map } = useMap() const { mapProvider } = useSettingsStore() const { mapData } = useMapData() + // Cast the actions to our defined interface to avoid build errors const actions = useActions() as unknown as HeaderActions const [, setMessages] = useUIState() const [isAnalyzing, setIsAnalyzing] = useState(false) - - // Use state for portals to trigger re-renders when they are found const [desktopPortal, setDesktopPortal] = useState(null) const [mobilePortal, setMobilePortal] = useState(null) useEffect(() => { - // Function to find and set portals - const findPortals = () => { - setDesktopPortal(document.getElementById('header-search-portal')) - setMobilePortal(document.getElementById('mobile-header-search-portal')) - } - - // Initial check - findPortals() - - // Use a MutationObserver to detect when portals are added to the DOM - const observer = new MutationObserver(() => { - findPortals() - }) - - observer.observe(document.body, { - childList: true, - subtree: true - }) - - return () => observer.disconnect() + // Portals can only be used on the client-side after the DOM has mounted + setDesktopPortal(document.getElementById('header-search-portal')) + setMobilePortal(document.getElementById('mobile-header-search-portal')) }, []) const handleResolutionSearch = async () => { @@ -58,10 +40,6 @@ export function HeaderSearchButton() { toast.error('Map is not available yet. Please wait for it to load.') return } - if (mapProvider === 'google' && !mapData.cameraState) { - toast.error('Google Maps state is not available. Try moving the map first.') - return - } if (!actions) { toast.error('Search actions are not available.') return @@ -124,14 +102,12 @@ export function HeaderSearchButton() { } } - const isMapAvailable = mapProvider === 'mapbox' ? !!map : !!mapData.cameraState - const desktopButton = ( diff --git a/components/map/map-query-handler.tsx b/components/map/map-query-handler.tsx index f6567bf4..b85f1125 100644 --- a/components/map/map-query-handler.tsx +++ b/components/map/map-query-handler.tsx @@ -3,7 +3,26 @@ import { useEffect } from 'react'; import { useMapData } from './map-data-context'; import { useMapToggle, MapToggleEnum } from '../map-toggle-context'; -import { ToolOutput } from '@/lib/types/tools'; + +// Define the expected structure of the mcp_response from geospatialTool +interface McpResponseData { + location: { + latitude?: number; + longitude?: number; + place_name?: string; + address?: string; + }; + mapUrl?: string; +} + +interface ToolOutput { + type: string; + originalUserInput?: string; + timestamp: string; + mcp_response?: McpResponseData | null; + features?: any[]; + error?: string | null; +} interface MapQueryHandlerProps { toolOutput?: ToolOutput | null; @@ -14,12 +33,7 @@ export const MapQueryHandler: React.FC = ({ toolOutput }) const { setMapType } = useMapToggle(); useEffect(() => { - if (!toolOutput) { - if (process.env.NODE_ENV === 'development') { - console.warn('MapQueryHandler: missing toolOutput'); - } - return; - } + if (!toolOutput) return; if (toolOutput.type === 'DRAWING_TRIGGER' && toolOutput.features) { console.log('MapQueryHandler: Received drawing data.', toolOutput.features); @@ -28,25 +42,19 @@ export const MapQueryHandler: React.FC = ({ toolOutput }) ...prevData, pendingFeatures: toolOutput.features })); - } else if (toolOutput.type === 'MAP_QUERY_TRIGGER') { - if (toolOutput.mcp_response && toolOutput.mcp_response.location) { - const { latitude, longitude, place_name } = toolOutput.mcp_response.location; - - if (typeof latitude === 'number' && typeof longitude === 'number') { - console.log(`MapQueryHandler: Received data from geospatialTool. Place: ${place_name}, Lat: ${latitude}, Lng: ${longitude}`); - setMapData(prevData => ({ - ...prevData, - targetPosition: { lat: latitude, lng: longitude }, - mapFeature: { - place_name, - mapUrl: toolOutput.mcp_response?.mapUrl - } - })); - } else { - console.warn('MapQueryHandler: invalid MAP_QUERY_TRIGGER payload', { toolOutput, mcp_response: toolOutput.mcp_response }); - } - } else { - console.warn('MapQueryHandler: invalid MAP_QUERY_TRIGGER payload', { toolOutput, mcp_response: toolOutput?.mcp_response }); + } else if (toolOutput.type === 'MAP_QUERY_TRIGGER' && toolOutput.mcp_response && toolOutput.mcp_response.location) { + const { latitude, longitude, place_name } = toolOutput.mcp_response.location; + + if (typeof latitude === 'number' && typeof longitude === 'number') { + console.log(`MapQueryHandler: Received data from geospatialTool. Place: ${place_name}, Lat: ${latitude}, Lng: ${longitude}`); + setMapData(prevData => ({ + ...prevData, + targetPosition: { lat: latitude, lng: longitude }, + mapFeature: { + place_name, + mapUrl: toolOutput.mcp_response?.mapUrl + } + })); } } }, [toolOutput, setMapData, setMapType]); diff --git a/components/mobile-icons-bar.tsx b/components/mobile-icons-bar.tsx index cd66b5af..d0db2cfa 100644 --- a/components/mobile-icons-bar.tsx +++ b/components/mobile-icons-bar.tsx @@ -45,10 +45,9 @@ export const MobileIconsBar: React.FC = ({ onAttachmentClic - - {/* Portal target for resolution search button on mobile */} -
- +