Compare commits

..

6 Commits

Author SHA1 Message Date
swapnil-signoz
fb26cc36c8 feat: adding integration test for new API endpoint 2026-05-29 18:49:07 +05:30
swapnil-signoz
9ed3486d2c feat: adding get cloud integration service for account handler 2026-05-29 16:20:04 +05:30
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
Vinicius Lourenço
fe8283e4de refactor(query-builder): removed unused query component (#11486)
Some checks failed
build-staging / go-build (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
2026-05-28 17:55:55 +00:00
Vinicius Lourenço
4366d6fd96 fix(divider): mismatch on margin/colors (#11488) 2026-05-28 14:57:57 +00:00
122 changed files with 978 additions and 1119 deletions

View File

@@ -7965,6 +7965,80 @@ paths:
tags:
- cloudintegration
/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services/{service_id}:
get:
deprecated: false
description: This endpoint gets a service and its configuration for the specified
cloud integration account
operationId: GetAccountService
parameters:
- in: path
name: cloud_provider
required: true
schema:
type: string
- in: path
name: id
required: true
schema:
type: string
- in: path
name: service_id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/CloudintegrationtypesService'
status:
type: string
required:
- status
- data
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Get service for account
tags:
- cloudintegration
put:
deprecated: false
description: This endpoint updates a service for the specified cloud provider

View File

@@ -31,6 +31,8 @@ import type {
DisconnectAccountPathParameters,
GetAccount200,
GetAccountPathParameters,
GetAccountService200,
GetAccountServicePathParameters,
GetConnectionCredentials200,
GetConnectionCredentialsPathParameters,
GetService200,
@@ -631,6 +633,117 @@ export const useUpdateAccount = <
> => {
return useMutation(getUpdateAccountMutationOptions(options));
};
/**
* This endpoint gets a service and its configuration for the specified cloud integration account
* @summary Get service for account
*/
export const getAccountService = (
{ cloudProvider, id, serviceId }: GetAccountServicePathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetAccountService200>({
url: `/api/v1/cloud_integrations/${cloudProvider}/accounts/${id}/services/${serviceId}`,
method: 'GET',
signal,
});
};
export const getGetAccountServiceQueryKey = ({
cloudProvider,
id,
serviceId,
}: GetAccountServicePathParameters) => {
return [
`/api/v1/cloud_integrations/${cloudProvider}/accounts/${id}/services/${serviceId}`,
] as const;
};
export const getGetAccountServiceQueryOptions = <
TData = Awaited<ReturnType<typeof getAccountService>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ cloudProvider, id, serviceId }: GetAccountServicePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getAccountService>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getGetAccountServiceQueryKey({ cloudProvider, id, serviceId });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getAccountService>>
> = ({ signal }) =>
getAccountService({ cloudProvider, id, serviceId }, signal);
return {
queryKey,
queryFn,
enabled: !!(cloudProvider && id && serviceId),
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getAccountService>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetAccountServiceQueryResult = NonNullable<
Awaited<ReturnType<typeof getAccountService>>
>;
export type GetAccountServiceQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get service for account
*/
export function useGetAccountService<
TData = Awaited<ReturnType<typeof getAccountService>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ cloudProvider, id, serviceId }: GetAccountServicePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getAccountService>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetAccountServiceQueryOptions(
{ cloudProvider, id, serviceId },
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* @summary Get service for account
*/
export const invalidateGetAccountService = async (
queryClient: QueryClient,
{ cloudProvider, id, serviceId }: GetAccountServicePathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetAccountServiceQueryKey({ cloudProvider, id, serviceId }) },
options,
);
return queryClient;
};
/**
* This endpoint updates a service for the specified cloud provider
* @summary Update service

View File

@@ -8566,6 +8566,19 @@ export type UpdateAccountPathParameters = {
cloudProvider: string;
id: string;
};
export type GetAccountServicePathParameters = {
cloudProvider: string;
id: string;
serviceId: string;
};
export type GetAccountService200 = {
data: CloudintegrationtypesServiceDTO;
/**
* @type string
*/
status: string;
};
export type UpdateServicePathParameters = {
cloudProvider: string;
id: string;

View File

@@ -11,7 +11,6 @@
}
.divider {
border-color: var(--l1-border);
margin: 16px 0;
margin-top: 10px;
--divider-color: var(--l1-border);
--divider-margin: 10px 0 16px 0;
}

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

@@ -69,8 +69,6 @@ export function useLogsTableColumns({
id: 'timestamp',
header: 'Timestamp',
accessorFn: (log): unknown => log.timestamp,
canBeHidden: false,
enableRemove: false,
width: { default: 170, min: 170 },
cell: ({ value }): ReactElement => {
const ts = value as string | number;
@@ -94,7 +92,6 @@ export function useLogsTableColumns({
header: 'Body',
accessorFn: (log): string => getBodyDisplayString(log.body),
canBeHidden: false,
enableRemove: false,
width: { default: '100%', min: 300 },
cell: ({ value, isActive }): ReactElement => (
<TanStackTable.Text

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

@@ -62,7 +62,6 @@ describe('LogsFormatOptionsMenu (unit)', () => {
onSearch: jest.fn(),
onSelect: jest.fn(),
onRemove: jest.fn(),
onReorder: jest.fn(),
},
}}
/>,

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

@@ -11,7 +11,7 @@ import cx from 'classnames';
import { ENTITY_VERSION_V4, ENTITY_VERSION_V5 } from 'constants/app';
import { PANEL_TYPES } from 'constants/queryBuilder';
import QBEntityOptions from 'container/QueryBuilder/components/QBEntityOptions/QBEntityOptions';
import { QueryProps } from 'container/QueryBuilder/components/Query/Query.interfaces';
import { QueryProps } from 'container/QueryBuilder/type';
import SpanScopeSelector from 'container/QueryBuilder/filters/QueryBuilderSearchV2/SpanScopeSelector';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';

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

@@ -308,7 +308,9 @@ function TanStackTableInner<TData>(
});
const hasSingleColumn = useMemo(
() => effectiveColumns.filter((c) => !c.pin).length <= 1,
() =>
effectiveColumns.filter((c) => !c.pin && c.enableRemove !== false).length <=
1,
[effectiveColumns],
);

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,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

@@ -23,6 +23,10 @@
}
}
}
&__divider {
--divider-vertical-margin: 0;
}
}
.hide-update {
@@ -55,12 +59,6 @@
.hidden {
display: none;
}
.ant-divider {
margin: 0;
height: 28px;
border: 1px solid var(--l1-border);
}
}
.explorer-options {

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';
@@ -874,7 +874,9 @@ function ExplorerOptions({
<>
<Divider
type="vertical"
className={isEditDeleteSupported ? '' : 'hidden'}
className={cx('explorer-options-container__divider', {
hidden: !isEditDeleteSupported,
})}
/>
<Tooltip title="Update this view" placement="top">
<Button

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,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

@@ -94,11 +94,8 @@
margin-bottom: 24px;
width: 100%;
.ant-divider::before,
.ant-divider::after {
border-bottom: 2px dotted var(--l1-border);
border-top: 2px dotted var(--l1-border);
height: 8px;
&__divider {
--divider-border-width: 1px;
}
.ant-typography {

View File

@@ -125,7 +125,7 @@ export function AlertsEmptyState(): JSX.Element {
</div>
</section>
<div className="get-started-text">
<Divider>
<Divider className="get-started-text__divider">
<Typography.Text className="get-started-text">
Or get started with these sample alerts
</Typography.Text>

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

@@ -16,6 +16,7 @@ import { useLogsTableColumns } from 'components/Logs/TableView/useLogsTableColum
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import type { TanStackTableHandle } from 'components/TanStackTableView';
import TanStackTable from 'components/TanStackTableView';
import { useHiddenColumnIds } from 'components/TanStackTableView/useColumnStore';
import { CARD_BODY_STYLE } from 'constants/card';
import { LOCALSTORAGE } from 'constants/localStorage';
import { OptionFormatTypes } from 'constants/optionsFormatTypes';
@@ -23,11 +24,13 @@ import { QueryParams } from 'constants/query';
import { InfinityWrapperStyled } from 'container/LogsExplorerList/styles';
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
import { useOptionsMenu } from 'container/OptionsMenu';
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
import useLogDetailHandlers from 'hooks/logs/useLogDetailHandlers';
import useScrollToLog from 'hooks/logs/useScrollToLog';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useEventSource } from 'providers/EventSource';
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
// interfaces
import { ILog } from 'types/api/logs/log';
import { DataSource, StringOperators } from 'types/common/queryBuilder';
@@ -51,6 +54,9 @@ function LiveLogsList({
const { isConnectionLoading } = useEventSource();
const { activeLogId } = useCopyLogLink();
const { logs: logsPreferences } = usePreferenceContext();
const hiddenColumnIds = useHiddenColumnIds(LOCALSTORAGE.LOGS_LIST_COLUMNS);
const hasReconciledHiddenColumnsRef = useRef(false);
const {
activeLog,
@@ -66,7 +72,7 @@ function LiveLogsList({
[logs],
);
const { options, config } = useOptionsMenu({
const { options } = useOptionsMenu({
storageKey: LOCALSTORAGE.LOGS_LIST_OPTIONS,
dataSource: DataSource.LOGS,
aggregateOperator: StringOperators.NOOP,
@@ -77,7 +83,16 @@ function LiveLogsList({
[formattedLogs, activeLogId],
);
const selectedFields = convertKeysToColumnFields(options.selectColumns);
const selectedFields = convertKeysToColumnFields([
...defaultLogsSelectedColumns,
...options.selectColumns,
]);
const syncedSelectedColumns = useMemo(
() =>
options.selectColumns.filter(({ name }) => !hiddenColumnIds.includes(name)),
[options.selectColumns, hiddenColumnIds],
);
const logsColumns = useLogsTableColumns({
fields: selectedFields,
@@ -85,6 +100,30 @@ function LiveLogsList({
appendTo: 'end',
});
useEffect(() => {
if (hasReconciledHiddenColumnsRef.current) {
return;
}
hasReconciledHiddenColumnsRef.current = true;
if (syncedSelectedColumns.length === options.selectColumns.length) {
return;
}
logsPreferences.updateColumns(syncedSelectedColumns);
}, [logsPreferences, options.selectColumns.length, syncedSelectedColumns]);
const handleColumnRemove = useCallback(
(columnId: string) => {
const updatedColumns = options.selectColumns.filter(
({ name }) => name !== columnId,
);
logsPreferences.updateColumns(updatedColumns);
},
[options.selectColumns, logsPreferences],
);
const makeOnLogCopy = useCallback(
(log: ILog) =>
(event: MouseEvent<HTMLElement>): void => {
@@ -198,7 +237,7 @@ function LiveLogsList({
ref={ref as React.Ref<TanStackTableHandle>}
columns={logsColumns}
columnStorageKey={LOCALSTORAGE.LOGS_LIST_COLUMNS}
onColumnRemove={config?.addColumn?.onRemove}
onColumnRemove={handleColumnRemove}
plainTextCellLineClamp={options.maxLines}
cellTypographySize={options.fontSize}
data={formattedLogs}

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

@@ -18,19 +18,21 @@ import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import Spinner from 'components/Spinner';
import type { TanStackTableHandle } from 'components/TanStackTableView';
import TanStackTable from 'components/TanStackTableView';
import type { TableColumnDef } from 'components/TanStackTableView/types';
import { useHiddenColumnIds } from 'components/TanStackTableView/useColumnStore';
import { CARD_BODY_STYLE } from 'constants/card';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch';
import { LogsLoading } from 'container/LogsLoading/LogsLoading';
import { useOptionsMenu } from 'container/OptionsMenu';
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
import { FontSize } from 'container/OptionsMenu/types';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
import useLogDetailHandlers from 'hooks/logs/useLogDetailHandlers';
import useScrollToLog from 'hooks/logs/useScrollToLog';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
import APIError from 'types/api/error';
// interfaces
import { ILog } from 'types/api/logs/log';
@@ -67,6 +69,10 @@ function LogsExplorerList({
const [, setCopy] = useCopyToClipboard();
const isDarkMode = useIsDarkMode();
const { activeLogId } = useCopyLogLink();
const { logs: logsPreferences } = usePreferenceContext();
const hiddenColumnIds = useHiddenColumnIds(LOCALSTORAGE.LOGS_LIST_COLUMNS);
const hasReconciledHiddenColumnsRef = useRef(false);
const {
activeLog,
onAddToQuery,
@@ -75,7 +81,7 @@ function LogsExplorerList({
handleCloseLogDetail,
} = useLogDetailHandlers();
const { options, config } = useOptionsMenu({
const { options } = useOptionsMenu({
storageKey: LOCALSTORAGE.LOGS_LIST_OPTIONS,
dataSource: DataSource.LOGS,
aggregateOperator:
@@ -91,15 +97,28 @@ function LogsExplorerList({
);
const selectedFields = useMemo(
() => convertKeysToColumnFields(options.selectColumns),
[options.selectColumns],
() =>
convertKeysToColumnFields([
...defaultLogsSelectedColumns,
...options.selectColumns,
]),
[options],
);
const handleColumnOrderChange = useCallback(
(cols: TableColumnDef<ILog>[]): void => {
config?.addColumn?.onReorder(cols.map((c) => c.id));
const syncedSelectedColumns = useMemo(
() =>
options.selectColumns.filter(({ name }) => !hiddenColumnIds.includes(name)),
[options.selectColumns, hiddenColumnIds],
);
const handleColumnRemove = useCallback(
(columnId: string) => {
const updatedColumns = options.selectColumns.filter(
({ name }) => name !== columnId,
);
logsPreferences.updateColumns(updatedColumns);
},
[config],
[options.selectColumns, logsPreferences],
);
const logsColumns = useLogsTableColumns({
@@ -142,6 +161,20 @@ function LogsExplorerList({
}
}, [isLoading, isFetching, isError, logs.length]);
useEffect(() => {
if (hasReconciledHiddenColumnsRef.current) {
return;
}
hasReconciledHiddenColumnsRef.current = true;
if (syncedSelectedColumns.length === options.selectColumns.length) {
return;
}
logsPreferences.updateColumns(syncedSelectedColumns);
}, [logsPreferences, options.selectColumns.length, syncedSelectedColumns]);
const getItemContent = useCallback(
(_: number, log: ILog): JSX.Element => {
if (options.format === 'raw') {
@@ -204,8 +237,7 @@ function LogsExplorerList({
ref={ref as React.Ref<TanStackTableHandle>}
columns={logsColumns}
columnStorageKey={LOCALSTORAGE.LOGS_LIST_COLUMNS}
onColumnRemove={config?.addColumn?.onRemove}
onColumnOrderChange={handleColumnOrderChange}
onColumnRemove={handleColumnRemove}
plainTextCellLineClamp={options.maxLines}
cellTypographySize={options.fontSize}
data={logs}

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

@@ -19,9 +19,9 @@
letter-spacing: 0.5px;
}
.ant-divider {
margin: 8px 0 !important;
border: 0.5px solid var(--l1-border);
&__divider {
--divider-color: var(--l1-border);
--divider-margin: 8px 0;
}
.explorer-columns-contents {

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,
@@ -234,7 +235,7 @@ function ExplorerColumnsRenderer({
</Tooltip>
)}
</div>
<Divider />
<Divider className="explorer-columns-renderer__divider" />
{!isError && (
<div className="explorer-columns-contents">
<DragDropContext onDragEnd={onDragEnd}>

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,79 +0,0 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import {
defaultLogsSelectedColumns,
ensureLogsRequiredColumns,
} from '../constants';
const TIMESTAMP = defaultLogsSelectedColumns.find(
(c) => c.name === 'timestamp',
);
const BODY = defaultLogsSelectedColumns.find((c) => c.name === 'body');
if (!TIMESTAMP || !BODY) {
throw new Error('defaults missing timestamp/body — test fixture invalid');
}
const ATTR_A: TelemetryFieldKey = {
name: 'service.name',
signal: 'logs',
fieldContext: 'resource',
fieldDataType: 'string',
};
const ATTR_B: TelemetryFieldKey = {
name: 'severity_text',
signal: 'logs',
fieldContext: 'log',
fieldDataType: 'string',
};
describe('ensureLogsRequiredColumns', () => {
it('prepends both timestamp + body to an empty list', () => {
expect(ensureLogsRequiredColumns([])).toStrictEqual([TIMESTAMP, BODY]);
});
it('prepends only `body` when `timestamp` is already present', () => {
expect(ensureLogsRequiredColumns([TIMESTAMP, ATTR_A])).toStrictEqual([
BODY,
TIMESTAMP,
ATTR_A,
]);
});
it('prepends only `timestamp` when `body` is already present', () => {
expect(ensureLogsRequiredColumns([BODY, ATTR_A])).toStrictEqual([
TIMESTAMP,
BODY,
ATTR_A,
]);
});
it('returns the same array when both are present (no duplicates, original order preserved)', () => {
const input = [TIMESTAMP, BODY, ATTR_A, ATTR_B];
expect(ensureLogsRequiredColumns(input)).toBe(input);
});
it('preserves a non-default order when both are present', () => {
const input = [ATTR_A, BODY, ATTR_B, TIMESTAMP];
expect(ensureLogsRequiredColumns(input)).toStrictEqual(input);
});
it('prepends both when neither is present in a list of user attributes', () => {
expect(ensureLogsRequiredColumns([ATTR_A, ATTR_B])).toStrictEqual([
TIMESTAMP,
BODY,
ATTR_A,
ATTR_B,
]);
});
it('does not duplicate if a required column appears twice in the input', () => {
// Tolerant of malformed input — invariant only adds *missing* required
// columns; it does not deduplicate existing entries (that's a separate
// concern, not its job).
const input = [BODY, BODY, ATTR_A];
const result = ensureLogsRequiredColumns(input);
expect(result.filter((c) => c.name === 'timestamp')).toHaveLength(1);
expect(result[0]).toStrictEqual(TIMESTAMP);
});
});

View File

@@ -35,32 +35,6 @@ export const defaultLogsSelectedColumns: TelemetryFieldKey[] = [
},
];
const LOGS_REQUIRED_COLUMNS = ['timestamp', 'body'] as const;
/**
* Always-on invariant: every logs selectColumns array must contain `body` and
* `timestamp`. Applied at both loader and writer boundaries so the picker, the
* table, and persisted state can never diverge into a "missing required
* column" state.
*/
export function ensureLogsRequiredColumns(
columns: TelemetryFieldKey[],
): TelemetryFieldKey[] {
const missing = LOGS_REQUIRED_COLUMNS.filter(
(name) => !columns.some((c) => c.name === name),
);
if (missing.length === 0) {
return columns;
}
const defaultsByName = new Map(
defaultLogsSelectedColumns.map((c) => [c.name, c]),
);
const prepended = missing
.map((name) => defaultsByName.get(name))
.filter((c): c is TelemetryFieldKey => c !== undefined);
return [...prepended, ...columns];
}
export const defaultTraceSelectedColumns: TelemetryFieldKey[] = [
{
name: 'service.name',

View File

@@ -40,6 +40,5 @@ export type OptionsMenuConfig = {
isFetching: boolean;
value: TelemetryFieldKey[];
onRemove: (key: string) => void;
onReorder: (orderedIds: string[]) => void;
};
};

View File

@@ -187,6 +187,30 @@ const useOptionsMenu = ({
searchedAttributesDataV5?.data.data.keys || {},
).flat();
if (searchedAttributesDataList.length) {
if (dataSource === DataSource.LOGS) {
const logsSelectedColumns: TelemetryFieldKey[] =
defaultLogsSelectedColumns.map((e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
}));
return [
...logsSelectedColumns,
...searchedAttributesDataList
.filter((attribute) => attribute.name !== 'body')
// eslint-disable-next-line sonarjs/no-identical-functions
.map((e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
})),
];
}
// eslint-disable-next-line sonarjs/no-identical-functions
return searchedAttributesDataList.map((e) => ({
...e,
name: e.name,
@@ -273,9 +297,24 @@ const useOptionsMenu = ({
return [...acc, column];
}, [] as TelemetryFieldKey[]);
const optionsData: OptionsQuery = {
...defaultOptionsQuery,
selectColumns: newSelectedColumns,
format: preferences?.formatting?.format || defaultOptionsQuery.format,
maxLines: preferences?.formatting?.maxLines || defaultOptionsQuery.maxLines,
fontSize: preferences?.formatting?.fontSize || defaultOptionsQuery.fontSize,
};
updateColumns(newSelectedColumns);
handleRedirectWithOptionsData(optionsData);
},
[searchedAttributeKeys, selectedColumnKeys, preferences, updateColumns],
[
searchedAttributeKeys,
selectedColumnKeys,
preferences,
handleRedirectWithOptionsData,
updateColumns,
],
);
const handleRemoveSelectedColumn = useCallback(
@@ -288,12 +327,27 @@ const useOptionsMenu = ({
notifications.error({
message: 'There must be at least one selected column',
});
return;
} else {
const optionsData: OptionsQuery = {
...defaultOptionsQuery,
selectColumns: newSelectedColumns || [],
format: preferences?.formatting?.format || defaultOptionsQuery.format,
maxLines:
preferences?.formatting?.maxLines || defaultOptionsQuery.maxLines,
fontSize:
preferences?.formatting?.fontSize || defaultOptionsQuery.fontSize,
};
updateColumns(newSelectedColumns || []);
handleRedirectWithOptionsData(optionsData);
}
updateColumns(newSelectedColumns || []);
},
[dataSource, notifications, preferences, updateColumns],
[
dataSource,
notifications,
preferences,
handleRedirectWithOptionsData,
updateColumns,
],
);
const handleFormatChange = useCallback(
@@ -360,18 +414,6 @@ const useOptionsMenu = ({
setSearchText(value);
}, []);
const reorderSelectColumns = useCallback(
(orderedIds: string[]): void => {
const current = preferences?.columns ?? [];
const byName = new Map(current.map((f) => [f.name, f]));
const reordered = orderedIds
.map((id) => byName.get(id))
.filter((f): f is TelemetryFieldKey => f !== undefined);
updateColumns(reordered);
},
[preferences, updateColumns],
);
const handleFocus = (): void => {
setIsFocused(true);
};
@@ -394,7 +436,6 @@ const useOptionsMenu = ({
onSelect: handleSelectColumns,
onRemove: handleRemoveSelectedColumn,
onSearch: handleSearchAttribute,
onReorder: reorderSelectColumns,
},
format: {
value: preferences?.formatting?.format || defaultOptionsQuery.format,
@@ -416,7 +457,6 @@ const useOptionsMenu = ({
handleSelectColumns,
handleRemoveSelectedColumn,
handleSearchAttribute,
reorderSelectColumns,
handleFormatChange,
handleMaxLinesChange,
handleFontSizeChange,

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

@@ -19,12 +19,6 @@
}
}
.ant-modal-body {
.ant-divider {
margin: 16px 0;
border: 0.5px solid var(--l1-border);
}
}
.downtime-schedule-btn {
display: flex;
}

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

@@ -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,18 +0,0 @@
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
export type QueryProps = {
index: number;
isAvailableToDisable: boolean;
query: IBuilderQuery;
queryVariant?: 'static' | 'dropdown';
isListViewPanel?: boolean;
showFunctions?: boolean;
version: string;
showSpanScopeSelector?: boolean;
showOnlyWhereClause?: boolean;
showTraceOperator?: boolean;
hasTraceOperator?: boolean;
signalSource?: string;
isMultiQueryAllowed?: boolean;
} & Pick<QueryBuilderProps, 'filterConfigs' | 'queryComponents'>;

View File

@@ -1,8 +0,0 @@
.qb-search-container {
display: block;
position: relative;
}
.qb-container {
padding: 0 24px;
}

View File

@@ -1,628 +0,0 @@
/* eslint-disable sonarjs/cognitive-complexity */
// ** Hooks
import {
ChangeEvent,
memo,
ReactNode,
useCallback,
useMemo,
useState,
} from 'react';
import { useLocation } from 'react-use';
import { Col, Input, Row, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { ENTITY_VERSION_V4 } from 'constants/app';
// ** Constants
import { ATTRIBUTE_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
// ** Components
import {
AdditionalFiltersToggler,
DataSourceDropdown,
FilterLabel,
} from 'container/QueryBuilder/components';
import {
AggregatorFilter,
GroupByFilter,
HavingFilter,
MetricNameSelector,
OperatorsSelect,
OrderByFilter,
ReduceToFilter,
} from 'container/QueryBuilder/filters';
import AggregateEveryFilter from 'container/QueryBuilder/filters/AggregateEveryFilter';
import LimitFilter from 'container/QueryBuilder/filters/LimitFilter/LimitFilter';
import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
import QueryBuilderSearchV2 from 'container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { transformToUpperCase } from 'utils/transformToUpperCase';
import QBEntityOptions from '../QBEntityOptions/QBEntityOptions';
import SpaceAggregationOptions from '../SpaceAggregationOptions/SpaceAggregationOptions';
// ** Types
import { QueryProps } from './Query.interfaces';
import './Query.styles.scss';
export const Query = memo(function Query({
index,
queryVariant,
query,
filterConfigs,
queryComponents,
isListViewPanel = false,
showFunctions = false,
version,
}: QueryProps): JSX.Element {
const { panelType, currentQuery, cloneQuery } = useQueryBuilder();
const { pathname } = useLocation();
const [isCollapse, setIsCollapsed] = useState(false);
const {
operators,
spaceAggregationOptions,
isMetricsDataSource,
isTracePanelType,
listOfAdditionalFilters,
handleChangeAggregatorAttribute,
handleChangeQueryData,
handleChangeDataSource,
handleChangeOperator,
handleSpaceAggregationChange,
handleDeleteQuery,
handleQueryFunctionsUpdates,
} = useQueryOperations({
index,
query,
filterConfigs,
isListViewPanel,
entityVersion: version,
});
const handleChangeAggregateEvery = useCallback(
(value: IBuilderQuery['stepInterval']) => {
handleChangeQueryData('stepInterval', value);
},
[handleChangeQueryData],
);
const handleChangeLimit = useCallback(
(value: IBuilderQuery['limit']) => {
handleChangeQueryData('limit', value);
},
[handleChangeQueryData],
);
const handleChangeHavingFilter = useCallback(
(value: IBuilderQuery['having']) => {
handleChangeQueryData('having', value);
},
[handleChangeQueryData],
);
const handleChangeOrderByKeys = useCallback(
(value: IBuilderQuery['orderBy']) => {
handleChangeQueryData('orderBy', value);
},
[handleChangeQueryData],
);
const handleToggleDisableQuery = useCallback(() => {
handleChangeQueryData('disabled', !query.disabled);
}, [handleChangeQueryData, query]);
const handleChangeTagFilters = useCallback(
(value: IBuilderQuery['filters']) => {
handleChangeQueryData('filters', value);
},
[handleChangeQueryData],
);
const handleChangeReduceTo = useCallback(
(value: IBuilderQuery['reduceTo']) => {
handleChangeQueryData('reduceTo', value);
},
[handleChangeQueryData],
);
const handleChangeGroupByKeys = useCallback(
(value: IBuilderQuery['groupBy']) => {
handleChangeQueryData('groupBy', value);
},
[handleChangeQueryData],
);
const handleChangeQueryLegend = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
handleChangeQueryData('legend', event.target.value);
},
[handleChangeQueryData],
);
const handleToggleCollapsQuery = (): void => {
setIsCollapsed(!isCollapse);
};
const renderOrderByFilter = useCallback((): ReactNode => {
if (queryComponents?.renderOrderBy) {
return queryComponents.renderOrderBy({
query,
onChange: handleChangeOrderByKeys,
});
}
return (
<OrderByFilter
entityVersion={version}
query={query}
onChange={handleChangeOrderByKeys}
isListViewPanel={isListViewPanel}
/>
);
}, [
queryComponents,
query,
version,
handleChangeOrderByKeys,
isListViewPanel,
]);
const renderAggregateEveryFilter = useCallback(
(): JSX.Element | null =>
!filterConfigs?.stepInterval?.isHidden ? (
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="Aggregate Every" />
</Col>
<Col flex="1 1 6rem">
<AggregateEveryFilter
query={query}
disabled={filterConfigs?.stepInterval?.isDisabled || false}
onChange={handleChangeAggregateEvery}
/>
</Col>
</Row>
) : null,
[
filterConfigs?.stepInterval?.isHidden,
filterConfigs?.stepInterval?.isDisabled,
query,
handleChangeAggregateEvery,
],
);
const isExplorerPage = useMemo(
() =>
pathname === ROUTES.LOGS_EXPLORER || pathname === ROUTES.TRACES_EXPLORER,
[pathname],
);
const renderAdditionalFilters = useCallback((): ReactNode => {
switch (panelType) {
case PANEL_TYPES.TIME_SERIES: {
return (
<>
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="Limit" />
</Col>
<Col flex="1 1 12.5rem">
<LimitFilter query={query} onChange={handleChangeLimit} />
</Col>
</Row>
</Col>
<Col span={24}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="HAVING" />
</Col>
<Col flex="1 1 12.5rem">
<HavingFilter
entityVersion={version}
onChange={handleChangeHavingFilter}
query={query}
/>
</Col>
</Row>
</Col>
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="Order by" />
</Col>
<Col flex="1 1 12.5rem">{renderOrderByFilter()}</Col>
</Row>
</Col>
<Col span={11}>{renderAggregateEveryFilter()}</Col>
</>
);
}
case PANEL_TYPES.VALUE: {
return (
<>
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="HAVING" />
</Col>
<Col flex="1 1 12.5rem">
<HavingFilter
onChange={handleChangeHavingFilter}
entityVersion={version}
query={query}
/>
</Col>
</Row>
</Col>
<Col span={11}>{renderAggregateEveryFilter()}</Col>
</>
);
}
default: {
return (
<>
{!filterConfigs?.limit?.isHidden && (
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="Limit" />
</Col>
<Col flex="1 1 12.5rem">
<LimitFilter query={query} onChange={handleChangeLimit} />
</Col>
</Row>
</Col>
)}
{!filterConfigs?.having?.isHidden && (
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="HAVING" />
</Col>
<Col flex="1 1 12.5rem">
<HavingFilter
entityVersion={version}
onChange={handleChangeHavingFilter}
query={query}
/>
</Col>
</Row>
</Col>
)}
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<FilterLabel label="Order by" />
</Col>
<Col flex="1 1 12.5rem">{renderOrderByFilter()}</Col>
</Row>
</Col>
<Col span={11}>{renderAggregateEveryFilter()}</Col>
</>
);
}
}
}, [
panelType,
query,
handleChangeLimit,
version,
handleChangeHavingFilter,
renderOrderByFilter,
renderAggregateEveryFilter,
filterConfigs?.limit?.isHidden,
filterConfigs?.having?.isHidden,
]);
const disableOperatorSelector =
!query?.aggregateAttribute?.key || query?.aggregateAttribute?.key === '';
const isVersionV4 = version && version === ENTITY_VERSION_V4;
return (
<Row gutter={[0, 12]} className={`query-builder-${version}`}>
<QBEntityOptions
isMetricsDataSource={isMetricsDataSource}
showFunctions={
(version && version === ENTITY_VERSION_V4) ||
query.dataSource === DataSource.LOGS ||
showFunctions ||
false
}
isCollapsed={isCollapse}
entityType="query"
entityData={query}
onToggleVisibility={handleToggleDisableQuery}
onDelete={handleDeleteQuery}
onCloneQuery={cloneQuery}
onCollapseEntity={handleToggleCollapsQuery}
query={query}
onQueryFunctionsUpdates={handleQueryFunctionsUpdates}
showDeleteButton={currentQuery.builder.queryData.length > 1}
isListViewPanel={isListViewPanel}
index={index}
queryVariant={queryVariant}
/>
{!isCollapse && (
<Row gutter={[0, 12]} className="qb-container">
<Col span={24}>
<Row align="middle" gutter={[5, 11]}>
{!isExplorerPage && (
<Col>
{queryVariant === 'dropdown' ? (
<DataSourceDropdown
onChange={handleChangeDataSource}
value={query.dataSource}
style={{ minWidth: '5.625rem' }}
isListViewPanel={isListViewPanel}
/>
) : (
<FilterLabel label={transformToUpperCase(query.dataSource)} />
)}
</Col>
)}
{isMetricsDataSource && (
<Col span={12}>
<Row gutter={[11, 5]}>
{version && version === 'v3' && (
<Col flex="5.93rem">
<Tooltip
title={
<div style={{ textAlign: 'center' }}>
Select Aggregate Operator
<Typography.Link
className="learn-more"
href="https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=query-builder#aggregation"
target="_blank"
style={{ textDecoration: 'underline' }}
>
{' '}
<br />
Learn more
</Typography.Link>
</div>
}
>
<OperatorsSelect
value={query.aggregateOperator || ''}
onChange={handleChangeOperator}
operators={operators}
/>
</Tooltip>
</Col>
)}
<Col flex="auto">
<MetricNameSelector
onChange={handleChangeAggregatorAttribute}
query={query}
/>
</Col>
{version &&
version === ENTITY_VERSION_V4 &&
operators &&
Array.isArray(operators) &&
operators.length > 0 && (
<Col flex="5.93rem">
<Tooltip
title={
<div style={{ textAlign: 'center' }}>
Select Aggregate Operator
<Typography.Link
className="learn-more"
href="https://signoz.io/docs/metrics-management/types-and-aggregation/?utm_source=product&utm_medium=query-builder#aggregation"
target="_blank"
style={{ textDecoration: 'underline' }}
>
{' '}
<br />
Learn more
</Typography.Link>
</div>
}
>
<OperatorsSelect
value={query.aggregateOperator || ''}
onChange={handleChangeOperator}
operators={operators}
disabled={disableOperatorSelector}
/>
</Tooltip>
</Col>
)}
</Row>
</Col>
)}
<Col flex="1 1 40rem">
<Row gutter={[11, 5]}>
{isMetricsDataSource && (
<Col>
<FilterLabel label="WHERE" />
</Col>
)}
<Col flex="1" className="qb-search-container">
{[DataSource.LOGS, DataSource.TRACES].includes(query.dataSource) ? (
<QueryBuilderSearchV2
query={query}
onChange={handleChangeTagFilters}
whereClauseConfig={filterConfigs?.filters}
hideSpanScopeSelector={query.dataSource !== DataSource.TRACES}
/>
) : (
<QueryBuilderSearch
query={query}
onChange={handleChangeTagFilters}
whereClauseConfig={filterConfigs?.filters}
/>
)}
</Col>
</Row>
</Col>
</Row>
</Col>
{!isMetricsDataSource && !isListViewPanel && (
<Col span={11}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
<Tooltip
title={
<div style={{ textAlign: 'center' }}>
Select Aggregate Operator
<Typography.Link
href="https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=query-builder#aggregation"
target="_blank"
style={{ textDecoration: 'underline' }}
>
{' '}
<br />
Learn more
</Typography.Link>
</div>
}
>
<OperatorsSelect
value={query.aggregateOperator || ''}
onChange={handleChangeOperator}
operators={operators}
/>
</Tooltip>
</Col>
<Col flex="1 1 12.5rem">
<AggregatorFilter
query={query}
onChange={handleChangeAggregatorAttribute}
disabled={
panelType === PANEL_TYPES.LIST || panelType === PANEL_TYPES.TRACE
}
/>
</Col>
</Row>
</Col>
)}
{!isListViewPanel && (
<Col span={24}>
<Row gutter={[11, 5]}>
<Col flex="5.93rem">
{isVersionV4 && isMetricsDataSource ? (
<SpaceAggregationOptions
panelType={panelType}
key={`${panelType}${query.spaceAggregation}${query.timeAggregation}`}
aggregatorAttributeType={
query?.aggregateAttribute?.type as ATTRIBUTE_TYPES
}
selectedValue={query.spaceAggregation}
disabled={disableOperatorSelector}
onSelect={handleSpaceAggregationChange}
operators={spaceAggregationOptions}
/>
) : (
<FilterLabel
label={panelType === PANEL_TYPES.VALUE ? 'Reduce to' : 'Group by'}
/>
)}
</Col>
<Col flex="1 1 12.5rem">
{panelType === PANEL_TYPES.VALUE ? (
<Row>
{isVersionV4 && isMetricsDataSource && (
<Col span={4}>
<FilterLabel label="Reduce to" />
</Col>
)}
<Col span={isVersionV4 && isMetricsDataSource ? 20 : 24}>
<ReduceToFilter query={query} onChange={handleChangeReduceTo} />
</Col>
</Row>
) : (
<GroupByFilter
disabled={isMetricsDataSource && !query.aggregateAttribute?.key}
query={query}
onChange={handleChangeGroupByKeys}
/>
)}
</Col>
{isVersionV4 &&
isMetricsDataSource &&
(panelType === PANEL_TYPES.TABLE || panelType === PANEL_TYPES.PIE) && (
<Col flex="1 1 12.5rem">
<Row>
<Col span={6}>
<FilterLabel label="Reduce to" />
</Col>
<Col span={18}>
<ReduceToFilter query={query} onChange={handleChangeReduceTo} />
</Col>
</Row>
</Col>
)}
</Row>
</Col>
)}
{!isTracePanelType && !isListViewPanel && (
<Col span={24}>
<AdditionalFiltersToggler
listOfAdditionalFilter={listOfAdditionalFilters}
>
<Row gutter={[0, 11]} justify="space-between">
{renderAdditionalFilters()}
</Row>
</AdditionalFiltersToggler>
</Col>
)}
{isListViewPanel && (
<Col span={24}>
<Row gutter={[0, 11]} justify="space-between">
{renderAdditionalFilters()}
</Row>
</Col>
)}
{panelType !== PANEL_TYPES.LIST && panelType !== PANEL_TYPES.TRACE && (
<Row style={{ width: '100%' }}>
<Tooltip
placement="right"
title={
<div style={{ textAlign: 'center' }}>
Name of legend
<Typography.Link
style={{ textDecoration: 'underline' }}
href="https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=query-builder#legend-format"
target="_blank"
>
{' '}
<br />
Learn more
</Typography.Link>
</div>
}
>
<Input
onChange={handleChangeQueryLegend}
size="middle"
value={query.legend}
addonBefore="Legend Format"
/>
</Tooltip>
</Row>
)}
</Row>
)}
</Row>
);
});

View File

@@ -1 +0,0 @@
export { Query } from './Query';

View File

@@ -5,4 +5,3 @@ export { Formula } from './Formula';
export { HavingFilterTag } from './HavingFilterTag';
export { ListItemWrapper } from './ListItemWrapper';
export { ListMarker } from './ListMarker';
export { Query } from './Query';

View File

@@ -1,4 +1,6 @@
import { IQueryBuilderState } from 'constants/queryBuilder';
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
export interface InitialStateI {
search: string;
@@ -18,3 +20,19 @@ export type Option = {
isIndexed?: boolean;
type?: string;
};
export type QueryProps = {
index: number;
isAvailableToDisable: boolean;
query: IBuilderQuery;
queryVariant?: 'static' | 'dropdown';
isListViewPanel?: boolean;
showFunctions?: boolean;
version: string;
showSpanScopeSelector?: boolean;
showOnlyWhereClause?: boolean;
showTraceOperator?: boolean;
hasTraceOperator?: boolean;
signalSource?: string;
isMultiQueryAllowed?: boolean;
} & Pick<QueryBuilderProps, 'filterConfigs' | 'queryComponents'>;

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

@@ -191,13 +191,6 @@
line-height: 20px;
}
}
.ant-modal-body {
.ant-divider {
margin: 16px 0;
border: 0.5px solid var(--l1-border);
}
}
}
.create-policy-container {

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

@@ -15,11 +15,8 @@
}
}
.ant-divider {
margin-inline-start: 10px !important;
margin-inline-end: 16px !important;
height: 16px;
border-color: var(--l1-border);
&__divider {
--divider-vertical-margin: 10px;
}
.ant-drawer-close {
margin: 0 !important;

View File

@@ -1,5 +1,5 @@
import { useCallback, useMemo, useState } from 'react';
import { Color, Spacing } from '@signozhq/design-tokens';
import { Color } from '@signozhq/design-tokens';
import { Button, Drawer } from 'antd';
import { Divider } from '@signozhq/ui/divider';
import { Typography } from '@signozhq/ui/typography';
@@ -179,7 +179,10 @@ function SpanRelatedSignals({
width="50%"
title={
<>
<Divider type="vertical" />
<Divider
type="vertical"
className="span-related-signals-drawer__divider"
/>
<Typography.Text className="title">
Related Signals - {selectedSpan.name}
</Typography.Text>
@@ -194,7 +197,7 @@ function SpanRelatedSignals({
}}
className="span-related-signals-drawer"
destroyOnClose
closeIcon={<X size={16} style={{ marginTop: Spacing.MARGIN_1 }} />}
closeIcon={<X size={16} />}
>
{selectedSpan && (
<div className="span-related-signals-drawer__content">

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

@@ -30,7 +30,10 @@ import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { Pagination } from 'hooks/queryPagination';
import { getDefaultPaginationConfig } from 'hooks/queryPagination/utils';
import useDragColumns from 'hooks/useDragColumns';
import { getDraggedColumns } from 'hooks/useDragColumns/utils';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { ArrowUp10, Minus } from '@signozhq/icons';
import { useTimezone } from 'providers/Timezone';
import { AppState } from 'store/reducers';
@@ -82,6 +85,10 @@ function ListView({
},
});
const { draggedColumns, onDragColumns } = useDragColumns<RowData>(
LOCALSTORAGE.TRACES_LIST_COLUMNS,
);
const { queryData: paginationQueryData } = useUrlQueryData<Pagination>(
QueryParams.pagination,
);
@@ -93,19 +100,6 @@ function ListView({
[stagedQuery, orderBy],
);
// TEMP — remove after traces moves to TanStack table.
// - Drag updates selectColumns; raw queryKey would churn on reorder.
// - Trace API fetches only listed columns → add/remove must refetch.
// - Sorted-name signature: stable on reorder, changes on add/remove.
const selectColumnsSignature = useMemo(
() =>
(options?.selectColumns ?? [])
.map((c) => c.name)
.sort()
.join(','),
[options?.selectColumns],
);
const queryKey = useMemo(
() => [
REACT_QUERY_KEY.GET_QUERY_RANGE,
@@ -115,7 +109,7 @@ function ListView({
stagedQuery,
panelType,
paginationConfig,
selectColumnsSignature,
options?.selectColumns,
orderBy,
],
[
@@ -123,7 +117,7 @@ function ListView({
panelType,
globalSelectedTime,
paginationConfig,
selectColumnsSignature,
options?.selectColumns,
maxTime,
minTime,
orderBy,
@@ -188,14 +182,13 @@ function ListView({
const { formatTimezoneAdjustedTimestamp } = useTimezone();
const columns = useMemo(
() =>
getListColumns(
options?.selectColumns || [],
formatTimezoneAdjustedTimestamp,
),
[options?.selectColumns, formatTimezoneAdjustedTimestamp],
);
const columns = useMemo(() => {
const updatedColumns = getListColumns(
options?.selectColumns || [],
formatTimezoneAdjustedTimestamp,
);
return getDraggedColumns(updatedColumns, draggedColumns);
}, [options?.selectColumns, formatTimezoneAdjustedTimestamp, draggedColumns]);
const transformedQueryTableData = useMemo(
() => transformDataWithDate(queryTableData) || [],
@@ -203,16 +196,9 @@ function ListView({
);
const handleDragColumn = useCallback(
(fromIndex: number, toIndex: number): void => {
const reordered = [...columns];
const [moved] = reordered.splice(fromIndex, 1);
reordered.splice(toIndex, 0, moved);
const orderedIds = reordered
.map((c) => String(('dataIndex' in c && c.dataIndex) || c.key || ''))
.filter(Boolean);
config?.addColumn?.onReorder(orderedIds);
},
[columns, config],
(fromIndex: number, toIndex: number) =>
onDragColumns(columns, fromIndex, toIndex),
[columns, onDragColumns],
);
const handleOrderChange = useCallback((value: string) => {

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

@@ -41,9 +41,9 @@
}
.alert-details {
.divider {
border-color: var(--l1-border);
margin: 16px 0;
&__divider {
--divider-color: var(--l1-border);
--divider-margin: 16px 0;
}
.breadcrumb-divider {
margin-top: 10px;

View File

@@ -104,7 +104,7 @@ function AlertDetails(): JSX.Element {
/>
{alertRuleDetails && <AlertHeader alertDetails={alertRuleDetails} />}
<Divider className="divider" />
<Divider className="alert-details__divider" />
<div className="tabs-and-filters">
<RouteTab
routes={routes}

View File

@@ -3,10 +3,9 @@
align-items: center;
gap: 12px;
color: var(--l1-border);
.ant-divider-vertical {
height: 16px;
border-color: var(--l1-border);
margin: 0;
&__divider {
--divider-color: var(--l1-border);
--divider-vertical-margin: 0;
}
.dropdown-trigger-wrapper {
display: flex;

View File

@@ -122,7 +122,7 @@ function AlertActionButtons({
</Tooltip>
<CopyToClipboard textToCopy={window.location.href} />
<Divider type="vertical" />
<Divider type="vertical" className="alert-action-buttons__divider" />
<DropdownMenuSimple menu={{ items: menuItems }}>
<span className="dropdown-trigger-wrapper">

View File

@@ -3,6 +3,7 @@ import { useQueryClient } from 'react-query';
import * as Sentry from '@sentry/react';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import { TelemetryFieldKey } from 'api/v5/v5';
import cx from 'classnames';
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
import QueryCancelledPlaceholder from 'components/QueryCancelledPlaceholder';
@@ -14,6 +15,12 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { usePageActions } from 'container/AIAssistant/pageActions/usePageActions';
import LogExplorerQuerySection from 'container/LogExplorerQuerySection';
import LogsExplorerViewsContainer from 'container/LogsExplorerViews';
import {
defaultLogsSelectedColumns,
defaultOptionsQuery,
URL_OPTIONS,
} from 'container/OptionsMenu/constants';
import { OptionsQuery } from 'container/OptionsMenu/types';
import LeftToolbarActions from 'container/QueryBuilder/components/ToolbarActions/LeftToolbarActions';
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
import Toolbar from 'container/Toolbar/Toolbar';
@@ -24,9 +31,11 @@ import {
useHandleExplorerTabChange,
} from 'hooks/useHandleExplorerTabChange';
import { useIsAIAssistantEnabled } from 'hooks/useIsAIAssistantEnabled';
import { defaultTo, isEmpty, isNull } from 'lodash-es';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { defaultTo, isEmpty, isEqual, isNull } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { EventSourceProvider } from 'providers/EventSource';
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
import { Warning } from 'types/api';
import { DataSource } from 'types/common/queryBuilder';
import {
@@ -53,6 +62,8 @@ function LogsExplorer(): JSX.Element {
const [selectedView, setSelectedView] = useState<ExplorerViews>(
() => panelTypeToExplorerView[panelTypesFromUrl],
);
const { logs } = usePreferenceContext();
const { preferences } = logs;
const [showFilters, setShowFilters] = useState<boolean>(() => {
const localStorageValue = getLocalStorageKey(
@@ -171,6 +182,116 @@ function LogsExplorer(): JSX.Element {
setShowFilters((prev) => !prev);
};
const { redirectWithQuery: redirectWithOptionsData } =
useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
// Get and parse stored columns from localStorage
const logListOptionsFromLocalStorage = useMemo(() => {
const data = getLocalStorageKey(LOCALSTORAGE.LOGS_LIST_OPTIONS);
if (!data) {
return null;
}
try {
return JSON.parse(data);
} catch {
return null;
}
}, []);
// Check if the columns have the required columns (timestamp, body)
const hasRequiredColumns = useCallback(
(columns?: TelemetryFieldKey[] | null): boolean => {
if (!columns?.length) {
return false;
}
const hasTimestamp = columns.some((col) => col.name === 'timestamp');
const hasBody = columns.some((col) => col.name === 'body');
return hasTimestamp && hasBody;
},
[],
);
// Merge the columns with the required columns (timestamp, body) if missing
const mergeWithRequiredColumns = useCallback(
(columns: TelemetryFieldKey[]): TelemetryFieldKey[] => [
// Add required columns (timestamp, body) if missing
...(!hasRequiredColumns(columns) ? defaultLogsSelectedColumns : []),
...columns,
],
[hasRequiredColumns],
);
// Migrate the options query to the new format
const migrateOptionsQuery = useCallback(
(query: OptionsQuery): OptionsQuery => {
// Skip if already migrated
if (query.version) {
return query;
}
if (logListOptionsFromLocalStorage?.version) {
return logListOptionsFromLocalStorage;
}
// Case 1: we have localStorage columns
if (logListOptionsFromLocalStorage?.selectColumns?.length > 0) {
return {
...query,
version: 1,
selectColumns: mergeWithRequiredColumns(
logListOptionsFromLocalStorage.selectColumns,
),
};
}
// Case 2: No query columns in localStorage in but query has columns
if (query.selectColumns.length > 0) {
return {
...query,
version: 1,
selectColumns: mergeWithRequiredColumns(query.selectColumns),
};
}
// Case 3: No columns anywhere, use defaults
return {
...query,
version: 1,
selectColumns: defaultLogsSelectedColumns,
};
},
[mergeWithRequiredColumns, logListOptionsFromLocalStorage],
);
useEffect(() => {
if (!preferences) {
return;
}
const migratedQuery = migrateOptionsQuery({
selectColumns: preferences.columns || defaultLogsSelectedColumns,
maxLines: preferences.formatting?.maxLines || defaultOptionsQuery.maxLines,
format: preferences.formatting?.format || defaultOptionsQuery.format,
fontSize: preferences.formatting?.fontSize || defaultOptionsQuery.fontSize,
version: preferences.formatting?.version,
});
// Only redirect if the query was actually modified
if (
!isEqual(migratedQuery, {
selectColumns: preferences?.columns,
maxLines: preferences?.formatting?.maxLines,
format: preferences?.formatting?.format,
fontSize: preferences?.formatting?.fontSize,
version: preferences?.formatting?.version,
})
) {
redirectWithOptionsData(migratedQuery);
}
}, [migrateOptionsQuery, preferences, redirectWithOptionsData]);
const toolbarViews = useMemo(
() => ({
list: {

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

@@ -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

@@ -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

@@ -47,10 +47,9 @@
}
}
.divider {
background-color: var(--l1-border);
margin: 0;
border-color: var(--l1-border);
.section-body__divider {
--divider-color: var(--l1-border);
--divider-margin: 0;
}
.filter-header {

View File

@@ -65,7 +65,7 @@ export function Section(props: SectionProps): JSX.Element {
return (
<div>
<Divider plain className="divider" />
<Divider plain className="section-body__divider" />
<div className="section-body-header" data-testid={`collapse-${panelName}`}>
<Collapse
bordered={false}

View File

@@ -24,9 +24,6 @@
align-items: center;
}
gap: 12px;
.ant-divider-vertical {
margin: 0;
}
.funnel-configuration__rename-btn {
padding: 4px;
width: 24px;
@@ -74,4 +71,7 @@
gap: 12px;
padding: 16px;
}
&__divider {
--divider-margin: 0px;
}
}

View File

@@ -77,7 +77,7 @@ function FunnelConfiguration({
/>
</Tooltip>
<CopyToClipboard textToCopy={window.location.href} />
<Divider type="vertical" />
<Divider type="vertical" className="funnel-configuration__divider" />
<FunnelItemPopover
isPopoverOpen={isPopoverOpen}
setIsPopoverOpen={setIsPopoverOpen}

View File

@@ -94,9 +94,6 @@
display: flex;
align-items: center;
}
.ant-divider-vertical {
margin: 0 12px;
}
.funnel-item__action-btn {
border: none;
padding: 4px;

View File

@@ -26,10 +26,7 @@
}
&__divider {
width: 100%;
.ant-divider {
margin: 0;
border-color: var(--l1-border);
}
--divider-margin: 0;
}
&__latency-options {
flex-shrink: 0;

View File

@@ -17,14 +17,6 @@
flex-shrink: 0;
}
&__divider {
width: 100%;
.ant-divider {
margin: 0;
border-color: var(--l1-border);
}
}
&__time-range {
width: 100%;
height: 32px;

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';

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