diff --git a/src/api/dashboard.ts b/src/api/dashboard.ts index f6f840b2..f2761ba7 100644 --- a/src/api/dashboard.ts +++ b/src/api/dashboard.ts @@ -28,7 +28,7 @@ export const putDashboard = (dashboardId: string, dashboard: UpdateDashboardType }; export const postDashboard = (dashboard: CreateDashboardType | ImportDashboardType) => { - return Axios().post(CREATE_DASHBOARDS_URL, { ...dashboard}); + return Axios().post(CREATE_DASHBOARDS_URL, { ...dashboard }); }; export const removeDashboard = (dashboardId: string) => { diff --git a/src/hooks/useDashboards.tsx b/src/hooks/useDashboards.tsx index d24bda84..3b6a5426 100644 --- a/src/hooks/useDashboards.tsx +++ b/src/hooks/useDashboards.tsx @@ -4,12 +4,10 @@ import { AxiosError, isAxiosError } from 'axios'; import _ from 'lodash'; import { useDashboardsStore, dashboardsStoreReducers } from '@/pages/Dashboards/providers/DashboardsProvider'; import { getDashboards, getQueryData, postDashboard, putDashboard, removeDashboard } from '@/api/dashboard'; -import { useCallback, useState } from 'react'; import { CreateDashboardType, Dashboard, ImportDashboardType, - TileQuery, TileQueryResponse, UpdateDashboardType, } from '@/@types/parseable/api/dashboards'; @@ -145,34 +143,48 @@ export const useDashboardsQuery = (opts: { updateTimeRange?: (dashboard: Dashboa }; }; -export const useTileQuery = (opts?: { tileId?: string; onSuccess?: (data: TileQueryResponse) => void }) => { +export const useTileQuery = (opts: { + tileId?: string; + query: string; + startTime: Date; + endTime: Date; + onSuccess?: (data: TileQueryResponse) => void; + enabled?: boolean; +}) => { const [, setDashboardsStore] = useDashboardsStore((_store) => null); - const { onSuccess } = opts || {}; - const [fetchState, setFetchState] = useState<{ - isLoading: boolean; - isError: null | boolean; - isSuccess: null | boolean; - }>({ isLoading: false, isError: null, isSuccess: null }); - - const fetchTileData = useCallback( - async (queryOpts: TileQuery) => { - try { - setFetchState({ isLoading: true, isError: null, isSuccess: null }); - const res = await getQueryData(queryOpts); + const { query, startTime, endTime, tileId, enabled = true } = opts; + const { isLoading, isFetching, isError, refetch } = useQuery( + [tileId, query, startTime, endTime], + () => + getQueryData({ + query, + startTime, + endTime, + }), + { + onSuccess: (res) => { const tileData = _.isEmpty(res) ? { records: [], fields: [] } : res.data; - opts?.tileId && setDashboardsStore((store) => setTileData(store, opts.tileId || '', tileData)); - opts?.onSuccess && opts.onSuccess(tileData); - setFetchState({ isLoading: false, isError: false, isSuccess: true }); - } catch (e: any) { - setFetchState({ isLoading: false, isError: true, isSuccess: false }); - notifyError({ message: _.isString(e.response.data) ? e.response.data : 'Unable to fetch tile data' }); - } + if (tileId) { + setDashboardsStore((store) => setTileData(store, tileId, tileData)); + } + }, + onError: (error: AxiosError) => { + if (isAxiosError(error) && error.response) { + notifyError({ + message: _.isString(error.response.data) ? error.response.data : 'Unable to fetch tile data', + }); + } + }, + refetchOnWindowFocus: false, + enabled, }, - [onSuccess], ); + const isLoadingState = isLoading || isFetching; + return { - ...fetchState, - fetchTileData, + isLoading: isLoadingState, + isError, + refetch, }; }; diff --git a/src/pages/Dashboards/CreateTileForm.tsx b/src/pages/Dashboards/CreateTileForm.tsx index f834543d..a77b3ea0 100644 --- a/src/pages/Dashboards/CreateTileForm.tsx +++ b/src/pages/Dashboards/CreateTileForm.tsx @@ -326,7 +326,13 @@ const Query = (props: { form: TileFormType; onChangeValue: (key: string, value: props.form.validate(); }, []); - const { fetchTileData, isLoading } = useTileQuery({ onSuccess: onFetchTileSuccess }); + const { refetch, isLoading } = useTileQuery({ + onSuccess: onFetchTileSuccess, + query: '', // Initial query (will be updated in refetch) + startTime: timeRange.startTime, + endTime: timeRange.endTime, + enabled: false, + }); const validateQuery = useCallback(() => { if (_.isEmpty(dashboardId)) return; @@ -337,7 +343,9 @@ const Query = (props: { form: TileFormType; onChangeValue: (key: string, value: const santizedQuery = sanitiseSqlString(query, true, 100); onChangeValue('query', santizedQuery); const { from, to } = selectedDashboard.time_filter || { from: timeRange.startTime, to: timeRange.endTime }; - fetchTileData({ query: santizedQuery, startTime: dayjs(from).toDate(), endTime: dayjs(to).toDate() }); + refetch({ + queryKey: [santizedQuery, dayjs(from).toDate(), dayjs(to).toDate()], + }); }, [query, dashboardId, dashboards, timeRange]); const onStreamSelect = useCallback((val: string | null) => { diff --git a/src/pages/Dashboards/Tile.tsx b/src/pages/Dashboards/Tile.tsx index 2b3f6953..6c4fd90f 100644 --- a/src/pages/Dashboards/Tile.tsx +++ b/src/pages/Dashboards/Tile.tsx @@ -23,7 +23,7 @@ import handleCapture, { makeExportClassName } from '@/utils/exportImage'; import { useDashboardsStore, dashboardsStoreReducers } from './providers/DashboardsProvider'; import _ from 'lodash'; import { useTileQuery } from '@/hooks/useDashboards'; -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { Tile as TileType, TileQueryResponse } from '@/@types/parseable/api/dashboards'; import { sanitiseSqlString } from '@/utils/sanitiseSqlString'; import Table from './Table'; @@ -115,13 +115,23 @@ const Graph = (props: { tile: TileType; data: TileQueryResponse }) => { const y_keys = _.get(graph_config, 'y_keys', []); const xUnit = getUnitTypeByKey(x_key, tick_config); const yUnit = getUnitTypeByKey(_.head(y_keys) || '', tick_config); - const orientation = _.get(graph_config, 'orientation', 'horizontal'); - const graphBasicType = _.get(graph_config, 'graph_type', 'default') - const color_config = _.get(props.tile.visualization, 'color_config', []) + const orientation = _.get(graph_config, 'orientation', 'horizontal'); + const graphBasicType = _.get(graph_config, 'graph_type', 'default'); + const color_config = _.get(props.tile.visualization, 'color_config', []); return ( - {renderGraph({ queryResponse: data, x_key, y_keys, chart: visualization_type, yUnit, xUnit, orientation, graphBasicType, color_config })} + {renderGraph({ + queryResponse: data, + x_key, + y_keys, + chart: visualization_type, + yUnit, + xUnit, + orientation, + graphBasicType, + color_config, + })} ); }; @@ -247,23 +257,24 @@ function TileControls(props: { tile: TileType; data: TileQueryResponse }) { } const Tile = (props: { id: string }) => { - // const [showJson, setShowJson] = useState(false); const [timeRange] = useLogsStore((store) => store.timeRange); - const [activeDashboard] = useDashboardsStore((store) => store.activeDashboard); const [tilesData] = useDashboardsStore((store) => store.tilesData); const tileData = _.get(tilesData, props.id, { records: [], fields: [] }); + const [activeDashboard] = useDashboardsStore((store) => store.activeDashboard); const tile = _.chain(activeDashboard) .get('tiles', []) .find((tile) => tile.tile_id === props.id) .value(); - const { fetchTileData, isLoading } = useTileQuery({ tileId: props.id }); + const shouldNotify = false; + const santizedQuery = sanitiseSqlString(tile.query, shouldNotify, 100); - useEffect(() => { - const shouldNotify = false; - const santizedQuery = sanitiseSqlString(tile.query, shouldNotify, 100); - fetchTileData({ query: santizedQuery, startTime: timeRange.startTime, endTime: timeRange.endTime }); - }, [timeRange.startTime, timeRange.endTime]); + const { isLoading } = useTileQuery({ + tileId: props.id, + query: santizedQuery, + startTime: timeRange.startTime, + endTime: timeRange.endTime, + }); // const toggleJsonView = useCallback(() => { // return setShowJson((prev) => !prev);