diff --git a/docs/sources/developers/http_api/correlations.md b/docs/sources/developers/http_api/correlations.md index bd0dd51c0b6..d000105e530 100644 --- a/docs/sources/developers/http_api/correlations.md +++ b/docs/sources/developers/http_api/correlations.md @@ -267,6 +267,12 @@ Status codes: Get all correlations. +Query parameters: + +- **page** - Optional. Specify which page number to return. Use the limit parameter to specify the number of correlations per page. The default is page 1. +- **limit** - Optional. Limits the number of returned correlations per page. The default is 100 correlations per page. The maximum limit is 1000 correlations in a page. +- **sourceUID** - Optional. Specify a source datasource UID to filter by. This can be repeated to filter by multiple datasources. + **Example request:** ```http diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.tsx index a28da5cab68..770fe90f3db 100644 --- a/packages/grafana-ui/src/components/Pagination/Pagination.tsx +++ b/packages/grafana-ui/src/components/Pagination/Pagination.tsx @@ -102,7 +102,7 @@ export const Pagination = ({
  1. @@ -188,19 +188,28 @@ export default function CorrelationsPage() { {isAdding && setIsAdding(false)} onCreated={handleAdded} />} - {data && data.length >= 1 && ( - ( - - )} - columns={columns} - data={data} - getRowId={(correlation) => `${correlation.source.uid}-${correlation.uid}`} - /> + {data && data.correlations.length >= 1 && ( + <> + ( + + )} + columns={columns} + data={data.correlations} + getRowId={(correlation) => `${correlation.source.uid}-${correlation.uid}`} + /> + { + fetchCorrelations({ page: (page.current = toPage) }); + }} + /> + )} diff --git a/public/app/features/correlations/types.ts b/public/app/features/correlations/types.ts index 08ee7328dde..5ef056ac707 100644 --- a/public/app/features/correlations/types.ts +++ b/public/app/features/correlations/types.ts @@ -44,6 +44,10 @@ export interface Correlation { config: CorrelationConfig; } +export type GetCorrelationsParams = { + page: number; +}; + export type RemoveCorrelationParams = Pick; export type CreateCorrelationParams = Omit; export type UpdateCorrelationParams = Omit; diff --git a/public/app/features/correlations/useCorrelations.ts b/public/app/features/correlations/useCorrelations.ts index c45e78d64c2..f32af6080d8 100644 --- a/public/app/features/correlations/useCorrelations.ts +++ b/public/app/features/correlations/useCorrelations.ts @@ -9,17 +9,32 @@ import { Correlation, CreateCorrelationParams, CreateCorrelationResponse, + GetCorrelationsParams, RemoveCorrelationParams, RemoveCorrelationResponse, UpdateCorrelationParams, UpdateCorrelationResponse, } from './types'; +export interface CorrelationsResponse { + correlations: Correlation[]; + page: number; + limit: number; + totalCount: number; +} + export interface CorrelationData extends Omit { source: DataSourceInstanceSettings; target: DataSourceInstanceSettings; } +export interface CorrelationsData { + correlations: CorrelationData[]; + page: number; + limit: number; + totalCount: number; +} + const toEnrichedCorrelationData = ({ sourceUID, targetUID, @@ -39,10 +54,14 @@ const toEnrichedCorrelationData = ({ const validSourceFilter = (correlation: CorrelationData | undefined): correlation is CorrelationData => !!correlation; -const toEnrichedCorrelationsData = (correlations: Correlation[]): CorrelationData[] => { - return correlations.map(toEnrichedCorrelationData).filter(validSourceFilter); +export const toEnrichedCorrelationsData = (correlationsResponse: CorrelationsResponse): CorrelationsData => { + return { + ...correlationsResponse, + correlations: correlationsResponse.correlations.map(toEnrichedCorrelationData).filter(validSourceFilter), + }; }; -function getData(response: FetchResponse) { + +export function getData(response: FetchResponse) { return response.data; } @@ -55,10 +74,15 @@ function getData(response: FetchResponse) { export const useCorrelations = () => { const { backend } = useGrafana(); - const [getInfo, get] = useAsyncFn<() => Promise>( - () => + const [getInfo, get] = useAsyncFn<(params: GetCorrelationsParams) => Promise>( + (params) => lastValueFrom( - backend.fetch({ url: '/api/datasources/correlations', method: 'GET', showErrorAlert: false }) + backend.fetch({ + url: '/api/datasources/correlations', + params: { page: params.page }, + method: 'GET', + showErrorAlert: false, + }) ) .then(getData) .then(toEnrichedCorrelationsData), diff --git a/public/app/features/correlations/utils.ts b/public/app/features/correlations/utils.ts index 1e363577ef1..a59c570b553 100644 --- a/public/app/features/correlations/utils.ts +++ b/public/app/features/correlations/utils.ts @@ -1,8 +1,17 @@ +import { lastValueFrom } from 'rxjs'; + import { DataFrame, DataLinkConfigOrigin } from '@grafana/data'; +import { getBackendSrv } from '@grafana/runtime'; import { formatValueName } from '../explore/PrometheusListView/ItemLabels'; -import { CorrelationData } from './useCorrelations'; +import { + CorrelationData, + CorrelationsData, + CorrelationsResponse, + getData, + toEnrichedCorrelationsData, +} from './useCorrelations'; type DataFrameRefIdToDataSourceUid = Record; @@ -58,3 +67,18 @@ const decorateDataFrameWithInternalDataLinks = (dataFrame: DataFrame, correlatio }); }); }; + +export const getCorrelationsBySourceUIDs = async (sourceUIDs: string[]): Promise => { + return lastValueFrom( + getBackendSrv().fetch({ + url: `/api/datasources/correlations`, + method: 'GET', + showErrorAlert: false, + params: { + sourceUID: sourceUIDs, + }, + }) + ) + .then(getData) + .then(toEnrichedCorrelationsData); +}; diff --git a/public/app/features/explore/ExplorePage.test.tsx b/public/app/features/explore/ExplorePage.test.tsx index 53f7b48afd6..0ad7977e0a2 100644 --- a/public/app/features/explore/ExplorePage.test.tsx +++ b/public/app/features/explore/ExplorePage.test.tsx @@ -31,6 +31,20 @@ jest.mock('react-virtualized-auto-sizer', () => { }; }); +const fetch = jest.fn().mockResolvedValue({ correlations: [] }); +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getBackendSrv: () => ({ fetch }), +})); + +jest.mock('rxjs', () => ({ + ...jest.requireActual('rxjs'), + lastValueFrom: () => + new Promise((resolve, reject) => { + resolve({ data: { correlations: [] } }); + }), +})); + describe('ExplorePage', () => { afterEach(() => { tearDown(); diff --git a/public/app/features/explore/ExplorePage.tsx b/public/app/features/explore/ExplorePage.tsx index 58aba32eaab..bf0b0920c31 100644 --- a/public/app/features/explore/ExplorePage.tsx +++ b/public/app/features/explore/ExplorePage.tsx @@ -13,7 +13,6 @@ import { ExploreQueryParams } from 'app/types/explore'; import { ExploreActions } from './ExploreActions'; import { ExplorePaneContainer } from './ExplorePaneContainer'; -import { useExploreCorrelations } from './hooks/useExploreCorrelations'; import { useExplorePageTitle } from './hooks/useExplorePageTitle'; import { useStateSync } from './hooks/useStateSync'; import { useTimeSrvFix } from './hooks/useTimeSrvFix'; @@ -39,7 +38,6 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor // if we were to update the URL on state change, the title would not match the URL. // Ultimately the URL is the single source of truth from which state is derived, the page title is not different useExplorePageTitle(props.queryParams); - useExploreCorrelations(); const dispatch = useDispatch(); const { keybindings, chrome } = useGrafana(); const navModel = useNavModel('explore'); diff --git a/public/app/features/explore/QueryRows.test.tsx b/public/app/features/explore/QueryRows.test.tsx index 95783ae7ecd..0064c6a1183 100644 --- a/public/app/features/explore/QueryRows.test.tsx +++ b/public/app/features/explore/QueryRows.test.tsx @@ -56,10 +56,10 @@ function setup(queries: DataQuery[]) { richHistory: [], datasourceInstance: datasources['someDs-uid'], queries, + correlations: [], }, }, syncedTimes: false, - correlations: [], richHistoryStorageFull: false, richHistoryLimitExceededWarningShown: false, }; diff --git a/public/app/features/explore/hooks/useExploreCorrelations.ts b/public/app/features/explore/hooks/useExploreCorrelations.ts deleted file mode 100644 index 1b68740c84b..00000000000 --- a/public/app/features/explore/hooks/useExploreCorrelations.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useEffect } from 'react'; - -import { config } from '@grafana/runtime'; -import { useAppNotification } from 'app/core/copy/appNotification'; -import { useCorrelations } from 'app/features/correlations/useCorrelations'; -import { useDispatch } from 'app/types'; - -import { saveCorrelationsAction } from '../state/main'; - -export function useExploreCorrelations() { - const { get } = useCorrelations(); - const { warning } = useAppNotification(); - - const dispatch = useDispatch(); - useEffect(() => { - if (!config.featureToggles.correlations) { - dispatch(saveCorrelationsAction([])); - } else { - get.execute(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - if (get.value) { - dispatch(saveCorrelationsAction(get.value)); - } else if (get.error) { - dispatch(saveCorrelationsAction([])); - warning( - 'Could not load correlations.', - 'Correlations data could not be loaded, DataLinks may have partial data.' - ); - } - }, [get.value, get.error, dispatch, warning]); -} diff --git a/public/app/features/explore/hooks/useStateSync/index.test.tsx b/public/app/features/explore/hooks/useStateSync/index.test.tsx index b9d8e5b6e99..260bf24dd5b 100644 --- a/public/app/features/explore/hooks/useStateSync/index.test.tsx +++ b/public/app/features/explore/hooks/useStateSync/index.test.tsx @@ -17,6 +17,20 @@ import { splitClose, splitOpen } from '../../state/main'; import { useStateSync } from './'; +const fetch = jest.fn().mockResolvedValue({ correlations: [] }); +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getBackendSrv: () => ({ fetch }), +})); + +jest.mock('rxjs', () => ({ + ...jest.requireActual('rxjs'), + lastValueFrom: () => + new Promise((resolve, reject) => { + resolve({ data: { correlations: [] } }); + }), +})); + function defaultDsGetter(datasources: Array>): DataSourceSrv['get'] { return (datasource) => { let ds; diff --git a/public/app/features/explore/spec/datasourceState.test.tsx b/public/app/features/explore/spec/datasourceState.test.tsx index 55778487cee..6c727bf40f4 100644 --- a/public/app/features/explore/spec/datasourceState.test.tsx +++ b/public/app/features/explore/spec/datasourceState.test.tsx @@ -4,6 +4,12 @@ import { changeDatasource } from './helper/interactions'; import { makeLogsQueryResponse } from './helper/query'; import { setupExplore, tearDown, waitForExplore } from './helper/setup'; +jest.mock('../../correlations/utils', () => { + return { + getCorrelationsBySourceUIDs: jest.fn().mockReturnValue({ correlations: [] }), + }; +}); + describe('Explore: handle datasource states', () => { afterEach(() => { tearDown(); diff --git a/public/app/features/explore/spec/interpolation.test.tsx b/public/app/features/explore/spec/interpolation.test.tsx index 93f4171e861..0d98c2f5cbd 100644 --- a/public/app/features/explore/spec/interpolation.test.tsx +++ b/public/app/features/explore/spec/interpolation.test.tsx @@ -29,6 +29,12 @@ jest.mock('react-virtualized-auto-sizer', () => { }; }); +jest.mock('../../correlations/utils', () => { + return { + getCorrelationsBySourceUIDs: jest.fn().mockReturnValue({ correlations: [] }), + }; +}); + describe('Explore: interpolation', () => { // support-escalations/issues/1459 it('Time is interpolated when explore is opened with a URL', async () => { diff --git a/public/app/features/explore/spec/query.test.tsx b/public/app/features/explore/spec/query.test.tsx index 5703508320b..e5ebd638130 100644 --- a/public/app/features/explore/spec/query.test.tsx +++ b/public/app/features/explore/spec/query.test.tsx @@ -5,6 +5,12 @@ import { serializeStateToUrlParam } from '@grafana/data'; import { makeLogsQueryResponse } from './helper/query'; import { setupExplore, tearDown, waitForExplore } from './helper/setup'; +jest.mock('../../correlations/utils', () => { + return { + getCorrelationsBySourceUIDs: jest.fn().mockReturnValue({ correlations: [] }), + }; +}); + describe('Explore: handle running/not running query', () => { afterEach(() => { tearDown(); diff --git a/public/app/features/explore/spec/queryHistory.test.tsx b/public/app/features/explore/spec/queryHistory.test.tsx index 0afbe089734..325a80a4fb0 100644 --- a/public/app/features/explore/spec/queryHistory.test.tsx +++ b/public/app/features/explore/spec/queryHistory.test.tsx @@ -74,6 +74,12 @@ jest.mock('react-virtualized-auto-sizer', () => { }; }); +jest.mock('../../correlations/utils', () => { + return { + getCorrelationsBySourceUIDs: jest.fn().mockReturnValue({ correlations: [] }), + }; +}); + describe('Explore: Query History', () => { const USER_INPUT = 'my query'; const RAW_QUERY = `{"expr":"${USER_INPUT}"}`; diff --git a/public/app/features/explore/state/datasource.ts b/public/app/features/explore/state/datasource.ts index 61ed5b1aa13..f2585d4609e 100644 --- a/public/app/features/explore/state/datasource.ts +++ b/public/app/features/explore/state/datasource.ts @@ -6,13 +6,15 @@ 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, loadAndInitDatasource } from './utils'; +import { createEmptyQueryResponse, getDatasourceUIDs, loadAndInitDatasource } from './utils'; // // Actions and Payloads @@ -60,8 +62,13 @@ export function changeDatasource( }) ); + 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) { - const queries = getState().explore.panes[exploreId]!.queries; await dispatch(importQueries(exploreId, queries, currentDataSourceInstance, instance)); } diff --git a/public/app/features/explore/state/explorePane.ts b/public/app/features/explore/state/explorePane.ts index e8767684831..a88032ab9aa 100644 --- a/public/app/features/explore/state/explorePane.ts +++ b/public/app/features/explore/state/explorePane.ts @@ -11,6 +11,8 @@ import { } from '@grafana/data'; import { DataQuery, DataSourceRef } from '@grafana/schema'; import { getQueryKeys } from 'app/core/utils/explore'; +import { CorrelationData } from 'app/features/correlations/useCorrelations'; +import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils'; import { getTimeZone } from 'app/features/profile/state/selectors'; import { createAsyncThunk, ThunkResult } from 'app/types'; import { ExploreItemState } from 'app/types/explore'; @@ -20,7 +22,13 @@ import { historyReducer } from './history'; import { richHistorySearchFiltersUpdatedAction, richHistoryUpdatedAction } from './main'; import { queryReducer, runQueries } from './query'; import { timeReducer, updateTime } from './time'; -import { makeExplorePaneState, loadAndInitDatasource, createEmptyQueryResponse, getRange } from './utils'; +import { + makeExplorePaneState, + loadAndInitDatasource, + createEmptyQueryResponse, + getRange, + getDatasourceUIDs, +} from './utils'; // Types // @@ -86,6 +94,12 @@ export interface SetUrlReplacedPayload { } export const setUrlReplacedAction = createAction('explore/setUrlReplaced'); +export interface SaveCorrelationsPayload { + exploreId: string; + correlations: CorrelationData[]; +} +export const saveCorrelationsAction = createAction('explore/saveCorrelationsAction'); + /** * Keep track of the Explore container size, in particular the width. * The width will be used to calculate graph intervals (number of datapoints). @@ -141,6 +155,10 @@ export const initializeExplore = createAsyncThunk( dispatch(updateTime({ exploreId })); if (instance) { + const datasourceUIDs = getDatasourceUIDs(instance.uid, queries); + const correlations = await getCorrelationsBySourceUIDs(datasourceUIDs); + dispatch(saveCorrelationsAction({ exploreId: exploreId, correlations: correlations.correlations || [] })); + dispatch(runQueries({ exploreId })); } @@ -189,6 +207,13 @@ export const paneReducer = (state: ExploreItemState = makeExplorePaneState(), ac return { ...state, panelsState }; } + if (saveCorrelationsAction.match(action)) { + return { + ...state, + correlations: action.payload.correlations, + }; + } + if (initializeExploreAction.match(action)) { const { queries, range, datasourceInstance, history } = action.payload; @@ -202,6 +227,7 @@ export const paneReducer = (state: ExploreItemState = makeExplorePaneState(), ac history, queryResponse: createEmptyQueryResponse(), cache: [], + correlations: [], }; } diff --git a/public/app/features/explore/state/main.ts b/public/app/features/explore/state/main.ts index 6a0312bd979..21d7f9d744b 100644 --- a/public/app/features/explore/state/main.ts +++ b/public/app/features/explore/state/main.ts @@ -10,7 +10,6 @@ import { ExploreItemState, ExploreState } from 'app/types/explore'; import { RichHistoryResults } from '../../../core/history/RichHistoryStorage'; import { RichHistorySearchFilters, RichHistorySettings } from '../../../core/utils/richHistoryTypes'; import { createAsyncThunk, ThunkResult } from '../../../types'; -import { CorrelationData } from '../../correlations/useCorrelations'; import { TimeSrv } from '../../dashboard/services/TimeSrv'; import { withUniqueRefIds } from '../utils/queries'; @@ -38,8 +37,6 @@ export const richHistorySearchFiltersUpdatedAction = createAction<{ filters?: RichHistorySearchFilters; }>('explore/richHistorySearchFiltersUpdatedAction'); -export const saveCorrelationsAction = createAction('explore/saveCorrelationsAction'); - export const splitSizeUpdateAction = createAction<{ largerExploreId?: string; }>('explore/splitSizeUpdateAction'); @@ -144,7 +141,6 @@ const initialExploreItemState = makeExplorePaneState(); export const initialExploreState: ExploreState = { syncedTimes: false, panes: {}, - correlations: undefined, richHistoryStorageFull: false, richHistoryLimitExceededWarningShown: false, largerExploreId: undefined, @@ -199,13 +195,6 @@ export const exploreReducer = (state = initialExploreState, action: AnyAction): }; } - if (saveCorrelationsAction.match(action)) { - return { - ...state, - correlations: action.payload, - }; - } - if (syncTimesAction.match(action)) { return { ...state, syncedTimes: action.payload.syncedTimes }; } diff --git a/public/app/features/explore/state/query.test.ts b/public/app/features/explore/state/query.test.ts index 436ecf94fe2..289b95ac184 100644 --- a/public/app/features/explore/state/query.test.ts +++ b/public/app/features/explore/state/query.test.ts @@ -25,8 +25,8 @@ import { setTimeSrv, TimeSrv } from '../../dashboard/services/TimeSrv'; import { makeLogs } from '../__mocks__/makeLogs'; import { supplementaryQueryTypes } from '../utils/supplementaryQueries'; +import { saveCorrelationsAction } from './explorePane'; import { createDefaultInitialState } from './helpers'; -import { saveCorrelationsAction } from './main'; import { addQueryRowAction, addResultsToCache, @@ -159,7 +159,8 @@ describe('runQueries', () => { it('should pass dataFrames to state even if there is error in response', async () => { const { dispatch, getState } = setupTests(); setupQueryResponse(getState()); - await dispatch(saveCorrelationsAction([])); + + await dispatch(saveCorrelationsAction({ exploreId: 'left', correlations: [] })); await dispatch(runQueries({ exploreId: 'left' })); expect(getState().explore.panes.left!.showMetrics).toBeTruthy(); expect(getState().explore.panes.left!.graphResult).toBeDefined(); @@ -168,7 +169,7 @@ describe('runQueries', () => { it('should modify the request-id for all supplementary queries', () => { const { dispatch, getState } = setupTests(); setupQueryResponse(getState()); - dispatch(saveCorrelationsAction([])); + dispatch(saveCorrelationsAction({ exploreId: 'left', correlations: [] })); dispatch(runQueries({ exploreId: 'left' })); const state = getState().explore.panes.left!; @@ -188,7 +189,7 @@ describe('runQueries', () => { const { dispatch, getState } = setupTests(); const leftDatasourceInstance = assertIsDefined(getState().explore.panes.left!.datasourceInstance); jest.mocked(leftDatasourceInstance.query).mockReturnValueOnce(EMPTY); - await dispatch(saveCorrelationsAction([])); + await dispatch(saveCorrelationsAction({ exploreId: 'left', correlations: [] })); await dispatch(runQueries({ exploreId: 'left' })); await new Promise((resolve) => setTimeout(() => resolve(''), 500)); expect(getState().explore.panes.left!.queryResponse.state).toBe(LoadingState.Done); @@ -199,7 +200,7 @@ describe('runQueries', () => { setupQueryResponse(getState()); await dispatch(runQueries({ exploreId: 'left' })); expect(getState().explore.panes.left!.graphResult).not.toBeDefined(); - await dispatch(saveCorrelationsAction([])); + await dispatch(saveCorrelationsAction({ exploreId: 'left', correlations: [] })); expect(getState().explore.panes.left!.graphResult).toBeDefined(); }); }); diff --git a/public/app/features/explore/state/query.ts b/public/app/features/explore/state/query.ts index 2be33daa966..f2a5ccdc184 100644 --- a/public/app/features/explore/state/query.ts +++ b/public/app/features/explore/state/query.ts @@ -35,6 +35,7 @@ import { } from 'app/core/utils/explore'; import { getShiftedTimeRange } from 'app/core/utils/timePicker'; import { CorrelationData } from 'app/features/correlations/useCorrelations'; +import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils'; import { getTimeZone } from 'app/features/profile/state/selectors'; import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; import { store } from 'app/store/store'; @@ -59,9 +60,10 @@ import { supplementaryQueryTypes, } from '../utils/supplementaryQueries'; +import { saveCorrelationsAction } from './explorePane'; import { addHistoryItem, historyUpdatedAction, loadRichHistory } from './history'; import { updateTime } from './time'; -import { createCacheKey, filterLogRowsByIndex, getResultsFromCache } from './utils'; +import { createCacheKey, filterLogRowsByIndex, getDatasourceUIDs, getResultsFromCache } from './utils'; /** * Derives from explore state if a given Explore pane is waiting for more data to be received @@ -319,6 +321,7 @@ export const changeQueries = createAsyncThunk( async ({ queries, exploreId }, { getState, dispatch }) => { let queriesImported = false; const oldQueries = getState().explore.panes[exploreId]!.queries; + const rootUID = getState().explore.panes[exploreId]!.datasourceInstance?.uid; for (const newQuery of queries) { for (const oldQuery of oldQueries) { @@ -328,6 +331,16 @@ export const changeQueries = createAsyncThunk( await dispatch(importQueries(exploreId, oldQueries, queryDatasource, targetDS, newQuery.refId)); queriesImported = true; } + + if ( + rootUID === MIXED_DATASOURCE_NAME && + newQuery.refId === oldQuery.refId && + newQuery.datasource?.uid !== oldQuery.datasource?.uid + ) { + const datasourceUIDs = getDatasourceUIDs(MIXED_DATASOURCE_NAME, queries); + const correlations = await getCorrelationsBySourceUIDs(datasourceUIDs); + dispatch(saveCorrelationsAction({ exploreId: exploreId, correlations: correlations.correlations || [] })); + } } } @@ -481,7 +494,7 @@ export const runQueries = createAsyncThunk( async ({ exploreId, preserveCache }, { dispatch, getState }) => { dispatch(updateTime({ exploreId })); - const correlations$ = getCorrelations(); + const correlations$ = getCorrelations(exploreId); // We always want to clear cache unless we explicitly pass preserveCache parameter if (preserveCache !== true) { @@ -1134,15 +1147,15 @@ export const queryReducer = (state: ExploreItemState, action: AnyAction): Explor /** * Creates an observable that emits correlations once they are loaded */ -const getCorrelations = () => { +const getCorrelations = (exploreId: string) => { return new Observable((subscriber) => { - const existingCorrelations = store.getState().explore.correlations; + const existingCorrelations = store.getState().explore.panes[exploreId]?.correlations; if (existingCorrelations) { subscriber.next(existingCorrelations); subscriber.complete(); } else { const unsubscribe = store.subscribe(() => { - const { correlations } = store.getState().explore; + const correlations = store.getState().explore.panes[exploreId]?.correlations; if (correlations) { unsubscribe(); subscriber.next(correlations); diff --git a/public/app/features/explore/state/utils.ts b/public/app/features/explore/state/utils.ts index 7d39cd26033..53c2f356191 100644 --- a/public/app/features/explore/state/utils.ts +++ b/public/app/features/explore/state/utils.ts @@ -1,3 +1,5 @@ +import { uniq } from 'lodash'; + import { AbsoluteTimeRange, DataSourceApi, @@ -15,7 +17,8 @@ import { isDateTime, toUtc, } from '@grafana/data'; -import { DataSourceRef, TimeZone } from '@grafana/schema'; +import { DataQuery, DataSourceRef, TimeZone } from '@grafana/schema'; +import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; import { ExplorePanelData } from 'app/types'; import { ExploreItemState } from 'app/types/explore'; @@ -67,6 +70,7 @@ export const makeExplorePaneState = (): ExploreItemState => ({ richHistory: [], supplementaryQueries: loadSupplementaryQueries(), panelsState: {}, + correlations: undefined, }); export const createEmptyQueryResponse = (): ExplorePanelData => ({ @@ -205,3 +209,11 @@ export const filterLogRowsByIndex = ( return logRows; }; + +export const getDatasourceUIDs = (datasourceUID: string, queries: DataQuery[]): string[] => { + if (datasourceUID === MIXED_DATASOURCE_NAME) { + return uniq(queries.map((query) => query.datasource?.uid).filter((uid): uid is string => !!uid)); + } else { + return [datasourceUID]; + } +}; diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index 7d8abc9d159..29899e70840 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -33,8 +33,6 @@ export interface ExploreState { panes: Record; - correlations?: CorrelationData[]; - /** * Settings for rich history (note: filters are stored per each pane separately) */ @@ -192,6 +190,8 @@ export interface ExploreItemState { supplementaryQueries: SupplementaryQueries; panelsState: ExplorePanelsState; + + correlations?: CorrelationData[]; } export interface ExploreUpdateState { diff --git a/public/openapi3.json b/public/openapi3.json index 51abfa9780a..e39114c079f 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -17,6 +17,29 @@ "SMTPNotEnabledError": { "description": "(empty)" }, + "StateHistory": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Frame" + } + } + }, + "description": "(empty)" + }, + "TestGrafanaRuleResponse": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/postableAlert" + }, + "type": "array" + } + } + }, + "description": "(empty)" + }, "acceptedResponse": { "content": { "application/json": { @@ -27,25 +50,6 @@ }, "description": "AcceptedResponse" }, - "addPermissionResponse": { - "content": { - "application/json": { - "schema": { - "properties": { - "message": { - "type": "string" - }, - "permissionId": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - } - } - }, - "description": "(empty)" - }, "adminCreateUserResponse": { "content": { "application/json": { @@ -123,20 +127,6 @@ }, "description": "ConflictError" }, - "contentResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "format": "uint8", - "type": "integer" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "createCorrelationResponse": { "content": { "application/json": { @@ -252,35 +242,6 @@ }, "description": "(empty)" }, - "createReportResponse": { - "content": { - "application/json": { - "schema": { - "properties": { - "id": { - "format": "int64", - "type": "integer" - }, - "message": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "description": "(empty)" - }, - "createRoleResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDTO" - } - } - }, - "description": "(empty)" - }, "createServiceAccountResponse": { "content": { "application/json": { @@ -525,16 +486,6 @@ }, "description": "(empty)" }, - "getAccessControlStatusResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Status" - } - } - }, - "description": "(empty)" - }, "getAlertNotificationChannelResponse": { "content": { "application/json": { @@ -594,29 +545,6 @@ }, "description": "(empty)" }, - "getAllPermissionseResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DataSourcePermissionsDTO" - } - } - }, - "description": "(empty)" - }, - "getAllRolesResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/RoleDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "getAnnotationByIDResponse": { "content": { "application/json": { @@ -696,19 +624,6 @@ }, "description": "(empty)" }, - "getCustomPermissionsReportResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/CustomPermissionsRecordDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "getDashboardPermissionsListResponse": { "content": { "application/json": { @@ -868,16 +783,6 @@ }, "description": "(empty)" }, - "getLicenseTokenResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Token" - } - } - }, - "description": "(empty)" - }, "getOrgByIDResponse": { "content": { "application/json": { @@ -1036,59 +941,6 @@ }, "description": "(empty)" }, - "getReportResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigDTO" - } - } - }, - "description": "(empty)" - }, - "getReportSettingsResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SettingsDTO" - } - } - }, - "description": "(empty)" - }, - "getReportsResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ConfigDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, - "getRoleAssignmentsResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleAssignmentsDTO" - } - } - }, - "description": "(empty)" - }, - "getRoleResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDTO" - } - } - }, - "description": "(empty)" - }, "getSharingOptionsResponse": { "content": { "application/json": { @@ -1136,19 +988,6 @@ }, "description": "(empty)" }, - "getStatusResponse": { - "description": "(empty)" - }, - "getSyncStatusResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ActiveSyncStatusDTO" - } - } - }, - "description": "(empty)" - }, "getTeamByIDResponse": { "content": { "application/json": { @@ -1159,19 +998,6 @@ }, "description": "(empty)" }, - "getTeamGroupsApiResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/TeamGroupDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "getTeamMembersResponse": { "content": { "application/json": { @@ -1263,48 +1089,6 @@ }, "description": "InternalServerError is a general error indicating something went wrong internally." }, - "listBuiltinRolesResponse": { - "content": { - "application/json": { - "schema": { - "additionalProperties": { - "items": { - "$ref": "#/components/schemas/RoleDTO" - }, - "type": "array" - }, - "type": "object" - } - } - }, - "description": "(empty)" - }, - "listRecordingRulesResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/RecordingRuleJSON" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, - "listRolesResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/RoleDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "listSortOptionsResponse": { "content": { "application/json": { @@ -1501,9 +1285,6 @@ }, "description": "(empty)" }, - "postRenewLicenseTokenResponse": { - "description": "(empty)" - }, "preconditionFailedError": { "content": { "application/json": { @@ -1537,36 +1318,6 @@ }, "description": "(empty)" }, - "recordingRuleResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RecordingRuleJSON" - } - } - }, - "description": "(empty)" - }, - "recordingRuleWriteTargetResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PrometheusRemoteWriteTargetJSON" - } - } - }, - "description": "(empty)" - }, - "refreshLicenseStatsResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ActiveUserStats" - } - } - }, - "description": "(empty)" - }, "retrieveServiceAccountResponse": { "content": { "application/json": { @@ -1643,16 +1394,6 @@ }, "description": "(empty)" }, - "searchResultResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SearchResult" - } - } - }, - "description": "(empty)" - }, "searchTeamsResponse": { "content": { "application/json": { @@ -1673,16 +1414,6 @@ }, "description": "(empty)" }, - "setRoleAssignmentsResponse": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleAssignmentsDTO" - } - } - }, - "description": "(empty)" - }, "testAlertResponse": { "content": { "application/json": { @@ -1798,42 +1529,6 @@ "Ack": { "type": "object" }, - "ActiveSyncStatusDTO": { - "description": "ActiveSyncStatusDTO holds the information for LDAP background Sync", - "properties": { - "enabled": { - "type": "boolean" - }, - "nextSync": { - "format": "date-time", - "type": "string" - }, - "prevSync": { - "$ref": "#/components/schemas/SyncResult" - }, - "schedule": { - "type": "string" - } - }, - "type": "object" - }, - "ActiveUserStats": { - "properties": { - "active_admins_and_editors": { - "format": "int64", - "type": "integer" - }, - "active_users": { - "format": "int64", - "type": "integer" - }, - "active_viewers": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "AddCommand": { "properties": { "name": { @@ -1940,25 +1635,6 @@ }, "type": "object" }, - "AddPermissionDTO": { - "properties": { - "builtinRole": { - "type": "string" - }, - "permission": { - "$ref": "#/components/schemas/DsPermissionType" - }, - "teamId": { - "format": "int64", - "type": "integer" - }, - "userId": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "AddServiceAccountTokenCommand": { "properties": { "name": { @@ -1980,25 +1656,6 @@ }, "type": "object" }, - "AddTeamRoleCommand": { - "properties": { - "roleUid": { - "type": "string" - } - }, - "type": "object" - }, - "AddUserRoleCommand": { - "properties": { - "global": { - "type": "boolean" - }, - "roleUid": { - "type": "string" - } - }, - "type": "object" - }, "Address": { "properties": { "address1": { @@ -2913,26 +2570,6 @@ "title": "BasicAuth contains basic HTTP authentication credentials.", "type": "object" }, - "BrandingOptionsDTO": { - "properties": { - "emailFooterLink": { - "type": "string" - }, - "emailFooterMode": { - "type": "string" - }, - "emailFooterText": { - "type": "string" - }, - "emailLogoUrl": { - "type": "string" - }, - "reportLogoUrl": { - "type": "string" - } - }, - "type": "object" - }, "CalculateDiffTarget": { "properties": { "dashboardId": { @@ -2995,88 +2632,6 @@ "title": "Config is the top-level configuration for Alertmanager's config files.", "type": "object" }, - "ConfigDTO": { - "description": "ConfigDTO is model representation in transfer", - "properties": { - "created": { - "format": "date-time", - "type": "string" - }, - "dashboardId": { - "format": "int64", - "type": "integer" - }, - "dashboardName": { - "type": "string" - }, - "dashboardUid": { - "type": "string" - }, - "dashboards": { - "items": { - "$ref": "#/components/schemas/DashboardDTO" - }, - "type": "array" - }, - "enableCsv": { - "type": "boolean" - }, - "enableDashboardUrl": { - "type": "boolean" - }, - "formats": { - "items": { - "$ref": "#/components/schemas/Type" - }, - "type": "array" - }, - "id": { - "format": "int64", - "type": "integer" - }, - "message": { - "type": "string" - }, - "name": { - "type": "string" - }, - "options": { - "$ref": "#/components/schemas/ReportOptionsDTO" - }, - "orgId": { - "format": "int64", - "type": "integer" - }, - "recipients": { - "type": "string" - }, - "replyTo": { - "type": "string" - }, - "scaleFactor": { - "format": "int64", - "type": "integer" - }, - "schedule": { - "$ref": "#/components/schemas/ScheduleDTO" - }, - "state": { - "$ref": "#/components/schemas/State" - }, - "templateVars": { - "type": "object" - }, - "updated": { - "format": "date-time", - "type": "string" - }, - "userId": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "ContactPoints": { "items": { "$ref": "#/components/schemas/EmbeddedContactPoint" @@ -3131,7 +2686,8 @@ "additionalProperties": false, "description": "Target data query", "example": { - "expr": "job=app" + "prop1": "value1", + "prop2": "value" }, "type": "object" }, @@ -3163,7 +2719,8 @@ "additionalProperties": false, "description": "Target data query", "example": { - "expr": "job=app" + "prop1": "value1", + "prop2": "value" }, "type": "object" }, @@ -3190,6 +2747,12 @@ }, "type": "object" }, + "CounterResetHint": { + "description": "or alternatively that we are dealing with a gauge histogram, where counter resets do not apply.", + "format": "uint8", + "title": "CounterResetHint contains the known information about a counter reset,", + "type": "integer" + }, "CreateAlertNotificationCommand": { "properties": { "disableResolveMessage": { @@ -3349,64 +2912,6 @@ }, "type": "object" }, - "CreateOrUpdateConfigCmd": { - "properties": { - "dashboardId": { - "format": "int64", - "type": "integer" - }, - "dashboardUid": { - "type": "string" - }, - "dashboards": { - "items": { - "$ref": "#/components/schemas/DashboardDTO" - }, - "type": "array" - }, - "enableCsv": { - "type": "boolean" - }, - "enableDashboardUrl": { - "type": "boolean" - }, - "formats": { - "items": { - "$ref": "#/components/schemas/Type" - }, - "type": "array" - }, - "message": { - "type": "string" - }, - "name": { - "type": "string" - }, - "options": { - "$ref": "#/components/schemas/ReportOptionsDTO" - }, - "recipients": { - "type": "string" - }, - "replyTo": { - "type": "string" - }, - "scaleFactor": { - "format": "int64", - "type": "integer" - }, - "schedule": { - "$ref": "#/components/schemas/ScheduleDTO" - }, - "state": { - "$ref": "#/components/schemas/State" - }, - "templateVars": { - "type": "object" - } - }, - "type": "object" - }, "CreateOrgCommand": { "properties": { "name": { @@ -3449,42 +2954,6 @@ ], "type": "object" }, - "CreateRoleForm": { - "properties": { - "description": { - "type": "string" - }, - "displayName": { - "type": "string" - }, - "global": { - "type": "boolean" - }, - "group": { - "type": "string" - }, - "hidden": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "permissions": { - "items": { - "$ref": "#/components/schemas/Permission" - }, - "type": "array" - }, - "uid": { - "type": "string" - }, - "version": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "CreateServiceAccountForm": { "properties": { "isDisabled": { @@ -3518,53 +2987,6 @@ }, "type": "object" }, - "CustomPermissionsRecordDTO": { - "properties": { - "customPermissions": { - "type": "string" - }, - "granteeName": { - "type": "string" - }, - "granteeType": { - "type": "string" - }, - "granteeUrl": { - "type": "string" - }, - "id": { - "format": "int64", - "type": "integer" - }, - "isFolder": { - "type": "boolean" - }, - "orgId": { - "format": "int64", - "type": "integer" - }, - "orgRole": { - "type": "string" - }, - "slug": { - "type": "string" - }, - "title": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "url": { - "type": "string" - }, - "usersCount": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "DashboardACLInfoDTO": { "properties": { "created": { @@ -3668,20 +3090,6 @@ }, "type": "object" }, - "DashboardDTO": { - "properties": { - "dashboard": { - "$ref": "#/components/schemas/DashboardReportDTO" - }, - "reportVariables": { - "type": "object" - }, - "timeRange": { - "$ref": "#/components/schemas/TimeRangeDTO" - } - }, - "type": "object" - }, "DashboardFullWithMeta": { "properties": { "dashboard": { @@ -3795,21 +3203,6 @@ }, "type": "object" }, - "DashboardReportDTO": { - "properties": { - "id": { - "format": "int64", - "type": "integer" - }, - "name": { - "type": "string" - }, - "uid": { - "type": "string" - } - }, - "type": "object" - }, "DashboardSnapshotDTO": { "description": "DashboardSnapshotDTO without dashboard map", "properties": { @@ -4067,83 +3460,6 @@ }, "type": "object" }, - "DataSourcePermissionRuleDTO": { - "properties": { - "builtInRole": { - "type": "string" - }, - "created": { - "format": "date-time", - "type": "string" - }, - "datasourceId": { - "format": "int64", - "type": "integer" - }, - "id": { - "format": "int64", - "type": "integer" - }, - "isManaged": { - "type": "boolean" - }, - "permission": { - "$ref": "#/components/schemas/DsPermissionType" - }, - "permissionName": { - "type": "string" - }, - "team": { - "type": "string" - }, - "teamAvatarUrl": { - "type": "string" - }, - "teamEmail": { - "type": "string" - }, - "teamId": { - "format": "int64", - "type": "integer" - }, - "updated": { - "format": "date-time", - "type": "string" - }, - "userAvatarUrl": { - "type": "string" - }, - "userEmail": { - "type": "string" - }, - "userId": { - "format": "int64", - "type": "integer" - }, - "userLogin": { - "type": "string" - } - }, - "type": "object" - }, - "DataSourcePermissionsDTO": { - "properties": { - "datasourceId": { - "format": "int64", - "type": "integer" - }, - "enabled": { - "type": "boolean" - }, - "permissions": { - "items": { - "$ref": "#/components/schemas/DataSourcePermissionRuleDTO" - }, - "type": "array" - } - }, - "type": "object" - }, "DataTopic": { "description": "nolint:revive", "title": "DataTopic is used to identify which topic the frame should be assigned to.", @@ -4158,14 +3474,6 @@ }, "type": "object" }, - "DeleteTokenCommand": { - "properties": { - "instance": { - "type": "string" - } - }, - "type": "object" - }, "DescendantCounts": { "additionalProperties": { "format": "int64", @@ -4214,11 +3522,6 @@ "DsAccess": { "type": "string" }, - "DsPermissionType": { - "description": "Datasource permission\nDescription:\n`0` - No Access\n`1` - Query\n`2` - Edit\nEnum: 0,1,2", - "format": "int64", - "type": "integer" - }, "Duration": { "description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.", "format": "int64", @@ -4479,18 +3782,6 @@ }, "type": "object" }, - "FailedUser": { - "description": "FailedUser holds the information of an user that failed", - "properties": { - "Error": { - "type": "string" - }, - "Login": { - "type": "string" - } - }, - "type": "object" - }, "Failure": { "$ref": "#/components/schemas/ResponseDetails" }, @@ -4536,7 +3827,7 @@ "type": "string" }, "displayNameFromDS": { - "description": "DisplayNameFromDS overrides Grafana default naming in a better way that allows users to override it easily.", + "description": "DisplayNameFromDS overrides Grafana default naming strategy.", "type": "string" }, "filterable": { @@ -4611,6 +3902,56 @@ "title": "FindTagsResult is the result of a tags search.", "type": "object" }, + "FloatHistogram": { + "description": "A FloatHistogram is needed by PromQL to handle operations that might result\nin fractional counts. Since the counts in a histogram are unlikely to be too\nlarge to be represented precisely by a float64, a FloatHistogram can also be\nused to represent a histogram with integer counts and thus serves as a more\ngeneralized representation.", + "properties": { + "Count": { + "description": "Total number of observations. Must be zero or positive.", + "format": "double", + "type": "number" + }, + "CounterResetHint": { + "$ref": "#/components/schemas/CounterResetHint" + }, + "PositiveBuckets": { + "description": "Observation counts in buckets. Each represents an absolute count and\nmust be zero or positive.", + "items": { + "format": "double", + "type": "number" + }, + "type": "array" + }, + "PositiveSpans": { + "description": "Spans for positive and negative buckets (see Span below).", + "items": { + "$ref": "#/components/schemas/Span" + }, + "type": "array" + }, + "Schema": { + "description": "Currently valid schema numbers are -4 \u003c= n \u003c= 8. They are all for\nbase-2 bucket schemas, where 1 is a bucket boundary in each case, and\nthen each power of two is divided into 2^n logarithmic buckets. Or\nin other words, each bucket boundary is the previous boundary times\n2^(2^-n).", + "format": "int32", + "type": "integer" + }, + "Sum": { + "description": "Sum of observations. This is also used as the stale marker.", + "format": "double", + "type": "number" + }, + "ZeroCount": { + "description": "Observations falling into the zero bucket. Must be zero or positive.", + "format": "double", + "type": "number" + }, + "ZeroThreshold": { + "description": "Width of the zero bucket.", + "format": "double", + "type": "number" + } + }, + "title": "FloatHistogram is similar to Histogram but uses float64 for all\ncounts. Additionally, bucket counts are absolute and not deltas.", + "type": "object" + }, "Folder": { "properties": { "accessControl": { @@ -5328,12 +4669,20 @@ "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", "type": "boolean" }, + "no_proxy": { + "description": "NoProxy contains addresses that should not use a proxy.", + "type": "string" + }, "oauth2": { "$ref": "#/components/schemas/OAuth2" }, "proxy_connect_header": { "$ref": "#/components/schemas/Header" }, + "proxy_from_environment": { + "description": "ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function\nto determine proxies.", + "type": "boolean" + }, "proxy_url": { "$ref": "#/components/schemas/URL" }, @@ -6295,6 +5644,17 @@ }, "type": "object" }, + "no_proxy": { + "description": "NoProxy contains addresses that should not use a proxy.", + "type": "string" + }, + "proxy_connect_header": { + "$ref": "#/components/schemas/Header" + }, + "proxy_from_environment": { + "description": "ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function\nto determine proxies.", + "type": "boolean" + }, "proxy_url": { "$ref": "#/components/schemas/URL" }, @@ -6711,26 +6071,6 @@ }, "type": "object" }, - "Permission": { - "properties": { - "action": { - "type": "string" - }, - "created": { - "format": "date-time", - "type": "string" - }, - "scope": { - "type": "string" - }, - "updated": { - "format": "date-time", - "type": "string" - } - }, - "title": "Permission is the model for access control permissions.", - "type": "object" - }, "PermissionDenied": { "type": "object" }, @@ -6821,7 +6161,11 @@ "type": "array" }, "Point": { + "description": "If H is not nil, then this is a histogram point and only (T, H) is valid.\nIf H is nil, then only (T, V) is valid.", "properties": { + "H": { + "$ref": "#/components/schemas/FloatHistogram" + }, "T": { "format": "int64", "type": "integer" @@ -7044,6 +6388,29 @@ }, "type": "object" }, + "PostableExtendedRuleNodeExtended": { + "properties": { + "folderTitle": { + "example": "project_x", + "type": "string" + }, + "folderUid": { + "example": "okrd3I0Vz", + "type": "string" + }, + "rule": { + "$ref": "#/components/schemas/PostableExtendedRuleNode" + }, + "ruleGroup": { + "example": "eval_group_1", + "type": "string" + } + }, + "required": [ + "rule" + ], + "type": "object" + }, "PostableGrafanaReceiver": { "properties": { "disableResolveMessage": { @@ -7164,20 +6531,6 @@ }, "type": "object" }, - "PrometheusRemoteWriteTargetJSON": { - "properties": { - "data_source_uid": { - "type": "string" - }, - "id": { - "type": "string" - }, - "remote_write_path": { - "type": "string" - } - }, - "type": "object" - }, "Provenance": { "type": "string" }, @@ -7334,8 +6687,30 @@ }, "type": "array" }, + "ProxyConfig": { + "properties": { + "no_proxy": { + "description": "NoProxy contains addresses that should not use a proxy.", + "type": "string" + }, + "proxy_connect_header": { + "$ref": "#/components/schemas/Header" + }, + "proxy_from_environment": { + "description": "ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function\nto determine proxies.", + "type": "boolean" + }, + "proxy_url": { + "$ref": "#/components/schemas/URL" + } + }, + "type": "object" + }, "PushoverConfig": { "properties": { + "device": { + "type": "string" + }, "expire": { "type": "string" }, @@ -7509,7 +6884,7 @@ "type": "string" }, "displayNameFromDS": { - "description": "DisplayNameFromDS overrides Grafana default naming in a better way that allows users to override it easily.", + "description": "DisplayNameFromDS overrides Grafana default naming strategy.", "type": "string" }, "filterable": { @@ -7676,51 +7051,6 @@ "title": "Receiver configuration provides configuration on how to contact a receiver.", "type": "object" }, - "RecordingRuleJSON": { - "description": "RecordingRuleJSON is the external representation of a recording rule", - "properties": { - "active": { - "type": "boolean" - }, - "count": { - "type": "boolean" - }, - "description": { - "type": "string" - }, - "dest_data_source_uid": { - "type": "string" - }, - "id": { - "type": "string" - }, - "interval": { - "format": "int64", - "type": "integer" - }, - "name": { - "type": "string" - }, - "prom_name": { - "type": "string" - }, - "queries": { - "items": { - "additionalProperties": false, - "type": "object" - }, - "type": "array" - }, - "range": { - "format": "int64", - "type": "integer" - }, - "target_ref_id": { - "type": "string" - } - }, - "type": "object" - }, "Regexp": { "description": "A Regexp is safe for concurrent use by multiple goroutines,\nexcept for configuration methods, such as Longest.", "title": "Regexp is the representation of a compiled regular expression.", @@ -7738,41 +7068,6 @@ }, "type": "object" }, - "ReportEmailDTO": { - "properties": { - "email": { - "type": "string" - }, - "emails": { - "description": "Comma-separated list of emails to which to send the report to.", - "type": "string" - }, - "id": { - "description": "Send the report to the emails specified in the report. Required if emails is not present.", - "format": "int64", - "type": "string" - }, - "useEmailsFromReport": { - "description": "Send the report to the emails specified in the report. Required if emails is not present.", - "type": "boolean" - } - }, - "type": "object" - }, - "ReportOptionsDTO": { - "properties": { - "layout": { - "type": "string" - }, - "orientation": { - "type": "string" - }, - "timeRange": { - "$ref": "#/components/schemas/TimeRangeDTO" - } - }, - "type": "object" - }, "ResponseDetails": { "properties": { "msg": { @@ -7807,79 +7102,6 @@ }, "type": "object" }, - "RoleAssignmentsDTO": { - "properties": { - "role_uid": { - "type": "string" - }, - "service_accounts": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "teams": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "users": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - } - }, - "type": "object" - }, - "RoleDTO": { - "properties": { - "created": { - "format": "date-time", - "type": "string" - }, - "delegatable": { - "type": "boolean" - }, - "description": { - "type": "string" - }, - "displayName": { - "type": "string" - }, - "group": { - "type": "string" - }, - "hidden": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "permissions": { - "items": { - "$ref": "#/components/schemas/Permission" - }, - "type": "array" - }, - "uid": { - "type": "string" - }, - "updated": { - "format": "date-time", - "type": "string" - }, - "version": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "Route": { "description": "A Route is a node that contains definitions of how to handle alerts. This is modified\nfrom the upstream alertmanager in that it adds the ObjectMatchers property.", "properties": { @@ -8127,6 +7349,9 @@ }, "Sample": { "properties": { + "H": { + "$ref": "#/components/schemas/FloatHistogram" + }, "Metric": { "$ref": "#/components/schemas/Labels" }, @@ -8174,49 +7399,6 @@ }, "type": "object" }, - "ScheduleDTO": { - "properties": { - "day": { - "type": "string" - }, - "dayOfMonth": { - "type": "string" - }, - "endDate": { - "format": "date-time", - "type": "string" - }, - "frequency": { - "type": "string" - }, - "hour": { - "format": "int64", - "type": "integer" - }, - "intervalAmount": { - "format": "int64", - "type": "integer" - }, - "intervalFrequency": { - "type": "string" - }, - "minute": { - "format": "int64", - "type": "integer" - }, - "startDate": { - "format": "date-time", - "type": "string" - }, - "timeZone": { - "type": "string" - }, - "workdaysOnly": { - "type": "boolean" - } - }, - "type": "object" - }, "SearchOrgServiceAccountsResult": { "description": "swagger: model", "properties": { @@ -8265,50 +7447,6 @@ }, "type": "object" }, - "SearchResult": { - "properties": { - "result": { - "items": { - "$ref": "#/components/schemas/SearchResultItem" - }, - "type": "array" - } - }, - "type": "object" - }, - "SearchResultItem": { - "properties": { - "action": { - "type": "string" - }, - "basicRole": { - "type": "string" - }, - "orgId": { - "format": "int64", - "type": "integer" - }, - "roleName": { - "type": "string" - }, - "scope": { - "type": "string" - }, - "teamId": { - "format": "int64", - "type": "integer" - }, - "userId": { - "format": "int64", - "type": "integer" - }, - "version": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "SearchTeamQueryResult": { "properties": { "page": { @@ -8475,49 +7613,6 @@ }, "type": "object" }, - "SetRoleAssignmentsCommand": { - "properties": { - "service_accounts": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "teams": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "users": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - } - }, - "type": "object" - }, - "SetUserRolesCommand": { - "properties": { - "global": { - "type": "boolean" - }, - "includeHidden": { - "type": "boolean" - }, - "roleUids": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, "SettingsBag": { "additionalProperties": { "additionalProperties": { @@ -8527,26 +7622,6 @@ }, "type": "object" }, - "SettingsDTO": { - "properties": { - "branding": { - "$ref": "#/components/schemas/BrandingOptionsDTO" - }, - "id": { - "format": "int64", - "type": "integer" - }, - "orgId": { - "format": "int64", - "type": "integer" - }, - "userId": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "SigV4Config": { "description": "SigV4Config is the configuration for signing remote write requests with\nAWS's SigV4 verification process. Empty values will be retrieved using the\nAWS default credentials chain.", "properties": { @@ -8718,6 +7793,22 @@ "SmtpNotEnabled": { "$ref": "#/components/schemas/ResponseDetails" }, + "Span": { + "properties": { + "Length": { + "description": "Length of the span.", + "format": "uint32", + "type": "integer" + }, + "Offset": { + "description": "Gap to previous span (always positive), or starting index for the 1st\nspan (which can be negative).", + "format": "int32", + "type": "integer" + } + }, + "title": "A Span defines a continuous sequence of buckets.", + "type": "object" + }, "Spec": { "properties": { "homeDashboardUID": { @@ -8747,9 +7838,6 @@ "title": "Spec defines model for Spec.", "type": "object" }, - "State": { - "type": "string" - }, "Status": { "format": "int64", "type": "integer" @@ -8768,39 +7856,6 @@ "SupportedTransformationTypes": { "type": "string" }, - "SyncResult": { - "properties": { - "Elapsed": { - "$ref": "#/components/schemas/Duration" - }, - "FailedUsers": { - "items": { - "$ref": "#/components/schemas/FailedUser" - }, - "type": "array" - }, - "MissingUserIds": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "Started": { - "format": "date-time", - "type": "string" - }, - "UpdatedUserIds": { - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - } - }, - "title": "SyncResult holds the result of a sync with LDAP. This gives us information on which users were updated and how.", - "type": "object" - }, "TLSConfig": { "properties": { "ca_file": { @@ -8888,30 +7943,6 @@ }, "type": "object" }, - "TeamGroupDTO": { - "properties": { - "groupId": { - "type": "string" - }, - "orgId": { - "format": "int64", - "type": "integer" - }, - "teamId": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, - "TeamGroupMapping": { - "properties": { - "groupId": { - "type": "string" - } - }, - "type": "object" - }, "TeamMemberDTO": { "properties": { "auth_module": { @@ -8982,6 +8013,9 @@ }, "token": { "$ref": "#/components/schemas/Secret" + }, + "token_file": { + "type": "string" } }, "title": "TelegramConfig configures notifications via Telegram.", @@ -9302,104 +8336,6 @@ }, "type": "object" }, - "TimeRangeDTO": { - "properties": { - "from": { - "type": "string" - }, - "to": { - "type": "string" - } - }, - "type": "object" - }, - "Token": { - "properties": { - "account": { - "type": "string" - }, - "company": { - "type": "string" - }, - "details_url": { - "type": "string" - }, - "exp": { - "format": "int64", - "type": "integer" - }, - "iat": { - "format": "int64", - "type": "integer" - }, - "included_users": { - "format": "int64", - "type": "integer" - }, - "iss": { - "type": "string" - }, - "jti": { - "type": "string" - }, - "lexp": { - "format": "int64", - "type": "integer" - }, - "lic_exp_warn_days": { - "format": "int64", - "type": "integer" - }, - "lid": { - "type": "string" - }, - "limit_by": { - "type": "string" - }, - "max_concurrent_user_sessions": { - "format": "int64", - "type": "integer" - }, - "nbf": { - "format": "int64", - "type": "integer" - }, - "prod": { - "items": { - "type": "string" - }, - "type": "array" - }, - "slug": { - "type": "string" - }, - "status": { - "$ref": "#/components/schemas/TokenStatus" - }, - "sub": { - "type": "string" - }, - "tok_exp_warn_days": { - "format": "int64", - "type": "integer" - }, - "trial": { - "type": "boolean" - }, - "trial_exp": { - "format": "int64", - "type": "integer" - }, - "update_days": { - "format": "int64", - "type": "integer" - }, - "usage_billing": { - "type": "boolean" - } - }, - "type": "object" - }, "TokenDTO": { "properties": { "created": { @@ -9442,10 +8378,6 @@ }, "type": "object" }, - "TokenStatus": { - "format": "int64", - "type": "integer" - }, "Transformation": { "properties": { "expression": { @@ -9495,9 +8427,6 @@ }, "type": "object" }, - "Type": { - "type": "string" - }, "URL": { "properties": { "ForceQuery": { @@ -9881,39 +8810,6 @@ }, "type": "object" }, - "UpdateRoleCommand": { - "properties": { - "description": { - "type": "string" - }, - "displayName": { - "type": "string" - }, - "global": { - "type": "boolean" - }, - "group": { - "type": "string" - }, - "hidden": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "permissions": { - "items": { - "$ref": "#/components/schemas/Permission" - }, - "type": "array" - }, - "version": { - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, "UpdateServiceAccountForm": { "properties": { "isDisabled": { @@ -10275,7 +9171,10 @@ "type": "boolean" }, "url": { - "$ref": "#/components/schemas/URL" + "$ref": "#/components/schemas/SecretURL" + }, + "url_file": { + "type": "string" } }, "title": "WebhookConfig configures notifications via a generic webhook.", @@ -10466,7 +9365,6 @@ "type": "object" }, "gettableAlert": { - "description": "GettableAlert gettable alert", "properties": { "annotations": { "$ref": "#/components/schemas/labelSet" @@ -10522,13 +9420,13 @@ "type": "object" }, "gettableAlerts": { - "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/components/schemas/gettableAlert" }, "type": "array" }, "gettableSilence": { + "description": "GettableSilence gettable silence", "properties": { "comment": { "description": "comment", @@ -10727,6 +9625,7 @@ "type": "array" }, "postableSilence": { + "description": "PostableSilence postable silence", "properties": { "comment": { "description": "comment", @@ -10764,7 +9663,6 @@ "type": "object" }, "receiver": { - "description": "Receiver receiver", "properties": { "active": { "description": "active", @@ -10902,701 +9800,6 @@ }, "openapi": "3.0.3", "paths": { - "/access-control/assignments/search": { - "post": { - "description": "Returns the result of the search through access-control role assignments.\n\nYou need to have a permission with action `teams.roles:read` on scope `teams:*`\nand a permission with action `users.roles:read` on scope `users:*`.", - "operationId": "searchResult", - "responses": { - "200": { - "$ref": "#/components/responses/searchResultResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Debug permissions.", - "tags": [ - "enterprise" - ] - } - }, - "/access-control/roles": { - "get": { - "description": "Gets all existing roles. The response contains all global and organization local roles, for the organization which user is signed in.\n\nYou need to have a permission with action `roles:read` and scope `roles:*`.", - "operationId": "listRoles", - "parameters": [ - { - "in": "query", - "name": "delegatable", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/listRolesResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get all roles.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "post": { - "description": "Creates a new custom role and maps given permissions to that role. Note that roles with the same prefix as Fixed Roles can’t be created.\n\nYou need to have a permission with action `roles:write` and scope `permissions:type:delegate`. `permissions:type:delegate` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.\nFor example, if a user does not have required permissions for creating users, they won’t be able to create a custom role which allows to do that. This is done to prevent escalation of privileges.", - "operationId": "createRole", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleForm" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "201": { - "$ref": "#/components/responses/createRoleResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Create a new custom role.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/roles/{roleUID}": { - "delete": { - "description": "Delete a role with the given UID, and it’s permissions. If the role is assigned to a built-in role, the deletion operation will fail, unless force query param is set to true, and in that case all assignments will also be deleted.\n\nYou need to have a permission with action `roles:delete` and scope `permissions:type:delegate`. `permissions:type:delegate` scope ensures that users can only delete a custom role with the same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to delete a custom role which allows to do that.", - "operationId": "deleteRole", - "parameters": [ - { - "in": "query", - "name": "force", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "global", - "schema": { - "type": "boolean" - } - }, - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Delete a custom role.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "get": { - "description": "Get a role for the given UID.\n\nYou need to have a permission with action `roles:read` and scope `roles:*`.", - "operationId": "getRole", - "parameters": [ - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getRoleResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get a role.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "put": { - "description": "You need to have a permission with action `roles:write` and scope `permissions:type:delegate`. `permissions:type:delegate` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.", - "operationId": "updateRole", - "parameters": [ - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/getRoleResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Update a custom role.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/roles/{roleUID}/assignments": { - "get": { - "description": "Get role assignments for the role with the given UID.\n\nYou need to have a permission with action `teams.roles:list` and scope `teams:id:*` and `users.roles:list` and scope `users:id:*`.", - "operationId": "getRoleAssignments", - "parameters": [ - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getRoleAssignmentsResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get role assignments.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "put": { - "description": "Set role assignments for the role with the given UID.\n\nYou need to have a permission with action `teams.roles:add` and `teams.roles:remove` and scope `permissions:type:delegate`, and `users.roles:add` and `users.roles:remove` and scope `permissions:type:delegate`.", - "operationId": "setRoleAssignments", - "parameters": [ - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetRoleAssignmentsCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/setRoleAssignmentsResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Set role assignments.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/status": { - "get": { - "description": "Returns an indicator to check if fine-grained access control is enabled or not.\n\nYou need to have a permission with action `status:accesscontrol` and scope `services:accesscontrol`.", - "operationId": "getAccessControlStatus", - "responses": { - "200": { - "$ref": "#/components/responses/getAccessControlStatusResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get status.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/teams/{teamId}/roles": { - "get": { - "description": "You need to have a permission with action `teams.roles:read` and scope `teams:id:\u003cteam ID\u003e`.", - "operationId": "listTeamRoles", - "parameters": [ - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get team roles.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "post": { - "description": "You need to have a permission with action `teams.roles:add` and scope `permissions:type:delegate`.", - "operationId": "addTeamRole", - "parameters": [ - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddTeamRoleCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Add team role.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "put": { - "description": "You need to have a permission with action `teams.roles:add` and `teams.roles:remove` and scope `permissions:type:delegate` for each.", - "operationId": "setTeamRoles", - "parameters": [ - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Update team role.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/teams/{teamId}/roles/{roleUID}": { - "delete": { - "description": "You need to have a permission with action `teams.roles:remove` and scope `permissions:type:delegate`.", - "operationId": "removeTeamRole", - "parameters": [ - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Remove team role.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/users/{userId}/roles": { - "get": { - "description": "Lists the roles that have been directly assigned to a given user. The list does not include built-in roles (Viewer, Editor, Admin or Grafana Admin), and it does not include roles that have been inherited from a team.\n\nYou need to have a permission with action `users.roles:read` and scope `users:id:\u003cuser ID\u003e`.", - "operationId": "listUserRoles", - "parameters": [ - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getAllRolesResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "List roles assigned to a user.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "post": { - "description": "Assign a role to a specific user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:add` and scope `permissions:type:delegate`. `permissions:type:delegate` scope ensures that users can only assign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign a role which will allow to do that. This is done to prevent escalation of privileges.", - "operationId": "addUserRole", - "parameters": [ - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddUserRoleCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Add a user role assignment.", - "tags": [ - "access_control", - "enterprise" - ] - }, - "put": { - "description": "Update the user’s role assignments to match the provided set of UIDs. This will remove any assigned roles that aren’t in the request and add roles that are in the set but are not already assigned to the user.\nIf you want to add or remove a single role, consider using Add a user role assignment or Remove a user role assignment instead.\n\nYou need to have a permission with action `users.roles:add` and `users.roles:remove` and scope `permissions:type:delegate` for each. `permissions:type:delegate` scope ensures that users can only assign or unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign or unassign a role which will allow to do that. This is done to prevent escalation of privileges.", - "operationId": "setUserRoles", - "parameters": [ - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetUserRolesCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Set user role assignments.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/access-control/users/{userId}/roles/{roleUID}": { - "delete": { - "description": "Revoke a role from a user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:remove` and scope `permissions:type:delegate`. `permissions:type:delegate` scope ensures that users can only unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to unassign a role which will allow to do that. This is done to prevent escalation of privileges.", - "operationId": "removeUserRole", - "parameters": [ - { - "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment.", - "in": "query", - "name": "global", - "schema": { - "type": "boolean" - } - }, - { - "in": "path", - "name": "roleUID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "userId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Remove a user role assignment.", - "tags": [ - "access_control", - "enterprise" - ] - } - }, - "/admin/ldap-sync-status": { - "get": { - "description": "You need to have a permission with action `ldap.status:read`.", - "operationId": "getSyncStatus", - "responses": { - "200": { - "$ref": "#/components/responses/getSyncStatusResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Returns the current state of the LDAP background sync integration.", - "tags": [ - "ldap_debug" - ] - } - }, "/admin/ldap/reload": { "post": { "description": "If you are running Grafana Enterprise and have Fine-grained access control enabled, you need to have a permission with action `ldap.config:reload`.", @@ -11773,27 +9976,6 @@ ] } }, - "/admin/provisioning/access-control/reload": { - "post": { - "operationId": "adminProvisioningReloadAccessControl", - "responses": { - "202": { - "$ref": "#/components/responses/acceptedResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - } - }, - "summary": "You need to have a permission with action `provisioning:reload` with scope `provisioners:accesscontrol`.", - "tags": [ - "access_control_provisioning", - "enterprise" - ] - } - }, "/admin/provisioning/dashboards/reload": { "post": { "description": "Reloads the provisioning config files for dashboards again. It won’t return until the new provisioned entities are already stored in the database. In case of dashboards, it will stop polling for changes in dashboard files and then restart it with new configurations after returning.\nIf you are running Grafana Enterprise and have Fine-grained access control enabled, you need to have a permission with action `provisioning:reload` and scope `provisioners:dashboards`.", @@ -15467,6 +13649,40 @@ "/datasources/correlations": { "get": { "operationId": "getCorrelations", + "parameters": [ + { + "description": "Limit the maximum number of correlations to return per page", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "format": "int64", + "maximum": 1000, + "type": "integer" + } + }, + { + "description": "Page index for starting fetching correlations", + "in": "query", + "name": "page", + "schema": { + "default": 1, + "format": "int64", + "type": "integer" + } + }, + { + "description": "Source datasource UID filter to be applied to correlations", + "in": "query", + "name": "sourceUID", + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + ], "responses": { "200": { "$ref": "#/components/responses/getCorrelationsResponse" @@ -16322,236 +14538,6 @@ ] } }, - "/datasources/{datasourceId}/disable-permissions": { - "post": { - "description": "Disables permissions for the data source with the given id. All existing permissions will be removed and anyone will be able to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", - "operationId": "disablePermissions", - "parameters": [ - { - "in": "path", - "name": "datasourceId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/createOrUpdateDatasourceResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Disable permissions for a data source.", - "tags": [ - "datasource_permissions", - "enterprise" - ] - } - }, - "/datasources/{datasourceId}/enable-permissions": { - "post": { - "description": "Enables permissions for the data source with the given id.\nNo one except Org Admins will be able to query the data source until permissions have been added\nwhich permit certain users or teams to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", - "operationId": "enablePermissions", - "parameters": [ - { - "in": "path", - "name": "datasourceId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/createOrUpdateDatasourceResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Enable permissions for a data source.", - "tags": [ - "datasource_permissions", - "enterprise" - ] - } - }, - "/datasources/{datasourceId}/permissions": { - "get": { - "description": "Gets all existing permissions for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:read` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", - "operationId": "getAllPermissions", - "parameters": [ - { - "in": "path", - "name": "datasourceId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getAllPermissionseResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get permissions for a data source.", - "tags": [ - "datasource_permissions", - "enterprise" - ] - }, - "post": { - "description": "You need to have a permission with action `datasources.permissions:read` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", - "operationId": "addPermission", - "parameters": [ - { - "in": "query", - "name": "userId", - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "in": "query", - "name": "teamId", - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "in": "query", - "name": "builtinRole", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "permission", - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "in": "path", - "name": "datasourceId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/addPermissionResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Add permissions for a data source.", - "tags": [ - "datasource_permissions", - "enterprise" - ] - } - }, - "/datasources/{datasourceId}/permissions/{permissionId}": { - "delete": { - "description": "Removes the permission with the given permissionId for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:delete` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", - "operationId": "deletePermissions", - "parameters": [ - { - "in": "path", - "name": "datasourceId", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "permissionId", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - } - }, - "summary": "Remove permission for a data source.", - "tags": [ - "datasource_permissions", - "enterprise" - ] - } - }, "/datasources/{id}": { "delete": { "deprecated": true, @@ -17563,216 +15549,6 @@ ] } }, - "/licensing/check": { - "get": { - "operationId": "getStatus", - "responses": { - "200": { - "$ref": "#/components/responses/getStatusResponse" - } - }, - "summary": "Check license availability.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/licensing/custom-permissions": { - "get": { - "description": "You need to have a permission with action `licensing.reports:read`.", - "operationId": "getCustomPermissionsReport", - "responses": { - "200": { - "$ref": "#/components/responses/getCustomPermissionsReportResponse" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get custom permissions report.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/licensing/custom-permissions-csv": { - "get": { - "description": "You need to have a permission with action `licensing.reports:read`.", - "operationId": "getCustomPermissionsCSV", - "responses": { - "200": { - "$ref": "#/components/responses/getCustomPermissionsReportResponse" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get custom permissions report in CSV format.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/licensing/refresh-stats": { - "get": { - "description": "You need to have a permission with action `licensing:read`.", - "operationId": "refreshLicenseStats", - "responses": { - "200": { - "$ref": "#/components/responses/refreshLicenseStatsResponse" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Refresh license stats.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/licensing/token": { - "delete": { - "description": "Removes the license stored in the Grafana database. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:delete`.", - "operationId": "deleteLicenseToken", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTokenCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "202": { - "$ref": "#/components/responses/acceptedResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "422": { - "$ref": "#/components/responses/unprocessableEntityError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Remove license from database.", - "tags": [ - "licensing", - "enterprise" - ] - }, - "get": { - "description": "You need to have a permission with action `licensing:read`.", - "operationId": "getLicenseToken", - "responses": { - "200": { - "$ref": "#/components/responses/getLicenseTokenResponse" - } - }, - "summary": "Get license token.", - "tags": [ - "licensing", - "enterprise" - ] - }, - "post": { - "description": "You need to have a permission with action `licensing:update`.", - "operationId": "postLicenseToken", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeleteTokenCommand" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/getLicenseTokenResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - } - }, - "summary": "Create license token.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/licensing/token/renew": { - "post": { - "description": "Manually ask license issuer for a new token. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:update`.", - "operationId": "postRenewLicenseToken", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/postRenewLicenseTokenResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - } - }, - "summary": "Manually force license refresh.", - "tags": [ - "licensing", - "enterprise" - ] - } - }, - "/logout/saml": { - "get": { - "operationId": "getSAMLLogout", - "responses": { - "302": { - "description": "(empty)" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "GetLogout initiates single logout process.", - "tags": [ - "saml", - "enterprise" - ] - } - }, "/org": { "get": { "operationId": "getCurrentOrg", @@ -19440,865 +17216,6 @@ ] } }, - "/recording-rules": { - "get": { - "operationId": "listRecordingRules", - "responses": { - "200": { - "$ref": "#/components/responses/listRecordingRulesResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Lists all rules in the database: active or deleted.", - "tags": [ - "recording_rules", - "enterprise" - ] - }, - "post": { - "operationId": "createRecordingRule", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RecordingRuleJSON" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/recordingRuleResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Create a recording rule that is then registered and started.", - "tags": [ - "recording_rules", - "enterprise" - ] - }, - "put": { - "operationId": "updateRecordingRule", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RecordingRuleJSON" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/recordingRuleResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Update the active status of a rule.", - "tags": [ - "recording_rules", - "enterprise" - ] - } - }, - "/recording-rules/test": { - "post": { - "operationId": "testCreateRecordingRule", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RecordingRuleJSON" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "422": { - "$ref": "#/components/responses/unprocessableEntityError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Test a recording rule.", - "tags": [ - "recording_rules", - "enterprise" - ] - } - }, - "/recording-rules/writer": { - "delete": { - "operationId": "deleteRecordingRuleWriteTarget", - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Delete the remote write target.", - "tags": [ - "recording_rules", - "enterprise" - ] - }, - "get": { - "operationId": "getRecordingRuleWriteTarget", - "responses": { - "200": { - "$ref": "#/components/responses/recordingRuleWriteTargetResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Return the prometheus remote write target.", - "tags": [ - "recording_rules", - "enterprise" - ] - }, - "post": { - "description": "It returns a 422 if there is not an existing prometheus data source configured.", - "operationId": "createRecordingRuleWriteTarget", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PrometheusRemoteWriteTargetJSON" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/recordingRuleWriteTargetResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "422": { - "$ref": "#/components/responses/unprocessableEntityError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Create a remote write target.", - "tags": [ - "recording_rules", - "enterprise" - ] - } - }, - "/recording-rules/{recordingRuleID}": { - "delete": { - "operationId": "deleteRecordingRule", - "parameters": [ - { - "in": "path", - "name": "recordingRuleID", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Delete removes the rule from the registry and stops it.", - "tags": [ - "recording_rules", - "enterprise" - ] - } - }, - "/reports": { - "get": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports:read` with scope `reports:*`.", - "operationId": "getReports", - "responses": { - "200": { - "$ref": "#/components/responses/getReportsResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "List reports.", - "tags": [ - "reports", - "enterprise" - ] - }, - "post": { - "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports.admin:create`.", - "operationId": "createReport", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrUpdateConfigCmd" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/createReportResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Create a report.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/email": { - "post": { - "description": "Generate and send a report. This API waits for the report to be generated before returning. We recommend that you set the client’s timeout to at least 60 seconds. Available to org admins only and with a valid license.\n\nOnly available in Grafana Enterprise v7.0+.\nThis API endpoint is experimental and may be deprecated in a future release. On deprecation, a migration strategy will be provided and the endpoint will remain functional until the next major release of Grafana.\n\nYou need to have a permission with action `reports:send`.", - "operationId": "sendReport", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReportEmailDTO" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Send a report.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/render/pdf/{dashboardID}": { - "get": { - "deprecated": true, - "description": "Please refer to [reports enterprise](#/reports/renderReportPDFs) instead. This will be removed in Grafana 10.", - "operationId": "renderReportPDF", - "parameters": [ - { - "in": "path", - "name": "DashboardID", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "in": "path", - "name": "dashboardID", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "in": "query", - "name": "title", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "variables", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "from", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "to", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "orientation", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "layout", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/contentResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Render report for dashboard.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/render/pdfs": { - "get": { - "description": "Available to all users and with a valid license.", - "operationId": "renderReportPDFs", - "parameters": [ - { - "in": "query", - "name": "dashboardID", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "orientation", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "layout", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/contentResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Render report for multiple dashboards.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/settings": { - "get": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports.settings:read`x.", - "operationId": "getReportSettings", - "responses": { - "200": { - "$ref": "#/components/responses/getReportSettingsResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get settings.", - "tags": [ - "reports", - "enterprise" - ] - }, - "post": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports.settings:write`xx.", - "operationId": "saveReportSettings", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SettingsDTO" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Save settings.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/test-email": { - "post": { - "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports:send`.", - "operationId": "sendTestEmail", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrUpdateConfigCmd" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Send test report via email.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/reports/{id}": { - "delete": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports.delete` with scope `reports:id:\u003creport ID\u003e`.", - "operationId": "deleteReport", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Delete a report.", - "tags": [ - "reports", - "enterprise" - ] - }, - "get": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports:read` with scope `reports:id:\u003creport ID\u003e`.", - "operationId": "getReport", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getReportResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get a report.", - "tags": [ - "reports", - "enterprise" - ] - }, - "put": { - "description": "Available to org admins only and with a valid or expired license.\n\nYou need to have a permission with action `reports.admin:write` with scope `reports:id:\u003creport ID\u003e`.", - "operationId": "updateReport", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrUpdateConfigCmd" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Update a report.", - "tags": [ - "reports", - "enterprise" - ] - } - }, - "/saml/acs": { - "post": { - "operationId": "postACS", - "parameters": [ - { - "in": "query", - "name": "RelayState", - "schema": { - "type": "string" - } - } - ], - "responses": { - "302": { - "description": "(empty)" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "It performs assertion Consumer Service (ACS).", - "tags": [ - "saml", - "enterprise" - ] - } - }, - "/saml/metadata": { - "get": { - "operationId": "getMetadata", - "responses": { - "200": { - "$ref": "#/components/responses/contentResponse" - } - }, - "summary": "It exposes the SP (Grafana's) metadata for the IdP's consumption.", - "tags": [ - "saml", - "enterprise" - ] - } - }, - "/saml/slo": { - "get": { - "description": "There might be two possible requests:\n1. Logout response (callback) when Grafana initiates single logout and IdP returns response to logout request.\n2. Logout request when another SP initiates single logout and IdP sends logout request to the Grafana,\nor in case of IdP-initiated logout.", - "operationId": "getSLO", - "responses": { - "302": { - "description": "(empty)" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "It performs Single Logout (SLO) callback.", - "tags": [ - "saml", - "enterprise" - ] - }, - "post": { - "description": "There might be two possible requests:\n1. Logout response (callback) when Grafana initiates single logout and IdP returns response to logout request.\n2. Logout request when another SP initiates single logout and IdP sends logout request to the Grafana,\nor in case of IdP-initiated logout.", - "operationId": "postSLO", - "parameters": [ - { - "in": "query", - "name": "SAMLRequest", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "SAMLResponse", - "schema": { - "type": "string" - } - } - ], - "responses": { - "302": { - "description": "(empty)" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "It performs Single Logout (SLO) callback.", - "tags": [ - "saml", - "enterprise" - ] - } - }, "/search": { "get": { "operationId": "search", @@ -21076,193 +17993,6 @@ ] } }, - "/teams/{teamId}/groups": { - "delete": { - "operationId": "removeTeamGroupApiQuery", - "parameters": [ - { - "in": "query", - "name": "groupId", - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Remove External Group.", - "tags": [ - "sync_team_groups", - "enterprise" - ] - }, - "get": { - "operationId": "getTeamGroupsApi", - "parameters": [ - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getTeamGroupsApiResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get External Groups.", - "tags": [ - "sync_team_groups", - "enterprise" - ] - }, - "post": { - "operationId": "addTeamGroupApi", - "parameters": [ - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamGroupMapping" - } - } - }, - "required": true, - "x-originalParamName": "body" - }, - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Add External Group.", - "tags": [ - "sync_team_groups", - "enterprise" - ] - } - }, - "/teams/{teamId}/groups/{groupId}": { - "delete": { - "deprecated": true, - "operationId": "removeTeamGroupApi", - "parameters": [ - { - "in": "path", - "name": "groupId", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "path", - "name": "teamId", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "400": { - "$ref": "#/components/responses/badRequestError" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Remove External Group.", - "tags": [ - "sync_team_groups", - "enterprise" - ] - } - }, "/teams/{team_id}": { "delete": { "operationId": "deleteTeamByID",