From 78df27a1400a3bbfed8004c1ac3d749fa26d2a96 Mon Sep 17 00:00:00 2001 From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:03:00 +0700 Subject: [PATCH 1/8] chore: pre-populate the alert condition based on the selected reduce to and thresholds (#8352) --- frontend/src/constants/query.ts | 1 + ...AlertRuleDocumentationRedirection.test.tsx | 10 ++ ...malyAlertDocumentationRedirection.test.tsx | 10 ++ .../src/container/CreateAlertRule/index.tsx | 11 +- .../container/FormAlertRules/RuleOptions.tsx | 2 +- .../usePrefillAlertConditions.test.ts | 125 ++++++++++++++++++ .../src/container/FormAlertRules/index.tsx | 11 ++ .../usePrefillAlertConditions.ts | 87 ++++++++++++ .../NewWidget/RightContainer/index.tsx | 6 +- .../hooks/queryBuilder/useCreateAlerts.tsx | 25 ++-- 10 files changed, 277 insertions(+), 11 deletions(-) create mode 100644 frontend/src/container/FormAlertRules/__tests__/usePrefillAlertConditions.test.ts create mode 100644 frontend/src/container/FormAlertRules/usePrefillAlertConditions.ts diff --git a/frontend/src/constants/query.ts b/frontend/src/constants/query.ts index 9460602aec3c..656cdb0040f3 100644 --- a/frontend/src/constants/query.ts +++ b/frontend/src/constants/query.ts @@ -47,4 +47,5 @@ export enum QueryParams { destination = 'destination', kindString = 'kindString', tab = 'tab', + thresholds = 'thresholds', } diff --git a/frontend/src/container/CreateAlertRule/AlertRuleDocumentationRedirection.test.tsx b/frontend/src/container/CreateAlertRule/AlertRuleDocumentationRedirection.test.tsx index 1dc088d3d8f0..f7a1b1fb0f07 100644 --- a/frontend/src/container/CreateAlertRule/AlertRuleDocumentationRedirection.test.tsx +++ b/frontend/src/container/CreateAlertRule/AlertRuleDocumentationRedirection.test.tsx @@ -1,4 +1,5 @@ import ROUTES from 'constants/routes'; +import * as usePrefillAlertConditions from 'container/FormAlertRules/usePrefillAlertConditions'; import CreateAlertPage from 'pages/CreateAlert'; import { MemoryRouter, Route } from 'react-router-dom'; import { act, fireEvent, render } from 'tests/test-utils'; @@ -33,6 +34,15 @@ jest.mock('hooks/useSafeNavigate', () => ({ }), })); +jest + .spyOn(usePrefillAlertConditions, 'usePrefillAlertConditions') + .mockReturnValue({ + matchType: '3', + op: '1', + target: 100, + targetUnit: 'rpm', + }); + let mockWindowOpen: jest.Mock; window.ResizeObserver = diff --git a/frontend/src/container/CreateAlertRule/AnomalyAlertDocumentationRedirection.test.tsx b/frontend/src/container/CreateAlertRule/AnomalyAlertDocumentationRedirection.test.tsx index 498595d183ad..783f6f658531 100644 --- a/frontend/src/container/CreateAlertRule/AnomalyAlertDocumentationRedirection.test.tsx +++ b/frontend/src/container/CreateAlertRule/AnomalyAlertDocumentationRedirection.test.tsx @@ -1,4 +1,5 @@ import ROUTES from 'constants/routes'; +import * as usePrefillAlertConditions from 'container/FormAlertRules/usePrefillAlertConditions'; import CreateAlertPage from 'pages/CreateAlert'; import { MemoryRouter, Route } from 'react-router-dom'; import { act, fireEvent, render } from 'tests/test-utils'; @@ -41,6 +42,15 @@ jest.mock('hooks/useSafeNavigate', () => ({ safeNavigate: jest.fn(), }), })); +jest + .spyOn(usePrefillAlertConditions, 'usePrefillAlertConditions') + .mockReturnValue({ + matchType: '3', + op: '1', + target: 100, + targetUnit: 'rpm', + }); + describe('Anomaly Alert Documentation Redirection', () => { let mockWindowOpen: jest.Mock; diff --git a/frontend/src/container/CreateAlertRule/index.tsx b/frontend/src/container/CreateAlertRule/index.tsx index e17f6fe3bb5d..456aef831129 100644 --- a/frontend/src/container/CreateAlertRule/index.tsx +++ b/frontend/src/container/CreateAlertRule/index.tsx @@ -3,6 +3,7 @@ import logEvent from 'api/common/logEvent'; import { ENTITY_VERSION_V4 } from 'constants/app'; import { QueryParams } from 'constants/query'; import FormAlertRules, { AlertDetectionTypes } from 'container/FormAlertRules'; +import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types'; import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam'; import history from 'lib/history'; import { useEffect, useState } from 'react'; @@ -32,6 +33,12 @@ function CreateRules(): JSX.Element { ? AlertTypes.ANOMALY_BASED_ALERT : queryParams.get(QueryParams.alertType); + const { thresholds } = (location.state as { + thresholds: ThresholdProps[]; + }) || { + thresholds: null, + }; + const compositeQuery = useGetCompositeQueryParam(); function getAlertTypeFromDataSource(): AlertTypes | null { if (!compositeQuery) { @@ -96,7 +103,9 @@ function CreateRules(): JSX.Element { } const generatedUrl = `${location.pathname}?${queryParams.toString()}`; - history.replace(generatedUrl); + history.replace(generatedUrl, { + thresholds, + }); }; useEffect(() => { diff --git a/frontend/src/container/FormAlertRules/RuleOptions.tsx b/frontend/src/container/FormAlertRules/RuleOptions.tsx index a30321fcfd77..19f47220f149 100644 --- a/frontend/src/container/FormAlertRules/RuleOptions.tsx +++ b/frontend/src/container/FormAlertRules/RuleOptions.tsx @@ -390,7 +390,7 @@ function RuleOptions({ {ruleType !== AlertDetectionTypes.ANOMALY_DETECTION_ALERT && ( - + ': '1', + '<': '2', + '=': '3', + }, + matchType: { + avg: '3', + sum: '4', + }, +}; + +jest.mock('react-router-dom-v5-compat', () => { + const mockThreshold1 = { + index: '0d11f426-a02e-48da-867c-b79c6ef1ff06', + isEditEnabled: false, + keyIndex: 1, + selectedGraph: 'graph', + thresholdColor: 'Orange', + thresholdFormat: 'Text', + thresholdLabel: 'Caution', + thresholdOperator: '>', + thresholdTableOptions: 'A', + thresholdUnit: 'rpm', + thresholdValue: 800, + }; + const mockThreshold2 = { + index: 'edbe8ef2-fa54-4cb9-b343-7afe883bb714', + isEditEnabled: false, + keyIndex: 0, + selectedGraph: 'graph', + thresholdColor: 'Red', + thresholdFormat: 'Text', + thresholdLabel: 'Danger', + thresholdOperator: '<', + thresholdTableOptions: 'A', + thresholdUnit: 'rpm', + thresholdValue: 900, + }; + return { + ...jest.requireActual('react-router-dom-v5-compat'), + useLocation: jest.fn().mockReturnValue({ + state: { + thresholds: [mockThreshold1, mockThreshold2], + }, + }), + }; +}); + +const mockStagedQuery = { + builder: { + queryData: [ + { + reduceTo: 'avg', + }, + ], + }, +}; + +describe('usePrefillAlertConditions', () => { + it('returns the correct matchType for a single query', () => { + const { result } = renderHook(() => + usePrefillAlertConditions(mockStagedQuery as any), + ); + expect(result.current.matchType).toBe(TEST_MAPPINGS.matchType.avg); + }); + + it('returns null matchType for a single query with unsupported time aggregation', () => { + const { result } = renderHook(() => + usePrefillAlertConditions({ + builder: { queryData: [{ reduceTo: 'p90' }] }, + } as any), + ); + expect(result.current.matchType).toBe(null); + }); + + it('returns the correct matchType for multiple queries with same time aggregation', () => { + const { result } = renderHook(() => + usePrefillAlertConditions({ + builder: { + queryData: [ + { + reduceTo: 'avg', + }, + { + reduceTo: 'avg', + }, + ], + }, + } as any), + ); + expect(result.current.matchType).toBe(TEST_MAPPINGS.matchType.avg); + }); + + it('returns null matchType for multiple queries with different time aggregation', () => { + const { result } = renderHook(() => + usePrefillAlertConditions({ + builder: { + queryData: [ + { + reduceTo: 'avg', + }, + { + reduceTo: 'sum', + }, + ], + }, + } as any), + ); + expect(result.current.matchType).toBe(null); + }); + + it('returns the correct op, target, targetUnit from the higher priority threshold for multiple thresholds', () => { + const { result } = renderHook(() => + usePrefillAlertConditions(mockStagedQuery as any), + ); + expect(result.current.op).toBe(TEST_MAPPINGS.op['<']); + expect(result.current.target).toBe(900); + expect(result.current.targetUnit).toBe('rpm'); + }); +}); diff --git a/frontend/src/container/FormAlertRules/index.tsx b/frontend/src/container/FormAlertRules/index.tsx index 6a56beb05830..736967d23fec 100644 --- a/frontend/src/container/FormAlertRules/index.tsx +++ b/frontend/src/container/FormAlertRules/index.tsx @@ -57,6 +57,7 @@ import { StepContainer, StepHeading, } from './styles'; +import { usePrefillAlertConditions } from './usePrefillAlertConditions'; import { getSelectedQueryOptions } from './utils'; export enum AlertDetectionTypes { @@ -113,6 +114,9 @@ function FormAlertRules({ handleSetConfig, redirectWithQueryBuilderData, } = useQueryBuilder(); + const { matchType, op, target, targetUnit } = usePrefillAlertConditions( + stagedQuery, + ); useEffect(() => { handleSetConfig(panelType || PANEL_TYPES.TIME_SERIES, dataSource); @@ -266,6 +270,13 @@ function FormAlertRules({ ...initialValue, broadcastToAll: !broadcastToSpecificChannels, ruleType, + condition: { + ...initialValue.condition, + matchType: matchType || initialValue.condition.matchType, + op: op || initialValue.condition.op, + target: target || initialValue.condition.target, + targetUnit: targetUnit || initialValue.condition.targetUnit, + }, }); setDetectionMethod(ruleType); diff --git a/frontend/src/container/FormAlertRules/usePrefillAlertConditions.ts b/frontend/src/container/FormAlertRules/usePrefillAlertConditions.ts new file mode 100644 index 000000000000..0827aa40252c --- /dev/null +++ b/frontend/src/container/FormAlertRules/usePrefillAlertConditions.ts @@ -0,0 +1,87 @@ +import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types'; +import { useMemo } from 'react'; +import { useLocation } from 'react-router-dom-v5-compat'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; + +const THRESHOLD_COLORS_SORTING_ORDER = ['Red', 'Orange', 'Green', 'Blue']; + +export const usePrefillAlertConditions = ( + stagedQuery: Query | null, +): { + matchType: string | null; + op: string | null; + target: number | undefined; + targetUnit: string | undefined; +} => { + const location = useLocation(); + + // Extract and set match type + const reduceTo = useMemo(() => { + if (!stagedQuery) return null; + const isSameTimeAggregation = stagedQuery.builder.queryData.every( + (queryData) => + queryData.reduceTo === stagedQuery.builder.queryData[0].reduceTo, + ); + return isSameTimeAggregation + ? stagedQuery.builder.queryData[0].reduceTo + : null; + }, [stagedQuery]); + + const matchType = useMemo(() => { + switch (reduceTo) { + case 'avg': + return '3'; + case 'sum': + return '4'; + default: + return null; + } + }, [reduceTo]); + + // Extract and set threshold operator, value and unit + const threshold = useMemo(() => { + const { thresholds } = (location.state as { + thresholds: ThresholdProps[]; + }) || { + thresholds: null, + }; + if (!thresholds || thresholds.length === 0) return null; + const sortedThresholds = thresholds.sort((a, b) => { + const aIndex = THRESHOLD_COLORS_SORTING_ORDER.indexOf( + a.thresholdColor || '', + ); + const bIndex = THRESHOLD_COLORS_SORTING_ORDER.indexOf( + b.thresholdColor || '', + ); + return aIndex - bIndex; + }); + return sortedThresholds[0]; + }, [location.state]); + + const thresholdOperator = useMemo(() => { + const op = threshold?.thresholdOperator; + switch (op) { + case '>': + case '>=': + return '1'; + case '<': + case '<=': + return '2'; + case '=': + return '3'; + default: + return null; + } + }, [threshold]); + + const thresholdUnit = useMemo(() => threshold?.thresholdUnit, [threshold]); + + const thresholdValue = useMemo(() => threshold?.thresholdValue, [threshold]); + + return { + matchType, + op: thresholdOperator, + target: thresholdValue, + targetUnit: thresholdUnit, + }; +}; diff --git a/frontend/src/container/NewWidget/RightContainer/index.tsx b/frontend/src/container/NewWidget/RightContainer/index.tsx index f0e518ab06f5..8e63faa020b4 100644 --- a/frontend/src/container/NewWidget/RightContainer/index.tsx +++ b/frontend/src/container/NewWidget/RightContainer/index.tsx @@ -130,7 +130,11 @@ function RightContainer({ const selectedGraphType = GraphTypes.find((e) => e.name === selectedGraph)?.display || ''; - const onCreateAlertsHandler = useCreateAlerts(selectedWidget, 'panelView'); + const onCreateAlertsHandler = useCreateAlerts( + selectedWidget, + 'panelView', + thresholds, + ); const allowThreshold = panelTypeVsThreshold[selectedGraph]; const allowSoftMinMax = panelTypeVsSoftMinMax[selectedGraph]; diff --git a/frontend/src/hooks/queryBuilder/useCreateAlerts.tsx b/frontend/src/hooks/queryBuilder/useCreateAlerts.tsx index d85586ddfa33..e4a36ebcbe10 100644 --- a/frontend/src/hooks/queryBuilder/useCreateAlerts.tsx +++ b/frontend/src/hooks/queryBuilder/useCreateAlerts.tsx @@ -5,6 +5,7 @@ import { DEFAULT_ENTITY_VERSION } from 'constants/app'; import { QueryParams } from 'constants/query'; import ROUTES from 'constants/routes'; import { MenuItemKeys } from 'container/GridCardLayout/WidgetHeader/contants'; +import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types'; import { useNotifications } from 'hooks/useNotifications'; import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; import { prepareQueryRangePayload } from 'lib/dashboard/prepareQueryRangePayload'; @@ -19,7 +20,11 @@ import { Widgets } from 'types/api/dashboard/getAll'; import { GlobalReducer } from 'types/reducer/globalTime'; import { getGraphType } from 'utils/getGraphType'; -const useCreateAlerts = (widget?: Widgets, caller?: string): VoidFunction => { +const useCreateAlerts = ( + widget?: Widgets, + caller?: string, + thresholds?: ThresholdProps[], +): VoidFunction => { const queryRangeMutation = useMutation(getQueryRangeFormat); const { selectedTime: globalSelectedInterval } = useSelector< @@ -66,13 +71,17 @@ const useCreateAlerts = (widget?: Widgets, caller?: string): VoidFunction => { widget?.query, ); - history.push( - `${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent( - JSON.stringify(updatedQuery), - )}&${QueryParams.panelTypes}=${widget.panelTypes}&version=${ - selectedDashboard?.data.version || DEFAULT_ENTITY_VERSION - }`, - ); + const url = `${ROUTES.ALERTS_NEW}?${ + QueryParams.compositeQuery + }=${encodeURIComponent(JSON.stringify(updatedQuery))}&${ + QueryParams.panelTypes + }=${widget.panelTypes}&version=${ + selectedDashboard?.data.version || DEFAULT_ENTITY_VERSION + }`; + + history.push(url, { + thresholds, + }); }, onError: () => { notifications.error({ From bba3e9591495ce91477ddb67b73b1526cf1d16ce Mon Sep 17 00:00:00 2001 From: "primus-bot[bot]" <171087277+primus-bot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 12:20:10 +0530 Subject: [PATCH 2/8] chore(release): bump to v0.91.0 (#8596) Co-authored-by: primus-bot[bot] <171087277+primus-bot[bot]@users.noreply.github.com> --- deploy/docker-swarm/docker-compose.ha.yaml | 2 +- deploy/docker-swarm/docker-compose.yaml | 2 +- deploy/docker/docker-compose.ha.yaml | 2 +- deploy/docker/docker-compose.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/docker-swarm/docker-compose.ha.yaml b/deploy/docker-swarm/docker-compose.ha.yaml index 9ad2cd558772..cdde64259bf4 100644 --- a/deploy/docker-swarm/docker-compose.ha.yaml +++ b/deploy/docker-swarm/docker-compose.ha.yaml @@ -174,7 +174,7 @@ services: # - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml signoz: !!merge <<: *db-depend - image: signoz/signoz:v0.90.1 + image: signoz/signoz:v0.91.0 command: - --config=/root/config/prometheus.yml ports: diff --git a/deploy/docker-swarm/docker-compose.yaml b/deploy/docker-swarm/docker-compose.yaml index 1d9f518d8178..90e94be7a066 100644 --- a/deploy/docker-swarm/docker-compose.yaml +++ b/deploy/docker-swarm/docker-compose.yaml @@ -115,7 +115,7 @@ services: # - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml signoz: !!merge <<: *db-depend - image: signoz/signoz:v0.90.1 + image: signoz/signoz:v0.91.0 command: - --config=/root/config/prometheus.yml ports: diff --git a/deploy/docker/docker-compose.ha.yaml b/deploy/docker/docker-compose.ha.yaml index 215b0eed073d..c6c9f6796f33 100644 --- a/deploy/docker/docker-compose.ha.yaml +++ b/deploy/docker/docker-compose.ha.yaml @@ -177,7 +177,7 @@ services: # - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml signoz: !!merge <<: *db-depend - image: signoz/signoz:${VERSION:-v0.90.1} + image: signoz/signoz:${VERSION:-v0.91.0} container_name: signoz command: - --config=/root/config/prometheus.yml diff --git a/deploy/docker/docker-compose.yaml b/deploy/docker/docker-compose.yaml index 7bc052176f5c..35db637ef0a8 100644 --- a/deploy/docker/docker-compose.yaml +++ b/deploy/docker/docker-compose.yaml @@ -110,7 +110,7 @@ services: # - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml signoz: !!merge <<: *db-depend - image: signoz/signoz:${VERSION:-v0.90.1} + image: signoz/signoz:${VERSION:-v0.91.0} container_name: signoz command: - --config=/root/config/prometheus.yml From 76b58b731753ae7e2d831aa652ff1be155a718ce Mon Sep 17 00:00:00 2001 From: Yunus M Date: Thu, 24 Jul 2025 19:01:17 +0530 Subject: [PATCH 3/8] feat: show success message with note to notify user on role change (#8491) --- .../OrganizationSettings/Members/index.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/frontend/src/container/OrganizationSettings/Members/index.tsx b/frontend/src/container/OrganizationSettings/Members/index.tsx index 51de24f3cccd..365c4909476d 100644 --- a/frontend/src/container/OrganizationSettings/Members/index.tsx +++ b/frontend/src/container/OrganizationSettings/Members/index.tsx @@ -115,12 +115,23 @@ function UserFunction({ role, }); onUpdateDetailsHandler(); - notifications.success({ - message: t('success', { - ns: 'common', - }), - }); + + if (role !== accessLevel) { + notifications.success({ + message: 'User details updated successfully', + description: + 'The user details have been updated successfully. Please request the user to logout and login again to access the platform with updated privileges.', + }); + } else { + notifications.success({ + message: t('success', { + ns: 'common', + }), + }); + } + setIsUpdateLoading(false); + setIsModalVisible(false); } catch (error) { notifications.error({ message: (error as APIError).getErrorCode(), From db440a6eb4d7199458979dd7d81a7e87c111de3f Mon Sep 17 00:00:00 2001 From: Yunus M Date: Thu, 24 Jul 2025 19:10:48 +0530 Subject: [PATCH 4/8] feat: alert module ui improvements (#8572) * feat: alert module ui improvements * feat: update something went wrong page * feat: remove safe navigate hook usage in ErrorBoundaryFallback --- .../FormAlertRules/FormAlertRules.styles.scss | 18 ++++++ .../src/container/FormAlertRules/index.tsx | 7 ++- .../container/ListAlertRules/ListAlert.tsx | 4 +- .../PlannedDowntime.styles.scss | 1 - .../src/container/TriggeredAlerts/index.tsx | 16 +++--- .../AlertDetails/AlertDetails.styles.scss | 9 +-- .../src/pages/AlertList/AlertList.styles.scss | 6 +- frontend/src/pages/AlertList/index.tsx | 13 ++++- .../ErrorBoundaryFallback.styles.scss | 18 ++++-- .../ErrorBoundaryFallback.tsx | 56 ++++++++++--------- 10 files changed, 92 insertions(+), 56 deletions(-) diff --git a/frontend/src/container/FormAlertRules/FormAlertRules.styles.scss b/frontend/src/container/FormAlertRules/FormAlertRules.styles.scss index 22a272ca93fc..66d2167519f1 100644 --- a/frontend/src/container/FormAlertRules/FormAlertRules.styles.scss +++ b/frontend/src/container/FormAlertRules/FormAlertRules.styles.scss @@ -21,6 +21,24 @@ } } +.form-alert-rules-container { + &.create-mode { + padding: 16px; + } +} + +.triggered-alerts-container { + padding: 8px; +} + +.alert-rules-list-container { + padding: 8px; +} + +.planned-downtime-container { + padding: 8px; +} + .steps-container { width: 80%; } diff --git a/frontend/src/container/FormAlertRules/index.tsx b/frontend/src/container/FormAlertRules/index.tsx index 736967d23fec..38ca8567a1c4 100644 --- a/frontend/src/container/FormAlertRules/index.tsx +++ b/frontend/src/container/FormAlertRules/index.tsx @@ -766,7 +766,12 @@ function FormAlertRules({ <> {Element} -
+
{isNewRule && ( diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx index fae18d12e9c2..08509345483d 100644 --- a/frontend/src/container/ListAlertRules/ListAlert.tsx +++ b/frontend/src/container/ListAlertRules/ListAlert.tsx @@ -341,7 +341,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { defaultCurrent: Number(paginationParam) || 1, }; return ( - <> +
- +
); } diff --git a/frontend/src/container/PlannedDowntime/PlannedDowntime.styles.scss b/frontend/src/container/PlannedDowntime/PlannedDowntime.styles.scss index b81e4d1e5150..ee1471a52bca 100644 --- a/frontend/src/container/PlannedDowntime/PlannedDowntime.styles.scss +++ b/frontend/src/container/PlannedDowntime/PlannedDowntime.styles.scss @@ -151,7 +151,6 @@ } .planned-downtime-container { - margin-top: 70px; display: flex; justify-content: center; width: 100%; diff --git a/frontend/src/container/TriggeredAlerts/index.tsx b/frontend/src/container/TriggeredAlerts/index.tsx index a7f9bd5843cc..ab85fc30d1a8 100644 --- a/frontend/src/container/TriggeredAlerts/index.tsx +++ b/frontend/src/container/TriggeredAlerts/index.tsx @@ -69,13 +69,15 @@ function TriggeredAlerts(): JSX.Element { } return ( - +
+ +
); } diff --git a/frontend/src/pages/AlertDetails/AlertDetails.styles.scss b/frontend/src/pages/AlertDetails/AlertDetails.styles.scss index f43d253451ba..22ed56d6e12f 100644 --- a/frontend/src/pages/AlertDetails/AlertDetails.styles.scss +++ b/frontend/src/pages/AlertDetails/AlertDetails.styles.scss @@ -8,6 +8,7 @@ .top-level-tab.periscope-tab { padding: 2px 0; } + .ant-tabs { &-nav { margin-bottom: 0 !important; @@ -22,13 +23,7 @@ &:not(:first-of-type) { margin-left: 24px !important; } - .periscope-tab { - font-size: 14px; - color: var(--text-vanilla-100); - line-height: 20px; - letter-spacing: -0.07px; - gap: 10px; - } + [aria-selected='false'] { .periscope-tab { color: var(--text-vanilla-400); diff --git a/frontend/src/pages/AlertList/AlertList.styles.scss b/frontend/src/pages/AlertList/AlertList.styles.scss index 8cacccd64670..0d1c58f36b28 100644 --- a/frontend/src/pages/AlertList/AlertList.styles.scss +++ b/frontend/src/pages/AlertList/AlertList.styles.scss @@ -1,9 +1,5 @@ .alerts-container { - .ant-tabs-nav-wrap { + .ant-tabs-nav-wrap:first-of-type { padding-left: 16px; } - - .ant-tabs-content-holder { - padding: 8px; - } } diff --git a/frontend/src/pages/AlertList/index.tsx b/frontend/src/pages/AlertList/index.tsx index 71f0dedcbf18..8df082d995b1 100644 --- a/frontend/src/pages/AlertList/index.tsx +++ b/frontend/src/pages/AlertList/index.tsx @@ -43,8 +43,11 @@ function AllAlertList(): JSX.Element {
), key: 'AlertRules', - children: - isAlertHistory || isAlertOverview ? : , + children: ( +
+ {isAlertHistory || isAlertOverview ? : } +
+ ), }, { label: ( @@ -54,7 +57,11 @@ function AllAlertList(): JSX.Element {
), key: 'Configuration', - children: , + children: ( +
+ +
+ ), }, ]; diff --git a/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.styles.scss b/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.styles.scss index 78fd73bf0f60..33f0121b974b 100644 --- a/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.styles.scss +++ b/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.styles.scss @@ -1,10 +1,16 @@ .error-boundary-fallback-container { width: 100%; + height: 100%; - .actionBtn { - display: flex; - align-items: center; - gap: 4px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + color: var(--bg-vanilla-100); + + .error-icon { + margin-bottom: 16px; } .title, @@ -13,4 +19,8 @@ align-items: center; gap: 8px; } + + .actions { + margin-top: 16px; + } } diff --git a/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.tsx b/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.tsx index d8ceb5890f56..3bf26e0db1f4 100644 --- a/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.tsx +++ b/frontend/src/pages/ErrorBoundaryFallback/ErrorBoundaryFallback.tsx @@ -1,8 +1,10 @@ import './ErrorBoundaryFallback.styles.scss'; -import { BugOutlined, UndoOutlined } from '@ant-design/icons'; -import { Button, Card, Typography } from 'antd'; +import { BugOutlined } from '@ant-design/icons'; +import { Button, Typography } from 'antd'; +import ROUTES from 'constants/routes'; import Slack from 'container/SideNav/Slack'; +import { Home, TriangleAlert } from 'lucide-react'; import { useTranslation } from 'react-i18next'; function ErrorBoundaryFallback(): JSX.Element { @@ -13,10 +15,14 @@ function ErrorBoundaryFallback(): JSX.Element { }; const handleReload = (): void => { - window.location.reload(); + // Go to home page + window.location.href = ROUTES.HOME; }; return ( - +
+
+ +
@@ -24,30 +30,28 @@ function ErrorBoundaryFallback(): JSX.Element {
- <> -

{t('contact_if_issue_exists')}

+

{t('contact_if_issue_exists')}

-
- +
+ - -
- - + +
+
); } From db0f3624827dd051fd329e5729c4ecdcbf5ef664 Mon Sep 17 00:00:00 2001 From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com> Date: Thu, 24 Jul 2025 21:30:47 +0700 Subject: [PATCH 5/8] chore: fix sentry issues in alerts and infra monitoring (#8566) --- .../container/FormAlertRules/ChannelSelect/index.tsx | 4 ++-- .../src/container/InfraMonitoringK8s/commonUtils.tsx | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/src/container/FormAlertRules/ChannelSelect/index.tsx b/frontend/src/container/FormAlertRules/ChannelSelect/index.tsx index 1dd152a87aa1..fc4134f17a2b 100644 --- a/frontend/src/container/FormAlertRules/ChannelSelect/index.tsx +++ b/frontend/src/container/FormAlertRules/ChannelSelect/index.tsx @@ -48,8 +48,8 @@ function ChannelSelect({ if (hasError) { notifications.error({ - message: error.getErrorCode(), - description: error.getErrorMessage(), + message: error?.getErrorCode?.() || 'Error', + description: error?.getErrorMessage?.() || 'Something went wrong', }); } diff --git a/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx b/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx index e61f64e5dbd9..06e051ed669a 100644 --- a/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx +++ b/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx @@ -285,9 +285,13 @@ export const getFiltersFromParams = ( ): IBuilderQuery['filters'] | null => { const filtersFromParams = searchParams.get(queryKey); if (filtersFromParams) { - const decoded = decodeURIComponent(filtersFromParams); - const parsed = JSON.parse(decoded); - return parsed as IBuilderQuery['filters']; + try { + const decoded = decodeURIComponent(filtersFromParams); + const parsed = JSON.parse(decoded); + return parsed as IBuilderQuery['filters']; + } catch (error) { + return null; + } } return null; }; From d7fdbcd90dafde4e783ee6e5c0eb8959d5efb6c3 Mon Sep 17 00:00:00 2001 From: Yunus M Date: Fri, 25 Jul 2025 11:08:12 +0530 Subject: [PATCH 6/8] feat: open entities in new tab on ctrl / cmd + click (#8607) * feat: open entities in new tab on ctrl / cmd + click * feat: open entities in new tab on ctrl / cmd + click --- .../container/ListAlertRules/ListAlert.tsx | 31 +++++++++++++++---- .../ListOfDashboard/DashboardsList.tsx | 21 ++++++++----- .../ListOfDashboard/RequestDashboardBtn.tsx | 2 +- .../Overview/TableRenderer/ColumnWithLink.tsx | 9 ++++-- .../MetricsApplication/TopOperationsTable.tsx | 16 ++++++++-- .../src/container/MetricsApplication/types.ts | 1 + .../src/container/MetricsApplication/utils.ts | 7 ++++- 7 files changed, 68 insertions(+), 19 deletions(-) diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx index 08509345483d..638c210abe93 100644 --- a/frontend/src/container/ListAlertRules/ListAlert.tsx +++ b/frontend/src/container/ListAlertRules/ListAlert.tsx @@ -105,7 +105,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const onEditHandler = (record: GettableAlert) => (): void => { + const onEditHandler = (record: GettableAlert, openInNewTab: boolean): void => { const compositeQuery = mapQueryDataFromApi(record.condition.compositeQuery); params.set( QueryParams.compositeQuery, @@ -117,7 +117,12 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { params.set(QueryParams.ruleId, record.id.toString()); setEditLoader(false); - history.push(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`); + + if (openInNewTab) { + window.open(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`, '_blank'); + } else { + history.push(`${ROUTES.ALERT_OVERVIEW}?${params.toString()}`); + } }; const onCloneHandler = ( @@ -250,9 +255,15 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { } return 0; }, - render: (value, record): JSX.Element => ( - {value} - ), + render: (value, record): JSX.Element => { + const onClickHandler = (e: React.MouseEvent): void => { + e.stopPropagation(); + e.preventDefault(); + onEditHandler(record, e.metaKey || e.ctrlKey); + }; + + return {value}; + }, sortOrder: sortedInfo.columnKey === 'name' ? sortedInfo.order : null, }, { @@ -311,12 +322,20 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element { />, onEditHandler(record, false)} type="link" loading={editLoader} > Edit , + onEditHandler(record, true)} + type="link" + loading={editLoader} + > + Edit in New Tab + , -
{ - e.stopPropagation(); - safeNavigate(getLink()); - }} - > +
dashboard-image View +