mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-28 12:50:32 +01:00
Compare commits
12 Commits
mute-rules
...
v0.126.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8f5bdf256 | ||
|
|
2f102ee3f5 | ||
|
|
0a3717e0d8 | ||
|
|
fd413d336d | ||
|
|
7b892ee1fc | ||
|
|
31e4012fe5 | ||
|
|
71cb97f52f | ||
|
|
11f1789dea | ||
|
|
1a97e90117 | ||
|
|
939f0d7a05 | ||
|
|
9d1c27cb57 | ||
|
|
07ce2d341c |
@@ -445,7 +445,12 @@ authz:
|
||||
|
||||
##################### Meter Reporter #####################
|
||||
meterreporter:
|
||||
# The interval between collection ticks. Minimum 5m.
|
||||
# The interval between collection ticks. Minimum 10m, maximum 24h.
|
||||
interval: 6h
|
||||
# Whether to backfill sealed days from the license creation day.
|
||||
backfill: true
|
||||
# Random jitter applied to the first collect and to every subsequent cycle.
|
||||
# The first collect fires at a random time in [0, jitter); each cycle then takes
|
||||
# interval - random(0, jitter). Must be between 10m and interval. Defaults to
|
||||
# min(interval, 2h) when unset.
|
||||
jitter: 2h
|
||||
|
||||
@@ -190,7 +190,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.126.0
|
||||
image: signoz/signoz:v0.126.1
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
# - "6060:6060" # pprof port
|
||||
|
||||
@@ -117,7 +117,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.126.0
|
||||
image: signoz/signoz:v0.126.1
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
volumes:
|
||||
|
||||
@@ -181,7 +181,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.126.0}
|
||||
image: signoz/signoz:${VERSION:-v0.126.1}
|
||||
container_name: signoz
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
|
||||
@@ -109,7 +109,7 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.126.0}
|
||||
image: signoz/signoz:${VERSION:-v0.126.1}
|
||||
container_name: signoz
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
|
||||
@@ -17,9 +17,15 @@ const BANNED_COMPONENTS = {
|
||||
Typography:
|
||||
'Use @signozhq/ui/typography Typography instead of antd Typography.',
|
||||
Switch: 'Use @signozhq/ui/switch Switch instead of antd Switch.',
|
||||
Dropdown:
|
||||
'Use @signozhq/ui DropdownMenuSimple (or the composable DropdownMenu primitives) from @signozhq/ui/dropdown-menu instead of antd Dropdown.',
|
||||
Badge: 'Use @signozhq/ui/badge instead of antd Badge.',
|
||||
Radio:
|
||||
'Use @signozhq/ui/radio-group RadioGroup (dots) or @signozhq/ui/toggle-group ToggleGroup (segmented buttons) instead of antd Radio.',
|
||||
Progress: 'Use @signozhq/ui/progress instead of antd Progress.',
|
||||
Avatar: 'Use @signozhq/ui/avatar instead of antd Avatar.',
|
||||
Divider: 'Use @signozhq/ui/divider Divider instead of antd Divider.',
|
||||
Tag: 'Use @signozhq/ui/badge Bagde instead of antd Tag.',
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Breadcrumb, Divider } from 'antd';
|
||||
import { Breadcrumb } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
|
||||
import styles from './AlertBreadcrumb.module.scss';
|
||||
import BreadcrumbItem, { BreadcrumbItemConfig } from './BreadcrumbItem';
|
||||
|
||||
@@ -14,11 +14,6 @@
|
||||
.ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ant-tag {
|
||||
margin-right: 0;
|
||||
background: var(--card);
|
||||
}
|
||||
}
|
||||
|
||||
.add-tag-container {
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { Dispatch, SetStateAction, useState } from 'react';
|
||||
import { Check, Plus, X } from '@signozhq/icons';
|
||||
import { Button, Flex, Tag } from 'antd';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import Input from 'components/Input';
|
||||
|
||||
import './Tags.styles.scss';
|
||||
import './Badges.styles.scss';
|
||||
|
||||
function Tags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
function Badges({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
const [inputValue, setInputValue] = useState<string>('');
|
||||
const [inputVisible, setInputVisible] = useState<boolean>(false);
|
||||
|
||||
@@ -46,14 +47,18 @@ function Tags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
return (
|
||||
<div className="tags-container">
|
||||
{tags.map<React.ReactNode>((tag) => (
|
||||
<Tag
|
||||
<Badge
|
||||
key={tag}
|
||||
closable
|
||||
color="vanilla"
|
||||
style={{ userSelect: 'none' }}
|
||||
onClose={(): void => handleClose(tag)}
|
||||
closable
|
||||
onClose={(e): void => {
|
||||
e.preventDefault();
|
||||
handleClose(tag);
|
||||
}}
|
||||
>
|
||||
<span>{tag}</span>
|
||||
</Tag>
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
|
||||
{inputVisible && (
|
||||
@@ -113,4 +118,4 @@ interface AddTagsProps {
|
||||
setTags: Dispatch<SetStateAction<string[]>>;
|
||||
}
|
||||
|
||||
export default Tags;
|
||||
export default Badges;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { Color, Spacing } from '@signozhq/design-tokens';
|
||||
import { Divider, Drawer } from 'antd';
|
||||
import { Drawer } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Select, Tag, Tooltip } from 'antd';
|
||||
import { Select, Tooltip } from 'antd';
|
||||
import {
|
||||
OPERATORS,
|
||||
QUERY_BUILDER_OPERATORS_BY_TYPES,
|
||||
@@ -51,6 +51,7 @@ import { popupContainer } from 'utils/selectPopupContainer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import './ClientSideQBSearch.styles.scss';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
|
||||
export interface AttributeKey {
|
||||
key: string;
|
||||
@@ -547,10 +548,14 @@ function ClientSideQBSearch(
|
||||
|
||||
return (
|
||||
<span className="qb-search-bar-tokenised-tags">
|
||||
<Tag
|
||||
closable={!searchValue && closable}
|
||||
onClose={onCloseHandler}
|
||||
<Badge
|
||||
color="vanilla"
|
||||
className={tagDetails?.key?.type || ''}
|
||||
closable={!searchValue && closable}
|
||||
onClose={(e): void => {
|
||||
e.preventDefault();
|
||||
onCloseHandler();
|
||||
}}
|
||||
>
|
||||
<Tooltip title={chipValue}>
|
||||
<TypographyText
|
||||
@@ -566,7 +571,7 @@ function ClientSideQBSearch(
|
||||
{chipValue}
|
||||
</TypographyText>
|
||||
</Tooltip>
|
||||
</Tag>
|
||||
</Badge>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { Button, Popover, Radio, Tooltip } from 'antd';
|
||||
import { Button, Popover, Tooltip } from 'antd';
|
||||
import { RadioGroup, RadioGroupItem } from '@signozhq/ui/radio-group';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { useExportRawData } from 'hooks/useDownloadOptionsMenu/useDownloadOptionsMenu';
|
||||
@@ -63,27 +64,30 @@ export default function DownloadOptionsMenu({
|
||||
>
|
||||
<div className="export-format">
|
||||
<Typography.Text className="title">FORMAT</Typography.Text>
|
||||
<Radio.Group
|
||||
value={exportFormat}
|
||||
onChange={(e): void => setExportFormat(e.target.value)}
|
||||
>
|
||||
<Radio value={DownloadFormats.CSV}>csv</Radio>
|
||||
<Radio value={DownloadFormats.JSONL}>jsonl</Radio>
|
||||
</Radio.Group>
|
||||
<RadioGroup value={exportFormat} onChange={setExportFormat}>
|
||||
<RadioGroupItem value={DownloadFormats.CSV}>csv</RadioGroupItem>
|
||||
<RadioGroupItem value={DownloadFormats.JSONL}>jsonl</RadioGroupItem>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<div className="horizontal-line" />
|
||||
|
||||
<div className="row-limit">
|
||||
<Typography.Text className="title">Number of Rows</Typography.Text>
|
||||
<Radio.Group
|
||||
value={rowLimit}
|
||||
onChange={(e): void => setRowLimit(e.target.value)}
|
||||
<RadioGroup
|
||||
value={String(rowLimit)}
|
||||
onChange={(value): void => setRowLimit(Number(value))}
|
||||
>
|
||||
<Radio value={DownloadRowCounts.TEN_K}>10k</Radio>
|
||||
<Radio value={DownloadRowCounts.THIRTY_K}>30k</Radio>
|
||||
<Radio value={DownloadRowCounts.FIFTY_K}>50k</Radio>
|
||||
</Radio.Group>
|
||||
<RadioGroupItem value={String(DownloadRowCounts.TEN_K)}>
|
||||
10k
|
||||
</RadioGroupItem>
|
||||
<RadioGroupItem value={String(DownloadRowCounts.THIRTY_K)}>
|
||||
30k
|
||||
</RadioGroupItem>
|
||||
<RadioGroupItem value={String(DownloadRowCounts.FIFTY_K)}>
|
||||
50k
|
||||
</RadioGroupItem>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{dataSource !== DataSource.TRACES && (
|
||||
@@ -92,13 +96,12 @@ export default function DownloadOptionsMenu({
|
||||
|
||||
<div className="columns-scope">
|
||||
<Typography.Text className="title">Columns</Typography.Text>
|
||||
<Radio.Group
|
||||
value={columnsScope}
|
||||
onChange={(e): void => setColumnsScope(e.target.value)}
|
||||
>
|
||||
<Radio value={DownloadColumnsScopes.ALL}>All</Radio>
|
||||
<Radio value={DownloadColumnsScopes.SELECTED}>Selected</Radio>
|
||||
</Radio.Group>
|
||||
<RadioGroup value={columnsScope} onChange={setColumnsScope}>
|
||||
<RadioGroupItem value={DownloadColumnsScopes.ALL}>All</RadioGroupItem>
|
||||
<RadioGroupItem value={DownloadColumnsScopes.SELECTED}>
|
||||
Selected
|
||||
</RadioGroupItem>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.dropdown-button {
|
||||
color: var(--l1-foreground);
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { Ellipsis } from '@signozhq/icons';
|
||||
import { Button, Dropdown, MenuProps } from 'antd';
|
||||
|
||||
import './DropDown.styles.scss';
|
||||
|
||||
function DropDown({
|
||||
element,
|
||||
onDropDownItemClick,
|
||||
}: {
|
||||
element: JSX.Element[];
|
||||
onDropDownItemClick?: MenuProps['onClick'];
|
||||
}): JSX.Element {
|
||||
const items: MenuProps['items'] = element.map(
|
||||
(e: JSX.Element, index: number) => ({
|
||||
label: e,
|
||||
key: index,
|
||||
}),
|
||||
);
|
||||
|
||||
const [isDdOpen, setDdOpen] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items,
|
||||
onMouseEnter: (): void => setDdOpen(true),
|
||||
onMouseLeave: (): void => setDdOpen(false),
|
||||
onClick: (item): void => onDropDownItemClick?.(item),
|
||||
}}
|
||||
open={isDdOpen}
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
className={`dropdown-button`}
|
||||
onClick={(e): void => {
|
||||
e.preventDefault();
|
||||
setDdOpen(true);
|
||||
}}
|
||||
>
|
||||
<Ellipsis className="dropdown-icon" size={16} />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
DropDown.defaultProps = {
|
||||
onDropDownItemClick: (): void => {},
|
||||
};
|
||||
|
||||
export default DropDown;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Modal, Tag } from 'antd';
|
||||
import { Button, Modal } from 'antd';
|
||||
import { CircleAlert, X } from '@signozhq/icons';
|
||||
import KeyValueLabel from 'periscope/components/KeyValueLabel';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
@@ -9,6 +9,7 @@ import APIError from 'types/api/error';
|
||||
import ErrorContent from './components/ErrorContent';
|
||||
|
||||
import './ErrorModal.styles.scss';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
|
||||
type Props = {
|
||||
error: APIError;
|
||||
@@ -45,14 +46,17 @@ function ErrorModal({
|
||||
return (
|
||||
<>
|
||||
{!triggerComponent ? (
|
||||
<Tag
|
||||
<span
|
||||
className="error-modal__trigger"
|
||||
icon={<CircleAlert size={14} color={Color.BG_CHERRY_500} />}
|
||||
color="error"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={(): void => setVisible(true)}
|
||||
onKeyDown={undefined}
|
||||
>
|
||||
error
|
||||
</Tag>
|
||||
<Badge color="error">
|
||||
<CircleAlert size={14} color={Color.BG_CHERRY_500} /> error
|
||||
</Badge>
|
||||
</span>
|
||||
) : (
|
||||
React.cloneElement(triggerComponent, {
|
||||
onClick: () => setVisible(true),
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Dropdown,
|
||||
MenuProps,
|
||||
Popover,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
} from 'antd';
|
||||
import { Button, Col, Popover, Row, Select, Space } from 'antd';
|
||||
import { DropdownMenuSimple, type MenuProps } from '@signozhq/ui/dropdown-menu';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import axios from 'axios';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
@@ -241,9 +233,9 @@ function ExplorerCard({
|
||||
</Popover>
|
||||
<Share2 onClick={onCopyUrlHandler} size="md" />
|
||||
{viewKey && (
|
||||
<Dropdown trigger={['click']} menu={moreOptionMenu}>
|
||||
<Ellipsis size="md" />
|
||||
</Dropdown>
|
||||
<DropdownMenuSimple menu={moreOptionMenu}>
|
||||
<Button type="text" size="small" icon={<Ellipsis size="md" />} />
|
||||
</DropdownMenuSimple>
|
||||
)}
|
||||
</Space>
|
||||
</OffSetCol>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { Button, Input, Radio, RadioChangeEvent } from 'antd';
|
||||
import { Button, Input } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { handleContactSupport } from 'container/Integrations/utils';
|
||||
@@ -101,13 +102,12 @@ function FeedbackModal({ onClose }: { onClose: () => void }): JSX.Element {
|
||||
return (
|
||||
<div className="feedback-modal-container">
|
||||
<div className="feedback-modal-header">
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={activeTab}
|
||||
defaultValue={activeTab}
|
||||
optionType="button"
|
||||
className="feedback-modal-tabs"
|
||||
options={items}
|
||||
onChange={(e: RadioChangeEvent): void => setActiveTab(e.target.value)}
|
||||
onChange={setActiveTab}
|
||||
items={items}
|
||||
/>
|
||||
</div>
|
||||
<div className="feedback-modal-content">
|
||||
|
||||
@@ -158,23 +158,23 @@
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.tab {
|
||||
> button {
|
||||
border: 1px solid var(--l1-border);
|
||||
width: 114px;
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
|
||||
.selected_view {
|
||||
background: var(--l3-background);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
}
|
||||
&[data-state='on'] {
|
||||
background: var(--l3-background);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
|
||||
.selected_view::before {
|
||||
background: var(--l1-border);
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import { useSelector } from 'react-redux'; // old code, TODO: fix this correctly
|
||||
import { useCopyToClipboard, useLocation } from 'react-use';
|
||||
import { Color, Spacing } from '@signozhq/design-tokens';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Divider, Drawer, Radio, Tooltip } from 'antd';
|
||||
import { Drawer, Tooltip } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { RadioChangeEvent } from 'antd/lib';
|
||||
import cx from 'classnames';
|
||||
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
|
||||
import QuerySearch from 'components/QueryBuilderV2/QueryV2/QuerySearch/QuerySearch';
|
||||
@@ -197,8 +198,8 @@ function LogDetailInner({
|
||||
|
||||
const LogJsonData = log ? aggregateAttributesResourcesToString(log) : '';
|
||||
|
||||
const handleModeChange = (e: RadioChangeEvent): void => {
|
||||
setSelectedView(e.target.value);
|
||||
const handleModeChange = (value: string): void => {
|
||||
setSelectedView(value as VIEWS);
|
||||
setIsEdit(false);
|
||||
setIsFilterVisible(false);
|
||||
};
|
||||
@@ -452,56 +453,50 @@ function LogDetailInner({
|
||||
</div>
|
||||
|
||||
<div className="tabs-and-search">
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
className="views-tabs"
|
||||
onChange={handleModeChange}
|
||||
value={selectedView}
|
||||
>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.OVERVIEW ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.OVERVIEW}
|
||||
>
|
||||
<div className="view-title">
|
||||
<Table size={14} />
|
||||
Overview
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.JSON ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.JSON}
|
||||
>
|
||||
<div className="view-title">
|
||||
<Braces size={14} />
|
||||
JSON
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.CONTEXT ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.CONTEXT}
|
||||
>
|
||||
<div className="view-title">
|
||||
<TextSelect size={14} />
|
||||
Context
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.INFRAMETRICS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.INFRAMETRICS}
|
||||
>
|
||||
<div className="view-title">
|
||||
<Histogram size="md" />
|
||||
Metrics
|
||||
</div>
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
items={[
|
||||
{
|
||||
value: VIEW_TYPES.OVERVIEW,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<Table size={14} />
|
||||
Overview
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: VIEW_TYPES.JSON,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<Braces size={14} />
|
||||
JSON
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: VIEW_TYPES.CONTEXT,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<TextSelect size={14} />
|
||||
Context
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: VIEW_TYPES.INFRAMETRICS,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<Histogram size="md" />
|
||||
Metrics
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className="log-detail-drawer__actions">
|
||||
{selectedView === VIEW_TYPES.CONTEXT && (
|
||||
|
||||
@@ -18,7 +18,8 @@ import {
|
||||
RefreshCw,
|
||||
} from '@signozhq/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Checkbox, Select } from 'antd';
|
||||
import { Button, Select } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import cx from 'classnames';
|
||||
import TextToolTip from 'components/TextToolTip/TextToolTip';
|
||||
@@ -749,7 +750,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
|
||||
tabIndex={isActive ? 0 : -1}
|
||||
>
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
value={isSelected}
|
||||
className="option-checkbox"
|
||||
onClick={(e): void => {
|
||||
e.stopPropagation();
|
||||
@@ -1584,7 +1585,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
|
||||
<Checkbox checked={allOptionsSelected} className="option-checkbox">
|
||||
<Checkbox value={allOptionsSelected} className="option-checkbox">
|
||||
<div className="option-content">
|
||||
<div className="all-option-text">ALL</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
.query-add-ons {
|
||||
width: 100%;
|
||||
|
||||
.add-on-tab-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--margin-2);
|
||||
}
|
||||
}
|
||||
|
||||
.add-ons-list {
|
||||
@@ -25,7 +32,7 @@
|
||||
color: var(--l2-foreground);
|
||||
}
|
||||
|
||||
.tab {
|
||||
> button {
|
||||
border: 1px solid var(--l1-border);
|
||||
border-left: none;
|
||||
min-width: 120px;
|
||||
@@ -35,21 +42,21 @@
|
||||
&:first-child {
|
||||
border-left: 1px solid var(--l1-border);
|
||||
}
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
|
||||
.selected-view {
|
||||
color: var(--text-robin-500);
|
||||
border: 1px solid var(--l1-border);
|
||||
&[data-state='on'] {
|
||||
color: var(--text-robin-500);
|
||||
border: 1px solid var(--l1-border);
|
||||
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
|
||||
.selected-view::before {
|
||||
background: var(--l1-border);
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Button, Radio, RadioChangeEvent, Tooltip } from 'antd';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import InputWithLabel from 'components/InputWithLabel/InputWithLabel';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { GroupByFilter } from 'container/QueryBuilder/filters/GroupByFilter/GroupByFilter';
|
||||
@@ -250,8 +251,7 @@ function QueryAddOns({
|
||||
);
|
||||
}, [panelType, isListViewPanel, query, showReduceTo]);
|
||||
|
||||
const handleOptionClick = (e: RadioChangeEvent): void => {
|
||||
const clickedAddOn = e.target.value as AddOn;
|
||||
const handleOptionClick = (clickedAddOn: AddOn): void => {
|
||||
const isAlreadySelected = selectedViews.some(
|
||||
(view) => view.key === clickedAddOn.key,
|
||||
);
|
||||
@@ -515,15 +515,27 @@ function QueryAddOns({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="add-ons-list">
|
||||
<Radio.Group
|
||||
className="add-ons-tabs"
|
||||
onChange={handleOptionClick}
|
||||
value={selectedViews}
|
||||
>
|
||||
{addOns.map((addOn) => (
|
||||
<ToggleGroupSimple
|
||||
type="multiple"
|
||||
className="add-ons-tabs"
|
||||
value={selectedViews.map((view) => view.key)}
|
||||
onChange={(newKeys: string[]): void => {
|
||||
const oldKeys = selectedViews.map((view) => view.key);
|
||||
const toggledKey =
|
||||
newKeys.find((k) => !oldKeys.includes(k)) ??
|
||||
oldKeys.find((k) => !newKeys.includes(k));
|
||||
if (!toggledKey) {
|
||||
return;
|
||||
}
|
||||
const clickedAddOn = addOns.find((a) => a.key === toggledKey);
|
||||
if (clickedAddOn) {
|
||||
handleOptionClick(clickedAddOn);
|
||||
}
|
||||
}}
|
||||
items={addOns.map((addOn) => ({
|
||||
value: addOn.key,
|
||||
label: (
|
||||
<Tooltip
|
||||
key={addOn.key}
|
||||
title={
|
||||
<TooltipContent
|
||||
label={addOn.label}
|
||||
@@ -534,26 +546,17 @@ function QueryAddOns({
|
||||
placement="top"
|
||||
mouseEnterDelay={0.5}
|
||||
>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedViews.find((view) => view.key === addOn.key)
|
||||
? 'selected-view tab'
|
||||
: 'tab'
|
||||
}
|
||||
value={addOn}
|
||||
<span
|
||||
className="add-on-tab-title"
|
||||
data-testid={`query-add-on-${addOn.key}`}
|
||||
>
|
||||
<div
|
||||
className="add-on-tab-title"
|
||||
data-testid={`query-add-on-${addOn.key}`}
|
||||
>
|
||||
{addOn.icon}
|
||||
{addOn.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
{addOn.icon}
|
||||
{addOn.label}
|
||||
</span>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Radio.Group>
|
||||
</div>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import { Color } from '@signozhq/design-tokens';
|
||||
import { copilot } from '@uiw/codemirror-theme-copilot';
|
||||
import { githubLight } from '@uiw/codemirror-theme-github';
|
||||
import CodeMirror, { EditorView, keymap, Prec } from '@uiw/react-codemirror';
|
||||
import { Button, Card, Collapse, Popover, Tag, Tooltip } from 'antd';
|
||||
import { Button, Card, Collapse, Popover, Tooltip } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||
import { getValueSuggestions } from 'api/querySuggestions/getValueSuggestion';
|
||||
import cx from 'classnames';
|
||||
@@ -664,26 +665,26 @@ function QuerySearch({
|
||||
// Helper function to render a badge for the current context mode
|
||||
const renderContextBadge = (): JSX.Element => {
|
||||
if (!editingMode) {
|
||||
return <Tag>Unknown</Tag>;
|
||||
return <Badge color="vanilla">Unknown</Badge>;
|
||||
}
|
||||
|
||||
switch (editingMode) {
|
||||
case 'key':
|
||||
return <Tag color="blue">Key</Tag>;
|
||||
return <Badge color="robin">Key</Badge>;
|
||||
case 'operator':
|
||||
return <Tag color="purple">Operator</Tag>;
|
||||
return <Badge color="sakura">Operator</Badge>;
|
||||
case 'value':
|
||||
return <Tag color="green">Value</Tag>;
|
||||
return <Badge color="forest">Value</Badge>;
|
||||
case 'conjunction':
|
||||
return <Tag color="orange">Conjunction</Tag>;
|
||||
return <Badge color="amber">Conjunction</Badge>;
|
||||
case 'function':
|
||||
return <Tag color="cyan">Function</Tag>;
|
||||
return <Badge color="aqua">Function</Badge>;
|
||||
case 'parenthesis':
|
||||
return <Tag color="magenta">Parenthesis</Tag>;
|
||||
return <Badge color="sakura">Parenthesis</Badge>;
|
||||
case 'bracketList':
|
||||
return <Tag color="red">Bracket List</Tag>;
|
||||
return <Badge color="cherry">Bracket List</Badge>;
|
||||
default:
|
||||
return <Tag>Unknown</Tag>;
|
||||
return <Badge color="vanilla">Unknown</Badge>;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1304,34 +1305,37 @@ function QuerySearch({
|
||||
Currently editing: {renderContextBadge()}
|
||||
{queryContext?.keyToken && (
|
||||
<span className="triplet-info">
|
||||
Key: <Tag>{queryContext.keyToken}</Tag>
|
||||
Key: <Badge color="vanilla">{queryContext.keyToken}</Badge>
|
||||
</span>
|
||||
)}
|
||||
{queryContext?.operatorToken && (
|
||||
<span className="triplet-info">
|
||||
Operator: <Tag>{queryContext.operatorToken}</Tag>
|
||||
Operator: <Badge color="vanilla">{queryContext.operatorToken}</Badge>
|
||||
</span>
|
||||
)}
|
||||
{queryContext?.valueToken && (
|
||||
<span className="triplet-info">
|
||||
Value: <Tag>{queryContext.valueToken}</Tag>
|
||||
Value: <Badge color="vanilla">{queryContext.valueToken}</Badge>
|
||||
</span>
|
||||
)}
|
||||
{queryContext?.currentPair && (
|
||||
<span className="triplet-info query-pair-info">
|
||||
Current pair: <Tag color="blue">{queryContext.currentPair.key}</Tag>
|
||||
<Tag color="purple">{queryContext.currentPair.operator}</Tag>
|
||||
Current pair: <Badge color="robin">{queryContext.currentPair.key}</Badge>
|
||||
<Badge color="sakura">{queryContext.currentPair.operator}</Badge>
|
||||
{queryContext.currentPair.value && (
|
||||
<Tag color="green">{queryContext.currentPair.value}</Tag>
|
||||
<Badge color="forest">{queryContext.currentPair.value}</Badge>
|
||||
)}
|
||||
<Tag color={queryContext.currentPair.isComplete ? 'success' : 'warning'}>
|
||||
<Badge
|
||||
color={queryContext.currentPair.isComplete ? 'success' : 'warning'}
|
||||
>
|
||||
{queryContext.currentPair.isComplete ? 'Complete' : 'Incomplete'}
|
||||
</Tag>
|
||||
</Badge>
|
||||
</span>
|
||||
)}
|
||||
{queryContext?.queryPairs && queryContext.queryPairs.length > 0 && (
|
||||
<span className="triplet-info">
|
||||
Total pairs: <Tag color="blue">{queryContext.queryPairs.length}</Tag>
|
||||
Total pairs:{' '}
|
||||
<Badge color="robin">{queryContext.queryPairs.length}</Badge>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Dropdown } from 'antd';
|
||||
import { DropdownMenuSimple } from '@signozhq/ui/dropdown-menu';
|
||||
import cx from 'classnames';
|
||||
import { ENTITY_VERSION_V4, ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
@@ -195,7 +195,7 @@ export const QueryV2 = forwardRef(function QueryV2(
|
||||
)}
|
||||
|
||||
{isMultiQueryAllowed && (
|
||||
<Dropdown
|
||||
<DropdownMenuSimple
|
||||
className="query-actions-dropdown"
|
||||
menu={{
|
||||
items: [
|
||||
@@ -217,10 +217,10 @@ export const QueryV2 = forwardRef(function QueryV2(
|
||||
: []),
|
||||
],
|
||||
}}
|
||||
placement="bottomRight"
|
||||
align="end"
|
||||
>
|
||||
<Ellipsis size={16} />
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 24px;
|
||||
|
||||
.checkbox-value-section {
|
||||
display: flex;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable sonarjs/no-identical-functions */
|
||||
import { Fragment, useMemo, useState } from 'react';
|
||||
import { Button, Checkbox, Input, Skeleton } from 'antd';
|
||||
import { Button, Input, Skeleton } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import cx from 'classnames';
|
||||
import { removeKeysFromExpression } from 'components/QueryBuilderV2/utils';
|
||||
@@ -634,10 +635,12 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
|
||||
)}
|
||||
<div className="value">
|
||||
<Checkbox
|
||||
onChange={(e): void => onChange(value, e.target.checked, false)}
|
||||
checked={currentFilterState[value]}
|
||||
onChange={(checked): void =>
|
||||
onChange(value, checked === true, false)
|
||||
}
|
||||
value={currentFilterState[value]}
|
||||
disabled={isFilterDisabled}
|
||||
rootClassName="check-box"
|
||||
className="check-box"
|
||||
/>
|
||||
|
||||
<div
|
||||
|
||||
@@ -4,14 +4,14 @@ import type {
|
||||
TableColumnsType as ColumnsType,
|
||||
TableColumnType as ColumnType,
|
||||
} from 'antd';
|
||||
import { Button, Dropdown, Flex, MenuProps } from 'antd';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { DropdownMenuSimple, type MenuItem } from '@signozhq/ui/dropdown-menu';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import LaunchChatSupport from 'components/LaunchChatSupport/LaunchChatSupport';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { SlidersHorizontal } from '@signozhq/icons';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import ResizeTable from './ResizeTable';
|
||||
import { DynamicColumnTableProps } from './types';
|
||||
@@ -84,8 +84,9 @@ function DynamicColumnTable({
|
||||
);
|
||||
};
|
||||
|
||||
const items: MenuProps['items'] =
|
||||
const items: MenuItem[] =
|
||||
dynamicColumns?.map((column, index) => ({
|
||||
key: String(index),
|
||||
label: (
|
||||
<div
|
||||
className="dynamicColumnsTable-items"
|
||||
@@ -99,8 +100,6 @@ function DynamicColumnTable({
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
key: index,
|
||||
type: 'checkbox',
|
||||
})) || [];
|
||||
|
||||
// Get current page from URL or default to 1
|
||||
@@ -129,18 +128,14 @@ function DynamicColumnTable({
|
||||
<Flex justify="flex-end" align="center" gap={8}>
|
||||
{facingIssueBtn && <LaunchChatSupport {...facingIssueBtn} />}
|
||||
{dynamicColumns && (
|
||||
<Dropdown
|
||||
getPopupContainer={popupContainer}
|
||||
menu={{ items }}
|
||||
trigger={['click']}
|
||||
>
|
||||
<DropdownMenuSimple menu={{ items }}>
|
||||
<Button
|
||||
className="dynamicColumnTable-button filter-btn"
|
||||
size="middle"
|
||||
icon={<SlidersHorizontal size={14} />}
|
||||
data-testid="additional-filters-button"
|
||||
/>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CircleAlert, RefreshCw } from '@signozhq/icons';
|
||||
import { Checkbox, Select } from 'antd';
|
||||
import { Select } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useListRoles } from 'api/generated/services/role';
|
||||
import type { AuthtypesRoleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
@@ -146,12 +147,11 @@ function RolesSelect(props: RolesSelectProps): JSX.Element {
|
||||
options={options}
|
||||
optionFilterProp="label"
|
||||
optionRender={(option): JSX.Element => (
|
||||
<Checkbox
|
||||
checked={value.includes(option.value as string)}
|
||||
style={{ pointerEvents: 'none' }}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
<div style={{ pointerEvents: 'none' }}>
|
||||
<Checkbox value={value.includes(option.value as string)}>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
</div>
|
||||
)}
|
||||
getPopupContainer={getPopupContainer}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Control, UseFormRegister } from 'react-hook-form';
|
||||
import { Controller } from 'react-hook-form';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Input } from '@signozhq/ui/input';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@signozhq/ui/toggle-group';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { DatePicker } from 'antd';
|
||||
import AuthZTooltip from 'components/AuthZTooltip/AuthZTooltip';
|
||||
import {
|
||||
@@ -60,30 +60,21 @@ function KeyFormPhase({
|
||||
name="expiryMode"
|
||||
control={control}
|
||||
render={({ field }): JSX.Element => (
|
||||
<ToggleGroup
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={field.value}
|
||||
onChange={(val): void => {
|
||||
onChange={(val: string): void => {
|
||||
if (val) {
|
||||
field.onChange(val);
|
||||
}
|
||||
}}
|
||||
size="sm"
|
||||
className="add-key-modal__expiry-toggle"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value={ExpiryMode.NONE}
|
||||
className="add-key-modal__expiry-toggle-btn"
|
||||
>
|
||||
No Expiration
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value={ExpiryMode.DATE}
|
||||
className="add-key-modal__expiry-toggle-btn"
|
||||
>
|
||||
Set Expiration Date
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
items={[
|
||||
{ value: ExpiryMode.NONE, label: 'No Expiration' },
|
||||
{ value: ExpiryMode.DATE, label: 'Set Expiration Date' },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { LockKeyhole, Trash2, X } from '@signozhq/icons';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Input } from '@signozhq/ui/input';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@signozhq/ui/toggle-group';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { DatePicker } from 'antd';
|
||||
import type { ServiceaccounttypesGettableFactorAPIKeyDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import AuthZTooltip from 'components/AuthZTooltip/AuthZTooltip';
|
||||
@@ -101,31 +101,22 @@ function EditKeyForm({
|
||||
name="expiryMode"
|
||||
control={control}
|
||||
render={({ field }): JSX.Element => (
|
||||
<ToggleGroup
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={field.value}
|
||||
onChange={(val): void => {
|
||||
onChange={(val: string): void => {
|
||||
if (val && canUpdate) {
|
||||
field.onChange(val);
|
||||
}
|
||||
}}
|
||||
size="sm"
|
||||
disabled={!canUpdate}
|
||||
className="edit-key-modal__expiry-toggle"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value={ExpiryMode.NONE}
|
||||
disabled={!canUpdate}
|
||||
className="edit-key-modal__expiry-toggle-btn"
|
||||
>
|
||||
No Expiration
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value={ExpiryMode.DATE}
|
||||
disabled={!canUpdate}
|
||||
className="edit-key-modal__expiry-toggle-btn"
|
||||
>
|
||||
Set Expiration Date
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
items={[
|
||||
{ value: ExpiryMode.NONE, label: 'No Expiration' },
|
||||
{ value: ExpiryMode.DATE, label: 'Set Expiration Date' },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Key, LayoutGrid, Plus, Trash2, X } from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { DrawerWrapper } from '@signozhq/ui/drawer';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@signozhq/ui/toggle-group';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Pagination, Skeleton } from 'antd';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import {
|
||||
@@ -395,11 +395,11 @@ function ServiceAccountDrawer({
|
||||
const drawerContent = (
|
||||
<div className="sa-drawer__layout">
|
||||
<div className="sa-drawer__tabs">
|
||||
<ToggleGroup
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={activeTab}
|
||||
size="sm"
|
||||
onChange={(val): void => {
|
||||
onChange={(val: string): void => {
|
||||
if (val) {
|
||||
void setActiveTab(val as ServiceAccountDrawerTab);
|
||||
if (val !== ServiceAccountDrawerTab.Keys) {
|
||||
@@ -409,25 +409,30 @@ function ServiceAccountDrawer({
|
||||
}
|
||||
}}
|
||||
className="sa-drawer__tab-group"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value={ServiceAccountDrawerTab.Overview}
|
||||
className="sa-drawer__tab"
|
||||
>
|
||||
<LayoutGrid size={14} />
|
||||
Overview
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value={ServiceAccountDrawerTab.Keys}
|
||||
className="sa-drawer__tab"
|
||||
>
|
||||
<Key size={14} />
|
||||
Keys
|
||||
{keys.length > 0 && (
|
||||
<span className="sa-drawer__tab-count">{keys.length}</span>
|
||||
)}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
items={[
|
||||
{
|
||||
value: ServiceAccountDrawerTab.Overview,
|
||||
label: (
|
||||
<>
|
||||
<LayoutGrid size={14} />
|
||||
Overview
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: ServiceAccountDrawerTab.Keys,
|
||||
label: (
|
||||
<>
|
||||
<Key size={14} />
|
||||
Keys
|
||||
{keys.length > 0 && (
|
||||
<span className="sa-drawer__tab-count">{keys.length}</span>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{activeTab === ServiceAccountDrawerTab.Keys && (
|
||||
<AuthZTooltip
|
||||
checks={[
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
.signoz-radio-group.ant-radio-group {
|
||||
.signoz-radio-group {
|
||||
color: var(--l2-foreground);
|
||||
|
||||
&.ant-radio-group-disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.view-title {
|
||||
display: flex;
|
||||
gap: var(--margin-2);
|
||||
@@ -30,43 +24,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
> button {
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l1-background);
|
||||
|
||||
&:hover {
|
||||
color: var(--l1-foreground);
|
||||
}
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
}
|
||||
|
||||
.selected_view {
|
||||
&,
|
||||
&:hover {
|
||||
background: var(--l3-background);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
&[data-state='on'] {
|
||||
&,
|
||||
&:hover {
|
||||
background: var(--l3-background);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
}
|
||||
&::before {
|
||||
background: var(--l3-background);
|
||||
border-left: 1px solid var(--l1-border);
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
background: var(--l3-background);
|
||||
border-left: 1px solid var(--l1-border);
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-radio-group-disabled {
|
||||
.tab,
|
||||
.selected_view {
|
||||
&[disabled],
|
||||
&[data-disabled] {
|
||||
background: var(--l2-background) !important;
|
||||
border-color: var(--l1-border) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
}
|
||||
|
||||
.tab:hover,
|
||||
.selected_view:hover {
|
||||
background: var(--l2-background) !important;
|
||||
border-color: var(--l1-border) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
&:hover {
|
||||
background: var(--l2-background) !important;
|
||||
border-color: var(--l1-border) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Radio, RadioChangeEvent } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
|
||||
import './SignozRadioGroup.styles.scss';
|
||||
|
||||
@@ -11,7 +11,7 @@ interface Option {
|
||||
interface SignozRadioGroupProps {
|
||||
value: string;
|
||||
options: Option[];
|
||||
onChange: (e: RadioChangeEvent) => void;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
@@ -24,26 +24,22 @@ function SignozRadioGroup({
|
||||
disabled = false,
|
||||
}: SignozRadioGroupProps): JSX.Element {
|
||||
return (
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={value}
|
||||
buttonStyle="solid"
|
||||
className={`signoz-radio-group ${className}`}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<Radio.Button
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={value === option.value ? 'selected_view tab' : 'tab'}
|
||||
>
|
||||
items={options.map((option) => ({
|
||||
value: option.value,
|
||||
label: (
|
||||
<div className="view-title-container">
|
||||
{option.icon && <div className="icon-container">{option.icon}</div>}
|
||||
{option.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
))}
|
||||
</Radio.Group>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,10 @@ import {
|
||||
ButtonProps,
|
||||
Col,
|
||||
ColProps,
|
||||
Divider,
|
||||
DividerProps,
|
||||
Row,
|
||||
RowProps,
|
||||
Space,
|
||||
SpaceProps,
|
||||
TabsProps,
|
||||
} from 'antd';
|
||||
import {
|
||||
Typography,
|
||||
@@ -34,21 +31,11 @@ const StyledRow = styled(Row)<TStyledRow>`
|
||||
${styledClass}
|
||||
`;
|
||||
|
||||
type TStyledDivider = DividerProps & IStyledClass;
|
||||
const StyledDivider = styled(Divider)<TStyledDivider>`
|
||||
${styledClass}
|
||||
`;
|
||||
|
||||
type TStyledSpace = SpaceProps & IStyledClass;
|
||||
const StyledSpace = styled(Space)<TStyledSpace>`
|
||||
${styledClass}
|
||||
`;
|
||||
|
||||
type TStyledTabs = TabsProps & IStyledClass;
|
||||
const StyledTabs = styled(Divider)<TStyledTabs>`
|
||||
${styledClass}
|
||||
`;
|
||||
|
||||
type TStyledButton = ButtonProps & IStyledClass;
|
||||
const StyledButton = styled(Button)<TStyledButton>`
|
||||
${styledClass}
|
||||
@@ -79,9 +66,7 @@ export {
|
||||
StyledButton,
|
||||
StyledCol,
|
||||
StyledDiv,
|
||||
StyledDivider,
|
||||
StyledRow,
|
||||
StyledSpace,
|
||||
StyledTabs,
|
||||
StyledTypography,
|
||||
};
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
import { Tag, Tooltip } from 'antd';
|
||||
import { Tooltip } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
|
||||
import { getLabelRenderingValue } from './utils';
|
||||
|
||||
function TagWithToolTip({
|
||||
function BadgeWithTooltip({
|
||||
label,
|
||||
value,
|
||||
color,
|
||||
}: TagWithToolTipProps): JSX.Element {
|
||||
}: BadgeWithTooltipProps): JSX.Element {
|
||||
const tooltipTitle =
|
||||
value && value[label] ? `${label}: ${value[label]}` : label;
|
||||
return (
|
||||
<div key={label}>
|
||||
<Tooltip title={tooltipTitle}>
|
||||
<Tag className="label-column--tag" color={color}>
|
||||
<Badge className="label-column--tag" color="vanilla">
|
||||
{getLabelRenderingValue(label, value && value[label])}
|
||||
</Tag>
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type TagWithToolTipProps = {
|
||||
type BadgeWithTooltipProps = {
|
||||
label: string;
|
||||
color?: string;
|
||||
value?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
|
||||
TagWithToolTip.defaultProps = {
|
||||
BadgeWithTooltip.defaultProps = {
|
||||
value: undefined,
|
||||
color: undefined,
|
||||
};
|
||||
|
||||
export default TagWithToolTip;
|
||||
export default BadgeWithTooltip;
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Popover, Tag } from 'antd';
|
||||
import { Popover } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
|
||||
import { LabelColumnProps } from './TableRenderer.types';
|
||||
import TagWithToolTip from './TagWithToolTip';
|
||||
import BadgeWithTooltip from './BadgeWithTooltip';
|
||||
import { getLabelAndValueContent } from './utils';
|
||||
|
||||
import './LabelColumn.styles.scss';
|
||||
|
||||
function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element {
|
||||
function LabelColumn({ labels, value }: LabelColumnProps): JSX.Element {
|
||||
const newLabels = labels.length > 3 ? labels.slice(0, 3) : labels;
|
||||
const remainingLabels = labels.length > 3 ? labels.slice(3) : [];
|
||||
|
||||
@@ -14,7 +15,7 @@ function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element {
|
||||
<div className="label-column">
|
||||
{newLabels.map(
|
||||
(label: string): JSX.Element => (
|
||||
<TagWithToolTip key={label} label={label} color={color} value={value} />
|
||||
<BadgeWithTooltip key={label} label={label} value={value} />
|
||||
),
|
||||
)}
|
||||
{remainingLabels.length > 0 && (
|
||||
@@ -26,9 +27,9 @@ function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element {
|
||||
{labels.map(
|
||||
(label: string): JSX.Element => (
|
||||
<div key={label}>
|
||||
<Tag className="label-column--tag" color={color}>
|
||||
<Badge className="label-column--tag" color="vanilla">
|
||||
{getLabelAndValueContent(label, value && value[label])}
|
||||
</Tag>
|
||||
</Badge>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
@@ -36,9 +37,9 @@ function LabelColumn({ labels, value, color }: LabelColumnProps): JSX.Element {
|
||||
}
|
||||
trigger="hover"
|
||||
>
|
||||
<Tag className="label-column--tag" color={color}>
|
||||
<Badge className="label-column--tag" color="vanilla">
|
||||
+{remainingLabels.length}
|
||||
</Tag>
|
||||
</Badge>
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Dispatch, SetStateAction, useCallback, useMemo } from 'react';
|
||||
import { ChevronDown, Globe } from '@signozhq/icons';
|
||||
import { Button, Dropdown } from 'antd';
|
||||
import { DropdownMenuSimple } from '@signozhq/ui/dropdown-menu';
|
||||
import { Button } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import TimeItems, {
|
||||
timePreferance,
|
||||
@@ -27,20 +28,17 @@ function TimePreference({
|
||||
|
||||
const menu = useMemo(
|
||||
() => ({
|
||||
items: menuItems,
|
||||
onClick: timeMenuItemOnChangeHandler,
|
||||
items: menuItems.map((item) => ({
|
||||
...item,
|
||||
onClick: timeMenuItemOnChangeHandler,
|
||||
})),
|
||||
}),
|
||||
[timeMenuItemOnChangeHandler],
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
menu={menu}
|
||||
rootClassName="time-selection-menu"
|
||||
className="time-selection-target"
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button>
|
||||
<DropdownMenuSimple menu={menu} className="time-selection-menu">
|
||||
<Button className="time-selection-target">
|
||||
<div className="button-selected-text">
|
||||
<Globe size={14} />
|
||||
<Typography.Text className="selected-value">
|
||||
@@ -49,7 +47,7 @@ function TimePreference({
|
||||
</div>
|
||||
<ChevronDown size="md" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
DialogSubtitle,
|
||||
DialogTitle,
|
||||
} from '@signozhq/ui/dialog';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@signozhq/ui/toggle-group';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { TooltipSimple } from '@signozhq/ui/tooltip';
|
||||
import type {
|
||||
ApprovalEventDTO,
|
||||
@@ -132,45 +132,43 @@ export default function ApprovalCard({
|
||||
<div className={styles.diffModalBody}>
|
||||
<p className={styles.diffModalSummary}>{approval.summary}</p>
|
||||
<div className={styles.diffToolbarRow}>
|
||||
<ToggleGroup
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
size="sm"
|
||||
value={viewMode}
|
||||
onChange={(next): void => {
|
||||
// Radix `single` group can emit '' when the active item is clicked again.
|
||||
onChange={(next: string): void => {
|
||||
// Radix `single` group can emit '' when the active item
|
||||
// is clicked again — preserve the current mode.
|
||||
if (next === 'split' || next === 'unified') {
|
||||
setViewMode(next);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TooltipSimple title="Split view">
|
||||
<ToggleGroupItem value="split" aria-label="Split view">
|
||||
<Columns2 size={12} />
|
||||
</ToggleGroupItem>
|
||||
</TooltipSimple>
|
||||
<TooltipSimple title="Unified view">
|
||||
<ToggleGroupItem value="unified" aria-label="Unified view">
|
||||
<List size={12} />
|
||||
</ToggleGroupItem>
|
||||
</TooltipSimple>
|
||||
</ToggleGroup>
|
||||
<ToggleGroup
|
||||
items={[
|
||||
{
|
||||
value: 'split',
|
||||
'aria-label': 'Split view',
|
||||
label: <Columns2 size={12} />,
|
||||
},
|
||||
{
|
||||
value: 'unified',
|
||||
'aria-label': 'Unified view',
|
||||
label: <List size={12} />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ToggleGroupSimple
|
||||
type="multiple"
|
||||
size="sm"
|
||||
value={wrapText ? ['wrap'] : []}
|
||||
onChange={(next): void => setWrapText(next.includes('wrap'))}
|
||||
>
|
||||
<TooltipSimple
|
||||
title={wrapText ? 'Disable text wrap' : 'Wrap long lines'}
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="wrap"
|
||||
aria-label={wrapText ? 'Disable text wrap' : 'Wrap long lines'}
|
||||
>
|
||||
<WrapText size={12} />
|
||||
</ToggleGroupItem>
|
||||
</TooltipSimple>
|
||||
</ToggleGroup>
|
||||
onChange={(next: string[]): void => setWrapText(next.includes('wrap'))}
|
||||
items={[
|
||||
{
|
||||
value: 'wrap',
|
||||
'aria-label': wrapText ? 'Disable text wrap' : 'Wrap long lines',
|
||||
label: <WrapText size={12} />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{approval.diff && (
|
||||
<DiffView
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { Checkbox, Radio } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { RadioGroup, RadioGroupItem } from '@signozhq/ui/radio-group';
|
||||
|
||||
import { AIAssistantEvents } from '../../../events';
|
||||
import { useAIAssistantAnalyticsContext } from '../../../hooks/useAIAssistantAnalyticsContext';
|
||||
@@ -81,31 +82,43 @@ export default function InteractiveQuestion({
|
||||
{question && <p className={blockStyles.title}>{question}</p>}
|
||||
|
||||
{type === 'radio' ? (
|
||||
<Radio.Group
|
||||
<RadioGroup
|
||||
className={styles.options}
|
||||
onChange={(e): void => {
|
||||
setSelected([e.target.value]);
|
||||
handleSubmit([e.target.value]);
|
||||
onChange={(value): void => {
|
||||
setSelected([value]);
|
||||
handleSubmit([value]);
|
||||
}}
|
||||
>
|
||||
{normalized.map((opt) => (
|
||||
<Radio key={opt.value} value={opt.value} className={styles.option}>
|
||||
<RadioGroupItem
|
||||
key={opt.value}
|
||||
value={opt.value}
|
||||
className={styles.option}
|
||||
>
|
||||
{opt.label}
|
||||
</Radio>
|
||||
</RadioGroupItem>
|
||||
))}
|
||||
</Radio.Group>
|
||||
</RadioGroup>
|
||||
) : (
|
||||
<>
|
||||
<Checkbox.Group
|
||||
className={cx(styles.options, styles.checkbox)}
|
||||
onChange={(vals): void => setSelected(vals as string[])}
|
||||
>
|
||||
<div className={cx(styles.options, styles.checkbox)}>
|
||||
{normalized.map((opt) => (
|
||||
<Checkbox key={opt.value} value={opt.value} className={styles.option}>
|
||||
<Checkbox
|
||||
key={opt.value}
|
||||
value={selected.includes(opt.value)}
|
||||
onChange={(checked): void => {
|
||||
setSelected((prev) =>
|
||||
checked === true
|
||||
? [...prev, opt.value]
|
||||
: prev.filter((v) => v !== opt.value),
|
||||
);
|
||||
}}
|
||||
className={styles.option}
|
||||
>
|
||||
{opt.label}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Checkbox.Group>
|
||||
</div>
|
||||
<Button
|
||||
variant="solid"
|
||||
size="sm"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Checkbox, Input } from 'antd';
|
||||
import { Input } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
@@ -320,10 +321,8 @@ function AnomalyAlertEvaluationView({
|
||||
{filteredSeriesKeys.length > 0 && (
|
||||
<Checkbox
|
||||
className="anomaly-alert-evaluation-view-series-list-item"
|
||||
type="checkbox"
|
||||
name="series"
|
||||
value="all"
|
||||
checked={selectedSeries === null}
|
||||
value={selectedSeries === null}
|
||||
onChange={(): void => handleSeriesChange(null)}
|
||||
>
|
||||
Show All
|
||||
@@ -335,10 +334,8 @@ function AnomalyAlertEvaluationView({
|
||||
<Checkbox
|
||||
className="anomaly-alert-evaluation-view-series-list-item"
|
||||
key={seriesKey}
|
||||
type="checkbox"
|
||||
name="series"
|
||||
value={seriesKey}
|
||||
checked={selectedSeries === seriesKey}
|
||||
value={selectedSeries === seriesKey}
|
||||
onChange={(): void => handleSeriesChange(seriesKey)}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -161,41 +161,6 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--l1-border);
|
||||
|
||||
.views-tabs {
|
||||
color: var(--l2-foreground);
|
||||
|
||||
.view-title {
|
||||
display: flex;
|
||||
gap: var(--margin-2);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 0 32px;
|
||||
background: var(--l3-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
|
||||
.selected_view {
|
||||
background: none;
|
||||
border: 1px solid var(--l1-border);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.selected_view::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,40 +664,6 @@
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.views-tabs {
|
||||
color: var(--l2-foreground);
|
||||
|
||||
.ant-btn {
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab {
|
||||
border: 1px solid var(--l1-border);
|
||||
width: 114px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l2-background);
|
||||
}
|
||||
|
||||
.selected_view {
|
||||
background: var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.selected_view::before {
|
||||
background: var(--l2-background);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-services-content {
|
||||
|
||||
@@ -2,9 +2,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Spacing } from '@signozhq/design-tokens';
|
||||
import { Button, Divider, Drawer, Radio } from 'antd';
|
||||
import { Button, Drawer } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { RadioChangeEvent } from 'antd/lib';
|
||||
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||
import {
|
||||
CustomTimeType,
|
||||
@@ -55,9 +56,9 @@ function DomainDetails({
|
||||
const [initialFiltersEndPointStats, setInitialFiltersEndPointStats] =
|
||||
useState<IBuilderQuery['filters']>(domainListFilters);
|
||||
|
||||
const handleTabChange = (e: RadioChangeEvent): void => {
|
||||
setSelectedView(e.target.value);
|
||||
setParams({ selectedView: e.target.value });
|
||||
const handleTabChange = (value: string): void => {
|
||||
setSelectedView(value as VIEWS);
|
||||
setParams({ selectedView: value });
|
||||
};
|
||||
|
||||
const handleEndPointChange = (name: string): void => {
|
||||
@@ -224,38 +225,17 @@ function DomainDetails({
|
||||
timeRange={modalTimeRange}
|
||||
/>
|
||||
<div className="views-tabs-container">
|
||||
<Radio.Group
|
||||
className="views-tabs"
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
onChange={handleTabChange}
|
||||
value={selectedView}
|
||||
>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.ALL_ENDPOINTS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.ALL_ENDPOINTS}
|
||||
>
|
||||
<div className="view-title">All Endpoints</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.ENDPOINT_STATS
|
||||
? 'tab selected_view'
|
||||
: 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.ENDPOINT_STATS}
|
||||
>
|
||||
<div className="view-title">Endpoint(s) Stats</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.TOP_ERRORS ? 'tab selected_view' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.TOP_ERRORS}
|
||||
>
|
||||
<div className="view-title">Top 10 Errors</div>
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
size="lg"
|
||||
items={[
|
||||
{ value: VIEW_TYPES.ALL_ENDPOINTS, label: 'All Endpoints' },
|
||||
{ value: VIEW_TYPES.ENDPOINT_STATS, label: 'Endpoint(s) Stats' },
|
||||
{ value: VIEW_TYPES.TOP_ERRORS, label: 'Top 10 Errors' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{selectedView === VIEW_TYPES.ALL_ENDPOINTS && (
|
||||
<AllEndPoints
|
||||
|
||||
@@ -21,14 +21,17 @@ import { useResizeObserver } from 'hooks/useDimensions';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
|
||||
import { LegendPosition } from 'lib/uPlotV2/components/types';
|
||||
import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import ErrorState from './ErrorState';
|
||||
import { prepareStatusCodeBarChartsConfig } from './utils';
|
||||
import {
|
||||
getStepIntervalForQuery,
|
||||
getTracesTimeRangeFromStepInterval,
|
||||
prepareStatusCodeBarChartsConfig,
|
||||
} from './utils';
|
||||
|
||||
function StatusCodeBarCharts({
|
||||
endPointStatusCodeBarChartsDataQuery,
|
||||
@@ -135,6 +138,18 @@ function StatusCodeBarCharts({
|
||||
[domainName, filters],
|
||||
);
|
||||
|
||||
const activeApiResponse = useMemo(
|
||||
() =>
|
||||
currentWidgetInfoIndex === 0
|
||||
? formattedEndPointStatusCodeBarChartsDataPayload
|
||||
: formattedEndPointStatusCodeLatencyBarChartsDataPayload,
|
||||
[
|
||||
currentWidgetInfoIndex,
|
||||
formattedEndPointStatusCodeBarChartsDataPayload,
|
||||
formattedEndPointStatusCodeLatencyBarChartsDataPayload,
|
||||
],
|
||||
);
|
||||
|
||||
const graphClickHandler = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
@@ -144,11 +159,14 @@ function StatusCodeBarCharts({
|
||||
metric?: { [key: string]: string },
|
||||
queryData?: { queryName: string; inFocusOrNot: boolean },
|
||||
): void => {
|
||||
const TWO_AND_HALF_MINUTES_IN_MILLISECONDS = 2.5 * 60 * 1000; // 150,000 milliseconds
|
||||
const customFilters = getCustomFiltersForBarChart(metric);
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(
|
||||
const stepInterval = getStepIntervalForQuery(
|
||||
activeApiResponse,
|
||||
queryData?.queryName,
|
||||
);
|
||||
const { start, end } = getTracesTimeRangeFromStepInterval(
|
||||
xValue,
|
||||
TWO_AND_HALF_MINUTES_IN_MILLISECONDS,
|
||||
stepInterval,
|
||||
);
|
||||
|
||||
handleGraphClick({
|
||||
@@ -171,6 +189,7 @@ function StatusCodeBarCharts({
|
||||
});
|
||||
},
|
||||
[
|
||||
activeApiResponse,
|
||||
widget,
|
||||
navigateToExplorerPages,
|
||||
navigateToExplorer,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
getMinStepIntervalFromApiResponse,
|
||||
getStepIntervalForQuery,
|
||||
getTracesTimeRangeFromStepInterval,
|
||||
} from '../utils';
|
||||
|
||||
describe('StatusCodeBarCharts utils', () => {
|
||||
describe('getTracesTimeRangeFromStepInterval', () => {
|
||||
const xValue = 1609459200; // seconds
|
||||
|
||||
it('keeps start at click time with a minimum 5 minute end range', () => {
|
||||
const { start, end } = getTracesTimeRangeFromStepInterval(xValue, 60);
|
||||
|
||||
expect(start).toBe(xValue * 1000);
|
||||
expect(end - start).toBe(5 * 60 * 1000);
|
||||
expect(end).toBe(xValue * 1000 + 5 * 60 * 1000);
|
||||
});
|
||||
|
||||
it('extends end when step interval is larger than 5 minutes', () => {
|
||||
const stepInterval = 600; // 10 minutes
|
||||
const { start, end } = getTracesTimeRangeFromStepInterval(
|
||||
xValue,
|
||||
stepInterval,
|
||||
);
|
||||
|
||||
expect(start).toBe(xValue * 1000);
|
||||
expect(end - start).toBe(10 * 60 * 1000);
|
||||
expect(end).toBe(xValue * 1000 + 10 * 60 * 1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMinStepIntervalFromApiResponse', () => {
|
||||
it('returns 60 when step intervals are missing', () => {
|
||||
expect(getMinStepIntervalFromApiResponse({} as any)).toBe(60);
|
||||
});
|
||||
|
||||
it('returns the minimum step interval from the response', () => {
|
||||
const apiResponse = {
|
||||
data: {
|
||||
newResult: {
|
||||
meta: {
|
||||
stepIntervals: { A: 120, B: 60 },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(getMinStepIntervalFromApiResponse(apiResponse as any)).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStepIntervalForQuery', () => {
|
||||
it('returns query-specific step interval when available', () => {
|
||||
const apiResponse = {
|
||||
data: {
|
||||
newResult: {
|
||||
meta: {
|
||||
stepIntervals: { A: 120, B: 60 },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(getStepIntervalForQuery(apiResponse as any, 'A')).toBe(120);
|
||||
expect(getStepIntervalForQuery(apiResponse as any, 'B')).toBe(60);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,65 @@ import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { QueryData } from 'types/api/widgets/getQuery';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
const DEFAULT_STEP_INTERVAL_SECONDS = 60;
|
||||
const MIN_TRACES_TIME_RANGE_MINUTES = 5;
|
||||
|
||||
export function getMinStepIntervalFromApiResponse(
|
||||
apiResponse: MetricRangePayloadProps,
|
||||
): number {
|
||||
const stepIntervals: ExecStats['stepIntervals'] = get(
|
||||
apiResponse,
|
||||
'data.newResult.meta.stepIntervals',
|
||||
{},
|
||||
);
|
||||
const values = Object.values(stepIntervals).filter(
|
||||
(value): value is number =>
|
||||
typeof value === 'number' && Number.isFinite(value),
|
||||
);
|
||||
|
||||
if (values.length === 0) {
|
||||
return DEFAULT_STEP_INTERVAL_SECONDS;
|
||||
}
|
||||
|
||||
return Math.min(...values);
|
||||
}
|
||||
|
||||
export function getStepIntervalForQuery(
|
||||
apiResponse: MetricRangePayloadProps,
|
||||
queryName?: string,
|
||||
): number {
|
||||
const minStepInterval = getMinStepIntervalFromApiResponse(apiResponse);
|
||||
|
||||
if (!queryName) {
|
||||
return minStepInterval;
|
||||
}
|
||||
|
||||
const stepIntervals: ExecStats['stepIntervals'] = get(
|
||||
apiResponse,
|
||||
'data.newResult.meta.stepIntervals',
|
||||
{},
|
||||
);
|
||||
|
||||
return get(stepIntervals, queryName, minStepInterval) ?? minStepInterval;
|
||||
}
|
||||
|
||||
export function getTracesTimeRangeFromStepInterval(
|
||||
xValue: number,
|
||||
stepIntervalSeconds: number,
|
||||
): { start: number; end: number } {
|
||||
const rangeMinutes = Math.max(
|
||||
stepIntervalSeconds / 60,
|
||||
MIN_TRACES_TIME_RANGE_MINUTES,
|
||||
);
|
||||
const rangeMs = rangeMinutes * 60 * 1000;
|
||||
const start = Math.floor(xValue * 1000);
|
||||
|
||||
return {
|
||||
start,
|
||||
end: Math.ceil(start + rangeMs),
|
||||
};
|
||||
}
|
||||
|
||||
export const prepareStatusCodeBarChartsConfig = ({
|
||||
timezone,
|
||||
isDarkMode,
|
||||
@@ -41,7 +100,7 @@ export const prepareStatusCodeBarChartsConfig = ({
|
||||
'data.newResult.meta.stepIntervals',
|
||||
{},
|
||||
);
|
||||
const minStepInterval = Math.min(...Object.values(stepIntervals));
|
||||
const minStepInterval = getMinStepIntervalFromApiResponse(apiResponse);
|
||||
|
||||
const config = buildBaseConfig({
|
||||
id: v4(),
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { TableColumnType as ColumnType, Tag, Tooltip } from 'antd';
|
||||
import { TableColumnType as ColumnType, Tooltip } from 'antd';
|
||||
import { Progress } from '@signozhq/ui/progress';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { convertFiltersToExpressionWithExistingQuery } from 'components/QueryBuilderV2/utils';
|
||||
import {
|
||||
FiltersType,
|
||||
@@ -972,13 +973,9 @@ export const getEndPointsColumnsConfig = (
|
||||
})()}
|
||||
{isGroupedByAttribute
|
||||
? text.split(',').map((value) => (
|
||||
<Tag
|
||||
key={value}
|
||||
color={Color.BG_SLATE_100}
|
||||
className="endpoint-group-tag-item"
|
||||
>
|
||||
<Badge key={value} color="vanilla" className="endpoint-group-tag-item">
|
||||
{value === '' ? '<no-value>' : value}
|
||||
</Tag>
|
||||
</Badge>
|
||||
))
|
||||
: endPointName}
|
||||
</div>
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
Skeleton,
|
||||
Table,
|
||||
TableColumnsType as ColumnsType,
|
||||
Tag,
|
||||
} from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import getUsage, { UsageResponsePayloadProps } from 'api/billing/getUsage';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import updateCreditCardApi from 'api/v1/checkout/create';
|
||||
@@ -434,7 +434,7 @@ export default function BillingContainer(): JSX.Element {
|
||||
<Flex vertical>
|
||||
<Typography.Title level={5} style={{ marginTop: 2, fontWeight: 500 }}>
|
||||
{isCloudUserVal ? t('teams_cloud') : t('teams')}{' '}
|
||||
{isFreeTrial ? <Tag color="success"> Free Trial </Tag> : ''}
|
||||
{isFreeTrial ? <Badge color="success"> Free Trial </Badge> : ''}
|
||||
</Typography.Title>
|
||||
|
||||
{!isLoading && !isFetchingBillingData && !showGracePeriodMessage ? (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Row, Tag } from 'antd';
|
||||
import { Row } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
||||
@@ -66,13 +67,7 @@ function SelectAlertType({ onSelect }: SelectAlertTypeProps): JSX.Element {
|
||||
<AlertTypeCard
|
||||
key={option.selection}
|
||||
title={option.title}
|
||||
extra={
|
||||
option.isBeta ? (
|
||||
<Tag bordered={false} color="geekblue">
|
||||
Beta
|
||||
</Tag>
|
||||
) : undefined
|
||||
}
|
||||
extra={option.isBeta ? <Badge color="robin">Beta</Badge> : undefined}
|
||||
onClick={(e): void => {
|
||||
onSelect(option.selection, isModifierKeyPressed(e));
|
||||
}}
|
||||
|
||||
@@ -11,8 +11,13 @@ import {
|
||||
} from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Callout } from '@signozhq/ui/callout';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@signozhq/ui/dropdown-menu';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { Dropdown, Skeleton } from 'antd';
|
||||
import { Skeleton } from 'antd';
|
||||
import {
|
||||
RenderErrorResponseDTO,
|
||||
ZeustypesHostDTO,
|
||||
@@ -200,10 +205,15 @@ export default function CustomDomainSettings(): JSX.Element {
|
||||
!workspaceName ? 'workspace-name-hidden' : ''
|
||||
}`}
|
||||
>
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
disabled={isFetchingHosts}
|
||||
dropdownRender={(): JSX.Element => (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="link" color="none" disabled={isFetchingHosts}>
|
||||
<Link2 size={12} />
|
||||
<span>{stripProtocol(activeHost?.url ?? '')}</span>
|
||||
<ChevronDown size={12} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<div className="workspace-url-dropdown">
|
||||
<span className="workspace-url-dropdown-header">
|
||||
All Workspace URLs
|
||||
@@ -236,14 +246,8 @@ export default function CustomDomainSettings(): JSX.Element {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<Button variant="link" color="none">
|
||||
<Link2 size={12} />
|
||||
<span>{stripProtocol(activeHost?.url ?? '')}</span>
|
||||
<ChevronDown size={12} />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span className="custom-domain-card-meta-timezone">
|
||||
<Clock size={11} />
|
||||
{timezone.offset}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { GetHosts200 } from 'api/generated/services/sigNoz.schemas';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { rest, server } from 'mocks-server/server';
|
||||
import { fireEvent, render, screen, waitFor } from 'tests/test-utils';
|
||||
|
||||
@@ -142,12 +143,13 @@ describe('CustomDomainSettings', () => {
|
||||
});
|
||||
|
||||
it('shows all workspace URLs as links in the dropdown', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
render(<CustomDomainSettings />);
|
||||
|
||||
await screen.findByText(/custom-host\.test\.cloud/i);
|
||||
|
||||
// Open the URL dropdown
|
||||
fireEvent.click(
|
||||
await user.click(
|
||||
screen.getByRole('button', { name: /custom-host\.test\.cloud/i }),
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
Plus,
|
||||
X,
|
||||
} from '@signozhq/icons';
|
||||
import { Button, Card, Input, Modal, Popover, Tag, Tooltip } from 'antd';
|
||||
import { Button, Card, Input, Modal, Popover, Tooltip } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';
|
||||
@@ -506,9 +507,9 @@ function DashboardDescription(props: DashboardDescriptionProps): JSX.Element {
|
||||
{(tags?.length || 0) > 0 && (
|
||||
<div className="dashboard-tags">
|
||||
{tags?.map((tag) => (
|
||||
<Tag key={tag} className="tag">
|
||||
<Badge key={tag} className="tag" color="vanilla">
|
||||
{tag}
|
||||
</Tag>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -359,7 +359,7 @@
|
||||
flex-flow: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.ant-tag {
|
||||
[data-slot='badge'] {
|
||||
height: 30px;
|
||||
color: var(--l1-foreground);
|
||||
font-family: 'Space Mono';
|
||||
|
||||
@@ -5,7 +5,8 @@ import { useQuery } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { orange } from '@ant-design/colors';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Collapse, Input, Select, Tag } from 'antd';
|
||||
import { Button, Collapse, Input, Select } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import dashboardVariablesQuery from 'api/dashboard/variables/dashboardVariablesQuery';
|
||||
@@ -542,9 +543,9 @@ function VariableItem({
|
||||
}}
|
||||
>
|
||||
Dynamic
|
||||
<Tag bordered={false} className="sidenav-beta-tag" color="geekblue">
|
||||
<Badge color="robin" className="sidenav-beta-tag">
|
||||
Beta
|
||||
</Tag>
|
||||
</Badge>
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
@@ -599,9 +600,9 @@ function VariableItem({
|
||||
}}
|
||||
>
|
||||
Query
|
||||
<Tag bordered={false} className="sidenav-beta-tag" color="warning">
|
||||
<Badge color="amber" className="sidenav-beta-tag">
|
||||
Not Recommended
|
||||
</Tag>
|
||||
</Badge>
|
||||
<div onClick={(e): void => e.stopPropagation()}>
|
||||
<TextToolTip
|
||||
text="Learn why we don't recommend"
|
||||
@@ -733,7 +734,9 @@ function VariableItem({
|
||||
<Typography style={{ color: orange[5] }}>{errorPreview}</Typography>
|
||||
) : (
|
||||
map(previewValues, (value, idx) => (
|
||||
<Tag key={`${value}${idx}`}>{value.toString()}</Tag>
|
||||
<Badge key={`${value}${idx}`} color="vanilla">
|
||||
{value.toString()}
|
||||
</Badge>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,38 @@
|
||||
.tags-input {
|
||||
.badgesContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-flow: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.badgeContainer {
|
||||
color: var(--bg-sienna-400);
|
||||
font-family: 'Space Mono';
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0.52px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50px;
|
||||
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
|
||||
padding: 2px 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.inputContainer {
|
||||
> div {
|
||||
margin: 0;
|
||||
}
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
|
||||
.tagsInput {
|
||||
display: flex;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
@@ -8,23 +42,7 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tag-container {
|
||||
color: var(--bg-sienna-400);
|
||||
font-family: 'Space Mono';
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px; /* 153.846% */
|
||||
letter-spacing: 0.52px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50px;
|
||||
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.edit-input {
|
||||
.editInput {
|
||||
.ant-form-item {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import { Col, Tooltip } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import Input from 'components/Input';
|
||||
|
||||
import { InputContainer, NewTagContainer, TagsContainer } from './styles';
|
||||
|
||||
import './AddTags.styles.scss';
|
||||
import styles from './AddBadges.module.scss';
|
||||
|
||||
function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
const [inputValue, setInputValue] = useState<string>('');
|
||||
@@ -39,11 +38,11 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
};
|
||||
|
||||
return (
|
||||
<TagsContainer>
|
||||
<div className={styles.badgesContainer}>
|
||||
{tags.map((tag, index) => {
|
||||
if (editInputIndex === index) {
|
||||
return (
|
||||
<Col key={tag} lg={4} className="edit-input">
|
||||
<Col key={tag} lg={4} className={styles.editInput}>
|
||||
<Input
|
||||
size="small"
|
||||
value={editInputValue}
|
||||
@@ -60,11 +59,15 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
const isLongTag = tag.length > 20;
|
||||
|
||||
const tagElem = (
|
||||
<NewTagContainer
|
||||
closable
|
||||
<Badge
|
||||
key={tag}
|
||||
onClose={(): void => handleClose(tag)}
|
||||
className="tag-container"
|
||||
color="vanilla"
|
||||
className={styles.badgeContainer}
|
||||
closable
|
||||
onClose={(e): void => {
|
||||
e.preventDefault();
|
||||
handleClose(tag);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
onDoubleClick={(e): void => {
|
||||
@@ -75,7 +78,7 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
>
|
||||
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||
</span>
|
||||
</NewTagContainer>
|
||||
</Badge>
|
||||
);
|
||||
|
||||
return isLongTag ? (
|
||||
@@ -87,11 +90,11 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
);
|
||||
})}
|
||||
|
||||
<InputContainer>
|
||||
<Col className={styles.inputContainer}>
|
||||
<Input
|
||||
type="text"
|
||||
value={inputValue}
|
||||
rootClassName="tags-input"
|
||||
rootClassName={styles.tagsInput}
|
||||
placeholder="Start typing your tag name"
|
||||
onChangeHandler={(event): void =>
|
||||
onChangeHandler(event.target.value, setInputValue)
|
||||
@@ -99,8 +102,8 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||
onBlurHandler={handleInputConfirm}
|
||||
onPressEnterHandler={handleInputConfirm}
|
||||
/>
|
||||
</InputContainer>
|
||||
</TagsContainer>
|
||||
</Col>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Col, Tag } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const TagsContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-flow: wrap;
|
||||
gap: 6px;
|
||||
`;
|
||||
|
||||
export const NewTagContainer = styled(Tag)`
|
||||
&&& {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
svg {
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const InputContainer = styled(Col)`
|
||||
> div {
|
||||
margin: 0;
|
||||
}
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
`;
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Col, Input, Radio, Select, Space, Tooltip } from 'antd';
|
||||
import { Col, Input, Select, Space, Tooltip } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import AddTags from 'container/DashboardContainer/DashboardSettings/General/AddTags';
|
||||
import AddTags from 'container/DashboardContainer/DashboardSettings/General/AddBadges';
|
||||
import { useDashboardCursorSyncMode } from 'hooks/dashboard/useDashboardCursorSyncMode';
|
||||
import { useSyncTooltipFilterMode } from 'hooks/dashboard/useSyncTooltipFilterMode';
|
||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||
@@ -213,18 +214,18 @@ function GeneralDashboardSettings(): JSX.Element {
|
||||
Sync crosshair and tooltip across all the dashboard panels
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={cursorSyncMode}
|
||||
onChange={(e): void => {
|
||||
setCursorSyncMode(e.target.value as DashboardCursorSync);
|
||||
onChange={(value: string): void => {
|
||||
setCursorSyncMode(value as DashboardCursorSync);
|
||||
}}
|
||||
>
|
||||
<Radio.Button value={DashboardCursorSync.None}>No Sync</Radio.Button>
|
||||
<Radio.Button value={DashboardCursorSync.Crosshair}>
|
||||
Crosshair
|
||||
</Radio.Button>
|
||||
<Radio.Button value={DashboardCursorSync.Tooltip}>Tooltip</Radio.Button>
|
||||
</Radio.Group>
|
||||
items={[
|
||||
{ value: DashboardCursorSync.None, label: 'No Sync' },
|
||||
{ value: DashboardCursorSync.Crosshair, label: 'Crosshair' },
|
||||
{ value: DashboardCursorSync.Tooltip, label: 'Tooltip' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{cursorSyncMode === DashboardCursorSync.Tooltip && (
|
||||
<div className={styles.crossPanelSyncRow}>
|
||||
@@ -237,21 +238,21 @@ function GeneralDashboardSettings(): JSX.Element {
|
||||
matching ones highlighted
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
value={syncTooltipFilterMode}
|
||||
onChange={(e): void => {
|
||||
onChange={(value: string): void => {
|
||||
logEvent(Events.TOOLTIP_SYNC_MODE_CHANGED, {
|
||||
path: getAbsoluteUrl(window.location.pathname),
|
||||
mode: e.target.value,
|
||||
mode: value,
|
||||
});
|
||||
setSyncTooltipFilterMode(e.target.value as SyncTooltipFilterMode);
|
||||
setSyncTooltipFilterMode(value as SyncTooltipFilterMode);
|
||||
}}
|
||||
>
|
||||
<Radio.Button value={SyncTooltipFilterMode.All}>All</Radio.Button>
|
||||
<Radio.Button value={SyncTooltipFilterMode.Filtered}>
|
||||
Filtered
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
items={[
|
||||
{ value: SyncTooltipFilterMode.All, label: 'All' },
|
||||
{ value: SyncTooltipFilterMode.Filtered, label: 'Filtered' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
|
||||
@@ -395,8 +395,8 @@ describe('Dynamic Variable Default Behavior', () => {
|
||||
|
||||
// Check if the checkbox exists (it should be unchecked initially)
|
||||
const checkbox = allOptionContainer?.querySelector(
|
||||
'input[type="checkbox"]',
|
||||
) as HTMLInputElement;
|
||||
'[role="checkbox"]',
|
||||
) as HTMLElement;
|
||||
expect(checkbox).toBeInTheDocument();
|
||||
|
||||
// Should call onValueUpdate with all values (ALL selection)
|
||||
@@ -516,10 +516,10 @@ describe('Dynamic Variable Default Behavior', () => {
|
||||
|
||||
// Check if the checkbox for ALL option is checked
|
||||
const checkbox = dropdownAllOption.querySelector(
|
||||
'input[type="checkbox"]',
|
||||
) as HTMLInputElement;
|
||||
'[role="checkbox"]',
|
||||
) as HTMLElement;
|
||||
expect(checkbox).toBeInTheDocument();
|
||||
expect(checkbox.checked).toBe(true);
|
||||
expect(checkbox).toHaveAttribute('data-state', 'checked');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -196,10 +196,10 @@ describe('Panel Management Tests', () => {
|
||||
expect(allOption).toHaveClass('selected');
|
||||
|
||||
const allCheckbox = allOption.querySelector(
|
||||
'input[type="checkbox"]',
|
||||
) as HTMLInputElement;
|
||||
'[role="checkbox"]',
|
||||
) as HTMLElement;
|
||||
expect(allCheckbox).toBeInTheDocument();
|
||||
expect(allCheckbox.checked).toBe(true);
|
||||
expect(allCheckbox).toHaveAttribute('data-state', 'checked');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -160,8 +160,8 @@ describe('getChartManagerColumns', () => {
|
||||
expect(renderFn).toBeDefined();
|
||||
const { container } = render(renderFn!(null, tableDataSet[1], 1));
|
||||
|
||||
const checkbox = container.querySelector('input[type="checkbox"]');
|
||||
const checkbox = container.querySelector('[role="checkbox"]');
|
||||
expect(checkbox).toBeInTheDocument();
|
||||
expect(checkbox).toBeChecked(); // graphVisibilityState[1] is true
|
||||
expect(checkbox).toHaveAttribute('data-state', 'checked'); // graphVisibilityState[1] is true
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { CloudDownload } from '@signozhq/icons';
|
||||
import { Button, Dropdown, MenuProps, Flex } from 'antd';
|
||||
import { DropdownMenuSimple, type MenuProps } from '@signozhq/ui/dropdown-menu';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { unparse } from 'papaparse';
|
||||
|
||||
import { DownloadProps } from './Download.types';
|
||||
@@ -67,7 +68,7 @@ function Download({ data, isLoading, fileName }: DownloadProps): JSX.Element {
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropdown menu={menu} trigger={['click']}>
|
||||
<DropdownMenuSimple menu={menu}>
|
||||
<Button
|
||||
className="download-button"
|
||||
loading={isLoading || isDownloading}
|
||||
@@ -79,7 +80,7 @@ function Download({ data, isLoading, fileName }: DownloadProps): JSX.Element {
|
||||
Download
|
||||
</Flex>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Button, Divider, Space } from 'antd';
|
||||
import { Button, Space } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import getNextPrevId from 'api/errors/getNextPrevId';
|
||||
|
||||
@@ -22,13 +22,13 @@ import { Color } from '@signozhq/design-tokens';
|
||||
import {
|
||||
Button,
|
||||
ColorPicker,
|
||||
Divider,
|
||||
Input,
|
||||
Modal,
|
||||
RefSelectProps,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { QueryChipContainer, QueryChipItem } from './styles';
|
||||
import { ILabelRecord } from './types';
|
||||
|
||||
interface QueryChipProps {
|
||||
queryData: ILabelRecord;
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
export default function QueryChip({
|
||||
queryData,
|
||||
onRemove,
|
||||
}: QueryChipProps): JSX.Element {
|
||||
const { key, value } = queryData;
|
||||
return (
|
||||
<QueryChipContainer>
|
||||
<QueryChipItem
|
||||
closable={key !== 'severity' && key !== 'description'}
|
||||
onClose={(): void => onRemove(key)}
|
||||
>
|
||||
{key}: {value}
|
||||
</QueryChipItem>
|
||||
</QueryChipContainer>
|
||||
);
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import { map } from 'lodash-es';
|
||||
import { Labels } from 'types/api/alerts/def';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import QueryChip from './QueryChip';
|
||||
import { QueryChipItem, SearchContainer } from './styles';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { QueryChipContainer, QueryChipItem, SearchContainer } from './styles';
|
||||
import { ILabelRecord } from './types';
|
||||
import { createQuery, flattenLabels, prepareLabels } from './utils';
|
||||
|
||||
@@ -147,12 +147,24 @@ function LabelSelect({
|
||||
<SearchContainer isDarkMode={isDarkMode} disabled={false}>
|
||||
<div style={{ display: 'inline-flex', flexWrap: 'wrap' }}>
|
||||
{queries.length > 0 &&
|
||||
map(
|
||||
queries,
|
||||
(query): JSX.Element => (
|
||||
<QueryChip key={query.key} queryData={query} onRemove={handleClose} />
|
||||
),
|
||||
)}
|
||||
map(queries, (query): JSX.Element => {
|
||||
const isClosable =
|
||||
query.key !== 'severity' && query.key !== 'description';
|
||||
return (
|
||||
<QueryChipContainer key={query.key}>
|
||||
<Badge
|
||||
color="vanilla"
|
||||
closable={isClosable}
|
||||
onClose={(e): void => {
|
||||
e.preventDefault();
|
||||
handleClose(query.key);
|
||||
}}
|
||||
>
|
||||
{query.key}: {query.value}
|
||||
</Badge>
|
||||
</QueryChipContainer>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{map(staging, (item) => (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { grey } from '@ant-design/colors';
|
||||
import { Tag } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface SearchContainerProps {
|
||||
@@ -27,8 +27,11 @@ export const QueryChipContainer = styled.span`
|
||||
background: ${grey.primary}44;
|
||||
}
|
||||
}
|
||||
[data-slot='badge'] {
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
`;
|
||||
|
||||
export const QueryChipItem = styled(Tag)`
|
||||
export const QueryChipItem = styled(Badge)`
|
||||
margin-right: 0.1rem;
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
Col,
|
||||
Dropdown as DropDownComponent,
|
||||
Input as InputComponent,
|
||||
} from 'antd';
|
||||
import { Col, Input as InputComponent } from 'antd';
|
||||
import { Typography as TypographyComponent } from '@signozhq/ui/typography';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -34,16 +30,6 @@ export const ButtonContainer = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
export const Dropdown = styled(DropDownComponent)`
|
||||
&&& {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 150px;
|
||||
min-width: 150px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const TextContainer = styled.div`
|
||||
&&& {
|
||||
min-width: 100px;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { grey } from '@ant-design/colors';
|
||||
import { Checkbox, ConfigProvider } from 'antd';
|
||||
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
import { CheckBoxProps } from '../types';
|
||||
|
||||
@@ -11,30 +11,22 @@ function CustomCheckBox({
|
||||
checkBoxOnChangeHandler,
|
||||
disabled = false,
|
||||
}: CheckBoxProps): JSX.Element {
|
||||
const onChangeHandler = (e: CheckboxChangeEvent): void => {
|
||||
checkBoxOnChangeHandler(e, index);
|
||||
};
|
||||
|
||||
const color = data[index]?.stroke?.toString() || grey[0];
|
||||
|
||||
const isChecked = graphVisibilityState[index] || false;
|
||||
|
||||
const colorStyle = {
|
||||
'--checkbox-checked-background': color,
|
||||
'--checkbox-border-color': color,
|
||||
} as CSSProperties;
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: color,
|
||||
colorBorder: color,
|
||||
colorBgContainer: color,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<span style={colorStyle}>
|
||||
<Checkbox
|
||||
onChange={onChangeHandler}
|
||||
checked={isChecked}
|
||||
onChange={(checked): void => checkBoxOnChangeHandler(checked, index)}
|
||||
value={isChecked}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Dispatch, MutableRefObject, RefObject, SetStateAction } from 'react';
|
||||
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
|
||||
import { ToggleGraphProps } from 'components/Graph/types';
|
||||
import { UplotProps } from 'components/Uplot/Uplot';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
@@ -77,7 +76,10 @@ export interface CheckBoxProps {
|
||||
data: ExtendedChartDataset[];
|
||||
index: number;
|
||||
graphVisibilityState: boolean[];
|
||||
checkBoxOnChangeHandler: (e: CheckboxChangeEvent, index: number) => void;
|
||||
checkBoxOnChangeHandler: (
|
||||
checked: boolean | 'indeterminate',
|
||||
index: number,
|
||||
) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Provider } from 'react-redux';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { AppProvider } from 'providers/App/App';
|
||||
@@ -176,6 +177,7 @@ jest.mock('providers/Dashboard/store/useDashboardStore', () => ({
|
||||
|
||||
describe('WidgetGraphComponent', () => {
|
||||
it('should show correct menu items when hovering over more options while loading', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
const { getByTestId, findByRole, getByText, container } = render(
|
||||
<MockQueryClientProvider>
|
||||
<ErrorModalProvider>
|
||||
@@ -208,7 +210,7 @@ describe('WidgetGraphComponent', () => {
|
||||
expect(skeleton).toBeInTheDocument();
|
||||
|
||||
const moreOptionsButton = getByTestId('widget-header-options');
|
||||
fireEvent.mouseEnter(moreOptionsButton);
|
||||
await user.click(moreOptionsButton);
|
||||
|
||||
const menu = await findByRole('menu');
|
||||
expect(menu).toBeInTheDocument();
|
||||
|
||||
@@ -54,6 +54,17 @@
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
// currently the width of the dropdown menu is set to 100% of the parent container,
|
||||
// which is not desired. This is a workaround to unset that width and allow the dropdown menu to size based on its content.
|
||||
// This is necessary because the dropdown menu can contain items with varying widths, and setting it to 100% can cause layout issues and make the menu look unbalanced.
|
||||
// we should idealy fix this in the dropdown menu component itself, but for now this is a quick fix to ensure the dropdown menu looks correct in the widget header.
|
||||
|
||||
[data-radix-popper-content-wrapper]
|
||||
[data-slot='dropdown-menu-content'].widget-header-dropdown
|
||||
[data-slot='dropdown-menu-item'] {
|
||||
width: unset !important;
|
||||
}
|
||||
|
||||
.widget-api-actions {
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
@@ -467,6 +467,7 @@ describe('WidgetHeader', () => {
|
||||
|
||||
describe('Create Alerts Menu Item', () => {
|
||||
it('renders Create Alerts menu item with external link icon when included in headerMenuList', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
render(
|
||||
<WidgetHeader
|
||||
title={TEST_WIDGET_TITLE}
|
||||
@@ -483,7 +484,7 @@ describe('WidgetHeader', () => {
|
||||
|
||||
const moreOptionsIcon = await screen.findByTestId(WIDGET_HEADER_OPTIONS_ID);
|
||||
expect(moreOptionsIcon).toBeInTheDocument();
|
||||
await userEvent.hover(moreOptionsIcon);
|
||||
await user.click(moreOptionsIcon);
|
||||
|
||||
await screen.findByText(CREATE_ALERTS_TEXT);
|
||||
|
||||
@@ -494,6 +495,7 @@ describe('WidgetHeader', () => {
|
||||
});
|
||||
|
||||
it('Create Alerts menu item is enabled and clickable', async () => {
|
||||
const user = userEvent.setup({ pointerEventsCheck: 0 });
|
||||
const mockCreateAlertsHandler = jest.fn();
|
||||
const useCreateAlerts = jest.requireMock(
|
||||
'hooks/queryBuilder/useCreateAlerts',
|
||||
@@ -517,12 +519,12 @@ describe('WidgetHeader', () => {
|
||||
expect(useCreateAlerts).toHaveBeenCalledWith(mockWidget, 'dashboardView');
|
||||
|
||||
const moreOptionsIcon = await screen.findByTestId(WIDGET_HEADER_OPTIONS_ID);
|
||||
await userEvent.hover(moreOptionsIcon);
|
||||
await user.click(moreOptionsIcon);
|
||||
|
||||
const createAlertsMenuItem = await screen.findByText(CREATE_ALERTS_TEXT);
|
||||
|
||||
// Verify the menu item is clickable by actually clicking it
|
||||
await userEvent.click(createAlertsMenuItem);
|
||||
await user.click(createAlertsMenuItem);
|
||||
expect(mockCreateAlertsHandler).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,8 @@ import {
|
||||
X,
|
||||
} from '@signozhq/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Dropdown, Input, MenuProps, Tooltip } from 'antd';
|
||||
import { Button, Input, Tooltip } from 'antd';
|
||||
import { DropdownMenuSimple } from '@signozhq/ui/dropdown-menu';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import ErrorContent from 'components/ErrorModal/components/ErrorContent';
|
||||
import ErrorPopover from 'components/ErrorPopover/ErrorPopover';
|
||||
@@ -128,7 +129,7 @@ function WidgetHeader({
|
||||
],
|
||||
);
|
||||
|
||||
const onMenuItemSelectHandler: MenuProps['onClick'] = useCallback(
|
||||
const onMenuItemSelectHandler = useCallback(
|
||||
({ key }: { key: string }): void => {
|
||||
if (isTWidgetOptions(key)) {
|
||||
const functionToCall = keyMethodMapping[key];
|
||||
@@ -188,18 +189,8 @@ function WidgetHeader({
|
||||
{
|
||||
key: MenuItemKeys.CreateAlerts,
|
||||
icon: <Bell size="md" />,
|
||||
label: (
|
||||
<span
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{MENUITEM_KEYS_VS_LABELS[MenuItemKeys.CreateAlerts]}
|
||||
<SquareArrowOutUpRight size={10} />
|
||||
</span>
|
||||
),
|
||||
label: MENUITEM_KEYS_VS_LABELS[MenuItemKeys.CreateAlerts],
|
||||
rightIcon: <SquareArrowOutUpRight size="lg" />,
|
||||
isVisible: headerMenuList?.includes(MenuItemKeys.CreateAlerts) || false,
|
||||
disabled: false,
|
||||
},
|
||||
@@ -221,8 +212,10 @@ function WidgetHeader({
|
||||
|
||||
const menu = useMemo(
|
||||
() => ({
|
||||
items: updatedMenuList,
|
||||
onClick: onMenuItemSelectHandler,
|
||||
items: updatedMenuList.map((item) => ({
|
||||
...item,
|
||||
onClick: onMenuItemSelectHandler,
|
||||
})),
|
||||
}),
|
||||
[updatedMenuList, onMenuItemSelectHandler],
|
||||
);
|
||||
@@ -321,7 +314,12 @@ function WidgetHeader({
|
||||
/>
|
||||
)}
|
||||
{menu && Array.isArray(menu.items) && menu.items.length > 0 && (
|
||||
<Dropdown menu={menu} trigger={['hover']} placement="bottomRight">
|
||||
<DropdownMenuSimple
|
||||
menu={menu}
|
||||
side="bottom"
|
||||
align="end"
|
||||
className="widget-header-dropdown"
|
||||
>
|
||||
<Button
|
||||
data-testid="widget-header-options"
|
||||
className={`widget-header-more-options ${
|
||||
@@ -329,7 +327,7 @@ function WidgetHeader({
|
||||
}`}
|
||||
icon={<EllipsisVertical size="md" />}
|
||||
/>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface MenuItem {
|
||||
key: MenuItemKeys;
|
||||
icon: ReactNode;
|
||||
label: ReactNode;
|
||||
rightIcon?: ReactNode;
|
||||
isVisible: boolean;
|
||||
disabled: boolean;
|
||||
danger?: boolean;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { MenuItemType } from 'antd/es/menu/hooks/useItems';
|
||||
import type { MenuItem as DropdownMenuItem } from '@signozhq/ui/dropdown-menu';
|
||||
|
||||
import { MenuItemKeys } from './contants';
|
||||
import { MenuItem } from './types';
|
||||
|
||||
export const generateMenuList = (actions: MenuItem[]): MenuItemType[] =>
|
||||
export const generateMenuList = (actions: MenuItem[]): DropdownMenuItem[] =>
|
||||
actions
|
||||
.filter((action: MenuItem) => action.isVisible)
|
||||
.map(({ key, icon: Icon, label, disabled, ...rest }) => ({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Button, Skeleton, Tag } from 'antd';
|
||||
import { Button, Skeleton } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { useListRules } from 'api/generated/services/rules';
|
||||
import type { RuletypesRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
@@ -177,12 +178,14 @@ export default function AlertRules({
|
||||
</div>
|
||||
|
||||
<div className="alert-rule-item-description home-data-item-tag">
|
||||
<Tag color={rule?.labels?.severity}>{rule?.labels?.severity}</Tag>
|
||||
<Badge color="sienna" variant="outline">
|
||||
{rule?.labels?.severity}
|
||||
</Badge>
|
||||
|
||||
{rule.state === 'firing' && (
|
||||
<Tag color="red" className="firing-tag">
|
||||
<Badge color="cherry" variant="outline" className="firing-tag">
|
||||
{rule.state}
|
||||
</Tag>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Skeleton, Tag } from 'antd';
|
||||
import { Button, Skeleton } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard';
|
||||
@@ -148,9 +149,9 @@ export default function Dashboards({
|
||||
|
||||
<div className="alert-rule-item-description home-data-item-tag">
|
||||
{dashboard.data.tags?.map((tag) => (
|
||||
<Tag color={tag} key={tag}>
|
||||
<Badge color="sienna" variant="outline" key={tag}>
|
||||
{tag}
|
||||
</Tag>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -574,30 +574,7 @@
|
||||
|
||||
.home-data-item-tag {
|
||||
display: flex;
|
||||
|
||||
.ant-tag {
|
||||
display: flex;
|
||||
padding: 2px 12px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border-radius: 20px;
|
||||
border: 1px solid color-mix(in srgb, var(--bg-sienna-500) 20%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-sienna-500) 10%, transparent);
|
||||
|
||||
color: var(--bg-sienna-400);
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
.firing-tag {
|
||||
color: var(--bg-sakura-500);
|
||||
background: color-mix(in srgb, var(--danger-background) 10%, transparent);
|
||||
}
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&.services-list-container {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Skeleton, Tag } from 'antd';
|
||||
import { Button, Skeleton } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { getViewDetailsUsingViewKey } from 'components/ExplorerCard/utils';
|
||||
import ROUTES from 'constants/routes';
|
||||
@@ -249,9 +250,9 @@ export default function SavedViews({
|
||||
}
|
||||
|
||||
return (
|
||||
<Tag color={tag} key={tag}>
|
||||
<Badge color="sienna" key={tag}>
|
||||
{tag}
|
||||
</Tag>
|
||||
</Badge>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Tag } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Progress } from '@signozhq/ui/progress';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import {
|
||||
@@ -52,14 +52,14 @@ export const hostDetailsMetadataConfig: K8sDetailsMetadataConfig<HostData>[] = [
|
||||
label: 'STATUS',
|
||||
getValue: (h): string => (h.active ? 'ACTIVE' : 'INACTIVE'),
|
||||
render: (value, h): React.ReactNode => (
|
||||
<Tag
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`${infraHostsStyles.infraMonitoringTags} ${
|
||||
h.active ? infraHostsStyles.tagsActive : infraHostsStyles.tagsInactive
|
||||
}`}
|
||||
bordered
|
||||
>
|
||||
{value}
|
||||
</Tag>
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -67,9 +67,9 @@ export const hostDetailsMetadataConfig: K8sDetailsMetadataConfig<HostData>[] = [
|
||||
getValue: (h): string => h.os || '-',
|
||||
render: (value): React.ReactNode =>
|
||||
value !== '-' ? (
|
||||
<Tag className={infraHostsStyles.infraMonitoringTags} bordered>
|
||||
<Badge variant="outline" className={infraHostsStyles.infraMonitoringTags}>
|
||||
{value}
|
||||
</Tag>
|
||||
</Badge>
|
||||
) : (
|
||||
<Typography.Text>-</Typography.Text>
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Tag, Tooltip } from 'antd';
|
||||
import { Tooltip } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { HostData } from 'api/infraMonitoring/getHostLists';
|
||||
import TanStackTable, { TableColumnDef } from 'components/TanStackTableView';
|
||||
import { getGroupByEl } from 'container/InfraMonitoringK8s/Base/utils';
|
||||
@@ -92,14 +93,13 @@ export const hostColumnsConfig: TableColumnDef<HostData>[] = [
|
||||
cell: ({ value }): React.ReactNode => {
|
||||
const active = value as boolean;
|
||||
return (
|
||||
<Tag
|
||||
bordered
|
||||
<Badge
|
||||
className={`${styles.statusTag} ${
|
||||
active ? styles.statusTagActive : styles.statusTagInactive
|
||||
}`}
|
||||
>
|
||||
{active ? 'ACTIVE' : 'INACTIVE'}
|
||||
</Tag>
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,9 +8,10 @@ import React, {
|
||||
import { useQuery } from 'react-query';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Color, Spacing } from '@signozhq/design-tokens';
|
||||
import { Button, Divider, Drawer, Radio, Tooltip } from 'antd';
|
||||
import { Button, Drawer, Tooltip } from 'antd';
|
||||
import { ToggleGroupSimple } from '@signozhq/ui/toggle-group';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { RadioChangeEvent } from 'antd/lib';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { combineInitialAndUserExpression } from 'components/QueryBuilderV2/QueryV2/QuerySearch/utils';
|
||||
import { convertFiltersToExpression } from 'components/QueryBuilderV2/utils';
|
||||
@@ -330,8 +331,8 @@ export default function K8sBaseDetails<T>({
|
||||
}
|
||||
}, [getMinMaxTime, selectedTime]);
|
||||
|
||||
const handleTabChange = (e: RadioChangeEvent): void => {
|
||||
setSelectedView(e.target.value);
|
||||
const handleTabChange = (value: string): void => {
|
||||
setSelectedView(value);
|
||||
setLogFiltersParam(null);
|
||||
setTracesFiltersParam(null);
|
||||
setEventsFiltersParam(null);
|
||||
@@ -339,7 +340,7 @@ export default function K8sBaseDetails<T>({
|
||||
entity: InfraMonitoringEvents.K8sEntity,
|
||||
page: InfraMonitoringEvents.DetailedPage,
|
||||
category: eventCategory,
|
||||
view: e.target.value,
|
||||
view: value,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -520,102 +521,101 @@ export default function K8sBaseDetails<T>({
|
||||
|
||||
{!hideDetailViewTabs && (
|
||||
<div className="views-tabs-container">
|
||||
<Radio.Group
|
||||
<ToggleGroupSimple
|
||||
type="single"
|
||||
className="views-tabs"
|
||||
onChange={handleTabChange}
|
||||
value={selectedView}
|
||||
>
|
||||
{tabVisibility.showMetrics && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.METRICS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.METRICS}
|
||||
>
|
||||
<div className="view-title">
|
||||
<BarChart size={14} />
|
||||
Metrics
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{tabVisibility.showLogs && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.LOGS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.LOGS}
|
||||
>
|
||||
<div className="view-title">
|
||||
<ScrollText size={14} />
|
||||
Logs
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{tabVisibility.showTraces && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.TRACES ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.TRACES}
|
||||
>
|
||||
<div className="view-title">
|
||||
<DraftingCompass size={14} />
|
||||
Traces
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{tabVisibility.showEvents && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.EVENTS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.EVENTS}
|
||||
>
|
||||
<div className="view-title">
|
||||
<ChevronsLeftRight size={14} />
|
||||
Events
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{tabVisibility.showContainers && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.CONTAINERS ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.CONTAINERS}
|
||||
>
|
||||
<div className="view-title">
|
||||
<Package2 size={14} />
|
||||
Containers
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{tabVisibility.showProcesses && (
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === VIEW_TYPES.PROCESSES ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={VIEW_TYPES.PROCESSES}
|
||||
>
|
||||
<div className="view-title">
|
||||
<ChevronsLeftRight size={14} />
|
||||
Processes
|
||||
</div>
|
||||
</Radio.Button>
|
||||
)}
|
||||
{customTabs?.map((tab) => (
|
||||
<Radio.Button
|
||||
key={tab.key}
|
||||
className={selectedView === tab.key ? 'selected_view tab' : 'tab'}
|
||||
value={tab.key}
|
||||
>
|
||||
<div className="view-title">
|
||||
{tab.icon}
|
||||
{tab.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
))}
|
||||
</Radio.Group>
|
||||
items={[
|
||||
...(tabVisibility.showMetrics
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.METRICS,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<BarChart size={14} />
|
||||
Metrics
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(tabVisibility.showLogs
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.LOGS,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<ScrollText size={14} />
|
||||
Logs
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(tabVisibility.showTraces
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.TRACES,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<DraftingCompass size={14} />
|
||||
Traces
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(tabVisibility.showEvents
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.EVENTS,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<ChevronsLeftRight size={14} />
|
||||
Events
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(tabVisibility.showContainers
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.CONTAINERS,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<Package2 size={14} />
|
||||
Containers
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(tabVisibility.showProcesses
|
||||
? [
|
||||
{
|
||||
value: VIEW_TYPES.PROCESSES,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
<ChevronsLeftRight size={14} />
|
||||
Processes
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(customTabs?.map((tab) => ({
|
||||
value: tab.key,
|
||||
label: (
|
||||
<div className="view-title">
|
||||
{tab.icon}
|
||||
{tab.label}
|
||||
</div>
|
||||
),
|
||||
})) ?? []),
|
||||
]}
|
||||
/>
|
||||
|
||||
{selectedView === VIEW_TYPES.LOGS && (
|
||||
<Tooltip title="Go to Logs Explorer" placement="left">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:global(.ant-tag .ant-typography) {
|
||||
:global([data-slot='badge'] .ant-typography) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:global(.ant-tag .ant-typography) {
|
||||
:global([data-slot='badge'] .ant-typography) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:global(.ant-tag .ant-typography) {
|
||||
:global([data-slot='badge'] .ant-typography) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:global(.ant-tag .ant-typography) {
|
||||
:global([data-slot='badge'] .ant-typography) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { TableColumnsType as ColumnsType, Tag } from 'antd';
|
||||
import { TableColumnsType as ColumnsType } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
|
||||
@@ -93,9 +94,9 @@ export const getTraceListColumns = (
|
||||
if (primaryKey === 'httpMethod' || primaryKey === 'responseStatusCode') {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(itemData)} openInNewTab>
|
||||
<Tag data-testid={key} color="magenta">
|
||||
<Badge data-testid={key} color="sakura">
|
||||
{getValueForKey(itemData, key)}
|
||||
</Tag>
|
||||
</Badge>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,23 +152,23 @@
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
.tab {
|
||||
> button {
|
||||
border: 1px solid var(--l1-border);
|
||||
width: 114px;
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
|
||||
.selected_view {
|
||||
background: var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
}
|
||||
&[data-state='on'] {
|
||||
background: var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
|
||||
.selected_view::before {
|
||||
background: var(--l1-border);
|
||||
&::before {
|
||||
background: var(--l1-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-tag .ant-typography {
|
||||
[data-slot='badge'] .ant-typography {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
@@ -349,7 +349,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-tag .ant-typography {
|
||||
[data-slot='badge'] .ant-typography {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
Table,
|
||||
TablePaginationConfig,
|
||||
TableProps as AntDTableProps,
|
||||
Tag,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
@@ -41,7 +40,7 @@ import {
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { AxiosError } from 'axios';
|
||||
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||
import Tags from 'components/Tags/Tags';
|
||||
import Badges from 'components/Badges/Badges';
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
@@ -1055,7 +1054,10 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
<div className="ingestion-key-tags">
|
||||
{APIKey.tags.map((tag, index) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<Tag key={`${tag}-${index}`}> {tag} </Tag>
|
||||
<Badge key={`${tag}-${index}`} color="vanilla">
|
||||
{' '}
|
||||
{tag}{' '}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1834,7 +1836,7 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="tags" label="Tags">
|
||||
<Tags tags={updatedTags} setTags={setUpdatedTags} />
|
||||
<Badges tags={updatedTags} setTags={setUpdatedTags} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
@@ -1924,7 +1926,7 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="tags" label="Tags">
|
||||
<Tags tags={updatedTags} setTags={setUpdatedTags} />
|
||||
<Badges tags={updatedTags} setTags={setUpdatedTags} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { Checkbox } from 'antd';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { useRegionSelection } from 'hooks/integration/aws/useRegionSelection';
|
||||
import { regions } from 'utils/regions';
|
||||
|
||||
@@ -21,18 +21,18 @@ export function RegionSelector({
|
||||
setIncludeAllRegions,
|
||||
});
|
||||
|
||||
const allSelected =
|
||||
allRegionIds.length > 0 &&
|
||||
allRegionIds.every((regionId) => selectedRegions.includes(regionId));
|
||||
const someSelected =
|
||||
selectedRegions.length > 0 && selectedRegions.length < allRegionIds.length;
|
||||
|
||||
return (
|
||||
<div className="region-selector">
|
||||
<div className="select-all">
|
||||
<Checkbox
|
||||
checked={
|
||||
allRegionIds.length > 0 &&
|
||||
allRegionIds.every((regionId) => selectedRegions.includes(regionId))
|
||||
}
|
||||
indeterminate={
|
||||
selectedRegions.length > 0 && selectedRegions.length < allRegionIds.length
|
||||
}
|
||||
onChange={(e): void => handleSelectAll(e.target.checked)}
|
||||
value={allSelected ? true : someSelected ? 'indeterminate' : false}
|
||||
onChange={(checked): void => handleSelectAll(checked === true)}
|
||||
>
|
||||
Select All Regions
|
||||
</Checkbox>
|
||||
@@ -45,7 +45,7 @@ export function RegionSelector({
|
||||
{region.subRegions.map((subRegion) => (
|
||||
<Checkbox
|
||||
key={subRegion.id}
|
||||
checked={selectedRegions.includes(subRegion.id)}
|
||||
value={selectedRegions.includes(subRegion.id)}
|
||||
onChange={(): void => handleRegionSelect(subRegion.id)}
|
||||
>
|
||||
{subRegion.name}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Plus } from '@signozhq/icons';
|
||||
import { Button, Divider, Flex } from 'antd';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ROUTES from 'constants/routes';
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { Button, Flex, Input } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { Plus } from '@signozhq/icons';
|
||||
import { Ellipsis, Plus } from '@signozhq/icons';
|
||||
import { DropdownMenuSimple } from '@signozhq/ui/dropdown-menu';
|
||||
import type { ColumnsType } from 'antd/es/table/interface';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
@@ -15,7 +16,6 @@ import type {
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import type { ErrorType } from 'api/generatedAPIInstance';
|
||||
import { AxiosError } from 'axios';
|
||||
import DropDown from 'components/DropDown/DropDown';
|
||||
import {
|
||||
DynamicColumnsKey,
|
||||
TableDataSource,
|
||||
@@ -310,9 +310,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
return <Typography>-</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<LabelColumn labels={withOutSeverityKeys} value={value} color="magenta" />
|
||||
);
|
||||
return <LabelColumn labels={withOutSeverityKeys} value={value} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -323,55 +321,67 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
||||
dataIndex: 'id',
|
||||
key: 'action',
|
||||
width: 10,
|
||||
render: (id: RuletypesRuleDTO['id'], record): JSX.Element => (
|
||||
<div data-testid="alert-actions">
|
||||
<DropDown
|
||||
onDropDownItemClick={(item): void =>
|
||||
alertActionLogEvent(item.key, record)
|
||||
render: (id: RuletypesRuleDTO['id'], record): JSX.Element => {
|
||||
const actionItems = [
|
||||
<ToggleAlertState
|
||||
key="1"
|
||||
disabled={record.disabled ?? false}
|
||||
setData={setData}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
<ColumnButton
|
||||
key="2"
|
||||
onClick={(e: React.MouseEvent): void =>
|
||||
onEditHandler(record, { newTab: isModifierKeyPressed(e) })
|
||||
}
|
||||
element={[
|
||||
<ToggleAlertState
|
||||
key="1"
|
||||
disabled={record.disabled ?? false}
|
||||
setData={setData}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
<ColumnButton
|
||||
key="2"
|
||||
onClick={(e: React.MouseEvent): void =>
|
||||
onEditHandler(record, { newTab: isModifierKeyPressed(e) })
|
||||
}
|
||||
type="link"
|
||||
loading={editLoader}
|
||||
>
|
||||
Edit
|
||||
</ColumnButton>,
|
||||
<ColumnButton
|
||||
key="3-new-tab"
|
||||
onClick={(): void => onEditHandler(record, { newTab: true })}
|
||||
type="link"
|
||||
loading={editLoader}
|
||||
>
|
||||
Edit in New Tab
|
||||
</ColumnButton>,
|
||||
<ColumnButton
|
||||
key="3-clone"
|
||||
onClick={onCloneHandler(record)}
|
||||
type="link"
|
||||
loading={cloneLoader}
|
||||
>
|
||||
Clone
|
||||
</ColumnButton>,
|
||||
<DeleteAlert
|
||||
key="4"
|
||||
notifications={notificationsApi}
|
||||
setData={setData}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
];
|
||||
return (
|
||||
<div data-testid="alert-actions">
|
||||
<DropdownMenuSimple
|
||||
menu={{
|
||||
items: actionItems.map((element, index) => ({
|
||||
key: String(index),
|
||||
label: element,
|
||||
onClick: ({ key }): void => alertActionLogEvent(key, record),
|
||||
})),
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
loading={editLoader}
|
||||
>
|
||||
Edit
|
||||
</ColumnButton>,
|
||||
<ColumnButton
|
||||
key="3"
|
||||
onClick={(): void => onEditHandler(record, { newTab: true })}
|
||||
type="link"
|
||||
loading={editLoader}
|
||||
>
|
||||
Edit in New Tab
|
||||
</ColumnButton>,
|
||||
<ColumnButton
|
||||
key="3"
|
||||
onClick={onCloneHandler(record)}
|
||||
type="link"
|
||||
loading={cloneLoader}
|
||||
>
|
||||
Clone
|
||||
</ColumnButton>,
|
||||
<DeleteAlert
|
||||
key="4"
|
||||
notifications={notificationsApi}
|
||||
setData={setData}
|
||||
id={id ?? ''}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
style={{ color: 'var(--l1-foreground)' }}
|
||||
icon={<Ellipsis size={16} />}
|
||||
/>
|
||||
</DropdownMenuSimple>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,46 @@
|
||||
import { Tag } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import type { RuletypesRuleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
|
||||
function Status({ status }: StatusProps): JSX.Element {
|
||||
switch (status) {
|
||||
case 'inactive': {
|
||||
return <Tag color="green">OK</Tag>;
|
||||
return (
|
||||
<Badge color="forest" variant="outline">
|
||||
OK
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
case 'pending': {
|
||||
return <Tag color="orange">Pending</Tag>;
|
||||
return (
|
||||
<Badge color="amber" variant="outline">
|
||||
Pending
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
case 'firing': {
|
||||
return <Tag color="red">Firing</Tag>;
|
||||
return (
|
||||
<Badge color="cherry" variant="outline">
|
||||
Firing
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
case 'disabled': {
|
||||
return <Tag>Disabled</Tag>;
|
||||
return (
|
||||
<Badge color="vanilla" variant="outline">
|
||||
Disabled
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
default: {
|
||||
return <Tag color="default">Unknown</Tag>;
|
||||
return (
|
||||
<Badge color="vanilla" variant="outline">
|
||||
Unknown
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,18 @@ import { useTranslation } from 'react-i18next';
|
||||
import { generatePath } from 'react-router-dom';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { DropdownMenuSimple, type MenuItem } from '@signozhq/ui/dropdown-menu';
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
Flex,
|
||||
Input,
|
||||
MenuProps,
|
||||
Modal,
|
||||
Popover,
|
||||
Skeleton,
|
||||
Table,
|
||||
Tag,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { TableProps } from 'antd/lib';
|
||||
@@ -420,15 +419,15 @@ function DashboardsList(): JSX.Element {
|
||||
{dashboard?.tags && dashboard.tags.length > 0 && (
|
||||
<div className="dashboard-tags">
|
||||
{dashboard.tags.slice(0, 3).map((tag) => (
|
||||
<Tag className="tag" key={tag}>
|
||||
<Badge className="tag" color="vanilla" key={tag}>
|
||||
{tag}
|
||||
</Tag>
|
||||
</Badge>
|
||||
))}
|
||||
|
||||
{dashboard.tags.length > 3 && (
|
||||
<Tag className="tag" key={dashboard.tags[3]}>
|
||||
<Badge className="tag" color="vanilla" key={dashboard.tags[3]}>
|
||||
+ <span> {dashboard.tags.length - 3} </span>
|
||||
</Tag>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -553,7 +552,7 @@ function DashboardsList(): JSX.Element {
|
||||
];
|
||||
|
||||
const getCreateDashboardItems = useMemo(() => {
|
||||
const menuItems: MenuProps['items'] = [
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
label: (
|
||||
<div
|
||||
@@ -711,11 +710,11 @@ function DashboardsList(): JSX.Element {
|
||||
|
||||
{createNewDashboard && (
|
||||
<section className="actions">
|
||||
<Dropdown
|
||||
overlayClassName="new-dashboard-menu"
|
||||
<DropdownMenuSimple
|
||||
className="new-dashboard-menu"
|
||||
menu={{ items: getCreateDashboardItems }}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}
|
||||
side="bottom"
|
||||
align="end"
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
@@ -727,7 +726,7 @@ function DashboardsList(): JSX.Element {
|
||||
>
|
||||
New Dashboard
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
<Button
|
||||
type="text"
|
||||
className="learn-more"
|
||||
@@ -756,11 +755,11 @@ function DashboardsList(): JSX.Element {
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
{createNewDashboard && (
|
||||
<Dropdown
|
||||
overlayClassName="new-dashboard-menu"
|
||||
<DropdownMenuSimple
|
||||
className="new-dashboard-menu"
|
||||
menu={{ items: getCreateDashboardItems }}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}
|
||||
side="bottom"
|
||||
align="end"
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -773,7 +772,7 @@ function DashboardsList(): JSX.Element {
|
||||
>
|
||||
New dashboard
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</DropdownMenuSimple>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Button, Divider, Flex } from 'antd';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import Controls from 'container/Controls';
|
||||
import Download from 'container/Download/Download';
|
||||
|
||||
@@ -2,7 +2,13 @@ import { useCallback } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import { orange } from '@ant-design/colors';
|
||||
import { Settings } from '@signozhq/icons';
|
||||
import { Dropdown, MenuProps } from 'antd';
|
||||
import {
|
||||
type BaseMenuItem,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@signozhq/ui/dropdown-menu';
|
||||
import {
|
||||
negateOperator,
|
||||
OPERATORS,
|
||||
@@ -135,41 +141,38 @@ function BodyTitleRenderer({
|
||||
viewName,
|
||||
]);
|
||||
|
||||
const onClickHandler: MenuProps['onClick'] = (props): void => {
|
||||
const onClickHandler = (key: string): void => {
|
||||
const mapper = {
|
||||
[DROPDOWN_KEY.FILTER_IN]: filterHandler(true),
|
||||
[DROPDOWN_KEY.FILTER_OUT]: filterHandler(false),
|
||||
[DROPDOWN_KEY.GROUP_BY]: groupByHandler,
|
||||
};
|
||||
|
||||
const handler = mapper[props.key];
|
||||
const handler = mapper[key];
|
||||
|
||||
if (handler) {
|
||||
handler();
|
||||
}
|
||||
};
|
||||
|
||||
const menu: MenuProps = {
|
||||
items: [
|
||||
{
|
||||
key: DROPDOWN_KEY.FILTER_IN,
|
||||
label: `Filter for ${value}`,
|
||||
},
|
||||
{
|
||||
key: DROPDOWN_KEY.FILTER_OUT,
|
||||
label: `Filter out ${value}`,
|
||||
},
|
||||
...(isGroupBySupported
|
||||
? [
|
||||
{
|
||||
key: DROPDOWN_KEY.GROUP_BY,
|
||||
label: `Group by ${nodeKey}`,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
onClick: onClickHandler,
|
||||
};
|
||||
const menuItems: BaseMenuItem[] = [
|
||||
{
|
||||
key: DROPDOWN_KEY.FILTER_IN,
|
||||
label: `Filter for ${value}`,
|
||||
},
|
||||
{
|
||||
key: DROPDOWN_KEY.FILTER_OUT,
|
||||
label: `Filter out ${value}`,
|
||||
},
|
||||
...(isGroupBySupported
|
||||
? [
|
||||
{
|
||||
key: DROPDOWN_KEY.GROUP_BY,
|
||||
label: `Group by ${nodeKey}`,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
const handleNodeClick = useCallback(
|
||||
(e: React.MouseEvent): void => {
|
||||
@@ -218,15 +221,23 @@ function BodyTitleRenderer({
|
||||
}}
|
||||
onMouseDown={(e): void => e.preventDefault()}
|
||||
>
|
||||
<Dropdown
|
||||
menu={menu}
|
||||
trigger={['click']}
|
||||
dropdownRender={(originNode): React.ReactNode => (
|
||||
<div data-log-detail-ignore="true">{originNode}</div>
|
||||
)}
|
||||
>
|
||||
<Settings style={{ marginRight: 8 }} className="hover-reveal" />
|
||||
</Dropdown>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Settings style={{ marginRight: 8 }} className="hover-reveal" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<div data-log-detail-ignore="true">
|
||||
{menuItems.map((item) => (
|
||||
<DropdownMenuItem
|
||||
key={item.key}
|
||||
onSelect={(): void => onClickHandler(item.key as string)}
|
||||
>
|
||||
{item.label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</span>
|
||||
)}
|
||||
{title.toString()}{' '}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Tag } from 'antd';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const TagContainer = styled(Tag)`
|
||||
export const TagContainer = styled(Badge)`
|
||||
&&& {
|
||||
border-color: var(--bg-slate-400);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Divider } from 'antd';
|
||||
import { Divider } from '@signozhq/ui/divider';
|
||||
import { TooltipSimple } from '@signozhq/ui/tooltip';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Empty } from 'antd';
|
||||
import type { RadioChangeEvent } from 'antd/lib';
|
||||
import SignozRadioGroup from 'components/SignozRadioGroup/SignozRadioGroup';
|
||||
import { History, Table } from '@signozhq/icons';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
@@ -60,8 +59,8 @@ function InfraMetrics({
|
||||
return options;
|
||||
}, [podName]);
|
||||
|
||||
const handleModeChange = (e: RadioChangeEvent): void => {
|
||||
setSelectedView(e.target.value);
|
||||
const handleModeChange = (value: string): void => {
|
||||
setSelectedView(value);
|
||||
};
|
||||
|
||||
if (!podName && !nodeName && !hostName) {
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
.ant-tag-borderless {
|
||||
[data-slot='badge'] {
|
||||
border-radius: 2px;
|
||||
background: color-mix(in srgb, var(--bg-robin-400) 8%, transparent);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user