mirror of
https://github.com/SigNoz/signoz.git
synced 2026-11-13 11:50:42 +00:00
Compare commits
4 Commits
feat/input
...
fix/query-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c947dfdbb | ||
|
|
98a0d906ed | ||
|
|
20e6d44289 | ||
|
|
9fef8eea69 |
@@ -11,6 +11,8 @@ import axios, { AxiosError, AxiosRequestConfig } from 'axios';
|
||||
// generated API Instance
|
||||
const generatedAPIAxiosInstance = axios.create({
|
||||
baseURL: ENVIRONMENT.baseURL,
|
||||
// The backend binds repeated keys (`states=a&states=b`); axios' default sends `states[]=`.
|
||||
paramsSerializer: { indexes: null },
|
||||
});
|
||||
|
||||
let generatedAPIQueryKeyHeaderContext: Record<string, unknown> | undefined;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useListRulesV3 } from 'api/generated/services/rules';
|
||||
import {
|
||||
type ListRulesV3200,
|
||||
type ListRulesV3Params,
|
||||
RuletypesAlertStateDTO,
|
||||
type RuletypesListableRuleDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { GeneratedAPIInstance } from 'api/generatedAPIInstance';
|
||||
|
||||
const HOME_ALERT_RULES_LIMIT = 5;
|
||||
|
||||
@@ -23,18 +21,7 @@ interface HomeAlertRules {
|
||||
|
||||
export function useHomeAlertRules(): HomeAlertRules {
|
||||
const firing = useListRulesV3(FIRING_RULES_PARAMS, {
|
||||
query: {
|
||||
cacheTime: 0,
|
||||
// The backend binds repeated `states=` keys; axios' default sends `states[]=`.
|
||||
queryFn: ({ signal }) =>
|
||||
GeneratedAPIInstance<ListRulesV3200>({
|
||||
url: '/api/v3/rules',
|
||||
method: 'GET',
|
||||
params: FIRING_RULES_PARAMS,
|
||||
paramsSerializer: { indexes: null },
|
||||
signal,
|
||||
}),
|
||||
},
|
||||
query: { cacheTime: 0 },
|
||||
});
|
||||
const firingRules = firing.data?.data.rules;
|
||||
const latest = useListRulesV3(
|
||||
|
||||
@@ -31,6 +31,8 @@ jest.mock('@floating-ui/dom', () => ({
|
||||
Promise.resolve({ x: 0, y: 0, placement, strategy, middlewareData: {} }),
|
||||
}));
|
||||
|
||||
jest.setTimeout(15_000);
|
||||
|
||||
const VIEW_1_ORDER_BY = JSON.stringify({ columnName: 'name', order: 'asc' });
|
||||
const VIEW_1_QUERY = "severity = 'critical'";
|
||||
|
||||
|
||||
@@ -3,13 +3,11 @@ import logEvent from 'api/common/logEvent';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useListRulesV3 } from 'api/generated/services/rules';
|
||||
import type {
|
||||
ListRulesV3200,
|
||||
ListRulesV3Params,
|
||||
RenderErrorResponseDTO,
|
||||
RuletypesLabelPairDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { AxiosError } from 'axios';
|
||||
import { GeneratedAPIInstance } from 'api/generatedAPIInstance';
|
||||
import { isUndefined } from 'lodash-es';
|
||||
|
||||
import type { AlertRule } from './types';
|
||||
@@ -35,18 +33,7 @@ export function useAlertRulesData(
|
||||
const hasLoggedEvent = useRef(false);
|
||||
|
||||
const rulesResponse = useListRulesV3(params, {
|
||||
query: {
|
||||
keepPreviousData: true,
|
||||
// The backend binds repeated `states=` keys; axios' default sends `states[]=`.
|
||||
queryFn: ({ signal }) =>
|
||||
GeneratedAPIInstance<ListRulesV3200>({
|
||||
url: '/api/v3/rules',
|
||||
method: 'GET',
|
||||
params,
|
||||
paramsSerializer: { indexes: null },
|
||||
signal,
|
||||
}),
|
||||
},
|
||||
query: { keepPreviousData: true },
|
||||
});
|
||||
|
||||
const rules = useMemo(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { back, getCurrentLocation } from 'lib/router/navigation';
|
||||
import { act, AllTheProviders, renderHook, waitFor } from 'tests/test-utils';
|
||||
|
||||
// jest.config.ts maps `hooks/useSafeNavigate` to a mock; the `.ts` path loads the real hook.
|
||||
const { useSafeNavigate } = jest.requireActual<
|
||||
typeof import('hooks/useSafeNavigate')
|
||||
>('hooks/useSafeNavigate.ts');
|
||||
|
||||
describe('useSafeNavigate', () => {
|
||||
it('adds a history entry for replace: false even when the target adds params', async () => {
|
||||
const initialSearch = `?${QueryParams.relativeTime}=15m`;
|
||||
const { result } = renderHook(() => useSafeNavigate(), {
|
||||
wrapper: ({ children }): JSX.Element => (
|
||||
<AllTheProviders initialRoute={`${ROUTES.LOGS_EXPLORER}${initialSearch}`}>
|
||||
{children}
|
||||
</AllTheProviders>
|
||||
),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.safeNavigate(
|
||||
`${ROUTES.LOGS_EXPLORER}?${QueryParams.startTime}=1000`,
|
||||
{ replace: false },
|
||||
);
|
||||
});
|
||||
act(() => back());
|
||||
|
||||
await waitFor(() => expect(getCurrentLocation().search).toBe(initialSearch));
|
||||
});
|
||||
});
|
||||
@@ -90,7 +90,7 @@ export const useHandleExplorerTabChange = (): {
|
||||
},
|
||||
redirectToUrl,
|
||||
undefined,
|
||||
newTab,
|
||||
{ newTab },
|
||||
);
|
||||
},
|
||||
[panelType, getUpdateQuery, redirectWithQueryBuilderData, viewKey],
|
||||
|
||||
@@ -140,7 +140,7 @@ export const useSafeNavigate = (
|
||||
|
||||
const navigationOptions = {
|
||||
...options,
|
||||
replace: isDefaultParamsNavigation || options?.replace,
|
||||
replace: options?.replace ?? isDefaultParamsNavigation,
|
||||
};
|
||||
|
||||
if (typeof to === 'string') {
|
||||
|
||||
@@ -949,7 +949,7 @@ export function QueryBuilderProvider({
|
||||
searchParams?: Record<string, unknown>,
|
||||
redirectingUrl?: (typeof ROUTES)[keyof typeof ROUTES],
|
||||
shouldNotStringify?: boolean,
|
||||
newTab?: boolean,
|
||||
navigateOptions?: { newTab?: boolean; replace?: boolean },
|
||||
) => {
|
||||
const queryType =
|
||||
!query.queryType || !Object.values(EQueryType).includes(query.queryType)
|
||||
@@ -1001,14 +1001,18 @@ export function QueryBuilderProvider({
|
||||
);
|
||||
|
||||
if (searchParams) {
|
||||
Object.keys(searchParams).forEach((param) =>
|
||||
Object.keys(searchParams).forEach((param) => {
|
||||
if (searchParams[param] === null) {
|
||||
urlQuery.delete(param);
|
||||
return;
|
||||
}
|
||||
urlQuery.set(
|
||||
param,
|
||||
shouldNotStringify
|
||||
? (searchParams[param] as string)
|
||||
: JSON.stringify(searchParams[param]),
|
||||
),
|
||||
);
|
||||
);
|
||||
});
|
||||
}
|
||||
// Remove Hidden Filters from URL query parameters on query change
|
||||
urlQuery.delete(QueryParams.activeLogId);
|
||||
@@ -1017,7 +1021,7 @@ export function QueryBuilderProvider({
|
||||
? `${redirectingUrl}?${urlQuery}`
|
||||
: `${location.pathname}?${urlQuery}`;
|
||||
|
||||
safeNavigate(generatedUrl, { newTab });
|
||||
safeNavigate(generatedUrl, navigateOptions);
|
||||
},
|
||||
[location.pathname, safeNavigate],
|
||||
);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { safeNavigateMock } from '__tests__/safeNavigateMock';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { act, AllTheProviders, renderHook } from 'tests/test-utils';
|
||||
|
||||
describe('redirectWithQueryBuilderData search params', () => {
|
||||
it('removes params passed as null and JSON-encodes the rest', () => {
|
||||
const { result } = renderHook(() => useQueryBuilder(), {
|
||||
wrapper: ({ children }): JSX.Element => (
|
||||
<AllTheProviders
|
||||
initialRoute={`/unconstrained?${QueryParams.relativeTime}=6h&${QueryParams.viewName}=kept`}
|
||||
>
|
||||
{children}
|
||||
</AllTheProviders>
|
||||
),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.redirectWithQueryBuilderData(initialQueriesMap.logs, {
|
||||
[QueryParams.relativeTime]: null,
|
||||
[QueryParams.startTime]: 1000,
|
||||
});
|
||||
});
|
||||
|
||||
const [url] = safeNavigateMock.mock.lastCall ?? [];
|
||||
expect(url).toContain(`${QueryParams.startTime}=1000`);
|
||||
expect(url).not.toContain(`${QueryParams.relativeTime}=`);
|
||||
expect(url).toContain(`${QueryParams.viewName}=kept`);
|
||||
});
|
||||
|
||||
it('passes navigate options to safeNavigate', () => {
|
||||
const { result } = renderHook(() => useQueryBuilder(), {
|
||||
wrapper: ({ children }): JSX.Element => (
|
||||
<AllTheProviders initialRoute="/unconstrained">{children}</AllTheProviders>
|
||||
),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.redirectWithQueryBuilderData(
|
||||
initialQueriesMap.logs,
|
||||
{ [QueryParams.startTime]: 1000 },
|
||||
undefined,
|
||||
undefined,
|
||||
{ replace: false },
|
||||
);
|
||||
});
|
||||
|
||||
expect(safeNavigateMock).toHaveBeenLastCalledWith(expect.any(String), {
|
||||
replace: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -312,7 +312,7 @@ export type QueryBuilderContextType = {
|
||||
searchParams?: Record<string, unknown>,
|
||||
redirectToUrl?: (typeof ROUTES)[keyof typeof ROUTES],
|
||||
shallStringify?: boolean,
|
||||
newTab?: boolean,
|
||||
navigateOptions?: { newTab?: boolean; replace?: boolean },
|
||||
) => void;
|
||||
handleRunQuery: () => void;
|
||||
resetQuery: (newCurrentQuery?: QueryState) => void;
|
||||
|
||||
Reference in New Issue
Block a user