diff --git a/frontend/src/assets/CustomIcons/EmptyQuickFilterIcon.tsx b/frontend/src/assets/CustomIcons/EmptyQuickFilterIcon.tsx new file mode 100644 index 0000000000..89ab66896d --- /dev/null +++ b/frontend/src/assets/CustomIcons/EmptyQuickFilterIcon.tsx @@ -0,0 +1,90 @@ +interface EmptyQuickFilterIconProps { + width?: number; + height?: number; + className?: string; +} + +function EmptyQuickFilterIcon({ + width = 32, + height = 32, + className, +}: EmptyQuickFilterIconProps): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + ); +} + +EmptyQuickFilterIcon.defaultProps = { + width: 32, + height: 32, + className: '', +}; + +export default EmptyQuickFilterIcon; diff --git a/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.styles.scss b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.styles.scss index 72fc1b44b2..2d7834b626 100644 --- a/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.styles.scss +++ b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.styles.scss @@ -130,6 +130,39 @@ cursor: pointer; } } + .go-to-docs { + display: flex; + flex-direction: column; + gap: 64px; + &__container { + display: flex; + flex-direction: column; + gap: 4px; + margin-top: 4px; + + &-message { + color: var(--bg-vanilla-400); + font-size: 14px; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + &__button { + display: flex; + align-items: center; + gap: 4px; + cursor: pointer; + margin: 0 0 4px; + padding: 0; + &-text { + color: var(--bg-robin-400); + font-family: Inter; + font-size: 14px; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + } } .lightMode { diff --git a/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx index 8b48a55dde..1051a47c3d 100644 --- a/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx +++ b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx @@ -6,7 +6,10 @@ import './Checkbox.styles.scss'; import { Button, Checkbox, Input, Skeleton, Typography } from 'antd'; import cx from 'classnames'; -import { IQuickFiltersConfig } from 'components/QuickFilters/QuickFilters'; +import { + IQuickFiltersConfig, + QuickFiltersSource, +} from 'components/QuickFilters/types'; import { OPERATORS } from 'constants/queryBuilder'; import { DEBOUNCE_DELAY } from 'constants/queryBuilderFilterConfig'; import { getOperatorValue } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils'; @@ -21,9 +24,13 @@ import { Query, TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource } from 'types/common/queryBuilder'; import { v4 as uuid } from 'uuid'; +import LogsQuickFilterEmptyState from './LogsQuickFilterEmptyState'; + const SELECTED_OPERATORS = [OPERATORS['='], 'in']; const NON_SELECTED_OPERATORS = [OPERATORS['!='], 'nin']; +const SOURCES_WITH_EMPTY_STATE_ENABLED = [QuickFiltersSource.LOGS_EXPLORER]; + function setDefaultValues( values: string[], trueOrFalse: boolean, @@ -36,11 +43,13 @@ function setDefaultValues( } interface ICheckboxProps { filter: IQuickFiltersConfig; + source: QuickFiltersSource; onFilterChange?: (query: Query) => void; } +// eslint-disable-next-line sonarjs/cognitive-complexity export default function CheckboxFilter(props: ICheckboxProps): JSX.Element { - const { filter, onFilterChange } = props; + const { source, filter, onFilterChange } = props; const [searchText, setSearchText] = useState(''); const [isOpen, setIsOpen] = useState(filter.defaultOpen); const [visibleItemsCount, setVisibleItemsCount] = useState(10); @@ -410,6 +419,11 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element { } }; + const isEmptyStateWithDocsEnabled = + SOURCES_WITH_EMPTY_STATE_ENABLED.includes(source) && + !searchText && + !attributeValues.length; + return (
{filter.title}
- {isOpen && ( + {isOpen && !!attributeValues.length && ( { @@ -453,13 +467,15 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element { )} {isOpen && !isLoading && ( <> -
- setSearchTextDebounced(e.target.value)} - disabled={isFilterDisabled} - /> -
+ {!isEmptyStateWithDocsEnabled && ( +
+ setSearchTextDebounced(e.target.value)} + disabled={isFilterDisabled} + /> +
+ )} {attributeValues.length > 0 ? (
{currentAttributeKeys.map((value: string) => ( @@ -507,6 +523,8 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
))} + ) : isEmptyStateWithDocsEnabled ? ( + ) : (
No values found{' '} diff --git a/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/LogsQuickFilterEmptyState.tsx b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/LogsQuickFilterEmptyState.tsx new file mode 100644 index 0000000000..e1646dad28 --- /dev/null +++ b/frontend/src/components/QuickFilters/FilterRenderers/Checkbox/LogsQuickFilterEmptyState.tsx @@ -0,0 +1,53 @@ +import { Color } from '@signozhq/design-tokens'; +import { Button } from 'antd'; +import EmptyQuickFilterIcon from 'assets/CustomIcons/EmptyQuickFilterIcon'; +import { ArrowUpRight } from 'lucide-react'; + +const QUICK_FILTER_DOC_PATHS: Record = { + severity_text: 'severity-text', + 'deployment.environment': 'environment', + 'service.name': 'service-name', + 'host.name': 'hostname', + 'k8s.cluster.name': 'k8s-cluster-name', + 'k8s.deployment.name': 'k8s-deployment-name', + 'k8s.namespace.name': 'k8s-namespace-name', + 'k8s.pod.name': 'k8s-pod-name', +}; + +function LogsQuickFilterEmptyState({ + attributeKey, +}: { + attributeKey: string; +}): JSX.Element { + const handleLearnMoreClick = (): void => { + const section = QUICK_FILTER_DOC_PATHS[attributeKey]; + + window.open( + `https://signoz.io/docs/logs-management/features/logs-quick-filters#${section}`, + '_blank', + ); + }; + return ( +
+
+
+ +
+
+ {`You'd need to parse out this attribute to start getting them as a fast + filter.`} +
+
+ +
+ ); +} + +export default LogsQuickFilterEmptyState; diff --git a/frontend/src/components/QuickFilters/FilterRenderers/Slider/Slider.tsx b/frontend/src/components/QuickFilters/FilterRenderers/Slider/Slider.tsx index f7cd9547e8..70b2fdceea 100644 --- a/frontend/src/components/QuickFilters/FilterRenderers/Slider/Slider.tsx +++ b/frontend/src/components/QuickFilters/FilterRenderers/Slider/Slider.tsx @@ -1,6 +1,6 @@ import './Slider.styles.scss'; -import { IQuickFiltersConfig } from 'components/QuickFilters/QuickFilters'; +import { IQuickFiltersConfig } from 'components/QuickFilters/types'; interface ISliderProps { filter: IQuickFiltersConfig; diff --git a/frontend/src/components/QuickFilters/QuickFilters.tsx b/frontend/src/components/QuickFilters/QuickFilters.tsx index bc367b58fc..ffd7ee3a25 100644 --- a/frontend/src/components/QuickFilters/QuickFilters.tsx +++ b/frontend/src/components/QuickFilters/QuickFilters.tsx @@ -8,45 +8,11 @@ import { import { Tooltip, Typography } from 'antd'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { cloneDeep, isFunction } from 'lodash-es'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; -import { DataSource } from 'types/common/queryBuilder'; import Checkbox from './FilterRenderers/Checkbox/Checkbox'; import Slider from './FilterRenderers/Slider/Slider'; - -export enum FiltersType { - SLIDER = 'SLIDER', - CHECKBOX = 'CHECKBOX', -} - -export enum MinMax { - MIN = 'MIN', - MAX = 'MAX', -} - -export enum SpecficFilterOperations { - ALL = 'ALL', - ONLY = 'ONLY', -} - -export interface IQuickFiltersConfig { - type: FiltersType; - title: string; - attributeKey: BaseAutocompleteData; - aggregateOperator?: string; - aggregateAttribute?: string; - dataSource?: DataSource; - customRendererForValue?: (value: string) => JSX.Element; - defaultOpen: boolean; -} - -interface IQuickFiltersProps { - config: IQuickFiltersConfig[]; - handleFilterVisibilityChange: () => void; - source?: string | null; - onFilterChange?: (query: Query) => void; -} +import { FiltersType, IQuickFiltersProps, QuickFiltersSource } from './types'; export default function QuickFilters(props: IQuickFiltersProps): JSX.Element { const { config, handleFilterVisibilityChange, source, onFilterChange } = props; @@ -95,11 +61,9 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element { const lastQueryName = currentQuery.builder.queryData?.[lastUsedQuery || 0]?.queryName; - const isInfraMonitoring = source === 'infra-monitoring'; - return (
- {!isInfraMonitoring && ( + {source !== QuickFiltersSource.INFRA_MONITORING && (
@@ -128,11 +92,24 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element { {config.map((filter) => { switch (filter.type) { case FiltersType.CHECKBOX: - return ; + return ( + + ); case FiltersType.SLIDER: return ; + // eslint-disable-next-line sonarjs/no-duplicated-branches default: - return ; + return ( + + ); } })}
@@ -141,6 +118,5 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element { } QuickFilters.defaultProps = { - source: null, onFilterChange: null, }; diff --git a/frontend/src/components/QuickFilters/types.ts b/frontend/src/components/QuickFilters/types.ts new file mode 100644 index 0000000000..0d5766f862 --- /dev/null +++ b/frontend/src/components/QuickFilters/types.ts @@ -0,0 +1,42 @@ +import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; +import { DataSource } from 'types/common/queryBuilder'; + +export enum FiltersType { + SLIDER = 'SLIDER', + CHECKBOX = 'CHECKBOX', +} + +export enum MinMax { + MIN = 'MIN', + MAX = 'MAX', +} + +export enum SpecficFilterOperations { + ALL = 'ALL', + ONLY = 'ONLY', +} + +export interface IQuickFiltersConfig { + type: FiltersType; + title: string; + attributeKey: BaseAutocompleteData; + aggregateOperator?: string; + aggregateAttribute?: string; + dataSource?: DataSource; + customRendererForValue?: (value: string) => JSX.Element; + defaultOpen: boolean; +} + +export interface IQuickFiltersProps { + config: IQuickFiltersConfig[]; + handleFilterVisibilityChange: () => void; + source: QuickFiltersSource; + onFilterChange?: (query: Query) => void; +} + +export enum QuickFiltersSource { + LOGS_EXPLORER = 'logs-explorer', + INFRA_MONITORING = 'infra-monitoring', + TRACES_EXPLORER = 'traces-explorer', +} diff --git a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx index 2e99fdb4dd..5ed5cd5633 100644 --- a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx +++ b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx @@ -5,6 +5,7 @@ import * as Sentry from '@sentry/react'; import type { CollapseProps } from 'antd'; import { Collapse, Tooltip, Typography } from 'antd'; import QuickFilters from 'components/QuickFilters/QuickFilters'; +import { QuickFiltersSource } from 'components/QuickFilters/types'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations'; import { @@ -83,7 +84,7 @@ export default function InfraMonitoringK8s(): JSX.Element { showArrow: false, children: ( diff --git a/frontend/src/pages/LogsExplorer/utils.tsx b/frontend/src/pages/LogsExplorer/utils.tsx index a886013941..f140f495b4 100644 --- a/frontend/src/pages/LogsExplorer/utils.tsx +++ b/frontend/src/pages/LogsExplorer/utils.tsx @@ -1,7 +1,7 @@ import { FiltersType, IQuickFiltersConfig, -} from 'components/QuickFilters/QuickFilters'; +} from 'components/QuickFilters/types'; import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { Query } from 'types/api/queryBuilder/queryBuilderData';