diff --git a/src/RelativeRangeRequestCache/RelativeRangeCache.test.ts b/src/RelativeRangeRequestCache/RelativeRangeCache.test.ts index d83761fd..fe53404d 100644 --- a/src/RelativeRangeRequestCache/RelativeRangeCache.test.ts +++ b/src/RelativeRangeRequestCache/RelativeRangeCache.test.ts @@ -36,7 +36,50 @@ describe('RelativeRangeCache', () => { startTime: 1716858000000, }; + const requestDisabledCache = { + ...request, + targets: [ + { + ...request.targets[0], + clientCache: false, + }, + ], + }; + describe('get()', () => { + it('returns undefined when any query with client cache disabled', () => { + const cachedQueryInfo = [ + { + query: { + queryType: QueryType.PropertyValueHistory, + refId: 'A', + }, + dataFrame: { + name: 'Demo Turbine Asset 1', + refId: 'A', + fields: [ + { + name: 'time', + type: FieldType.time, + config: {}, + values: [], + }, + ], + length: 0 + }, + }, + ]; + const cacheData = { + [generateSiteWiseRequestCacheId(requestDisabledCache)]: { + queries: cachedQueryInfo, + range, + }, + }; + const cache = new RelativeRangeCache(new Map(Object.entries(cacheData))); + + expect(cache.get(requestDisabledCache)).toBeUndefined(); + }); + it('returns undefined when there is no cached response', () => { const cache = new RelativeRangeCache(); @@ -462,21 +505,34 @@ describe('RelativeRangeCache', () => { }, ]; - const cacheData = { - [generateSiteWiseRequestCacheId(request)]: { - queries: cachedQueryInfo, - range, - }, - }; - const expectedCacheMap = new Map(Object.entries(cacheData)) - - const cacheMap = new Map(); - const cache = new RelativeRangeCache(cacheMap); - - cache.set(request, { - data: expectedDataFrames + it('does nothing when any query with client cache disabled', () => { + const cacheMap = new Map(); + const cache = new RelativeRangeCache(cacheMap); + + cache.set(requestDisabledCache, { + data: expectedDataFrames, + }); + + expect(cacheMap.size).toBe(0); }); - expect(cacheMap).toEqual(expectedCacheMap); + it('set request/response pair', () => { + const cacheData = { + [generateSiteWiseRequestCacheId(request)]: { + queries: cachedQueryInfo, + range, + }, + }; + const expectedCacheMap = new Map(Object.entries(cacheData)); + + const cacheMap = new Map(); + const cache = new RelativeRangeCache(cacheMap); + + cache.set(request, { + data: expectedDataFrames, + }); + + expect(cacheMap).toEqual(expectedCacheMap); + }); }); }); diff --git a/src/RelativeRangeRequestCache/RelativeRangeCache.ts b/src/RelativeRangeRequestCache/RelativeRangeCache.ts index ed9b00a8..2bfdae90 100644 --- a/src/RelativeRangeRequestCache/RelativeRangeCache.ts +++ b/src/RelativeRangeRequestCache/RelativeRangeCache.ts @@ -47,6 +47,10 @@ export class RelativeRangeCache { range, } = request; + if (!RelativeRangeCache.isClientCacheEnabled(targets)) { + return; + } + if (!isCacheableTimeRange(range)) { return; } @@ -96,7 +100,11 @@ export class RelativeRangeCache { * 4. otherwise, it returns undefined */ get(request: DataQueryRequest): RelativeRangeCacheInfo | undefined { - const { range: requestRange } = request; + const { range: requestRange, targets } = request; + + if (!RelativeRangeCache.isClientCacheEnabled(targets)) { + return undefined; + } if (!isCacheableTimeRange(request.range)) { return undefined; @@ -111,6 +119,11 @@ export class RelativeRangeCache { return RelativeRangeCache.parseCacheInfo(cachedDataInfo, request); } + private static isClientCacheEnabled(targets: DataQueryRequest['targets']) { + // default to enabled unless any query explicitly disables clientCache + return !targets.some((target) => target.clientCache === false); + } + /** * Lookup cached data for the given request. * @param request DataQueryRequest request to lookup cached data for diff --git a/src/components/query/ClientCacheRow.tsx b/src/components/query/ClientCacheRow.tsx new file mode 100644 index 00000000..f78f3283 --- /dev/null +++ b/src/components/query/ClientCacheRow.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { InlineField, InlineSwitch, Switch } from '@grafana/ui'; +import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental'; + +interface Props { + clientCache?: boolean; + newFormStylingEnabled?: boolean; + onClientCacheChange: (evt: React.SyntheticEvent) => void; +} + +export const ClientCacheRow = ({clientCache, newFormStylingEnabled, onClientCacheChange}: Props) => { + if (newFormStylingEnabled) { + return ( + + + + + + + + ); + } + + return ( +
+ + + +
+ ); +}; diff --git a/src/components/query/QueryEditor.test.tsx b/src/components/query/QueryEditor.test.tsx index e702fd2a..583a33a1 100644 --- a/src/components/query/QueryEditor.test.tsx +++ b/src/components/query/QueryEditor.test.tsx @@ -144,6 +144,7 @@ describe('QueryEditor', () => { expect(screen.getByText('Quality')).toBeInTheDocument(); expect(screen.getByText('Expand Time Range')).toBeInTheDocument(); expect(screen.getByText('Format L4E Anomaly Result')).toBeInTheDocument(); + expect(screen.getByText('Client cache')).toBeInTheDocument(); expect(screen.getByText('Time')).toBeInTheDocument(); expect(screen.getByText('Format')).toBeInTheDocument(); }); @@ -173,6 +174,7 @@ describe('QueryEditor', () => { expect(screen.getByText('Property')).toBeInTheDocument(); expect(screen.getByText('Quality')).toBeInTheDocument(); expect(screen.getByText('Format L4E Anomaly Result')).toBeInTheDocument(); + expect(screen.getByText('Client cache')).toBeInTheDocument(); expect(screen.getByText('Time')).toBeInTheDocument(); expect(screen.getByText('Format')).toBeInTheDocument(); }); diff --git a/src/components/query/QueryEditor.tsx b/src/components/query/QueryEditor.tsx index 1200b8a5..821872ba 100644 --- a/src/components/query/QueryEditor.tsx +++ b/src/components/query/QueryEditor.tsx @@ -11,12 +11,14 @@ import { PropertyQueryEditor } from './PropertyQueryEditor'; import { EditorField, EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental'; import { config } from '@grafana/runtime'; import { QueryEditorHeader } from '@grafana/aws-sdk'; +import { ClientCacheRow } from './ClientCacheRow'; type Props = QueryEditorProps; const queryDefaults: Partial = { maxPageAggregations: 1, flattenL4e: true, + clientCache: true, }; export const firstLabelWith = 20; @@ -46,6 +48,11 @@ export function QueryEditor(props: Props) { onChange({ ...query, assetId: undefined, propertyId: undefined, region: sel.value }); }; + const onClientCacheChange = (evt: React.SyntheticEvent) => { + const { onChange, query } = props; + onChange({ ...query, clientCache: evt.currentTarget.checked }); + }; + const renderQuery = (query: SitewiseQuery, newFormStylingEnabled?: boolean) => { if (!query.queryType) { return; @@ -80,6 +87,8 @@ export function QueryEditor(props: Props) { ) : undefined; + const clientCacheRow = ; + return ( <> {newFormStylingEnabled ? ( @@ -119,6 +128,7 @@ export function QueryEditor(props: Props) { {renderQuery(query, true)} + {clientCacheRow} ) : ( @@ -163,6 +173,8 @@ export function QueryEditor(props: Props) { {renderQuery(query)} + {clientCacheRow} + )} diff --git a/src/types.ts b/src/types.ts index 6d6d40af..c59f6fb2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -68,6 +68,7 @@ export interface SitewiseQuery extends DataQuery { lastObservation?: boolean; flattenL4e?: boolean; maxPageAggregations?: number; + clientCache?: boolean; } export interface SitewiseNextQuery extends SitewiseQuery {