diff --git a/public/app/features/explore/state/reducers.test.ts b/public/app/features/explore/state/reducers.test.ts index 5ece646ed83..4fa6ac3bb52 100644 --- a/public/app/features/explore/state/reducers.test.ts +++ b/public/app/features/explore/state/reducers.test.ts @@ -31,10 +31,14 @@ import { toggleGraphAction, toggleTableAction, updateDatasourceInstanceAction, + addQueryRowAction, + removeQueryRowAction, } from './actionTypes'; import { serializeStateToUrlParam } from 'app/core/utils/explore'; import { updateLocation } from '../../../core/actions'; +const QUERY_KEY_REGEX = /Q-([0-9]+)-([0-9.]+)-([0-9]+)/; + describe('Explore item reducer', () => { describe('scanning', () => { it('should start scanning', () => { @@ -231,6 +235,75 @@ describe('Explore item reducer', () => { }); }); }); + + describe('query rows', () => { + it('adds a new query row', () => { + reducerTester() + .givenReducer(itemReducer, ({ + queries: [], + } as unknown) as ExploreItemState) + .whenActionIsDispatched( + addQueryRowAction({ + exploreId: ExploreId.left, + query: { refId: 'A', key: 'mockKey' }, + index: 0, + }) + ) + .thenStateShouldEqual(({ + queries: [{ refId: 'A', key: 'mockKey' }], + queryKeys: ['mockKey-0'], + } as unknown) as ExploreItemState); + }); + it('removes a query row', () => { + reducerTester() + .givenReducer(itemReducer, ({ + queries: [ + { refId: 'A', key: 'mockKey' }, + { refId: 'B', key: 'mockKey' }, + ], + queryKeys: ['mockKey-0', 'mockKey-1'], + } as unknown) as ExploreItemState) + .whenActionIsDispatched( + removeQueryRowAction({ + exploreId: ExploreId.left, + index: 0, + }) + ) + .thenStatePredicateShouldEqual((resultingState: ExploreItemState) => { + expect(resultingState.queries.length).toBe(1); + expect(resultingState.queries[0].refId).toBe('A'); + expect(resultingState.queries[0].key).toMatch(QUERY_KEY_REGEX); + expect(resultingState.queryKeys[0]).toMatch(QUERY_KEY_REGEX); + return true; + }); + }); + it('reassigns query refId after removing a query to keep queries in order', () => { + reducerTester() + .givenReducer(itemReducer, ({ + queries: [{ refId: 'A' }, { refId: 'B' }, { refId: 'C' }], + queryKeys: ['undefined-0', 'undefined-1', 'undefined-2'], + } as unknown) as ExploreItemState) + .whenActionIsDispatched( + removeQueryRowAction({ + exploreId: ExploreId.left, + index: 0, + }) + ) + .thenStatePredicateShouldEqual((resultingState: ExploreItemState) => { + expect(resultingState.queries.length).toBe(2); + const queriesRefIds = resultingState.queries.map(query => query.refId); + const queriesKeys = resultingState.queries.map(query => query.key); + expect(queriesRefIds).toEqual(['A', 'B']); + queriesKeys.forEach(queryKey => { + expect(queryKey).toMatch(QUERY_KEY_REGEX); + }); + resultingState.queryKeys.forEach(queryKey => { + expect(queryKey).toMatch(QUERY_KEY_REGEX); + }); + return true; + }); + }); + }); }); export const setup = (urlStateOverrides?: any) => { diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index e3bf248952c..8bbcc66bea0 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -367,15 +367,24 @@ export const itemReducer = (state: ExploreItemState = makeExploreItemState(), ac } if (removeQueryRowAction.match(action)) { - const { queries, queryKeys } = state; + const { queries } = state; const { index } = action.payload; if (queries.length <= 1) { return state; } - const nextQueries = [...queries.slice(0, index), ...queries.slice(index + 1)]; - const nextQueryKeys = [...queryKeys.slice(0, index), ...queryKeys.slice(index + 1)]; + // removes a query under a given index and reassigns query keys and refIds to keep everything in order + const queriesAfterRemoval: DataQuery[] = [...queries.slice(0, index), ...queries.slice(index + 1)].map(query => { + return { ...query, refId: '' }; + }); + const nextQueries: DataQuery[] = []; + + queriesAfterRemoval.forEach((query, i) => { + nextQueries.push(generateNewKeyAndAddRefIdIfMissing(query, nextQueries, i)); + }); + + const nextQueryKeys: string[] = nextQueries.map(query => query.key); return { ...state,