diff --git a/packages/react-components/src/components/dial/dial.tsx b/packages/react-components/src/components/dial/dial.tsx index 0a51085ab..620710a03 100644 --- a/packages/react-components/src/components/dial/dial.tsx +++ b/packages/react-components/src/components/dial/dial.tsx @@ -22,7 +22,7 @@ export const Dial = ({ }) => { const { dataStreams } = useTimeSeriesData({ viewport: passedInViewport, - query, + queries: [query], settings: { fetchMostRecentBeforeEnd: true }, styles, }); diff --git a/packages/react-components/src/components/kpi/kpi.tsx b/packages/react-components/src/components/kpi/kpi.tsx index 487e490bd..b51279853 100644 --- a/packages/react-components/src/components/kpi/kpi.tsx +++ b/packages/react-components/src/components/kpi/kpi.tsx @@ -22,7 +22,7 @@ export const Kpi = ({ }) => { const { dataStreams } = useTimeSeriesData({ viewport: passedInViewport, - query, + queries: [query], settings: { fetchMostRecentBeforeEnd: true }, styles, }); diff --git a/packages/react-components/src/components/status/status.tsx b/packages/react-components/src/components/status/status.tsx index c8dac6aad..32b6c16b5 100644 --- a/packages/react-components/src/components/status/status.tsx +++ b/packages/react-components/src/components/status/status.tsx @@ -22,7 +22,7 @@ export const Status = ({ }) => { const { dataStreams } = useTimeSeriesData({ viewport: passedInViewport, - query, + queries: [query], settings: { fetchMostRecentBeforeEnd: true }, styles, }); diff --git a/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.spec.ts b/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.spec.ts index 8f2f16cb8..dcfe40e2a 100644 --- a/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.spec.ts +++ b/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.spec.ts @@ -1,14 +1,15 @@ import { renderHook } from '@testing-library/react-hooks'; -import { useTimeSeriesData } from './useTimeSeriesData'; - import { DataStream, TimeQuery, TimeSeriesData, TimeSeriesDataRequest, Viewport } from '@iot-app-kit/core'; +import { useTimeSeriesData } from './useTimeSeriesData'; const noop = () => {}; + const queryCreator = ( timeSeriesData: TimeSeriesData[], overrides?: { updateViewport?: (viewport: Viewport) => void; unsubscribe?: () => void } ): TimeQuery => { const { updateViewport = noop, unsubscribe = noop } = overrides || {}; + return { build: () => ({ subscribe: ({ next }) => { @@ -21,12 +22,12 @@ const queryCreator = ( }; it('returns no time series data when query returns no time series data', () => { - const query = queryCreator([]); + const queries = [queryCreator([])]; const { result: { current: timeSeriesData }, } = renderHook(() => useTimeSeriesData({ - query, + queries, viewport: { duration: '5m' }, }) ); @@ -36,14 +37,14 @@ it('returns no time series data when query returns no time series data', () => { it('provides time series data returned from query', () => { const QUERY_RESPONSE: TimeSeriesData[] = [{ dataStreams: [], viewport: { duration: '5m' }, annotations: { y: [] } }]; - const query = queryCreator(QUERY_RESPONSE); + const queries = [queryCreator(QUERY_RESPONSE)]; const viewport = { duration: '5m' }; const { result: { current }, } = renderHook(() => useTimeSeriesData({ - query, + queries, viewport, }) ); @@ -58,14 +59,14 @@ it('binds style settings color to the data stream color', () => { viewport: { duration: '5m' }, annotations: {}, }; - const query = queryCreator([TIME_SERIES_DATA]); + const queries = [queryCreator([TIME_SERIES_DATA])]; const color = 'red'; const { result: { current: timeSeriesData }, } = renderHook(() => useTimeSeriesData({ - query, + queries, viewport: { duration: '5m' }, styles: { red: { color } }, }) @@ -82,14 +83,14 @@ it('combines multiple time series data results into a single time series data', { dataStreams: [DATA_STREAM_1], viewport: { duration: '5m' }, annotations: { y: [] } }, { dataStreams: [DATA_STREAM_2], viewport: { duration: '5m' }, annotations: { y: [] } }, ]; - const query = queryCreator(QUERY_RESPONSE); + const queries = [queryCreator(QUERY_RESPONSE)]; const viewport = { duration: '5m' }; const { result: { current: timeSeriesData }, } = renderHook(() => useTimeSeriesData({ - query, + queries, viewport, }) ); @@ -99,6 +100,33 @@ it('combines multiple time series data results into a single time series data', }); }); +it('returns data streams from multiple queries', () => { + const DATA_STREAM_1: DataStream = { id: 'abc-1', data: [], resolution: 0, name: 'my-name' }; + const DATA_STREAM_2: DataStream = { id: 'abc-2', data: [], resolution: 0, name: 'my-name-2' }; + + const QUERY_RESPONSE_1: TimeSeriesData[] = [ + { dataStreams: [DATA_STREAM_1], viewport: { duration: '5m' }, annotations: { y: [] } }, + ]; + const QUERY_RESPONSE_2: TimeSeriesData[] = [ + { dataStreams: [DATA_STREAM_2], viewport: { duration: '5m' }, annotations: { y: [] } }, + ]; + + const queries = [queryCreator(QUERY_RESPONSE_1), queryCreator(QUERY_RESPONSE_2)]; + + const { + result: { + current: { dataStreams }, + }, + } = renderHook(() => + useTimeSeriesData({ + queries, + viewport: { duration: '5m' }, + }) + ); + + expect(dataStreams).toEqual([DATA_STREAM_1, DATA_STREAM_2]); +}); + it('providers updated viewport to query', () => { let viewport = { duration: '5m' }; const updateViewport = jest.fn(); @@ -109,12 +137,12 @@ it('providers updated viewport to query', () => { annotations: {}, }; - const query = queryCreator([TIME_SERIES_DATA], { updateViewport }); + const queries = [queryCreator([TIME_SERIES_DATA], { updateViewport })]; const color = 'red'; const { rerender } = renderHook(() => useTimeSeriesData({ - query, + queries, viewport, styles: { red: { color } }, }) @@ -135,7 +163,7 @@ it.skip('does not attempt to re-create the subscription when provided a new refe result: { current: timeSeriesData }, } = renderHook(() => useTimeSeriesData({ - query: queryCreator([]), + queries: [queryCreator([])], viewport: { duration: '5m' }, }) ); diff --git a/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.ts b/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.ts index 3c3b12ce9..76d6c3190 100644 --- a/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.ts +++ b/packages/react-components/src/hooks/useTimeSeriesData/useTimeSeriesData.ts @@ -7,12 +7,13 @@ import { TimeSeriesDataRequestSettings, ProviderWithViewport, StyleSettingsMap, + combineProviders, } from '@iot-app-kit/core'; import { v4 as uuid } from 'uuid'; import { bindStylesToDataStreams } from '../utils/bindStylesToDataStreams'; import { combineTimeSeriesData } from '../utils/combineTimeSeriesData'; -import { useViewport } from '../useViewport/useViewport'; +import { useViewport } from '../useViewport'; const DEFAULT_SETTINGS: TimeSeriesDataRequestSettings = { resolution: '0', @@ -22,12 +23,12 @@ const DEFAULT_SETTINGS: TimeSeriesDataRequestSettings = { const DEFAULT_VIEWPORT = { duration: '10m' }; export const useTimeSeriesData = ({ - query, + queries, viewport: passedInViewport, settings = DEFAULT_SETTINGS, styles, }: { - query: TimeQuery; + queries: TimeQuery[]; viewport?: Viewport; settings?: TimeSeriesDataRequestSettings; styles?: StyleSettingsMap; @@ -42,10 +43,14 @@ export const useTimeSeriesData = ({ useEffect(() => { const id = uuid(); - provider.current = query.build(id, { - viewport, - settings, - }); + provider.current = combineProviders( + queries.map((query) => + query.build(id, { + viewport, + settings, + }) + ) + ); provider.current.subscribe({ next: (timeSeriesDataCollection: TimeSeriesData[]) => { @@ -72,7 +77,7 @@ export const useTimeSeriesData = ({ prevViewport.current = undefined; }); }; - }, [query]); + }, [queries]); useEffect(() => { if (prevViewport.current != null) {