Maintenance Love :)

This commit is contained in:
lovebird 2026-03-26 00:44:56 +01:00
parent 18ee395568
commit 4fc41f2eeb
6 changed files with 75 additions and 12 deletions

View File

@ -198,3 +198,60 @@ export const fetchGridSearchExport = async (jobId: string, format: 'md' | 'json'
if (!res.ok) throw new Error(`Failed to load report: ${res.statusText}`);
return await res.text();
};
// --- Places GridSearch API Methods (New C++ backend) ---
export const fetchPlacesGridSearches = async (): Promise<GridSearchSummary[]> => {
const headers = await getAuthHeaders();
const res = await fetch(`${serverUrl}/api/places/gridsearch`, { headers });
if (!res.ok) throw new Error(`Failed to fetch places grid searches: ${res.statusText}`);
const json = await res.json();
return json.data || [];
};
export const fetchPlacesGridSearchById = async (id: string): Promise<any> => {
const cacheKey = `places-gridsearch-id-${id}`;
return fetchWithDeduplication(cacheKey, async () => {
const headers = await getAuthHeaders();
const res = await fetch(`${serverUrl}/api/places/gridsearch/${id}`, { headers });
if (!res.ok) throw new Error(`Failed to fetch places grid search result: ${res.statusText}`);
const json = await res.json();
return json.data;
}, 60000 * 5);
};
export const fetchPlacesGridSearchRunState = async (id: string): Promise<RestoredRunState> => {
const headers = await getAuthHeaders();
const res = await fetch(`${serverUrl}/api/places/gridsearch/${id}/state`, { headers });
if (!res.ok) throw new Error(`Failed to fetch run state: ${res.statusText}`);
const json = await res.json();
return json.data;
};
export const submitPlacesGridSearchJob = async (payload: GridSearchJobPayload): Promise<{ message: string; jobId: string }> => {
const headers = await getAuthHeaders();
const res = await fetch(`${serverUrl}/api/places/gridsearch`, {
method: 'POST',
headers,
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(`Failed to submit places grid search job: ${res.statusText}`);
return await res.json();
};
export const deletePlacesGridSearch = async (id: string): Promise<boolean> => {
// We will just call the old locations route for deletion to keep it simple,
// since both manipulate the exact same Postgres table (grid_search_runs).
return deleteGridSearch(id);
};
export const getPlacesGridSearchStreamUrl = (jobId: string, token?: string): string => {
// If not implemented in places, fallback to locations or just use the same URL format
const url = `${serverUrl}/api/places/gridsearch/${jobId}/stream`;
return token ? `${url}?token=${token}` : url;
};
export const fetchPlacesGridSearchExport = async (jobId: string, format: 'md' | 'json' = 'md'): Promise<string> => {
// If not implemented in places, fallback to locations export since they share the database
return fetchGridSearchExport(jobId, format);
};

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { Loader2, AlertCircle, Download } from 'lucide-react';
import MarkdownRenderer from '@/components/MarkdownRenderer';
import { fetchGridSearchExport } from '../client-gridsearch';
import { fetchPlacesGridSearchExport } from '../client-gridsearch';
export function CompetitorsReportView({ jobId }: { jobId: string }) {
const [markdown, setMarkdown] = useState<string | null>(null);
@ -17,7 +17,7 @@ export function CompetitorsReportView({ jobId }: { jobId: string }) {
setLoading(true);
setError(null);
const text = await fetchGridSearchExport(jobId, 'md');
const text = await fetchPlacesGridSearchExport(jobId, 'md');
if (active) {
setMarkdown(text);

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import { Loader2, Search, MapPin, CheckCircle, ChevronRight, ChevronLeft } from 'lucide-react';
import { previewGridSearch, submitGridSearchJob, addActiveGridSearchJob } from '../client-gridsearch';
import { previewGridSearch, submitPlacesGridSearchJob, addActiveGridSearchJob } from '../client-gridsearch';
import { searchGadmRegions } from '../client-searches';
import { CompetitorsGridView } from '../CompetitorsGridView';
@ -96,7 +96,7 @@ export function GridSearchWizard({ onJobSubmitted }: { onJobSubmitted: (jobId: s
setSubmitting(true);
setError('');
try {
const res = await submitGridSearchJob({
const res = await submitPlacesGridSearchJob({
region: selectedRegionName,
types: [searchQuery],
level,

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Loader2, AlertCircle, Plus, Lock, MapPin } from 'lucide-react';
import { fetchGridSearchById } from '../client-gridsearch';
import { fetchPlacesGridSearchById } from '../client-gridsearch';
import { GridSearchResults } from './GridSearchResults';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { useRestoredSearch } from './RestoredSearchContext';
@ -28,7 +28,7 @@ export function JobViewer({ jobId }: { jobId: string }) {
try {
setLoading(true);
setError(null);
const data = await fetchGridSearchById(jobId);
const data = await fetchPlacesGridSearchById(jobId);
console.log(`job results`, data);
if (!active) return;
@ -92,6 +92,12 @@ export function JobViewer({ jobId }: { jobId: string }) {
const allResults = jobData?.result?.searchResult?.results || competitors;
const foundTypes = Array.from(new Set(allResults.flatMap((r: any) => r.types || []).filter(Boolean))).sort() as string[];
console.log(`foundTypes`, foundTypes);
console.log(`allResults`, allResults);
console.log(`jobData`, jobData);
console.log('guidedAreas', guidedAreas);
console.log('searchSettings', searchSettings);
console.log('searchQuery', searchQuery);
return (
<div className="flex flex-col p-6 flex-1 w-full box-border overflow-hidden min-h-0">

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { getActiveGridSearchJobs, removeActiveGridSearchJob, getGridSearchStreamUrl, fetchGridSearches, deleteGridSearch, GridSearchSummary } from '../client-gridsearch';
import { getActiveGridSearchJobs, removeActiveGridSearchJob, getPlacesGridSearchStreamUrl, fetchPlacesGridSearches, deletePlacesGridSearch, GridSearchSummary } from '../client-gridsearch';
import { supabase } from '@/integrations/supabase/client';
import { Loader2, XCircle, CheckCircle, Search, ChevronRight, Trash2 } from 'lucide-react';
@ -19,7 +19,7 @@ const ActiveJobItem = ({ jobId, onSelectJob }: { jobId: string, onSelectJob?: (j
if (!isSubscribed) return;
const url = getGridSearchStreamUrl(jobId, token);
const url = getPlacesGridSearchStreamUrl(jobId, token);
es = new EventSource(url);
es.addEventListener('progress', (e) => {
@ -117,7 +117,7 @@ export const OngoingSearches = ({ onSelectJob, selectedJobId, onSearchDeleted }:
const loadPast = async () => {
try {
const history = await fetchGridSearches();
const history = await fetchPlacesGridSearches();
setPastSearches(history);
} catch (err) {
console.error('Failed to load past searches', err);
@ -190,7 +190,7 @@ export const OngoingSearches = ({ onSelectJob, selectedJobId, onSearchDeleted }:
e.stopPropagation();
if (confirm('Are you sure you want to delete this search?')) {
try {
await deleteGridSearch(search.id);
await deletePlacesGridSearch(search.id);
setPastSearches(prev => prev.filter(s => s.id !== search.id));
if (onSearchDeleted) onSearchDeleted(search.id);
} catch (err) {

View File

@ -1,5 +1,5 @@
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { fetchGridSearchRunState, RestoredRunState } from '../client-gridsearch';
import { fetchPlacesGridSearchRunState, RestoredRunState } from '../client-gridsearch';
interface RestoredSearchContextValue {
/** The loaded run state, null until fetched */
@ -42,7 +42,7 @@ export function RestoredSearchProvider({
setLoading(true);
setError(null);
try {
const data = await fetchGridSearchRunState(id);
const data = await fetchPlacesGridSearchRunState(id);
setState(data);
} catch (err: any) {
setError(err.message || 'Failed to load run state');