mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-24 10:56:53 +00:00
feat: use qb-v2 in explorers and alerts
This commit is contained in:
parent
a66c8e671f
commit
c9cbc75217
@ -5,10 +5,12 @@
|
||||
|
||||
width: 100%;
|
||||
|
||||
border-bottom: 1px solid var(--bg-slate-400);
|
||||
border-top: 1px solid var(--bg-slate-400);
|
||||
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
'Helvetica Neue', sans-serif;
|
||||
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
|
||||
@ -90,6 +92,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
.where-clause-view {
|
||||
.qb-content-section {
|
||||
.qb-elements-container {
|
||||
margin-left: 0px;
|
||||
|
||||
.code-mirror-where-clause,
|
||||
.query-aggregation-container,
|
||||
.query-add-ons,
|
||||
.metrics-aggregation-section-content {
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-names-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -18,6 +18,7 @@ export const QueryBuilderV2 = memo(function QueryBuilderV2({
|
||||
queryComponents,
|
||||
isListViewPanel = false,
|
||||
showFunctions = false,
|
||||
showOnlyWhereClause = false,
|
||||
version,
|
||||
}: QueryBuilderProps): JSX.Element {
|
||||
const {
|
||||
@ -67,12 +68,13 @@ export const QueryBuilderV2 = memo(function QueryBuilderV2({
|
||||
queryComponents={queryComponents}
|
||||
version={version}
|
||||
isAvailableToDisable={false}
|
||||
showSpanScopeSelector
|
||||
showSpanScopeSelector={initialDataSource === DataSource.TRACES}
|
||||
queryVariant={config?.queryVariant || 'dropdown'}
|
||||
showOnlyWhereClause={showOnlyWhereClause}
|
||||
/>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.length > 0 && (
|
||||
{!showOnlyWhereClause && currentQuery.builder.queryFormulas.length > 0 && (
|
||||
<div className="qb-formulas-container">
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => {
|
||||
const query =
|
||||
@ -94,25 +96,29 @@ export const QueryBuilderV2 = memo(function QueryBuilderV2({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<QueryFooter
|
||||
addNewBuilderQuery={addNewBuilderQuery}
|
||||
addNewFormula={addNewFormula}
|
||||
/>
|
||||
{!showOnlyWhereClause && (
|
||||
<QueryFooter
|
||||
addNewBuilderQuery={addNewBuilderQuery}
|
||||
addNewFormula={addNewFormula}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="query-names-section">
|
||||
{currentQuery.builder.queryData.map((query) => (
|
||||
<div key={query.queryName} className="query-name">
|
||||
{query.queryName}
|
||||
</div>
|
||||
))}
|
||||
{!showOnlyWhereClause && (
|
||||
<div className="query-names-section">
|
||||
{currentQuery.builder.queryData.map((query) => (
|
||||
<div key={query.queryName} className="query-name">
|
||||
{query.queryName}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</QueryBuilderV2Provider>
|
||||
);
|
||||
|
||||
@ -4,6 +4,7 @@ import { Button, Radio, RadioChangeEvent } from 'antd';
|
||||
import InputWithLabel from 'components/InputWithLabel/InputWithLabel';
|
||||
import { GroupByFilter } from 'container/QueryBuilder/filters/GroupByFilter/GroupByFilter';
|
||||
import { OrderByFilter } from 'container/QueryBuilder/filters/OrderByFilter/OrderByFilter';
|
||||
import { ReduceToFilter } from 'container/QueryBuilder/filters/ReduceToFilter/ReduceToFilter';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { BarChart2, ScrollText, X } from 'lucide-react';
|
||||
import { useCallback, useState } from 'react';
|
||||
@ -44,16 +45,23 @@ const ADD_ONS: Record<string, AddOn> = {
|
||||
label: 'Legend format',
|
||||
key: 'legend_format',
|
||||
},
|
||||
REDUCE_TO: {
|
||||
icon: <ScrollText size={14} />,
|
||||
label: 'Reduce to',
|
||||
key: 'reduce_to',
|
||||
},
|
||||
};
|
||||
|
||||
function QueryAddOns({
|
||||
query,
|
||||
version,
|
||||
isListViewPanel,
|
||||
showReduceTo,
|
||||
}: {
|
||||
query: IBuilderQuery;
|
||||
version: string;
|
||||
isListViewPanel: boolean;
|
||||
showReduceTo: boolean;
|
||||
}): JSX.Element {
|
||||
const [selectedViews, setSelectedViews] = useState<AddOn[]>([]);
|
||||
|
||||
@ -87,6 +95,13 @@ function QueryAddOns({
|
||||
[handleChangeQueryData],
|
||||
);
|
||||
|
||||
const handleChangeReduceTo = useCallback(
|
||||
(value: IBuilderQuery['reduceTo']) => {
|
||||
handleChangeQueryData('reduceTo', value);
|
||||
},
|
||||
[handleChangeQueryData],
|
||||
);
|
||||
|
||||
const handleRemoveView = useCallback(
|
||||
(key: string): void => {
|
||||
setSelectedViews(selectedViews.filter((view) => view.key !== key));
|
||||
@ -139,7 +154,7 @@ function QueryAddOns({
|
||||
{selectedViews.find((view) => view.key === 'limit') && (
|
||||
<div className="add-on-content">
|
||||
<InputWithLabel
|
||||
label="LIMIT"
|
||||
label="Limit"
|
||||
placeholder="Enter limit"
|
||||
onClose={(): void => {
|
||||
setSelectedViews(selectedViews.filter((view) => view.key !== 'limit'));
|
||||
@ -167,10 +182,28 @@ function QueryAddOns({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedViews.find((view) => view.key === 'reduce_to') && showReduceTo && (
|
||||
<div className="add-on-content">
|
||||
<div className="periscope-input-with-label">
|
||||
<div className="label">Reduce to</div>
|
||||
<div className="input">
|
||||
<ReduceToFilter query={query} onChange={handleChangeReduceTo} />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className="close-btn periscope-btn ghost"
|
||||
icon={<X size={16} />}
|
||||
onClick={(): void => handleRemoveView('reduce_to')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedViews.find((view) => view.key === 'legend_format') && (
|
||||
<div className="add-on-content">
|
||||
<InputWithLabel
|
||||
label="LEGEND FORMAT"
|
||||
label="Legend format"
|
||||
placeholder="Write legend format"
|
||||
onClose={(): void => {
|
||||
setSelectedViews(
|
||||
@ -189,22 +222,24 @@ function QueryAddOns({
|
||||
onChange={handleOptionClick}
|
||||
value={selectedViews}
|
||||
>
|
||||
{Object.values(ADD_ONS).map((addOn) => (
|
||||
<Radio.Button
|
||||
key={addOn.label}
|
||||
className={
|
||||
selectedViews.find((view) => view.key === addOn.key)
|
||||
? 'selected-view tab'
|
||||
: 'tab'
|
||||
}
|
||||
value={addOn}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
{addOn.icon}
|
||||
{addOn.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
))}
|
||||
{Object.values(ADD_ONS)
|
||||
.filter((addOn) => addOn.key !== 'reduce_to' || showReduceTo)
|
||||
.map((addOn) => (
|
||||
<Radio.Button
|
||||
key={addOn.label}
|
||||
className={
|
||||
selectedViews.find((view) => view.key === addOn.key)
|
||||
? 'selected-view tab'
|
||||
: 'tab'
|
||||
}
|
||||
value={addOn}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
{addOn.icon}
|
||||
{addOn.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
))}
|
||||
</Radio.Group>
|
||||
</div>
|
||||
</div>
|
||||
@ -212,60 +247,3 @@ function QueryAddOns({
|
||||
}
|
||||
|
||||
export default QueryAddOns;
|
||||
|
||||
/*
|
||||
|
||||
<Radio.Button
|
||||
className={
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
selectedView === ADD_ONS.GROUP_BY ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={ADD_ONS.GROUP_BY}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
<BarChart2 size={14} />
|
||||
{selectedView.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={selectedView === ADD_ONS.HAVING ? 'selected_view tab' : 'tab'}
|
||||
value={ADD_ONS.HAVING}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
<ScrollText size={14} />
|
||||
{selectedView.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === ADD_ONS.ORDER_BY ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={ADD_ONS.ORDER_BY}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
<DraftingCompass size={14} />
|
||||
{selectedView.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={selectedView === ADD_ONS.LIMIT ? 'selected_view tab' : 'tab'}
|
||||
value={ADD_ONS.LIMIT}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
<Package2 size={14} />
|
||||
{selectedView.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
className={
|
||||
selectedView === ADD_ONS.LEGEND_FORMAT ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
value={ADD_ONS.LEGEND_FORMAT}
|
||||
>
|
||||
<div className="add-on-tab-title">
|
||||
<ChevronsLeftRight size={14} />
|
||||
{selectedView.label}
|
||||
</div>
|
||||
</Radio.Button>
|
||||
|
||||
*/
|
||||
|
||||
@ -1,17 +1,10 @@
|
||||
import './QueryAggregation.styles.scss';
|
||||
|
||||
import InputWithLabel from 'components/InputWithLabel/InputWithLabel';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import QueryAggregationSelect from './QueryAggregationSelect';
|
||||
|
||||
function QueryAggregationOptions({
|
||||
source,
|
||||
}: {
|
||||
source: DataSource;
|
||||
}): JSX.Element {
|
||||
console.log('source', source);
|
||||
|
||||
function QueryAggregationOptions(): JSX.Element {
|
||||
return (
|
||||
<div className="query-aggregation-container">
|
||||
<QueryAggregationSelect />
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { Dropdown } from 'antd';
|
||||
import cx from 'classnames';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import QBEntityOptions from 'container/QueryBuilder/components/QBEntityOptions/QBEntityOptions';
|
||||
import { QueryProps } from 'container/QueryBuilder/components/Query/Query.interfaces';
|
||||
import SpanScopeSelector from 'container/QueryBuilder/filters/QueryBuilderSearchV2/SpanScopeSelector';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { Copy, Ellipsis, Trash } from 'lucide-react';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import MetricsAggregateSection from './MerticsAggregateSection/MetricsAggregateSection';
|
||||
@ -20,18 +22,16 @@ export const QueryV2 = memo(function QueryV2({
|
||||
queryVariant,
|
||||
query,
|
||||
filterConfigs,
|
||||
queryComponents,
|
||||
isListViewPanel = false,
|
||||
version,
|
||||
showSpanScopeSelector = false,
|
||||
showOnlyWhereClause = false,
|
||||
}: QueryProps): JSX.Element {
|
||||
const { cloneQuery } = useQueryBuilder();
|
||||
const { cloneQuery, panelType } = useQueryBuilder();
|
||||
|
||||
const showFunctions = query?.functions?.length > 0;
|
||||
const { dataSource } = query;
|
||||
|
||||
console.log('queryComponents', queryComponents);
|
||||
|
||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||
|
||||
const {
|
||||
@ -59,62 +59,73 @@ export const QueryV2 = memo(function QueryV2({
|
||||
cloneQuery('query', query);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="query-v2">
|
||||
<div className="qb-content-section">
|
||||
<div className="qb-header-container">
|
||||
<div className="query-actions-container">
|
||||
<div className="query-actions-left-container">
|
||||
<QBEntityOptions
|
||||
isMetricsDataSource={dataSource === DataSource.METRICS}
|
||||
showFunctions={
|
||||
(version && version === ENTITY_VERSION_V4) ||
|
||||
query.dataSource === DataSource.LOGS ||
|
||||
showFunctions ||
|
||||
false
|
||||
}
|
||||
isCollapsed={isCollapsed}
|
||||
entityType="query"
|
||||
entityData={query}
|
||||
onToggleVisibility={handleToggleDisableQuery}
|
||||
onDelete={handleDeleteQuery}
|
||||
onCloneQuery={cloneQuery}
|
||||
onCollapseEntity={handleToggleCollapsQuery}
|
||||
query={query}
|
||||
onQueryFunctionsUpdates={handleQueryFunctionsUpdates}
|
||||
showDeleteButton={false}
|
||||
showCloneOption={false}
|
||||
isListViewPanel={isListViewPanel}
|
||||
index={index}
|
||||
queryVariant={queryVariant}
|
||||
onChangeDataSource={handleChangeDataSource}
|
||||
/>
|
||||
</div>
|
||||
const showReduceTo = useMemo(
|
||||
() =>
|
||||
dataSource === DataSource.METRICS &&
|
||||
(panelType === PANEL_TYPES.TABLE ||
|
||||
panelType === PANEL_TYPES.PIE ||
|
||||
panelType === PANEL_TYPES.VALUE),
|
||||
[dataSource, panelType],
|
||||
);
|
||||
|
||||
<Dropdown
|
||||
className="query-actions-dropdown"
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
label: 'Clone',
|
||||
key: 'clone-query',
|
||||
icon: <Copy size={14} />,
|
||||
onClick: handleCloneEntity,
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete-query',
|
||||
icon: <Trash size={14} />,
|
||||
onClick: handleDeleteQuery,
|
||||
},
|
||||
],
|
||||
}}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Ellipsis size={16} />
|
||||
</Dropdown>
|
||||
return (
|
||||
<div className={cx('query-v2', { 'where-clause-view': showOnlyWhereClause })}>
|
||||
<div className="qb-content-section">
|
||||
{!showOnlyWhereClause && (
|
||||
<div className="qb-header-container">
|
||||
<div className="query-actions-container">
|
||||
<div className="query-actions-left-container">
|
||||
<QBEntityOptions
|
||||
isMetricsDataSource={dataSource === DataSource.METRICS}
|
||||
showFunctions={
|
||||
(version && version === ENTITY_VERSION_V4) ||
|
||||
query.dataSource === DataSource.LOGS ||
|
||||
showFunctions ||
|
||||
false
|
||||
}
|
||||
isCollapsed={isCollapsed}
|
||||
entityType="query"
|
||||
entityData={query}
|
||||
onToggleVisibility={handleToggleDisableQuery}
|
||||
onDelete={handleDeleteQuery}
|
||||
onCloneQuery={cloneQuery}
|
||||
onCollapseEntity={handleToggleCollapsQuery}
|
||||
query={query}
|
||||
onQueryFunctionsUpdates={handleQueryFunctionsUpdates}
|
||||
showDeleteButton={false}
|
||||
showCloneOption={false}
|
||||
isListViewPanel={isListViewPanel}
|
||||
index={index}
|
||||
queryVariant={queryVariant}
|
||||
onChangeDataSource={handleChangeDataSource}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Dropdown
|
||||
className="query-actions-dropdown"
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
label: 'Clone',
|
||||
key: 'clone-query',
|
||||
icon: <Copy size={14} />,
|
||||
onClick: handleCloneEntity,
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete-query',
|
||||
icon: <Trash size={14} />,
|
||||
onClick: handleDeleteQuery,
|
||||
},
|
||||
],
|
||||
}}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Ellipsis size={16} />
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="qb-elements-container">
|
||||
<div className="qb-search-container">
|
||||
@ -136,13 +147,20 @@ export const QueryV2 = memo(function QueryV2({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<QueryAggregation source={dataSource} />
|
||||
{!showOnlyWhereClause && <QueryAggregation />}
|
||||
|
||||
{dataSource === DataSource.METRICS && (
|
||||
{!showOnlyWhereClause && dataSource === DataSource.METRICS && (
|
||||
<MetricsAggregateSection query={query} index={0} version="v4" />
|
||||
)}
|
||||
|
||||
<QueryAddOns query={query} version="v3" isListViewPanel={false} />
|
||||
{!showOnlyWhereClause && (
|
||||
<QueryAddOns
|
||||
query={query}
|
||||
version="v3"
|
||||
isListViewPanel={false}
|
||||
showReduceTo={showReduceTo}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -69,7 +69,7 @@ function Download({ data, isLoading, fileName }: DownloadProps): JSX.Element {
|
||||
}
|
||||
>
|
||||
<Button
|
||||
className="periscope-btn"
|
||||
className="periscope-btn ghost"
|
||||
loading={isLoading}
|
||||
icon={<FileDown size={14} />}
|
||||
/>
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
.explorer-options-container {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
bottom: 8px;
|
||||
left: calc(50% + 240px);
|
||||
transform: translate(calc(-50% - 120px), 0);
|
||||
transition: left 0.2s linear;
|
||||
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--Slate-500, #161922);
|
||||
background: var(--Ink-300, #16181d);
|
||||
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
background-color: transparent;
|
||||
|
||||
.multi-alert-button,
|
||||
@ -32,19 +35,15 @@
|
||||
.explorer-update {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 10px;
|
||||
border-radius: 50px;
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
background: rgba(22, 24, 29, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
gap: 4px;
|
||||
padding: 8px;
|
||||
background: var(--Ink-300, #16181d);
|
||||
|
||||
.action-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
border-radius: 50px;
|
||||
padding: 6px;
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
background: var(--bg-slate-500);
|
||||
cursor: pointer;
|
||||
@ -64,10 +63,7 @@
|
||||
|
||||
.explorer-options {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
border-radius: 50px;
|
||||
background: rgba(22, 24, 29, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
background: var(--Ink-300, #16181d);
|
||||
|
||||
cursor: default;
|
||||
display: flex;
|
||||
@ -96,27 +92,6 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
|
||||
border: 1px solid #1d2023;
|
||||
|
||||
box-shadow: none !important;
|
||||
|
||||
&.ant-btn-round {
|
||||
padding: 8px 12px 8px 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&.ant-btn-round:disabled {
|
||||
background-color: rgba(209, 209, 209, 0.074);
|
||||
color: #5f5f5f;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select-focused {
|
||||
border-color: transparent !important;
|
||||
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
import './ExplorerOptions.styles.scss';
|
||||
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import {
|
||||
Button,
|
||||
ColorPicker,
|
||||
Divider,
|
||||
Input,
|
||||
Modal,
|
||||
RefSelectProps,
|
||||
@ -45,14 +43,7 @@ import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
|
||||
import { cloneDeep, isEqual, omit } from 'lodash-es';
|
||||
import {
|
||||
Check,
|
||||
ConciergeBell,
|
||||
Disc3,
|
||||
PanelBottomClose,
|
||||
Plus,
|
||||
X,
|
||||
} from 'lucide-react';
|
||||
import { Check, ConciergeBell, Disc3, Plus, X } from 'lucide-react';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { FormattingOptions } from 'providers/preferences/types';
|
||||
import {
|
||||
@ -78,10 +69,8 @@ import ExplorerOptionsHideArea from './ExplorerOptionsHideArea';
|
||||
import { PreservedViewsInLocalStorage } from './types';
|
||||
import {
|
||||
DATASOURCE_VS_ROUTES,
|
||||
generateRGBAFromHex,
|
||||
getRandomColor,
|
||||
saveNewViewHandler,
|
||||
setExplorerToolBarVisibility,
|
||||
} from './utils';
|
||||
|
||||
const allowedRoles = [USER_ROLES.ADMIN, USER_ROLES.AUTHOR, USER_ROLES.EDITOR];
|
||||
@ -253,12 +242,6 @@ function ExplorerOptions({
|
||||
const extraData = viewsData?.data?.data?.find((view) => view.id === viewKey)
|
||||
?.extraData;
|
||||
|
||||
const extraDataColor = extraData ? JSON.parse(extraData).color : '';
|
||||
const rgbaColor = generateRGBAFromHex(
|
||||
extraDataColor || Color.BG_SIENNA_500,
|
||||
0.08,
|
||||
);
|
||||
|
||||
const { options, handleOptionsChange } = useOptionsMenu({
|
||||
storageKey:
|
||||
sourcepage === DataSource.TRACES
|
||||
@ -589,13 +572,6 @@ function ExplorerOptions({
|
||||
[isDarkMode],
|
||||
);
|
||||
|
||||
const hideToolbar = (): void => {
|
||||
setExplorerToolBarVisibility(false, sourcepage);
|
||||
if (setIsExplorerOptionHidden) {
|
||||
setIsExplorerOptionHidden(true);
|
||||
}
|
||||
};
|
||||
|
||||
const isEditDeleteSupported = allowedRoles.includes(user.role as string);
|
||||
|
||||
const [
|
||||
@ -647,27 +623,6 @@ function ExplorerOptions({
|
||||
viewsData?.data?.data,
|
||||
]);
|
||||
|
||||
const infoIconText = useMemo(() => {
|
||||
if (isLogsExplorer) {
|
||||
return 'Learn more about Logs explorer';
|
||||
}
|
||||
if (isMetricsExplorer) {
|
||||
return 'Learn more about Metrics explorer';
|
||||
}
|
||||
return 'Learn more about Traces explorer';
|
||||
}, [isLogsExplorer, isMetricsExplorer]);
|
||||
|
||||
const infoIconLink = useMemo(() => {
|
||||
if (isLogsExplorer) {
|
||||
return 'https://signoz.io/docs/product-features/logs-explorer/?utm_source=product&utm_medium=logs-explorer-toolbar';
|
||||
}
|
||||
// TODO: Add metrics explorer info icon link
|
||||
if (isMetricsExplorer) {
|
||||
return '';
|
||||
}
|
||||
return 'https://signoz.io/docs/product-features/trace-explorer/?utm_source=product&utm_medium=trace-explorer-toolbar';
|
||||
}, [isLogsExplorer, isMetricsExplorer]);
|
||||
|
||||
const getQueryName = (query: Query): string => {
|
||||
if (query.builder.queryFormulas.length > 0) {
|
||||
return `Formula ${query.builder.queryFormulas[0].queryName}`;
|
||||
@ -680,11 +635,10 @@ function ExplorerOptions({
|
||||
const selectLabel = (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
className="periscope-btn ghost"
|
||||
shape="default"
|
||||
icon={<ConciergeBell size={16} />}
|
||||
>
|
||||
Create an Alert
|
||||
</Button>
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Select
|
||||
@ -713,12 +667,11 @@ function ExplorerOptions({
|
||||
return (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
shape="default"
|
||||
className="periscope-btn ghost"
|
||||
onClick={(): void => onCreateAlertsHandler(query)}
|
||||
icon={<ConciergeBell size={16} />}
|
||||
>
|
||||
Create an Alert
|
||||
</Button>
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
disabled,
|
||||
@ -732,14 +685,11 @@ function ExplorerOptions({
|
||||
if (isOneChartPerQuery) {
|
||||
const selectLabel = (
|
||||
<Button
|
||||
type="primary"
|
||||
className="periscope-btn ghost"
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
onClick={onAddToDashboard}
|
||||
icon={<Plus size={16} />}
|
||||
>
|
||||
Add to Dashboard
|
||||
</Button>
|
||||
icon={<Plus size={12} />}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Select
|
||||
@ -771,14 +721,11 @@ function ExplorerOptions({
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
type="primary"
|
||||
className="periscope-btn ghost"
|
||||
disabled={disabled}
|
||||
shape="round"
|
||||
onClick={onAddToDashboard}
|
||||
icon={<Plus size={16} />}
|
||||
>
|
||||
Add to Dashboard
|
||||
</Button>
|
||||
/>
|
||||
);
|
||||
}, [disabled, isOneChartPerQuery, onAddToDashboard, splitedQueries]);
|
||||
|
||||
@ -797,41 +744,31 @@ function ExplorerOptions({
|
||||
>
|
||||
<Tooltip title="Clear this view" placement="top">
|
||||
<Button
|
||||
className="action-icon"
|
||||
className="periscope-btn ghost"
|
||||
onClick={handleClearSelect}
|
||||
icon={<X size={14} />}
|
||||
icon={<X size={16} />}
|
||||
/>
|
||||
</Tooltip>
|
||||
{
|
||||
// only show the update view option when the query is updated
|
||||
}
|
||||
{isQueryUpdated && (
|
||||
<>
|
||||
<Divider
|
||||
type="vertical"
|
||||
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||
<Tooltip title="Update this view" placement="top">
|
||||
<Button
|
||||
className={cx(
|
||||
'periscope-btn ghost',
|
||||
isEditDeleteSupported ? '' : 'hidden',
|
||||
)}
|
||||
disabled={isViewUpdating}
|
||||
onClick={onUpdateQueryHandler}
|
||||
icon={<Disc3 size={16} />}
|
||||
/>
|
||||
<Tooltip title="Update this view" placement="top">
|
||||
<Button
|
||||
className={cx('action-icon', isEditDeleteSupported ? ' ' : 'hidden')}
|
||||
disabled={isViewUpdating}
|
||||
onClick={onUpdateQueryHandler}
|
||||
icon={<Disc3 size={14} />}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!isExplorerOptionHidden && (
|
||||
<div
|
||||
className="explorer-options"
|
||||
style={{
|
||||
background: extraData
|
||||
? `linear-gradient(90deg, rgba(0,0,0,0) -5%, ${rgbaColor} 9%, rgba(0,0,0,0) 30%)`
|
||||
: 'transparent',
|
||||
}}
|
||||
>
|
||||
<div className="explorer-options">
|
||||
<div className="view-options">
|
||||
<Select<string, { key: string; value: string }>
|
||||
showSearch
|
||||
@ -872,49 +809,23 @@ function ExplorerOptions({
|
||||
</Select>
|
||||
|
||||
<Button
|
||||
shape="round"
|
||||
shape="default"
|
||||
className={cx(
|
||||
'periscope-btn secondary',
|
||||
isEditDeleteSupported ? '' : 'hidden',
|
||||
)}
|
||||
onClick={handleSaveViewModalToggle}
|
||||
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||
disabled={viewsIsLoading || isRefetching}
|
||||
icon={<Disc3 size={16} />}
|
||||
icon={<Disc3 size={12} />}
|
||||
>
|
||||
Save this view
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<hr className={isEditDeleteSupported ? '' : 'hidden'} />
|
||||
|
||||
<div className={cx('actions', isEditDeleteSupported ? '' : 'hidden')}>
|
||||
{alertButton}
|
||||
{dashboardButton}
|
||||
</div>
|
||||
<div className="actions">
|
||||
{/* Hide the info icon for metrics explorer until we get the docs link */}
|
||||
{!isMetricsExplorer && (
|
||||
<Tooltip
|
||||
title={
|
||||
<div>
|
||||
{infoIconText}
|
||||
<Typography.Link href={infoIconLink} target="_blank">
|
||||
{' '}
|
||||
here
|
||||
</Typography.Link>{' '}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<InfoCircleOutlined className="info-icon" />
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="Hide">
|
||||
<Button
|
||||
disabled={disabled}
|
||||
shape="circle"
|
||||
onClick={hideToolbar}
|
||||
icon={<PanelBottomClose size={16} />}
|
||||
data-testid="hide-toolbar"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<ExplorerOptionsHideArea
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
.alert-tabs {
|
||||
padding: 0px 8px;
|
||||
|
||||
.ant-tabs-tab {
|
||||
border: none !important;
|
||||
margin-left: 0px !important;
|
||||
@ -48,6 +50,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
.alert-query-section-container {
|
||||
.ant-card-body {
|
||||
padding: 0px;
|
||||
|
||||
.alert-tabs {
|
||||
padding: 0px;
|
||||
|
||||
.ant-tabs {
|
||||
.ant-tabs-nav {
|
||||
padding: 8px 0;
|
||||
|
||||
.ant-tabs-nav-wrap {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-extra-content {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.alert-tabs {
|
||||
.ant-tabs-nav-list {
|
||||
|
||||
@ -4,11 +4,11 @@ import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Tabs, Tooltip } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import PromQLIcon from 'assets/Dashboard/PromQl';
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { QBShortcuts } from 'constants/shortcuts/QBShortcuts';
|
||||
import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
@ -48,7 +48,7 @@ function QuerySection({
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const renderMetricUI = (): JSX.Element => (
|
||||
<QueryBuilder
|
||||
<QueryBuilderV2
|
||||
panelType={panelType}
|
||||
config={{
|
||||
queryVariant: 'static',
|
||||
@ -144,7 +144,7 @@ function QuerySection({
|
||||
<div className="alert-tabs">
|
||||
<Tabs
|
||||
type="card"
|
||||
style={{ width: '100%' }}
|
||||
style={{ width: '100%', padding: '0px 8px' }}
|
||||
defaultActiveKey={currentTab}
|
||||
activeKey={currentTab}
|
||||
onChange={handleQueryCategoryChange}
|
||||
@ -178,7 +178,7 @@ function QuerySection({
|
||||
<div className="alert-tabs">
|
||||
<Tabs
|
||||
type="card"
|
||||
style={{ width: '100%' }}
|
||||
style={{ width: '100%', padding: '0px 8px' }}
|
||||
defaultActiveKey={currentTab}
|
||||
activeKey={currentTab}
|
||||
onChange={handleQueryCategoryChange}
|
||||
@ -218,7 +218,7 @@ function QuerySection({
|
||||
return (
|
||||
<>
|
||||
<StepHeading> {t('alert_form_step2', { step: step2Label })}</StepHeading>
|
||||
<FormContainer>
|
||||
<FormContainer className="alert-query-section-container">
|
||||
<div>{renderTabs(alertType)}</div>
|
||||
{renderQuerySection(currentTab)}
|
||||
</FormContainer>
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
.qb-search-view-container {
|
||||
padding: 8px 16px;
|
||||
border-top: 1px solid var(--bg-slate-400, #1d212d);
|
||||
border-bottom: 1px solid var(--bg-slate-400, #1d212d);
|
||||
|
||||
.ant-select-selector {
|
||||
border-radius: 2px;
|
||||
@ -20,9 +18,6 @@
|
||||
|
||||
.lightMode {
|
||||
.qb-search-view-container {
|
||||
border-top: 1px solid var(--bg-vanilla-300);
|
||||
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||
|
||||
.ant-select-selector {
|
||||
border-color: var(--bg-vanilla-300) !important;
|
||||
background-color: var(--bg-vanilla-100) !important;
|
||||
|
||||
@ -8,18 +8,15 @@ import {
|
||||
} from 'constants/queryBuilder';
|
||||
import ExplorerOrderBy from 'container/ExplorerOrderBy';
|
||||
import { OrderByFilterProps } from 'container/QueryBuilder/filters/OrderByFilter/OrderByFilter.interfaces';
|
||||
import QueryBuilderSearchV2 from 'container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2';
|
||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import {
|
||||
ExplorerViews,
|
||||
prepareQueryWithDefaultTimestamp,
|
||||
} from 'pages/LogsExplorer/utils';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
function LogExplorerQuerySection({
|
||||
@ -27,9 +24,7 @@ function LogExplorerQuerySection({
|
||||
}: {
|
||||
selectedView: ExplorerViews;
|
||||
}): JSX.Element {
|
||||
const { currentQuery, updateAllQueriesOperators } = useQueryBuilder();
|
||||
|
||||
const query = currentQuery?.builder?.queryData[0] || null;
|
||||
const { updateAllQueriesOperators } = useQueryBuilder();
|
||||
|
||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||
const defaultValue = useMemo(() => {
|
||||
@ -58,13 +53,6 @@ function LogExplorerQuerySection({
|
||||
return config;
|
||||
}, [panelTypes]);
|
||||
|
||||
const { handleChangeQueryData } = useQueryOperations({
|
||||
index: 0,
|
||||
query,
|
||||
filterConfigs,
|
||||
entityVersion: '',
|
||||
});
|
||||
|
||||
const renderOrderBy = useCallback(
|
||||
({ query, onChange }: OrderByFilterProps): JSX.Element => (
|
||||
<ExplorerOrderBy query={query} onChange={onChange} />
|
||||
@ -79,38 +67,16 @@ function LogExplorerQuerySection({
|
||||
[panelTypes, renderOrderBy],
|
||||
);
|
||||
|
||||
const handleChangeTagFilters = useCallback(
|
||||
(value: IBuilderQuery['filters']) => {
|
||||
handleChangeQueryData('filters', value);
|
||||
},
|
||||
[handleChangeQueryData],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedView === ExplorerViews.LIST && (
|
||||
<div className="qb-search-view-container">
|
||||
<QueryBuilderSearchV2
|
||||
query={query}
|
||||
onChange={handleChangeTagFilters}
|
||||
whereClauseConfig={filterConfigs?.filters}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(selectedView === ExplorerViews.TABLE ||
|
||||
selectedView === ExplorerViews.TIMESERIES ||
|
||||
selectedView === ExplorerViews.CLICKHOUSE) && (
|
||||
<QueryBuilderV2
|
||||
isListViewPanel={panelTypes === PANEL_TYPES.LIST}
|
||||
config={{ initialDataSource: DataSource.LOGS, queryVariant: 'static' }}
|
||||
panelType={panelTypes}
|
||||
filterConfigs={filterConfigs}
|
||||
queryComponents={queryComponents}
|
||||
version="v3" // setting this to v3 as we this is rendered in logs explorer
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<QueryBuilderV2
|
||||
isListViewPanel={panelTypes === PANEL_TYPES.LIST}
|
||||
config={{ initialDataSource: DataSource.LOGS, queryVariant: 'static' }}
|
||||
panelType={panelTypes}
|
||||
filterConfigs={filterConfigs}
|
||||
queryComponents={queryComponents}
|
||||
showOnlyWhereClause={selectedView === ExplorerViews.LIST}
|
||||
version="v3" // setting this to v3 as we this is rendered in logs explorer
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -76,6 +76,12 @@
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
}
|
||||
|
||||
.order-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.format-options-container {
|
||||
position: relative;
|
||||
}
|
||||
@ -111,7 +117,35 @@
|
||||
.tab-options-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 4px;
|
||||
|
||||
.order-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.order-by-label {
|
||||
color: var(--text-vanilla-400);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.order-by-select {
|
||||
width: 100px;
|
||||
|
||||
.ant-select-selector {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.frequency-chart-view-controller {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import './LogsExplorerViews.styles.scss';
|
||||
|
||||
import { Button, Switch, Typography } from 'antd';
|
||||
import { Button, Select, Switch, Typography } from 'antd';
|
||||
import { getQueryStats, WsDataEvent } from 'api/common/getQueryStats';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||
@ -46,7 +46,7 @@ import {
|
||||
omit,
|
||||
set,
|
||||
} from 'lodash-es';
|
||||
import { Sliders } from 'lucide-react';
|
||||
import { ArrowUp10, Minus, Sliders } from 'lucide-react';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import {
|
||||
@ -138,6 +138,8 @@ function LogsExplorerViewsContainer({
|
||||
const [queryStats, setQueryStats] = useState<WsDataEvent>();
|
||||
const [listChartQuery, setListChartQuery] = useState<Query | null>(null);
|
||||
|
||||
const [orderDirection, setOrderDirection] = useState<string>('asc');
|
||||
|
||||
const listQuery = useMemo(() => {
|
||||
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
|
||||
|
||||
@ -656,6 +658,23 @@ function LogsExplorerViewsContainer({
|
||||
<div className="tab-options-right">
|
||||
{selectedPanelType === PANEL_TYPES.LIST && (
|
||||
<>
|
||||
<div className="order-by-container">
|
||||
<div className="order-by-label">
|
||||
Order by <Minus size={14} /> <ArrowUp10 size={14} />
|
||||
</div>
|
||||
|
||||
<Select
|
||||
placeholder="Select order by"
|
||||
className="order-by-select"
|
||||
style={{ width: 100 }}
|
||||
value={orderDirection}
|
||||
onChange={(value): void => setOrderDirection(value)}
|
||||
options={[
|
||||
{ label: 'Ascending', value: 'asc' },
|
||||
{ label: 'Descending', value: 'desc' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Download
|
||||
data={flattenLogData}
|
||||
isLoading={isFetching}
|
||||
@ -663,7 +682,7 @@ function LogsExplorerViewsContainer({
|
||||
/>
|
||||
<div className="format-options-container" ref={menuRef}>
|
||||
<Button
|
||||
className="periscope-btn"
|
||||
className="periscope-btn ghost"
|
||||
onClick={handleToggleShowFormatOptions}
|
||||
icon={<Sliders size={14} />}
|
||||
data-testid="periscope-btn"
|
||||
|
||||
@ -28,5 +28,6 @@ export type QueryBuilderProps = {
|
||||
queryComponents?: { renderOrderBy?: (props: OrderByFilterProps) => ReactNode };
|
||||
isListViewPanel?: boolean;
|
||||
showFunctions?: boolean;
|
||||
showOnlyWhereClause?: boolean;
|
||||
version: string;
|
||||
};
|
||||
|
||||
@ -10,4 +10,5 @@ export type QueryProps = {
|
||||
showFunctions?: boolean;
|
||||
version: string;
|
||||
showSpanScopeSelector?: boolean;
|
||||
showOnlyWhereClause?: boolean;
|
||||
} & Pick<QueryBuilderProps, 'filterConfigs' | 'queryComponents'>;
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
background: var(--bg-ink-300);
|
||||
flex-direction: row;
|
||||
border-bottom: none;
|
||||
margin-bottom: -1px;
|
||||
|
||||
.prom-ql-icon {
|
||||
height: 14px;
|
||||
@ -33,17 +35,35 @@
|
||||
border: none;
|
||||
padding: 9px;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border-radius: 0px;
|
||||
border-left: 1px solid var(--bg-slate-400);
|
||||
border-bottom: 1px solid var(--bg-slate-400);
|
||||
|
||||
gap: 8px;
|
||||
|
||||
&.active-tab {
|
||||
background-color: var(--bg-slate-400);
|
||||
background-color: var(--bg-ink-500);
|
||||
border-bottom: 1px solid var(--bg-ink-500);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--bg-ink-500) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #121317;
|
||||
background-color: var(--bg-ink-300);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
border-left: 1px solid transparent !important;
|
||||
color: var(--bg-vanilla-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
.query-builder-search-v2 {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex: 1;
|
||||
|
||||
.ant-select-dropdown {
|
||||
padding: 0px;
|
||||
|
||||
@ -1,12 +1,23 @@
|
||||
.toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: 3fr auto auto;
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
|
||||
border-top: 1px solid var(--bg-slate-400);
|
||||
border-bottom: 1px solid var(--bg-slate-400);
|
||||
|
||||
padding: 0px 8px;
|
||||
gap: 8px;
|
||||
|
||||
.rightActions {
|
||||
margin: 4px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.timeRange {
|
||||
display: flex;
|
||||
padding-right: 8px;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@ -32,14 +32,19 @@ export default function Toolbar({
|
||||
return (
|
||||
<div className="toolbar">
|
||||
<div className="leftActions">{leftActions}</div>
|
||||
<div className="timeRange">
|
||||
{showOldCTA && <NewExplorerCTA />}
|
||||
<DateTimeSelectionV2
|
||||
showAutoRefresh={showAutoRefresh}
|
||||
showRefreshText={!isLogsExplorerPage && !isApiMonitoringPage}
|
||||
/>
|
||||
|
||||
<div className="rightActions">
|
||||
<div className="timeRange">
|
||||
{showOldCTA && <NewExplorerCTA />}
|
||||
<DateTimeSelectionV2
|
||||
showAutoRefresh={showAutoRefresh}
|
||||
showRefreshText={!isLogsExplorerPage && !isApiMonitoringPage}
|
||||
hideShareModal
|
||||
/>
|
||||
</div>
|
||||
|
||||
{rightActions}
|
||||
</div>
|
||||
<div className="rightActions">{rightActions}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,4 +1,33 @@
|
||||
.trace-explorer-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.order-by-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.order-by-label {
|
||||
color: var(--text-vanilla-400);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px; /* 133.333% */
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.order-by-select {
|
||||
width: 100px;
|
||||
|
||||
.ant-select-selector {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import './ListView.styles.scss';
|
||||
|
||||
import { Select } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
@ -20,8 +21,9 @@ import useDragColumns from 'hooks/useDragColumns';
|
||||
import { getDraggedColumns } from 'hooks/useDragColumns/utils';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import { ArrowUp10, Minus } from 'lucide-react';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
@ -44,6 +46,8 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
|
||||
const panelType = panelTypeFromQueryBuilder || PANEL_TYPES.LIST;
|
||||
|
||||
const [orderDirection, setOrderDirection] = useState<string>('asc');
|
||||
|
||||
const {
|
||||
selectedTime: globalSelectedTime,
|
||||
maxTime,
|
||||
@ -170,6 +174,24 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
<Container>
|
||||
{transformedQueryTableData.length !== 0 && (
|
||||
<div className="trace-explorer-controls">
|
||||
<div className="order-by-container">
|
||||
<div className="order-by-label">
|
||||
Order by <Minus size={14} /> <ArrowUp10 size={14} />
|
||||
</div>
|
||||
|
||||
<Select
|
||||
placeholder="Select order by"
|
||||
className="order-by-select"
|
||||
style={{ width: 100 }}
|
||||
value={orderDirection}
|
||||
onChange={(value): void => setOrderDirection(value)}
|
||||
options={[
|
||||
{ label: 'Ascending', value: 'asc' },
|
||||
{ label: 'Descending', value: 'desc' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TraceExplorerControls
|
||||
isLoading={isFetching}
|
||||
totalCount={totalCount}
|
||||
|
||||
@ -1,26 +1,15 @@
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
// import QuerySearch from 'components/QueryBuilderV2/QueryV2/QuerySearch/QuerySearch';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import ExplorerOrderBy from 'container/ExplorerOrderBy';
|
||||
import { OrderByFilterProps } from 'container/QueryBuilder/filters/OrderByFilter/OrderByFilter.interfaces';
|
||||
// import SpanScopeSelector from 'container/QueryBuilder/filters/QueryBuilderSearchV2/SpanScopeSelector';
|
||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||
// import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { Container } from './styles';
|
||||
|
||||
function QuerySection({
|
||||
selectedView,
|
||||
}: {
|
||||
selectedView: PANEL_TYPES;
|
||||
}): JSX.Element {
|
||||
// const { currentQuery } = useQueryBuilder();
|
||||
|
||||
// const queryName = currentQuery?.builder?.queryData[0]?.queryName || '';
|
||||
|
||||
function QuerySection(): JSX.Element {
|
||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||
|
||||
const filterConfigs: QueryBuilderProps['filterConfigs'] = useMemo(() => {
|
||||
@ -50,30 +39,19 @@ function QuerySection({
|
||||
};
|
||||
}, [panelTypes, renderOrderBy]);
|
||||
|
||||
console.log('query - section - selectedView', selectedView);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{/* {(selectedView === 'list' || selectedView === 'trace') && (
|
||||
<div className="qb-search-view-container">
|
||||
<QuerySearch />
|
||||
|
||||
<div className="traces-search-filter-in">in</div>
|
||||
|
||||
<SpanScopeSelector queryName={queryName} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(selectedView === 'graph' || selectedView === 'table') && ( */}
|
||||
<QueryBuilderV2
|
||||
isListViewPanel={panelTypes === PANEL_TYPES.LIST}
|
||||
config={{ initialDataSource: DataSource.TRACES, queryVariant: 'static' }}
|
||||
queryComponents={queryComponents}
|
||||
panelType={panelTypes}
|
||||
filterConfigs={filterConfigs}
|
||||
showOnlyWhereClause={
|
||||
panelTypes === PANEL_TYPES.LIST || panelTypes === PANEL_TYPES.TRACE
|
||||
}
|
||||
version="v3" // setting this to v3 as we this is rendered in logs explorer
|
||||
/>
|
||||
{/* )} */}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Typography } from 'antd';
|
||||
import { Select, Typography } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
@ -11,7 +11,8 @@ import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { memo, useEffect, useMemo } from 'react';
|
||||
import { ArrowUp10, Minus } from 'lucide-react';
|
||||
import { memo, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
@ -29,6 +30,7 @@ interface TracesViewProps {
|
||||
|
||||
function TracesView({ isFilterApplied }: TracesViewProps): JSX.Element {
|
||||
const { stagedQuery, panelType } = useQueryBuilder();
|
||||
const [orderDirection, setOrderDirection] = useState<string>('asc');
|
||||
|
||||
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
|
||||
AppState,
|
||||
@ -92,11 +94,32 @@ function TracesView({ isFilterApplied }: TracesViewProps): JSX.Element {
|
||||
here
|
||||
</Typography.Link>
|
||||
</Typography>
|
||||
<TraceExplorerControls
|
||||
isLoading={isLoading}
|
||||
totalCount={responseData?.length || 0}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
/>
|
||||
|
||||
<div className="trace-explorer-controls">
|
||||
<div className="order-by-container">
|
||||
<div className="order-by-label">
|
||||
Order by <Minus size={14} /> <ArrowUp10 size={14} />
|
||||
</div>
|
||||
|
||||
<Select
|
||||
placeholder="Select order by"
|
||||
className="order-by-select"
|
||||
style={{ width: 100 }}
|
||||
value={orderDirection}
|
||||
onChange={(value): void => setOrderDirection(value)}
|
||||
options={[
|
||||
{ label: 'Ascending', value: 'asc' },
|
||||
{ label: 'Descending', value: 'desc' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TraceExplorerControls
|
||||
isLoading={isLoading}
|
||||
totalCount={responseData?.length || 0}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
/>
|
||||
</div>
|
||||
</ActionsContainer>
|
||||
)}
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ export const useHandleExplorerTabChange = (): {
|
||||
currentQueryData?: ICurrentQueryData,
|
||||
redirectToUrl?: typeof ROUTES[keyof typeof ROUTES],
|
||||
) => {
|
||||
console.log('type', type);
|
||||
console.log('hook - type', type);
|
||||
|
||||
const newPanelType = type as PANEL_TYPES;
|
||||
|
||||
|
||||
@ -263,7 +263,6 @@ function LogsExplorer(): JSX.Element {
|
||||
isLoadingQueries={isLoadingQueries}
|
||||
/>
|
||||
}
|
||||
showOldCTA
|
||||
/>
|
||||
|
||||
<div className="log-explorer-query-container">
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
.qb-search-view-container {
|
||||
padding: 8px;
|
||||
border: 1px solid var(--Slate-400, #1d212d) !important;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -40,8 +39,8 @@
|
||||
|
||||
.ant-select-selector {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--Slate-400, #1d212d) !important;
|
||||
background: var(--Ink-300, #16181d) !important;
|
||||
border: 1px solid var(--bg-slate-400) !important;
|
||||
background: var(--bg-ink-300) !important;
|
||||
height: 34px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
@ -83,7 +82,6 @@
|
||||
|
||||
.trace-explorer {
|
||||
width: 100%;
|
||||
border-left: 1px solid var(--bg-slate-400);
|
||||
background: var(--bg-ink-500);
|
||||
|
||||
> .ant-card-body {
|
||||
|
||||
@ -18,20 +18,17 @@ import RightToolbarActions from 'container/QueryBuilder/components/ToolbarAction
|
||||
import TimeSeriesView from 'container/TimeSeriesView';
|
||||
import Toolbar from 'container/Toolbar/Toolbar';
|
||||
import ListView from 'container/TracesExplorer/ListView';
|
||||
// import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||
import { defaultSelectedColumns } from 'container/TracesExplorer/ListView/configs';
|
||||
import QuerySection from 'container/TracesExplorer/QuerySection';
|
||||
import TableView from 'container/TracesExplorer/TableView';
|
||||
import TracesView from 'container/TracesExplorer/TracesView';
|
||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
|
||||
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import { cloneDeep, isEmpty, set } from 'lodash-es';
|
||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -46,6 +43,7 @@ function TracesExplorer(): JSX.Element {
|
||||
updateAllQueriesOperators,
|
||||
handleRunQuery,
|
||||
stagedQuery,
|
||||
handleSetConfig,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const { options } = useOptionsMenu({
|
||||
@ -57,12 +55,27 @@ function TracesExplorer(): JSX.Element {
|
||||
},
|
||||
});
|
||||
|
||||
const currentPanelType = useGetPanelTypesQueryParam();
|
||||
const currentTab = panelType || PANEL_TYPES.LIST;
|
||||
const [selectedView, setSelectedView] = useState<ExplorerViews>(
|
||||
ExplorerViews.LIST,
|
||||
);
|
||||
|
||||
const { handleExplorerTabChange } = useHandleExplorerTabChange();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
|
||||
const handleChangeSelectedView = useCallback(
|
||||
(view: ExplorerViews): void => {
|
||||
if (selectedView === ExplorerViews.LIST) {
|
||||
handleSetConfig(PANEL_TYPES.LIST, DataSource.LOGS);
|
||||
}
|
||||
|
||||
setSelectedView(view);
|
||||
handleExplorerTabChange(
|
||||
view === ExplorerViews.TIMESERIES ? PANEL_TYPES.TIME_SERIES : view,
|
||||
);
|
||||
},
|
||||
[handleSetConfig, handleExplorerTabChange, selectedView],
|
||||
);
|
||||
|
||||
const listQuery = useMemo(() => {
|
||||
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
|
||||
|
||||
@ -163,23 +176,6 @@ function TracesExplorer(): JSX.Element {
|
||||
|
||||
useShareBuilderUrl(defaultQuery);
|
||||
|
||||
useEffect(() => {
|
||||
const shouldChangeView = isMultipleQueries || isGroupByExist;
|
||||
|
||||
if (
|
||||
(currentTab === PANEL_TYPES.LIST || currentTab === PANEL_TYPES.TRACE) &&
|
||||
shouldChangeView
|
||||
) {
|
||||
handleExplorerTabChange(currentPanelType || PANEL_TYPES.TIME_SERIES);
|
||||
}
|
||||
}, [
|
||||
currentTab,
|
||||
isMultipleQueries,
|
||||
isGroupByExist,
|
||||
handleExplorerTabChange,
|
||||
currentPanelType,
|
||||
]);
|
||||
|
||||
const [isOpen, setOpen] = useState<boolean>(true);
|
||||
const logEventCalledRef = useRef(false);
|
||||
|
||||
@ -260,27 +256,16 @@ function TracesExplorer(): JSX.Element {
|
||||
showFilter={isOpen}
|
||||
handleFilterVisibilityChange={(): void => setOpen(!isOpen)}
|
||||
items={toolbarViews}
|
||||
selectedView={
|
||||
currentTab === PANEL_TYPES.TIME_SERIES ? 'timeseries' : currentTab
|
||||
}
|
||||
onChangeSelectedView={(view): void => {
|
||||
if (view === 'timeseries') {
|
||||
handleExplorerTabChange(PANEL_TYPES.TIME_SERIES);
|
||||
// setSelectedView(PANEL_TYPES.TIME_SERIES);
|
||||
} else {
|
||||
handleExplorerTabChange((view as unknown) as PANEL_TYPES);
|
||||
// setSelectedView((view as unknown) as PANEL_TYPES);
|
||||
}
|
||||
}}
|
||||
selectedView={selectedView}
|
||||
onChangeSelectedView={handleChangeSelectedView}
|
||||
/>
|
||||
}
|
||||
rightActions={<RightToolbarActions onStageRunQuery={handleRunQuery} />}
|
||||
// showOldCTA={false}
|
||||
/>
|
||||
</div>
|
||||
<ExplorerCard sourcepage={DataSource.TRACES}>
|
||||
<div className="query-section-container">
|
||||
<QuerySection selectedView={currentTab} />
|
||||
<QuerySection />
|
||||
</div>
|
||||
</ExplorerCard>
|
||||
|
||||
@ -293,19 +278,19 @@ function TracesExplorer(): JSX.Element {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{currentTab === PANEL_TYPES.LIST && (
|
||||
{selectedView === ExplorerViews.LIST && (
|
||||
<div className="trace-explorer-list-view">
|
||||
<ListView isFilterApplied={isFilterApplied} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TRACE && (
|
||||
{selectedView === ExplorerViews.TRACE && (
|
||||
<div className="trace-explorer-traces-view">
|
||||
<TracesView isFilterApplied={isFilterApplied} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TIME_SERIES && (
|
||||
{selectedView === ExplorerViews.TIMESERIES && (
|
||||
<div className="trace-explorer-time-series-view">
|
||||
<TimeSeriesView
|
||||
dataSource={DataSource.TRACES}
|
||||
@ -314,7 +299,7 @@ function TracesExplorer(): JSX.Element {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TABLE && (
|
||||
{selectedView === ExplorerViews.TABLE && (
|
||||
<div className="trace-explorer-table-view">
|
||||
<TableView />
|
||||
</div>
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
&.ghost {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
@ -33,6 +35,12 @@
|
||||
box-shadow: 0 2px 0 rgba(62, 86, 245, 0.09);
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--Slate-300, #242834);
|
||||
background: var(--Ink-200, #23262e);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@ -85,12 +93,12 @@
|
||||
font-size: 12px;
|
||||
|
||||
color: var(--bg-vanilla-400);
|
||||
font-size: 11px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 18px;
|
||||
letter-spacing: 0.56px;
|
||||
text-transform: uppercase;
|
||||
|
||||
max-width: 150px;
|
||||
min-width: 120px;
|
||||
white-space: nowrap;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user