Alerting: Move alerting RTKQ client to api-clients package (#114546)

This commit is contained in:
Gilles De Mey
2026-01-06 14:25:36 +00:00
committed by GitHub
parent 92464b2dc8
commit bbaf91ed9c
44 changed files with 324 additions and 623 deletions
+1 -2
View File
@@ -58,14 +58,12 @@
"bundle": "rollup -c rollup.config.ts --configPlugin esbuild",
"clean": "rimraf ./dist ./compiled ./unstable ./testing ./package.tgz",
"typecheck": "tsc --emitDeclarationOnly false --noEmit",
"codegen": "rtk-query-codegen-openapi ./scripts/codegen.ts",
"prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js",
"postpack": "mv package.json.bak package.json",
"i18n-extract": "i18next-cli extract --sync-primary"
},
"devDependencies": {
"@grafana/test-utils": "workspace:*",
"@rtk-query/codegen-openapi": "^2.0.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
@@ -96,6 +94,7 @@
"dependencies": {
"@emotion/css": "11.13.5",
"@faker-js/faker": "^9.8.0",
"@grafana/api-clients": "12.4.0-pre",
"@grafana/i18n": "12.4.0-pre",
"@reduxjs/toolkit": "^2.9.0",
"fishery": "^2.3.1",
@@ -1,23 +0,0 @@
# Re-generate the clients
⚠️ This guide assumes the Backend definitions have been updated in `apps/alerting`.
## Re-create OpenAPI specification
Start with re-generating the OpenAPI snapshots by running the test in `pkg/tests/apis/openapi_test.go`.
This will output the OpenAPI JSON spec file(s) in `pkg/tests/apis/openapi_snapshots`.
## Process OpenAPI specifications
Next up run the post-processing of the snapshots with `yarn run process-specs`, this will copy processed specifications to `./data/openapi/`.
## Generate RTKQ files
These files are built using the `yarn run codegen` command, make sure to run that in the Grafana Alerting package working directory.
`yarn --cwd ./packages/grafana-alerting run codegen`.
API clients will be written to `src/grafana/api/<version>/api.gen.ts`.
Make sure to create a versioned API client for each API version – see `src/grafana/api/v0alpha1/api.ts` as an example.
@@ -1,55 +0,0 @@
/**
* This script will generate TypeScript type definitions and a RTKQ clients for the alerting k8s APIs.
*
* Run `yarn run codegen` from the "grafana-alerting" package to invoke this script.
*
* API clients will be placed in "src/grafana/api/<version>/api.gen.ts"
*/
import type { ConfigFile } from '@rtk-query/codegen-openapi';
// ℹ️ append API groups and versions here to generate additional API clients
const SPECS = [
['notifications.alerting.grafana.app', ['v0alpha1']],
['rules.alerting.grafana.app', ['v0alpha1']],
// keep this in Grafana Enterprise
// ['alertenrichment.grafana.app', ['v1beta1']],
] as const;
type OutputFile = Omit<ConfigFile, 'outputFile'>;
type OutputFiles = Record<string, OutputFile>;
const outputFiles = SPECS.reduce<OutputFiles>((groupAcc, [group, versions]) => {
return versions.reduce<OutputFiles>((versionAcc, version) => {
// Create a unique export name based on the group
const groupName = group.split('.')[0]; // e.g., 'notifications', 'rules', 'alertenrichment'
const exportName = `${groupName}API`;
// ℹ️ these snapshots are generated by running "go test pkg/tests/apis/openapi_test.go" and "scripts/process-specs.ts",
// see the README in the "openapi_snapshots" directory
const schemaFile = `../../../data/openapi/${group}-${version}.json`;
// ℹ️ make sure there is a API file in each versioned directory
const apiFile = `../src/grafana/api/${groupName}/${version}/api.ts`;
// output each api client into a versioned directory with group-specific naming
const outputPath = `../src/grafana/api/${groupName}/${version}/${groupName}.api.gen.ts`;
versionAcc[outputPath] = {
exportName,
schemaFile,
apiFile,
tag: true, // generate tags for cache invalidation
} satisfies OutputFile;
return versionAcc;
}, groupAcc);
}, {});
export default {
// these are intentionally empty but will be set for each versioned config file
exportName: '',
schemaFile: '',
apiFile: '',
outputFiles,
} satisfies ConfigFile;
@@ -1,18 +0,0 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { getAPIBaseURL, getAPIReducerPath } from '../../util';
import { GROUP, VERSION } from './const';
const baseUrl = getAPIBaseURL(GROUP, VERSION);
const reducerPath = getAPIReducerPath(GROUP, VERSION);
export const api = createApi({
reducerPath,
baseQuery: fetchBaseQuery({
// Set URL correctly so MSW can intercept requests
// https://mswjs.io/docs/runbook#rtk-query-requests-are-not-intercepted
baseUrl: new URL(baseUrl, globalThis.location.origin).href,
}),
endpoints: () => ({}),
});
@@ -1,2 +0,0 @@
export const VERSION = 'v0alpha1' as const;
export const GROUP = 'notifications.alerting.grafana.app' as const;
@@ -1,8 +1,9 @@
import { faker } from '@faker-js/faker';
import { Factory } from 'fishery';
import { API_GROUP, API_VERSION } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { DEFAULT_NAMESPACE, generateResourceVersion, generateTitle, generateUID } from '../../../../../mocks/util';
import { GROUP, VERSION } from '../../const';
import {
ContactPoint,
ContactPointMetadataAnnotations,
@@ -14,7 +15,7 @@ import { AlertingEntityMetadataAnnotationsFactory } from './common';
export const ListReceiverApiResponseFactory = Factory.define<EnhancedListReceiverApiResponse>(() => ({
kind: 'ReceiverList',
apiVersion: `${GROUP}/${VERSION}`,
apiVersion: `${API_GROUP}/${API_VERSION}`,
metadata: {
resourceVersion: generateResourceVersion(),
},
@@ -26,7 +27,7 @@ export const ContactPointFactory = Factory.define<ContactPoint>(() => {
return {
kind: 'Receiver',
apiVersion: `${GROUP}/${VERSION}`,
apiVersion: `${API_GROUP}/${API_VERSION}`,
metadata: {
name: btoa(title),
namespace: DEFAULT_NAMESPACE,
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
CreateReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { CreateReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function createReceiverHandler(
data: CreateReceiverApiResponse | ((info: Parameters<Parameters<typeof http.post>[1]>[0]) => Response)
) {
return http.post(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) {
return http.post(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
DeleteReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { DeleteReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function deleteReceiverHandler(
data: DeleteReceiverApiResponse | ((info: Parameters<Parameters<typeof http.delete>[1]>[0]) => Response)
) {
return http.delete(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) {
return http.delete(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
DeletecollectionReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { DeletecollectionReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function deletecollectionReceiverHandler(
data: DeletecollectionReceiverApiResponse | ((info: Parameters<Parameters<typeof http.delete>[1]>[0]) => Response)
) {
return http.delete(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) {
return http.delete(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
GetReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { GetReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function getReceiverHandler(
data: GetReceiverApiResponse | ((info: Parameters<Parameters<typeof http.get>[1]>[0]) => Response)
) {
return http.get(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) {
return http.get(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,14 @@
import { HttpResponse, http } from 'msw';
import { API_GROUP, API_VERSION } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { GROUP, VERSION } from '../../../const';
import { EnhancedListReceiverApiResponse } from '../../../types';
export function listReceiverHandler(
data: EnhancedListReceiverApiResponse | ((info: Parameters<Parameters<typeof http.get>[1]>[0]) => Response)
) {
return http.get(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) {
return http.get(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
ReplaceReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { ReplaceReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function replaceReceiverHandler(
data: ReplaceReceiverApiResponse | ((info: Parameters<Parameters<typeof http.put>[1]>[0]) => Response)
) {
return http.put(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) {
return http.put(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -1,13 +1,17 @@
import { HttpResponse, http } from 'msw';
import {
API_GROUP,
API_VERSION,
UpdateReceiverApiResponse,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { getAPIBaseURLForMocks } from '../../../../../../mocks/util';
import { UpdateReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen';
import { GROUP, VERSION } from '../../../const';
export function updateReceiverHandler(
data: UpdateReceiverApiResponse | ((info: Parameters<Parameters<typeof http.patch>[1]>[0]) => Response)
) {
return http.patch(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) {
return http.patch(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) {
if (typeof data === 'function') {
return data(info);
}
@@ -3,7 +3,11 @@
*/
import { MergeDeep, MergeExclusive, OverrideProperties } from 'type-fest';
import type { ListReceiverApiResponse, Receiver, ReceiverIntegration } from './notifications.api.gen';
import type {
ListReceiverApiResponse,
Receiver,
ReceiverIntegration,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
type GenericIntegration = OverrideProperties<
ReceiverIntegration,
@@ -1,18 +0,0 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { getAPIBaseURL, getAPIReducerPath } from '../../util';
import { GROUP, VERSION } from './const';
const baseUrl = getAPIBaseURL(GROUP, VERSION);
const reducerPath = getAPIReducerPath(GROUP, VERSION);
export const api = createApi({
reducerPath,
baseQuery: fetchBaseQuery({
// Set URL correctly so MSW can intercept requests
// https://mswjs.io/docs/runbook#rtk-query-requests-are-not-intercepted
baseUrl: new URL(baseUrl, globalThis.location.origin).href,
}),
endpoints: () => ({}),
});
@@ -1,2 +0,0 @@
export const VERSION = 'v0alpha1' as const;
export const GROUP = 'rules.alerting.grafana.app' as const;
@@ -7,9 +7,10 @@ import { OverrideProperties } from 'type-fest';
import {
CreateReceiverApiArg,
type ListReceiverApiArg,
notificationsAPI,
} from '../../../api/notifications/v0alpha1/notifications.api.gen';
ListReceiverApiArg,
generatedAPI as notificationsAPIv0alpha1,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import type { ContactPoint, EnhancedListReceiverApiResponse } from '../../../api/notifications/v0alpha1/types';
// this is a workaround for the fact that the generated types are not narrow enough
@@ -22,17 +23,17 @@ type ListContactPointsHookResult = TypedUseQueryHookResult<
// Type for the options that can be passed to the hook
// Based on the pattern used for mutation options in this file
type ListContactPointsQueryArgs = Parameters<
typeof notificationsAPI.endpoints.listReceiver.useQuery<ListContactPointsHookResult>
typeof notificationsAPIv0alpha1.endpoints.listReceiver.useQuery<ListContactPointsHookResult>
>[0];
type ListContactPointsQueryOptions = Parameters<
typeof notificationsAPI.endpoints.listReceiver.useQuery<ListContactPointsHookResult>
typeof notificationsAPIv0alpha1.endpoints.listReceiver.useQuery<ListContactPointsHookResult>
>[1];
/**
* useListContactPoints is a hook that fetches a list of contact points
*
* This function wraps the notificationsAPI.useListReceiverQuery with proper typing
* This function wraps the notificationsAPIv0alpha1.useListReceiverQuery with proper typing
* to ensure that the returned ContactPoints are correctly typed in the data.items array.
*
* It automatically uses the configured namespace for the query.
@@ -43,8 +44,8 @@ type ListContactPointsQueryOptions = Parameters<
export function useListContactPoints(
queryArgs: ListContactPointsQueryArgs = {},
queryOptions: ListContactPointsQueryOptions = {}
) {
return notificationsAPI.useListReceiverQuery<ListContactPointsHookResult>(queryArgs, queryOptions);
): ListContactPointsHookResult {
return notificationsAPIv0alpha1.useListReceiverQuery<ListContactPointsHookResult>(queryArgs, queryOptions);
}
// type narrowing mutations requires us to define a few helper types
@@ -60,7 +61,7 @@ type CreateContactPointMutation = TypedUseMutationResult<
>;
type UseCreateContactPointOptions = Parameters<
typeof notificationsAPI.endpoints.createReceiver.useMutation<CreateContactPointMutation>
typeof notificationsAPIv0alpha1.endpoints.createReceiver.useMutation<CreateContactPointMutation>
>[0];
/**
@@ -69,8 +70,16 @@ type UseCreateContactPointOptions = Parameters<
* This function wraps the notificationsAPI.useCreateReceiverMutation with proper typing
* to ensure that the payload supports type narrowing.
*/
export function useCreateContactPoint(options?: UseCreateContactPointOptions) {
const [updateFn, result] = notificationsAPI.endpoints.createReceiver.useMutation<CreateContactPointMutation>(options);
export function useCreateContactPoint(
options?: UseCreateContactPointOptions
): readonly [
(
args: CreateContactPointArgs
) => ReturnType<ReturnType<typeof notificationsAPIv0alpha1.endpoints.createReceiver.useMutation>[0]>,
ReturnType<typeof notificationsAPIv0alpha1.endpoints.createReceiver.useMutation<CreateContactPointMutation>>[1],
] {
const [updateFn, result] =
notificationsAPIv0alpha1.endpoints.createReceiver.useMutation<CreateContactPointMutation>(options);
const typedUpdateFn = (args: CreateContactPointArgs) => {
// @ts-expect-error this one is just impossible for me to figure out
@@ -1,6 +1,7 @@
import { countBy, isEmpty } from 'lodash';
import { Receiver } from '../api/notifications/v0alpha1/notifications.api.gen';
import { Receiver } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { ContactPoint } from '../api/notifications/v0alpha1/types';
/**
@@ -1,4 +1,4 @@
import { RoutingTreeMatcher } from '../api/notifications/v0alpha1/notifications.api.gen';
import { RoutingTreeMatcher } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
export type Label = [string, string];
@@ -1,6 +1,6 @@
import { VERSION } from '../../api/notifications/v0alpha1/const';
import { API_VERSION, RoutingTree } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { LabelMatcherFactory, RouteFactory } from '../../api/notifications/v0alpha1/mocks/fakes/Routes';
import { RoutingTree } from '../../api/notifications/v0alpha1/notifications.api.gen';
import { Label } from '../../matchers/types';
import { matchInstancesToRouteTrees } from './useMatchPolicies';
@@ -16,7 +16,7 @@ describe('matchInstancesToRouteTrees', () => {
const trees: RoutingTree[] = [
{
kind: 'RoutingTree',
apiVersion: VERSION,
apiVersion: API_VERSION,
metadata: { name: treeName },
spec: {
defaults: {
@@ -24,7 +24,6 @@ describe('matchInstancesToRouteTrees', () => {
},
routes: [route],
},
status: {},
},
];
@@ -51,7 +50,7 @@ describe('matchInstancesToRouteTrees', () => {
const trees: RoutingTree[] = [
{
kind: 'RoutingTree',
apiVersion: VERSION,
apiVersion: API_VERSION,
metadata: { name: treeName },
spec: {
defaults: {
@@ -59,7 +58,6 @@ describe('matchInstancesToRouteTrees', () => {
},
routes: [route],
},
status: {},
},
];
@@ -1,6 +1,10 @@
import { useCallback } from 'react';
import { RoutingTree, notificationsAPI } from '../../api/notifications/v0alpha1/notifications.api.gen';
import {
RoutingTree,
generatedAPI as notificationsAPIv0alpha1,
} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { Label } from '../../matchers/types';
import { USER_DEFINED_TREE_NAME } from '../consts';
import { Route, RouteWithID } from '../types';
@@ -24,6 +28,11 @@ export type InstanceMatchResult = {
matchedRoutes: RouteMatch[];
};
interface UseMatchInstancesToRouteTreesReturnType
extends ReturnType<typeof notificationsAPIv0alpha1.endpoints.listRoutingTree.useQuery> {
matchInstancesToRouteTrees: (instances: Label[][]) => InstanceMatchResult[];
}
/**
* React hook that finds notification policy routes in all routing trees that match the provided set of alert instances.
*
@@ -35,8 +44,8 @@ export type InstanceMatchResult = {
* @returns An object containing a `matchInstancesToRoutingTrees` function that takes alert instances
* and returns an array of InstanceMatchResult objects, each containing the matched routes and matching details
*/
export function useMatchInstancesToRouteTrees() {
const { data, ...rest } = notificationsAPI.endpoints.listRoutingTree.useQuery(
export function useMatchInstancesToRouteTrees(): UseMatchInstancesToRouteTreesReturnType {
const { data, ...rest } = notificationsAPIv0alpha1.endpoints.listRoutingTree.useQuery(
{},
{
refetchOnFocus: true,
@@ -1,6 +1,7 @@
import { OverrideProperties } from 'type-fest';
import { RoutingTreeRoute } from '../api/notifications/v0alpha1/notifications.api.gen';
import { RoutingTreeRoute } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { LabelMatcher } from '../matchers/types';
// type-narrow the route tree
@@ -1,6 +1,7 @@
import { groupBy, isArray, pick, reduce, uniqueId } from 'lodash';
import { RoutingTree, RoutingTreeRoute } from '../api/notifications/v0alpha1/notifications.api.gen';
import { RoutingTree, RoutingTreeRoute } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { Label } from '../matchers/types';
import { LabelMatchDetails, matchLabels } from '../matchers/utils';
+2 -2
View File
@@ -19,5 +19,5 @@ export { type LabelMatcher, type Label } from './grafana/matchers/types';
export { matchLabelsSet, matchLabels, isLabelMatch, type LabelMatchDetails } from './grafana/matchers/utils';
// API endpoints
export { notificationsAPI as notificationsAPIv0alpha1 } from './grafana/api/notifications/v0alpha1/notifications.api.gen';
export { rulesAPI as rulesAPIv0alpha1 } from './grafana/api/rules/v0alpha1/rules.api.gen';
export { generatedAPI as notificationsAPIv0alpha1 } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
export { generatedAPI as rulesAPIv0alpha1 } from '@grafana/api-clients/rtkq/rules.alerting/v0alpha1';
+15 -3
View File
@@ -2,13 +2,25 @@ import { configureStore } from '@reduxjs/toolkit';
import { useEffect } from 'react';
import { Provider } from 'react-redux';
import { notificationsAPIv0alpha1 } from '../src/unstable';
import { MockBackendSrv } from '@grafana/api-clients';
import { generatedAPI as notificationsAPIv0alpha1 } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';
import { generatedAPI as rulesAPIv0alpha1 } from '@grafana/api-clients/rtkq/rules.alerting/v0alpha1';
import { setBackendSrv } from '@grafana/runtime';
// Initialize BackendSrv for tests - this allows RTKQ to make HTTP requests
// The actual HTTP requests will be intercepted by MSW (setupMockServer)
// We only need to implement fetch() which is what RTKQ uses
// we could remove this once @grafana/api-client no longer uses the BackendSrv
// @ts-ignore
setBackendSrv(new MockBackendSrv());
// create an empty store
export const store = configureStore({
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(notificationsAPIv0alpha1.middleware),
export const store: ReturnType<typeof configureStore> = configureStore({
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(notificationsAPIv0alpha1.middleware).concat(rulesAPIv0alpha1.middleware),
reducer: {
[notificationsAPIv0alpha1.reducerPath]: notificationsAPIv0alpha1.reducer,
[rulesAPIv0alpha1.reducerPath]: rulesAPIv0alpha1.reducer,
},
});
@@ -13,7 +13,14 @@ import '@testing-library/jest-dom';
* method which wraps the passed element in all of the necessary Providers,
* so it can render correctly in the context of the application
*/
const customRender = (ui: React.ReactNode, renderOptions: RenderOptions = {}) => {
const customRender = (
ui: React.ReactNode,
renderOptions: RenderOptions = {}
): {
renderResult: ReturnType<typeof render>;
user: ReturnType<typeof userEvent.setup>;
store: typeof store;
} => {
const user = userEvent.setup();
const Providers = renderOptions.wrapper || getDefaultWrapper();
@@ -116,6 +116,14 @@
"import": "./dist/esm/clients/rtkq/shorturl/v1beta1/index.mjs",
"require": "./dist/cjs/clients/rtkq/shorturl/v1beta1/index.cjs"
},
"./rtkq/notifications.alerting/v0alpha1": {
"import": "./src/clients/rtkq/notifications.alerting/v0alpha1/index.ts",
"require": "./src/clients/rtkq/notifications.alerting/v0alpha1/index.ts"
},
"./rtkq/rules.alerting/v0alpha1": {
"import": "./src/clients/rtkq/rules.alerting/v0alpha1/index.ts",
"require": "./src/clients/rtkq/rules.alerting/v0alpha1/index.ts"
},
"./rtkq/historian.alerting/v0alpha1": {
"@grafana-app/source": "./src/clients/rtkq/historian.alerting/v0alpha1/index.ts",
"types": "./dist/types/clients/rtkq/historian.alerting/v0alpha1/index.d.ts",
@@ -10,10 +10,12 @@ import { generatedAPI as historianAlertingAPIv0alpha1 } from './historian.alerti
import { generatedAPI as iamAPIv0alpha1 } from './iam/v0alpha1';
import { generatedAPI as logsdrilldownAPIv1alpha1 } from './logsdrilldown/v1alpha1';
import { generatedAPI as migrateToCloudAPI } from './migrate-to-cloud';
import { generatedAPI as notificationsAlertingAPIv0alpha1 } from './notifications.alerting/v0alpha1';
import { generatedAPI as playlistAPIv0alpha1 } from './playlist/v0alpha1';
import { generatedAPI as preferencesUserAPI } from './preferences/user';
import { generatedAPI as preferencesAPIv1alpha1 } from './preferences/v1alpha1';
import { generatedAPI as provisioningAPIv0alpha1 } from './provisioning/v0alpha1';
import { generatedAPI as rulesAlertingAPIv0alpha1 } from './rules.alerting/v0alpha1';
import { generatedAPI as shortURLAPIv1beta1 } from './shorturl/v1beta1';
import { generatedAPI as legacyUserAPI } from './user';
// PLOP_INJECT_IMPORT
@@ -33,6 +35,8 @@ export const allMiddleware = [
shortURLAPIv1beta1.middleware,
correlationsAPIv0alpha1.middleware,
legacyUserAPI.middleware,
notificationsAlertingAPIv0alpha1.middleware,
rulesAlertingAPIv0alpha1.middleware,
historianAlertingAPIv0alpha1.middleware,
logsdrilldownAPIv1alpha1.middleware,
// PLOP_INJECT_MIDDLEWARE
@@ -53,6 +57,8 @@ export const allReducers = {
[shortURLAPIv1beta1.reducerPath]: shortURLAPIv1beta1.reducer,
[correlationsAPIv0alpha1.reducerPath]: correlationsAPIv0alpha1.reducer,
[legacyUserAPI.reducerPath]: legacyUserAPI.reducer,
[notificationsAlertingAPIv0alpha1.reducerPath]: notificationsAlertingAPIv0alpha1.reducer,
[rulesAlertingAPIv0alpha1.reducerPath]: rulesAlertingAPIv0alpha1.reducer,
[historianAlertingAPIv0alpha1.reducerPath]: historianAlertingAPIv0alpha1.reducer,
[logsdrilldownAPIv1alpha1.reducerPath]: logsdrilldownAPIv1alpha1.reducer,
// PLOP_INJECT_REDUCER
@@ -0,0 +1,16 @@
import { createApi } from '@reduxjs/toolkit/query/react';
import { getAPIBaseURL } from '../../../../utils/utils';
import { createBaseQuery } from '../../createBaseQuery';
export const API_GROUP = 'notifications.alerting.grafana.app' as const;
export const API_VERSION = 'v0alpha1' as const;
export const BASE_URL = getAPIBaseURL(API_GROUP, API_VERSION);
export const api = createApi({
reducerPath: 'notificationsAlertingAPIv0alpha1',
baseQuery: createBaseQuery({
baseURL: BASE_URL,
}),
endpoints: () => ({}),
});
@@ -1,4 +1,4 @@
import { api } from './api';
import { api } from './baseAPI';
export const addTagTypes = ['API Discovery', 'Receiver', 'RoutingTree', 'TemplateGroup', 'TimeInterval'] as const;
const injectedRtkApi = api
.enhanceEndpoints({
@@ -7,7 +7,7 @@ const injectedRtkApi = api
.injectEndpoints({
endpoints: (build) => ({
getApiResources: build.query<GetApiResourcesApiResponse, GetApiResourcesApiArg>({
query: () => ({ url: `/apis/notifications.alerting.grafana.app/v0alpha1/` }),
query: () => ({ url: `/` }),
providesTags: ['API Discovery'],
}),
listReceiver: build.query<ListReceiverApiResponse, ListReceiverApiArg>({
@@ -119,44 +119,6 @@ const injectedRtkApi = api
}),
invalidatesTags: ['Receiver'],
}),
getReceiverStatus: build.query<GetReceiverStatusApiResponse, GetReceiverStatusApiArg>({
query: (queryArg) => ({
url: `/receivers/${queryArg.name}/status`,
params: {
pretty: queryArg.pretty,
},
}),
providesTags: ['Receiver'],
}),
replaceReceiverStatus: build.mutation<ReplaceReceiverStatusApiResponse, ReplaceReceiverStatusApiArg>({
query: (queryArg) => ({
url: `/receivers/${queryArg.name}/status`,
method: 'PUT',
body: queryArg.receiver,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
},
}),
invalidatesTags: ['Receiver'],
}),
updateReceiverStatus: build.mutation<UpdateReceiverStatusApiResponse, UpdateReceiverStatusApiArg>({
query: (queryArg) => ({
url: `/receivers/${queryArg.name}/status`,
method: 'PATCH',
body: queryArg.patch,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
force: queryArg.force,
},
}),
invalidatesTags: ['Receiver'],
}),
listRoutingTree: build.query<ListRoutingTreeApiResponse, ListRoutingTreeApiArg>({
query: (queryArg) => ({
url: `/routingtrees`,
@@ -269,44 +231,6 @@ const injectedRtkApi = api
}),
invalidatesTags: ['RoutingTree'],
}),
getRoutingTreeStatus: build.query<GetRoutingTreeStatusApiResponse, GetRoutingTreeStatusApiArg>({
query: (queryArg) => ({
url: `/routingtrees/${queryArg.name}/status`,
params: {
pretty: queryArg.pretty,
},
}),
providesTags: ['RoutingTree'],
}),
replaceRoutingTreeStatus: build.mutation<ReplaceRoutingTreeStatusApiResponse, ReplaceRoutingTreeStatusApiArg>({
query: (queryArg) => ({
url: `/routingtrees/${queryArg.name}/status`,
method: 'PUT',
body: queryArg.routingTree,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
},
}),
invalidatesTags: ['RoutingTree'],
}),
updateRoutingTreeStatus: build.mutation<UpdateRoutingTreeStatusApiResponse, UpdateRoutingTreeStatusApiArg>({
query: (queryArg) => ({
url: `/routingtrees/${queryArg.name}/status`,
method: 'PATCH',
body: queryArg.patch,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
force: queryArg.force,
},
}),
invalidatesTags: ['RoutingTree'],
}),
listTemplateGroup: build.query<ListTemplateGroupApiResponse, ListTemplateGroupApiArg>({
query: (queryArg) => ({
url: `/templategroups`,
@@ -419,47 +343,6 @@ const injectedRtkApi = api
}),
invalidatesTags: ['TemplateGroup'],
}),
getTemplateGroupStatus: build.query<GetTemplateGroupStatusApiResponse, GetTemplateGroupStatusApiArg>({
query: (queryArg) => ({
url: `/templategroups/${queryArg.name}/status`,
params: {
pretty: queryArg.pretty,
},
}),
providesTags: ['TemplateGroup'],
}),
replaceTemplateGroupStatus: build.mutation<
ReplaceTemplateGroupStatusApiResponse,
ReplaceTemplateGroupStatusApiArg
>({
query: (queryArg) => ({
url: `/templategroups/${queryArg.name}/status`,
method: 'PUT',
body: queryArg.templateGroup,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
},
}),
invalidatesTags: ['TemplateGroup'],
}),
updateTemplateGroupStatus: build.mutation<UpdateTemplateGroupStatusApiResponse, UpdateTemplateGroupStatusApiArg>({
query: (queryArg) => ({
url: `/templategroups/${queryArg.name}/status`,
method: 'PATCH',
body: queryArg.patch,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
force: queryArg.force,
},
}),
invalidatesTags: ['TemplateGroup'],
}),
listTimeInterval: build.query<ListTimeIntervalApiResponse, ListTimeIntervalApiArg>({
query: (queryArg) => ({
url: `/timeintervals`,
@@ -572,48 +455,10 @@ const injectedRtkApi = api
}),
invalidatesTags: ['TimeInterval'],
}),
getTimeIntervalStatus: build.query<GetTimeIntervalStatusApiResponse, GetTimeIntervalStatusApiArg>({
query: (queryArg) => ({
url: `/timeintervals/${queryArg.name}/status`,
params: {
pretty: queryArg.pretty,
},
}),
providesTags: ['TimeInterval'],
}),
replaceTimeIntervalStatus: build.mutation<ReplaceTimeIntervalStatusApiResponse, ReplaceTimeIntervalStatusApiArg>({
query: (queryArg) => ({
url: `/timeintervals/${queryArg.name}/status`,
method: 'PUT',
body: queryArg.timeInterval,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
},
}),
invalidatesTags: ['TimeInterval'],
}),
updateTimeIntervalStatus: build.mutation<UpdateTimeIntervalStatusApiResponse, UpdateTimeIntervalStatusApiArg>({
query: (queryArg) => ({
url: `/timeintervals/${queryArg.name}/status`,
method: 'PATCH',
body: queryArg.patch,
params: {
pretty: queryArg.pretty,
dryRun: queryArg.dryRun,
fieldManager: queryArg.fieldManager,
fieldValidation: queryArg.fieldValidation,
force: queryArg.force,
},
}),
invalidatesTags: ['TimeInterval'],
}),
}),
overrideExisting: false,
});
export { injectedRtkApi as notificationsAPI };
export { injectedRtkApi as generatedAPI };
export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList;
export type GetApiResourcesApiArg = void;
export type ListReceiverApiResponse = /** status 200 OK */ ReceiverList;
@@ -781,43 +626,6 @@ export type UpdateReceiverApiArg = {
force?: boolean;
patch: Patch;
};
export type GetReceiverStatusApiResponse = /** status 200 OK */ Receiver;
export type GetReceiverStatusApiArg = {
/** name of the Receiver */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
};
export type ReplaceReceiverStatusApiResponse = /** status 200 OK */ Receiver | /** status 201 Created */ Receiver;
export type ReplaceReceiverStatusApiArg = {
/** name of the Receiver */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
receiver: Receiver;
};
export type UpdateReceiverStatusApiResponse = /** status 200 OK */ Receiver | /** status 201 Created */ Receiver;
export type UpdateReceiverStatusApiArg = {
/** name of the Receiver */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
/** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */
force?: boolean;
patch: Patch;
};
export type ListRoutingTreeApiResponse = /** status 200 OK */ RoutingTreeList;
export type ListRoutingTreeApiArg = {
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
@@ -983,47 +791,6 @@ export type UpdateRoutingTreeApiArg = {
force?: boolean;
patch: Patch;
};
export type GetRoutingTreeStatusApiResponse = /** status 200 OK */ RoutingTree;
export type GetRoutingTreeStatusApiArg = {
/** name of the RoutingTree */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
};
export type ReplaceRoutingTreeStatusApiResponse = /** status 200 OK */
| RoutingTree
| /** status 201 Created */ RoutingTree;
export type ReplaceRoutingTreeStatusApiArg = {
/** name of the RoutingTree */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
routingTree: RoutingTree;
};
export type UpdateRoutingTreeStatusApiResponse = /** status 200 OK */
| RoutingTree
| /** status 201 Created */ RoutingTree;
export type UpdateRoutingTreeStatusApiArg = {
/** name of the RoutingTree */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
/** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */
force?: boolean;
patch: Patch;
};
export type ListTemplateGroupApiResponse = /** status 200 OK */ TemplateGroupList;
export type ListTemplateGroupApiArg = {
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
@@ -1193,47 +960,6 @@ export type UpdateTemplateGroupApiArg = {
force?: boolean;
patch: Patch;
};
export type GetTemplateGroupStatusApiResponse = /** status 200 OK */ TemplateGroup;
export type GetTemplateGroupStatusApiArg = {
/** name of the TemplateGroup */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
};
export type ReplaceTemplateGroupStatusApiResponse = /** status 200 OK */
| TemplateGroup
| /** status 201 Created */ TemplateGroup;
export type ReplaceTemplateGroupStatusApiArg = {
/** name of the TemplateGroup */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
templateGroup: TemplateGroup;
};
export type UpdateTemplateGroupStatusApiResponse = /** status 200 OK */
| TemplateGroup
| /** status 201 Created */ TemplateGroup;
export type UpdateTemplateGroupStatusApiArg = {
/** name of the TemplateGroup */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
/** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */
force?: boolean;
patch: Patch;
};
export type ListTimeIntervalApiResponse = /** status 200 OK */ TimeIntervalList;
export type ListTimeIntervalApiArg = {
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
@@ -1399,47 +1125,6 @@ export type UpdateTimeIntervalApiArg = {
force?: boolean;
patch: Patch;
};
export type GetTimeIntervalStatusApiResponse = /** status 200 OK */ TimeInterval;
export type GetTimeIntervalStatusApiArg = {
/** name of the TimeInterval */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
};
export type ReplaceTimeIntervalStatusApiResponse = /** status 200 OK */
| TimeInterval
| /** status 201 Created */ TimeInterval;
export type ReplaceTimeIntervalStatusApiArg = {
/** name of the TimeInterval */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
timeInterval: TimeInterval;
};
export type UpdateTimeIntervalStatusApiResponse = /** status 200 OK */
| TimeInterval
| /** status 201 Created */ TimeInterval;
export type UpdateTimeIntervalStatusApiArg = {
/** name of the TimeInterval */
name: string;
/** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */
pretty?: string;
/** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */
dryRun?: string;
/** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */
fieldManager?: string;
/** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */
fieldValidation?: string;
/** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */
force?: boolean;
patch: Patch;
};
export type ApiResource = {
/** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */
categories?: string[];
@@ -1572,34 +1257,6 @@ export type ReceiverSpec = {
integrations: ReceiverIntegration[];
title: string;
};
export type ReceiverOperatorState = {
/** descriptiveState is an optional more descriptive state field which has no requirements on format */
descriptiveState?: string;
/** details contains any extra information that is operator-specific */
details?: {
[key: string]: {
[key: string]: any;
};
};
/** lastEvaluation is the ResourceVersion last evaluated */
lastEvaluation: string;
/** state describes the state of the lastEvaluation.
It is limited to three possible states for machine evaluation. */
state: 'success' | 'in_progress' | 'failed';
};
export type ReceiverStatus = {
/** additionalFields is reserved for future use */
additionalFields?: {
[key: string]: {
[key: string]: any;
};
};
/** operatorStates is a map of operator ID to operator state evaluations.
Any operator which consumes this kind SHOULD add its state evaluation information to this field. */
operatorStates?: {
[key: string]: ReceiverOperatorState;
};
};
export type Receiver = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
apiVersion: string;
@@ -1607,7 +1264,6 @@ export type Receiver = {
kind: string;
metadata: ObjectMeta;
spec: ReceiverSpec;
status?: ReceiverStatus;
};
export type ListMeta = {
/** continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. */
@@ -1700,34 +1356,6 @@ export type RoutingTreeSpec = {
defaults: RoutingTreeRouteDefaults;
routes: RoutingTreeRoute[];
};
export type RoutingTreeOperatorState = {
/** descriptiveState is an optional more descriptive state field which has no requirements on format */
descriptiveState?: string;
/** details contains any extra information that is operator-specific */
details?: {
[key: string]: {
[key: string]: any;
};
};
/** lastEvaluation is the ResourceVersion last evaluated */
lastEvaluation: string;
/** state describes the state of the lastEvaluation.
It is limited to three possible states for machine evaluation. */
state: 'success' | 'in_progress' | 'failed';
};
export type RoutingTreeStatus = {
/** additionalFields is reserved for future use */
additionalFields?: {
[key: string]: {
[key: string]: any;
};
};
/** operatorStates is a map of operator ID to operator state evaluations.
Any operator which consumes this kind SHOULD add its state evaluation information to this field. */
operatorStates?: {
[key: string]: RoutingTreeOperatorState;
};
};
export type RoutingTree = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
apiVersion: string;
@@ -1735,7 +1363,6 @@ export type RoutingTree = {
kind: string;
metadata: ObjectMeta;
spec: RoutingTreeSpec;
status?: RoutingTreeStatus;
};
export type RoutingTreeList = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
@@ -1745,38 +1372,12 @@ export type RoutingTreeList = {
kind?: string;
metadata: ListMeta;
};
export type TemplateGroupTemplateKind = 'grafana' | 'mimir';
export type TemplateGroupSpec = {
content: string;
kind: TemplateGroupTemplateKind;
title: string;
};
export type TemplateGroupOperatorState = {
/** descriptiveState is an optional more descriptive state field which has no requirements on format */
descriptiveState?: string;
/** details contains any extra information that is operator-specific */
details?: {
[key: string]: {
[key: string]: any;
};
};
/** lastEvaluation is the ResourceVersion last evaluated */
lastEvaluation: string;
/** state describes the state of the lastEvaluation.
It is limited to three possible states for machine evaluation. */
state: 'success' | 'in_progress' | 'failed';
};
export type TemplateGroupStatus = {
/** additionalFields is reserved for future use */
additionalFields?: {
[key: string]: {
[key: string]: any;
};
};
/** operatorStates is a map of operator ID to operator state evaluations.
Any operator which consumes this kind SHOULD add its state evaluation information to this field. */
operatorStates?: {
[key: string]: TemplateGroupOperatorState;
};
};
export type TemplateGroup = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
apiVersion: string;
@@ -1784,7 +1385,6 @@ export type TemplateGroup = {
kind: string;
metadata: ObjectMeta;
spec: TemplateGroupSpec;
status?: TemplateGroupStatus;
};
export type TemplateGroupList = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
@@ -1810,34 +1410,6 @@ export type TimeIntervalSpec = {
name: string;
time_intervals: TimeIntervalInterval[];
};
export type TimeIntervalOperatorState = {
/** descriptiveState is an optional more descriptive state field which has no requirements on format */
descriptiveState?: string;
/** details contains any extra information that is operator-specific */
details?: {
[key: string]: {
[key: string]: any;
};
};
/** lastEvaluation is the ResourceVersion last evaluated */
lastEvaluation: string;
/** state describes the state of the lastEvaluation.
It is limited to three possible states for machine evaluation. */
state: 'success' | 'in_progress' | 'failed';
};
export type TimeIntervalStatus = {
/** additionalFields is reserved for future use */
additionalFields?: {
[key: string]: {
[key: string]: any;
};
};
/** operatorStates is a map of operator ID to operator state evaluations.
Any operator which consumes this kind SHOULD add its state evaluation information to this field. */
operatorStates?: {
[key: string]: TimeIntervalOperatorState;
};
};
export type TimeInterval = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
apiVersion: string;
@@ -1845,7 +1417,6 @@ export type TimeInterval = {
kind: string;
metadata: ObjectMeta;
spec: TimeIntervalSpec;
status?: TimeIntervalStatus;
};
export type TimeIntervalList = {
/** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */
@@ -1855,3 +1426,43 @@ export type TimeIntervalList = {
kind?: string;
metadata: ListMeta;
};
export const {
useGetApiResourcesQuery,
useLazyGetApiResourcesQuery,
useListReceiverQuery,
useLazyListReceiverQuery,
useCreateReceiverMutation,
useDeletecollectionReceiverMutation,
useGetReceiverQuery,
useLazyGetReceiverQuery,
useReplaceReceiverMutation,
useDeleteReceiverMutation,
useUpdateReceiverMutation,
useListRoutingTreeQuery,
useLazyListRoutingTreeQuery,
useCreateRoutingTreeMutation,
useDeletecollectionRoutingTreeMutation,
useGetRoutingTreeQuery,
useLazyGetRoutingTreeQuery,
useReplaceRoutingTreeMutation,
useDeleteRoutingTreeMutation,
useUpdateRoutingTreeMutation,
useListTemplateGroupQuery,
useLazyListTemplateGroupQuery,
useCreateTemplateGroupMutation,
useDeletecollectionTemplateGroupMutation,
useGetTemplateGroupQuery,
useLazyGetTemplateGroupQuery,
useReplaceTemplateGroupMutation,
useDeleteTemplateGroupMutation,
useUpdateTemplateGroupMutation,
useListTimeIntervalQuery,
useLazyListTimeIntervalQuery,
useCreateTimeIntervalMutation,
useDeletecollectionTimeIntervalMutation,
useGetTimeIntervalQuery,
useLazyGetTimeIntervalQuery,
useReplaceTimeIntervalMutation,
useDeleteTimeIntervalMutation,
useUpdateTimeIntervalMutation,
} = injectedRtkApi;
@@ -0,0 +1,5 @@
export { BASE_URL, API_GROUP, API_VERSION } from './baseAPI';
import { generatedAPI as rawAPI } from './endpoints.gen';
export * from './endpoints.gen';
export const generatedAPI = rawAPI.enhanceEndpoints({});
@@ -0,0 +1,16 @@
import { createApi } from '@reduxjs/toolkit/query/react';
import { getAPIBaseURL } from '../../../../utils/utils';
import { createBaseQuery } from '../../createBaseQuery';
export const API_GROUP = 'rules.alerting.grafana.app' as const;
export const API_VERSION = 'v0alpha1' as const;
export const BASE_URL = getAPIBaseURL(API_GROUP, API_VERSION);
export const api = createApi({
reducerPath: 'rulesAlertingAPIv0alpha1',
baseQuery: createBaseQuery({
baseURL: BASE_URL,
}),
endpoints: () => ({}),
});
@@ -1,4 +1,4 @@
import { api } from './api';
import { api } from './baseAPI';
export const addTagTypes = ['API Discovery', 'AlertRule', 'RecordingRule'] as const;
const injectedRtkApi = api
.enhanceEndpoints({
@@ -7,7 +7,7 @@ const injectedRtkApi = api
.injectEndpoints({
endpoints: (build) => ({
getApiResources: build.query<GetApiResourcesApiResponse, GetApiResourcesApiArg>({
query: () => ({ url: `/apis/rules.alerting.grafana.app/v0alpha1/` }),
query: () => ({ url: `/` }),
providesTags: ['API Discovery'],
}),
listAlertRule: build.query<ListAlertRuleApiResponse, ListAlertRuleApiArg>({
@@ -313,7 +313,7 @@ const injectedRtkApi = api
}),
overrideExisting: false,
});
export { injectedRtkApi as rulesAPI };
export { injectedRtkApi as generatedAPI };
export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList;
export type GetApiResourcesApiArg = void;
export type ListAlertRuleApiResponse = /** status 200 OK */ AlertRuleList;
@@ -1085,3 +1085,33 @@ export type RecordingRuleList = {
kind?: string;
metadata: ListMeta;
};
export const {
useGetApiResourcesQuery,
useLazyGetApiResourcesQuery,
useListAlertRuleQuery,
useLazyListAlertRuleQuery,
useCreateAlertRuleMutation,
useDeletecollectionAlertRuleMutation,
useGetAlertRuleQuery,
useLazyGetAlertRuleQuery,
useReplaceAlertRuleMutation,
useDeleteAlertRuleMutation,
useUpdateAlertRuleMutation,
useGetAlertRuleStatusQuery,
useLazyGetAlertRuleStatusQuery,
useReplaceAlertRuleStatusMutation,
useUpdateAlertRuleStatusMutation,
useListRecordingRuleQuery,
useLazyListRecordingRuleQuery,
useCreateRecordingRuleMutation,
useDeletecollectionRecordingRuleMutation,
useGetRecordingRuleQuery,
useLazyGetRecordingRuleQuery,
useReplaceRecordingRuleMutation,
useDeleteRecordingRuleMutation,
useUpdateRecordingRuleMutation,
useGetRecordingRuleStatusQuery,
useLazyGetRecordingRuleStatusQuery,
useReplaceRecordingRuleStatusMutation,
useUpdateRecordingRuleStatusMutation,
} = injectedRtkApi;
@@ -0,0 +1,5 @@
export { BASE_URL, API_GROUP, API_VERSION } from './baseAPI';
import { generatedAPI as rawAPI } from './endpoints.gen';
export * from './endpoints.gen';
export const generatedAPI = rawAPI.enhanceEndpoints({});
@@ -1 +1,4 @@
export { getAPINamespace, getAPIBaseURL, normalizeError, handleRequestError } from './utils/utils';
/* @TODO figure out how to automatically set the MockBackendSrv when consumers of this package write tests using the exported clients */
export { MockBackendSrv } from './utils/backendSrv.mock';
@@ -108,6 +108,8 @@ const config: ConfigFile = {
...createAPIConfig('preferences', 'v1alpha1'),
...createAPIConfig('provisioning', 'v0alpha1'),
...createAPIConfig('shorturl', 'v1beta1'),
...createAPIConfig('notifications.alerting', 'v0alpha1'),
...createAPIConfig('rules.alerting', 'v0alpha1'),
...createAPIConfig('historian.alerting', 'v0alpha1'),
...createAPIConfig('logsdrilldown', 'v1alpha1'),
// PLOP_INJECT_API_CLIENT - Used by the API client generator
@@ -0,0 +1,46 @@
import { Observable } from 'rxjs';
import { fromFetch } from 'rxjs/fetch';
import { BackendSrv, BackendSrvRequest, FetchResponse } from '@grafana/runtime';
/**
* Minimal mock implementation of BackendSrv for testing.
* Only implements the fetch() method which is used by RTKQ.
* HTTP requests are intercepted by MSW in tests.
*/
export class MockBackendSrv implements Partial<BackendSrv> {
fetch<T>(options: BackendSrvRequest): Observable<FetchResponse<T>> {
const init: RequestInit = {
method: options.method || 'GET',
headers: options.headers,
body: options.data ? JSON.stringify(options.data) : undefined,
credentials: options.credentials,
signal: options.abortSignal,
};
return new Observable((observer) => {
fromFetch(options.url, init).subscribe({
next: async (response) => {
try {
const data = await response.json();
observer.next({
data,
status: response.status,
statusText: response.statusText,
ok: response.ok,
headers: response.headers,
redirected: response.redirected,
type: response.type,
url: response.url,
config: options,
});
observer.complete();
} catch (error) {
observer.error(error);
}
},
error: (error) => observer.error(error),
});
});
}
}
-3
View File
@@ -1,7 +1,6 @@
import { ReducersMapObject } from '@reduxjs/toolkit';
import { AnyAction, combineReducers } from 'redux';
import { notificationsAPIv0alpha1, rulesAPIv0alpha1 } from '@grafana/alerting/unstable';
import { allReducers as allApiClientReducers } from '@grafana/api-clients/rtkq';
import { generatedAPI as legacyAPI } from '@grafana/api-clients/rtkq/legacy';
import sharedReducers from 'app/core/reducers';
@@ -51,8 +50,6 @@ const rootReducers = {
[legacyAPI.reducerPath]: legacyAPI.reducer,
plugins: pluginsReducer,
[alertingApi.reducerPath]: alertingApi.reducer,
[notificationsAPIv0alpha1.reducerPath]: notificationsAPIv0alpha1.reducer,
[rulesAPIv0alpha1.reducerPath]: rulesAPIv0alpha1.reducer,
[publicDashboardApi.reducerPath]: publicDashboardApi.reducer,
[browseDashboardsAPI.reducerPath]: browseDashboardsAPI.reducer,
...allApiClientReducers,
@@ -2,6 +2,8 @@ import { render, screen } from 'test/test-utils';
import { setupMockServer } from '@grafana/test-utils/server';
import { setupBackendSrv } from '../../mockApi';
import { ContactPointLink } from './ContactPointLink';
import {
RECEIVER_NAME,
@@ -11,6 +13,10 @@ import {
const server = setupMockServer();
beforeAll(() => {
setupBackendSrv();
});
describe('render contact point link', () => {
it('should render correctly', async () => {
server.use(...listContactPointsScenario);
@@ -2,6 +2,7 @@ import { render, screen } from 'test/test-utils';
import { setupMockServer } from '@grafana/test-utils/server';
import { setupBackendSrv } from '../../../mockApi';
import { mockCombinedRule } from '../../../mocks';
import { alertingFactory } from '../../../mocks/server/db';
import { setupDataSources } from '../../../testSetup/datasources';
@@ -12,6 +13,7 @@ import { Details } from './Details';
const server = setupMockServer();
beforeAll(() => {
setupBackendSrv();
setupDataSources();
});
@@ -242,6 +242,10 @@ export function mockDashboardApi(server: SetupServer) {
};
}
export function setupBackendSrv() {
setBackendSrv(backendSrv);
}
/**
* Sets up MSW server with additional handlers for Alerting tests
*/
@@ -249,7 +253,7 @@ export function setupMswServer() {
setupMockServer(allHandlers);
beforeAll(() => {
setBackendSrv(backendSrv);
setupBackendSrv();
});
afterEach(() => {
@@ -143,8 +143,7 @@ function convertToMatcherOperator(type: LabelMatcher['type']): MatcherOperator {
case '!~':
return MatcherOperator.notRegex;
default:
const exhaustiveCheck: never = type;
throw new Error(`Unknown matcher type: ${exhaustiveCheck}`);
throw new Error(`Unknown matcher type: ${type}`);
}
}
-4
View File
@@ -2,7 +2,6 @@ import { configureStore as reduxConfigureStore, createListenerMiddleware } from
import { setupListeners } from '@reduxjs/toolkit/query';
import { Middleware } from 'redux';
import { notificationsAPIv0alpha1, rulesAPIv0alpha1 } from '@grafana/alerting/unstable';
import { allMiddleware as allApiClientMiddleware } from '@grafana/api-clients/rtkq';
import { legacyAPI } from 'app/api/clients/legacy';
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
@@ -37,9 +36,6 @@ export function configureStore(initialState?: Partial<StoreState>) {
listenerMiddleware.middleware,
// older internal alerting API client
alertingApi.middleware,
// @grafana/alerting clients for managing (Alertmanager) notification entities and rules
notificationsAPIv0alpha1.middleware,
rulesAPIv0alpha1.middleware,
// other Grafana core APIs
publicDashboardApi.middleware,
browseDashboardsAPI.middleware,
+2 -2
View File
@@ -3006,10 +3006,10 @@ __metadata:
dependencies:
"@emotion/css": "npm:11.13.5"
"@faker-js/faker": "npm:^9.8.0"
"@grafana/api-clients": "npm:12.4.0-pre"
"@grafana/i18n": "npm:12.4.0-pre"
"@grafana/test-utils": "workspace:*"
"@reduxjs/toolkit": "npm:^2.9.0"
"@rtk-query/codegen-openapi": "npm:^2.0.0"
"@testing-library/jest-dom": "npm:^6.6.3"
"@testing-library/react": "npm:^16.3.0"
"@testing-library/user-event": "npm:^14.6.1"
@@ -3041,7 +3041,7 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/api-clients@workspace:*, @grafana/api-clients@workspace:packages/grafana-api-clients":
"@grafana/api-clients@npm:12.4.0-pre, @grafana/api-clients@workspace:*, @grafana/api-clients@workspace:packages/grafana-api-clients":
version: 0.0.0-use.local
resolution: "@grafana/api-clients@workspace:packages/grafana-api-clients"
dependencies: