mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
* Add pagination params and apply to sql * Create getCorrelationsResponse that returns metadata * Set up pagination, change correlations fetch to only get source datasource correlations * Move correlations from root to pane, only fetch correlations for one datasource when initialized or datasource is changed * Fix tests * Fix remaining tests * Use functional component to handle state * Remove unneeded mocks, fix tests * Change perPage to limit * Fix Go Tests * Fix linter * Remove parameter * Account for mixed datasources * Delete unused hook * add source UID filter to API, start backing out front end hook changes * add source IDs to API, use when loading or changing datasource * Fix prettier * Mock correlations response * Get correlations for all datasources in mixed scenario * Add documentation for new parameters * Attempt to fix swagger * Fix correlations page * add swagger and openapi docs * Add mocks to failing test * Change API for consistency, remove extra hooks and unused function * Add max to limit and re-gen api docs * Move the page to the previous page if deleting all the rows on the page * Only fetch if remove does not have value * Change page to a reference hook * Fix documentation, a test and some logic thinking page could be 0
120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
// Libraries
|
|
import { AnyAction, createAction } from '@reduxjs/toolkit';
|
|
|
|
import { DataSourceApi, HistoryItem } from '@grafana/data';
|
|
import { reportInteraction } from '@grafana/runtime';
|
|
import { DataSourceRef } from '@grafana/schema';
|
|
import { RefreshPicker } from '@grafana/ui';
|
|
import { stopQueryState } from 'app/core/utils/explore';
|
|
import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils';
|
|
import { ExploreItemState, ThunkResult } from 'app/types';
|
|
|
|
import { loadSupplementaryQueries } from '../utils/supplementaryQueries';
|
|
|
|
import { saveCorrelationsAction } from './explorePane';
|
|
import { importQueries, runQueries } from './query';
|
|
import { changeRefreshInterval } from './time';
|
|
import { createEmptyQueryResponse, getDatasourceUIDs, loadAndInitDatasource } from './utils';
|
|
|
|
//
|
|
// Actions and Payloads
|
|
//
|
|
|
|
/**
|
|
* Updates datasource instance before datasource loading has started
|
|
*/
|
|
export interface UpdateDatasourceInstancePayload {
|
|
exploreId: string;
|
|
datasourceInstance: DataSourceApi;
|
|
history: HistoryItem[];
|
|
}
|
|
export const updateDatasourceInstanceAction = createAction<UpdateDatasourceInstancePayload>(
|
|
'explore/updateDatasourceInstance'
|
|
);
|
|
|
|
//
|
|
// Action creators
|
|
//
|
|
|
|
/**
|
|
* Loads a new datasource identified by the given name.
|
|
*/
|
|
export function changeDatasource(
|
|
exploreId: string,
|
|
datasource: string | DataSourceRef,
|
|
options?: { importQueries: boolean }
|
|
): ThunkResult<Promise<void>> {
|
|
return async (dispatch, getState) => {
|
|
const orgId = getState().user.orgId;
|
|
const { history, instance } = await loadAndInitDatasource(orgId, datasource);
|
|
const currentDataSourceInstance = getState().explore.panes[exploreId]!.datasourceInstance;
|
|
|
|
reportInteraction('explore_change_ds', {
|
|
from: (currentDataSourceInstance?.meta?.mixed ? 'mixed' : currentDataSourceInstance?.type) || 'unknown',
|
|
to: instance.meta.mixed ? 'mixed' : instance.type,
|
|
exploreId,
|
|
});
|
|
dispatch(
|
|
updateDatasourceInstanceAction({
|
|
exploreId,
|
|
datasourceInstance: instance,
|
|
history,
|
|
})
|
|
);
|
|
|
|
const queries = getState().explore.panes[exploreId]!.queries;
|
|
|
|
const datasourceUIDs = getDatasourceUIDs(instance.uid, queries);
|
|
const correlations = await getCorrelationsBySourceUIDs(datasourceUIDs);
|
|
dispatch(saveCorrelationsAction({ exploreId: exploreId, correlations: correlations.correlations || [] }));
|
|
|
|
if (options?.importQueries) {
|
|
await dispatch(importQueries(exploreId, queries, currentDataSourceInstance, instance));
|
|
}
|
|
|
|
if (getState().explore.panes[exploreId]!.isLive) {
|
|
dispatch(changeRefreshInterval({ exploreId, refreshInterval: RefreshPicker.offOption.value }));
|
|
}
|
|
|
|
// Exception - we only want to run queries on data source change, if the queries were imported
|
|
if (options?.importQueries) {
|
|
dispatch(runQueries({ exploreId }));
|
|
}
|
|
};
|
|
}
|
|
|
|
//
|
|
// Reducer
|
|
//
|
|
|
|
/**
|
|
* Reducer for an Explore area, to be used by the global Explore reducer.
|
|
*/
|
|
// Redux Toolkit uses ImmerJs as part of their solution to ensure that state objects are not mutated.
|
|
// ImmerJs has an autoFreeze option that freezes objects from change which means this reducer can't be migrated to createSlice
|
|
// because the state would become frozen and during run time we would get errors because flot (Graph lib) would try to mutate
|
|
// the frozen state.
|
|
// https://github.com/reduxjs/redux-toolkit/issues/242
|
|
export const datasourceReducer = (state: ExploreItemState, action: AnyAction): ExploreItemState => {
|
|
if (updateDatasourceInstanceAction.match(action)) {
|
|
const { datasourceInstance, history } = action.payload;
|
|
|
|
// Custom components
|
|
stopQueryState(state.querySubscription);
|
|
|
|
return {
|
|
...state,
|
|
datasourceInstance,
|
|
graphResult: null,
|
|
tableResult: null,
|
|
logsResult: null,
|
|
supplementaryQueries: loadSupplementaryQueries(),
|
|
queryResponse: createEmptyQueryResponse(),
|
|
queryKeys: [],
|
|
history,
|
|
};
|
|
}
|
|
|
|
return state;
|
|
};
|