mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-23 02:10:27 +01:00
Compare commits
1 Commits
feat/field
...
feat/selec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b73b58acc |
@@ -19,6 +19,8 @@ const BANNED_COMPONENTS = {
|
||||
Switch: 'Use @signozhq/ui/switch Switch instead of antd Switch.',
|
||||
Badge: 'Use @signozhq/ui/badge instead of antd Badge.',
|
||||
Progress: 'Use @signozhq/ui/progress instead of antd Progress.',
|
||||
Select:
|
||||
'Use SelectSimple / ComboboxSimple from @signozhq/ui/select or @signozhq/ui/combobox instead of antd Select.',
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.",
|
||||
"button_testrule": "Test Notification",
|
||||
"label_channel_select": "Notification Channels",
|
||||
"placeholder_channel_select": "select one or more channels",
|
||||
"placeholder_channel_select": "Select one or more channels",
|
||||
"channel_select_tooltip": "Leave empty to send this alert on all the configured channels",
|
||||
"preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.",
|
||||
"preview_chart_threshold_label": "Threshold",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.",
|
||||
"button_testrule": "Test Notification",
|
||||
"label_channel_select": "Notification Channels",
|
||||
"placeholder_channel_select": "select one or more channels",
|
||||
"placeholder_channel_select": "Select one or more channels",
|
||||
"channel_select_tooltip": "Leave empty to send this alert on all the configured channels",
|
||||
"preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.",
|
||||
"preview_chart_threshold_label": "Threshold",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { Row, Select, Spin } from 'antd';
|
||||
import { Row } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import {
|
||||
getValuesFromQueryParams,
|
||||
setQueryParamsFromOptions,
|
||||
} from 'components/CeleryTask/CeleryUtils';
|
||||
import { useCeleryFilterOptions } from 'components/CeleryTask/useCeleryFilterOptions';
|
||||
import { SelectMaxTagPlaceholder } from 'components/MessagingQueues/MQCommon/MQCommon';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
|
||||
@@ -48,7 +48,7 @@ export function FilterSelect({
|
||||
: getValuesFromQueryParams(queryParam, urlQuery) || [];
|
||||
|
||||
// Memoize options to include the typed value if not present
|
||||
const mergedOptions = useMemo(() => {
|
||||
const mergedOptions = useMemo<ComboboxSimpleItem[]>(() => {
|
||||
if (
|
||||
!!searchValue.trim().length &&
|
||||
!options.some((opt) => opt.value === searchValue)
|
||||
@@ -84,35 +84,16 @@ export function FilterSelect({
|
||||
],
|
||||
);
|
||||
|
||||
// Update searchValue on user input
|
||||
const handleSearchInput = (input: string): void => {
|
||||
setSearchValue(input);
|
||||
handleSearch(input);
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
key={filterType.toString()}
|
||||
placeholder={placeholder}
|
||||
showSearch
|
||||
{...(isMultiple ? { mode: 'multiple' } : {})}
|
||||
options={mergedOptions}
|
||||
multiple={isMultiple}
|
||||
items={mergedOptions}
|
||||
loading={isFetching}
|
||||
className="config-select-option"
|
||||
onSearch={handleSearchInput}
|
||||
maxTagCount={4}
|
||||
allowClear
|
||||
maxTagPlaceholder={SelectMaxTagPlaceholder}
|
||||
value={selectValue}
|
||||
notFoundContent={
|
||||
isFetching ? (
|
||||
<span>
|
||||
<Spin size="small" /> Loading...
|
||||
</span>
|
||||
) : (
|
||||
<span>No {placeholder} found</span>
|
||||
)
|
||||
}
|
||||
emptyPlaceholder={`No ${placeholder} found`}
|
||||
onChange={handleSelectChange}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { Select, Spin } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { SelectMaxTagPlaceholder } from 'components/MessagingQueues/MQCommon/MQCommon';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
|
||||
@@ -27,30 +26,18 @@ function CeleryTaskConfigOptions(): JSX.Element {
|
||||
<Typography.Text style={{ whiteSpace: 'nowrap' }}>
|
||||
Task Name
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
placeholder="Task Name"
|
||||
showSearch
|
||||
mode="multiple"
|
||||
options={options}
|
||||
multiple
|
||||
items={options}
|
||||
loading={isFetching}
|
||||
className="config-select-option"
|
||||
onSearch={handleSearch}
|
||||
maxTagCount={4}
|
||||
maxTagPlaceholder={SelectMaxTagPlaceholder}
|
||||
value={getValuesFromQueryParams(QueryParams.taskName, urlQuery) || []}
|
||||
notFoundContent={
|
||||
isFetching ? (
|
||||
<span>
|
||||
<Spin size="small" /> Loading...
|
||||
</span>
|
||||
) : (
|
||||
<span>No Task Name found</span>
|
||||
)
|
||||
}
|
||||
emptyPlaceholder="No Task Name found"
|
||||
onChange={(value): void => {
|
||||
handleSearch('');
|
||||
setQueryParamsFromOptions(
|
||||
value,
|
||||
value as string[],
|
||||
urlQuery,
|
||||
history,
|
||||
location,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from 'react-query';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useSelector } from 'react-redux';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { getAttributesValues } from 'api/queryBuilder/getAttributesValues';
|
||||
import { DATA_TYPE_VS_ATTRIBUTE_VALUES_KEY } from 'constants/queryBuilder';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
@@ -21,7 +21,7 @@ export interface Filters {
|
||||
}
|
||||
|
||||
export interface GetAllFiltersResponse {
|
||||
options: DefaultOptionType[];
|
||||
options: ComboboxSimpleItem[];
|
||||
isFetching: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
@@ -17,7 +17,7 @@ export const useCeleryFilterOptions = (
|
||||
searchText: string;
|
||||
handleSearch: (value: string) => void;
|
||||
isFetching: boolean;
|
||||
options: DefaultOptionType[];
|
||||
options: ComboboxSimpleItem[];
|
||||
} => {
|
||||
const [searchText, setSearchText] = useState<string>('');
|
||||
const { isFetching, options } = useGetAllFilters({
|
||||
|
||||
@@ -5,17 +5,25 @@ import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Select, Tag, Tooltip } from 'antd';
|
||||
import {
|
||||
Combobox,
|
||||
ComboboxCommand,
|
||||
ComboboxContent,
|
||||
ComboboxEmpty,
|
||||
ComboboxItem,
|
||||
ComboboxList,
|
||||
ComboboxMultiTrigger,
|
||||
ComboboxPill,
|
||||
} from '@signozhq/ui/combobox';
|
||||
import { Tag, Tooltip } from 'antd';
|
||||
import {
|
||||
OPERATORS,
|
||||
QUERY_BUILDER_OPERATORS_BY_TYPES,
|
||||
QUERY_BUILDER_SEARCH_VALUES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { CustomTagProps } from 'container/QueryBuilder/filters/QueryBuilderSearch';
|
||||
import { selectStyle } from 'container/QueryBuilder/filters/QueryBuilderSearch/config';
|
||||
import { PLACEHOLDER } from 'container/QueryBuilder/filters/QueryBuilderSearch/constant';
|
||||
import { TypographyText } from 'container/QueryBuilder/filters/QueryBuilderSearch/style';
|
||||
@@ -38,7 +46,6 @@ import { operatorTypeMapper } from 'hooks/queryBuilder/useOperatorType';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { isArray, isEmpty, isEqual, isObject } from 'lodash-es';
|
||||
import { ChevronDown, ChevronUp } from '@signozhq/icons';
|
||||
import type { BaseSelectRef } from 'rc-select';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
@@ -47,7 +54,6 @@ import {
|
||||
IBuilderQuery,
|
||||
TagFilter,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import './ClientSideQBSearch.styles.scss';
|
||||
@@ -93,8 +99,6 @@ function ClientSideQBSearch(
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const selectRef = useRef<BaseSelectRef>(null);
|
||||
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
// create the tags from the initial query here, this should only be computed on the first load as post that tags and query will be always in sync.
|
||||
@@ -214,7 +218,7 @@ function ClientSideQBSearch(
|
||||
}, []);
|
||||
|
||||
const onInputKeyDownHandler = useCallback(
|
||||
(event: KeyboardEvent<Element>): void => {
|
||||
(event: KeyboardEvent<HTMLInputElement>): void => {
|
||||
if (event.key === 'Backspace' && !searchValue) {
|
||||
event.stopPropagation();
|
||||
setTags((prev) => prev.slice(0, -1));
|
||||
@@ -516,29 +520,23 @@ function ClientSideQBSearch(
|
||||
[tags],
|
||||
);
|
||||
|
||||
const onTagRender = ({
|
||||
value,
|
||||
closable,
|
||||
onClose,
|
||||
}: CustomTagProps): React.ReactElement => {
|
||||
const renderPill = (value: string, index: number): React.ReactElement => {
|
||||
const { tagOperator } = getTagToken(value);
|
||||
const isInNin = isInNInOperator(tagOperator);
|
||||
const chipValue = isInNin
|
||||
? value?.trim()?.replace(/,\s*$/, '')
|
||||
: value?.trim();
|
||||
|
||||
const indexInQueryTags = queryTags.findIndex((qTag) => isEqual(qTag, value));
|
||||
const tagDetails = tags[indexInQueryTags];
|
||||
const tagDetails = tags[index];
|
||||
|
||||
const onCloseHandler = (): void => {
|
||||
onClose();
|
||||
setSearchValue('');
|
||||
setTags((prev) => prev.filter((t) => !isEqual(t, tagDetails)));
|
||||
};
|
||||
|
||||
const tagEditHandler = (value: string): void => {
|
||||
const tagEditHandler = (next: string): void => {
|
||||
setCurrentFilterItem(tagDetails);
|
||||
setSearchValue(value);
|
||||
setSearchValue(next);
|
||||
setCurrentState(DropdownState.ATTRIBUTE_VALUE);
|
||||
setTags((prev) => prev.filter((t) => !isEqual(t, tagDetails)));
|
||||
};
|
||||
@@ -546,12 +544,13 @@ function ClientSideQBSearch(
|
||||
const isDisabled = !!searchValue;
|
||||
|
||||
return (
|
||||
<span className="qb-search-bar-tokenised-tags">
|
||||
<Tag
|
||||
closable={!searchValue && closable}
|
||||
onClose={onCloseHandler}
|
||||
className={tagDetails?.key?.type || ''}
|
||||
>
|
||||
<ComboboxPill
|
||||
key={`${value}-${index}`}
|
||||
value={value}
|
||||
onRemove={onCloseHandler}
|
||||
className="qb-search-bar-tokenised-tags"
|
||||
>
|
||||
<Tag closable={false} className={tagDetails?.key?.type || ''}>
|
||||
<Tooltip title={chipValue}>
|
||||
<TypographyText
|
||||
$isInNin={isInNin}
|
||||
@@ -567,7 +566,7 @@ function ClientSideQBSearch(
|
||||
</TypographyText>
|
||||
</Tooltip>
|
||||
</Tag>
|
||||
</span>
|
||||
</ComboboxPill>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -588,59 +587,73 @@ function ClientSideQBSearch(
|
||||
);
|
||||
}, [isDarkMode, isOpen, suffixIcon]);
|
||||
|
||||
const handleItemSelect = (rawValue: string): void => {
|
||||
handleDropdownSelect(rawValue);
|
||||
setIsOpen(true);
|
||||
};
|
||||
|
||||
const handleInputKeyDownWrapper = (
|
||||
e: KeyboardEvent<HTMLInputElement>,
|
||||
): void => {
|
||||
onInputKeyDownHandler(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="query-builder-search-v2 ">
|
||||
<Select
|
||||
ref={selectRef}
|
||||
getPopupContainer={popupContainer}
|
||||
virtual={false}
|
||||
showSearch
|
||||
tagRender={onTagRender}
|
||||
transitionName=""
|
||||
choiceTransitionName=""
|
||||
filterOption={false}
|
||||
open={isOpen}
|
||||
suffixIcon={suffixIconContent}
|
||||
onDropdownVisibleChange={setIsOpen}
|
||||
autoClearSearchValue={false}
|
||||
mode="multiple"
|
||||
placeholder={placeholder}
|
||||
value={queryTags}
|
||||
searchValue={searchValue}
|
||||
className={className}
|
||||
rootClassName="query-builder-search client-side-qb-search"
|
||||
disabled={!attributeKeys.length}
|
||||
style={selectStyle}
|
||||
onSearch={handleSearch}
|
||||
onSelect={handleDropdownSelect}
|
||||
onInputKeyDown={onInputKeyDownHandler}
|
||||
notFoundContent={null}
|
||||
showAction={['focus']}
|
||||
onBlur={handleOnBlur}
|
||||
>
|
||||
{dropdownOptions.map((option) => {
|
||||
let val = option.value;
|
||||
try {
|
||||
if (isObject(option.value)) {
|
||||
val = JSON.stringify(option.value);
|
||||
} else {
|
||||
val = option.value;
|
||||
}
|
||||
} catch {
|
||||
val = option.value;
|
||||
}
|
||||
return (
|
||||
<Select.Option key={isObject(val) ? `select-option` : val} value={val}>
|
||||
<Suggestions
|
||||
label={option.label}
|
||||
value={option.value}
|
||||
option={currentState}
|
||||
searchValue={searchValue}
|
||||
/>
|
||||
</Select.Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<div className="query-builder-search-v2" style={selectStyle}>
|
||||
<Combobox open={isOpen} onOpenChange={setIsOpen}>
|
||||
<ComboboxMultiTrigger
|
||||
id="client-side-qb-search-trigger"
|
||||
testId="client-side-qb-search"
|
||||
className={className ?? 'query-builder-search client-side-qb-search'}
|
||||
placeholder={placeholder ?? PLACEHOLDER}
|
||||
inputValue={searchValue}
|
||||
onInputChange={handleSearch}
|
||||
onKeyDown={handleInputKeyDownWrapper}
|
||||
onFocus={(): void => setIsOpen(true)}
|
||||
disabled={!attributeKeys.length}
|
||||
>
|
||||
{queryTags.map((tagValue, idx) => renderPill(tagValue, idx))}
|
||||
</ComboboxMultiTrigger>
|
||||
<ComboboxContent
|
||||
onCloseAutoFocus={(): void => {
|
||||
handleOnBlur();
|
||||
}}
|
||||
>
|
||||
<ComboboxCommand shouldFilter={false}>
|
||||
<ComboboxList>
|
||||
{dropdownOptions.map((option) => {
|
||||
let val = option.value as unknown as string;
|
||||
try {
|
||||
if (isObject(option.value)) {
|
||||
val = JSON.stringify(option.value);
|
||||
}
|
||||
} catch {
|
||||
val = String(option.value);
|
||||
}
|
||||
const itemKey = isObject(val) ? `select-option` : String(val);
|
||||
return (
|
||||
<ComboboxItem
|
||||
key={itemKey}
|
||||
value={String(val)}
|
||||
onSelect={(): void => handleItemSelect(String(val))}
|
||||
>
|
||||
<Suggestions
|
||||
label={option.label}
|
||||
value={option.value}
|
||||
option={currentState}
|
||||
searchValue={searchValue}
|
||||
/>
|
||||
</ComboboxItem>
|
||||
);
|
||||
})}
|
||||
<ComboboxEmpty>No results found.</ComboboxEmpty>
|
||||
</ComboboxList>
|
||||
</ComboboxCommand>
|
||||
</ComboboxContent>
|
||||
</Combobox>
|
||||
<div className="qb-search-suffix" aria-hidden>
|
||||
{suffixIconContent}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Dropdown,
|
||||
MenuProps,
|
||||
Popover,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
} from 'antd';
|
||||
import { Button, Col, Dropdown, MenuProps, Popover, Row, Space } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import axios from 'axios';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
@@ -31,11 +23,7 @@ import { popupContainer } from 'utils/selectPopupContainer';
|
||||
import { ExploreHeaderToolTip, SaveButtonText } from './constants';
|
||||
import MenuItemGenerator from './MenuItemGenerator';
|
||||
import SaveViewWithName from './SaveViewWithName';
|
||||
import {
|
||||
DropDownOverlay,
|
||||
ExplorerCardHeadContainer,
|
||||
OffSetCol,
|
||||
} from './styles';
|
||||
import { ExplorerCardHeadContainer, OffSetCol } from './styles';
|
||||
import { ExplorerCardProps } from './types';
|
||||
import { deleteViewHandler } from './utils';
|
||||
import { Ellipsis, Save, Share2, Trash2 } from '@signozhq/icons';
|
||||
@@ -164,6 +152,26 @@ function ExplorerCard({
|
||||
|
||||
const showSaveView = false;
|
||||
|
||||
const viewItems = useMemo(
|
||||
() =>
|
||||
(viewsData?.data.data ?? []).map((view) => ({
|
||||
value: view.name,
|
||||
label: (
|
||||
<MenuItemGenerator
|
||||
viewName={view.name}
|
||||
viewKey={viewKey}
|
||||
createdBy={view.createdBy}
|
||||
uuid={view.id}
|
||||
refetchAllView={refetchAllView}
|
||||
viewData={viewsData?.data.data ?? []}
|
||||
sourcePage={sourcepage}
|
||||
/>
|
||||
),
|
||||
displayValue: view.name,
|
||||
})),
|
||||
[refetchAllView, sourcepage, viewKey, viewsData?.data.data],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showSaveView && (
|
||||
@@ -183,30 +191,12 @@ function ExplorerCard({
|
||||
<Space size="large">
|
||||
{viewsData?.data.data && viewsData?.data.data.length && (
|
||||
<Space>
|
||||
<Select
|
||||
getPopupContainer={popupContainer}
|
||||
<ComboboxSimple
|
||||
loading={isLoading || isRefetching}
|
||||
showSearch
|
||||
placeholder="Select a view"
|
||||
dropdownStyle={DropDownOverlay}
|
||||
dropdownMatchSelectWidth={false}
|
||||
optionLabelProp="value"
|
||||
items={viewItems}
|
||||
value={viewName || undefined}
|
||||
>
|
||||
{viewsData?.data.data.map((view) => (
|
||||
<Select.Option key={view.id} value={view.name}>
|
||||
<MenuItemGenerator
|
||||
viewName={view.name}
|
||||
viewKey={viewKey}
|
||||
createdBy={view.createdBy}
|
||||
uuid={view.id}
|
||||
refetchAllView={refetchAllView}
|
||||
viewData={viewsData.data.data}
|
||||
sourcePage={sourcepage}
|
||||
/>
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
/>
|
||||
</Space>
|
||||
)}
|
||||
{isQueryUpdated && (
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
padding: 0px 8px;
|
||||
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--l2-border);
|
||||
background: var(--l2-background);
|
||||
color: var(--l2-foreground);
|
||||
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
|
||||
background: var(--input-with-label-background-color, var(--l2-background));
|
||||
color: var(--input-with-label-color, var(--l2-foreground));
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
@@ -35,21 +35,28 @@
|
||||
min-width: 150px;
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l2-background);
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
|
||||
background: var(--input-with-label-background-color, var(--l2-background));
|
||||
color: var(--input-with-label-color, var(--l2-foreground));
|
||||
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
font-size: 12px !important;
|
||||
line-height: 27px;
|
||||
line-height: 25px;
|
||||
|
||||
&.input__has-label-after {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
}
|
||||
|
||||
&.input__has-close-button {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--l2-foreground) !important;
|
||||
color: var(--input-with-label-color, var(--l3-foreground)) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
&[type='number']::-webkit-inner-spin-button,
|
||||
@@ -63,25 +70,24 @@
|
||||
|
||||
.close-btn {
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid var(--l2-border);
|
||||
background: var(--l2-background);
|
||||
height: 38px;
|
||||
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
|
||||
background: var(--input-with-label-background-color, var(--l2-background));
|
||||
height: 100%;
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
&.labelAfter {
|
||||
.input {
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l2-background);
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--input-with-label-border-color, var(--l2-border));
|
||||
background: var(--input-with-label-background-color, var(--l2-background));
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
|
||||
.label {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ function InputWithLabel({
|
||||
>
|
||||
{!labelAfter && <Typography.Text className="label">{label}</Typography.Text>}
|
||||
<Input
|
||||
className="input"
|
||||
className={cx('input', {
|
||||
'input__has-label-after': !labelAfter,
|
||||
'input__has-close-button': !!onClose,
|
||||
})}
|
||||
placeholder={placeholder}
|
||||
type={type}
|
||||
value={inputValue}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Style } from '@signozhq/design-tokens';
|
||||
import { ChevronDown, Plus, Trash2, X } from '@signozhq/icons';
|
||||
import { Plus, Trash2, X } from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Callout } from '@signozhq/ui/callout';
|
||||
import { DialogFooter, DialogWrapper } from '@signozhq/ui/dialog';
|
||||
import { Input } from '@signozhq/ui/input';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { Select } from 'antd';
|
||||
import inviteUsers from 'api/v1/invite/bulk/create';
|
||||
import sendInvite from 'api/v1/invite/create';
|
||||
import { cloneDeep, debounce } from 'lodash-es';
|
||||
@@ -15,7 +15,6 @@ import APIError from 'types/api/error';
|
||||
import { ROLES } from 'types/roles';
|
||||
import { EMAIL_REGEX } from 'utils/app';
|
||||
import { getBaseUrl } from 'utils/basePath';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import './InviteMembersModal.styles.scss';
|
||||
@@ -254,18 +253,17 @@ function InviteMembersModal({
|
||||
)}
|
||||
</div>
|
||||
<div className="team-member-cell role-cell">
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={row.role || undefined}
|
||||
onChange={(role): void => updateRole(row.id, role as ROLES)}
|
||||
className="team-member-role-select"
|
||||
placeholder="Select roles"
|
||||
suffixIcon={<ChevronDown size={14} />}
|
||||
getPopupContainer={popupContainer}
|
||||
>
|
||||
<Select.Option value="VIEWER">Viewer</Select.Option>
|
||||
<Select.Option value="EDITOR">Editor</Select.Option>
|
||||
<Select.Option value="ADMIN">Admin</Select.Option>
|
||||
</Select>
|
||||
items={[
|
||||
{ value: 'VIEWER', label: 'Viewer' },
|
||||
{ value: 'EDITOR', label: 'Editor' },
|
||||
{ value: 'ADMIN', label: 'Admin' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<div className="team-member-cell action-cell">
|
||||
{rows.length > 1 && (
|
||||
|
||||
@@ -69,8 +69,6 @@ export function useLogsTableColumns({
|
||||
id: 'timestamp',
|
||||
header: 'Timestamp',
|
||||
accessorFn: (log): unknown => log.timestamp,
|
||||
canBeHidden: false,
|
||||
enableRemove: false,
|
||||
width: { default: 170, min: 170 },
|
||||
cell: ({ value }): ReactElement => {
|
||||
const ts = value as string | number;
|
||||
@@ -94,7 +92,6 @@ export function useLogsTableColumns({
|
||||
header: 'Body',
|
||||
accessorFn: (log): string => getBodyDisplayString(log.body),
|
||||
canBeHidden: false,
|
||||
enableRemove: false,
|
||||
width: { default: '100%', min: 300 },
|
||||
cell: ({ value, isActive }): ReactElement => (
|
||||
<TanStackTable.Text
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Button, Input, InputNumber, Popover, Tooltip } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import cx from 'classnames';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { FontSize, OptionsMenuConfig } from 'container/OptionsMenu/types';
|
||||
@@ -113,15 +113,11 @@ function OptionsMenu({
|
||||
|
||||
function handleColumnSelection(
|
||||
currentIndex: number,
|
||||
optionsData: DefaultOptionType[],
|
||||
optionsData: ComboboxSimpleItem[],
|
||||
): void {
|
||||
const currentItem = optionsData[currentIndex];
|
||||
const itemLength = optionsData.length;
|
||||
if (addColumn && addColumn?.onSelect) {
|
||||
addColumn?.onSelect(selectedValue, {
|
||||
label: currentItem.label,
|
||||
disabled: false,
|
||||
});
|
||||
if (addColumn && addColumn?.onSelect && selectedValue) {
|
||||
addColumn?.onSelect(selectedValue);
|
||||
|
||||
// if the last element is selected then select the previous one
|
||||
if (currentIndex === itemLength - 1) {
|
||||
@@ -175,7 +171,7 @@ function OptionsMenu({
|
||||
}
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
handleColumnSelection(currentIndex, optionsData);
|
||||
handleColumnSelection(currentIndex, optionsData as ComboboxSimpleItem[]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -317,7 +313,10 @@ function OptionsMenu({
|
||||
}}
|
||||
onClick={(eve): void => {
|
||||
eve.stopPropagation();
|
||||
handleColumnSelection(index, addColumn?.options || []);
|
||||
handleColumnSelection(
|
||||
index,
|
||||
(addColumn?.options || []) as ComboboxSimpleItem[],
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className="name">
|
||||
|
||||
@@ -62,7 +62,6 @@ describe('LogsFormatOptionsMenu (unit)', () => {
|
||||
onSearch: jest.fn(),
|
||||
onSelect: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
onReorder: jest.fn(),
|
||||
},
|
||||
}}
|
||||
/>,
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
Loader,
|
||||
X,
|
||||
} from '@signozhq/icons';
|
||||
import { Modal, Select, Spin, Tooltip, Tree, TreeDataNode } from 'antd';
|
||||
import { Modal, Spin, Tooltip, Tree, TreeDataNode } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { OnboardingStatusResponse } from 'api/messagingQueues/onboarding/getOnboardingStatus';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
@@ -181,8 +182,8 @@ function AttributeCheckList({
|
||||
const [filter, setFilter] = useState<AttributesFilters>(AttributesFilters.ALL);
|
||||
const [treeData, setTreeData] = useState<TreeDataNode[]>([]);
|
||||
|
||||
const handleFilterChange = (value: AttributesFilters): void => {
|
||||
setFilter(value);
|
||||
const handleFilterChange = (value: string | string[]): void => {
|
||||
setFilter(value as AttributesFilters);
|
||||
};
|
||||
const { isCloudUser: isCloudUserVal } = useGetTenantLicense();
|
||||
const history = useHistory();
|
||||
@@ -237,11 +238,11 @@ function AttributeCheckList({
|
||||
</div>
|
||||
) : (
|
||||
<div className="modal-content">
|
||||
<Select
|
||||
<SelectSimple
|
||||
defaultValue={AttributesFilters.ALL}
|
||||
className="attribute-select"
|
||||
onChange={handleFilterChange}
|
||||
options={[
|
||||
items={[
|
||||
{
|
||||
value: AttributesFilters.ALL,
|
||||
label: AttributeLabels({ title: 'Attributes: All' }),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Tooltip } from 'antd';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Info } from '@signozhq/icons';
|
||||
|
||||
import './MQCommon.styles.scss';
|
||||
@@ -35,7 +35,7 @@ export function ComingSoon(): JSX.Element {
|
||||
}
|
||||
|
||||
export function SelectMaxTagPlaceholder(
|
||||
omittedValues: Partial<DefaultOptionType>[],
|
||||
omittedValues: Partial<ComboboxSimpleItem>[],
|
||||
): JSX.Element {
|
||||
return (
|
||||
<Tooltip title={omittedValues.map(({ value }) => value).join(', ')}>
|
||||
|
||||
@@ -18,7 +18,9 @@ import {
|
||||
RefreshCw,
|
||||
} from '@signozhq/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Checkbox, Select } from 'antd';
|
||||
// oxlint-disable-next-line signoz/no-antd-components This component for now is too complex to be migrated in one PR
|
||||
import { Select } from 'antd';
|
||||
import { Button, Checkbox } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import cx from 'classnames';
|
||||
import TextToolTip from 'components/TextToolTip/TextToolTip';
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
X,
|
||||
} from '@signozhq/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
// oxlint-disable-next-line signoz/no-antd-components This component for now is too complex to be migrated in one PR
|
||||
import { Select } from 'antd';
|
||||
import cx from 'classnames';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Select, Spin } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||
import { QueryKeyDataSuggestionsProps } from 'types/api/querySuggestions/types';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
@@ -13,48 +13,25 @@ interface ListViewOrderByProps {
|
||||
dataSource: DataSource;
|
||||
}
|
||||
|
||||
// Loader component for the dropdown when loading or no results
|
||||
function Loader({ isLoading }: { isLoading: boolean }): JSX.Element {
|
||||
return (
|
||||
<div className="order-by-loading-container">
|
||||
{isLoading ? <Spin size="default" /> : 'No results found'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ListViewOrderBy({
|
||||
value,
|
||||
onChange,
|
||||
dataSource,
|
||||
}: ListViewOrderByProps): JSX.Element {
|
||||
const [searchInput, setSearchInput] = useState('');
|
||||
const [debouncedInput, setDebouncedInput] = useState('');
|
||||
const [selectOptions, setSelectOptions] = useState<
|
||||
{ label: string; value: string }[]
|
||||
>([]);
|
||||
const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const [selectOptions, setSelectOptions] = useState<ComboboxSimpleItem[]>([]);
|
||||
|
||||
// Fetch key suggestions based on debounced input
|
||||
// Fetch key suggestions once; ComboboxSimple handles local filtering.
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ['orderByKeySuggestions', dataSource, debouncedInput],
|
||||
queryKey: ['orderByKeySuggestions', dataSource],
|
||||
queryFn: async () => {
|
||||
const response = await getKeySuggestions({
|
||||
signal: dataSource,
|
||||
searchText: debouncedInput,
|
||||
searchText: '',
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(
|
||||
() => (): void => {
|
||||
if (debounceTimer.current) {
|
||||
clearTimeout(debounceTimer.current);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
// Update options when API data changes
|
||||
useEffect(() => {
|
||||
const rawKeys: QueryKeyDataSuggestionsProps[] = data?.data?.keys
|
||||
@@ -62,52 +39,33 @@ function ListViewOrderBy({
|
||||
: [];
|
||||
|
||||
const keyNames = rawKeys.map((key) => key.name);
|
||||
const uniqueKeys = [
|
||||
...new Set(searchInput ? keyNames : ['timestamp', ...keyNames]),
|
||||
];
|
||||
const uniqueKeys = [...new Set(['timestamp', ...keyNames])];
|
||||
|
||||
const updatedOptions = uniqueKeys.flatMap((key) => [
|
||||
const updatedOptions: ComboboxSimpleItem[] = uniqueKeys.flatMap((key) => [
|
||||
{ label: `${key} (desc)`, value: `${key}:desc` },
|
||||
{ label: `${key} (asc)`, value: `${key}:asc` },
|
||||
]);
|
||||
|
||||
setSelectOptions(updatedOptions);
|
||||
}, [data, searchInput]);
|
||||
}, [data]);
|
||||
|
||||
// Handle search input with debounce
|
||||
const handleSearch = (input: string): void => {
|
||||
setSearchInput(input);
|
||||
|
||||
// Filter current options for instant client-side match
|
||||
const filteredOptions = selectOptions.filter((option) =>
|
||||
option.value.toLowerCase().includes(input.trim().toLowerCase()),
|
||||
);
|
||||
|
||||
// If no match found or input is empty, trigger debounced fetch
|
||||
if (filteredOptions.length === 0 || input === '') {
|
||||
if (debounceTimer.current) {
|
||||
clearTimeout(debounceTimer.current);
|
||||
}
|
||||
|
||||
debounceTimer.current = setTimeout(() => {
|
||||
setDebouncedInput(input);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
const handleChange = useMemo(
|
||||
() =>
|
||||
(val: string | string[]): void => {
|
||||
onChange(val as string);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<Select
|
||||
showSearch
|
||||
<ComboboxSimple
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onSearch={handleSearch}
|
||||
notFoundContent={<Loader isLoading={isLoading} />}
|
||||
onChange={handleChange}
|
||||
loading={isLoading}
|
||||
placeholder="Select a field"
|
||||
style={{ width: 200 }}
|
||||
options={selectOptions}
|
||||
filterOption={(input, option): boolean =>
|
||||
(option?.value ?? '').toLowerCase().includes(input.trim().toLowerCase())
|
||||
}
|
||||
items={selectOptions}
|
||||
emptyPlaceholder="No results found"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,37 @@
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
|
||||
--select-trigger-height: 2.25rem;
|
||||
--select-trigger-background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
);
|
||||
--select-trigger-border-color: var(
|
||||
--query-builder-v2-border-color,
|
||||
var(--l2-border)
|
||||
);
|
||||
|
||||
--combobox-trigger-height: 2.25rem;
|
||||
--combobox-trigger-padding: 7px var(--spacing-6);
|
||||
--combobox-trigger-background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
);
|
||||
--combobox-trigger-border-color: var(
|
||||
--query-builder-v2-border-color,
|
||||
var(--l2-border)
|
||||
);
|
||||
|
||||
[data-slot='combobox-trigger'],
|
||||
[data-slot='select-trigger'] {
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
}
|
||||
|
||||
[data-slot='combobox-placeholder'],
|
||||
[data-slot='select-placeholder'] {
|
||||
color: var(--query-builder-v2-placeholder-color, var(--l3-foreground));
|
||||
}
|
||||
|
||||
.qb-content-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -80,8 +111,8 @@
|
||||
width: 1px;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
var(--l1-border),
|
||||
var(--l1-border) 4px,
|
||||
var(--query-builder-v2-border-color, var(--l2-border)),
|
||||
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
@@ -101,7 +132,8 @@
|
||||
top: 12px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-left: 6px dotted var(--l1-border);
|
||||
border-left: 6px dotted
|
||||
var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
|
||||
/* Horizontal line pointing from vertical to the item */
|
||||
@@ -114,8 +146,8 @@
|
||||
height: 1px;
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
var(--l1-border),
|
||||
var(--l1-border) 4px,
|
||||
var(--query-builder-v2-border-color, var(--l2-border)),
|
||||
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
@@ -241,7 +273,8 @@
|
||||
top: 12px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-left: 6px dotted var(--l1-border);
|
||||
border-left: 6px dotted
|
||||
var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
|
||||
/* Horizontal line pointing from vertical to the item */
|
||||
@@ -254,8 +287,8 @@
|
||||
height: 1px;
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
var(--l1-border),
|
||||
var(--l1-border) 4px,
|
||||
var(--query-builder-v2-border-color, var(--l2-border)),
|
||||
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
@@ -273,6 +306,16 @@
|
||||
line-height: 16px; /* 128.571% */
|
||||
|
||||
resize: none;
|
||||
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
|
||||
&:placeholder {
|
||||
color: var(--query-builder-v2-placeholder-color, var(--l3-foreground));
|
||||
}
|
||||
}
|
||||
|
||||
.formula-legend {
|
||||
@@ -282,15 +325,30 @@
|
||||
.ant-input-group-addon {
|
||||
border-top-left-radius: 0px !important;
|
||||
border-top-right-radius: 0px !important;
|
||||
background: var(--l2-background);
|
||||
color: var(--l2-foreground);
|
||||
background: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
);
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
border-top-left-radius: 0px !important;
|
||||
border-top-right-radius: 0px !important;
|
||||
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
|
||||
&:placeholder {
|
||||
color: var(--query-builder-v2-placeholder-color, var(--l3-foreground));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,8 +381,8 @@
|
||||
width: 1px;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
var(--l1-border),
|
||||
var(--l1-border) 4px,
|
||||
var(--query-builder-v2-border-color, var(--l2-border)),
|
||||
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
@@ -395,8 +453,8 @@
|
||||
width: 1px;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
var(--l1-border),
|
||||
var(--l1-border) 4px,
|
||||
var(--query-builder-v2-border-color, var(--l2-border)),
|
||||
var(--query-builder-v2-border-color, var(--l2-border)) 4px,
|
||||
transparent 4px,
|
||||
transparent 8px
|
||||
);
|
||||
@@ -412,7 +470,7 @@
|
||||
min-width: 120px;
|
||||
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--l1-background);
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
|
||||
@@ -457,7 +515,7 @@
|
||||
|
||||
.ant-select-selector {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border) !important;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border)) !important;
|
||||
background: var(--l1-background) !important;
|
||||
height: 34px !important;
|
||||
box-sizing: border-box !important;
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
|
||||
.group-by-filter-container {
|
||||
min-width: 340px !important;
|
||||
--combobox-trigger-height: auto;
|
||||
}
|
||||
|
||||
.metrics-aggregation-section-content-item {
|
||||
@@ -146,17 +147,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metrics-operators-select {
|
||||
border-radius: 2px;
|
||||
border: 1.005px solid var(--l1-border);
|
||||
background: var(--l1-background);
|
||||
|
||||
color: var(--l1-foreground);
|
||||
font-family: 'Geist Mono';
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,6 @@ const MetricsAggregateSection = memo(function MetricsAggregateSection({
|
||||
value={queryAggregation.timeAggregation || ''}
|
||||
onChange={handleChangeOperator}
|
||||
operators={operators}
|
||||
className="metrics-operators-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
|
||||
--select-trigger-width: auto;
|
||||
|
||||
.ant-select-selection-search-input {
|
||||
font-size: 12px !important;
|
||||
line-height: 27px;
|
||||
line-height: 25px;
|
||||
&::placeholder {
|
||||
color: var(--l2-foreground) !important;
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
@@ -22,9 +24,9 @@
|
||||
.ant-select-selector {
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border) !important;
|
||||
background: var(--l1-background);
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border)) !important;
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
font-family: 'Geist Mono';
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
@@ -33,20 +35,23 @@
|
||||
min-height: 36px;
|
||||
|
||||
.ant-select-selection-placeholder {
|
||||
color: var(--l2-foreground) !important;
|
||||
color: var(
|
||||
--query-builder-v2-placeholder-color,
|
||||
var(--l3-foreground)
|
||||
) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select-dropdown {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l1-background);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
|
||||
backdrop-filter: blur(20px);
|
||||
|
||||
.ant-select-item {
|
||||
color: var(--l1-foreground);
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
font-family: 'Geist Mono';
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
@@ -55,12 +60,18 @@
|
||||
|
||||
&:hover,
|
||||
&.ant-select-item-option-active {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selected-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
}
|
||||
|
||||
&.ant-select-item-option-selected {
|
||||
background: var(--l3-background) !important;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(
|
||||
--query-builder-v2-selected-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { SelectSimple, type SelectSimpleItem } from '@signozhq/ui/select';
|
||||
import {
|
||||
initialQueriesMap,
|
||||
initialQueryMeterWithType,
|
||||
@@ -10,7 +10,6 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { SelectOption } from 'types/common/select';
|
||||
|
||||
import {
|
||||
getPreviousQueryFromKey,
|
||||
@@ -21,7 +20,7 @@ import {
|
||||
|
||||
import './MetricsSelect.styles.scss';
|
||||
|
||||
export const SOURCE_OPTIONS: SelectOption<string, string>[] = [
|
||||
export const SOURCE_OPTIONS: SelectSimpleItem[] = [
|
||||
{ value: 'metrics', label: 'Metrics' },
|
||||
{ value: 'meter', label: 'Meter' },
|
||||
];
|
||||
@@ -140,14 +139,14 @@ export const MetricsSelect = memo(function MetricsSelect({
|
||||
return (
|
||||
<div className="metrics-source-select-container">
|
||||
{signalSourceChangeEnabled && (
|
||||
<Select
|
||||
<SelectSimple
|
||||
className="source-selector"
|
||||
placeholder="Source"
|
||||
options={SOURCE_OPTIONS}
|
||||
items={SOURCE_OPTIONS}
|
||||
value={source}
|
||||
defaultValue="metrics"
|
||||
data-testid={`metrics-source-selector-${index}`}
|
||||
onChange={handleSignalSourceChange}
|
||||
testId={`metrics-source-selector-${index}`}
|
||||
onChange={(value): void => handleSignalSourceChange(value as string)}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -22,34 +22,35 @@
|
||||
font-style: normal;
|
||||
font-weight: var(--font-weight-normal);
|
||||
|
||||
color: var(--l2-foreground);
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
}
|
||||
|
||||
.tab {
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
border-left: none;
|
||||
min-width: 120px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
|
||||
&:first-child {
|
||||
border-left: 1px solid var(--l1-border);
|
||||
border-left: 1px solid
|
||||
var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
}
|
||||
|
||||
.tab::before {
|
||||
background: var(--l1-border);
|
||||
background: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
|
||||
.selected-view {
|
||||
color: var(--text-robin-500);
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected-view::before {
|
||||
background: var(--l1-border);
|
||||
background: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@
|
||||
height: 30px;
|
||||
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--l3-background);
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@@ -71,10 +72,13 @@
|
||||
align-items: center;
|
||||
|
||||
.having-filter-select-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
padding-right: 38px;
|
||||
|
||||
.having-filter-select-editor {
|
||||
border-radius: 2px;
|
||||
@@ -99,15 +103,17 @@
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
border-left-width: 0px;
|
||||
border-right-width: 0px;
|
||||
padding: 0px !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,17 +217,32 @@
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
line-height: 36px !important;
|
||||
min-height: 34px;
|
||||
line-height: 32px !important;
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
|
||||
&,
|
||||
.ͼ1a {
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
@@ -230,8 +251,11 @@
|
||||
}
|
||||
|
||||
.chip-decorator {
|
||||
background: var(--l3-background) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
background: var(
|
||||
--query-builder-v2-chip-decorator-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
|
||||
border-radius: 4px;
|
||||
padding: 2px 4px;
|
||||
margin-right: 4px;
|
||||
@@ -239,24 +263,36 @@
|
||||
}
|
||||
|
||||
.cm-selectionBackground {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
.cm-activeLine > span {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.cm-placeholder {
|
||||
color: var(
|
||||
--query-builder-v2-placeholder-color,
|
||||
var(--l3-foreground)
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid var(--l2-border);
|
||||
background: var(--l2-background);
|
||||
height: 38px;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
height: 100%;
|
||||
width: 38px;
|
||||
|
||||
border-left: transparent;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 12px;
|
||||
color: var(--l2-foreground) !important;
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
|
||||
|
||||
&.error {
|
||||
.cm-editor {
|
||||
@@ -51,14 +51,15 @@
|
||||
|
||||
.cm-content {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
padding: 0px !important;
|
||||
background-color: var(--l1-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@
|
||||
right: 0px !important;
|
||||
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: linear-gradient(
|
||||
139deg,
|
||||
color-mix(in srgb, var(--card) 80%, transparent) 0%,
|
||||
@@ -118,7 +119,7 @@
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
color: var(--l2-foreground) !important;
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
|
||||
.cm-completionIcon {
|
||||
@@ -127,7 +128,10 @@
|
||||
|
||||
&:hover,
|
||||
&[aria-selected='true'] {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
@@ -142,15 +146,24 @@
|
||||
.cm-line {
|
||||
line-height: 36px !important;
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
|
||||
::-moz-selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
@@ -159,8 +172,11 @@
|
||||
}
|
||||
|
||||
.chip-decorator {
|
||||
background: var(--l3-background) !important;
|
||||
color: var(--l1-foreground) !important;
|
||||
background: var(
|
||||
--query-builder-v2-chip-decorator-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
color: var(--query-builder-v2-color, var(--l1-foreground)) !important;
|
||||
border-radius: 4px;
|
||||
padding: 2px 4px;
|
||||
margin-right: 4px;
|
||||
@@ -168,7 +184,10 @@
|
||||
}
|
||||
|
||||
.cm-selectionBackground {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
}
|
||||
@@ -201,12 +220,11 @@
|
||||
|
||||
.close-btn {
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l1-background);
|
||||
height: 38px;
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
height: 100%;
|
||||
width: 38px;
|
||||
|
||||
border-left: transparent;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
}
|
||||
@@ -217,13 +235,13 @@
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--l1-foreground);
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +258,7 @@
|
||||
input {
|
||||
max-width: 120px;
|
||||
&::placeholder {
|
||||
color: var(--l2-foreground);
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,8 +269,8 @@
|
||||
|
||||
.query-aggregation-error-popover {
|
||||
.ant-popover-inner {
|
||||
background-color: var(--l1-border);
|
||||
border: 1px solid var(--l1-border);
|
||||
background-color: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.add-trace-operator-button,
|
||||
.add-new-query-button,
|
||||
.add-formula-button {
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l2-background);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
background: var(--query-builder-v2-background-color, var(--l2-background));
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@@ -34,11 +34,14 @@
|
||||
.query-status-container {
|
||||
width: 32px;
|
||||
|
||||
background-color: var(--l1-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
border-radius: 2px;
|
||||
border-top-left-radius: 0px !important;
|
||||
border-bottom-left-radius: 0px !important;
|
||||
@@ -77,16 +80,16 @@
|
||||
|
||||
.cm-content {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
padding: 0px !important;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
}
|
||||
|
||||
&.cm-focused {
|
||||
outline: 1px solid var(--l1-border);
|
||||
outline: 1px solid var(--query-builder-v2-border-color, var(--l2-border));
|
||||
}
|
||||
|
||||
.cm-tooltip-autocomplete {
|
||||
@@ -148,11 +151,17 @@
|
||||
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
|
||||
background-color: var(--l1-background) !important;
|
||||
color: var(--l2-foreground) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground)) !important;
|
||||
|
||||
&:hover {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
}
|
||||
|
||||
.cm-completionIcon {
|
||||
@@ -160,7 +169,10 @@
|
||||
}
|
||||
|
||||
&[aria-selected='true'] {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
@@ -172,25 +184,49 @@
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
line-height: 34px !important;
|
||||
line-height: 36px !important;
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
background-color: var(
|
||||
--query-builder-v2-background-color,
|
||||
var(--l2-background)
|
||||
) !important;
|
||||
|
||||
&,
|
||||
.ͼ1a {
|
||||
color: var(--query-builder-v2-color, var(--l2-foreground));
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-selectionBackground {
|
||||
background: var(--l3-background) !important;
|
||||
background: var(
|
||||
--query-builder-v2-selection-background-color,
|
||||
var(--l3-background)
|
||||
) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
.cm-placeholder {
|
||||
color: var(
|
||||
--query-builder-v2-placeholder-color,
|
||||
var(--l3-foreground)
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cursor-position {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { CircleAlert, RefreshCw } from '@signozhq/icons';
|
||||
import { Checkbox, Select } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useListRoles } from 'api/generated/services/role';
|
||||
import type { AuthtypesRoleDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import cx from 'classnames';
|
||||
import APIError from 'types/api/error';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import './RolesSelect.styles.scss';
|
||||
|
||||
@@ -74,7 +73,6 @@ interface BaseProps {
|
||||
id?: string;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
getPopupContainer?: (trigger: HTMLElement) => HTMLElement;
|
||||
roles?: AuthtypesRoleDTO[];
|
||||
loading?: boolean;
|
||||
isError?: boolean;
|
||||
@@ -112,14 +110,13 @@ function RolesSelect(props: RolesSelectProps): JSX.Element {
|
||||
});
|
||||
|
||||
const roles = externalRoles ?? data?.data ?? [];
|
||||
const options = getRoleOptions(roles);
|
||||
const items: ComboboxSimpleItem[] = getRoleOptions(roles);
|
||||
|
||||
const {
|
||||
mode,
|
||||
id,
|
||||
placeholder = 'Select role',
|
||||
className,
|
||||
getPopupContainer = popupContainer,
|
||||
loading = internalLoading,
|
||||
isError = internalError,
|
||||
error = convertToApiError(internalErrorObj),
|
||||
@@ -127,55 +124,47 @@ function RolesSelect(props: RolesSelectProps): JSX.Element {
|
||||
disabled,
|
||||
} = props;
|
||||
|
||||
const notFoundContent = isError ? (
|
||||
<ErrorContent error={error} onRefetch={onRefetch} />
|
||||
) : undefined;
|
||||
const emptyPlaceholder = isError
|
||||
? error?.message || 'Failed to load roles'
|
||||
: 'No roles available';
|
||||
|
||||
if (mode === 'multiple') {
|
||||
const { value = [], onChange } = props as MultipleProps;
|
||||
return (
|
||||
<Select
|
||||
id={id}
|
||||
mode="multiple"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
className={cx('roles-select', className)}
|
||||
loading={loading}
|
||||
notFoundContent={notFoundContent}
|
||||
options={options}
|
||||
optionFilterProp="label"
|
||||
optionRender={(option): JSX.Element => (
|
||||
<Checkbox
|
||||
checked={value.includes(option.value as string)}
|
||||
style={{ pointerEvents: 'none' }}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
)}
|
||||
getPopupContainer={getPopupContainer}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<>
|
||||
<ComboboxSimple
|
||||
id={id}
|
||||
multiple
|
||||
value={value}
|
||||
onChange={(v): void => onChange?.(v as string[])}
|
||||
placeholder={placeholder}
|
||||
className={cx('roles-select', className)}
|
||||
loading={loading}
|
||||
emptyPlaceholder={emptyPlaceholder}
|
||||
items={items}
|
||||
style={disabled ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
||||
/>
|
||||
{isError && <ErrorContent error={error} onRefetch={onRefetch} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const { value, onChange, allowClear = true } = props as SingleProps;
|
||||
const { value, onChange } = props as SingleProps;
|
||||
return (
|
||||
<Select
|
||||
id={id}
|
||||
showSearch
|
||||
value={value || undefined}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
allowClear={allowClear}
|
||||
className={cx('roles-single-select', className)}
|
||||
loading={loading}
|
||||
notFoundContent={notFoundContent}
|
||||
options={options}
|
||||
optionFilterProp="label"
|
||||
getPopupContainer={getPopupContainer}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<>
|
||||
<ComboboxSimple
|
||||
id={id}
|
||||
value={value || undefined}
|
||||
onChange={(v): void => onChange?.((v as string) || undefined)}
|
||||
placeholder={placeholder}
|
||||
className={cx('roles-single-select', className)}
|
||||
loading={loading}
|
||||
emptyPlaceholder={emptyPlaceholder}
|
||||
items={items}
|
||||
style={disabled ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
||||
/>
|
||||
{isError && <ErrorContent error={error} onRefetch={onRefetch} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -308,7 +308,9 @@ function TanStackTableInner<TData>(
|
||||
});
|
||||
|
||||
const hasSingleColumn = useMemo(
|
||||
() => effectiveColumns.filter((c) => !c.pin).length <= 1,
|
||||
() =>
|
||||
effectiveColumns.filter((c) => !c.pin && c.enableRemove !== false).length <=
|
||||
1,
|
||||
[effectiveColumns],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { useMemo } from 'react';
|
||||
import { SolidAlertTriangle } from '@signozhq/icons';
|
||||
import { Select, Tooltip } from 'antd';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import {
|
||||
ComboboxSimple,
|
||||
ComboboxSimpleGroup,
|
||||
ComboboxSimpleItem,
|
||||
} from '@signozhq/ui/combobox';
|
||||
import { Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { UniversalYAxisUnitMappings } from './constants';
|
||||
@@ -42,69 +46,53 @@ function YAxisUnitSelector({
|
||||
return '';
|
||||
}, [initialValue, value, loading]);
|
||||
|
||||
const handleSearch = (
|
||||
searchTerm: string,
|
||||
currentOption: DefaultOptionType | undefined,
|
||||
): boolean => {
|
||||
if (!currentOption?.value) {
|
||||
return false;
|
||||
}
|
||||
const categoriesToRender = useMemo(
|
||||
() => categoriesOverride || getYAxisCategories(source),
|
||||
[categoriesOverride, source],
|
||||
);
|
||||
|
||||
const search = searchTerm.toLowerCase();
|
||||
const unitId = currentOption.value.toString().toLowerCase();
|
||||
const unitLabel = currentOption.children?.toString().toLowerCase() || '';
|
||||
const groups: ComboboxSimpleGroup[] = useMemo(
|
||||
() =>
|
||||
categoriesToRender.map((category) => ({
|
||||
heading: category.name,
|
||||
items: category.units.map((unit): ComboboxSimpleItem => {
|
||||
const aliases = Array.from(
|
||||
UniversalYAxisUnitMappings[unit.id as UniversalYAxisUnit] ?? [],
|
||||
);
|
||||
return {
|
||||
value: unit.id,
|
||||
label: unit.name,
|
||||
keywords: aliases,
|
||||
};
|
||||
}),
|
||||
})),
|
||||
[categoriesToRender],
|
||||
);
|
||||
|
||||
// Check label and id
|
||||
if (unitId.includes(search) || unitLabel.includes(search)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check aliases (from the mapping) using array iteration
|
||||
const aliases = Array.from(
|
||||
UniversalYAxisUnitMappings[currentOption.value as UniversalYAxisUnit] ?? [],
|
||||
);
|
||||
|
||||
return aliases.some((alias) => alias.toLowerCase().includes(search));
|
||||
const handleChange = (val: string | string[]): void => {
|
||||
onChange(val as UniversalYAxisUnit);
|
||||
};
|
||||
|
||||
const categoriesToRender = useMemo(() => {
|
||||
return categoriesOverride || getYAxisCategories(source);
|
||||
}, [categoriesOverride, source]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('y-axis-unit-selector-component', containerClassName)}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
value={universalUnit}
|
||||
onChange={onChange}
|
||||
<ComboboxSimple
|
||||
value={universalUnit ?? undefined}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
filterOption={(input, option): boolean => handleSearch(input, option)}
|
||||
loading={loading}
|
||||
suffixIcon={
|
||||
incompatibleUnitMessage ? (
|
||||
<Tooltip title={incompatibleUnitMessage}>
|
||||
<SolidAlertTriangle role="img" aria-label="warning" size="md" />
|
||||
</Tooltip>
|
||||
) : undefined
|
||||
}
|
||||
className={classNames({
|
||||
'warning-state': incompatibleUnitMessage,
|
||||
'warning-state': !!incompatibleUnitMessage,
|
||||
})}
|
||||
data-testid={dataTestId}
|
||||
allowClear
|
||||
>
|
||||
{categoriesToRender.map((category) => (
|
||||
<Select.OptGroup key={category.name} label={category.name}>
|
||||
{category.units.map((unit) => (
|
||||
<Select.Option key={unit.id} value={unit.id}>
|
||||
{unit.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select.OptGroup>
|
||||
))}
|
||||
</Select>
|
||||
testId={dataTestId}
|
||||
groups={groups}
|
||||
/>
|
||||
{incompatibleUnitMessage && (
|
||||
<Tooltip title={incompatibleUnitMessage}>
|
||||
<SolidAlertTriangle role="img" aria-label="warning" size="md" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
.y-axis-unit-selector-component {
|
||||
.ant-select {
|
||||
--combobox-trigger-background-color: var(--l2-background);
|
||||
--combobox-trigger-border-color: var(--l2-border);
|
||||
|
||||
[data-slot='combobox-trigger'] {
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import {
|
||||
@@ -115,11 +115,11 @@ function AllEndPoints({
|
||||
|
||||
// --- GROUP BY STATE SYNC (existing) ---
|
||||
const handleGroupByChange = useCallback(
|
||||
(value: IBuilderQuery['groupBy']) => {
|
||||
(value: string[]) => {
|
||||
const newGroupBy = [];
|
||||
|
||||
for (let index = 0; index < value.length; index++) {
|
||||
const element = value[index] as unknown as string;
|
||||
const element = value[index];
|
||||
|
||||
// Check if the key exists in our cached options first
|
||||
if (allAvailableGroupByOptions[element]) {
|
||||
@@ -242,17 +242,14 @@ function AllEndPoints({
|
||||
</div>
|
||||
<div className="group-by-container">
|
||||
<div className="group-by-label"> Group by </div>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
className="group-by-select"
|
||||
loading={isLoadingGroupByFilters}
|
||||
mode="multiple"
|
||||
value={groupBy}
|
||||
allowClear
|
||||
maxTagCount="responsive"
|
||||
multiple
|
||||
value={groupBy.map((g) => g.key)}
|
||||
placeholder="Search for attribute"
|
||||
options={groupByOptions}
|
||||
onChange={handleGroupByChange}
|
||||
onSearch={(value: string): void => setGroupBySearchValue(value)}
|
||||
items={groupByOptions}
|
||||
onChange={(value): void => handleGroupByChange(value as string[])}
|
||||
/>{' '}
|
||||
</div>
|
||||
<div className="endpoints-table-container">
|
||||
|
||||
@@ -211,14 +211,14 @@
|
||||
|
||||
.group-by-label {
|
||||
display: flex;
|
||||
padding: 6px 15px;
|
||||
padding: 4px 15px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--l2-border);
|
||||
border-right: none;
|
||||
background: var(--l3-background);
|
||||
|
||||
@@ -227,18 +227,15 @@
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
line-height: 22px;
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
.group-by-select {
|
||||
width: 100%;
|
||||
.ant-select-selector {
|
||||
font-size: 14px;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l3-background);
|
||||
}
|
||||
box-sizing: border-box;
|
||||
|
||||
--combobox-trigger-border-radius: 0px;
|
||||
}
|
||||
}
|
||||
// Add border-bottom to table cells when pagination is not present
|
||||
@@ -461,14 +458,13 @@
|
||||
}
|
||||
|
||||
.endpoint-details-filters-container-dropdown {
|
||||
width: 120px;
|
||||
width: 150px;
|
||||
border-right: 1px solid var(--l1-border);
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ant-select-single {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
--combobox-trigger-border-color: transparent;
|
||||
}
|
||||
|
||||
.endpoint-details-filters-container-search {
|
||||
|
||||
@@ -263,7 +263,6 @@ function EndPointDetails({
|
||||
setSelectedEndPointName={setSelectedEndPointName}
|
||||
endPointDropDownDataQuery={endPointDropDownDataQuery}
|
||||
parentContainerDiv=".endpoint-details-filters-container"
|
||||
dropdownStyle={{ width: 'calc(100% - 36px)' }}
|
||||
/>
|
||||
</div>
|
||||
<div className="endpoint-details-filters-container-search">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { Select } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { getFormattedEndPointDropDownData } from 'container/ApiMonitoring/utils';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
|
||||
@@ -22,40 +22,33 @@ function EndPointsDropDown({
|
||||
selectedEndPointName,
|
||||
setSelectedEndPointName,
|
||||
endPointDropDownDataQuery,
|
||||
parentContainerDiv,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
parentContainerDiv: _parentContainerDiv,
|
||||
dropdownStyle,
|
||||
}: EndPointsDropDownProps): JSX.Element {
|
||||
const { data, isLoading, isFetching } = endPointDropDownDataQuery;
|
||||
|
||||
const handleChange = (value: string): void => {
|
||||
setSelectedEndPointName(value);
|
||||
const handleChange = (value: string | string[]): void => {
|
||||
setSelectedEndPointName(value as string);
|
||||
};
|
||||
|
||||
const formattedData = useMemo(
|
||||
() =>
|
||||
getFormattedEndPointDropDownData(data?.payload.data.result[0].table.rows),
|
||||
getFormattedEndPointDropDownData(
|
||||
data?.payload.data.result[0].table.rows,
|
||||
) as ComboboxSimpleItem[],
|
||||
[data?.payload.data.result],
|
||||
);
|
||||
|
||||
return (
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
value={selectedEndPointName || undefined}
|
||||
placeholder="Select endpoint"
|
||||
loading={isLoading || isFetching}
|
||||
style={{ width: '100%' }}
|
||||
style={{ width: '100%', ...dropdownStyle }}
|
||||
onChange={handleChange}
|
||||
options={formattedData}
|
||||
getPopupContainer={
|
||||
parentContainerDiv
|
||||
? (): HTMLElement =>
|
||||
document.querySelector(parentContainerDiv) as HTMLElement
|
||||
: (triggerNode): HTMLElement => triggerNode.parentNode as HTMLElement
|
||||
}
|
||||
dropdownStyle={dropdownStyle}
|
||||
allowClear
|
||||
onClear={(): void => {
|
||||
setSelectedEndPointName('');
|
||||
}}
|
||||
items={formattedData}
|
||||
virtualized
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
import { ChevronLeft, ChevronRight } from '@signozhq/icons';
|
||||
import { Button, Flex, Select } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { DEFAULT_PER_PAGE_OPTIONS, Pagination } from 'hooks/queryPagination';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { defaultSelectStyle } from './config';
|
||||
import { Container } from './styles';
|
||||
@@ -59,20 +59,18 @@ function Controls({
|
||||
</Button>
|
||||
|
||||
{showSizeChanger && (
|
||||
<Select<Pagination['limit']>
|
||||
<SelectSimple
|
||||
style={defaultSelectStyle}
|
||||
loading={isLoading}
|
||||
value={countPerPage}
|
||||
onChange={handleCountItemsPerPageChange}
|
||||
getPopupContainer={popupContainer}
|
||||
>
|
||||
{perPageOptions.map((count) => (
|
||||
<Select.Option
|
||||
key={count}
|
||||
value={count}
|
||||
>{`${count} / page`}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
disabled={isLoading}
|
||||
value={String(countPerPage)}
|
||||
onChange={(value): void =>
|
||||
handleCountItemsPerPageChange(Number(value) as Pagination['limit'])
|
||||
}
|
||||
items={perPageOptions.map((count) => ({
|
||||
value: String(count),
|
||||
label: `${count} / page`,
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -61,10 +61,6 @@
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
&:not(:first-of-type) {
|
||||
margin-left: 24px !important;
|
||||
}
|
||||
|
||||
[aria-selected='false'] {
|
||||
.periscope-tab {
|
||||
color: var(--l2-foreground);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Button, Select, Tooltip } from 'antd';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import classNames from 'classnames';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
@@ -231,15 +232,18 @@ function AlertThreshold({
|
||||
<Typography.Text className="sentence-text">
|
||||
Send a notification when
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={thresholdState.selectedQuery}
|
||||
onChange={handleSelectedQueryChange}
|
||||
onChange={(value): void => handleSelectedQueryChange(value as string)}
|
||||
style={{ width: 80 }}
|
||||
options={queryNames}
|
||||
items={queryNames.map((q) => ({
|
||||
value: String(q.value),
|
||||
label: q.label as React.ReactNode,
|
||||
}))}
|
||||
data-testid="alert-threshold-query-select"
|
||||
/>
|
||||
<Typography.Text className="sentence-text">is</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={
|
||||
(normalizeOperator(thresholdState.operator) ??
|
||||
thresholdState.operator) as AlertThresholdOperator
|
||||
@@ -247,17 +251,17 @@ function AlertThreshold({
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_OPERATOR',
|
||||
payload: value,
|
||||
payload: value as AlertThresholdOperator,
|
||||
});
|
||||
}}
|
||||
style={{ width: 180 }}
|
||||
options={THRESHOLD_OPERATOR_OPTIONS}
|
||||
items={THRESHOLD_OPERATOR_OPTIONS}
|
||||
data-testid="alert-threshold-operator-select"
|
||||
/>
|
||||
<Typography.Text className="sentence-text">
|
||||
the threshold(s)
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={
|
||||
(normalizeMatchType(thresholdState.matchType) ??
|
||||
thresholdState.matchType) as AlertThresholdMatchType
|
||||
@@ -265,11 +269,11 @@ function AlertThreshold({
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_MATCH_TYPE',
|
||||
payload: value,
|
||||
payload: value as AlertThresholdMatchType,
|
||||
});
|
||||
}}
|
||||
style={{ width: 180 }}
|
||||
options={matchTypeOptionsWithTooltips}
|
||||
items={matchTypeOptionsWithTooltips}
|
||||
data-testid="alert-threshold-match-type-select"
|
||||
/>
|
||||
<Typography.Text className="sentence-text">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
|
||||
import { useCreateAlertState } from '../context';
|
||||
import {
|
||||
@@ -18,19 +18,13 @@ import {
|
||||
} from '../context/types';
|
||||
import { normalizeMatchType, normalizeOperator } from '../utils';
|
||||
import { AnomalyAndThresholdProps } from './types';
|
||||
import {
|
||||
getQueryNames,
|
||||
NotificationChannelsNotFoundContent,
|
||||
RoutingPolicyBanner,
|
||||
} from './utils';
|
||||
import { getQueryNames, RoutingPolicyBanner } from './utils';
|
||||
|
||||
function AnomalyThreshold({
|
||||
channels,
|
||||
isLoadingChannels,
|
||||
isErrorChannels,
|
||||
refreshChannels,
|
||||
}: AnomalyAndThresholdProps): JSX.Element {
|
||||
const { user } = useAppContext();
|
||||
const {
|
||||
thresholdState,
|
||||
setThresholdState,
|
||||
@@ -42,13 +36,14 @@ function AnomalyThreshold({
|
||||
|
||||
const queryNames = getQueryNames(currentQuery);
|
||||
|
||||
const deviationOptions = useMemo(() => {
|
||||
const options = [];
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
options.push({ label: i.toString(), value: i });
|
||||
}
|
||||
return options;
|
||||
}, []);
|
||||
const deviationOptions = useMemo(
|
||||
() =>
|
||||
Array.from({ length: 7 }, (_, i) => ({
|
||||
label: (i + 1).toString(),
|
||||
value: (i + 1).toString(),
|
||||
})),
|
||||
[],
|
||||
);
|
||||
|
||||
const updateThreshold = (
|
||||
id: string,
|
||||
@@ -71,16 +66,16 @@ function AnomalyThreshold({
|
||||
<Typography.Text data-testid="notification-text" className="sentence-text">
|
||||
Send notification when the observed value for
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={thresholdState.selectedQuery}
|
||||
data-testid="query-select"
|
||||
testId="query-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_SELECTED_QUERY',
|
||||
payload: value,
|
||||
payload: value as string,
|
||||
});
|
||||
}}
|
||||
options={queryNames}
|
||||
items={queryNames}
|
||||
/>
|
||||
<Typography.Text
|
||||
data-testid="evaluation-window-text"
|
||||
@@ -88,16 +83,16 @@ function AnomalyThreshold({
|
||||
>
|
||||
during the last
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={thresholdState.evaluationWindow}
|
||||
data-testid="evaluation-window-select"
|
||||
testId="evaluation-window-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_EVALUATION_WINDOW',
|
||||
payload: value,
|
||||
payload: value as string,
|
||||
});
|
||||
}}
|
||||
options={ANOMALY_TIME_DURATION_OPTIONS}
|
||||
items={ANOMALY_TIME_DURATION_OPTIONS}
|
||||
/>
|
||||
</div>
|
||||
<div className="alert-condition-sentence">
|
||||
@@ -105,34 +100,34 @@ function AnomalyThreshold({
|
||||
<Typography.Text data-testid="threshold-text" className="sentence-text">
|
||||
is
|
||||
</Typography.Text>
|
||||
<Select
|
||||
value={thresholdState.thresholds[0].thresholdValue}
|
||||
data-testid="threshold-value-select"
|
||||
<SelectSimple
|
||||
value={thresholdState.thresholds[0].thresholdValue?.toString()}
|
||||
testId="threshold-value-select"
|
||||
onChange={(value): void => {
|
||||
updateThreshold(
|
||||
thresholdState.thresholds[0].id,
|
||||
'thresholdValue',
|
||||
value.toString(),
|
||||
(value as string).toString(),
|
||||
);
|
||||
}}
|
||||
options={deviationOptions}
|
||||
items={deviationOptions}
|
||||
/>
|
||||
<Typography.Text data-testid="deviations-text" className="sentence-text">
|
||||
deviations
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={
|
||||
(normalizeOperator(thresholdState.operator) ??
|
||||
thresholdState.operator) as AlertThresholdOperator
|
||||
}
|
||||
data-testid="operator-select"
|
||||
testId="operator-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_OPERATOR',
|
||||
payload: value,
|
||||
payload: value as AlertThresholdOperator,
|
||||
});
|
||||
}}
|
||||
options={ANOMALY_THRESHOLD_OPERATOR_OPTIONS}
|
||||
items={ANOMALY_THRESHOLD_OPERATOR_OPTIONS}
|
||||
/>
|
||||
<Typography.Text
|
||||
data-testid="predicted-data-text"
|
||||
@@ -140,19 +135,19 @@ function AnomalyThreshold({
|
||||
>
|
||||
the predicted data
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={
|
||||
(normalizeMatchType(thresholdState.matchType) ??
|
||||
thresholdState.matchType) as AlertThresholdMatchType
|
||||
}
|
||||
data-testid="match-type-select"
|
||||
testId="match-type-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_MATCH_TYPE',
|
||||
payload: value,
|
||||
payload: value as AlertThresholdMatchType,
|
||||
});
|
||||
}}
|
||||
options={ANOMALY_THRESHOLD_MATCH_TYPE_OPTIONS}
|
||||
items={ANOMALY_THRESHOLD_MATCH_TYPE_OPTIONS}
|
||||
/>
|
||||
</div>
|
||||
{/* Sentence 3 */}
|
||||
@@ -160,16 +155,16 @@ function AnomalyThreshold({
|
||||
<Typography.Text data-testid="using-the-text" className="sentence-text">
|
||||
using the
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={thresholdState.algorithm}
|
||||
data-testid="algorithm-select"
|
||||
testId="algorithm-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_ALGORITHM',
|
||||
payload: value,
|
||||
payload: value as string,
|
||||
});
|
||||
}}
|
||||
options={ANOMALY_ALGORITHM_OPTIONS}
|
||||
items={ANOMALY_ALGORITHM_OPTIONS}
|
||||
/>
|
||||
<Typography.Text
|
||||
data-testid="algorithm-with-text"
|
||||
@@ -177,16 +172,16 @@ function AnomalyThreshold({
|
||||
>
|
||||
algorithm with
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={thresholdState.seasonality}
|
||||
data-testid="seasonality-select"
|
||||
testId="seasonality-select"
|
||||
onChange={(value): void => {
|
||||
setThresholdState({
|
||||
type: 'SET_SEASONALITY',
|
||||
payload: value,
|
||||
payload: value as string,
|
||||
});
|
||||
}}
|
||||
options={ANOMALY_SEASONALITY_OPTIONS}
|
||||
items={ANOMALY_SEASONALITY_OPTIONS}
|
||||
/>
|
||||
{notificationSettings.routingPolicies ? (
|
||||
<>
|
||||
@@ -196,35 +191,25 @@ function AnomalyThreshold({
|
||||
>
|
||||
seasonality to
|
||||
</Typography.Text>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
value={thresholdState.thresholds[0].channels}
|
||||
onChange={(value): void =>
|
||||
updateThreshold(thresholdState.thresholds[0].id, 'channels', value)
|
||||
updateThreshold(
|
||||
thresholdState.thresholds[0].id,
|
||||
'channels',
|
||||
value as string[],
|
||||
)
|
||||
}
|
||||
style={{ width: 350 }}
|
||||
options={channels.map((channel) => ({
|
||||
items={channels.map((channel) => ({
|
||||
value: channel.id,
|
||||
label: channel.name,
|
||||
}))}
|
||||
mode="multiple"
|
||||
multiple
|
||||
placeholder="Select notification channels"
|
||||
showSearch
|
||||
maxTagCount={2}
|
||||
maxTagPlaceholder={(omittedValues): string =>
|
||||
`+${omittedValues.length} more`
|
||||
}
|
||||
maxTagTextLength={10}
|
||||
filterOption={(input, option): boolean =>
|
||||
option?.label?.toLowerCase().includes(input.toLowerCase()) || false
|
||||
}
|
||||
status={isErrorChannels ? 'error' : undefined}
|
||||
disabled={isLoadingChannels}
|
||||
notFoundContent={
|
||||
<NotificationChannelsNotFoundContent
|
||||
user={user}
|
||||
refreshChannels={refreshChannels}
|
||||
/>
|
||||
}
|
||||
loading={isLoadingChannels}
|
||||
className={isErrorChannels ? 'error' : undefined}
|
||||
emptyPlaceholder="No channels found"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Button, Input, Select, Tooltip } from 'antd';
|
||||
import { Button, Input, Tooltip } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { CircleX, Trash } from '@signozhq/icons';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
|
||||
import { useCreateAlertState } from '../context';
|
||||
import { AlertThresholdOperator } from '../context/types';
|
||||
import { normalizeOperator } from '../utils';
|
||||
import { ThresholdItemProps } from './types';
|
||||
import { NotificationChannelsNotFoundContent } from './utils';
|
||||
|
||||
function ThresholdItem({
|
||||
threshold,
|
||||
@@ -18,36 +18,38 @@ function ThresholdItem({
|
||||
channels,
|
||||
units,
|
||||
isErrorChannels,
|
||||
refreshChannels,
|
||||
isLoadingChannels,
|
||||
}: ThresholdItemProps): JSX.Element {
|
||||
const { user } = useAppContext();
|
||||
const { thresholdState, notificationSettings } = useCreateAlertState();
|
||||
const [showRecoveryThreshold, setShowRecoveryThreshold] = useState(false);
|
||||
|
||||
const yAxisUnitSelect = useMemo(() => {
|
||||
let component = (
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="Unit"
|
||||
value={threshold.unit ? threshold.unit : null}
|
||||
onChange={(value): void => updateThreshold(threshold.id, 'unit', value)}
|
||||
value={threshold.unit ? threshold.unit : undefined}
|
||||
onChange={(value): void =>
|
||||
updateThreshold(threshold.id, 'unit', value as string)
|
||||
}
|
||||
style={{ width: 150 }}
|
||||
options={units}
|
||||
items={units}
|
||||
disabled={units.length === 0}
|
||||
data-testid="threshold-unit-select"
|
||||
testId="threshold-unit-select"
|
||||
/>
|
||||
);
|
||||
if (units.length === 0) {
|
||||
component = (
|
||||
<Tooltip trigger="hover" title="No compatible units available">
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="Unit"
|
||||
value={threshold.unit ? threshold.unit : null}
|
||||
onChange={(value): void => updateThreshold(threshold.id, 'unit', value)}
|
||||
value={threshold.unit ? threshold.unit : undefined}
|
||||
onChange={(value): void =>
|
||||
updateThreshold(threshold.id, 'unit', value as string)
|
||||
}
|
||||
style={{ width: 150 }}
|
||||
options={units}
|
||||
items={units}
|
||||
disabled={units.length === 0}
|
||||
data-testid="threshold-unit-select"
|
||||
testId="threshold-unit-select"
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -117,37 +119,22 @@ function ThresholdItem({
|
||||
{!notificationSettings.routingPolicies && (
|
||||
<>
|
||||
<Typography.Text className="sentence-text">send to</Typography.Text>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
value={threshold.channels}
|
||||
onChange={(value): void =>
|
||||
updateThreshold(threshold.id, 'channels', value)
|
||||
updateThreshold(threshold.id, 'channels', value as string[])
|
||||
}
|
||||
data-testid="threshold-notification-channel-select"
|
||||
testId="threshold-notification-channel-select"
|
||||
style={{ width: 350 }}
|
||||
options={channels.map((channel) => ({
|
||||
items={channels.map((channel) => ({
|
||||
value: channel.name,
|
||||
label: channel.name,
|
||||
'data-testid': `threshold-notification-channel-option-${threshold.label}`,
|
||||
}))}
|
||||
mode="multiple"
|
||||
multiple
|
||||
placeholder="Select notification channels"
|
||||
showSearch
|
||||
maxTagCount={2}
|
||||
maxTagPlaceholder={(omittedValues): string =>
|
||||
`+${omittedValues.length} more`
|
||||
}
|
||||
maxTagTextLength={10}
|
||||
filterOption={(input, option): boolean =>
|
||||
option?.label?.toLowerCase().includes(input.toLowerCase()) || false
|
||||
}
|
||||
status={isErrorChannels ? 'error' : undefined}
|
||||
disabled={isLoadingChannels}
|
||||
notFoundContent={
|
||||
<NotificationChannelsNotFoundContent
|
||||
user={user}
|
||||
refreshChannels={refreshChannels}
|
||||
/>
|
||||
}
|
||||
loading={isLoadingChannels}
|
||||
className={isErrorChannels ? 'error' : undefined}
|
||||
emptyPlaceholder="No channels found"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { createMockAlertContextState } from 'container/CreateAlertV2/EvaluationSettings/__tests__/testUtils';
|
||||
import { getAppContextMockState } from 'container/RoutingPolicies/__tests__/testUtils';
|
||||
import * as appHooks from 'providers/App/App';
|
||||
@@ -66,7 +66,7 @@ const mockChannels: Channels[] = [
|
||||
{ id: TEST_CONSTANTS.CHANNEL_3, name: 'PagerDuty Channel' } as any,
|
||||
];
|
||||
|
||||
const mockUnits: DefaultOptionType[] = [
|
||||
const mockUnits: ComboboxSimpleItem[] = [
|
||||
{ label: 'Bytes', value: 'bytes' },
|
||||
{ label: 'KB', value: 'kb' },
|
||||
{ label: 'MB', value: 'mb' },
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
.alert-condition-tabs {
|
||||
display: flex;
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--l2-border);
|
||||
background: var(--l2-background);
|
||||
flex-direction: row;
|
||||
border-bottom: none;
|
||||
@@ -26,19 +26,19 @@
|
||||
padding: 9px;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
border-left: 0.5px solid var(--l1-border);
|
||||
border-bottom: 0.5px solid var(--l1-border);
|
||||
border-left: 0.5px solid var(--l2-border);
|
||||
border-bottom: 0.5px solid var(--l2-border);
|
||||
width: 120px;
|
||||
height: 36px;
|
||||
|
||||
gap: 8px;
|
||||
|
||||
&.active-tab {
|
||||
background-color: var(--l1-background);
|
||||
background-color: var(--l2-background);
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--l1-background) !important;
|
||||
background-color: var(--l2-background-hover) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
border-left: 1px solid transparent !important;
|
||||
color: var(--l1-foreground);
|
||||
color: var(--l3-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,10 +65,16 @@
|
||||
.anomaly-threshold-container {
|
||||
padding: 24px;
|
||||
padding-right: 72px;
|
||||
background-color: var(--l1-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l2-border);
|
||||
width: 100%;
|
||||
|
||||
--select-trigger-background-color: var(--l3-background);
|
||||
--select-trigger-border-color: var(--l3-border);
|
||||
|
||||
--combobox-trigger-background-color: var(--l3-background);
|
||||
--combobox-trigger-border-color: var(--l3-border);
|
||||
|
||||
.alert-condition-sentences {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -88,34 +94,6 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
width: 240px;
|
||||
|
||||
.ant-select-selector {
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--muted-foreground);
|
||||
font-family: 'Space Mono';
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select-selection-item {
|
||||
color: var(--l1-foreground);
|
||||
}
|
||||
|
||||
.ant-select-arrow {
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +129,9 @@
|
||||
flex-wrap: wrap;
|
||||
|
||||
.ant-input {
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
background-color: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
color: var(--l2-foreground);
|
||||
height: 32px;
|
||||
|
||||
&::placeholder {
|
||||
@@ -161,28 +139,28 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l3-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l3-border);
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
.ant-select-selector {
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
background-color: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
color: var(--l2-foreground);
|
||||
height: 32px;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l2-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l2-border);
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
@@ -192,21 +170,23 @@
|
||||
}
|
||||
|
||||
.ant-select-selection-item {
|
||||
color: var(--l1-foreground);
|
||||
color: var(--l2-foreground);
|
||||
}
|
||||
|
||||
.ant-select-arrow {
|
||||
color: var(--muted-foreground);
|
||||
color: var(--l2-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
color: var(--muted-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l2-foreground);
|
||||
border: 1px solid var(--l3-border);
|
||||
background-color: var(--l3-background);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,8 +206,8 @@
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
color: var(--muted-foreground);
|
||||
background-color: var(--card) !important;
|
||||
border: 1px solid var(--l1-border);
|
||||
background-color: var(--l3-background) !important;
|
||||
border: 1px solid var(--l3-border);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -235,9 +215,9 @@
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
background-color: var(--card);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
background-color: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
color: var(--l2-foreground);
|
||||
height: 32px;
|
||||
|
||||
&::placeholder {
|
||||
@@ -245,11 +225,11 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l3-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l2-border);
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
@@ -258,7 +238,7 @@
|
||||
|
||||
.add-threshold-btn {
|
||||
margin-top: 8px;
|
||||
border: 1px dashed var(--l1-border);
|
||||
border: 1px dashed var(--l3-border);
|
||||
color: var(--l2-foreground);
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
@@ -267,10 +247,11 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: none;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
border-color: var(--l2-border);
|
||||
color: var(--l3-foreground);
|
||||
}
|
||||
|
||||
.anticon {
|
||||
@@ -339,8 +320,9 @@
|
||||
min-width: 240px;
|
||||
width: auto;
|
||||
justify-content: space-between;
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
background-color: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
box-shadow: none;
|
||||
|
||||
.evaluate-alert-conditions-button-left {
|
||||
color: var(--l2-foreground);
|
||||
@@ -358,7 +340,7 @@
|
||||
.evaluate-alert-conditions-button-right-text {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
background-color: var(--l1-border);
|
||||
background-color: var(--l3-border);
|
||||
padding: 1px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import type { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Channels } from 'types/api/channels/getAll';
|
||||
|
||||
import {
|
||||
@@ -23,7 +23,7 @@ export interface ThresholdItemProps {
|
||||
showRemoveButton: boolean;
|
||||
channels: Channels[];
|
||||
isLoadingChannels: boolean;
|
||||
units: DefaultOptionType[];
|
||||
units: ComboboxSimpleItem[];
|
||||
isErrorChannels: boolean;
|
||||
refreshChannels: () => void;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, Flex, SelectProps } from 'antd';
|
||||
import { Button, Flex } from 'antd';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { BaseOptionType, DefaultOptionType } from 'antd/es/select';
|
||||
import { getInvolvedQueriesInTraceOperator } from 'components/QueryBuilderV2/QueryV2/TraceOperator/utils/utils';
|
||||
import { YAxisSource } from 'components/YAxisUnitSelector/types';
|
||||
import { getYAxisCategories } from 'components/YAxisUnitSelector/utils';
|
||||
@@ -22,11 +22,11 @@ import { openInNewTab } from 'utils/navigation';
|
||||
import { ROUTING_POLICIES_ROUTE } from './constants';
|
||||
import { RoutingPolicyBannerProps } from './types';
|
||||
|
||||
export function getQueryNames(currentQuery: Query): BaseOptionType[] {
|
||||
export function getQueryNames(currentQuery: Query): ComboboxSimpleItem[] {
|
||||
const involvedQueriesInTraceOperator = getInvolvedQueriesInTraceOperator(
|
||||
currentQuery.builder.queryTraceOperator,
|
||||
);
|
||||
const queryConfig: Record<EQueryType, () => SelectProps['options']> = {
|
||||
const queryConfig: Record<EQueryType, () => ComboboxSimpleItem[]> = {
|
||||
[EQueryType.QUERY_BUILDER]: () => [
|
||||
...(getSelectedQueryOptions(currentQuery.builder.queryData)?.filter(
|
||||
(option) =>
|
||||
@@ -52,7 +52,7 @@ export function getCategoryByOptionId(id: string): string | undefined {
|
||||
|
||||
export function getCategorySelectOptionByName(
|
||||
name: string | undefined,
|
||||
): DefaultOptionType[] {
|
||||
): ComboboxSimpleItem[] {
|
||||
if (!name) {
|
||||
return [];
|
||||
}
|
||||
@@ -68,7 +68,6 @@ export function getCategorySelectOptionByName(
|
||||
?.units.map((unit) => ({
|
||||
label: unit.name,
|
||||
value: unit.id,
|
||||
'data-testid': `threshold-unit-select-option-${unit.id}`,
|
||||
})) || []
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { X } from '@signozhq/icons';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
|
||||
import { LabelInputState, LabelsInputProps } from './types';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
|
||||
function LabelsInput({
|
||||
labels,
|
||||
@@ -144,14 +145,16 @@ function LabelsInput({
|
||||
)}
|
||||
|
||||
{!isAdding ? (
|
||||
<button
|
||||
<Button
|
||||
className="labels-input__add-button"
|
||||
type="button"
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={handleAddLabelsClick}
|
||||
data-testid="alert-add-label-button"
|
||||
>
|
||||
+ Add labels
|
||||
</button>
|
||||
</Button>
|
||||
) : (
|
||||
<div className="labels-input__input-container">
|
||||
<input
|
||||
|
||||
@@ -39,9 +39,14 @@
|
||||
|
||||
&__input.title {
|
||||
background-color: transparent;
|
||||
color: var(--l1-foreground);
|
||||
background: var(--l2-background);
|
||||
color: var(--l2-foreground);
|
||||
width: 100%;
|
||||
min-width: 300px;
|
||||
|
||||
&:hover {
|
||||
background: var(--l2-background);
|
||||
}
|
||||
}
|
||||
|
||||
&__input.description {
|
||||
@@ -49,15 +54,6 @@
|
||||
background-color: transparent;
|
||||
color: var(--l2-foreground);
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
color: var(--l1-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.labels-input {
|
||||
@@ -66,19 +62,7 @@
|
||||
gap: 8px;
|
||||
|
||||
&__add-button {
|
||||
width: fit-content;
|
||||
font-size: 13px;
|
||||
color: var(--l2-foreground);
|
||||
border: 1px solid var(--l1-border);
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
}
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
&__existing-labels {
|
||||
@@ -121,6 +105,7 @@
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border: 1px solid var(--l2-border);
|
||||
}
|
||||
|
||||
&__input {
|
||||
|
||||
@@ -93,16 +93,16 @@
|
||||
gap: 8px;
|
||||
|
||||
.ant-input {
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
background-color: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
color: var(--l2-foreground);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l3-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
border-color: var(--l3-border);
|
||||
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Input, Select, Tooltip } from 'antd';
|
||||
import { Input, Tooltip } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { Info } from '@signozhq/icons';
|
||||
|
||||
@@ -79,8 +80,8 @@ function EvaluationCadence(): JSX.Element {
|
||||
}
|
||||
data-testid="evaluation-cadence-duration-input"
|
||||
/>
|
||||
<Select
|
||||
options={ADVANCED_OPTIONS_TIME_UNIT_OPTIONS}
|
||||
<SelectSimple
|
||||
items={ADVANCED_OPTIONS_TIME_UNIT_OPTIONS}
|
||||
placeholder="Select time unit"
|
||||
style={{ width: 120 }}
|
||||
value={advancedOptions.evaluationCadence.default.timeUnit}
|
||||
@@ -91,7 +92,7 @@ function EvaluationCadence(): JSX.Element {
|
||||
...advancedOptions.evaluationCadence,
|
||||
default: {
|
||||
...advancedOptions.evaluationCadence.default,
|
||||
timeUnit: value,
|
||||
timeUnit: value as string,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Button, DatePicker, Input, Select } from 'antd';
|
||||
import { Button, DatePicker, Input } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import classNames from 'classnames';
|
||||
import { useCreateAlertState } from 'container/CreateAlertV2/context';
|
||||
@@ -42,10 +43,6 @@ function EvaluationCadenceDetails({
|
||||
},
|
||||
});
|
||||
|
||||
const [searchTimezoneString, setSearchTimezoneString] = useState('');
|
||||
const [occurenceSearchString, setOccurenceSearchString] = useState('');
|
||||
const [repeatEverySearchString, setRepeatEverySearchString] = useState('');
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: 'Editor',
|
||||
@@ -93,45 +90,39 @@ function EvaluationCadenceDetails({
|
||||
<div className="editor-view" data-testid="editor-view">
|
||||
<div className="select-group">
|
||||
<Typography.Text>REPEAT EVERY</Typography.Text>
|
||||
<Select
|
||||
options={EVALUATION_CADENCE_REPEAT_EVERY_OPTIONS}
|
||||
value={evaluationCadence.custom.repeatEvery || null}
|
||||
<ComboboxSimple
|
||||
items={EVALUATION_CADENCE_REPEAT_EVERY_OPTIONS}
|
||||
value={evaluationCadence.custom.repeatEvery || undefined}
|
||||
onChange={(value): void =>
|
||||
setEvaluationCadence({
|
||||
...evaluationCadence,
|
||||
custom: {
|
||||
...evaluationCadence.custom,
|
||||
repeatEvery: value,
|
||||
repeatEvery: value as string,
|
||||
occurence: [],
|
||||
},
|
||||
})
|
||||
}
|
||||
placeholder="Select repeat every"
|
||||
showSearch
|
||||
searchValue={repeatEverySearchString}
|
||||
onSearch={setRepeatEverySearchString}
|
||||
/>
|
||||
</div>
|
||||
{evaluationCadence.custom.repeatEvery !== 'day' && (
|
||||
<div className="select-group">
|
||||
<Typography.Text>ON DAY(S)</Typography.Text>
|
||||
<Select
|
||||
options={occurenceOptions}
|
||||
value={evaluationCadence.custom.occurence || null}
|
||||
mode="multiple"
|
||||
<ComboboxSimple
|
||||
items={occurenceOptions}
|
||||
value={evaluationCadence.custom.occurence || []}
|
||||
multiple
|
||||
onChange={(value): void =>
|
||||
setEvaluationCadence({
|
||||
...evaluationCadence,
|
||||
custom: {
|
||||
...evaluationCadence.custom,
|
||||
occurence: value,
|
||||
occurence: value as string[],
|
||||
},
|
||||
})
|
||||
}
|
||||
placeholder="Select day(s)"
|
||||
showSearch
|
||||
searchValue={occurenceSearchString}
|
||||
onSearch={setOccurenceSearchString}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -152,22 +143,19 @@ function EvaluationCadenceDetails({
|
||||
</div>
|
||||
<div className="select-group">
|
||||
<Typography.Text>TIMEZONE</Typography.Text>
|
||||
<Select
|
||||
options={TIMEZONE_DATA}
|
||||
value={evaluationCadence.custom.timezone || null}
|
||||
<ComboboxSimple
|
||||
items={TIMEZONE_DATA}
|
||||
value={evaluationCadence.custom.timezone || undefined}
|
||||
onChange={(value): void =>
|
||||
setEvaluationCadence({
|
||||
...evaluationCadence,
|
||||
custom: {
|
||||
...evaluationCadence.custom,
|
||||
timezone: value,
|
||||
timezone: value as string,
|
||||
},
|
||||
})
|
||||
}
|
||||
placeholder="Select timezone"
|
||||
onSearch={setSearchTimezoneString}
|
||||
searchValue={searchTimezoneString}
|
||||
showSearch
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
.evaluation-cadence-container {
|
||||
border-bottom: 1px solid var(--l1-border);
|
||||
|
||||
--select-trigger-background-color: var(--l3-background);
|
||||
--select-trigger-border-color: var(--l3-border);
|
||||
|
||||
.evaluation-cadence-item {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
@@ -157,24 +161,6 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
border: 1px solid var(--l1-border);
|
||||
|
||||
.ant-select-selector {
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
color: var(--l1-foreground);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l1-border);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--l1-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker {
|
||||
background-color: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Input, Select } from 'antd';
|
||||
import { Input } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
|
||||
import { ADVANCED_OPTIONS_TIME_UNIT_OPTIONS } from '../../context/constants';
|
||||
@@ -19,7 +20,7 @@ function EvaluationWindowDetails({
|
||||
const currentHourOptions = useMemo(() => {
|
||||
const options = [];
|
||||
for (let i = 0; i < 60; i++) {
|
||||
options.push({ label: i.toString(), value: i });
|
||||
options.push({ label: i.toString(), value: i.toString() });
|
||||
}
|
||||
return options;
|
||||
}, []);
|
||||
@@ -27,7 +28,7 @@ function EvaluationWindowDetails({
|
||||
const currentMonthOptions = useMemo(() => {
|
||||
const options = [];
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
options.push({ label: i.toString(), value: i });
|
||||
options.push({ label: i.toString(), value: i.toString() });
|
||||
}
|
||||
return options;
|
||||
}, []);
|
||||
@@ -123,10 +124,10 @@ function EvaluationWindowDetails({
|
||||
<Typography.Text>{displayText}</Typography.Text>
|
||||
<div className="select-group">
|
||||
<Typography.Text>STARTING AT MINUTE</Typography.Text>
|
||||
<Select
|
||||
options={currentHourOptions}
|
||||
value={evaluationWindow.startingAt.number || null}
|
||||
onChange={handleNumberChange}
|
||||
<SelectSimple
|
||||
items={currentHourOptions}
|
||||
value={evaluationWindow.startingAt.number || undefined}
|
||||
onChange={(value): void => handleNumberChange(value as string)}
|
||||
placeholder="Select starting at"
|
||||
data-testid="evaluation-window-details-starting-at-select"
|
||||
/>
|
||||
@@ -151,10 +152,10 @@ function EvaluationWindowDetails({
|
||||
</div>
|
||||
<div className="select-group">
|
||||
<Typography.Text>SELECT TIMEZONE</Typography.Text>
|
||||
<Select
|
||||
options={TIMEZONE_DATA}
|
||||
value={evaluationWindow.startingAt.timezone || null}
|
||||
onChange={handleTimezoneChange}
|
||||
<SelectSimple
|
||||
items={TIMEZONE_DATA}
|
||||
value={evaluationWindow.startingAt.timezone || undefined}
|
||||
onChange={(value): void => handleTimezoneChange(value as string)}
|
||||
placeholder="Select timezone"
|
||||
data-testid="evaluation-window-details-timezone-select"
|
||||
/>
|
||||
@@ -172,10 +173,10 @@ function EvaluationWindowDetails({
|
||||
<Typography.Text>{displayText}</Typography.Text>
|
||||
<div className="select-group">
|
||||
<Typography.Text>STARTING ON DAY</Typography.Text>
|
||||
<Select
|
||||
options={currentMonthOptions}
|
||||
value={evaluationWindow.startingAt.number || null}
|
||||
onChange={handleNumberChange}
|
||||
<SelectSimple
|
||||
items={currentMonthOptions}
|
||||
value={evaluationWindow.startingAt.number || undefined}
|
||||
onChange={(value): void => handleNumberChange(value as string)}
|
||||
placeholder="Select starting at"
|
||||
data-testid="evaluation-window-details-starting-at-select"
|
||||
/>
|
||||
@@ -189,10 +190,10 @@ function EvaluationWindowDetails({
|
||||
</div>
|
||||
<div className="select-group">
|
||||
<Typography.Text>SELECT TIMEZONE</Typography.Text>
|
||||
<Select
|
||||
options={TIMEZONE_DATA}
|
||||
value={evaluationWindow.startingAt.timezone || null}
|
||||
onChange={handleTimezoneChange}
|
||||
<SelectSimple
|
||||
items={TIMEZONE_DATA}
|
||||
value={evaluationWindow.startingAt.timezone || undefined}
|
||||
onChange={(value): void => handleTimezoneChange(value as string)}
|
||||
placeholder="Select timezone"
|
||||
data-testid="evaluation-window-details-timezone-select"
|
||||
/>
|
||||
@@ -221,10 +222,10 @@ function EvaluationWindowDetails({
|
||||
</div>
|
||||
<div className="select-group time-select-group">
|
||||
<Typography.Text>UNIT</Typography.Text>
|
||||
<Select
|
||||
options={ADVANCED_OPTIONS_TIME_UNIT_OPTIONS}
|
||||
value={evaluationWindow.startingAt.unit || null}
|
||||
onChange={handleUnitChange}
|
||||
<SelectSimple
|
||||
items={ADVANCED_OPTIONS_TIME_UNIT_OPTIONS}
|
||||
value={evaluationWindow.startingAt.unit || undefined}
|
||||
onChange={(value): void => handleUnitChange(value as string)}
|
||||
placeholder="Select unit"
|
||||
data-testid="evaluation-window-details-custom-rolling-window-unit-select"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { Select, Tooltip } from 'antd';
|
||||
import { Tooltip } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { Info } from '@signozhq/icons';
|
||||
@@ -87,16 +88,15 @@ function MultipleNotifications(): JSX.Element {
|
||||
: 'No grouping fields available';
|
||||
let input = (
|
||||
<div>
|
||||
<Select
|
||||
options={spaceAggregationOptions}
|
||||
onChange={onSelectChange}
|
||||
value={notificationSettings.multipleNotifications}
|
||||
mode="multiple"
|
||||
<SelectSimple
|
||||
items={spaceAggregationOptions}
|
||||
onChange={(value): void => onSelectChange(value as string[])}
|
||||
value={notificationSettings.multipleNotifications || []}
|
||||
multiple
|
||||
placeholder={placeholder}
|
||||
disabled={!isMultipleNotificationsEnabled}
|
||||
aria-disabled={!isMultipleNotificationsEnabled}
|
||||
maxTagCount={3}
|
||||
data-testid="multiple-notifications-select"
|
||||
maxDisplayedPills={3}
|
||||
testId="multiple-notifications-select"
|
||||
/>
|
||||
{isMultipleNotificationsEnabled && (
|
||||
<Typography.Text className="multiple-notifications-select-description">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Input, Select } from 'antd';
|
||||
import { Input } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
|
||||
import { useCreateAlertState } from '../context';
|
||||
@@ -38,31 +39,31 @@ function NotificationSettings(): JSX.Element {
|
||||
}}
|
||||
data-testid="repeat-notifications-time-input"
|
||||
/>
|
||||
<Select
|
||||
value={notificationSettings.reNotification.unit || null}
|
||||
<SelectSimple
|
||||
value={notificationSettings.reNotification.unit || undefined}
|
||||
placeholder="Select unit"
|
||||
disabled={!notificationSettings.reNotification.enabled}
|
||||
options={RE_NOTIFICATION_TIME_UNIT_OPTIONS}
|
||||
items={RE_NOTIFICATION_TIME_UNIT_OPTIONS}
|
||||
onChange={(value): void => {
|
||||
setNotificationSettings({
|
||||
type: 'SET_RE_NOTIFICATION',
|
||||
payload: {
|
||||
enabled: notificationSettings.reNotification.enabled,
|
||||
value: notificationSettings.reNotification.value,
|
||||
unit: value,
|
||||
unit: value as string,
|
||||
conditions: notificationSettings.reNotification.conditions,
|
||||
},
|
||||
});
|
||||
}}
|
||||
data-testid="repeat-notifications-unit-select"
|
||||
testId="repeat-notifications-unit-select"
|
||||
/>
|
||||
<Typography.Text>while</Typography.Text>
|
||||
<Select
|
||||
mode="multiple"
|
||||
value={notificationSettings.reNotification.conditions || null}
|
||||
<SelectSimple
|
||||
multiple
|
||||
value={notificationSettings.reNotification.conditions || []}
|
||||
placeholder="Select conditions"
|
||||
disabled={!notificationSettings.reNotification.enabled}
|
||||
options={RE_NOTIFICATION_CONDITION_OPTIONS}
|
||||
items={RE_NOTIFICATION_CONDITION_OPTIONS}
|
||||
onChange={(value): void => {
|
||||
setNotificationSettings({
|
||||
type: 'SET_RE_NOTIFICATION',
|
||||
@@ -70,11 +71,11 @@ function NotificationSettings(): JSX.Element {
|
||||
enabled: notificationSettings.reNotification.enabled,
|
||||
value: notificationSettings.reNotification.value,
|
||||
unit: notificationSettings.reNotification.unit,
|
||||
conditions: value,
|
||||
conditions: value as ('firing' | 'nodata')[],
|
||||
},
|
||||
});
|
||||
}}
|
||||
data-testid="repeat-notifications-conditions-select"
|
||||
testId="repeat-notifications-conditions-select"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
flex-direction: column;
|
||||
margin: 0 16px;
|
||||
|
||||
--select-trigger-background-color: var(--l3-background);
|
||||
--select-trigger-border-color: var(--l3-border);
|
||||
|
||||
.notification-message-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -54,8 +57,8 @@
|
||||
|
||||
textarea {
|
||||
height: 150px;
|
||||
background: var(--l2-background);
|
||||
border: 1px solid var(--l1-border);
|
||||
background: var(--l3-background);
|
||||
border: 1px solid var(--l3-border);
|
||||
border-radius: 4px;
|
||||
color: var(--l2-foreground) !important;
|
||||
font-family: Inter;
|
||||
@@ -77,8 +80,9 @@
|
||||
gap: 8px;
|
||||
|
||||
.ant-input {
|
||||
width: 120px;
|
||||
border: 1px solid var(--l1-border);
|
||||
width: 190px;
|
||||
border: 1px solid var(--l3-border);
|
||||
background-color: var(--l3-background);
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
gap: 8px;
|
||||
|
||||
&.active-tab {
|
||||
background-color: var(--l1-background);
|
||||
background-color: var(--l3-background);
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--l1-background) !important;
|
||||
background-color: var(--l3-background) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Select } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import CustomSelect from 'components/NewSelect/CustomSelect';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
@@ -204,10 +204,9 @@ function DynamicVariable({
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="Source"
|
||||
defaultValue={AttributeSource.ALL_TELEMETRY}
|
||||
options={sources.map((source) => ({ label: source, value: source }))}
|
||||
items={sources.map((source) => ({ label: source, value: source }))}
|
||||
onChange={(value): void => setAttributeSource(value as AttributeSource)}
|
||||
value={attributeSource || dynamicVariablesSelectedValue?.value}
|
||||
/>
|
||||
|
||||
@@ -5,8 +5,9 @@ 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 { Switch } from '@signozhq/ui/switch';
|
||||
import { Button, Collapse, Input, Tag } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import dashboardVariablesQuery from 'api/dashboard/variables/dashboardVariablesQuery';
|
||||
import cx from 'classnames';
|
||||
@@ -56,7 +57,11 @@ import { WidgetSelector } from './WidgetSelector';
|
||||
|
||||
import './VariableItem.styles.scss';
|
||||
|
||||
const { Option } = Select;
|
||||
const SORT_ITEMS = [
|
||||
{ value: VariableSortTypeArr[0], label: 'Disabled' },
|
||||
{ value: VariableSortTypeArr[1], label: 'Ascending' },
|
||||
{ value: VariableSortTypeArr[2], label: 'Descending' },
|
||||
];
|
||||
|
||||
interface VariableItemProps {
|
||||
variableData: IDashboardVariable;
|
||||
@@ -743,19 +748,14 @@ function VariableItem({
|
||||
<Typography className="typography-variables">Sort Values</Typography>
|
||||
</LabelContainer>
|
||||
|
||||
<Select
|
||||
defaultActiveFirstOption
|
||||
defaultValue={VariableSortTypeArr[0]}
|
||||
<SelectSimple
|
||||
value={variableSortType}
|
||||
onChange={(value: TSortVariableValuesType): void =>
|
||||
setVariableSortType(value)
|
||||
onChange={(value): void =>
|
||||
setVariableSortType(value as TSortVariableValuesType)
|
||||
}
|
||||
className="sort-input"
|
||||
>
|
||||
<Option value={VariableSortTypeArr[0]}>Disabled</Option>
|
||||
<Option value={VariableSortTypeArr[1]}>Ascending</Option>
|
||||
<Option value={VariableSortTypeArr[2]}>Descending</Option>
|
||||
</Select>
|
||||
items={SORT_ITEMS}
|
||||
/>
|
||||
</VariableItemRow>
|
||||
<VariableItemRow className="multiple-values-section">
|
||||
<LabelContainer>
|
||||
@@ -798,10 +798,10 @@ function VariableItem({
|
||||
<CustomSelect
|
||||
placeholder="Select a default value"
|
||||
value={variableDefaultValue}
|
||||
onChange={(value): void => setVariableDefaultValue(value)}
|
||||
options={previewValues.map((value) => ({
|
||||
label: value,
|
||||
value,
|
||||
onChange={(value): void => setVariableDefaultValue(value ?? '')}
|
||||
options={previewValues.map((val) => ({
|
||||
label: val,
|
||||
value: val,
|
||||
}))}
|
||||
/>
|
||||
</VariableItemRow>
|
||||
|
||||
@@ -98,6 +98,14 @@
|
||||
|
||||
.nameIconInput {
|
||||
display: flex;
|
||||
|
||||
--select-trigger-width: 40px;
|
||||
--select-trigger-background-color: var(--l3-background);
|
||||
--select-trigger-border-color: var(--l1-border);
|
||||
|
||||
[data-slot='select-trigger'] svg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboardImageInput {
|
||||
@@ -108,7 +116,7 @@
|
||||
padding: 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border-radius: 2var (--l3-border) px 0px 0px 2px;
|
||||
border: 1px solid var(--l1-border) !important;
|
||||
background: var(--l3-background) !important;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Col, Input, Radio, Select, Space, Tooltip } from 'antd';
|
||||
import { Col, Input, Radio, Space, Tooltip } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import AddTags from 'container/DashboardContainer/DashboardSettings/General/AddTags';
|
||||
import { useDashboardCursorSyncMode } from 'hooks/dashboard/useDashboardCursorSyncMode';
|
||||
@@ -21,8 +22,6 @@ import logEvent from 'api/common/logEvent';
|
||||
import { Events } from 'constants/events';
|
||||
import { getAbsoluteUrl } from 'utils/basePath';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
function GeneralDashboardSettings(): JSX.Element {
|
||||
const { dashboardData, setDashboardData } = useDashboardStore();
|
||||
|
||||
@@ -130,24 +129,22 @@ function GeneralDashboardSettings(): JSX.Element {
|
||||
<div>
|
||||
<Typography className={styles.dashboardName}>Dashboard Name</Typography>
|
||||
<section className={styles.nameIconInput}>
|
||||
<Select
|
||||
defaultActiveFirstOption
|
||||
<SelectSimple
|
||||
data-testid="dashboard-image"
|
||||
suffixIcon={null}
|
||||
rootClassName={styles.dashboardImageInput}
|
||||
className={styles.dashboardImageInput}
|
||||
value={updatedImage}
|
||||
onChange={(value: string): void => setUpdatedImage(value)}
|
||||
>
|
||||
{Base64Icons.map((icon) => (
|
||||
<Option value={icon} key={icon}>
|
||||
onChange={(value): void => setUpdatedImage(value as string)}
|
||||
items={Base64Icons.map((icon) => ({
|
||||
value: icon,
|
||||
label: (
|
||||
<img
|
||||
src={icon}
|
||||
alt="dashboard-icon"
|
||||
className={styles.listItemImage}
|
||||
/>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
<Input
|
||||
data-testid="dashboard-name"
|
||||
className={styles.dashboardNameInput}
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useMutation } from 'react-query';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import { Checkbox } from '@signozhq/ui/checkbox';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { Button, Select } from 'antd';
|
||||
import { Button } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import createPublicDashboardAPI from 'api/dashboard/public/createPublicDashboard';
|
||||
import revokePublicDashboardAccessAPI from 'api/dashboard/public/revokePublicDashboardAccess';
|
||||
@@ -270,12 +271,12 @@ function PublicDashboardSetting(): JSX.Element {
|
||||
Default time range
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="Select default time range"
|
||||
options={TIME_RANGE_PRESETS_OPTIONS}
|
||||
items={TIME_RANGE_PRESETS_OPTIONS}
|
||||
value={defaultTimeRange}
|
||||
onChange={handleDefaultTimeRange}
|
||||
data-testid="default-time-range-select-dropdown"
|
||||
onChange={(value): void => handleDefaultTimeRange(value as string)}
|
||||
testId="default-time-range-select-dropdown"
|
||||
className="default-time-range-select-dropdown"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
gap: 16px;
|
||||
z-index: 1;
|
||||
|
||||
.ant-select-selector {
|
||||
padding: 0 !important;
|
||||
.views-dropdown {
|
||||
--combobox-trigger-border-color: transparent;
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -98,29 +98,17 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.ant-select-focused {
|
||||
border-color: transparent !important;
|
||||
|
||||
.ant-select-selector {
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select-selector {
|
||||
border: transparent !important;
|
||||
background-color: transparent !important;
|
||||
|
||||
.ant-select-selection-placeholder {
|
||||
margin-left: 12px;
|
||||
}
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button {
|
||||
.views-save-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
CSSProperties,
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
@@ -23,12 +21,12 @@ import {
|
||||
Button,
|
||||
ColorPicker,
|
||||
Divider,
|
||||
Dropdown,
|
||||
Input,
|
||||
Modal,
|
||||
RefSelectProps,
|
||||
Select,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
@@ -58,7 +56,6 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useGetAllViews } from 'hooks/saveViews/useGetAllViews';
|
||||
import { useSaveView } from 'hooks/saveViews/useSaveView';
|
||||
import { useUpdateView } from 'hooks/saveViews/useUpdateView';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useErrorNotification from 'hooks/useErrorNotification';
|
||||
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
@@ -108,8 +105,6 @@ function ExplorerOptions({
|
||||
const [color, setColor] = useState(Color.BG_SIENNA_500);
|
||||
const { notifications } = useNotifications();
|
||||
const history = useHistory();
|
||||
const ref = useRef<RefSelectProps>(null);
|
||||
const isDarkMode = useIsDarkMode();
|
||||
const [queryToExport, setQueryToExport] = useState<Query | null>(null);
|
||||
|
||||
const isLogsExplorer = sourcepage === DataSource.LOGS;
|
||||
@@ -493,10 +488,16 @@ function ExplorerOptions({
|
||||
);
|
||||
};
|
||||
|
||||
const handleSelect = (
|
||||
value: string,
|
||||
option: { key: string; value: string },
|
||||
): void => {
|
||||
const handleSelect = (value: string | string[]): void => {
|
||||
const selectedId = value as string;
|
||||
const selectedView = viewsData?.data?.data?.find(
|
||||
(view) => view.id === selectedId,
|
||||
);
|
||||
const option = {
|
||||
key: selectedId,
|
||||
value: selectedView?.name ?? '',
|
||||
};
|
||||
|
||||
onMenuItemSelectHandler({
|
||||
key: option.key,
|
||||
});
|
||||
@@ -530,10 +531,6 @@ function ExplorerOptions({
|
||||
options,
|
||||
handleOptionsChange,
|
||||
);
|
||||
|
||||
if (ref.current) {
|
||||
ref.current.blur();
|
||||
}
|
||||
};
|
||||
|
||||
const removeCurrentViewFromLocalStorage = (): void => {
|
||||
@@ -639,24 +636,42 @@ function ExplorerOptions({
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Remove this and move this to scss file
|
||||
const dropdownStyle: CSSProperties = useMemo(
|
||||
() => ({
|
||||
borderRadius: '4px',
|
||||
border: isDarkMode
|
||||
? `1px solid ${Color.BG_SLATE_400}`
|
||||
: `1px solid ${Color.BG_VANILLA_300}`,
|
||||
background: isDarkMode
|
||||
? 'var(--bg-gradient-dark-shadow)'
|
||||
: 'linear-gradient(139deg, rgba(241, 241, 241, 0.8) 0%, rgba(241, 241, 241, 0.9) 98.68%)',
|
||||
boxShadow: '4px 10px 16px 2px rgba(0, 0, 0, 0.20)',
|
||||
backdropFilter: 'blur(20px)',
|
||||
bottom: '74px',
|
||||
width: '191px',
|
||||
}),
|
||||
[isDarkMode],
|
||||
const viewSelectItems = useMemo<ComboboxSimpleItem[]>(
|
||||
() =>
|
||||
viewsData?.data?.data?.map((view) => {
|
||||
const extraData = view.extraData !== '' ? JSON.parse(view.extraData) : '';
|
||||
let bgColor = getRandomColor();
|
||||
if (extraData !== '') {
|
||||
bgColor = extraData.color;
|
||||
}
|
||||
return {
|
||||
value: view.id,
|
||||
label: (
|
||||
<div className="render-options">
|
||||
<span
|
||||
className="dot"
|
||||
style={{
|
||||
background: bgColor,
|
||||
boxShadow: `0px 0px 6px 0px ${bgColor}`,
|
||||
}}
|
||||
/>{' '}
|
||||
{view.name}
|
||||
</div>
|
||||
),
|
||||
displayValue: view.name,
|
||||
keywords: [view.name],
|
||||
};
|
||||
}) ?? [],
|
||||
[viewsData?.data?.data],
|
||||
);
|
||||
|
||||
const viewSelectValue = useMemo<string | undefined>(() => {
|
||||
if (!viewName) {
|
||||
return undefined;
|
||||
}
|
||||
return viewsData?.data?.data?.find((view) => view.name === viewName)?.id;
|
||||
}, [viewName, viewsData?.data?.data]);
|
||||
|
||||
const isEditDeleteSupported = allowedRoles.includes(user.role as string);
|
||||
|
||||
const [isRecentlyUsedSavedViewSelected, setIsRecentlyUsedSavedViewSelected] =
|
||||
@@ -735,37 +750,32 @@ function ExplorerOptions({
|
||||
|
||||
const CreateAlertButton = useMemo(() => {
|
||||
if (isOneChartPerQuery) {
|
||||
const selectLabel = (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
icon={<ConciergeBell size={16} />}
|
||||
>
|
||||
Create an Alert
|
||||
</Button>
|
||||
);
|
||||
return (
|
||||
<Select
|
||||
<Dropdown
|
||||
disabled={disabled}
|
||||
className="multi-alert-button"
|
||||
placeholder={selectLabel}
|
||||
value={selectLabel}
|
||||
suffixIcon={null}
|
||||
onSelect={(e): void => {
|
||||
const selectedQuery = splitedQueries.find(
|
||||
(query) => query.id === (e as unknown as string),
|
||||
);
|
||||
if (selectedQuery) {
|
||||
onCreateAlertsHandler(selectedQuery);
|
||||
}
|
||||
trigger={['click']}
|
||||
overlayClassName="multi-alert-button"
|
||||
menu={{
|
||||
items: splitedQueries.map((splittedQuery) => ({
|
||||
key: splittedQuery.id,
|
||||
label: getQueryName(splittedQuery),
|
||||
})),
|
||||
onClick: ({ key }): void => {
|
||||
const selectedQuery = splitedQueries.find((query) => query.id === key);
|
||||
if (selectedQuery) {
|
||||
onCreateAlertsHandler(selectedQuery);
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{splitedQueries.map((splittedQuery) => (
|
||||
<Select.Option key={splittedQuery.id} value={splittedQuery.id}>
|
||||
{getQueryName(splittedQuery)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
icon={<ConciergeBell size={16} />}
|
||||
>
|
||||
Create an Alert
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
return (
|
||||
@@ -788,43 +798,36 @@ function ExplorerOptions({
|
||||
|
||||
const AddToDashboardButton = useMemo(() => {
|
||||
if (isOneChartPerQuery) {
|
||||
const selectLabel = (
|
||||
<Button
|
||||
type="primary"
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
onClick={onAddToDashboard}
|
||||
icon={<Plus size={16} />}
|
||||
>
|
||||
Add to Dashboard
|
||||
</Button>
|
||||
);
|
||||
return (
|
||||
<Select
|
||||
<Dropdown
|
||||
disabled={disabled}
|
||||
className="multi-dashboard-button"
|
||||
placeholder={selectLabel}
|
||||
value={selectLabel}
|
||||
suffixIcon={null}
|
||||
onSelect={(e): void => {
|
||||
const selectedQuery = splitedQueries.find(
|
||||
(query) => query.id === (e as unknown as string),
|
||||
);
|
||||
if (selectedQuery) {
|
||||
setQueryToExport(() => {
|
||||
onAddToDashboard();
|
||||
return selectedQuery;
|
||||
});
|
||||
}
|
||||
trigger={['click']}
|
||||
overlayClassName="multi-dashboard-button"
|
||||
menu={{
|
||||
items: splitedQueries.map((splittedQuery) => ({
|
||||
key: splittedQuery.id,
|
||||
label: getQueryName(splittedQuery),
|
||||
})),
|
||||
onClick: ({ key }): void => {
|
||||
const selectedQuery = splitedQueries.find((query) => query.id === key);
|
||||
if (selectedQuery) {
|
||||
setQueryToExport(() => {
|
||||
onAddToDashboard();
|
||||
return selectedQuery;
|
||||
});
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{/* eslint-disable-next-line sonarjs/no-identical-functions */}
|
||||
{splitedQueries.map((splittedQuery) => (
|
||||
<Select.Option key={splittedQuery.id} value={splittedQuery.id}>
|
||||
{getQueryName(splittedQuery)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
<Button
|
||||
type="primary"
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
icon={<Plus size={16} />}
|
||||
>
|
||||
Add to Dashboard
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
return (
|
||||
@@ -898,48 +901,24 @@ function ExplorerOptions({
|
||||
}}
|
||||
>
|
||||
<div className="view-options">
|
||||
<Select<string, { key: string; value: string }>
|
||||
showSearch
|
||||
<ComboboxSimple
|
||||
placeholder="Select a view"
|
||||
loading={viewsIsLoading || isRefetching}
|
||||
value={viewName || undefined}
|
||||
onSelect={handleSelect}
|
||||
value={viewSelectValue}
|
||||
onChange={handleSelect}
|
||||
style={{
|
||||
minWidth: 170,
|
||||
}}
|
||||
dropdownStyle={dropdownStyle}
|
||||
className="views-dropdown"
|
||||
allowClear={false}
|
||||
ref={ref}
|
||||
>
|
||||
{viewsData?.data?.data?.map((view) => {
|
||||
const extraData =
|
||||
view.extraData !== '' ? JSON.parse(view.extraData) : '';
|
||||
let bgColor = getRandomColor();
|
||||
if (extraData !== '') {
|
||||
bgColor = extraData.color;
|
||||
}
|
||||
return (
|
||||
<Select.Option key={view.id} value={view.name}>
|
||||
<div className="render-options">
|
||||
<span
|
||||
className="dot"
|
||||
style={{
|
||||
background: bgColor,
|
||||
boxShadow: `0px 0px 6px 0px ${bgColor}`,
|
||||
}}
|
||||
/>{' '}
|
||||
{view.name}
|
||||
</div>
|
||||
</Select.Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
items={viewSelectItems}
|
||||
/>
|
||||
|
||||
<Button
|
||||
shape="round"
|
||||
onClick={handleSaveViewModalToggle}
|
||||
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||
className={
|
||||
isEditDeleteSupported ? 'views-save-button' : 'views-save-button hidden'
|
||||
}
|
||||
disabled={viewsIsLoading || isRefetching}
|
||||
icon={<Disc3 size={16} />}
|
||||
>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
import { Select, Spin } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { IOption } from 'hooks/useResourceAttribute/types';
|
||||
import { OrderByFilterProps } from 'container/QueryBuilder/filters/OrderByFilter/OrderByFilter.interfaces';
|
||||
import { useOrderByFilter } from 'container/QueryBuilder/filters/OrderByFilter/useOrderByFilter';
|
||||
import { selectStyle } from 'container/QueryBuilder/filters/QueryBuilderSearch/config';
|
||||
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
|
||||
import { uniqWith } from 'lodash-es';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { StringOperators } from 'types/common/queryBuilder';
|
||||
|
||||
@@ -15,7 +17,6 @@ function ExplorerOrderBy({ query, onChange }: OrderByFilterProps): JSX.Element {
|
||||
generateOptions,
|
||||
createOptions,
|
||||
handleChange,
|
||||
handleSearchKeys,
|
||||
} = useOrderByFilter({ query, onChange });
|
||||
|
||||
const { data, isFetching } = useGetAggregateKeys(
|
||||
@@ -54,18 +55,42 @@ function ExplorerOrderBy({ query, onChange }: OrderByFilterProps): JSX.Element {
|
||||
query.aggregateOperator,
|
||||
]);
|
||||
|
||||
const items: ComboboxSimpleItem[] = useMemo(() => {
|
||||
const merged: IOption[] = [...selectedValue, ...options];
|
||||
const unique = uniqWith(merged, (a, b) => a.value === b.value);
|
||||
return unique.map((opt) => ({
|
||||
label: opt.label,
|
||||
displayValue: opt.label,
|
||||
value: opt.value,
|
||||
}));
|
||||
}, [selectedValue, options]);
|
||||
|
||||
const value = useMemo(
|
||||
() => selectedValue.map((item) => item.value),
|
||||
[selectedValue],
|
||||
);
|
||||
|
||||
const handleComboboxChange = (next: string | string[]): void => {
|
||||
const values = (next as string[]) || [];
|
||||
const asOptions: IOption[] = values.map((v) => {
|
||||
const found = items.find((item) => item.value === v);
|
||||
return {
|
||||
label: typeof found?.label === 'string' ? found.label : v,
|
||||
value: v,
|
||||
};
|
||||
});
|
||||
handleChange(asOptions);
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
mode="tags"
|
||||
<ComboboxSimple
|
||||
multiple
|
||||
allowCreate
|
||||
loading={isFetching}
|
||||
style={selectStyle}
|
||||
onSearch={handleSearchKeys}
|
||||
showSearch
|
||||
showArrow={false}
|
||||
value={selectedValue}
|
||||
labelInValue
|
||||
options={options}
|
||||
notFoundContent={isFetching ? <Spin size="small" /> : null}
|
||||
onChange={handleChange}
|
||||
items={items}
|
||||
value={value}
|
||||
onChange={handleComboboxChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
Title,
|
||||
Wrapper,
|
||||
} from './styles';
|
||||
import { filterOptions, getSelectOptions } from './utils';
|
||||
import { getSelectOptions } from './utils';
|
||||
|
||||
function ExportPanelContainer({
|
||||
isLoading,
|
||||
@@ -91,13 +91,13 @@ function ExportPanelContainer({
|
||||
<SelectWrapper direction="horizontal">
|
||||
<DashboardSelect
|
||||
placeholder="Select Dashboard"
|
||||
options={options}
|
||||
showSearch
|
||||
items={options}
|
||||
loading={isDashboardLoading}
|
||||
disabled={isDashboardLoading}
|
||||
value={dashboardId}
|
||||
onSelect={handleSelect}
|
||||
filterOption={filterOptions}
|
||||
style={
|
||||
isDashboardLoading ? { pointerEvents: 'none', opacity: 0.5 } : undefined
|
||||
}
|
||||
value={dashboardId || ''}
|
||||
onChange={(value): void => handleSelect(value as string)}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import { Button, Select, SelectProps, Space } from 'antd';
|
||||
import { Button, Space } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const DashboardSelect: FunctionComponent<SelectProps> = styled(
|
||||
Select,
|
||||
)<SelectProps>`
|
||||
export const DashboardSelect = styled(ComboboxSimple)`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
|
||||
export const getSelectOptions = (data: Dashboard[]): SelectProps['options'] =>
|
||||
export const getSelectOptions = (data: Dashboard[]): ComboboxSimpleItem[] =>
|
||||
data.map(({ id, data }) => ({
|
||||
label: data.title,
|
||||
value: id,
|
||||
}));
|
||||
|
||||
export const filterOptions: SelectProps['filterOption'] = (
|
||||
input,
|
||||
options,
|
||||
): boolean =>
|
||||
(options?.label?.toString() ?? '')
|
||||
?.toLowerCase()
|
||||
.includes(input.toLowerCase());
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { ArrowLeft, ArrowRight } from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Input } from '@signozhq/ui/input';
|
||||
import { Form, Select } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Form } from 'antd';
|
||||
import { ErrorResponseHandlerForGeneratedAPIs } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
||||
import { useForgotPassword } from 'api/generated/services/users';
|
||||
import AuthError from 'components/AuthError/AuthError';
|
||||
@@ -168,15 +169,18 @@ function ForgotPassword({
|
||||
name="orgId"
|
||||
rules={[{ required: true, message: 'Please select your organization' }]}
|
||||
>
|
||||
<Select
|
||||
<SelectSimple
|
||||
id="orgId"
|
||||
data-testid="orgId"
|
||||
testId="orgId"
|
||||
className="login-form-input login-form-select-no-border"
|
||||
placeholder="Select your organization"
|
||||
options={orgs.map((org) => ({
|
||||
items={orgs.map((org) => ({
|
||||
value: org.id,
|
||||
label: org.name || 'default',
|
||||
}))}
|
||||
onChange={(value): void => {
|
||||
form.setFieldValue('orgId', value);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Dispatch, ReactElement, SetStateAction } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Form, FormInstance, Input, Select } from 'antd';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import { Form, FormInstance, Input } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { Store } from 'antd/lib/form/interface';
|
||||
import ROUTES from 'constants/routes';
|
||||
@@ -95,40 +96,20 @@ function FormAlertChannels({
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('field_channel_type')} labelAlign="left" name="type">
|
||||
<Select
|
||||
<SelectSimple
|
||||
disabled={editing}
|
||||
onChange={onTypeChangeHandler}
|
||||
onChange={(value): void => onTypeChangeHandler(value as ChannelType)}
|
||||
value={type}
|
||||
data-testid="channel-type-select"
|
||||
>
|
||||
<Select.Option value="slack" key="slack" data-testid="select-option">
|
||||
Slack
|
||||
</Select.Option>
|
||||
<Select.Option value="webhook" key="webhook" data-testid="select-option">
|
||||
Webhook
|
||||
</Select.Option>
|
||||
<Select.Option
|
||||
value="pagerduty"
|
||||
key="pagerduty"
|
||||
data-testid="select-option"
|
||||
>
|
||||
Pagerduty
|
||||
</Select.Option>
|
||||
<Select.Option
|
||||
value="opsgenie"
|
||||
key="opsgenie"
|
||||
data-testid="select-option"
|
||||
>
|
||||
Opsgenie
|
||||
</Select.Option>
|
||||
<Select.Option value="email" key="email" data-testid="select-option">
|
||||
Email
|
||||
</Select.Option>
|
||||
|
||||
<Select.Option value="msteams" key="msteams" data-testid="select-option">
|
||||
Microsoft Teams
|
||||
</Select.Option>
|
||||
</Select>
|
||||
testId="channel-type-select"
|
||||
items={[
|
||||
{ value: 'slack', label: 'Slack' },
|
||||
{ value: 'webhook', label: 'Webhook' },
|
||||
{ value: 'pagerduty', label: 'Pagerduty' },
|
||||
{ value: 'opsgenie', label: 'Opsgenie' },
|
||||
{ value: 'email', label: 'Email' },
|
||||
{ value: 'msteams', label: 'Microsoft Teams' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>{renderSettings()}</Form.Item>
|
||||
|
||||
@@ -2,8 +2,9 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Plus } from '@signozhq/icons';
|
||||
import { Button, Flex, Form, Select, Tooltip } from 'antd';
|
||||
import { Switch } from '@signozhq/ui/switch';
|
||||
import { Button, Flex, Form, Tooltip } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import getAll from 'api/channels/getAll';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
||||
@@ -17,7 +18,6 @@ import { Channels } from 'types/api/channels/getAll';
|
||||
import APIError from 'types/api/error';
|
||||
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
|
||||
import { openInNewTab } from 'utils/navigation';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import ChannelSelect from './ChannelSelect';
|
||||
import LabelSelect from './labels';
|
||||
@@ -25,15 +25,12 @@ import {
|
||||
FormContainer,
|
||||
FormItemMedium,
|
||||
InputSmall,
|
||||
SeveritySelect,
|
||||
StepHeading,
|
||||
TextareaMedium,
|
||||
} from './styles';
|
||||
|
||||
import './FormAlertRules.styles.scss';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
interface BasicInfoProps {
|
||||
isNewRule: boolean;
|
||||
alertDef: AlertDef;
|
||||
@@ -116,10 +113,9 @@ function BasicInfo({
|
||||
labelAlign="left"
|
||||
name={['labels', 'severity']}
|
||||
>
|
||||
<SeveritySelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue="critical"
|
||||
onChange={(value: unknown | string): void => {
|
||||
onChange={(value): void => {
|
||||
const s = (value as string) || 'critical';
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -129,12 +125,14 @@ function BasicInfo({
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Option value="critical">{t('option_critical')}</Option>
|
||||
<Option value="error">{t('option_error')}</Option>
|
||||
<Option value="warning">{t('option_warning')}</Option>
|
||||
<Option value="info">{t('option_info')}</Option>
|
||||
</SeveritySelect>
|
||||
items={[
|
||||
{ value: 'critical', label: t('option_critical') },
|
||||
{ value: 'error', label: t('option_error') },
|
||||
{ value: 'warning', label: t('option_warning') },
|
||||
{ value: 'info', label: t('option_info') },
|
||||
]}
|
||||
style={{ width: '25%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Plus } from '@signozhq/icons';
|
||||
import { Select, Spin } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import useComponentPermission from 'hooks/useComponentPermission';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { Channels } from 'types/api/channels/getAll';
|
||||
import APIError from 'types/api/error';
|
||||
|
||||
import { StyledCreateChannelOption, StyledSelect } from './styles';
|
||||
import { StyledCreateChannelOption } from './styles';
|
||||
|
||||
const ADD_NEW_CHANNEL_VALUE = 'add-new-channel';
|
||||
|
||||
export interface ChannelSelectProps {
|
||||
disabled?: boolean;
|
||||
@@ -38,12 +40,13 @@ function ChannelSelect({
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const handleChange = (value: string[]): void => {
|
||||
if (value.includes('add-new-channel')) {
|
||||
const handleChange = (value: string | string[]): void => {
|
||||
const arr = Array.isArray(value) ? value : [value];
|
||||
if (arr.includes(ADD_NEW_CHANNEL_VALUE)) {
|
||||
handleCreateNewChannels();
|
||||
return;
|
||||
}
|
||||
onSelectChannels(value);
|
||||
onSelectChannels(arr);
|
||||
};
|
||||
|
||||
if (hasError) {
|
||||
@@ -59,57 +62,55 @@ function ChannelSelect({
|
||||
user.role,
|
||||
);
|
||||
|
||||
const renderOptions = (): ReactNode[] => {
|
||||
const children: ReactNode[] = [];
|
||||
const items = useMemo<ComboboxSimpleItem[]>(() => {
|
||||
const result: ComboboxSimpleItem[] = [];
|
||||
|
||||
if (!isLoading && addNewChannelPermission) {
|
||||
children.push(
|
||||
<Select.Option key="add-new-channel" value="add-new-channel">
|
||||
result.push({
|
||||
value: ADD_NEW_CHANNEL_VALUE,
|
||||
label: (
|
||||
<StyledCreateChannelOption>
|
||||
<Plus size="md" />
|
||||
Create a new channel
|
||||
</StyledCreateChannelOption>
|
||||
</Select.Option>,
|
||||
);
|
||||
),
|
||||
displayValue: 'Create a new channel',
|
||||
});
|
||||
}
|
||||
|
||||
if (isLoading || channels.length === 0) {
|
||||
return children;
|
||||
if (!isLoading && channels.length > 0) {
|
||||
channels.forEach((o) => {
|
||||
result.push({
|
||||
value: o.name,
|
||||
label: o.name,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
channels.forEach((o) => {
|
||||
children.push(
|
||||
<Select.Option key={o.id} value={o.name}>
|
||||
{o.name}
|
||||
</Select.Option>,
|
||||
);
|
||||
});
|
||||
|
||||
return children;
|
||||
};
|
||||
return result;
|
||||
}, [isLoading, addNewChannelPermission, channels]);
|
||||
|
||||
return (
|
||||
<StyledSelect
|
||||
<ComboboxSimple
|
||||
multiple
|
||||
style={{
|
||||
width: '100%',
|
||||
borderRadius: 4,
|
||||
}}
|
||||
disabled={disabled}
|
||||
status={hasError ? 'error' : ''}
|
||||
mode="multiple"
|
||||
style={{ width: '100%' }}
|
||||
className={hasError ? 'channel-select-error' : undefined}
|
||||
placeholder={t('placeholder_channel_select')}
|
||||
data-testid="alert-channel-select"
|
||||
testId="alert-channel-select"
|
||||
value={currentValue}
|
||||
notFoundContent={isLoading && <Spin size="small" />}
|
||||
onDropdownVisibleChange={(open): void => {
|
||||
if (open) {
|
||||
onDropdownOpen();
|
||||
}
|
||||
}}
|
||||
loading={isLoading}
|
||||
items={items}
|
||||
onChange={(value): void => {
|
||||
handleChange(value as string[]);
|
||||
// ComboboxSimple has no onOpen callback, so we fire onDropdownOpen
|
||||
// (the refetch trigger) on the first interaction via onChange.
|
||||
onDropdownOpen();
|
||||
handleChange(value);
|
||||
}}
|
||||
optionLabelProp="label"
|
||||
>
|
||||
{renderOptions()}
|
||||
</StyledSelect>
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { Select } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const StyledSelect = styled(Select)`
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
export const StyledCreateChannelOption = styled.div`
|
||||
color: var(--accent-primary);
|
||||
display: flex;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
border: none !important;
|
||||
margin-left: 0px !important;
|
||||
padding: 0px !important;
|
||||
border-radius: 0 !important;
|
||||
|
||||
.nav-btns {
|
||||
display: flex;
|
||||
@@ -19,11 +20,13 @@
|
||||
}
|
||||
.ant-btn-default {
|
||||
border-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
.ant-tabs-tab-active {
|
||||
.nav-btns {
|
||||
background: var(--l1-border) !important;
|
||||
background: var(--l3-border) !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +38,10 @@
|
||||
border-bottom: none !important;
|
||||
}
|
||||
.ant-tabs-nav-list {
|
||||
border: 1px solid var(--l1-border);
|
||||
border: 1px solid var(--l3-border);
|
||||
}
|
||||
.ant-tabs-tab + .ant-tabs-tab {
|
||||
border-left: 1px solid var(--l1-border) !important;
|
||||
border-left: 1px solid var(--l3-border) !important;
|
||||
}
|
||||
|
||||
.stage-run-query {
|
||||
@@ -52,8 +55,26 @@
|
||||
}
|
||||
|
||||
.alert-query-section-container {
|
||||
border-color: var(--l1-border);
|
||||
|
||||
--query-builder-v2-color: var(--l2-foreground);
|
||||
--query-builder-v2-background-color: var(--l3-background);
|
||||
--query-builder-v2-border-color: var(--l3-border);
|
||||
--query-builder-v2-selection-background-color: var(--l2-background);
|
||||
--query-builder-v2-chip-decorator-background-color: var(--l2-background);
|
||||
--query-builder-v2-placeholder-color: var(--l3-foreground);
|
||||
--query-builder-v2-selected-background-color: var(--l3-foreground);
|
||||
--query-search-background-color: var(--l3-background);
|
||||
--query-search-background-color-selection: var(--l3-background);
|
||||
--input-with-label-border-color: var(--l3-border);
|
||||
--input-with-label-background-color: var(--l3-background);
|
||||
--input-with-label-color: var(--l2-foreground);
|
||||
|
||||
--combobox-pill-background: var(--l2-background);
|
||||
|
||||
.ant-card-body {
|
||||
padding: 0px;
|
||||
background-color: var(--l2-background);
|
||||
|
||||
.alert-tabs {
|
||||
padding: 0px;
|
||||
|
||||
@@ -8,3 +8,11 @@
|
||||
.rule-unit-selector {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.inline-select {
|
||||
display: inline-block;
|
||||
width: 10%;
|
||||
min-width: 120px;
|
||||
margin-left: 0.3em;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ import {
|
||||
Form,
|
||||
InputNumber,
|
||||
InputNumberProps,
|
||||
Select,
|
||||
SelectProps,
|
||||
Space,
|
||||
} from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { SelectSimple, SelectSimpleItem } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import type { DefaultOptionType } from 'antd/es/select';
|
||||
import {
|
||||
getCategoryByOptionId,
|
||||
getCategorySelectOptionByName,
|
||||
@@ -25,15 +24,9 @@ import {
|
||||
defaultSeasonality,
|
||||
} from 'types/api/alerts/def';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { AlertDetectionTypes } from '.';
|
||||
import {
|
||||
FormContainer,
|
||||
InlineSelect,
|
||||
StepHeading,
|
||||
VerticalLine,
|
||||
} from './styles';
|
||||
import { FormContainer, StepHeading, VerticalLine } from './styles';
|
||||
|
||||
import './RuleOptions.styles.scss';
|
||||
|
||||
@@ -49,7 +42,7 @@ function RuleOptions({
|
||||
|
||||
const { ruleType } = alertDef;
|
||||
|
||||
const handleMatchOptChange = (value: string | unknown): void => {
|
||||
const handleMatchOptChange = (value: string | string[]): void => {
|
||||
const m = (value as string) || alertDef.condition?.matchType;
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -74,13 +67,26 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const compareOpItems: SelectSimpleItem[] = [
|
||||
{ value: '1', label: t('option_above') },
|
||||
{ value: '2', label: t('option_below') },
|
||||
...(ruleType !== 'anomaly_rule'
|
||||
? [
|
||||
{ value: '3', label: t('option_equal') },
|
||||
{ value: '4', label: t('option_notequal') },
|
||||
]
|
||||
: []),
|
||||
...(ruleType === 'anomaly_rule'
|
||||
? [{ value: '7', label: t('option_above_below') }]
|
||||
: []),
|
||||
];
|
||||
|
||||
const renderCompareOps = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultCompareOp}
|
||||
value={alertDef.condition?.op}
|
||||
style={{ minWidth: '120px' }}
|
||||
onChange={(value: string | unknown): void => {
|
||||
items={compareOpItems}
|
||||
onChange={(value): void => {
|
||||
const newOp = (value as string) || '';
|
||||
|
||||
setAlertDef({
|
||||
@@ -91,47 +97,31 @@ function RuleOptions({
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Select.Option value="1">{t('option_above')}</Select.Option>
|
||||
<Select.Option value="2">{t('option_below')}</Select.Option>
|
||||
|
||||
{/* hide equal and not eqaul in case of analmoy based alert */}
|
||||
|
||||
{ruleType !== 'anomaly_rule' && (
|
||||
<>
|
||||
<Select.Option value="3">{t('option_equal')}</Select.Option>
|
||||
<Select.Option value="4">{t('option_notequal')}</Select.Option>
|
||||
</>
|
||||
)}
|
||||
{/* the value 5 and 6 are reserved for above or equal and below or equal */}
|
||||
{ruleType === 'anomaly_rule' && (
|
||||
<Select.Option value="7">{t('option_above_below')}</Select.Option>
|
||||
)}
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const matchOptItems: SelectSimpleItem[] = [
|
||||
{ value: '1', label: t('option_atleastonce') },
|
||||
{ value: '2', label: t('option_allthetimes') },
|
||||
...(ruleType !== 'anomaly_rule'
|
||||
? [
|
||||
{ value: '3', label: t('option_onaverage') },
|
||||
{ value: '4', label: t('option_intotal') },
|
||||
{ value: '5', label: t('option_last') },
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
const renderMatchOpts = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultMatchType}
|
||||
style={{ minWidth: '130px' }}
|
||||
value={alertDef.condition?.matchType}
|
||||
onChange={(value: string | unknown): void => handleMatchOptChange(value)}
|
||||
>
|
||||
<Select.Option value="1">{t('option_atleastonce')}</Select.Option>
|
||||
<Select.Option value="2">{t('option_allthetimes')}</Select.Option>
|
||||
|
||||
{ruleType !== 'anomaly_rule' && (
|
||||
<>
|
||||
<Select.Option value="3">{t('option_onaverage')}</Select.Option>
|
||||
<Select.Option value="4">{t('option_intotal')}</Select.Option>
|
||||
<Select.Option value="5">{t('option_last')}</Select.Option>
|
||||
</>
|
||||
)}
|
||||
</InlineSelect>
|
||||
items={matchOptItems}
|
||||
onChange={handleMatchOptChange}
|
||||
/>
|
||||
);
|
||||
|
||||
const onChangeEvalWindow = (value: string | unknown): void => {
|
||||
const onChangeEvalWindow = (value: string | string[]): void => {
|
||||
const ew = (value as string) || alertDef.evalWindow;
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -139,7 +129,7 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeAlgorithm = (value: string | unknown): void => {
|
||||
const onChangeAlgorithm = (value: string | string[]): void => {
|
||||
const alg = (value as string) || alertDef.condition.algorithm;
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -150,7 +140,7 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeSeasonality = (value: string | unknown): void => {
|
||||
const onChangeSeasonality = (value: string | string[]): void => {
|
||||
const seasonality = (value as string) || alertDef.condition.seasonality;
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -170,97 +160,91 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const evalWindowItems: SelectSimpleItem[] = [
|
||||
{ value: '5m0s', label: t('option_5min') },
|
||||
{ value: '10m0s', label: t('option_10min') },
|
||||
{ value: '15m0s', label: t('option_15min') },
|
||||
{ value: '1h0m0s', label: t('option_60min') },
|
||||
{ value: '4h0m0s', label: t('option_4hours') },
|
||||
{ value: '24h0m0s', label: t('option_24hours') },
|
||||
];
|
||||
|
||||
const renderEvalWindows = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultEvalWindow}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.evalWindow}
|
||||
items={evalWindowItems}
|
||||
onChange={onChangeEvalWindow}
|
||||
>
|
||||
<Select.Option value="5m0s">{t('option_5min')}</Select.Option>
|
||||
<Select.Option value="10m0s">{t('option_10min')}</Select.Option>
|
||||
<Select.Option value="15m0s">{t('option_15min')}</Select.Option>
|
||||
<Select.Option value="1h0m0s">{t('option_60min')}</Select.Option>
|
||||
<Select.Option value="4h0m0s">{t('option_4hours')}</Select.Option>
|
||||
<Select.Option value="24h0m0s">{t('option_24hours')}</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const promEvalWindowItems: SelectSimpleItem[] = [
|
||||
{ value: '5m0s', label: t('option_5min') },
|
||||
{ value: '10m0s', label: t('option_10min') },
|
||||
{ value: '15m0s', label: t('option_15min') },
|
||||
];
|
||||
|
||||
const renderPromEvalWindows = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultEvalWindow}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.evalWindow}
|
||||
items={promEvalWindowItems}
|
||||
onChange={onChangeEvalWindow}
|
||||
>
|
||||
<Select.Option value="5m0s">{t('option_5min')}</Select.Option>
|
||||
<Select.Option value="10m0s">{t('option_10min')}</Select.Option>
|
||||
<Select.Option value="15m0s">{t('option_15min')}</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const renderAlgorithms = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultAlgorithm}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.condition.algorithm}
|
||||
items={[{ value: 'standard', label: 'Standard' }]}
|
||||
onChange={onChangeAlgorithm}
|
||||
>
|
||||
<Select.Option value="standard">Standard</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const deviationItems: SelectSimpleItem[] = [1, 2, 3, 4, 5, 6, 7].map((n) => ({
|
||||
value: String(n),
|
||||
label: String(n),
|
||||
}));
|
||||
|
||||
const renderDeviationOpts = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
defaultValue={3}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.condition.target}
|
||||
onChange={(value: number | unknown): void => {
|
||||
if (typeof value === 'number') {
|
||||
onChangeDeviation(value);
|
||||
<SelectSimple
|
||||
defaultValue="3"
|
||||
value={alertDef.condition.target ? String(alertDef.condition.target) : '3'}
|
||||
items={deviationItems}
|
||||
onChange={(value): void => {
|
||||
const n = Number(value);
|
||||
if (!Number.isNaN(n)) {
|
||||
onChangeDeviation(n);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Select.Option value={1}>1</Select.Option>
|
||||
<Select.Option value={2}>2</Select.Option>
|
||||
<Select.Option value={3}>3</Select.Option>
|
||||
<Select.Option value={4}>4</Select.Option>
|
||||
<Select.Option value={5}>5</Select.Option>
|
||||
<Select.Option value={6}>6</Select.Option>
|
||||
<Select.Option value={7}>7</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const seasonalityItems: SelectSimpleItem[] = [
|
||||
{ value: 'hourly', label: 'Hourly' },
|
||||
{ value: 'daily', label: 'Daily' },
|
||||
{ value: 'weekly', label: 'Weekly' },
|
||||
];
|
||||
|
||||
const renderSeasonality = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultSeasonality}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.condition.seasonality}
|
||||
items={seasonalityItems}
|
||||
onChange={onChangeSeasonality}
|
||||
>
|
||||
<Select.Option value="hourly">Hourly</Select.Option>
|
||||
<Select.Option value="daily">Daily</Select.Option>
|
||||
<Select.Option value="weekly">Weekly</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const renderThresholdRuleOpts = (): JSX.Element => (
|
||||
<Form.Item>
|
||||
<Typography.Text>
|
||||
{t('text_condition1')}
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
options={queryOptions}
|
||||
<ComboboxSimple
|
||||
items={queryOptions}
|
||||
placeholder={t('selected_query_placeholder')}
|
||||
value={alertDef.condition.selectedQueryName}
|
||||
onChange={onChangeSelectedQueryName}
|
||||
value={alertDef.condition.selectedQueryName || ''}
|
||||
onChange={(value): void => onChangeSelectedQueryName(value as string)}
|
||||
/>
|
||||
<Typography.Text>is</Typography.Text>
|
||||
{renderCompareOps()} {t('text_condition2')} {renderMatchOpts()}{' '}
|
||||
@@ -273,14 +257,11 @@ function RuleOptions({
|
||||
<Form.Item>
|
||||
<Typography.Text>
|
||||
{t('text_condition1')}
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
options={queryOptions}
|
||||
<ComboboxSimple
|
||||
items={queryOptions}
|
||||
placeholder={t('selected_query_placeholder')}
|
||||
value={alertDef.condition.selectedQueryName}
|
||||
onChange={onChangeSelectedQueryName}
|
||||
value={alertDef.condition.selectedQueryName || ''}
|
||||
onChange={(value): void => onChangeSelectedQueryName(value as string)}
|
||||
/>
|
||||
<Typography.Text>is</Typography.Text>
|
||||
{renderCompareOps()} {t('text_condition2')} {renderMatchOpts()}
|
||||
@@ -301,7 +282,7 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeAlertUnit: SelectProps['onChange'] = (value) => {
|
||||
const onChangeAlertUnit = (value: string | string[]): void => {
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
condition: {
|
||||
@@ -311,7 +292,7 @@ function RuleOptions({
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeFrequency = (value: string | unknown): void => {
|
||||
const onChangeFrequency = (value: string | string[]): void => {
|
||||
const freq = (value as string) || alertDef.frequency;
|
||||
setAlertDef({
|
||||
...alertDef,
|
||||
@@ -323,14 +304,11 @@ function RuleOptions({
|
||||
<Form.Item>
|
||||
<Typography.Text className="rule-definition">
|
||||
{t('text_condition1_anomaly')}
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
options={queryOptions}
|
||||
<ComboboxSimple
|
||||
items={queryOptions}
|
||||
placeholder={t('selected_query_placeholder')}
|
||||
value={alertDef.condition.selectedQueryName}
|
||||
onChange={onChangeSelectedQueryName}
|
||||
value={alertDef.condition.selectedQueryName || ''}
|
||||
onChange={(value): void => onChangeSelectedQueryName(value as string)}
|
||||
/>
|
||||
{t('text_condition3')} {renderEvalWindows()}
|
||||
<Typography.Text>is</Typography.Text>
|
||||
@@ -345,25 +323,26 @@ function RuleOptions({
|
||||
</Form.Item>
|
||||
);
|
||||
|
||||
const frequencyItems: SelectSimpleItem[] = [
|
||||
{ value: '1m0s', label: t('option_1min') },
|
||||
{ value: '5m0s', label: t('option_5min') },
|
||||
{ value: '10m0s', label: t('option_10min') },
|
||||
{ value: '15m0s', label: t('option_15min') },
|
||||
{ value: '30m0s', label: t('option_30min') },
|
||||
{ value: '1h0m0s', label: t('option_60min') },
|
||||
{ value: '3h0m0s', label: t('option_3hours') },
|
||||
{ value: '6h0m0s', label: t('option_6hours') },
|
||||
{ value: '12h0m0s', label: t('option_12hours') },
|
||||
{ value: '24h0m0s', label: t('option_24hours') },
|
||||
];
|
||||
|
||||
const renderFrequency = (): JSX.Element => (
|
||||
<InlineSelect
|
||||
getPopupContainer={popupContainer}
|
||||
<SelectSimple
|
||||
defaultValue={defaultFrequency}
|
||||
style={{ minWidth: '120px' }}
|
||||
value={alertDef.frequency}
|
||||
items={frequencyItems}
|
||||
onChange={onChangeFrequency}
|
||||
>
|
||||
<Select.Option value="1m0s">{t('option_1min')}</Select.Option>
|
||||
<Select.Option value="5m0s">{t('option_5min')}</Select.Option>
|
||||
<Select.Option value="10m0s">{t('option_10min')}</Select.Option>
|
||||
<Select.Option value="15m0s">{t('option_15min')}</Select.Option>
|
||||
<Select.Option value="30m0s">{t('option_30min')}</Select.Option>
|
||||
<Select.Option value="1h0m0s">{t('option_60min')}</Select.Option>
|
||||
<Select.Option value="3h0m0s">{t('option_3hours')}</Select.Option>
|
||||
<Select.Option value="6h0m0s">{t('option_6hours')}</Select.Option>
|
||||
<Select.Option value="12h0m0s">{t('option_12hours')}</Select.Option>
|
||||
<Select.Option value="24h0m0s">{t('option_24hours')}</Select.Option>
|
||||
</InlineSelect>
|
||||
/>
|
||||
);
|
||||
|
||||
const selectedCategory = getCategoryByOptionId(yAxisUnit);
|
||||
@@ -375,7 +354,7 @@ function RuleOptions({
|
||||
return (
|
||||
<>
|
||||
<StepHeading>{t('alert_form_step3', { step: step3Label })}</StepHeading>
|
||||
<FormContainer>
|
||||
<FormContainer className="rule-options-container">
|
||||
{queryCategory === EQueryType.PROM && renderPromRuleOptions()}
|
||||
{queryCategory !== EQueryType.PROM &&
|
||||
ruleType === AlertDetectionTypes.ANOMALY_DETECTION_ALERT && (
|
||||
@@ -400,15 +379,12 @@ function RuleOptions({
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item noStyle>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
className="rule-unit-selector"
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
options={categorySelectOptions}
|
||||
items={categorySelectOptions as ComboboxSimpleItem[]}
|
||||
placeholder={t('field_unit')}
|
||||
value={alertDef.condition.targetUnit}
|
||||
onChange={onChangeAlertUnit}
|
||||
value={alertDef.condition.targetUnit || ''}
|
||||
onChange={(value): void => onChangeAlertUnit(value as string)}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Space>
|
||||
@@ -514,7 +490,7 @@ interface RuleOptionsProps {
|
||||
alertDef: AlertDef;
|
||||
setAlertDef: (a: AlertDef) => void;
|
||||
queryCategory: EQueryType;
|
||||
queryOptions: DefaultOptionType[];
|
||||
queryOptions: ComboboxSimpleItem[];
|
||||
yAxisUnit: string;
|
||||
}
|
||||
export default RuleOptions;
|
||||
|
||||
@@ -5,7 +5,8 @@ import { useQueryClient } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { BellDot, CircleAlert, ExternalLink, Save } from '@signozhq/icons';
|
||||
import { Button, FormInstance, SelectProps } from 'antd';
|
||||
import { Button, FormInstance } from 'antd';
|
||||
import { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { ConfirmDialog } from '@signozhq/ui/dialog';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
@@ -208,7 +209,7 @@ function FormAlertRules({
|
||||
const involvedQueriesInTraceOperator = getInvolvedQueriesInTraceOperator(
|
||||
currentQuery.builder.queryTraceOperator,
|
||||
);
|
||||
const queryConfig: Record<EQueryType, () => SelectProps['options']> = {
|
||||
const queryConfig: Record<EQueryType, () => ComboboxSimpleItem[]> = {
|
||||
[EQueryType.QUERY_BUILDER]: () => [
|
||||
...(getSelectedQueryOptions(currentQuery.builder.queryData)?.filter(
|
||||
(option) =>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CircleAlert, CircleX } from '@signozhq/icons';
|
||||
import { Button, Input, message, Modal } from 'antd';
|
||||
import { ConfirmDialog } from '@signozhq/ui/dialog';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { Button, Input, message } from 'antd';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { map } from 'lodash-es';
|
||||
import { Labels } from 'types/api/alerts/def';
|
||||
@@ -33,6 +35,7 @@ function LabelSelect({
|
||||
initialValues ? flattenLabels(initialValues) : [],
|
||||
);
|
||||
const [step, setStep] = useState<LabelStep>('Idle');
|
||||
const [showClearConfirm, setShowClearConfirm] = useState(false);
|
||||
|
||||
const dispatchChanges = (updatedRecs: ILabelRecord[]): void => {
|
||||
onSetLabels(prepareLabels(updatedRecs, initialValues));
|
||||
@@ -120,19 +123,16 @@ function LabelSelect({
|
||||
};
|
||||
|
||||
const handleClearAll = (): void => {
|
||||
Modal.confirm({
|
||||
title: 'Confirm',
|
||||
icon: <CircleAlert size="md" />,
|
||||
content: t('remove_label_confirm'),
|
||||
onOk() {
|
||||
send('RESET');
|
||||
dispatchChanges([]);
|
||||
setStaging([]);
|
||||
message.success(t('remove_label_success'));
|
||||
},
|
||||
okText: t('button_yes'),
|
||||
cancelText: t('button_no'),
|
||||
});
|
||||
setShowClearConfirm(true);
|
||||
};
|
||||
|
||||
const handleConfirmClear = (): void => {
|
||||
send('RESET');
|
||||
dispatchChanges([]);
|
||||
setStaging([]);
|
||||
setCurrentVal('');
|
||||
message.success(t('remove_label_success'));
|
||||
setShowClearConfirm(false);
|
||||
};
|
||||
const renderPlaceholder = useCallback((): string => {
|
||||
if (step === 'LabelKey') {
|
||||
@@ -187,6 +187,23 @@ function LabelSelect({
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
open={showClearConfirm}
|
||||
onOpenChange={(next): void => {
|
||||
if (!next) {
|
||||
setShowClearConfirm(false);
|
||||
}
|
||||
}}
|
||||
title={t('title_confirm')}
|
||||
titleIcon={<CircleAlert size={14} />}
|
||||
confirmText={t('button_yes')}
|
||||
cancelText={t('button_no')}
|
||||
onConfirm={handleConfirmClear}
|
||||
onCancel={(): void => setShowClearConfirm(false)}
|
||||
>
|
||||
<Typography>{t('remove_label_confirm')}</Typography>
|
||||
</ConfirmDialog>
|
||||
</SearchContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ interface SearchContainerProps {
|
||||
|
||||
export const SearchContainer = styled.div<SearchContainerProps>`
|
||||
border-radius: 4px;
|
||||
background: ${({ isDarkMode }): string => (isDarkMode ? '#000' : '#fff')};
|
||||
background: var(--l3-background);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.2rem;
|
||||
border: 1px solid #ccc5;
|
||||
border: 1px solid var(--l3-border);
|
||||
${({ disabled }): string => (disabled ? `cursor: not-allowed;` : '')}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Card, Col, Form, Input, Select } from 'antd';
|
||||
import { Button, Card, Col, Form, Input } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -53,17 +53,6 @@ export const StepHeading = styled.p`
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
export const InlineSelect = styled(Select)`
|
||||
display: inline-block;
|
||||
width: 10% !important;
|
||||
margin-left: 0.3em;
|
||||
margin-right: 0.3em;
|
||||
`;
|
||||
|
||||
export const SeveritySelect = styled(Select)`
|
||||
width: 25% !important;
|
||||
`;
|
||||
|
||||
export const VerticalLine = styled.div`
|
||||
border-left: 2px solid #e8e8e8; /* Adjust color and thickness as desired */
|
||||
padding-left: 20px; /* Adjust spacing to content as needed */
|
||||
@@ -80,9 +69,45 @@ export const FormContainer = styled(Card)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 4px;
|
||||
border-color: var(--l2-border);
|
||||
|
||||
.ant-card-body {
|
||||
padding: 12px;
|
||||
background-color: var(--l2-background);
|
||||
}
|
||||
|
||||
--combobox-trigger-width: auto;
|
||||
--combobox-trigger-display: inline-flex;
|
||||
--combobox-trigger-border-color: var(--l3-border);
|
||||
--combobox-trigger-background-color: var(--l3-background);
|
||||
|
||||
--select-trigger-width: auto;
|
||||
--select-trigger-display: inline-flex;
|
||||
--select-trigger-border-color: var(--l3-border);
|
||||
--select-trigger-background-color: var(--l3-background);
|
||||
|
||||
--typography-text-display: inline-flex;
|
||||
|
||||
&.rule-options-container {
|
||||
[data-slot='combobox-trigger'],
|
||||
[data-slot='select-trigger'] {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
[data-slot='typography'] {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
color: var(--l2-foreground);
|
||||
background-color: var(--l3-background);
|
||||
border-color: var(--l3-border);
|
||||
border-width: 1px;
|
||||
|
||||
&:placeholder {
|
||||
color: var(--l3-foreground);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import { Time } from 'container/TopNav/DateTimeSelectionV2/types';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import getStep from 'lib/getStep';
|
||||
@@ -60,7 +60,7 @@ export const getSelectedQueryOptions = (
|
||||
| IClickHouseQuery
|
||||
| IPromQLQuery
|
||||
>,
|
||||
): SelectProps['options'] =>
|
||||
): ComboboxSimpleItem[] =>
|
||||
queries
|
||||
.filter((query) => !query.disabled)
|
||||
.map((query) => ({
|
||||
|
||||
@@ -7,8 +7,9 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Input as SignozInput } from '@signozhq/ui/input';
|
||||
import { Col, Row, Select } from 'antd';
|
||||
import { Col, Row } from 'antd';
|
||||
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
|
||||
import { find } from 'lodash-es';
|
||||
import { TTTLType } from 'types/api/settings/common';
|
||||
@@ -26,8 +27,6 @@ import {
|
||||
TimeUnitsValues,
|
||||
} from './utils';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
function Retention({
|
||||
type,
|
||||
retentionValue,
|
||||
@@ -78,11 +77,10 @@ function Retention({
|
||||
}
|
||||
}, [initialTimeUnitValue]);
|
||||
|
||||
const menuItems = availableUnits.map((option) => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
{option.key}
|
||||
</Option>
|
||||
));
|
||||
const menuItems = availableUnits.map((option) => ({
|
||||
value: option.value,
|
||||
label: option.key,
|
||||
}));
|
||||
|
||||
const currentSelectedOption = (option: SettingPeriod): void => {
|
||||
const selectedValue = find(availableUnits, (e) => e.value === option)?.value;
|
||||
@@ -136,13 +134,12 @@ function Retention({
|
||||
disabled={isCloudUserVal}
|
||||
onChange={(e): void => onChangeHandler(e, setSelectedValue)}
|
||||
/>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={selectedTimeUnit}
|
||||
onChange={currentSelectedOption}
|
||||
onChange={(value): void => currentSelectedOption(value as SettingPeriod)}
|
||||
disabled={isCloudUserVal}
|
||||
>
|
||||
{menuItems}
|
||||
</Select>
|
||||
items={menuItems}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -161,14 +158,13 @@ function Retention({
|
||||
onChange={(e): void => onChangeHandler(e, setSelectedValue)}
|
||||
style={{ width: 75 }}
|
||||
/>
|
||||
<Select
|
||||
<SelectSimple
|
||||
value={selectedTimeUnit}
|
||||
onChange={currentSelectedOption}
|
||||
onChange={(value): void => currentSelectedOption(value as SettingPeriod)}
|
||||
disabled={isCloudUserVal}
|
||||
style={{ width: 100 }}
|
||||
>
|
||||
{menuItems}
|
||||
</Select>
|
||||
items={menuItems}
|
||||
/>
|
||||
</RetentionFieldInputContainer>
|
||||
</Row>
|
||||
</Row>
|
||||
|
||||
@@ -12,24 +12,23 @@
|
||||
line-height: 16px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-type-select {
|
||||
.view-panel-select-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.view-panel-select-option {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.display {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.display {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
@@ -10,8 +10,6 @@ import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import './PanelTypeSelector.scss';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
interface PanelTypeSelectorProps {
|
||||
selectedPanelType: PANEL_TYPES;
|
||||
disabled?: boolean;
|
||||
@@ -28,7 +26,11 @@ function PanelTypeSelector({
|
||||
const { redirectWithQueryBuilderData } = useQueryBuilder();
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newPanelType: PANEL_TYPES): void => {
|
||||
(value: string | string[]): void => {
|
||||
if (Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
const newPanelType = value as PANEL_TYPES;
|
||||
// Transform the query for the new panel type using handleQueryChange
|
||||
const transformedQuery = handleQueryChange(
|
||||
newPanelType as any,
|
||||
@@ -52,23 +54,23 @@ function PanelTypeSelector({
|
||||
|
||||
return (
|
||||
<div className="panel-type-selector">
|
||||
<Select
|
||||
<SelectSimple
|
||||
onChange={handleChange}
|
||||
value={selectedPanelType}
|
||||
style={{ width: '100%' }}
|
||||
className="panel-type-select"
|
||||
data-testid="panel-change-select"
|
||||
disabled={disabled}
|
||||
>
|
||||
{PanelTypesWithData.map((item) => (
|
||||
<Option key={item.name} value={item.name}>
|
||||
items={PanelTypesWithData.map((item) => ({
|
||||
value: item.name,
|
||||
label: (
|
||||
<div className="view-panel-select-option">
|
||||
<div className="icon">{item.icon}</div>
|
||||
<Typography.Text className="display">{item.display}</Typography.Text>
|
||||
</div>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,21 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
--query-builder-v2-color: var(--l2-foreground);
|
||||
--query-builder-v2-background-color: var(--l3-background);
|
||||
--query-builder-v2-border-color: var(--l3-border);
|
||||
--query-builder-v2-selection-background-color: var(--l2-background);
|
||||
--query-builder-v2-chip-decorator-background-color: var(--l2-background);
|
||||
--query-builder-v2-placeholder-color: var(--l3-foreground);
|
||||
--query-builder-v2-selected-background-color: var(--l3-foreground);
|
||||
--query-search-background-color: var(--l3-background);
|
||||
--query-search-background-color-selection: var(--l3-background);
|
||||
--input-with-label-border-color: var(--l3-border);
|
||||
--input-with-label-background-color: var(--l3-background);
|
||||
--input-with-label-color: var(--l2-foreground);
|
||||
|
||||
--combobox-pill-background: var(--l2-background);
|
||||
}
|
||||
|
||||
.graph-container {
|
||||
|
||||
@@ -3,7 +3,8 @@ import { QueryKey } from 'react-query';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Select, Skeleton, Table } from 'antd';
|
||||
import { Button, Skeleton, Table } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import ROUTES from 'constants/routes';
|
||||
@@ -326,10 +327,14 @@ function ServiceMetrics({
|
||||
{' '}
|
||||
Services
|
||||
<div className="services-header-actions">
|
||||
<Select
|
||||
value={timeRange.selectedInterval}
|
||||
onChange={handleTimeIntervalChange}
|
||||
options={TIME_PICKER_OPTIONS}
|
||||
<ComboboxSimple
|
||||
value={timeRange.selectedInterval.toString()}
|
||||
onChange={(value): void => handleTimeIntervalChange(Number(value))}
|
||||
items={TIME_PICKER_OPTIONS.map((opt) => ({
|
||||
value: opt.value.toString(),
|
||||
label: opt.label,
|
||||
displayValue: opt.label,
|
||||
}))}
|
||||
className="services-header-select"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,8 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useSelector } from 'react-redux'; // old code, TODO: fix this correctly
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Select, Skeleton, Table } from 'antd';
|
||||
import { Button, Skeleton, Table } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { useQueryService } from 'hooks/useQueryService';
|
||||
@@ -220,10 +221,14 @@ export default function ServiceTraces({
|
||||
<div className="services-header home-data-card-header">
|
||||
Services
|
||||
<div className="services-header-actions">
|
||||
<Select
|
||||
value={timeRange.selectedInterval}
|
||||
onChange={handleTimeIntervalChange}
|
||||
options={TIME_PICKER_OPTIONS}
|
||||
<ComboboxSimple
|
||||
value={timeRange.selectedInterval.toString()}
|
||||
onChange={(value): void => handleTimeIntervalChange(Number(value))}
|
||||
items={TIME_PICKER_OPTIONS.map((opt) => ({
|
||||
value: opt.value.toString(),
|
||||
label: opt.label,
|
||||
displayValue: opt.label,
|
||||
}))}
|
||||
className="services-header-select"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
align-items: center;
|
||||
gap: var(--spacing-4);
|
||||
|
||||
--combobox-trigger-border-color: var(--l2-border);
|
||||
--combobox-trigger-background-color: var(--l2-background);
|
||||
--combobox-trigger-border-radius: 0px 2px 2px 0px;
|
||||
|
||||
:global(.ant-select-selector) {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--border) !important;
|
||||
border: 1px solid var(--l2-border) !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
|
||||
input {
|
||||
@@ -18,6 +22,16 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.timeSelection-input) {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--l2-border) !important;
|
||||
background-color: var(--l2-background) !important;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--l2-border) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.k8SListControlsLeft {
|
||||
@@ -49,8 +63,10 @@
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.07px;
|
||||
|
||||
background-color: var(--l2-background);
|
||||
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--border);
|
||||
border: 1px solid var(--l2-border);
|
||||
border-right: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
@@ -64,10 +80,10 @@
|
||||
}
|
||||
|
||||
.groupBySelect {
|
||||
:global(.ant-select-selector) {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
transition: 200ms box-shadow ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 2px rgba(62, 86, 245, 0.09);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Select } from 'antd';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { TableColumnDef } from 'components/TanStackTableView';
|
||||
import { InfraMonitoringEvents } from 'constants/events';
|
||||
@@ -185,17 +185,17 @@ function K8sHeader<TData>({
|
||||
|
||||
<div className={styles.k8SAttributeSearchContainer}>
|
||||
<div className={styles.groupByLabel}> Group by </div>
|
||||
<Select
|
||||
<ComboboxSimple
|
||||
className={styles.groupBySelect}
|
||||
loading={isLoadingGroupByFilters}
|
||||
mode="multiple"
|
||||
value={groupBy}
|
||||
allowClear
|
||||
maxTagCount="responsive"
|
||||
multiple
|
||||
value={groupBy.map((g) => g.key)}
|
||||
placeholder="Search for attribute"
|
||||
style={{ width: '100%' }}
|
||||
options={groupByOptions}
|
||||
onChange={handleGroupByChange}
|
||||
items={groupByOptions}
|
||||
onChange={(value): void =>
|
||||
handleGroupByChange(value as unknown as IBuilderQuery['groupBy'])
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useCopyToClipboard } from 'react-use';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Badge } from '@signozhq/ui/badge';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import {
|
||||
Col,
|
||||
Collapse,
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
InputNumber,
|
||||
Modal,
|
||||
Row,
|
||||
Select,
|
||||
Table,
|
||||
TablePaginationConfig,
|
||||
TableProps as AntDTableProps,
|
||||
@@ -84,7 +84,18 @@ import { getDaysUntilExpiry } from 'utils/timeUtils';
|
||||
|
||||
import './IngestionSettings.styles.scss';
|
||||
|
||||
const { Option } = Select;
|
||||
const SIZE_UNIT_ITEMS = [
|
||||
{ value: 'TiB', label: 'TiB' },
|
||||
{ value: 'GiB', label: 'GiB' },
|
||||
{ value: 'MiB', label: 'MiB' },
|
||||
{ value: 'KiB', label: 'KiB' },
|
||||
];
|
||||
|
||||
const COUNT_UNIT_ITEMS = [
|
||||
{ value: 'thousand', label: 'Thousand' },
|
||||
{ value: 'million', label: 'Million' },
|
||||
{ value: 'billion', label: 'Billion' },
|
||||
];
|
||||
|
||||
const BYTES = 1073741824;
|
||||
|
||||
@@ -1212,12 +1223,11 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
<InputNumber
|
||||
disabled={!activeSignal?.config?.day?.enabled}
|
||||
addonAfter={
|
||||
<Select defaultValue="GiB" disabled>
|
||||
<Option value="TiB">TiB</Option>
|
||||
<Option value="GiB">GiB</Option>
|
||||
<Option value="MiB">MiB</Option>
|
||||
<Option value="KiB">KiB</Option>
|
||||
</Select>
|
||||
<SelectSimple
|
||||
defaultValue="GiB"
|
||||
disabled
|
||||
items={SIZE_UNIT_ITEMS}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -1240,15 +1250,12 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
noStyle
|
||||
initialValue="million"
|
||||
>
|
||||
<Select
|
||||
<SelectSimple
|
||||
style={{
|
||||
width: 90,
|
||||
}}
|
||||
>
|
||||
<Option value="thousand">Thousand</Option>
|
||||
<Option value="million">Million</Option>
|
||||
<Option value="billion">Billion</Option>
|
||||
</Select>
|
||||
items={COUNT_UNIT_ITEMS}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
/>
|
||||
@@ -1301,12 +1308,11 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
<InputNumber
|
||||
disabled={!activeSignal?.config?.second?.enabled}
|
||||
addonAfter={
|
||||
<Select defaultValue="GiB" disabled>
|
||||
<Option value="TiB">TiB</Option>
|
||||
<Option value="GiB">GiB</Option>
|
||||
<Option value="MiB">MiB</Option>
|
||||
<Option value="KiB">KiB</Option>
|
||||
</Select>
|
||||
<SelectSimple
|
||||
defaultValue="GiB"
|
||||
disabled
|
||||
items={SIZE_UNIT_ITEMS}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -1329,15 +1335,12 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
noStyle
|
||||
initialValue="million"
|
||||
>
|
||||
<Select
|
||||
<SelectSimple
|
||||
style={{
|
||||
width: 90,
|
||||
}}
|
||||
>
|
||||
<Option value="thousand">Thousand</Option>
|
||||
<Option value="million">Million</Option>
|
||||
<Option value="billion">Billion</Option>
|
||||
</Select>
|
||||
items={COUNT_UNIT_ITEMS}
|
||||
/>
|
||||
</Form.Item>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Select, Skeleton } from 'antd';
|
||||
import { SelectProps } from 'antd/lib';
|
||||
import { Skeleton } from 'antd';
|
||||
import { ComboboxSimple, ComboboxSimpleItem } from '@signozhq/ui/combobox';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { useListAccounts } from 'api/generated/services/cloudintegration';
|
||||
import cx from 'classnames';
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
IntegrationType,
|
||||
} from 'container/Integrations/types';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { ChevronDown, Dot, PencilLine, Plug, Plus } from '@signozhq/icons';
|
||||
import { Dot, PencilLine, Plug, Plus } from '@signozhq/icons';
|
||||
|
||||
import AzureCloudAccountSetupModal from '../../AzureCloudServices/AddNewAccount/CloudAccountSetupModal';
|
||||
import AzureAccountSettingsModal from '../../AzureCloudServices/EditAccount/AccountSettingsModal';
|
||||
@@ -41,7 +41,7 @@ function AccountActionsRenderer({
|
||||
accounts: IntegrationCloudAccount[] | undefined;
|
||||
isLoading: boolean;
|
||||
activeAccount: IntegrationCloudAccount | null;
|
||||
selectOptions: SelectProps['options'];
|
||||
selectOptions: ComboboxSimpleItem[];
|
||||
onAccountChange: (value: string) => void;
|
||||
onIntegrationModalOpen: () => void;
|
||||
onAccountSettingsModalOpen: () => void;
|
||||
@@ -65,16 +65,14 @@ function AccountActionsRenderer({
|
||||
<div className="account-selector-label">Account:</div>
|
||||
|
||||
<span className="account-selector">
|
||||
<Select
|
||||
value={activeAccount?.providerAccountId}
|
||||
options={selectOptions}
|
||||
rootClassName={cx('cloud-account-selector', {
|
||||
<ComboboxSimple
|
||||
value={activeAccount?.providerAccountId ?? ''}
|
||||
items={selectOptions}
|
||||
className={cx('cloud-account-selector', {
|
||||
[type.toLowerCase()]: type,
|
||||
})}
|
||||
popupMatchSelectWidth={false}
|
||||
placeholder={`Select ${type} Account`}
|
||||
suffixIcon={<ChevronDown size={16} color={Color.BG_VANILLA_400} />}
|
||||
onChange={onAccountChange}
|
||||
onChange={(value): void => onAccountChange(value as string)}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
@@ -218,7 +216,7 @@ function AccountActions({ type }: { type: IntegrationType }): JSX.Element {
|
||||
}
|
||||
}, [activeAccount, type]);
|
||||
|
||||
const selectOptions: SelectProps['options'] = useMemo(
|
||||
const selectOptions: ComboboxSimpleItem[] = useMemo(
|
||||
() =>
|
||||
accounts?.length
|
||||
? accounts.map((account) => ({
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Form, Select } from 'antd';
|
||||
import { ChevronDown } from '@signozhq/icons';
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react';
|
||||
import { Form } from 'antd';
|
||||
import { SelectSimple, SelectSimpleItem } from '@signozhq/ui/select';
|
||||
import { Region } from 'utils/regions';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { RegionSelector } from './RegionForm/RegionSelector';
|
||||
|
||||
@@ -17,6 +15,17 @@ function RegionDeploymentSection({
|
||||
handleRegionChange: (value: string) => void;
|
||||
isFormDisabled: boolean;
|
||||
}): JSX.Element {
|
||||
const regionItems = useMemo<SelectSimpleItem[]>(
|
||||
() =>
|
||||
regions.flatMap((region) =>
|
||||
region.subRegions.map((subRegion) => ({
|
||||
value: subRegion.id,
|
||||
label: subRegion.displayName,
|
||||
})),
|
||||
),
|
||||
[regions],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="cloud-account-setup-form__form-group">
|
||||
<div className="cloud-account-setup-form__title">
|
||||
@@ -30,22 +39,13 @@ function RegionDeploymentSection({
|
||||
rules={[{ required: true, message: 'Please select a region' }]}
|
||||
className="cloud-account-setup-form__form-item"
|
||||
>
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="e.g. US East (N. Virginia)"
|
||||
suffixIcon={<ChevronDown size={16} color={Color.BG_VANILLA_400} />}
|
||||
className="cloud-account-setup-form__select integrations-select"
|
||||
onChange={handleRegionChange}
|
||||
onChange={(value): void => handleRegionChange(value as string)}
|
||||
disabled={isFormDisabled}
|
||||
getPopupContainer={popupContainer}
|
||||
>
|
||||
{regions.flatMap((region) =>
|
||||
region.subRegions.map((subRegion) => (
|
||||
<Select.Option key={subRegion.id} value={subRegion.id}>
|
||||
{subRegion.displayName}
|
||||
</Select.Option>
|
||||
)),
|
||||
)}
|
||||
</Select>
|
||||
items={regionItems}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Select, Skeleton } from 'antd';
|
||||
import {
|
||||
ClipboardEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { Skeleton } from 'antd';
|
||||
import { useListAccounts } from 'api/generated/services/cloudintegration';
|
||||
import { INTEGRATION_TYPES } from 'container/Integrations/constants';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
@@ -95,6 +102,30 @@ function S3BucketsSelector({
|
||||
[onChange],
|
||||
);
|
||||
|
||||
// Replicates antd `tokenSeparators={[',']}` for pasted text.
|
||||
const handleRegionPaste = useCallback(
|
||||
(region: string) =>
|
||||
(event: ClipboardEvent<HTMLDivElement>): void => {
|
||||
const pasted = event.clipboardData?.getData('text');
|
||||
if (!pasted || !pasted.includes(',')) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const tokens = pasted
|
||||
.split(',')
|
||||
.map((token) => token.trim())
|
||||
.filter(Boolean);
|
||||
if (tokens.length === 0) {
|
||||
return;
|
||||
}
|
||||
const existing = bucketsByRegion[region] ?? [];
|
||||
const merged = Array.from(new Set([...existing, ...tokens]));
|
||||
handleRegionBucketsChange(region, merged);
|
||||
},
|
||||
[bucketsByRegion, handleRegionBucketsChange],
|
||||
);
|
||||
|
||||
// Show loading state while fetching account data
|
||||
if (isLoading || !activeAccount) {
|
||||
return <Skeleton active />;
|
||||
@@ -106,6 +137,7 @@ function S3BucketsSelector({
|
||||
<div className="s3-buckets-selector-content">
|
||||
{allRegions.map((region) => {
|
||||
const isRegionUnavailable = isRegionDisabled(region);
|
||||
const isRegionFieldDisabled = isSelectorDisabled || isRegionUnavailable;
|
||||
|
||||
return (
|
||||
<div key={region} className="s3-buckets-selector-region">
|
||||
@@ -118,19 +150,26 @@ function S3BucketsSelector({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="s3-buckets-selector-region-select">
|
||||
<Select
|
||||
mode="tags"
|
||||
<div
|
||||
className="s3-buckets-selector-region-select"
|
||||
onPaste={isRegionFieldDisabled ? undefined : handleRegionPaste(region)}
|
||||
>
|
||||
<ComboboxSimple
|
||||
multiple
|
||||
allowCreate
|
||||
items={[]}
|
||||
placeholder={`Enter S3 bucket names for ${region}`}
|
||||
value={bucketsByRegion[region] || []}
|
||||
onChange={(value): void => handleRegionBucketsChange(region, value)}
|
||||
tokenSeparators={[',']}
|
||||
allowClear
|
||||
disabled={isSelectorDisabled || isRegionUnavailable}
|
||||
suffixIcon={null}
|
||||
notFoundContent={null}
|
||||
filterOption={false}
|
||||
showSearch
|
||||
onChange={(v): void =>
|
||||
handleRegionBucketsChange(region, v as string[])
|
||||
}
|
||||
style={{
|
||||
width: '100%',
|
||||
...(isRegionFieldDisabled && {
|
||||
pointerEvents: 'none',
|
||||
opacity: 0.5,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { ClipboardEvent, useCallback, useRef, useState } from 'react';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import {
|
||||
ChevronDown,
|
||||
@@ -8,9 +8,11 @@ import {
|
||||
} from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Callout } from '@signozhq/ui/callout';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { DrawerWrapper } from '@signozhq/ui/drawer';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Tabs } from '@signozhq/ui/tabs';
|
||||
import { Form, Select, Spin } from 'antd';
|
||||
import { Form, Spin } from 'antd';
|
||||
import { useGetAccount } from 'api/generated/services/cloudintegration';
|
||||
import { CloudintegrationtypesAccountDTO } from 'api/generated/services/sigNoz.schemas';
|
||||
import CodeBlock from 'components/CodeBlock/CodeBlock';
|
||||
@@ -22,7 +24,6 @@ import {
|
||||
IntegrationModalProps,
|
||||
ModalStateEnum,
|
||||
} from 'container/Integrations/HeroSection/types';
|
||||
import { popupContainer } from 'utils/selectPopupContainer';
|
||||
|
||||
import { useIntegrationModal } from '../../../../../hooks/integration/azure/useIntegrationModal';
|
||||
import RenderConnectionFields from '../../AmazonWebServices/RegionForm/RenderConnectionParams';
|
||||
@@ -34,6 +35,65 @@ const AZURE_CLI_DESC =
|
||||
const AZURE_POWERSHELL_DESC =
|
||||
'Paste the following command in PowerShell CloudShell on Azure portal, you can switch to PowerShell on Azure portal.';
|
||||
|
||||
interface ResourceGroupsComboboxProps {
|
||||
value?: string[];
|
||||
onChange?: (value: string[]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper that adapts ComboboxSimple to antd Form.Item and re-implements
|
||||
* the antd `tokenSeparators={[',']}` paste behavior the original Select had.
|
||||
*/
|
||||
function ResourceGroupsCombobox({
|
||||
value,
|
||||
onChange,
|
||||
disabled,
|
||||
}: ResourceGroupsComboboxProps): JSX.Element {
|
||||
const current = value ?? [];
|
||||
|
||||
const handlePaste = (event: ClipboardEvent<HTMLDivElement>): void => {
|
||||
const pasted = event.clipboardData?.getData('text');
|
||||
if (!pasted || !pasted.includes(',')) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const tokens = pasted
|
||||
.split(',')
|
||||
.map((token) => token.trim())
|
||||
.filter(Boolean);
|
||||
if (tokens.length === 0) {
|
||||
return;
|
||||
}
|
||||
const merged = Array.from(new Set([...current, ...tokens]));
|
||||
onChange?.(merged);
|
||||
};
|
||||
|
||||
return (
|
||||
<div onPaste={disabled ? undefined : handlePaste} style={{ width: '100%' }}>
|
||||
<ComboboxSimple
|
||||
multiple
|
||||
allowCreate
|
||||
items={[]}
|
||||
placeholder="e.g. prod-platform-rg"
|
||||
value={current}
|
||||
onChange={(v): void => onChange?.(v as string[])}
|
||||
style={{
|
||||
width: '100%',
|
||||
...(disabled && { pointerEvents: 'none', opacity: 0.5 }),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ResourceGroupsCombobox.defaultProps = {
|
||||
value: undefined,
|
||||
onChange: undefined,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
function CloudAccountSetupModal({
|
||||
onClose,
|
||||
}: IntegrationModalProps): JSX.Element {
|
||||
@@ -264,13 +324,12 @@ function CloudAccountSetupModal({
|
||||
rules={[{ required: true, message: 'Please select a region' }]}
|
||||
className="cloud-account-setup-form__form-item"
|
||||
>
|
||||
<Select
|
||||
<SelectSimple
|
||||
placeholder="e.g. East US"
|
||||
options={AZURE_REGIONS.map((region) => ({
|
||||
items={AZURE_REGIONS.map((region) => ({
|
||||
label: `${region.label} (${region.value})`,
|
||||
value: region.value,
|
||||
}))}
|
||||
getPopupContainer={popupContainer}
|
||||
disabled={modalState === ModalStateEnum.WAITING}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -295,10 +354,7 @@ function CloudAccountSetupModal({
|
||||
]}
|
||||
className="cloud-account-setup-form__form-item"
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
placeholder="e.g. prod-platform-rg"
|
||||
tokenSeparators={[',']}
|
||||
<ResourceGroupsCombobox
|
||||
disabled={modalState === ModalStateEnum.WAITING}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { ComboboxSimple } from '@signozhq/ui/combobox';
|
||||
import { DrawerWrapper } from '@signozhq/ui/drawer';
|
||||
import { Form, Select } from 'antd';
|
||||
import { Form } from 'antd';
|
||||
import { invalidateListAccounts } from 'api/generated/services/cloudintegration';
|
||||
import { INTEGRATION_TYPES } from 'container/Integrations/constants';
|
||||
import { CloudAccount } from 'container/Integrations/types';
|
||||
@@ -132,11 +133,13 @@ function AccountSettingsModal({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
<ComboboxSimple
|
||||
multiple
|
||||
allowCreate
|
||||
items={[]}
|
||||
value={resourceGroups}
|
||||
onChange={(values): void => {
|
||||
setResourceGroups(values);
|
||||
setResourceGroups(values as string[]);
|
||||
form.setFieldValue('resourceGroups', values);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useLogsTableColumns } from 'components/Logs/TableView/useLogsTableColum
|
||||
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
|
||||
import type { TanStackTableHandle } from 'components/TanStackTableView';
|
||||
import TanStackTable from 'components/TanStackTableView';
|
||||
import { useHiddenColumnIds } from 'components/TanStackTableView/useColumnStore';
|
||||
import { CARD_BODY_STYLE } from 'constants/card';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { OptionFormatTypes } from 'constants/optionsFormatTypes';
|
||||
@@ -23,11 +24,13 @@ import { QueryParams } from 'constants/query';
|
||||
import { InfinityWrapperStyled } from 'container/LogsExplorerList/styles';
|
||||
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
|
||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
||||
import useLogDetailHandlers from 'hooks/logs/useLogDetailHandlers';
|
||||
import useScrollToLog from 'hooks/logs/useScrollToLog';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { useEventSource } from 'providers/EventSource';
|
||||
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
// interfaces
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { DataSource, StringOperators } from 'types/common/queryBuilder';
|
||||
@@ -51,6 +54,9 @@ function LiveLogsList({
|
||||
const { isConnectionLoading } = useEventSource();
|
||||
|
||||
const { activeLogId } = useCopyLogLink();
|
||||
const { logs: logsPreferences } = usePreferenceContext();
|
||||
const hiddenColumnIds = useHiddenColumnIds(LOCALSTORAGE.LOGS_LIST_COLUMNS);
|
||||
const hasReconciledHiddenColumnsRef = useRef(false);
|
||||
|
||||
const {
|
||||
activeLog,
|
||||
@@ -66,7 +72,7 @@ function LiveLogsList({
|
||||
[logs],
|
||||
);
|
||||
|
||||
const { options, config } = useOptionsMenu({
|
||||
const { options } = useOptionsMenu({
|
||||
storageKey: LOCALSTORAGE.LOGS_LIST_OPTIONS,
|
||||
dataSource: DataSource.LOGS,
|
||||
aggregateOperator: StringOperators.NOOP,
|
||||
@@ -77,7 +83,16 @@ function LiveLogsList({
|
||||
[formattedLogs, activeLogId],
|
||||
);
|
||||
|
||||
const selectedFields = convertKeysToColumnFields(options.selectColumns);
|
||||
const selectedFields = convertKeysToColumnFields([
|
||||
...defaultLogsSelectedColumns,
|
||||
...options.selectColumns,
|
||||
]);
|
||||
|
||||
const syncedSelectedColumns = useMemo(
|
||||
() =>
|
||||
options.selectColumns.filter(({ name }) => !hiddenColumnIds.includes(name)),
|
||||
[options.selectColumns, hiddenColumnIds],
|
||||
);
|
||||
|
||||
const logsColumns = useLogsTableColumns({
|
||||
fields: selectedFields,
|
||||
@@ -85,6 +100,30 @@ function LiveLogsList({
|
||||
appendTo: 'end',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (hasReconciledHiddenColumnsRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasReconciledHiddenColumnsRef.current = true;
|
||||
|
||||
if (syncedSelectedColumns.length === options.selectColumns.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
logsPreferences.updateColumns(syncedSelectedColumns);
|
||||
}, [logsPreferences, options.selectColumns.length, syncedSelectedColumns]);
|
||||
|
||||
const handleColumnRemove = useCallback(
|
||||
(columnId: string) => {
|
||||
const updatedColumns = options.selectColumns.filter(
|
||||
({ name }) => name !== columnId,
|
||||
);
|
||||
logsPreferences.updateColumns(updatedColumns);
|
||||
},
|
||||
[options.selectColumns, logsPreferences],
|
||||
);
|
||||
|
||||
const makeOnLogCopy = useCallback(
|
||||
(log: ILog) =>
|
||||
(event: MouseEvent<HTMLElement>): void => {
|
||||
@@ -198,7 +237,7 @@ function LiveLogsList({
|
||||
ref={ref as React.Ref<TanStackTableHandle>}
|
||||
columns={logsColumns}
|
||||
columnStorageKey={LOCALSTORAGE.LOGS_LIST_COLUMNS}
|
||||
onColumnRemove={config?.addColumn?.onRemove}
|
||||
onColumnRemove={handleColumnRemove}
|
||||
plainTextCellLineClamp={options.maxLines}
|
||||
cellTypographySize={options.fontSize}
|
||||
data={formattedLogs}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { green } from '@ant-design/colors';
|
||||
import { Pause, Play, EllipsisVertical } from '@signozhq/icons';
|
||||
import { Button, Flex, Popover, Select, Space } from 'antd';
|
||||
import { Button, Flex, Popover, Space } from 'antd';
|
||||
import { LiveTail } from 'api/logs/livetail';
|
||||
import dayjs from 'dayjs';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
@@ -165,24 +165,22 @@ function LogLiveTail({ getLogsAggregate }: Props): JSX.Element {
|
||||
const OptionsPopOverContent = useMemo(
|
||||
() => (
|
||||
<TimePickerSelect
|
||||
getPopupContainer={popupContainer}
|
||||
disabled={liveTail === 'PLAYING'}
|
||||
value={liveTailStartRange}
|
||||
value={String(liveTailStartRange)}
|
||||
onChange={(value): void => {
|
||||
if (typeof value === 'number') {
|
||||
const numValue = Number(value);
|
||||
if (!Number.isNaN(numValue)) {
|
||||
dispatch({
|
||||
type: SET_LIVE_TAIL_START_TIME,
|
||||
payload: value,
|
||||
payload: numValue,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{TIME_PICKER_OPTIONS.map((optionData) => (
|
||||
<Select.Option key={optionData.label} value={optionData.value}>
|
||||
Last {optionData.label}
|
||||
</Select.Option>
|
||||
))}
|
||||
</TimePickerSelect>
|
||||
items={TIME_PICKER_OPTIONS.map((optionData) => ({
|
||||
value: String(optionData.value),
|
||||
label: `Last ${optionData.label}`,
|
||||
}))}
|
||||
/>
|
||||
),
|
||||
[dispatch, liveTail, liveTailStartRange],
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Card, Select } from 'antd';
|
||||
import { Card } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const TimePickerCard = styled(Card)`
|
||||
@@ -8,7 +9,7 @@ export const TimePickerCard = styled(Card)`
|
||||
}
|
||||
`;
|
||||
|
||||
export const TimePickerSelect = styled(Select)`
|
||||
export const TimePickerSelect = styled(SelectSimple)`
|
||||
min-width: 100px;
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { SelectSimple } from '@signozhq/ui/select';
|
||||
import { Form, Input } from 'antd';
|
||||
import { Typography } from '@signozhq/ui/typography';
|
||||
import getVersion from 'api/v1/version/get';
|
||||
import get from 'api/v2/sessions/context/get';
|
||||
@@ -339,17 +340,18 @@ function Login(): JSX.Element {
|
||||
<ParentContainer>
|
||||
<Label htmlFor="orgId">Organization Name</Label>
|
||||
<FormContainer.Item name="orgId">
|
||||
<Select
|
||||
<SelectSimple
|
||||
id="orgId"
|
||||
data-testid="orgId"
|
||||
testId="orgId"
|
||||
className="login-form-input login-form-select-no-border"
|
||||
placeholder="Select your organization"
|
||||
options={sessionsContext.orgs.map((org) => ({
|
||||
items={sessionsContext.orgs.map((org) => ({
|
||||
value: org.id,
|
||||
label: org.name || 'default',
|
||||
}))}
|
||||
onChange={(value: string): void => {
|
||||
setSessionsOrgId(value);
|
||||
onChange={(value): void => {
|
||||
setSessionsOrgId(value as string);
|
||||
form.setFieldValue('orgId', value);
|
||||
}}
|
||||
/>
|
||||
</FormContainer.Item>
|
||||
|
||||
@@ -18,19 +18,21 @@ import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
|
||||
import Spinner from 'components/Spinner';
|
||||
import type { TanStackTableHandle } from 'components/TanStackTableView';
|
||||
import TanStackTable from 'components/TanStackTableView';
|
||||
import type { TableColumnDef } from 'components/TanStackTableView/types';
|
||||
import { useHiddenColumnIds } from 'components/TanStackTableView/useColumnStore';
|
||||
import { CARD_BODY_STYLE } from 'constants/card';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch';
|
||||
import { LogsLoading } from 'container/LogsLoading/LogsLoading';
|
||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
||||
import useLogDetailHandlers from 'hooks/logs/useLogDetailHandlers';
|
||||
import useScrollToLog from 'hooks/logs/useScrollToLog';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
import APIError from 'types/api/error';
|
||||
// interfaces
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
@@ -67,6 +69,10 @@ function LogsExplorerList({
|
||||
const [, setCopy] = useCopyToClipboard();
|
||||
const isDarkMode = useIsDarkMode();
|
||||
const { activeLogId } = useCopyLogLink();
|
||||
const { logs: logsPreferences } = usePreferenceContext();
|
||||
const hiddenColumnIds = useHiddenColumnIds(LOCALSTORAGE.LOGS_LIST_COLUMNS);
|
||||
const hasReconciledHiddenColumnsRef = useRef(false);
|
||||
|
||||
const {
|
||||
activeLog,
|
||||
onAddToQuery,
|
||||
@@ -75,7 +81,7 @@ function LogsExplorerList({
|
||||
handleCloseLogDetail,
|
||||
} = useLogDetailHandlers();
|
||||
|
||||
const { options, config } = useOptionsMenu({
|
||||
const { options } = useOptionsMenu({
|
||||
storageKey: LOCALSTORAGE.LOGS_LIST_OPTIONS,
|
||||
dataSource: DataSource.LOGS,
|
||||
aggregateOperator:
|
||||
@@ -91,15 +97,28 @@ function LogsExplorerList({
|
||||
);
|
||||
|
||||
const selectedFields = useMemo(
|
||||
() => convertKeysToColumnFields(options.selectColumns),
|
||||
[options.selectColumns],
|
||||
() =>
|
||||
convertKeysToColumnFields([
|
||||
...defaultLogsSelectedColumns,
|
||||
...options.selectColumns,
|
||||
]),
|
||||
[options],
|
||||
);
|
||||
|
||||
const handleColumnOrderChange = useCallback(
|
||||
(cols: TableColumnDef<ILog>[]): void => {
|
||||
config?.addColumn?.onReorder(cols.map((c) => c.id));
|
||||
const syncedSelectedColumns = useMemo(
|
||||
() =>
|
||||
options.selectColumns.filter(({ name }) => !hiddenColumnIds.includes(name)),
|
||||
[options.selectColumns, hiddenColumnIds],
|
||||
);
|
||||
|
||||
const handleColumnRemove = useCallback(
|
||||
(columnId: string) => {
|
||||
const updatedColumns = options.selectColumns.filter(
|
||||
({ name }) => name !== columnId,
|
||||
);
|
||||
logsPreferences.updateColumns(updatedColumns);
|
||||
},
|
||||
[config],
|
||||
[options.selectColumns, logsPreferences],
|
||||
);
|
||||
|
||||
const logsColumns = useLogsTableColumns({
|
||||
@@ -142,6 +161,20 @@ function LogsExplorerList({
|
||||
}
|
||||
}, [isLoading, isFetching, isError, logs.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasReconciledHiddenColumnsRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasReconciledHiddenColumnsRef.current = true;
|
||||
|
||||
if (syncedSelectedColumns.length === options.selectColumns.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
logsPreferences.updateColumns(syncedSelectedColumns);
|
||||
}, [logsPreferences, options.selectColumns.length, syncedSelectedColumns]);
|
||||
|
||||
const getItemContent = useCallback(
|
||||
(_: number, log: ILog): JSX.Element => {
|
||||
if (options.format === 'raw') {
|
||||
@@ -204,8 +237,7 @@ function LogsExplorerList({
|
||||
ref={ref as React.Ref<TanStackTableHandle>}
|
||||
columns={logsColumns}
|
||||
columnStorageKey={LOCALSTORAGE.LOGS_LIST_COLUMNS}
|
||||
onColumnRemove={config?.addColumn?.onRemove}
|
||||
onColumnOrderChange={handleColumnOrderChange}
|
||||
onColumnRemove={handleColumnRemove}
|
||||
plainTextCellLineClamp={options.maxLines}
|
||||
cellTypographySize={options.fontSize}
|
||||
data={logs}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user