Compare commits

...

15 Commits

Author SHA1 Message Date
Jatinderjit Singh
36417a5f9e test: cover recurring schedule active window in IsActive
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 23:44:39 +05:30
Jatinderjit Singh
989b1252df test: cover fixed schedule active window in IsActive
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 23:22:36 +05:30
Jatinderjit Singh
51cb119f79 fix: make startTime a required field 2026-05-29 22:50:06 +05:30
Jatinderjit Singh
180a2c067f refactor: remove redundant code 2026-05-29 22:32:17 +05:30
Jatinderjit Singh
83351ca01d fix: use embedded timezone in start/end times
Accept times in any timezone, but always convert them to the selected
timezone. The conversion is required to correctly handle the recurring
maintenances for timezones where DST is involved.
2026-05-29 21:18:45 +05:30
Jatinderjit Singh
b11e2af392 fix: remove recurrence.startTime/endTime usages 2026-05-29 21:18:45 +05:30
Jatinderjit Singh
7f6e89ea22 fix: upcoming check for recurring maintenances 2026-05-29 21:18:45 +05:30
Jatinderjit Singh
8aeb9b5a77 refactor: code cleanup 2026-05-29 21:18:45 +05:30
Jatinderjit Singh
46c8f3579e refactor(alertmanager): drop start/end bounds from Recurrence
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 18:39:40 +05:30
Jatinderjit Singh
9ff045482f feat(alertmanager): migrate recurrence bounds to schedule level
Promote startTime/endTime from a planned maintenance's nested recurrence
up to the schedule level. For recurring maintenances the recurrence
bounds were the source of truth; the recurrence struct loses these
fields in the next step, so the values are moved while they can still be
read. The migration operates on raw JSON for that reason.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 17:21:00 +05:30
swapnil-signoz
910645516d chore: remove cloud integration service cascade delete constraint (#11480)
* chore: remove cloud integration service cascade delete constraint

* refactor: manually recreate table
2026-05-29 11:21:05 +00:00
Tushar Vats
edc1278769 fix(querybuilder): return PreparedWhereClause by value so warnings propagate when clause is empty (#11395)
* fix: propage dropped warnings from where clause visitor

* fix: added integration test

* fix: make py-fmt

* fix: remove stale comment
2026-05-29 10:09:09 +00:00
Yunus M
da1b09c479 refactor: replace antd Tabs with @signozhq/ui Tabs (#11392)
* refactor: replace antd Tabs with @signozhq/ui Tabs

Migrates Tabs usage from antd to the @signozhq/ui Tabs component across
dashboard settings, integration details, metrics application, pipelines,
trace detail, and workspace-locked pages. API differences (activeKey →
value, defaultActiveKey → defaultValue, TabsProps['items'] → TabItemProps[])
are updated to match the new component.

* refactor: enhance RouteTab component with new styling and functionality
2026-05-29 09:53:51 +00:00
Gaurav Tewari
1f406823d8 refactor(frontend): migrate plain antd Input to @signozhq/ui/input (#11401)
* chore: refactor input

* chore: remove markdown

* chore: update markdown

* fix: minior comments for input

* chore: remove comments

---------

Co-authored-by: Gaurav Tewari <tewarig@users.noreply.github.com>
2026-05-29 08:37:54 +00:00
Nikhil Mantri
f626380b1a fix(infra-monitoring): align v2 custom queries' bounds with QBv5 querier step adjustment (#11397)
* chore: updated logic and use centralized function in the module

* chore: filter metric groups

* chore: filter metric groups

* chore: formula correction

* chore: added step flooring note

* chore: comment correction

* chore: comment correction

* chore: removed function

* chore: renamed variables

* chore: fix for surfacing meta for pods custom group by

* chore: added todo and note

* chore: added changes based on comments

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2026-05-29 07:14:43 +00:00
123 changed files with 1299 additions and 1096 deletions

View File

@@ -309,10 +309,6 @@ components:
properties:
duration:
type: string
endTime:
format: date-time
nullable: true
type: string
repeatOn:
items:
$ref: '#/components/schemas/AlertmanagertypesRepeatOn'
@@ -320,11 +316,7 @@ components:
type: array
repeatType:
$ref: '#/components/schemas/AlertmanagertypesRepeatType'
startTime:
format: date-time
type: string
required:
- startTime
- duration
- repeatType
type: object
@@ -358,6 +350,7 @@ components:
type: string
required:
- timezone
- startTime
type: object
AuthtypesAttributeMapping:
properties:

View File

@@ -162,21 +162,11 @@ export interface AlertmanagertypesRecurrenceDTO {
* @type string
*/
duration: string;
/**
* @type string,null
* @format date-time
*/
endTime?: string | null;
/**
* @type array,null
*/
repeatOn?: AlertmanagertypesRepeatOnDTO[] | null;
repeatType: AlertmanagertypesRepeatTypeDTO;
/**
* @type string
* @format date-time
*/
startTime: string;
}
export interface AlertmanagertypesScheduleDTO {
@@ -190,7 +180,7 @@ export interface AlertmanagertypesScheduleDTO {
* @type string
* @format date-time
*/
startTime?: string;
startTime: string;
/**
* @type string
*/

View File

@@ -41,14 +41,22 @@ $item-spacing: 8px;
width: 100%;
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
outline: none;
height: auto;
color: var(--l1-foreground);
font-size: 14px;
line-height: 20px;
letter-spacing: -0.07px;
padding: 0;
&.ant-input:focus {
&:focus,
&:focus-visible,
&:hover {
border: none;
box-shadow: none;
outline: none;
}
&::placeholder {

View File

@@ -6,7 +6,7 @@ import {
useState,
} from 'react';
import { Color } from '@signozhq/design-tokens';
import { Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';
import { TimezonePickerShortcuts } from 'constants/shortcuts/TimezonePickerShortcuts';

View File

@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Card, Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Card, Form } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { Button, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { X } from '@signozhq/icons';

View File

@@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Button, Input, InputNumber, Popover, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, InputNumber, Popover, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import type { DefaultOptionType } from 'antd/es/select';
import cx from 'classnames';

View File

@@ -266,6 +266,14 @@
border-left: transparent;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
&:focus:not(:focus-visible),
&.ant-btn:focus:not(:focus-visible) {
border-color: var(--l2-border);
border-left-color: transparent;
outline: none;
box-shadow: none;
}
}
}
}
@@ -291,5 +299,21 @@
.cm-placeholder {
font-size: 12px !important;
}
$add-on-row-height: 38px;
.periscope-input-with-label {
.input {
.ant-select {
height: $add-on-row-height;
}
}
}
.input-with-label {
.input {
height: $add-on-row-height;
}
}
}
}

View File

@@ -4,6 +4,23 @@
padding: 12px;
gap: 12px;
border-bottom: 1px solid var(--l1-border);
.search {
input {
--input-background: var(--l2-background);
--input-hover-background: var(--l2-background);
--input-focus-background: var(--l2-background);
&::placeholder {
color: var(--l3-foreground);
}
--input-font-size: 14px;
--input-border-color: var(--l1-border);
--input-focus-border-color: var(--primary-background);
--input-focus-outline-width: 0;
--input-focus-outline-offset: 0;
}
}
.filter-header-checkbox {
display: flex;
align-items: center;

View File

@@ -1,6 +1,7 @@
/* eslint-disable sonarjs/no-identical-functions */
import { Fragment, useMemo, useState } from 'react';
import { Button, Input, Skeleton } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Skeleton } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';

View File

@@ -1,5 +1,6 @@
import { useMemo } from 'react';
import { Button, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { Check, TableColumnsSplit, X } from '@signozhq/icons';
import { Filter as FilterType } from 'types/api/quickFilters/getCustomFilters';

View File

@@ -0,0 +1,12 @@
.route-tab-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 4px;
}
.route-tab-extra {
display: flex;
align-items: center;
}

View File

@@ -70,7 +70,7 @@ describe('RouteTab component', () => {
</Router>,
);
expect(history.location.pathname).toBe('/');
fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
fireEvent.mouseDown(screen.getByRole('tab', { name: 'Tab2' }));
expect(history.location.pathname).toBe('/tab2');
});
@@ -87,7 +87,7 @@ describe('RouteTab component', () => {
/>
</Router>,
);
fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
fireEvent.mouseDown(screen.getByRole('tab', { name: 'Tab2' }));
expect(onChangeHandler).toHaveBeenCalled();
});
});

View File

@@ -1,10 +1,17 @@
import './RouteTab.styles.scss';
import {
generatePath,
matchPath,
useLocation,
useParams,
} from 'react-router-dom';
import { Tabs, TabsProps } from 'antd';
import {
TabsContent,
TabsList,
TabsRoot,
TabsTrigger,
} from '@signozhq/ui/tabs';
import HeaderRightSection from 'components/HeaderRightSection/HeaderRightSection';
import { RouteTabProps } from './types';
@@ -16,11 +23,13 @@ interface Params {
function RouteTab({
routes,
activeKey,
defaultActiveKey,
onChangeHandler,
history,
showRightSection,
...rest
}: RouteTabProps & TabsProps): JSX.Element {
showRightSection = true,
tabBarExtraContent,
hideTabBar = false,
}: RouteTabProps): JSX.Element {
const params = useParams<Params>();
const location = useLocation();
@@ -46,38 +55,38 @@ function RouteTab({
}
};
const items = routes.map(({ Component, name, route, key }) => ({
label: name,
key,
tabKey: route,
children: <Component />,
}));
const resolvedActiveKey = currentRoute?.key || activeKey;
const extraContent =
tabBarExtraContent ??
(showRightSection && (
<HeaderRightSection enableAnnouncements={false} enableShare enableFeedback />
));
return (
<Tabs
onChange={onChange}
destroyInactiveTabPane
activeKey={currentRoute?.key || activeKey}
defaultActiveKey={currentRoute?.key || activeKey}
animated
items={items}
tabBarExtraContent={
showRightSection && (
<HeaderRightSection
enableAnnouncements={false}
enableShare
enableFeedback
/>
)
}
{...rest}
/>
<TabsRoot
value={resolvedActiveKey}
defaultValue={defaultActiveKey ?? resolvedActiveKey}
onValueChange={onChange}
>
{!hideTabBar && (
<div className="route-tab-header">
<TabsList>
{routes.map(({ name, key }) => (
<TabsTrigger key={key} value={key}>
{name}
</TabsTrigger>
))}
</TabsList>
{extraContent && <div className="route-tab-extra">{extraContent}</div>}
</div>
)}
{routes.map(({ key, Component }) => (
<TabsContent key={key} value={key}>
<Component />
</TabsContent>
))}
</TabsRoot>
);
}
RouteTab.defaultProps = {
onChangeHandler: undefined,
showRightSection: true,
};
export default RouteTab;

View File

@@ -1,5 +1,5 @@
import { TabsProps } from 'antd';
import { History } from 'history';
import { ReactNode } from 'react';
export type TabRoutes = {
name: React.ReactNode;
@@ -10,8 +10,11 @@ export type TabRoutes = {
export interface RouteTabProps {
routes: TabRoutes[];
activeKey: TabsProps['activeKey'];
activeKey: string | undefined;
defaultActiveKey?: string;
onChangeHandler?: (key: string) => void;
history: History<unknown>;
showRightSection: boolean;
showRightSection?: boolean;
tabBarExtraContent?: ReactNode;
hideTabBar?: boolean;
}

View File

@@ -1,5 +1,6 @@
import { useMemo, useState } from 'react';
import { Button, Input, Select, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Select, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { CircleX, Trash } from '@signozhq/icons';
import { useAppContext } from 'providers/App/App';

View File

@@ -1,4 +1,5 @@
import { Collapse, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Collapse } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useCreateAlertState } from '../context';

View File

@@ -1,5 +1,6 @@
import { useMemo } from 'react';
import { Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { ADVANCED_OPTIONS_TIME_UNIT_OPTIONS } from '../../context/constants';

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import './TimeInput.scss';
export interface TimeInputProps {

View File

@@ -1,4 +1,5 @@
import { Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useCreateAlertState } from '../context';

View File

@@ -16,9 +16,10 @@ import {
Plus,
X,
} from '@signozhq/icons';
import { Button, Card, Input, Modal, Popover, Tooltip } from 'antd';
import { Button, Card, Modal, Popover, Tooltip } from 'antd';
import { Badge } from '@signozhq/ui/badge';
import { Typography } from '@signozhq/ui/typography';
import { Input } from '@signozhq/ui/input';
import logEvent from 'api/common/logEvent';
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';

View File

@@ -1,70 +0,0 @@
.settings-tabs {
.ant-tabs-nav-list {
height: 32px;
flex-shrink: 0;
border-radius: 2px;
border: 1px solid var(--l1-border);
background: var(--l2-background);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
transition: opacity 0.1s !important;
.ant-tabs-tab + .ant-tabs-tab {
margin: 0px;
}
.ant-tabs-tab:not(:last-child) {
border-right: 1px solid var(--l1-border) !important;
}
.overview-btn {
width: 114px;
display: flex;
align-items: center;
justify-content: center;
}
.variables-btn {
width: 114px;
display: flex;
align-items: center;
justify-content: center;
}
.public-dashboard-btn {
width: 150px;
display: flex;
align-items: center;
justify-content: center;
&.disabled-btn {
opacity: 0.5;
cursor: not-allowed;
}
}
.ant-tabs-ink-bar {
display: none;
}
.ant-tabs-tab-active {
.overview-btn {
border-radius: 2px 0px 0px 2px;
background: var(--l1-border);
}
.variables-btn {
border-radius: 2px 0px 0px 2px;
background: var(--l1-border);
}
.public-dashboard-btn {
border-radius: 2px 0px 0px 2px;
background: var(--l1-border);
}
}
}
.ant-tabs-nav::before {
border-bottom: none;
}
}

View File

@@ -1,4 +1,4 @@
import { Button, Tabs, Tooltip } from 'antd';
import { Tabs, TabItemProps } from '@signozhq/ui/tabs';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import { Braces, Globe, Table } from '@signozhq/icons';
import { useAppContext } from 'providers/App/App';
@@ -9,8 +9,6 @@ import DashboardVariableSettings from './DashboardVariableSettings';
import GeneralDashboardSettings from './General';
import PublicDashboardSetting from './PublicDashboard';
import './DashboardSettingsContent.styles.scss';
function DashboardSettings({
variablesSettingsTabHandle,
}: {
@@ -21,49 +19,26 @@ function DashboardSettings({
const enablePublicDashboard = isCloudUser || isEnterpriseSelfHostedUser;
const publicDashboardItem = {
label: (
<Tooltip
title={
user?.role !== USER_ROLES.ADMIN
? 'Only admins can publish / manage public dashboards'
: ''
}
placement="right"
>
<Button
type="text"
icon={<Globe size={14} />}
className={`public-dashboard-btn ${
user?.role !== USER_ROLES.ADMIN ? 'disabled-btn' : ''
}`}
>
Publish
</Button>
</Tooltip>
),
const publicDashboardItem: TabItemProps = {
key: 'public-dashboard',
label: 'Publish',
prefixIcon: <Globe size={14} />,
children: <PublicDashboardSetting />,
disabled: user?.role !== USER_ROLES.ADMIN,
disabledReason: 'Only admins can publish / manage public dashboards',
};
const items = [
const items: TabItemProps[] = [
{
label: (
<Button type="text" icon={<Table size={14} />} className="overview-btn">
Overview
</Button>
),
key: 'general',
label: 'Overview',
prefixIcon: <Table size={14} />,
children: <GeneralDashboardSettings />,
},
{
label: (
<Button type="text" icon={<Braces size={14} />} className="variables-btn">
Variables
</Button>
),
key: 'variables',
label: 'Variables',
prefixIcon: <Braces size={14} />,
children: (
<DashboardVariableSettings
variablesSettingsTabHandle={variablesSettingsTabHandle}
@@ -73,7 +48,7 @@ function DashboardSettings({
...(enablePublicDashboard ? [publicDashboardItem] : []),
];
return <Tabs items={items} animated className="settings-tabs" />;
return <Tabs items={items} />;
}
export default DashboardSettings;

View File

@@ -1,5 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Button, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { PrecisionOption, PrecisionOptionsEnum } from 'components/Graph/types';
import { ResizeTable } from 'components/ResizeTable';
import { useNotifications } from 'hooks/useNotifications';

View File

@@ -22,7 +22,6 @@ import { Color } from '@signozhq/design-tokens';
import {
Button,
ColorPicker,
Input,
Modal,
RefSelectProps,
Select,
@@ -30,6 +29,7 @@ import {
} from 'antd';
import { Divider } from '@signozhq/ui/divider';
import { Typography } from '@signozhq/ui/typography';
import { Input } from '@signozhq/ui/input';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageKey from 'api/browser/localstorage/set';
import logEvent from 'api/common/logEvent';

View File

@@ -1,7 +1,7 @@
import { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { EmailChannel } from '../../CreateAlertChannels/config';
function EmailForm({ setSelectedConfig }: EmailFormProps): JSX.Element {

View File

@@ -1,6 +1,7 @@
import { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { MarkdownRenderer } from 'components/MarkdownRenderer/MarkdownRenderer';
import { WebhookChannel } from '../../CreateAlertChannels/config';

View File

@@ -1,7 +1,8 @@
import { Dispatch, ReactElement, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Form, FormInstance, Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Switch } from '@signozhq/ui/switch';
import { Form, FormInstance, Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import type { Store } from 'antd/lib/form/interface';
import ROUTES from 'constants/routes';

View File

@@ -6,7 +6,8 @@ import { useIsFetching } from 'react-query';
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Button, Form, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Form, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -5,12 +5,12 @@ import { useCopyToClipboard } from 'react-use';
import { Color } from '@signozhq/design-tokens';
import { Badge } from '@signozhq/ui/badge';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import {
Col,
Collapse,
DatePicker,
Form,
Input,
InputNumber,
Modal,
Row,

View File

@@ -1,4 +1,5 @@
import { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { CloudintegrationtypesCredentialsDTO } from 'api/generated/services/sigNoz.schemas';
function RenderConnectionFields({

View File

@@ -1,5 +1,4 @@
import { Button, Tabs, TabsProps } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { Tabs, TabItemProps } from '@signozhq/ui/tabs';
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';
import { CableCar, Group } from '@signozhq/icons';
import { IntegrationDetailedProps } from 'types/api/integrations/types';
@@ -22,18 +21,11 @@ function IntegrationDetailContent(
): JSX.Element {
const { activeDetailTab, integrationData, integrationId, setActiveDetailTab } =
props;
const items: TabsProps['items'] = [
const items: TabItemProps[] = [
{
key: 'overview',
label: (
<Button
type="text"
className="integration-tab-btns"
icon={<CableCar size={14} />}
>
<Typography.Text className="typography">Overview</Typography.Text>
</Button>
),
label: 'Overview',
prefixIcon: <CableCar size={14} />,
children: (
<Overview
categories={integrationData.categories}
@@ -44,15 +36,8 @@ function IntegrationDetailContent(
},
{
key: 'configuration',
label: (
<Button
type="text"
className="integration-tab-btns"
icon={<ConfigureIcon />}
>
<Typography.Text className="typography">Configure</Typography.Text>
</Button>
),
label: 'Configure',
prefixIcon: <ConfigureIcon />,
children: (
<Configure
configuration={integrationData.configuration}
@@ -62,15 +47,8 @@ function IntegrationDetailContent(
},
{
key: 'dataCollected',
label: (
<Button
type="text"
className="integration-tab-btns"
icon={<Group size={14} />}
>
<Typography.Text className="typography">Data Collected</Typography.Text>
</Button>
),
label: 'Data Collected',
prefixIcon: <Group size={14} />,
children: (
<DataCollected
logsData={integrationData.data_collected.logs}
@@ -81,11 +59,7 @@ function IntegrationDetailContent(
];
return (
<div className="integration-detail-container">
<Tabs
activeKey={activeDetailTab}
items={items}
onChange={setActiveDetailTab}
/>
<Tabs value={activeDetailTab} items={items} onChange={setActiveDetailTab} />
</div>
);
}

View File

@@ -168,45 +168,6 @@
padding: 10px 16px;
border: 1px solid var(--l1-border);
background: var(--l1-background);
.integration-tab-btns {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 8px 18px 8px !important;
.typography {
color: var(--l1-foreground);
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
}
}
.integration-tab-btns:hover {
&.ant-btn-text {
background-color: unset !important;
}
}
.ant-tabs-nav-list {
gap: 24px;
}
.ant-tabs-nav {
padding: 0px !important;
}
.ant-tabs-tab {
padding: 0 !important;
}
.ant-tabs-tab + .ant-tabs-tab {
margin: 0px !important;
}
}
.uninstall-integration-bar {

View File

@@ -1,6 +1,7 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Form } from 'antd';
import apply from 'api/v3/licenses/post';
import { useNotifications } from 'hooks/useNotifications';
import APIError from 'types/api/error';

View File

@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { ChangeEvent, useState } from 'react';
import { Button, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import ApacheIcon from 'assets/CustomIcons/ApacheIcon';
import DockerIcon from 'assets/CustomIcons/DockerIcon';

View File

@@ -12,17 +12,9 @@ import { useTranslation } from 'react-i18next';
import { generatePath } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { DropdownMenuSimple, type MenuItem } from '@signozhq/ui/dropdown-menu';
import {
Button,
Flex,
Input,
Modal,
Popover,
Skeleton,
Table,
Tooltip,
} from 'antd';
import { Button, Flex, Modal, Popover, Skeleton, Table, Tooltip } from 'antd';
import { Badge } from '@signozhq/ui/badge';
import { Switch } from '@signozhq/ui/switch';
import { Typography } from '@signozhq/ui/typography';

View File

@@ -1,7 +1,8 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { LoaderCircle, Check } from '@signozhq/icons';
import { Button, Input, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import { useNotifications } from 'hooks/useNotifications';

View File

@@ -2,8 +2,9 @@ import { ReactNode, useState } from 'react';
import MEditor, { EditorProps, Monaco } from '@monaco-editor/react';
import { Color } from '@signozhq/design-tokens';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import { Switch } from '@signozhq/ui/switch';
import { Collapse, Input } from 'antd';
import { Collapse } from 'antd';
import { Divider } from '@signozhq/ui/divider';
import { Badge } from '@signozhq/ui/badge';
import { Typography } from '@signozhq/ui/typography';

View File

@@ -2,7 +2,8 @@ import { ChangeEvent, useCallback, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { CirclePlus, X } from '@signozhq/icons';
import { Col, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Col } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import { fieldSearchFilter } from 'lib/logs/fieldSearch';
import { AppState } from 'store/reducers';

View File

@@ -2,7 +2,8 @@ import { useCallback, useMemo, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { SquareX, X } from '@signozhq/icons';
import { Button, Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Select } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import {
ConditionalOperators,

View File

@@ -1,6 +1,7 @@
import { Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { Select } from 'antd';
// TODO(@signozhq/ui-input): migrate this <Input> once @signozhq/ui Input
// supports the `onWheel` handler (used to blur on scroll for number inputs).
import { Input, Select } from 'antd';
import classNames from 'classnames';
import { TIME_AGGREGATION_OPTIONS } from './constants';

View File

@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useQueryClient } from 'react-query';
import type { TableColumnsType as ColumnsType } from 'antd';
import { Button, Collapse, Input, Select, Spin } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Collapse, Select, Spin } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import {

View File

@@ -7,7 +7,8 @@ import {
DropResult,
} from 'react-beautiful-dnd';
import { Color } from '@signozhq/design-tokens';
import { Button, Input, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Tooltip } from 'antd';
import {
DropdownMenu,
DropdownMenuContent,

View File

@@ -1,5 +1,7 @@
import { useEffect, useMemo, useState } from 'react';
import { Button, Col, Form, Input as AntInput, Input, Row } from 'antd';
// TODO(@signozhq/ui-input): migrate <Input> once @signozhq/ui Input
// supports the `spellCheck` prop on the URL input below.
import { Button, Col, Form, Input, Input as AntInput, Row } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { CONTEXT_LINK_FIELDS } from 'container/NewWidget/RightContainer/ContextLinks/constants';
import {

View File

@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Blocks, Check, LoaderCircle } from '@signozhq/icons';
import { Button, Card, Form, Input, Select, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Card, Form, Select, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -1,7 +1,8 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Check, Server, LoaderCircle } from '@signozhq/icons';
import { Button, Card, Form, Input, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Card, Form, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -1,6 +1,7 @@
import { useTranslation } from 'react-i18next';
import { Plus, Trash2 } from '@signozhq/icons';
import { Button, Form, FormInstance, Input, Select, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Form, FormInstance, Select, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';

View File

@@ -1,4 +1,6 @@
import { ChangeEventHandler, useState } from 'react';
// TODO(@signozhq/ui-input): migrate to @signozhq/ui Input once the antd
// `InputProps` spread (`size`, etc.) is no longer needed on this wrapper.
import { Input, InputProps } from 'antd';
function CSVInput({ value, onChange, ...otherProps }: InputProps): JSX.Element {

View File

@@ -1,7 +1,8 @@
import { useEffect, useState } from 'react';
import { Info } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Switch } from '@signozhq/ui/switch';
import { Flex, Form, Input, Space, Tooltip } from 'antd';
import { Flex, Form, Space, Tooltip } from 'antd';
import { ProcessorData } from 'types/api/pipeline/def';
import { PREDEFINED_MAPPING } from '../config';

View File

@@ -1,6 +1,7 @@
import { useTranslation } from 'react-i18next';
import { Form, Input, Select, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Switch } from '@signozhq/ui/switch';
import { Form, Select, Space } from 'antd';
import { ModalFooterTitle } from 'container/PipelinePage/styles';
import { ProcessorData } from 'types/api/pipeline/def';

View File

@@ -2,7 +2,8 @@ import React, { ChangeEvent, useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { Plus, Search } from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Button, Flex, Form, Input, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, Form, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import {
useDeleteDowntimeScheduleByID,

View File

@@ -152,6 +152,11 @@ export function PlannedDowntimeForm(
const saveHandler = useCallback(
async (values: PlannedDowntimeFormData) => {
const { startTime, timezone } = values;
if (!startTime || !timezone) {
// unreachable
return;
}
const data: AlertmanagertypesPostablePlannedMaintenanceDTO = {
alertIds:
values.alertRuleScope === 'all'
@@ -162,9 +167,9 @@ export function PlannedDowntimeForm(
name: values.name,
scope: values.scope,
schedule: {
startTime: values.startTime?.format(),
startTime: startTime.format(),
endTime: values.endTime?.format(),
timezone: values.timezone!,
timezone,
recurrence: values.recurrence,
},
};
@@ -201,25 +206,17 @@ export function PlannedDowntimeForm(
],
);
const onFinish = async (values: PlannedDowntimeFormData): Promise<void> => {
const { recurrence } = values;
const recurrenceData =
!recurrence ||
recurrence.repeatType === recurrenceOptions.doesNotRepeat.value
? undefined
: {
duration: recurrence.duration
? `${recurrence.duration}${durationUnit}`
: '',
startTime: values.startTime!.format(),
endTime: values.endTime?.format(),
repeatOn: recurrence.repeatOn,
repeatType: recurrence.repeatType,
};
const rec = values.recurrence;
const recurrence =
rec && rec.repeatType !== recurrenceOptions.doesNotRepeat.value
? {
duration: `${rec.duration}${durationUnit}`,
repeatOn: rec.repeatOn,
repeatType: rec.repeatType,
}
: undefined;
await saveHandler({
...values,
recurrence: recurrenceData,
});
await saveHandler({ ...values, recurrence });
};
const handleFormData = (data: Partial<PlannedDowntimeFormData>): void => {
@@ -276,9 +273,6 @@ export function PlannedDowntimeForm(
const formattedInitialValues = useMemo((): PlannedDowntimeFormData => {
const { schedule } = initialValues;
const startTime = schedule?.recurrence?.startTime || schedule?.startTime;
const endTime = schedule?.recurrence?.endTime || schedule?.endTime;
const initialAlertIds = initialValues.alertIds || [];
return {
@@ -286,8 +280,12 @@ export function PlannedDowntimeForm(
alertRuleScope:
isEditMode && initialAlertIds.length === 0 ? 'all' : 'specific',
alertRules: getAlertOptionsFromIds(initialAlertIds, alertOptions),
startTime: startTime ? dayjs(startTime).tz(schedule.timezone) : null,
endTime: endTime ? dayjs(endTime).tz(schedule.timezone) : null,
startTime: schedule?.startTime
? dayjs(schedule.startTime).tz(schedule.timezone)
: null,
endTime: schedule?.endTime
? dayjs(schedule.endTime).tz(schedule.timezone)
: null,
recurrence: {
...schedule?.recurrence,
repeatType: !isScheduleRecurring(schedule)

View File

@@ -142,7 +142,6 @@ export function CollapseListContent({
updated_by_name?: string;
alertOptions?: DefaultOptionType[];
}): JSX.Element {
const repeats = schedule?.recurrence;
const renderItems = (title: string, value: ReactNode): JSX.Element => (
<div className="render-item-collapse-list">
<Typography>{title}</Typography>
@@ -193,10 +192,7 @@ export function CollapseListContent({
'Timezone',
<Typography>{schedule?.timezone || '-'}</Typography>,
)}
{renderItems(
'Repeats',
<Typography>{recurrenceInfo(repeats, schedule?.timezone)}</Typography>,
)}
{renderItems('Repeats', <Typography>{recurrenceInfo(schedule)}</Typography>)}
{renderItems(
'Alerts silenced',
alertOptions?.length ? (

View File

@@ -6,7 +6,7 @@ import type {
DeleteDowntimeScheduleByIDPathParameters,
RenderErrorResponseDTO,
AlertmanagertypesPlannedMaintenanceDTO,
AlertmanagertypesRecurrenceDTO,
AlertmanagertypesScheduleDTO,
} from 'api/generated/services/sigNoz.schemas';
import type { ErrorType } from 'api/generatedAPIInstance';
import { AxiosError } from 'axios';
@@ -66,14 +66,17 @@ export const getAlertOptionsFromIds = (
);
export const recurrenceInfo = (
recurrence?: AlertmanagertypesRecurrenceDTO | null,
timezone?: string,
schedule?: AlertmanagertypesScheduleDTO | null,
): string => {
if (!schedule) {
return 'No';
}
const { startTime, endTime, timezone, recurrence } = schedule;
if (!recurrence) {
return 'No';
}
const { startTime, duration, repeatOn, repeatType, endTime } = recurrence;
const { duration, repeatOn, repeatType } = recurrence;
const formattedStartTime = startTime
? formatDateTime(startTime, timezone)
@@ -95,7 +98,7 @@ export const defaultInitialValues: Partial<AlertmanagertypesPlannedMaintenanceDT
timezone: '',
endTime: undefined,
recurrence: undefined,
startTime: undefined,
startTime: '',
},
alertIds: [],
createdAt: undefined,

View File

@@ -11,7 +11,7 @@ export const buildSchedule = (
schedule: Partial<AlertmanagertypesScheduleDTO>,
): AlertmanagertypesScheduleDTO => ({
timezone: schedule?.timezone ?? '',
startTime: schedule?.startTime,
startTime: schedule?.startTime ?? '',
endTime: schedule?.endTime,
recurrence: schedule?.recurrence,
});

View File

@@ -8,4 +8,16 @@
grid-template-columns: 60% 35%;
justify-content: space-between;
gap: 16px;
.input-with-label {
.label {
box-sizing: border-box;
height: 36px;
}
.input {
box-sizing: border-box;
height: 36px;
}
}
}

View File

@@ -1,6 +1,7 @@
import { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { Input, Skeleton } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Skeleton } from 'antd';
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import { QUERY_BUILDER_KEY_TYPES } from 'constants/antlrQueryConstants';

View File

@@ -1,7 +1,8 @@
import { ChangeEvent, useMemo } from 'react';
import { Plus, Search } from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Button, Flex, Input, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useAppContext } from 'providers/App/App';
import { USER_ROLES } from 'types/roles';

View File

@@ -1,5 +1,5 @@
import { useCallback, useMemo, useState } from 'react';
import { Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { Collapse, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Collapse, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import { Diamond } from '@signozhq/icons';

View File

@@ -9,10 +9,10 @@ import {
useState,
} from 'react';
import { useMutation, useQuery } from 'react-query';
import { Input } from '@signozhq/ui/input';
import {
Button,
Checkbox,
Input,
Modal,
Select,
Skeleton,

View File

@@ -1,5 +1,7 @@
import { Input } from 'antd';
// TODO(@signozhq/ui-input): migrate this styled(Input) once @signozhq/ui
// Input supports `addonAfter` (the consumer renders `<InputComponent addonAfter="ms">`).
import { Typography } from '@signozhq/ui/typography';
import { Input } from 'antd';
import styled from 'styled-components';
export const DurationText = styled.div`

View File

@@ -8,7 +8,8 @@ import {
import { useQuery } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { AutoComplete, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { AutoComplete } from 'antd';
import getTagFilters from 'api/trace/getTagFilter';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -2,7 +2,8 @@ import { useMemo, useState } from 'react';
import { useQuery } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { AutoComplete, Input, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { AutoComplete, Space } from 'antd';
import getTagFilters from 'api/trace/getTagFilter';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -1,6 +1,7 @@
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { ArrowLeft, Check, Loader, Plus, Search } from '@signozhq/icons';
import { Button, Input, Spin } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Spin } from 'antd';
import cx from 'classnames';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import SignozModal from 'components/SignozModal/SignozModal';

View File

@@ -1,4 +1,4 @@
import { Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import styled from 'styled-components';
export const InputComponent = styled(Input)`

View File

@@ -1,5 +1,6 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import './DropRateView.styles.scss';

View File

@@ -1,26 +1,3 @@
.service-route-tab {
margin-bottom: 64px;
.ant-tabs-nav {
&::before {
border-bottom: 1px solid var(--l1-border);
}
.ant-tabs-nav-wrap {
.ant-tabs-nav-list {
.ant-tabs-ink-bar {
background-color: var(--primary-background) !important;
}
.ant-tabs-tab {
font-size: 13px;
font-family: 'Inter';
color: var(--l1-foreground);
line-height: 20px;
letter-spacing: -0.07px;
gap: 10px;
}
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
color: var(--accent-primary);
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
import { useParams } from 'react-router-dom';
import { Tabs, TabsProps } from 'antd';
import { Tabs, TabItemProps } from '@signozhq/ui/tabs';
import { QueryParams } from 'constants/query';
import DBCall from 'container/MetricsApplication/Tabs/DBCall';
import External from 'container/MetricsApplication/Tabs/External';
@@ -24,7 +24,7 @@ function MetricsApplication(): JSX.Element {
const urlQuery = useUrlQuery();
const { safeNavigate } = useSafeNavigate();
const items: TabsProps['items'] = [
const items: TabItemProps[] = [
{
label: TAB_KEY_VS_LABEL[MetricsApplicationTab.OVER_METRICS],
key: MetricsApplicationTab.OVER_METRICS,
@@ -53,9 +53,8 @@ function MetricsApplication(): JSX.Element {
<ApDexApplication />
<Tabs
items={items}
activeKey={activeKey}
value={activeKey}
className="service-route-tab"
destroyInactiveTabPane
onChange={onTabChange}
/>
</div>

View File

@@ -1,9 +0,0 @@
.pipeline-tabs {
.ant-tabs-content {
padding: 0 16px;
}
.ant-tabs-tabpane-hidden {
display: none !important;
}
}

View File

@@ -2,8 +2,7 @@ import { useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import * as Sentry from '@sentry/react';
import type { TabsProps } from 'antd';
import { Tabs } from 'antd';
import { Tabs, TabItemProps } from '@signozhq/ui/tabs';
import getPipeline from 'api/pipeline/get';
import Spinner from 'components/Spinner';
import ChangeHistory from 'container/PipelinePage/Layouts/ChangeHistory';
@@ -13,8 +12,6 @@ import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFall
import { SuccessResponse } from 'types/api';
import { Pipeline } from 'types/api/pipeline/def';
import './Pipelines.styles.scss';
const pipelineRefetchInterval = (
pipelineResponse: SuccessResponse<Pipeline> | undefined,
): number | false => {
@@ -46,7 +43,7 @@ function Pipelines(): JSX.Element {
refetchInterval: pipelineRefetchInterval,
});
const tabItems: TabsProps['items'] = useMemo(
const tabItems: TabItemProps[] = useMemo(
() => [
{
key: 'pipelines',
@@ -83,11 +80,7 @@ function Pipelines(): JSX.Element {
return (
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
<Tabs
className="pipeline-tabs"
defaultActiveKey="pipelines"
items={tabItems}
/>
<Tabs defaultValue="pipelines" items={tabItems} />
</Sentry.ErrorBoundary>
);
}

View File

@@ -28,6 +28,10 @@
.learn-more {
font-size: 14px;
}
.search-input-container {
margin-top: 16px;
margin-bottom: 8px;
}
.ant-input-affix-wrapper {
margin-top: 16px;

View File

@@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Button } from '@signozhq/ui/button';
import { ColorPicker, Input, Modal, Table, TableProps } from 'antd';
import { Input } from '@signozhq/ui/input';
import { ColorPicker, Modal, Table, TableProps } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import {
@@ -311,12 +312,15 @@ function SaveView(): JSX.Element {
Learn more
</Typography.Link>
</Typography.Text>
<Input
placeholder="Search for views..."
prefix={<Search size={12} color={Color.BG_VANILLA_400} />}
value={searchValue}
onChange={handleSearch}
/>
<div className="search-input-container">
<Input
placeholder="Search for views..."
prefix={<Search size={12} color={Color.BG_VANILLA_400} />}
value={searchValue}
onChange={handleSearch}
className="search-input"
/>
</div>
<Table
columns={columns}

View File

@@ -340,7 +340,7 @@ function SettingsPage(): JSX.Element {
routes={routes}
activeKey={pathname}
history={history}
tabBarStyle={{ display: 'none' }}
hideTabBar
/>
</div>
</div>

View File

@@ -71,88 +71,6 @@
flex-direction: column;
gap: 25px;
padding-top: 16px;
.flamegraph-waterfall-toggle {
display: flex;
gap: 4px;
align-items: center;
justify-content: center;
height: 31px;
color: var(--l2-foreground);
padding: 5px 20px;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
.ant-btn-icon {
margin-inline-end: 0px !important;
}
}
.span-list-toggle {
display: flex;
gap: 4px;
align-items: center;
justify-content: center;
height: 31px;
padding: 5px 20px;
color: var(--l2-foreground);
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
.ant-btn-icon {
margin-inline-end: 0px !important;
}
}
.trace-visualisation-tabs {
.ant-tabs-tab {
border-radius: 2px 0px 0px 0px;
background: var(--l2-background);
border-radius: 2px 2px 0px 0px;
border: 1px solid var(--l1-border);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
height: 31px;
}
.ant-tabs-tab-active {
background-color: var(--l1-background);
.ant-btn {
color: var(--l1-foreground) !important;
}
}
.ant-tabs-tab + .ant-tabs-tab {
margin: 0px;
border-left: 0px;
}
.ant-tabs-ink-bar {
height: 1px !important;
background: var(--l1-background) !important;
}
.ant-tabs-nav-list {
transform: translate(15px, 0px) !important;
}
.ant-tabs-nav::before {
border-bottom: 1px solid var(--l1-border);
}
.ant-tabs-nav {
margin: 0px;
padding: 0px !important;
}
}
}
}
}

View File

@@ -5,7 +5,7 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from '@signozhq/resizable';
import { Button, Tabs } from 'antd';
import { Tabs, TabItemProps } from '@signozhq/ui/tabs';
import FlamegraphImg from 'assets/TraceDetail/Flamegraph';
import cx from 'classnames';
import TraceFlamegraph from 'container/PaginatedTraceFlamegraph/PaginatedTraceFlamegraph';
@@ -86,18 +86,11 @@ function TraceDetailsV2(): JSX.Element {
}
}, [noData]);
const items = [
const items: TabItemProps[] = [
{
label: (
<Button
type="text"
icon={<FlamegraphImg />}
className="flamegraph-waterfall-toggle"
>
Flamegraph
</Button>
),
key: 'flamegraph',
label: 'Flamegraph',
prefixIcon: <FlamegraphImg />,
children: (
<>
<TraceFlamegraph
@@ -145,11 +138,7 @@ function TraceDetailsV2(): JSX.Element {
totalSpans={traceData?.payload?.totalSpansCount || 0}
notFound={noData}
/>
{!noData ? (
<Tabs items={items} animated className="trace-visualisation-tabs" />
) : (
<NoData />
)}
{!noData ? <Tabs items={items} /> : <NoData />}
</ResizablePanel>
<ResizableHandle withHandle className="resizable-handle" />

View File

@@ -1,7 +1,8 @@
import { Input, Select, Skeleton } from 'antd';
import { Select, Skeleton } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Button } from '@signozhq/ui/button';
import { Typography } from '@signozhq/ui/typography';
import { Input } from '@signozhq/ui/input';
import cx from 'classnames';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';

View File

@@ -1,6 +1,7 @@
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { Button } from '@signozhq/ui/button';
import { Input, Spin } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Spin } from 'antd';
import cx from 'classnames';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import SignozModal from 'components/SignozModal/SignozModal';

View File

@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useQueryClient } from 'react-query';
import { Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import SignozModal from 'components/SignozModal/SignozModal';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useRenameFunnel } from 'hooks/TracesFunnels/useFunnels';

View File

@@ -9,10 +9,10 @@
.ant-input-prefix {
margin-inline-end: 6px;
}
&,
input {
font-family: Inter;
background: var(--l2-background);
font-size: 14px;
line-height: 18px;
font-style: normal;

View File

@@ -1,6 +1,7 @@
import { ChangeEvent } from 'react';
import { Color } from '@signozhq/design-tokens';
import { Button, Input, Popover, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Popover, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { ArrowDownWideNarrow, Check, Plus, Search } from '@signozhq/icons';
import { useAppContext } from 'providers/App/App';

View File

@@ -22,21 +22,6 @@ $dark-theme: 'darkMode';
&__tabs {
margin-top: 148px;
.ant-tabs {
&-nav {
&::before {
border-color: var(--l1-border);
.#{$light-theme} & {
border-color: var(--l1-border);
}
}
}
&-nav-wrap {
justify-content: center;
}
}
}
&__modal {

View File

@@ -2,7 +2,7 @@
import React, { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useMutation } from 'react-query';
import type { TabsProps } from 'antd';
import type { TabItemProps } from '@signozhq/ui/tabs';
import {
Alert,
Button,
@@ -14,8 +14,8 @@ import {
Row,
Skeleton,
Space,
Tabs,
} from 'antd';
import { Tabs } from '@signozhq/ui/tabs';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import updateCreditCardApi from 'api/v1/checkout/create';
@@ -154,7 +154,7 @@ export default function WorkspaceBlocked(): JSX.Element {
/>
));
const tabItems: TabsProps['items'] = [
const tabItems: TabItemProps[] = [
{
key: 'whyChooseSignoz',
label: t('whyChooseSignoz'),
@@ -398,8 +398,8 @@ export default function WorkspaceBlocked(): JSX.Element {
<div className="workspace-locked__tabs">
<Tabs
items={tabItems}
defaultActiveKey="youAreInGoodCompany"
onTabClick={handleTabClick}
defaultValue="youAreInGoodCompany"
onChange={handleTabClick}
/>
</div>
</>

View File

@@ -204,5 +204,12 @@
background: var(--l2-background);
height: 38px;
width: 38px;
&:focus:not(:focus-visible),
&.ant-btn:focus:not(:focus-visible) {
border-color: var(--l2-border);
outline: none;
box-shadow: none;
}
}
}

View File

@@ -825,5 +825,6 @@ body.ai-assistant-panel-open {
// overrides
:root {
--input-focus-outline-width: 0;
--tab-list-primary-gap: 12px;
--radius-2: 4px;
}

View File

@@ -13,7 +13,6 @@ import (
"github.com/DATA-DOG/go-sqlmock"
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerstore/sqlalertmanagerstore"
"github.com/SigNoz/signoz/pkg/alertmanager/nfmanager/nfmanagertest"
"github.com/SigNoz/signoz/pkg/factory/factorytest"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstoretest"
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
@@ -30,7 +29,7 @@ import (
func newTestMaintenanceStore() alertmanagertypes.MaintenanceStore {
ss := sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual)
return sqlalertmanagerstore.NewMaintenanceStore(ss, factorytest.NewSettings())
return sqlalertmanagerstore.NewMaintenanceStore(ss)
}
func TestServerSetConfigAndStop(t *testing.T) {

View File

@@ -2,11 +2,9 @@ package sqlalertmanagerstore
import (
"context"
"log/slog"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
@@ -16,13 +14,11 @@ import (
type maintenance struct {
sqlstore sqlstore.SQLStore
logger *slog.Logger
}
func NewMaintenanceStore(store sqlstore.SQLStore, providerSettings factory.ProviderSettings) alertmanagertypes.MaintenanceStore {
func NewMaintenanceStore(store sqlstore.SQLStore) alertmanagertypes.MaintenanceStore {
return &maintenance{
sqlstore: store,
logger: providerSettings.Logger,
}
}
@@ -41,11 +37,7 @@ func (r *maintenance) ListPlannedMaintenance(ctx context.Context, orgID string)
gettablePlannedMaintenance := make([]*alertmanagertypes.PlannedMaintenance, 0)
for _, gettableMaintenancesRule := range gettableMaintenancesRules {
m := gettableMaintenancesRule.ToPlannedMaintenance()
gettablePlannedMaintenance = append(gettablePlannedMaintenance, m)
if m.HasScheduleRecurrenceBoundsMismatch() {
r.logger.WarnContext(ctx, "planned_downtime_recurrence_schedule_mismatch", slog.String("maintenance_id", m.ID.StringValue()))
}
gettablePlannedMaintenance = append(gettablePlannedMaintenance, gettableMaintenancesRule.ToPlannedMaintenance())
}
return gettablePlannedMaintenance, nil

View File

@@ -149,6 +149,11 @@ func paginateWithBackfill(
groupBy []qbtypes.GroupByKey,
offset, limit int,
) []map[string]string {
// note: we took a stand here that we are NOT removing those metricGroups from the array that are not in metadataMap.
// we are relying on time adjustment logic from alignedMetricWindow. In future if a user complains about seeing metric groups
// with missing metadata, we can consider removing those groups from the metricGroups array here before paginating.
metricKeySet := make(map[string]bool, len(metricGroups))
for _, g := range metricGroups {
metricKeySet[g.compositeKey] = true
@@ -163,7 +168,7 @@ func paginateWithBackfill(
sort.Strings(metadataOnlyKeys)
totalMetric := len(metricGroups)
totalAll := totalMetric + len(metadataOnlyKeys)
totalAll := len(metadataMap)
end := offset + limit
if end > totalAll {
@@ -307,23 +312,57 @@ func parseFullQueryResponse(
return result
}
// buildSamplesTblFingerprintSubQuery returns a SelectBuilder that selects distinct fingerprints
// from the samples table for the given metric names andtime range.
func (m *module) buildSamplesTblFingerprintSubQuery(metricNames []string, startMs, endMs int64) *sqlbuilder.SelectBuilder {
samplesTableName := telemetrymetrics.WhichSamplesTableToUse(
uint64(startMs), uint64(endMs),
metrictypes.UnspecifiedType,
metrictypes.TimeAggregationUnspecified,
nil,
// alignedMetricWindow returns step-floored time bounds and the metric tables
// to use for the given window. The floor matches what the QB v5 metric
// querier does internally (see querybuilder.AdjustedMetricTimeRange).
// Please use the samplesAdjustedStartMs with samples table and tsAdjustedStartMs with ts tables.
// Both can use the same flooredEndMs.
func alignedMetricWindow(startMs, endMs int64) (
uint64, // samplesAdjustedStartMs
uint64, // flooredEndMs
uint64, // tsAdjustedStartMs
string, // distributedTSTable
string, // localTSTable
string, // distributedSamplesTable
string, // localSamplesTable
) {
samplesAdjustedStartMs := uint64(startMs)
flooredEndMs := uint64(endMs)
stepSecs := querybuilder.RecommendedStepIntervalForMetric(samplesAdjustedStartMs, flooredEndMs)
// note: this is the same flooring logic as in querybuilder.AdjustedMetricTimeRange. Duplicated code.
// TODO(nikhilmantri0902): if the querybuilder.AdjustMetricTimeRange logic changes, this needs to be updated too.
if stepSecs > 0 {
samplesAdjustedStartMs = samplesAdjustedStartMs - (samplesAdjustedStartMs % (stepSecs * 1000))
adjustStep := stepSecs
if adjustStep > 60 {
adjustStep = 60
}
flooredEndMs = flooredEndMs - (flooredEndMs % (adjustStep * 1000))
}
tsAdjustedStartMs, _, distributedTSTable, localTSTable := telemetrymetrics.WhichTSTableToUse(
samplesAdjustedStartMs, flooredEndMs, nil,
)
localSamplesTable := strings.TrimPrefix(samplesTableName, "distributed_")
distributedSamplesTable, localSamplesTable := telemetrymetrics.WhichSamplesTableToUse(
samplesAdjustedStartMs, flooredEndMs,
metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil,
)
return samplesAdjustedStartMs, flooredEndMs, tsAdjustedStartMs, distributedTSTable, localTSTable, distributedSamplesTable, localSamplesTable
}
// buildSamplesTblFingerprintSubQuery returns a SelectBuilder that selects distinct fingerprints
// from the samples table for the given metric names and time range.
// Bounds must already be step-floored by the caller via alignedMetricWindow.
func (m *module) buildSamplesTblFingerprintSubQuery(metricNames []string, samplesTable string, flooredStart, flooredEnd uint64) *sqlbuilder.SelectBuilder {
fpSB := sqlbuilder.NewSelectBuilder()
fpSB.Select("DISTINCT fingerprint")
fpSB.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, localSamplesTable))
fpSB.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, samplesTable))
fpSB.Where(
fpSB.In("metric_name", sqlbuilder.List(metricNames)),
fpSB.GE("unix_milli", startMs),
fpSB.L("unix_milli", endMs),
fpSB.GE("unix_milli", flooredStart),
fpSB.L("unix_milli", flooredEnd),
)
return fpSB
}
@@ -364,7 +403,7 @@ func (m *module) buildFilterClause(ctx context.Context, filter *qbtypes.Filter,
return nil, err
}
if whereClause == nil || whereClause.WhereClause == nil {
if whereClause.IsEmpty() {
return sqlbuilder.NewWhereClause(), nil
}
@@ -454,12 +493,12 @@ func (m *module) getMetadata(
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "groupBy must not be empty")
}
// Pick the optimal timeseries table based on time range; also get adjusted start.
adjustedStart, adjustedEnd, distributedTableName, _ := telemetrymetrics.WhichTSTableToUse(
uint64(startMs), uint64(endMs), nil,
)
// Step-floor the window and pick the right tables — matches the bounds the
// QB v5 metric querier uses, so metadataMap covers the same universe the
// ranking sees (see alignedMetricWindow doc).
samplesStartMs, flooredEndMs, tsAdjustedStartMs, distributedTableName, _, _, localSamplesTable := alignedMetricWindow(startMs, endMs)
fpSB := m.buildSamplesTblFingerprintSubQuery(metricNames, startMs, endMs)
fpSB := m.buildSamplesTblFingerprintSubQuery(metricNames, localSamplesTable, samplesStartMs, flooredEndMs)
// Flatten groupBy keys to string names for SQL expressions and result scanning.
groupByCols := make([]string, len(groupBy))
@@ -494,8 +533,8 @@ func (m *module) getMetadata(
innerSB.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, distributedTableName))
innerSB.Where(
innerSB.In("metric_name", sqlbuilder.List(metricNames)),
innerSB.GE("unix_milli", adjustedStart),
innerSB.L("unix_milli", adjustedEnd),
innerSB.GE("unix_milli", tsAdjustedStartMs),
innerSB.LE("unix_milli", flooredEndMs),
fmt.Sprintf("fingerprint IN (%s)", innerSB.Var(fpSB)),
)

View File

@@ -34,9 +34,8 @@ func (m *module) getPerGroupHostStatusCounts(
pageGroupsFilterExpr := buildPageGroupsFilterExpr(pageGroups)
filterExpr := mergeFilterExpressions(reqFilterExpr, pageGroupsFilterExpr)
adjustedStart, adjustedEnd, distributedTimeSeriesTableName, _ := telemetrymetrics.WhichTSTableToUse(
uint64(req.Start), uint64(req.End), nil,
)
// Step-floor bounds + resolve tables in one shot to match QB v5 querier.
samplesStartMs, flooredEndMs, tsAdjustedStartMs, distributedTimeSeriesTableName, _, _, localSamplesTable := alignedMetricWindow(req.Start, req.End)
hostNameExpr := fmt.Sprintf("JSONExtractString(labels, '%s')", inframonitoringtypes.HostNameAttrKey)
@@ -55,15 +54,15 @@ func (m *module) getPerGroupHostStatusCounts(
)
// Build a fingerprint subquery to restrict to fingerprints with actual sample
// data in the original time range (not the wider timeseries table window).
fpSB := m.buildSamplesTblFingerprintSubQuery(metricNames, req.Start, req.End)
// data in the floored time range.
fpSB := m.buildSamplesTblFingerprintSubQuery(metricNames, localSamplesTable, samplesStartMs, flooredEndMs)
sb.Select(selectCols...)
sb.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, distributedTimeSeriesTableName))
sb.Where(
sb.In("metric_name", sqlbuilder.List(metricNames)),
sb.GE("unix_milli", adjustedStart),
sb.L("unix_milli", adjustedEnd),
sb.GE("unix_milli", tsAdjustedStartMs),
sb.LE("unix_milli", flooredEndMs),
fmt.Sprintf("fingerprint IN (%s)", sb.Var(fpSB)),
)

View File

@@ -9,7 +9,6 @@ import (
"github.com/SigNoz/signoz/pkg/querybuilder"
"github.com/SigNoz/signoz/pkg/telemetrymetrics"
"github.com/SigNoz/signoz/pkg/types/inframonitoringtypes"
"github.com/SigNoz/signoz/pkg/types/metrictypes"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/huandu/go-sqlbuilder"
@@ -190,15 +189,9 @@ func (m *module) getPerGroupNodeConditionCounts(
pageGroupsFilterExpr := buildPageGroupsFilterExpr(pageGroups)
mergedFilterExpr := mergeFilterExpressions(userFilterExpr, pageGroupsFilterExpr)
// Resolve tables. Same convention as pods.
adjustedStart, adjustedEnd, _, localTimeSeriesTable := telemetrymetrics.WhichTSTableToUse(
uint64(start), uint64(end), nil,
)
samplesTable := telemetrymetrics.WhichSamplesTableToUse(
uint64(start), uint64(end),
metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil,
)
valueCol := telemetrymetrics.ValueColumnForSamplesTable(samplesTable)
// Step-floor bounds + resolve tables in one shot to match QB v5 querier.
samplesStartMs, flooredEndMs, tsAdjustedStartMs, _, localTimeSeriesTable, distributedSamplesTable, _ := alignedMetricWindow(start, end)
valueCol := telemetrymetrics.ValueColumnForSamplesTable(distributedSamplesTable)
// ----- timeSeriesFPs -----
timeSeriesFPs := sqlbuilder.NewSelectBuilder()
@@ -215,8 +208,8 @@ func (m *module) getPerGroupNodeConditionCounts(
timeSeriesFPs.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, localTimeSeriesTable))
timeSeriesFPs.Where(
timeSeriesFPs.E("metric_name", nodeConditionMetricName),
timeSeriesFPs.GE("unix_milli", adjustedStart),
timeSeriesFPs.L("unix_milli", adjustedEnd),
timeSeriesFPs.GE("unix_milli", tsAdjustedStartMs),
timeSeriesFPs.LE("unix_milli", flooredEndMs),
)
if mergedFilterExpr != "" {
filterClause, err := m.buildFilterClause(ctx, &qbtypes.Filter{Expression: mergedFilterExpr}, start, end)
@@ -249,12 +242,12 @@ func (m *module) getPerGroupNodeConditionCounts(
latestConditionPerNode.Select(latestConditionPerNodeSelectCols...)
latestConditionPerNode.From(fmt.Sprintf(
"%s.%s AS samples INNER JOIN time_series_fps AS tsfp ON samples.fingerprint = tsfp.fingerprint",
telemetrymetrics.DBName, samplesTable,
telemetrymetrics.DBName, distributedSamplesTable,
))
latestConditionPerNode.Where(
latestConditionPerNode.E("samples.metric_name", nodeConditionMetricName),
latestConditionPerNode.GE("samples.unix_milli", start),
latestConditionPerNode.L("samples.unix_milli", end),
latestConditionPerNode.GE("samples.unix_milli", samplesStartMs),
latestConditionPerNode.L("samples.unix_milli", flooredEndMs),
"tsfp.node_name != ''",
)
latestConditionPerNode.GroupBy(latestConditionPerNodeGroupBy...)

View File

@@ -10,7 +10,6 @@ import (
"github.com/SigNoz/signoz/pkg/querybuilder"
"github.com/SigNoz/signoz/pkg/telemetrymetrics"
"github.com/SigNoz/signoz/pkg/types/inframonitoringtypes"
"github.com/SigNoz/signoz/pkg/types/metrictypes"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/huandu/go-sqlbuilder"
@@ -96,14 +95,16 @@ func buildPodRecords(
}
}
if attrs, ok := metadataMap[compositeKey]; ok && isPodUIDInGroupBy {
// the condition above ensures we deduce age only if pod uid is in group by because if
// it's not in group by then we might have multiple pod uids in the same group and hence then podAge wont make sense
if startTimeStr, exists := attrs[podStartTimeAttrKey]; exists && startTimeStr != "" {
if t, err := time.Parse(time.RFC3339, startTimeStr); err == nil {
startTimeMs := t.UnixMilli()
if startTimeMs > 0 {
record.PodAge = reqEnd - startTimeMs
if attrs, ok := metadataMap[compositeKey]; ok {
// podAge only makes sense when pod uid is in groupBy. Otherwise the
// group can contain multiple pods with different start times.
if isPodUIDInGroupBy {
if startTimeStr, exists := attrs[podStartTimeAttrKey]; exists && startTimeStr != "" {
if t, err := time.Parse(time.RFC3339, startTimeStr); err == nil {
startTimeMs := t.UnixMilli()
if startTimeMs > 0 {
record.PodAge = reqEnd - startTimeMs
}
}
}
}
@@ -209,15 +210,9 @@ func (m *module) getPerGroupPodPhaseCounts(
pageGroupsFilterExpr := buildPageGroupsFilterExpr(pageGroups)
mergedFilterExpr := mergeFilterExpressions(userFilterExpr, pageGroupsFilterExpr)
// Resolve tables. Same convention as hosts (distributed names from helpers).
adjustedStart, adjustedEnd, _, localTimeSeriesTable := telemetrymetrics.WhichTSTableToUse(
uint64(start), uint64(end), nil,
)
samplesTable := telemetrymetrics.WhichSamplesTableToUse(
uint64(start), uint64(end),
metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil,
)
valueCol := telemetrymetrics.ValueColumnForSamplesTable(samplesTable)
// Step-floor bounds + resolve tables in one shot to match QB v5 querier.
samplesStartMs, flooredEndMs, tsAdjustedStart, _, localTimeSeriesTable, distributedSamplesTable, _ := alignedMetricWindow(start, end)
valueCol := telemetrymetrics.ValueColumnForSamplesTable(distributedSamplesTable)
// ----- timeSeriesFPs -----
timeSeriesFPs := sqlbuilder.NewSelectBuilder()
@@ -234,8 +229,8 @@ func (m *module) getPerGroupPodPhaseCounts(
timeSeriesFPs.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, localTimeSeriesTable))
timeSeriesFPs.Where(
timeSeriesFPs.E("metric_name", podPhaseMetricName),
timeSeriesFPs.GE("unix_milli", adjustedStart),
timeSeriesFPs.L("unix_milli", adjustedEnd),
timeSeriesFPs.GE("unix_milli", tsAdjustedStart),
timeSeriesFPs.LE("unix_milli", flooredEndMs),
)
if mergedFilterExpr != "" {
filterClause, err := m.buildFilterClause(ctx, &qbtypes.Filter{Expression: mergedFilterExpr}, start, end)
@@ -267,12 +262,12 @@ func (m *module) getPerGroupPodPhaseCounts(
latestPhasePerPod.Select(latestPhasePerPodSelectCols...)
latestPhasePerPod.From(fmt.Sprintf(
"%s.%s AS samples INNER JOIN time_series_fps AS tsfp ON samples.fingerprint = tsfp.fingerprint",
telemetrymetrics.DBName, samplesTable,
telemetrymetrics.DBName, distributedSamplesTable,
))
latestPhasePerPod.Where(
latestPhasePerPod.E("samples.metric_name", podPhaseMetricName),
latestPhasePerPod.GE("samples.unix_milli", start),
latestPhasePerPod.L("samples.unix_milli", end),
latestPhasePerPod.GE("samples.unix_milli", samplesStartMs),
latestPhasePerPod.L("samples.unix_milli", flooredEndMs),
"tsfp.pod_uid != ''",
)
latestPhasePerPod.GroupBy(latestPhasePerPodGroupBy...)

View File

@@ -964,7 +964,7 @@ func (m *module) buildFilterClause(ctx context.Context, filter *qbtypes.Filter,
return nil, err
}
if whereClause == nil || whereClause.WhereClause == nil {
if whereClause.IsEmpty() {
return sqlbuilder.NewWhereClause(), nil
}
@@ -981,7 +981,7 @@ func (m *module) fetchMetricsStatsWithSamples(
ctx = m.withMetricsExplorerContext(ctx, "fetchMetricsStatsWithSamples")
start, end, distributedTsTable, localTsTable := telemetrymetrics.WhichTSTableToUse(uint64(req.Start), uint64(req.End), nil)
samplesTable := telemetrymetrics.WhichSamplesTableToUse(uint64(req.Start), uint64(req.End), metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil)
samplesTable, _ := telemetrymetrics.WhichSamplesTableToUse(uint64(req.Start), uint64(req.End), metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil)
countExp := telemetrymetrics.CountExpressionForSamplesTable(samplesTable)
// Timeseries counts per metric
@@ -1155,7 +1155,7 @@ func (m *module) computeSamplesTreemap(ctx context.Context, req *metricsexplorer
ctx = m.withMetricsExplorerContext(ctx, "computeSamplesTreemap")
start, end, distributedTsTable, localTsTable := telemetrymetrics.WhichTSTableToUse(uint64(req.Start), uint64(req.End), nil)
samplesTable := telemetrymetrics.WhichSamplesTableToUse(uint64(req.Start), uint64(req.End), metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil)
samplesTable, _ := telemetrymetrics.WhichSamplesTableToUse(uint64(req.Start), uint64(req.End), metrictypes.UnspecifiedType, metrictypes.TimeAggregationUnspecified, nil)
countExp := telemetrymetrics.CountExpressionForSamplesTable(samplesTable)
candidateLimit := req.Limit + 50

View File

@@ -510,9 +510,7 @@ func (s *store) buildFilterClause(ctx context.Context, filter qbtypes.Filter, st
if err != nil {
return nil, err
}
if prepared == nil || prepared.WhereClause == nil {
return nil, nil //nolint:nilnil
}
return prepared.WhereClause, nil
}

View File

@@ -206,7 +206,6 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
dataType = telemetrytypes.FieldDataTypeFloat64
}
//
bodyJSONEnabled := v.flagger.BooleanOrEmpty(v.ctx, flagger.FeatureUseJSONBody, featuretypes.NewFlaggerEvaluationContext(valuer.UUID{}))
// Handle *If functions with predicate + values
@@ -231,8 +230,8 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
if err != nil {
return err
}
// not possible for whereClause to be nil here but still adding a check.
if whereClause == nil {
// not possible for whereClause to be empty here but still adding a check.
if whereClause.IsEmpty() {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid predicate argument for %q: %q", name, origPred)
}

View File

@@ -96,8 +96,12 @@ type PreparedWhereClause struct {
WarningsDocURL string
}
func (p PreparedWhereClause) IsEmpty() bool {
return p.WhereClause == nil
}
// PrepareWhereClause generates a ClickHouse compatible WHERE clause from the filter query.
func PrepareWhereClause(query string, opts FilterExprVisitorOpts) (*PreparedWhereClause, error) {
func PrepareWhereClause(query string, opts FilterExprVisitorOpts) (PreparedWhereClause, error) {
// Setup the ANTLR parsing pipeline
input := antlr.NewInputStream(query)
@@ -148,7 +152,7 @@ func PrepareWhereClause(query string, opts FilterExprVisitorOpts) (*PreparedWher
}
}
return nil, combinedErrors.WithAdditional(additionals...).WithUrl(searchTroubleshootingGuideURL)
return PreparedWhereClause{}, combinedErrors.WithAdditional(additionals...).WithUrl(searchTroubleshootingGuideURL)
}
// Visit the parse tree with our ClickHouse visitor
@@ -166,18 +170,17 @@ func PrepareWhereClause(query string, opts FilterExprVisitorOpts) (*PreparedWher
if url == "" {
url = searchTroubleshootingGuideURL
}
return nil, combinedErrors.WithAdditional(visitor.errors...).WithUrl(url)
return PreparedWhereClause{}, combinedErrors.WithAdditional(visitor.errors...).WithUrl(url)
}
// Return nil so callers can skip the
// entire CTE/subquery rather than emitting WHERE clause that select all the rows
// Return empty where clause so callers can skip the WHERE clause
if cond == "" || cond == SkipConditionLiteral {
return nil, nil //nolint:nilnil
return PreparedWhereClause{WhereClause: nil, Warnings: visitor.warnings, WarningsDocURL: visitor.mainWarnURL}, nil
}
whereClause := sqlbuilder.NewWhereClause().AddWhereExpr(visitor.builder.Args, cond)
return &PreparedWhereClause{WhereClause: whereClause, Warnings: visitor.warnings, WarningsDocURL: visitor.mainWarnURL}, nil
return PreparedWhereClause{WhereClause: whereClause, Warnings: visitor.warnings, WarningsDocURL: visitor.mainWarnURL}, nil
}
// Visit dispatches to the specific visit method based on node type.

View File

@@ -874,7 +874,7 @@ func TestVisitComparison_AND(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -883,7 +883,7 @@ func TestVisitComparison_AND(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -968,7 +968,7 @@ func TestVisitComparison_NOT(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -977,7 +977,7 @@ func TestVisitComparison_NOT(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1070,7 +1070,7 @@ func TestVisitComparison_OR(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1079,7 +1079,7 @@ func TestVisitComparison_OR(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1151,7 +1151,7 @@ func TestVisitComparison_Precedence(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1160,7 +1160,7 @@ func TestVisitComparison_Precedence(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1254,7 +1254,7 @@ func TestVisitComparison_Parens(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1263,7 +1263,7 @@ func TestVisitComparison_Parens(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1409,7 +1409,7 @@ func TestVisitComparison_FullText(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1418,7 +1418,7 @@ func TestVisitComparison_FullText(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1518,7 +1518,7 @@ func TestVisitComparison_AllVariable(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1527,7 +1527,7 @@ func TestVisitComparison_AllVariable(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1597,7 +1597,7 @@ func TestVisitComparison_FunctionCalls(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1606,7 +1606,7 @@ func TestVisitComparison_FunctionCalls(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1666,7 +1666,7 @@ func TestVisitComparison_UnknownKeys(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1675,7 +1675,7 @@ func TestVisitComparison_UnknownKeys(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)
@@ -1758,7 +1758,7 @@ func TestVisitComparison_SkippableLiteralValues(t *testing.T) {
assert.Equal(t, tt.wantErrRSB, err != nil, "resourceConditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantRSB, expr, "resourceConditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantRSB, expr)
@@ -1767,7 +1767,7 @@ func TestVisitComparison_SkippableLiteralValues(t *testing.T) {
assert.Equal(t, tt.wantErrSB, err != nil, "conditionBuilder: error expectation mismatch")
if err == nil {
var expr string
if result != nil {
if !result.IsEmpty() {
expr, _ = result.WhereClause.Build()
}
assert.Equal(t, tt.wantSB, expr, "conditionBuilder SQL mismatch:\n want: %s\n got: %s", tt.wantSB, expr)

View File

@@ -46,7 +46,7 @@ func NewFactory(
) factory.ProviderFactory[ruler.Ruler, ruler.Config] {
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, providerSettings factory.ProviderSettings, config ruler.Config) (ruler.Ruler, error) {
ruleStore := sqlrulestore.NewRuleStore(sqlstore, queryParser, providerSettings)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore, providerSettings)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore)
managerOpts := &rules.ManagerOptions{
TelemetryStore: telemetryStore,

View File

@@ -41,7 +41,7 @@ func TestNewHandlers(t *testing.T) {
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstore), sharder)
notificationManager := nfmanagertest.NewMock()
require.NoError(t, err)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore, providerSettings)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore)
alertmanager, err := signozalertmanager.New(providerSettings, alertmanager.Config{}, sqlstore, orgGetter, notificationManager, maintenanceStore)
require.NoError(t, err)
tokenizer := tokenizertest.NewMockTokenizer(t)

View File

@@ -42,7 +42,7 @@ func TestNewModules(t *testing.T) {
orgGetter := implorganization.NewGetter(implorganization.NewStore(sqlstore), sharder)
notificationManager := nfmanagertest.NewMock()
require.NoError(t, err)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore, providerSettings)
maintenanceStore := sqlalertmanagerstore.NewMaintenanceStore(sqlstore)
alertmanager, err := signozalertmanager.New(providerSettings, alertmanager.Config{}, sqlstore, orgGetter, notificationManager, maintenanceStore)
require.NoError(t, err)
tokenizer := tokenizertest.NewMockTokenizer(t)

Some files were not shown because too many files have changed in this diff Show More