fix(database-view): send tableId to bridge and correct SSE path
useViewData omitted the tableId query param required by the bridge GET /views/:id/data route -> 400 'tableId query param required' and a blank 'Could not load view'. The SSE consumer hit /api/v1/events/sse but the bridge mounts the stream at /api/events -> 404 reconnect loop. Thread tableId through ViewDataParams and all five callers; point the SSE URL at /api/events. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a23f836358
commit
fe75ea5c45
8 changed files with 18 additions and 4 deletions
|
|
@ -6,7 +6,7 @@ import { resolveBridgeUrl } from "../services/bridge-client";
|
||||||
/**
|
/**
|
||||||
* SSE consumer for realtime row/view updates from the bridge.
|
* SSE consumer for realtime row/view updates from the bridge.
|
||||||
*
|
*
|
||||||
* Connects to `GET /api/v1/events/sse?tables=<tableId>&views=<viewId>` and
|
* Connects to `GET /api/events/sse?tables=<tableId>&views=<viewId>` and
|
||||||
* listens for events whose type starts with `row.` or `view.`. On match, it
|
* listens for events whose type starts with `row.` or `view.`. On match, it
|
||||||
* invalidates the React Query cache for the affected view so the table
|
* invalidates the React Query cache for the affected view so the table
|
||||||
* re-fetches silently.
|
* re-fetches silently.
|
||||||
|
|
@ -46,7 +46,10 @@ export function useDatabaseRealtimeUpdates(
|
||||||
if (!tableId || !viewId) return;
|
if (!tableId || !viewId) return;
|
||||||
|
|
||||||
const url = resolveBridgeUrl(bridgeUrl);
|
const url = resolveBridgeUrl(bridgeUrl);
|
||||||
const sseUrl = `${url}/api/v1/events/sse?tables=${encodeURIComponent(tableId)}&views=${encodeURIComponent(viewId)}`;
|
// The bridge mounts the SSE router at /api/events (NOT under /api/v1) on
|
||||||
|
// purpose, to keep it out of the v1 mutation rate-limiter. See bridge
|
||||||
|
// src/index.ts: app.route('/api', eventsRouter) + eventsRoutes '/events'.
|
||||||
|
const sseUrl = `${url}/api/events/sse?tables=${encodeURIComponent(tableId)}&views=${encodeURIComponent(viewId)}`;
|
||||||
|
|
||||||
let retryTimeout: ReturnType<typeof setTimeout> | null = null;
|
let retryTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export interface UseViewDataResult {
|
||||||
*/
|
*/
|
||||||
export function useViewData({
|
export function useViewData({
|
||||||
viewId,
|
viewId,
|
||||||
|
tableId,
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page = 1,
|
page = 1,
|
||||||
size = 50,
|
size = 50,
|
||||||
|
|
@ -42,11 +43,13 @@ export function useViewData({
|
||||||
|
|
||||||
return useQuery<UseViewDataResult>({
|
return useQuery<UseViewDataResult>({
|
||||||
queryKey: viewDataQueryKey(viewId, page, size, url),
|
queryKey: viewDataQueryKey(viewId, page, size, url),
|
||||||
enabled: Boolean(viewId),
|
enabled: Boolean(viewId) && Boolean(tableId),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const client = getBridgeClient(url);
|
const client = getBridgeClient(url);
|
||||||
|
// tableId is mandatory: the bridge route GET /views/:viewId/data returns
|
||||||
|
// 400 "tableId query param required" without it.
|
||||||
const res = await (client.get(`/api/v1/views/${viewId}/data`, {
|
const res = await (client.get(`/api/v1/views/${viewId}/data`, {
|
||||||
params: { page, size },
|
params: { page, size, tableId },
|
||||||
}) as unknown as Promise<BridgeViewDataResponse>);
|
}) as unknown as Promise<BridgeViewDataResponse>);
|
||||||
|
|
||||||
// Normalise: bridge may return top-level array or wrapped envelope.
|
// Normalise: bridge may return top-level array or wrapped envelope.
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ export function CalendarRenderer({ tableId, viewId, bridgeUrl }: CalendarRendere
|
||||||
|
|
||||||
const { data, isLoading, isError, error, refetch } = useViewData({
|
const { data, isLoading, isError, error, refetch } = useViewData({
|
||||||
viewId,
|
viewId,
|
||||||
|
tableId,
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: PAGE_SIZE,
|
size: PAGE_SIZE,
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,7 @@ export function KanbanRenderer({ tableId, viewId, bridgeUrl }: KanbanRendererPro
|
||||||
|
|
||||||
const { data, isLoading, isError, error, refetch } = useViewData({
|
const { data, isLoading, isError, error, refetch } = useViewData({
|
||||||
viewId,
|
viewId,
|
||||||
|
tableId,
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: PAGE_SIZE,
|
size: PAGE_SIZE,
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ export function TableRenderer({ tableId, viewId, bridgeUrl }: TableRendererProps
|
||||||
|
|
||||||
const { data, isLoading, isError, error, refetch } = useViewData({
|
const { data, isLoading, isError, error, refetch } = useViewData({
|
||||||
viewId,
|
viewId,
|
||||||
|
tableId,
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page,
|
page,
|
||||||
size: PAGE_SIZE,
|
size: PAGE_SIZE,
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ export function TimelineRenderer({ tableId, viewId, bridgeUrl }: TimelineRendere
|
||||||
|
|
||||||
const { data, isLoading: dataLoading, isError: dataError, error, refetch } = useViewData({
|
const { data, isLoading: dataLoading, isError: dataError, error, refetch } = useViewData({
|
||||||
viewId,
|
viewId,
|
||||||
|
tableId,
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: PAGE_SIZE,
|
size: PAGE_SIZE,
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ export function InsertDatabaseModal({
|
||||||
isError: fieldsError,
|
isError: fieldsError,
|
||||||
} = useViewData({
|
} = useViewData({
|
||||||
viewId: selectedView?.id ?? "",
|
viewId: selectedView?.id ?? "",
|
||||||
|
tableId: selectedTable?.id ?? "",
|
||||||
bridgeUrl,
|
bridgeUrl,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 1,
|
size: 1,
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,9 @@ export interface BridgeViewDataResponse {
|
||||||
/** Paginated fetch params for the view-data hook. */
|
/** Paginated fetch params for the view-data hook. */
|
||||||
export interface ViewDataParams {
|
export interface ViewDataParams {
|
||||||
viewId: string;
|
viewId: string;
|
||||||
|
// Required by the bridge: GET /views/:viewId/data needs tableId to build
|
||||||
|
// Row instances (Baserow does not echo the tableId in listRows responses).
|
||||||
|
tableId: string;
|
||||||
bridgeUrl?: string | null;
|
bridgeUrl?: string | null;
|
||||||
page?: number;
|
page?: number;
|
||||||
size?: number;
|
size?: number;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue