123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- import { AnyAction, createAction } from '@reduxjs/toolkit';
- import { DataQuery, HistoryItem } from '@grafana/data';
- import { config, logError } from '@grafana/runtime';
- import { RICH_HISTORY_SETTING_KEYS } from 'app/core/history/richHistoryLocalStorageUtils';
- import store from 'app/core/store';
- import {
- addToRichHistory,
- deleteAllFromRichHistory,
- deleteQueryInRichHistory,
- getRichHistory,
- getRichHistorySettings,
- LocalStorageMigrationStatus,
- migrateQueryHistoryFromLocalStorage,
- updateCommentInRichHistory,
- updateRichHistorySettings,
- updateStarredInRichHistory,
- } from 'app/core/utils/richHistory';
- import { ExploreId, ExploreItemState, ExploreState, RichHistoryQuery, ThunkResult } from 'app/types';
- import { supportedFeatures } from '../../../core/history/richHistoryStorageProvider';
- import { RichHistorySearchFilters, RichHistorySettings } from '../../../core/utils/richHistoryTypes';
- import {
- richHistoryLimitExceededAction,
- richHistoryMigrationFailedAction,
- richHistorySearchFiltersUpdatedAction,
- richHistorySettingsUpdatedAction,
- richHistoryStorageFullAction,
- richHistoryUpdatedAction,
- } from './main';
- //
- // Actions and Payloads
- //
- export interface HistoryUpdatedPayload {
- exploreId: ExploreId;
- history: HistoryItem[];
- }
- export const historyUpdatedAction = createAction<HistoryUpdatedPayload>('explore/historyUpdated');
- //
- // Action creators
- //
- type SyncHistoryUpdatesOptions = {
- updatedQuery?: RichHistoryQuery;
- deletedId?: string;
- };
- /**
- * Updates current state in both Explore panes after changing or deleting a query history item
- */
- const updateRichHistoryState = ({ updatedQuery, deletedId }: SyncHistoryUpdatesOptions): ThunkResult<void> => {
- return async (dispatch, getState) => {
- forEachExplorePane(getState().explore, (item, exploreId) => {
- const newRichHistory = item.richHistory
- // update
- .map((query) => (query.id === updatedQuery?.id ? updatedQuery : query))
- // or remove
- .filter((query) => query.id !== deletedId);
- const deletedItems = item.richHistory.length - newRichHistory.length;
- dispatch(
- richHistoryUpdatedAction({
- richHistoryResults: { richHistory: newRichHistory, total: item.richHistoryTotal! - deletedItems },
- exploreId,
- })
- );
- });
- };
- };
- const forEachExplorePane = (state: ExploreState, callback: (item: ExploreItemState, exploreId: ExploreId) => void) => {
- callback(state.left, ExploreId.left);
- state.right && callback(state.right, ExploreId.right);
- };
- export const addHistoryItem = (
- datasourceUid: string,
- datasourceName: string,
- queries: DataQuery[]
- ): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const { richHistoryStorageFull, limitExceeded } = await addToRichHistory(
- datasourceUid,
- datasourceName,
- queries,
- false,
- '',
- !getState().explore.richHistoryStorageFull,
- !getState().explore.richHistoryLimitExceededWarningShown
- );
- if (richHistoryStorageFull) {
- dispatch(richHistoryStorageFullAction());
- }
- if (limitExceeded) {
- dispatch(richHistoryLimitExceededAction());
- }
- };
- };
- export const starHistoryItem = (id: string, starred: boolean): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const updatedQuery = await updateStarredInRichHistory(id, starred);
- dispatch(updateRichHistoryState({ updatedQuery }));
- };
- };
- export const commentHistoryItem = (id: string, comment?: string): ThunkResult<void> => {
- return async (dispatch) => {
- const updatedQuery = await updateCommentInRichHistory(id, comment);
- dispatch(updateRichHistoryState({ updatedQuery }));
- };
- };
- export const deleteHistoryItem = (id: string): ThunkResult<void> => {
- return async (dispatch) => {
- const deletedId = await deleteQueryInRichHistory(id);
- dispatch(updateRichHistoryState({ deletedId }));
- };
- };
- export const deleteRichHistory = (): ThunkResult<void> => {
- return async (dispatch) => {
- await deleteAllFromRichHistory();
- dispatch(
- richHistoryUpdatedAction({ richHistoryResults: { richHistory: [], total: 0 }, exploreId: ExploreId.left })
- );
- dispatch(
- richHistoryUpdatedAction({ richHistoryResults: { richHistory: [], total: 0 }, exploreId: ExploreId.right })
- );
- };
- };
- export const loadRichHistory = (exploreId: ExploreId): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const filters = getState().explore![exploreId]?.richHistorySearchFilters;
- if (filters) {
- const richHistoryResults = await getRichHistory(filters);
- dispatch(richHistoryUpdatedAction({ richHistoryResults, exploreId }));
- }
- };
- };
- export const loadMoreRichHistory = (exploreId: ExploreId): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const currentFilters = getState().explore![exploreId]?.richHistorySearchFilters;
- const currentRichHistory = getState().explore![exploreId]?.richHistory;
- if (currentFilters && currentRichHistory) {
- const nextFilters = { ...currentFilters, page: (currentFilters?.page || 1) + 1 };
- const moreRichHistory = await getRichHistory(nextFilters);
- const richHistory = [...currentRichHistory, ...moreRichHistory.richHistory];
- dispatch(richHistorySearchFiltersUpdatedAction({ filters: nextFilters, exploreId }));
- dispatch(
- richHistoryUpdatedAction({ richHistoryResults: { richHistory, total: moreRichHistory.total }, exploreId })
- );
- }
- };
- };
- export const clearRichHistoryResults = (exploreId: ExploreId): ThunkResult<void> => {
- return async (dispatch) => {
- dispatch(richHistorySearchFiltersUpdatedAction({ filters: undefined, exploreId }));
- dispatch(richHistoryUpdatedAction({ richHistoryResults: { richHistory: [], total: 0 }, exploreId }));
- };
- };
- /**
- * Initialize query history pane. To load history it requires settings to be loaded first
- * (but only once per session). Filters are initialised by the tab (starred or home).
- */
- export const initRichHistory = (): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const queriesMigrated = store.getBool(RICH_HISTORY_SETTING_KEYS.migrated, false);
- const migrationFailedDuringThisSession = getState().explore.richHistoryMigrationFailed;
- // Query history migration should always be successful, but in case of unexpected errors we ensure
- // the migration attempt happens only once per session, and the user is informed about the failure
- // in a way that can help with potential investigation.
- if (config.queryHistoryEnabled && !queriesMigrated && !migrationFailedDuringThisSession) {
- const migrationResult = await migrateQueryHistoryFromLocalStorage();
- if (migrationResult.status === LocalStorageMigrationStatus.Failed) {
- dispatch(richHistoryMigrationFailedAction());
- logError(migrationResult.error!, { explore: { event: 'QueryHistoryMigrationFailed' } });
- } else {
- store.set(RICH_HISTORY_SETTING_KEYS.migrated, true);
- }
- }
- let settings = getState().explore.richHistorySettings;
- if (!settings) {
- settings = await getRichHistorySettings();
- dispatch(richHistorySettingsUpdatedAction(settings));
- }
- };
- };
- export const updateHistorySettings = (settings: RichHistorySettings): ThunkResult<void> => {
- return async (dispatch) => {
- dispatch(richHistorySettingsUpdatedAction(settings));
- await updateRichHistorySettings(settings);
- };
- };
- /**
- * Assumed this can be called only when settings and filters are initialised
- */
- export const updateHistorySearchFilters = (
- exploreId: ExploreId,
- filters: RichHistorySearchFilters
- ): ThunkResult<void> => {
- return async (dispatch, getState) => {
- await dispatch(richHistorySearchFiltersUpdatedAction({ exploreId, filters: { ...filters } }));
- const currentSettings = getState().explore.richHistorySettings!;
- if (supportedFeatures().lastUsedDataSourcesAvailable) {
- await dispatch(
- updateHistorySettings({
- ...currentSettings,
- lastUsedDatasourceFilters: filters.datasourceFilters,
- })
- );
- }
- };
- };
- export const historyReducer = (state: ExploreItemState, action: AnyAction): ExploreItemState => {
- if (historyUpdatedAction.match(action)) {
- return {
- ...state,
- history: action.payload.history,
- };
- }
- return state;
- };
|