mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-23 02:17:11 +00:00
feat: update explorer views
This commit is contained in:
parent
6deb75ff46
commit
bde078472b
@ -1,5 +0,0 @@
|
||||
.logs-qb {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
import './LogsQB.styles.scss';
|
||||
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { Formula } from 'container/QueryBuilder/components/Formula/Formula';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { memo } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { QueryBuilderV2Props } from '../QueryBuilderV2';
|
||||
import QueryFooter from '../QueryV2/QueryFooter/QueryFooter';
|
||||
import { QueryV2 } from '../QueryV2/QueryV2';
|
||||
|
||||
export const LogsQB = memo(function LogsQB({
|
||||
filterConfigs,
|
||||
}: QueryBuilderV2Props): JSX.Element {
|
||||
const version = ENTITY_VERSION_V4;
|
||||
|
||||
const { currentQuery, addNewFormula, addNewBuilderQuery } = useQueryBuilder();
|
||||
|
||||
return (
|
||||
<div className="logs-qb">
|
||||
<div className="qb-content-container">
|
||||
{currentQuery.builder.queryData.map((query, index) => (
|
||||
<QueryV2
|
||||
key={query.queryName}
|
||||
index={index}
|
||||
query={query}
|
||||
filterConfigs={filterConfigs}
|
||||
version={version}
|
||||
isAvailableToDisable={false}
|
||||
queryVariant="static"
|
||||
source={DataSource.LOGS}
|
||||
/>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.length > 0 && (
|
||||
<div className="qb-formulas-container">
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => {
|
||||
const query =
|
||||
currentQuery.builder.queryData[index] ||
|
||||
currentQuery.builder.queryData[0];
|
||||
|
||||
return (
|
||||
<div key={formula.queryName} className="qb-formula">
|
||||
<Formula
|
||||
filterConfigs={filterConfigs}
|
||||
query={query}
|
||||
formula={formula}
|
||||
index={index}
|
||||
isAdditionalFilterEnable={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<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>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@ -1,19 +0,0 @@
|
||||
.metrics-qb {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
|
||||
border-bottom: 1px solid var(--Slate-400, #1d212d);
|
||||
|
||||
.query-v2 {
|
||||
.qb-entity-options {
|
||||
.options {
|
||||
.query-name {
|
||||
&::before {
|
||||
height: 306px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
import './MetricsQB.styles.scss';
|
||||
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { Formula } from 'container/QueryBuilder/components/Formula/Formula';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { QueryBuilderV2Props } from '../QueryBuilderV2';
|
||||
import QueryFooter from '../QueryV2/QueryFooter/QueryFooter';
|
||||
import { QueryV2 } from '../QueryV2/QueryV2';
|
||||
|
||||
function MetricsQB({ filterConfigs }: QueryBuilderV2Props): JSX.Element {
|
||||
const version = ENTITY_VERSION_V4;
|
||||
|
||||
const { currentQuery, addNewFormula, addNewBuilderQuery } = useQueryBuilder();
|
||||
|
||||
const { isMetricsDataSource } = useQueryOperations({
|
||||
index: 0,
|
||||
query: currentQuery.builder.queryData[0],
|
||||
filterConfigs,
|
||||
isListViewPanel: false,
|
||||
entityVersion: version,
|
||||
});
|
||||
|
||||
console.log('isMetricsDataSource', isMetricsDataSource);
|
||||
|
||||
return (
|
||||
<div className="metrics-qb">
|
||||
<div className="qb-content-container">
|
||||
{currentQuery.builder.queryData.map((query, index) => (
|
||||
<QueryV2
|
||||
key={query.queryName}
|
||||
index={index}
|
||||
query={query}
|
||||
filterConfigs={filterConfigs}
|
||||
version={version}
|
||||
isAvailableToDisable={false}
|
||||
queryVariant="static"
|
||||
source={DataSource.METRICS}
|
||||
/>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.length > 0 && (
|
||||
<div className="qb-formulas-container">
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => {
|
||||
const query =
|
||||
currentQuery.builder.queryData[index] ||
|
||||
currentQuery.builder.queryData[0];
|
||||
|
||||
return (
|
||||
<div key={formula.queryName} className="qb-formula">
|
||||
<Formula
|
||||
filterConfigs={filterConfigs}
|
||||
query={query}
|
||||
formula={formula}
|
||||
index={index}
|
||||
isAdditionalFilterEnable={false} // TODO: Need to enable this
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<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>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MetricsQB;
|
||||
@ -1,13 +1,10 @@
|
||||
.query-builder-v2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
flex-direction: row;
|
||||
gap: 4px;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
'Helvetica Neue', sans-serif;
|
||||
|
||||
@ -160,6 +157,7 @@
|
||||
|
||||
margin-left: 32px;
|
||||
padding-bottom: 16px;
|
||||
padding-left: 8px;
|
||||
|
||||
.qb-formula {
|
||||
.ant-row {
|
||||
@ -343,6 +341,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-data-source {
|
||||
margin-left: 8px;
|
||||
|
||||
.ant-select-selector {
|
||||
min-width: 120px;
|
||||
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--Slate-400, #1d212d);
|
||||
background: var(--Ink-300, #16181d);
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qb-search-container {
|
||||
|
||||
@ -1,108 +1,119 @@
|
||||
import './QueryBuilderV2.styles.scss';
|
||||
|
||||
import { OPERATORS, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { Formula } from 'container/QueryBuilder/components/Formula';
|
||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { memo, useEffect, useMemo } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { LogsQB } from './Logs/LogsQB';
|
||||
import MetricsQB from './Metrics/MetricsQB';
|
||||
import { QueryBuilderV2Provider } from './QueryBuilderV2Context';
|
||||
import TracesQB from './Traces/TracesQB';
|
||||
import QueryFooter from './QueryV2/QueryFooter/QueryFooter';
|
||||
import { QueryV2 } from './QueryV2/QueryV2';
|
||||
|
||||
export type QueryBuilderV2Props = {
|
||||
source: DataSource;
|
||||
panelType: PANEL_TYPES;
|
||||
filterConfigs: QueryBuilderProps['filterConfigs'];
|
||||
isListViewPanel: boolean;
|
||||
version: string;
|
||||
};
|
||||
|
||||
const QueryBuilderV2Main = memo(function QueryBuilderV2Main({
|
||||
source,
|
||||
panelType,
|
||||
filterConfigs,
|
||||
isListViewPanel,
|
||||
export const QueryBuilderV2 = memo(function QueryBuilderV2({
|
||||
config,
|
||||
panelType: newPanelType,
|
||||
filterConfigs = {},
|
||||
queryComponents,
|
||||
isListViewPanel = false,
|
||||
showFunctions = false,
|
||||
version,
|
||||
}: QueryBuilderV2Props): JSX.Element {
|
||||
const isMetricsDataSource = source === DataSource.METRICS;
|
||||
const isLogsDataSource = source === DataSource.LOGS;
|
||||
const isTracesDataSource = source === DataSource.TRACES;
|
||||
}: QueryBuilderProps): JSX.Element {
|
||||
const {
|
||||
currentQuery,
|
||||
addNewBuilderQuery,
|
||||
addNewFormula,
|
||||
handleSetConfig,
|
||||
panelType,
|
||||
initialDataSource,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const listViewLogFilterConfigs: QueryBuilderProps['filterConfigs'] = useMemo(() => {
|
||||
const config: QueryBuilderProps['filterConfigs'] = {
|
||||
stepInterval: { isHidden: true, isDisabled: true },
|
||||
having: { isHidden: true, isDisabled: true },
|
||||
filters: {
|
||||
customKey: 'body',
|
||||
customOp: OPERATORS.CONTAINS,
|
||||
},
|
||||
};
|
||||
console.log('isListViewPanel', isListViewPanel, showFunctions);
|
||||
|
||||
return config;
|
||||
}, []);
|
||||
|
||||
const listViewTracesFilterConfigs: QueryBuilderProps['filterConfigs'] = useMemo(() => {
|
||||
const config: QueryBuilderProps['filterConfigs'] = {
|
||||
stepInterval: { isHidden: true, isDisabled: true },
|
||||
having: { isHidden: true, isDisabled: true },
|
||||
limit: { isHidden: true, isDisabled: true },
|
||||
filters: {
|
||||
customKey: 'body',
|
||||
customOp: OPERATORS.CONTAINS,
|
||||
},
|
||||
};
|
||||
|
||||
return config;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="query-builder-v2">
|
||||
{isMetricsDataSource ? (
|
||||
<MetricsQB
|
||||
source={DataSource.METRICS}
|
||||
filterConfigs={filterConfigs}
|
||||
panelType={panelType}
|
||||
version={version}
|
||||
isListViewPanel={isListViewPanel}
|
||||
/>
|
||||
) : null}
|
||||
{isLogsDataSource ? (
|
||||
<LogsQB
|
||||
source={DataSource.LOGS}
|
||||
filterConfigs={listViewLogFilterConfigs}
|
||||
panelType={panelType}
|
||||
version={version}
|
||||
isListViewPanel={isListViewPanel}
|
||||
/>
|
||||
) : null}
|
||||
{isTracesDataSource ? (
|
||||
<TracesQB
|
||||
source={DataSource.TRACES}
|
||||
filterConfigs={listViewTracesFilterConfigs}
|
||||
panelType={panelType}
|
||||
version={version}
|
||||
isListViewPanel={isListViewPanel}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
const currentDataSource = useMemo(
|
||||
() =>
|
||||
(config && config.queryVariant === 'static' && config.initialDataSource) ||
|
||||
null,
|
||||
[config],
|
||||
);
|
||||
});
|
||||
|
||||
function QueryBuilderV2(props: QueryBuilderV2Props): JSX.Element {
|
||||
const { source, panelType, filterConfigs, isListViewPanel, version } = props;
|
||||
useEffect(() => {
|
||||
if (currentDataSource !== initialDataSource || newPanelType !== panelType) {
|
||||
if (newPanelType === PANEL_TYPES.BAR) {
|
||||
handleSetConfig(PANEL_TYPES.BAR, DataSource.METRICS);
|
||||
return;
|
||||
}
|
||||
handleSetConfig(newPanelType, currentDataSource);
|
||||
}
|
||||
}, [
|
||||
handleSetConfig,
|
||||
panelType,
|
||||
initialDataSource,
|
||||
currentDataSource,
|
||||
newPanelType,
|
||||
]);
|
||||
|
||||
return (
|
||||
<QueryBuilderV2Provider>
|
||||
<QueryBuilderV2Main
|
||||
source={source}
|
||||
panelType={panelType}
|
||||
<div className="query-builder-v2">
|
||||
<div className="qb-content-container">
|
||||
{currentQuery.builder.queryData.map((query, index) => (
|
||||
<QueryV2
|
||||
key={query.queryName}
|
||||
index={index}
|
||||
query={query}
|
||||
filterConfigs={filterConfigs}
|
||||
isListViewPanel={isListViewPanel}
|
||||
queryComponents={queryComponents}
|
||||
version={version}
|
||||
isAvailableToDisable={false}
|
||||
showSpanScopeSelector
|
||||
queryVariant={config?.queryVariant || 'dropdown'}
|
||||
/>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.length > 0 && (
|
||||
<div className="qb-formulas-container">
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => {
|
||||
const query =
|
||||
currentQuery.builder.queryData[index] ||
|
||||
currentQuery.builder.queryData[0];
|
||||
|
||||
return (
|
||||
<div key={formula.queryName} className="qb-formula">
|
||||
<Formula
|
||||
filterConfigs={filterConfigs}
|
||||
query={query}
|
||||
formula={formula}
|
||||
index={index}
|
||||
isAdditionalFilterEnable={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<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>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</QueryBuilderV2Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default QueryBuilderV2;
|
||||
});
|
||||
|
||||
@ -17,16 +17,20 @@ import QuerySearch from './QuerySearch/QuerySearch';
|
||||
|
||||
export const QueryV2 = memo(function QueryV2({
|
||||
index,
|
||||
queryVariant,
|
||||
query,
|
||||
filterConfigs,
|
||||
queryComponents,
|
||||
isListViewPanel = false,
|
||||
version,
|
||||
showSpanScopeSelector = false,
|
||||
source,
|
||||
}: QueryProps & { source: DataSource }): JSX.Element {
|
||||
}: QueryProps): JSX.Element {
|
||||
const { cloneQuery } = useQueryBuilder();
|
||||
|
||||
const showFunctions = query?.functions?.length > 0;
|
||||
const { dataSource } = query;
|
||||
|
||||
console.log('queryComponents', queryComponents);
|
||||
|
||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||
|
||||
@ -34,6 +38,7 @@ export const QueryV2 = memo(function QueryV2({
|
||||
handleChangeQueryData,
|
||||
handleDeleteQuery,
|
||||
handleQueryFunctionsUpdates,
|
||||
handleChangeDataSource,
|
||||
} = useQueryOperations({
|
||||
index,
|
||||
query,
|
||||
@ -61,7 +66,7 @@ export const QueryV2 = memo(function QueryV2({
|
||||
<div className="query-actions-container">
|
||||
<div className="query-actions-left-container">
|
||||
<QBEntityOptions
|
||||
isMetricsDataSource={source === DataSource.METRICS}
|
||||
isMetricsDataSource={dataSource === DataSource.METRICS}
|
||||
showFunctions={
|
||||
(version && version === ENTITY_VERSION_V4) ||
|
||||
query.dataSource === DataSource.LOGS ||
|
||||
@ -81,6 +86,8 @@ export const QueryV2 = memo(function QueryV2({
|
||||
showCloneOption={false}
|
||||
isListViewPanel={isListViewPanel}
|
||||
index={index}
|
||||
queryVariant={queryVariant}
|
||||
onChangeDataSource={handleChangeDataSource}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -111,7 +118,7 @@ export const QueryV2 = memo(function QueryV2({
|
||||
|
||||
<div className="qb-elements-container">
|
||||
<div className="qb-search-container">
|
||||
{source === DataSource.METRICS && (
|
||||
{dataSource === DataSource.METRICS && (
|
||||
<div className="metrics-select-container">
|
||||
<MetricsSelect query={query} index={0} version="v4" />
|
||||
</div>
|
||||
@ -129,9 +136,9 @@ export const QueryV2 = memo(function QueryV2({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<QueryAggregation source={source} />
|
||||
<QueryAggregation source={dataSource} />
|
||||
|
||||
{source === DataSource.METRICS && (
|
||||
{dataSource === DataSource.METRICS && (
|
||||
<MetricsAggregateSection query={query} index={0} version="v4" />
|
||||
)}
|
||||
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
.traces-qb {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
import './TracesQB.styles.scss';
|
||||
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { Formula } from 'container/QueryBuilder/components/Formula';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { QueryBuilderV2Props } from '../QueryBuilderV2';
|
||||
import QueryFooter from '../QueryV2/QueryFooter/QueryFooter';
|
||||
import { QueryV2 } from '../QueryV2/QueryV2';
|
||||
|
||||
function TracesQB({ filterConfigs }: QueryBuilderV2Props): JSX.Element {
|
||||
const version = ENTITY_VERSION_V4;
|
||||
|
||||
const { currentQuery, addNewFormula, addNewBuilderQuery } = useQueryBuilder();
|
||||
|
||||
const { isMetricsDataSource } = useQueryOperations({
|
||||
index: 0,
|
||||
query: currentQuery.builder.queryData[0],
|
||||
filterConfigs,
|
||||
isListViewPanel: false,
|
||||
entityVersion: version,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="traces-qb">
|
||||
<div className="qb-content-container">
|
||||
{currentQuery.builder.queryData.map((query, index) => (
|
||||
<QueryV2
|
||||
key={query.queryName}
|
||||
index={index}
|
||||
query={query}
|
||||
filterConfigs={filterConfigs}
|
||||
version={version}
|
||||
isAvailableToDisable={false}
|
||||
queryVariant="static"
|
||||
source={DataSource.TRACES}
|
||||
showSpanScopeSelector
|
||||
/>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.length > 0 && (
|
||||
<div className="qb-formulas-container">
|
||||
{currentQuery.builder.queryFormulas.map((formula, index) => {
|
||||
const query =
|
||||
currentQuery.builder.queryData[index] ||
|
||||
currentQuery.builder.queryData[0];
|
||||
|
||||
return (
|
||||
<div key={formula.queryName} className="qb-formula">
|
||||
<Formula
|
||||
filterConfigs={filterConfigs}
|
||||
query={query}
|
||||
formula={formula}
|
||||
index={index}
|
||||
isAdditionalFilterEnable={isMetricsDataSource}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<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>
|
||||
))}
|
||||
|
||||
{currentQuery.builder.queryFormulas.map((formula) => (
|
||||
<div key={formula.queryName} className="formula-name">
|
||||
{formula.queryName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TracesQB;
|
||||
@ -1,13 +1,12 @@
|
||||
import './LogsExplorerQuerySection.styles.scss';
|
||||
|
||||
import QueryBuilderV2 from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import {
|
||||
initialQueriesMap,
|
||||
OPERATORS,
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import ExplorerOrderBy from 'container/ExplorerOrderBy';
|
||||
import { QueryBuilder } from 'container/QueryBuilder';
|
||||
import { OrderByFilterProps } from 'container/QueryBuilder/filters/OrderByFilter/OrderByFilter.interfaces';
|
||||
import QueryBuilderSearchV2 from 'container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2';
|
||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||
@ -16,8 +15,8 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import {
|
||||
ExplorerViews,
|
||||
prepareQueryWithDefaultTimestamp,
|
||||
SELECTED_VIEWS,
|
||||
} from 'pages/LogsExplorer/utils';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -26,7 +25,7 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
function LogExplorerQuerySection({
|
||||
selectedView,
|
||||
}: {
|
||||
selectedView: SELECTED_VIEWS;
|
||||
selectedView: ExplorerViews;
|
||||
}): JSX.Element {
|
||||
const { currentQuery, updateAllQueriesOperators } = useQueryBuilder();
|
||||
|
||||
@ -89,7 +88,7 @@ function LogExplorerQuerySection({
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedView === SELECTED_VIEWS.SEARCH && (
|
||||
{selectedView === ExplorerViews.LIST && (
|
||||
<div className="qb-search-view-container">
|
||||
<QueryBuilderSearchV2
|
||||
query={query}
|
||||
@ -99,25 +98,18 @@ function LogExplorerQuerySection({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedView === SELECTED_VIEWS.QUERY_BUILDER && (
|
||||
<QueryBuilder
|
||||
panelType={panelTypes}
|
||||
{(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
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedView === SELECTED_VIEWS.QUERY_BUILDER_V2 && (
|
||||
<QueryBuilderV2
|
||||
source={DataSource.LOGS}
|
||||
isListViewPanel={panelTypes === PANEL_TYPES.LIST}
|
||||
panelType={panelTypes}
|
||||
filterConfigs={filterConfigs}
|
||||
version="v3" // setting this to v3 as we this is rendered in logs explorer
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -80,10 +80,54 @@
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logs-actions-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
height: 40px;
|
||||
padding: 4px 8px;
|
||||
width: 100%;
|
||||
|
||||
border-top: 1px solid var(--Slate-500, #161922);
|
||||
border-bottom: 1px solid var(--Slate-500, #161922);
|
||||
box-shadow: 0px 8px 6px 0px #0b0c0e;
|
||||
|
||||
.tab-options {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.tab-options-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tab-options-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.frequency-chart-view-controller {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.query-stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
align-self: flex-end;
|
||||
|
||||
.rows {
|
||||
color: var(--bg-vanilla-400);
|
||||
font-family: 'Geist Mono';
|
||||
@ -110,13 +154,6 @@
|
||||
letter-spacing: 0.36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logs-actions-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.ant-btn {
|
||||
border: none;
|
||||
@ -186,6 +223,14 @@
|
||||
background: var(--bg-robin-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logs-actions-container {
|
||||
.tab-options {
|
||||
border-top: 1px solid var(--text-vanilla-300);
|
||||
border-bottom: 1px solid var(--text-vanilla-300);
|
||||
}
|
||||
|
||||
.query-stats {
|
||||
.rows {
|
||||
color: var(--bg-ink-400);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import './LogsExplorerViews.styles.scss';
|
||||
|
||||
import { Button, Typography } from 'antd';
|
||||
import { Button, Switch, Typography } from 'antd';
|
||||
import { getQueryStats, WsDataEvent } from 'api/common/getQueryStats';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||
@ -47,7 +47,7 @@ import {
|
||||
set,
|
||||
} from 'lodash-es';
|
||||
import { Sliders } from 'lucide-react';
|
||||
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import {
|
||||
memo,
|
||||
@ -80,15 +80,13 @@ import { v4 } from 'uuid';
|
||||
|
||||
import QueryStatus from './QueryStatus';
|
||||
|
||||
function LogsExplorerViews({
|
||||
function LogsExplorerViewsContainer({
|
||||
selectedView,
|
||||
showFrequencyChart,
|
||||
setIsLoadingQueries,
|
||||
listQueryKeyRef,
|
||||
chartQueryKeyRef,
|
||||
}: {
|
||||
selectedView: SELECTED_VIEWS;
|
||||
showFrequencyChart: boolean;
|
||||
selectedView: ExplorerViews;
|
||||
setIsLoadingQueries: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
listQueryKeyRef: MutableRefObject<any>;
|
||||
@ -97,6 +95,7 @@ function LogsExplorerViews({
|
||||
}): JSX.Element {
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [showFrequencyChart, setShowFrequencyChart] = useState(true);
|
||||
|
||||
// this is to respect the panel type present in the URL rather than defaulting it to list always.
|
||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||
@ -240,15 +239,6 @@ function LogsExplorerViews({
|
||||
[currentQuery, selectedPanelType, updateAllQueriesOperators],
|
||||
);
|
||||
|
||||
const handleModeChange = (panelType: PANEL_TYPES): void => {
|
||||
if (selectedView === SELECTED_VIEWS.SEARCH) {
|
||||
handleSetConfig(panelType, DataSource.LOGS);
|
||||
}
|
||||
|
||||
setShowFormatMenuItems(false);
|
||||
handleExplorerTabChange(panelType);
|
||||
};
|
||||
|
||||
const {
|
||||
data: listChartData,
|
||||
isFetching: isFetchingListChartData,
|
||||
@ -460,8 +450,7 @@ function LogsExplorerViews({
|
||||
|
||||
useEffect(() => {
|
||||
const shouldChangeView =
|
||||
(isMultipleQueries || isGroupByExist) &&
|
||||
selectedView !== SELECTED_VIEWS.SEARCH;
|
||||
(isMultipleQueries || isGroupByExist) && selectedView !== ExplorerViews.LIST;
|
||||
|
||||
if (selectedPanelType === PANEL_TYPES.LIST && shouldChangeView) {
|
||||
handleExplorerTabChange(PANEL_TYPES.TIME_SERIES);
|
||||
@ -481,11 +470,7 @@ function LogsExplorerViews({
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
selectedView &&
|
||||
selectedView === SELECTED_VIEWS.SEARCH &&
|
||||
handleSetConfig
|
||||
) {
|
||||
if (selectedView && selectedView === ExplorerViews.LIST && handleSetConfig) {
|
||||
handleSetConfig(defaultTo(panelTypes, PANEL_TYPES.LIST), DataSource.LOGS);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -651,60 +636,26 @@ function LogsExplorerViews({
|
||||
|
||||
return (
|
||||
<div className="logs-explorer-views-container">
|
||||
{showFrequencyChart && (
|
||||
<LogsExplorerChart
|
||||
className="logs-histogram"
|
||||
isLoading={isFetchingListChartData || isLoadingListChartData}
|
||||
data={chartData}
|
||||
isLogsExplorerViews={panelType === PANEL_TYPES.LIST}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="logs-explorer-views-types">
|
||||
<div className="views-tabs-container">
|
||||
<Button.Group className="views-tabs">
|
||||
<Button
|
||||
value={PANEL_TYPES.LIST}
|
||||
className={
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
selectedPanelType === PANEL_TYPES.LIST ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
disabled={
|
||||
(isMultipleQueries || isGroupByExist) && selectedView !== 'search'
|
||||
}
|
||||
onClick={(): void => handleModeChange(PANEL_TYPES.LIST)}
|
||||
data-testid="logs-list-view"
|
||||
>
|
||||
List view
|
||||
</Button>
|
||||
<Button
|
||||
value={PANEL_TYPES.TIME_SERIES}
|
||||
className={
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
selectedPanelType === PANEL_TYPES.TIME_SERIES
|
||||
? 'selected_view tab'
|
||||
: 'tab'
|
||||
}
|
||||
onClick={(): void => handleModeChange(PANEL_TYPES.TIME_SERIES)}
|
||||
data-testid="time-series-view"
|
||||
>
|
||||
Time series
|
||||
</Button>
|
||||
<Button
|
||||
value={PANEL_TYPES.TABLE}
|
||||
className={
|
||||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
selectedPanelType === PANEL_TYPES.TABLE ? 'selected_view tab' : 'tab'
|
||||
}
|
||||
onClick={(): void => handleModeChange(PANEL_TYPES.TABLE)}
|
||||
data-testid="table-view"
|
||||
>
|
||||
Table
|
||||
</Button>
|
||||
</Button.Group>
|
||||
<div className="logs-actions-container">
|
||||
{selectedPanelType === PANEL_TYPES.LIST && (
|
||||
<div className="tab-options">
|
||||
<div className="tab-options-left">
|
||||
{selectedPanelType === PANEL_TYPES.LIST && (
|
||||
<div className="frequency-chart-view-controller">
|
||||
<Typography>Frequency chart</Typography>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={showFrequencyChart}
|
||||
defaultChecked
|
||||
onChange={(): void => setShowFrequencyChart(!showFrequencyChart)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tab-options-right">
|
||||
{selectedPanelType === PANEL_TYPES.LIST && (
|
||||
<>
|
||||
<Download
|
||||
data={flattenLogData}
|
||||
isLoading={isFetching}
|
||||
@ -727,8 +678,9 @@ function LogsExplorerViews({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{(selectedPanelType === PANEL_TYPES.TIME_SERIES ||
|
||||
selectedPanelType === PANEL_TYPES.TABLE) && (
|
||||
<div className="query-stats">
|
||||
@ -737,12 +689,14 @@ function LogsExplorerViews({
|
||||
error={isError}
|
||||
success={isSuccess}
|
||||
/>
|
||||
|
||||
{queryStats?.read_rows && (
|
||||
<Typography.Text className="rows">
|
||||
{getYAxisFormattedValue(queryStats.read_rows?.toString(), 'short')}{' '}
|
||||
rows
|
||||
</Typography.Text>
|
||||
)}
|
||||
|
||||
{queryStats?.elapsed_ms && (
|
||||
<>
|
||||
<div className="divider" />
|
||||
@ -755,6 +709,16 @@ function LogsExplorerViews({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedPanelType === PANEL_TYPES.LIST && showFrequencyChart && (
|
||||
<LogsExplorerChart
|
||||
className="logs-histogram"
|
||||
isLoading={isFetchingListChartData || isLoadingListChartData}
|
||||
data={chartData}
|
||||
isLogsExplorerViews={panelType === PANEL_TYPES.LIST}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="logs-explorer-views-type-content">
|
||||
{selectedPanelType === PANEL_TYPES.LIST && (
|
||||
@ -801,4 +765,4 @@ function LogsExplorerViews({
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(LogsExplorerViews);
|
||||
export default memo(LogsExplorerViewsContainer);
|
||||
|
||||
@ -4,7 +4,7 @@ import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQuery
|
||||
import { logsQueryRangeSuccessResponse } from 'mocks-server/__mockdata__/logs_query_range';
|
||||
import { server } from 'mocks-server/server';
|
||||
import { rest } from 'msw';
|
||||
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import { PreferenceContextProvider } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
import { QueryBuilderContext } from 'providers/QueryBuilder';
|
||||
import { VirtuosoMockContext } from 'react-virtuoso';
|
||||
@ -127,8 +127,7 @@ const renderer = (): RenderResult =>
|
||||
>
|
||||
<PreferenceContextProvider>
|
||||
<LogsExplorerViews
|
||||
selectedView={SELECTED_VIEWS.SEARCH}
|
||||
showFrequencyChart
|
||||
selectedView={ExplorerViews.LIST}
|
||||
setIsLoadingQueries={(): void => {}}
|
||||
listQueryKeyRef={{ current: {} }}
|
||||
chartQueryKeyRef={{ current: {} }}
|
||||
@ -212,8 +211,7 @@ describe('LogsExplorerViews -', () => {
|
||||
<QueryBuilderContext.Provider value={mockQueryBuilderContextValue}>
|
||||
<PreferenceContextProvider>
|
||||
<LogsExplorerViews
|
||||
selectedView={SELECTED_VIEWS.SEARCH}
|
||||
showFrequencyChart
|
||||
selectedView={ExplorerViews.LIST}
|
||||
setIsLoadingQueries={(): void => {}}
|
||||
listQueryKeyRef={{ current: {} }}
|
||||
chartQueryKeyRef={{ current: {} }}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 10px 0;
|
||||
margin: 4px 0;
|
||||
padding: 0 1rem;
|
||||
|
||||
.explore-header-left-actions {
|
||||
@ -56,7 +56,7 @@
|
||||
}
|
||||
|
||||
.explore-content {
|
||||
margin-top: 10px;
|
||||
padding: 0 8px;
|
||||
|
||||
.ant-space {
|
||||
margin-top: 10px;
|
||||
|
||||
@ -3,10 +3,11 @@ import './Explorer.styles.scss';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Switch } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import QueryBuilderV2 from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import ExplorerOptionWrapper from 'container/ExplorerOptions/ExplorerOptionWrapper';
|
||||
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
|
||||
import { QueryBuilderProps } from 'container/QueryBuilder/QueryBuilder.interfaces';
|
||||
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
@ -102,6 +103,11 @@ function Explorer(): JSX.Element {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const queryComponents = useMemo(
|
||||
(): QueryBuilderProps['queryComponents'] => ({}),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
|
||||
<div className="metrics-explorer-explore-container">
|
||||
@ -121,8 +127,12 @@ function Explorer(): JSX.Element {
|
||||
</div>
|
||||
{/* <QuerySection /> */}
|
||||
<QueryBuilderV2
|
||||
source={DataSource.METRICS}
|
||||
query={currentQuery.builder.queryData[0]}
|
||||
config={{ initialDataSource: DataSource.METRICS, queryVariant: 'static' }}
|
||||
panelType={PANEL_TYPES.TIME_SERIES}
|
||||
queryComponents={queryComponents}
|
||||
showFunctions={false}
|
||||
version="v3"
|
||||
isListViewPanel
|
||||
/>
|
||||
{/* TODO: Enable once we have resolved all related metrics issues */}
|
||||
{/* <Button.Group className="explore-tabs">
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import './QuerySection.styles.scss';
|
||||
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Select, Tabs, Typography } from 'antd';
|
||||
import { Button, Tabs, Typography } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import PromQLIcon from 'assets/Dashboard/PromQl';
|
||||
import QueryBuilderV2 from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import TextToolTip from 'components/TextToolTip';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { QBShortcuts } from 'constants/shortcuts/QBShortcuts';
|
||||
@ -27,14 +27,13 @@ import {
|
||||
getPreviousWidgets,
|
||||
getSelectedWidgetIndex,
|
||||
} from 'providers/Dashboard/util';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import ClickHouseQueryContainer from './QueryBuilder/clickHouse';
|
||||
import PromQLQueryContainer from './QueryBuilder/promQL';
|
||||
@ -49,10 +48,6 @@ function QuerySection({
|
||||
|
||||
const { selectedDashboard, setSelectedDashboard } = useDashboard();
|
||||
|
||||
const [selectedDataSource, setSelectedDataSource] = useState<DataSource>(
|
||||
DataSource.METRICS,
|
||||
);
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
const { widgets } = selectedDashboard?.data || {};
|
||||
@ -148,6 +143,11 @@ function QuerySection({
|
||||
return config;
|
||||
}, []);
|
||||
|
||||
const queryComponents = useMemo(
|
||||
(): QueryBuilderProps['queryComponents'] => ({}),
|
||||
[],
|
||||
);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const supportedQueryTypes = PANEL_TYPE_TO_QUERY_TYPES[selectedGraph] || [];
|
||||
|
||||
@ -157,20 +157,12 @@ function QuerySection({
|
||||
label: 'Query Builder',
|
||||
component: (
|
||||
<div className="query-builder-v2-container">
|
||||
<Select
|
||||
onChange={setSelectedDataSource}
|
||||
value={selectedDataSource}
|
||||
options={Object.values(DataSource).map((dataSource) => ({
|
||||
label: dataSource,
|
||||
value: dataSource,
|
||||
}))}
|
||||
/>
|
||||
<QueryBuilderV2
|
||||
panelType={selectedGraph}
|
||||
filterConfigs={filterConfigs}
|
||||
version={selectedDashboard?.data?.version || 'v3'}
|
||||
isListViewPanel={selectedGraph === PANEL_TYPES.LIST}
|
||||
source={selectedDataSource}
|
||||
queryComponents={queryComponents}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
@ -203,11 +195,11 @@ function QuerySection({
|
||||
children: queryTypeComponents[queryType].component,
|
||||
}));
|
||||
}, [
|
||||
queryComponents,
|
||||
selectedGraph,
|
||||
filterConfigs,
|
||||
selectedDashboard?.data?.version,
|
||||
isDarkMode,
|
||||
selectedDataSource,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { DataSourceDropdown } from '..';
|
||||
import QueryFunctions from '../QueryFunctions/QueryFunctions';
|
||||
|
||||
interface QBEntityOptionsProps {
|
||||
@ -40,8 +41,11 @@ interface QBEntityOptionsProps {
|
||||
showCloneOption?: boolean;
|
||||
isListViewPanel?: boolean;
|
||||
index?: number;
|
||||
queryVariant?: 'dropdown' | 'static';
|
||||
onChangeDataSource?: (value: DataSource) => void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
export default function QBEntityOptions({
|
||||
query,
|
||||
isMetricsDataSource,
|
||||
@ -58,6 +62,8 @@ export default function QBEntityOptions({
|
||||
showCloneOption,
|
||||
onCloneQuery,
|
||||
index,
|
||||
queryVariant,
|
||||
onChangeDataSource,
|
||||
}: QBEntityOptionsProps): JSX.Element {
|
||||
const handleCloneEntity = (): void => {
|
||||
if (isFunction(onCloneQuery)) {
|
||||
@ -117,6 +123,21 @@ export default function QBEntityOptions({
|
||||
{entityData.queryName}
|
||||
</Button>
|
||||
|
||||
{queryVariant === 'dropdown' && (
|
||||
<div className="query-data-source">
|
||||
<DataSourceDropdown
|
||||
onChange={(value): void => {
|
||||
if (onChangeDataSource) {
|
||||
onChangeDataSource(value);
|
||||
}
|
||||
}}
|
||||
value={query?.dataSource || DataSource.METRICS}
|
||||
isListViewPanel={isListViewPanel}
|
||||
className="query-data-source-dropdown"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showFunctions &&
|
||||
(isMetricsDataSource || isLogsDataSource) &&
|
||||
query &&
|
||||
@ -161,4 +182,6 @@ QBEntityOptions.defaultProps = {
|
||||
onDelete: noop,
|
||||
showDeleteButton: false,
|
||||
showCloneOption: true,
|
||||
queryVariant: 'static',
|
||||
onChangeDataSource: noop,
|
||||
};
|
||||
|
||||
@ -350,6 +350,7 @@ export const Query = memo(function Query({
|
||||
showDeleteButton={currentQuery.builder.queryData.length > 1}
|
||||
isListViewPanel={isListViewPanel}
|
||||
index={index}
|
||||
queryVariant={queryVariant}
|
||||
/>
|
||||
|
||||
{!isCollapse && (
|
||||
|
||||
@ -1,35 +1,31 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
import './ToolbarActions.styles.scss';
|
||||
|
||||
import { FilterOutlined } from '@ant-design/icons';
|
||||
import { Button, Switch, Tooltip, Typography } from 'antd';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import cx from 'classnames';
|
||||
import { Atom, Binoculars, SquareMousePointer, Terminal } from 'lucide-react';
|
||||
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
|
||||
interface LeftToolbarActionsProps {
|
||||
items: any;
|
||||
selectedView: string;
|
||||
onToggleHistrogramVisibility: () => void;
|
||||
onChangeSelectedView: (view: SELECTED_VIEWS) => void;
|
||||
showFrequencyChart: boolean;
|
||||
onChangeSelectedView: (view: ExplorerViews) => void;
|
||||
showFilter: boolean;
|
||||
handleFilterVisibilityChange: () => void;
|
||||
}
|
||||
|
||||
const activeTab = 'active-tab';
|
||||
const actionBtn = 'action-btn';
|
||||
export const queryBuilder = 'query-builder';
|
||||
export const queryBuilderV2 = 'query-builder-v2';
|
||||
|
||||
export default function LeftToolbarActions({
|
||||
items,
|
||||
selectedView,
|
||||
onToggleHistrogramVisibility,
|
||||
|
||||
onChangeSelectedView,
|
||||
showFrequencyChart,
|
||||
showFilter,
|
||||
handleFilterVisibilityChange,
|
||||
}: LeftToolbarActionsProps): JSX.Element {
|
||||
const { clickhouse, search, queryBuilder: QB } = items;
|
||||
const { clickhouse, list, timeseries, table, trace } = items;
|
||||
|
||||
return (
|
||||
<div className="left-toolbar">
|
||||
@ -41,72 +37,90 @@ export default function LeftToolbarActions({
|
||||
</Tooltip>
|
||||
)}
|
||||
<div className="left-toolbar-query-actions">
|
||||
<Tooltip title="Search">
|
||||
{list?.show && (
|
||||
<Tooltip title="List View">
|
||||
<Button
|
||||
disabled={search.disabled}
|
||||
disabled={list.disabled}
|
||||
className={cx(
|
||||
'search',
|
||||
actionBtn,
|
||||
selectedView === 'search' ? activeTab : '',
|
||||
'list-view-tab',
|
||||
'explorer-view-option',
|
||||
selectedView === list.key ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(SELECTED_VIEWS.SEARCH)}
|
||||
onClick={(): void => onChangeSelectedView(list.key)}
|
||||
>
|
||||
<SquareMousePointer size={14} data-testid="search-view" />
|
||||
List View
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Query Builder">
|
||||
<Button
|
||||
disabled={QB.disabled}
|
||||
className={cx(
|
||||
queryBuilder,
|
||||
actionBtn,
|
||||
selectedView === queryBuilder ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(SELECTED_VIEWS.QUERY_BUILDER)}
|
||||
|
||||
{trace?.show && (
|
||||
<Tooltip title="Trace View">
|
||||
<Button
|
||||
disabled={trace.disabled}
|
||||
className={cx(
|
||||
'trace-view-tab',
|
||||
'explorer-view-option',
|
||||
selectedView === trace.key ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(trace.key)}
|
||||
>
|
||||
<SquareMousePointer size={14} data-testid="trace-view" />
|
||||
Trace View
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{timeseries?.show && (
|
||||
<Tooltip title="Time Series">
|
||||
<Button
|
||||
disabled={timeseries.disabled}
|
||||
className={cx(
|
||||
'timeseries-view-tab',
|
||||
'explorer-view-option',
|
||||
selectedView === timeseries.key ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(timeseries.key)}
|
||||
>
|
||||
<Atom size={14} data-testid="query-builder-view" />
|
||||
Time Series
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{clickhouse?.show && (
|
||||
<Tooltip title="Clickhouse">
|
||||
<Button
|
||||
disabled={clickhouse.disabled}
|
||||
className={cx(
|
||||
SELECTED_VIEWS.CLICKHOUSE,
|
||||
actionBtn,
|
||||
selectedView === SELECTED_VIEWS.CLICKHOUSE ? activeTab : '',
|
||||
'clickhouse-view-tab',
|
||||
'explorer-view-option',
|
||||
selectedView === clickhouse.key ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(SELECTED_VIEWS.CLICKHOUSE)}
|
||||
onClick={(): void => onChangeSelectedView(clickhouse.key)}
|
||||
>
|
||||
<Terminal size={14} data-testid="clickhouse-view" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Tooltip title="Query Builder V2">
|
||||
<Button
|
||||
disabled={QB.disabled}
|
||||
className={cx(
|
||||
queryBuilderV2,
|
||||
actionBtn,
|
||||
selectedView === queryBuilderV2 ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void =>
|
||||
onChangeSelectedView(SELECTED_VIEWS.QUERY_BUILDER_V2)
|
||||
}
|
||||
>
|
||||
<Binoculars size={14} data-testid="query-builder-view-v2" />
|
||||
Clickhouse
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="frequency-chart-view-controller">
|
||||
<Typography>Frequency chart</Typography>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={showFrequencyChart}
|
||||
defaultChecked
|
||||
onChange={onToggleHistrogramVisibility}
|
||||
/>
|
||||
{table?.show && (
|
||||
<Tooltip title="Table">
|
||||
<Button
|
||||
disabled={table.disabled}
|
||||
className={cx(
|
||||
'table-view-tab',
|
||||
'explorer-view-option',
|
||||
selectedView === table.key ? activeTab : '',
|
||||
)}
|
||||
onClick={(): void => onChangeSelectedView(table.key)}
|
||||
>
|
||||
<Binoculars size={14} data-testid="query-builder-view-v2" />
|
||||
Table
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -25,14 +25,16 @@
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
.explorer-view-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
border: none;
|
||||
padding: 9px;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
gap: 8px;
|
||||
|
||||
&.active-tab {
|
||||
background-color: var(--bg-slate-400);
|
||||
@ -43,9 +45,6 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
.action-btn + .action-btn {
|
||||
border-left: 1px solid var(--bg-slate-400);
|
||||
}
|
||||
}
|
||||
|
||||
.frequency-chart-view-controller {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { SELECTED_VIEWS } from 'pages/LogsExplorer/utils';
|
||||
import { ExplorerViews } from 'pages/LogsExplorer/utils';
|
||||
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
|
||||
|
||||
import LeftToolbarActions from '../LeftToolbarActions';
|
||||
@ -9,7 +9,6 @@ import RightToolbarActions from '../RightToolbarActions';
|
||||
describe('ToolbarActions', () => {
|
||||
it('LeftToolbarActions - renders correctly with default props', async () => {
|
||||
const handleChangeSelectedView = jest.fn();
|
||||
const handleToggleShowFrequencyChart = jest.fn();
|
||||
const { queryByTestId } = render(
|
||||
<LeftToolbarActions
|
||||
items={{
|
||||
@ -31,10 +30,8 @@ describe('ToolbarActions', () => {
|
||||
disabled: false,
|
||||
},
|
||||
}}
|
||||
selectedView={SELECTED_VIEWS.SEARCH}
|
||||
selectedView={ExplorerViews.LIST}
|
||||
onChangeSelectedView={handleChangeSelectedView}
|
||||
onToggleHistrogramVisibility={handleToggleShowFrequencyChart}
|
||||
showFrequencyChart
|
||||
showFilter
|
||||
handleFilterVisibilityChange={(): void => {}}
|
||||
/>,
|
||||
@ -77,10 +74,8 @@ describe('ToolbarActions', () => {
|
||||
show: true,
|
||||
},
|
||||
}}
|
||||
selectedView={SELECTED_VIEWS.QUERY_BUILDER}
|
||||
selectedView={ExplorerViews.TIMESERIES}
|
||||
onChangeSelectedView={handleChangeSelectedView}
|
||||
onToggleHistrogramVisibility={handleToggleShowFrequencyChart}
|
||||
showFrequencyChart
|
||||
showFilter
|
||||
handleFilterVisibilityChange={(): void => {}}
|
||||
/>,
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
.time-series-view {
|
||||
height: 50vh;
|
||||
min-height: 350px;
|
||||
padding: 0px 12px;
|
||||
|
||||
.ant-card-body {
|
||||
height: 50vh;
|
||||
min-height: 350px;
|
||||
padding: 0px 12px;
|
||||
}
|
||||
}
|
||||
@ -33,8 +33,6 @@ import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import uPlot from 'uplot';
|
||||
import { getTimeRange } from 'utils/getTimeRange';
|
||||
|
||||
import { Container } from './styles';
|
||||
|
||||
function TimeSeriesView({
|
||||
data,
|
||||
isLoading,
|
||||
@ -162,7 +160,7 @@ function TimeSeriesView({
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="time-series-view">
|
||||
{isError && <LogsError />}
|
||||
<div
|
||||
className="graph-container"
|
||||
@ -204,7 +202,7 @@ function TimeSeriesView({
|
||||
!isEmpty(chartData?.[0]) &&
|
||||
chartOptions && <Uplot data={chartData} options={chartOptions} />}
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import './TimeSeriesView.styles.scss';
|
||||
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
.trace-explorer-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
import './ListView.styles.scss';
|
||||
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { ENTITY_VERSION_V4 } from 'constants/app';
|
||||
@ -167,12 +169,14 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
return (
|
||||
<Container>
|
||||
{transformedQueryTableData.length !== 0 && (
|
||||
<div className="trace-explorer-controls">
|
||||
<TraceExplorerControls
|
||||
isLoading={isFetching}
|
||||
totalCount={totalCount}
|
||||
config={config}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isError && <ErrorText>{data?.error || 'Something went wrong'}</ErrorText>}
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
import { Button } from 'antd';
|
||||
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 { QueryBuilder } from 'container/QueryBuilder';
|
||||
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 { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { ButtonWrapper, Container } from './styles';
|
||||
import { Container } from './styles';
|
||||
|
||||
function QuerySection(): JSX.Element {
|
||||
const { handleRunQuery } = useQueryBuilder();
|
||||
function QuerySection({
|
||||
selectedView,
|
||||
}: {
|
||||
selectedView: PANEL_TYPES;
|
||||
}): JSX.Element {
|
||||
// const { currentQuery } = useQueryBuilder();
|
||||
|
||||
// const queryName = currentQuery?.builder?.queryData[0]?.queryName || '';
|
||||
|
||||
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
|
||||
|
||||
@ -43,25 +50,30 @@ function QuerySection(): JSX.Element {
|
||||
};
|
||||
}, [panelTypes, renderOrderBy]);
|
||||
|
||||
console.log('query - section - selectedView', selectedView);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<QueryBuilder
|
||||
panelType={panelTypes}
|
||||
config={{
|
||||
queryVariant: 'static',
|
||||
initialDataSource: DataSource.TRACES,
|
||||
}}
|
||||
filterConfigs={filterConfigs}
|
||||
{/* {(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}
|
||||
version="v3" // setting this to v3 as we this is rendered in logs explorer
|
||||
actions={
|
||||
<ButtonWrapper>
|
||||
<Button onClick={(): void => handleRunQuery()} type="primary">
|
||||
Run Query
|
||||
</Button>
|
||||
</ButtonWrapper>
|
||||
}
|
||||
/>
|
||||
{/* )} */}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@ -58,6 +58,8 @@ export const useHandleExplorerTabChange = (): {
|
||||
currentQueryData?: ICurrentQueryData,
|
||||
redirectToUrl?: typeof ROUTES[keyof typeof ROUTES],
|
||||
) => {
|
||||
console.log('type', type);
|
||||
|
||||
const newPanelType = type as PANEL_TYPES;
|
||||
|
||||
if (newPanelType === panelType && !currentQueryData) return;
|
||||
|
||||
@ -8,8 +8,9 @@ import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
|
||||
import QuickFilters from 'components/QuickFilters/QuickFilters';
|
||||
import { QuickFiltersSource, SignalType } from 'components/QuickFilters/types';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import LogExplorerQuerySection from 'container/LogExplorerQuerySection';
|
||||
import LogsExplorerViews from 'container/LogsExplorerViews';
|
||||
import LogsExplorerViewsContainer from 'container/LogsExplorerViews';
|
||||
import {
|
||||
defaultLogsSelectedColumns,
|
||||
defaultOptionsQuery,
|
||||
@ -20,6 +21,7 @@ import LeftToolbarActions from 'container/QueryBuilder/components/ToolbarActions
|
||||
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
|
||||
import Toolbar from 'container/Toolbar/Toolbar';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { isEqual, isNull } from 'lodash-es';
|
||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||
@ -28,13 +30,11 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { WrapperStyled } from './styles';
|
||||
import { SELECTED_VIEWS } from './utils';
|
||||
import { ExplorerViews } from './utils';
|
||||
|
||||
function LogsExplorer(): JSX.Element {
|
||||
const [showFrequencyChart, setShowFrequencyChart] = useState(true);
|
||||
const [selectedView, setSelectedView] = useState<SELECTED_VIEWS>(
|
||||
SELECTED_VIEWS.QUERY_BUILDER_V2,
|
||||
const [selectedView, setSelectedView] = useState<ExplorerViews>(
|
||||
ExplorerViews.LIST,
|
||||
);
|
||||
const { preferences, loading: preferencesLoading } = usePreferenceContext();
|
||||
|
||||
@ -48,7 +48,9 @@ function LogsExplorer(): JSX.Element {
|
||||
return true;
|
||||
});
|
||||
|
||||
const { handleRunQuery, currentQuery } = useQueryBuilder();
|
||||
const { handleRunQuery, handleSetConfig } = useQueryBuilder();
|
||||
|
||||
const { handleExplorerTabChange } = useHandleExplorerTabChange();
|
||||
|
||||
const listQueryKeyRef = useRef<any>();
|
||||
|
||||
@ -56,13 +58,19 @@ function LogsExplorer(): JSX.Element {
|
||||
|
||||
const [isLoadingQueries, setIsLoadingQueries] = useState<boolean>(false);
|
||||
|
||||
const handleToggleShowFrequencyChart = (): void => {
|
||||
setShowFrequencyChart(!showFrequencyChart);
|
||||
};
|
||||
const handleChangeSelectedView = useCallback(
|
||||
(view: ExplorerViews): void => {
|
||||
if (selectedView === ExplorerViews.LIST) {
|
||||
handleSetConfig(PANEL_TYPES.LIST, DataSource.LOGS);
|
||||
}
|
||||
|
||||
const handleChangeSelectedView = (view: SELECTED_VIEWS): void => {
|
||||
setSelectedView(view);
|
||||
};
|
||||
handleExplorerTabChange(
|
||||
view === ExplorerViews.TIMESERIES ? PANEL_TYPES.TIME_SERIES : view,
|
||||
);
|
||||
},
|
||||
[handleSetConfig, handleExplorerTabChange, selectedView],
|
||||
);
|
||||
|
||||
const handleFilterVisibilityChange = (): void => {
|
||||
setLocalStorageApi(
|
||||
@ -72,19 +80,6 @@ function LogsExplorer(): JSX.Element {
|
||||
setShowFilters((prev) => !prev);
|
||||
};
|
||||
|
||||
// Switch to query builder view if there are more than 1 queries
|
||||
useEffect(() => {
|
||||
if (currentQuery.builder.queryData.length > 1) {
|
||||
handleChangeSelectedView(SELECTED_VIEWS.QUERY_BUILDER_V2);
|
||||
}
|
||||
if (
|
||||
currentQuery.builder.queryData.length === 1 &&
|
||||
currentQuery.builder.queryData?.[0]?.groupBy?.length > 0
|
||||
) {
|
||||
handleChangeSelectedView(SELECTED_VIEWS.QUERY_BUILDER_V2);
|
||||
}
|
||||
}, [currentQuery.builder.queryData, currentQuery.builder.queryData.length]);
|
||||
|
||||
const {
|
||||
redirectWithQuery: redirectWithOptionsData,
|
||||
} = useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
|
||||
@ -195,42 +190,44 @@ function LogsExplorer(): JSX.Element {
|
||||
preferencesLoading,
|
||||
]);
|
||||
|
||||
const isMultipleQueries = useMemo(
|
||||
() =>
|
||||
currentQuery.builder.queryData?.length > 1 ||
|
||||
currentQuery.builder.queryFormulas?.length > 0,
|
||||
[currentQuery],
|
||||
);
|
||||
|
||||
const isGroupByPresent = useMemo(
|
||||
() =>
|
||||
currentQuery.builder.queryData?.length === 1 &&
|
||||
currentQuery.builder.queryData?.[0]?.groupBy?.length > 0,
|
||||
[currentQuery.builder.queryData],
|
||||
);
|
||||
|
||||
const toolbarViews = useMemo(
|
||||
() => ({
|
||||
search: {
|
||||
name: 'search',
|
||||
label: 'Search',
|
||||
disabled: isMultipleQueries || isGroupByPresent,
|
||||
list: {
|
||||
name: 'list',
|
||||
label: 'List',
|
||||
show: true,
|
||||
key: 'list',
|
||||
},
|
||||
queryBuilder: {
|
||||
name: 'query-builder',
|
||||
label: 'Query Builder',
|
||||
timeseries: {
|
||||
name: 'timeseries',
|
||||
label: 'Timeseries',
|
||||
disabled: false,
|
||||
show: true,
|
||||
key: 'timeseries',
|
||||
},
|
||||
trace: {
|
||||
name: 'trace',
|
||||
label: 'Trace',
|
||||
disabled: false,
|
||||
show: false,
|
||||
key: 'trace',
|
||||
},
|
||||
table: {
|
||||
name: 'table',
|
||||
label: 'Table',
|
||||
disabled: false,
|
||||
show: true,
|
||||
key: 'table',
|
||||
},
|
||||
clickhouse: {
|
||||
name: 'clickhouse',
|
||||
label: 'Clickhouse',
|
||||
disabled: false,
|
||||
show: false,
|
||||
key: 'clickhouse',
|
||||
},
|
||||
}),
|
||||
[isGroupByPresent, isMultipleQueries],
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -256,8 +253,6 @@ function LogsExplorer(): JSX.Element {
|
||||
items={toolbarViews}
|
||||
selectedView={selectedView}
|
||||
onChangeSelectedView={handleChangeSelectedView}
|
||||
onToggleHistrogramVisibility={handleToggleShowFrequencyChart}
|
||||
showFrequencyChart={showFrequencyChart}
|
||||
/>
|
||||
}
|
||||
rightActions={
|
||||
@ -271,7 +266,6 @@ function LogsExplorer(): JSX.Element {
|
||||
showOldCTA
|
||||
/>
|
||||
|
||||
<WrapperStyled>
|
||||
<div className="log-explorer-query-container">
|
||||
<div>
|
||||
<ExplorerCard sourcepage={DataSource.LOGS}>
|
||||
@ -279,16 +273,14 @@ function LogsExplorer(): JSX.Element {
|
||||
</ExplorerCard>
|
||||
</div>
|
||||
<div className="logs-explorer-views">
|
||||
<LogsExplorerViews
|
||||
<LogsExplorerViewsContainer
|
||||
selectedView={selectedView}
|
||||
showFrequencyChart={showFrequencyChart}
|
||||
listQueryKeyRef={listQueryKeyRef}
|
||||
chartQueryKeyRef={chartQueryKeyRef}
|
||||
setIsLoadingQueries={setIsLoadingQueries}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</WrapperStyled>
|
||||
</section>
|
||||
</div>
|
||||
</Sentry.ErrorBoundary>
|
||||
|
||||
@ -17,11 +17,12 @@ export const prepareQueryWithDefaultTimestamp = (query: Query): Query => ({
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export enum SELECTED_VIEWS {
|
||||
SEARCH = 'search',
|
||||
QUERY_BUILDER = 'query-builder',
|
||||
export enum ExplorerViews {
|
||||
LIST = 'list',
|
||||
TIMESERIES = 'timeseries',
|
||||
TRACE = 'trace',
|
||||
TABLE = 'table',
|
||||
CLICKHOUSE = 'clickhouse',
|
||||
QUERY_BUILDER_V2 = 'query-builder-v2',
|
||||
}
|
||||
|
||||
export const LogsQuickFiltersConfig: IQuickFiltersConfig[] = [
|
||||
|
||||
@ -8,11 +8,11 @@
|
||||
.ant-collapse-header-text {
|
||||
color: var(--bg-vanilla-400);
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.07px;
|
||||
line-height: 16px;
|
||||
letter-spacing: -0.065px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
@ -24,11 +24,11 @@
|
||||
.ant-input-group-addon {
|
||||
color: var(--bg-vanilla-400);
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.48px;
|
||||
letter-spacing: 0.44px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
@ -37,11 +37,11 @@
|
||||
|
||||
color: var(--bg-vanilla-400);
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.48px;
|
||||
letter-spacing: 0.44px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,8 @@
|
||||
}
|
||||
|
||||
.filter-header {
|
||||
padding: 16px 8px 16px 12px;
|
||||
padding: 4px 8px;
|
||||
|
||||
.filter-title {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
.trace-explorer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-left: 8px;
|
||||
|
||||
.trace-explorer-run-query {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
@ -27,17 +22,54 @@
|
||||
}
|
||||
|
||||
.traces-explorer-views {
|
||||
padding: 8px;
|
||||
|
||||
.ant-tabs-tabpane {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.qb-search-view-container {
|
||||
padding: 8px;
|
||||
border: 1px solid var(--Slate-400, #1d212d) !important;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.ant-select-selector {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--Slate-400, #1d212d) !important;
|
||||
background: var(--Ink-300, #16181d) !important;
|
||||
height: 34px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
}
|
||||
|
||||
.trace-explorer-list-view {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.trace-explorer-traces-view {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.trace-explorer-table-view {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.trace-explorer-time-series-view {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.trace-explorer-page {
|
||||
display: flex;
|
||||
|
||||
.filter {
|
||||
width: 260px;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
|
||||
border-right: 0px;
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import './TracesExplorer.styles.scss';
|
||||
|
||||
import { FilterOutlined } from '@ant-design/icons';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Button, Card, Tabs, Tooltip } from 'antd';
|
||||
import { Card } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import cx from 'classnames';
|
||||
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
|
||||
import QueryBuilderV2 from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import QuickFilters from 'components/QuickFilters/QuickFilters';
|
||||
import { QuickFiltersSource, SignalType } from 'components/QuickFilters/types';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
@ -15,10 +13,16 @@ import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import ExplorerOptionWrapper from 'container/ExplorerOptions/ExplorerOptionWrapper';
|
||||
import ExportPanel from 'container/ExportPanel';
|
||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||
import LeftToolbarActions from 'container/QueryBuilder/components/ToolbarActions/LeftToolbarActions';
|
||||
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
|
||||
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||
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';
|
||||
@ -35,9 +39,6 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToDashboardLink';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ActionsWrapper, Container } from './styles';
|
||||
import { getTabsItems } from './utils';
|
||||
|
||||
function TracesExplorer(): JSX.Element {
|
||||
const {
|
||||
currentQuery,
|
||||
@ -57,12 +58,11 @@ function TracesExplorer(): JSX.Element {
|
||||
});
|
||||
|
||||
const currentPanelType = useGetPanelTypesQueryParam();
|
||||
const currentTab = panelType || PANEL_TYPES.LIST;
|
||||
|
||||
const { handleExplorerTabChange } = useHandleExplorerTabChange();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
|
||||
const currentTab = panelType || PANEL_TYPES.LIST;
|
||||
|
||||
const listQuery = useMemo(() => {
|
||||
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
|
||||
|
||||
@ -106,11 +106,6 @@ function TracesExplorer(): JSX.Element {
|
||||
};
|
||||
}, [updateAllQueriesOperators]);
|
||||
|
||||
const tabsItems = getTabsItems({
|
||||
isListViewDisabled: isMultipleQueries || isGroupByExist,
|
||||
isFilterApplied: !isEmpty(listQuery?.filters.items),
|
||||
});
|
||||
|
||||
const exportDefaultQuery = useMemo(
|
||||
() =>
|
||||
updateAllQueriesOperators(
|
||||
@ -184,8 +179,10 @@ function TracesExplorer(): JSX.Element {
|
||||
handleExplorerTabChange,
|
||||
currentPanelType,
|
||||
]);
|
||||
|
||||
const [isOpen, setOpen] = useState<boolean>(true);
|
||||
const logEventCalledRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!logEventCalledRef.current) {
|
||||
logEvent('Traces Explorer: Page visited', {});
|
||||
@ -193,6 +190,50 @@ function TracesExplorer(): JSX.Element {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toolbarViews = useMemo(
|
||||
() => ({
|
||||
list: {
|
||||
name: 'list',
|
||||
label: 'List',
|
||||
show: true,
|
||||
key: 'list',
|
||||
},
|
||||
timeseries: {
|
||||
name: 'timeseries',
|
||||
label: 'Timeseries',
|
||||
disabled: false,
|
||||
show: true,
|
||||
key: 'timeseries',
|
||||
},
|
||||
trace: {
|
||||
name: 'trace',
|
||||
label: 'Trace',
|
||||
disabled: false,
|
||||
show: true,
|
||||
key: 'trace',
|
||||
},
|
||||
table: {
|
||||
name: 'table',
|
||||
label: 'Table',
|
||||
disabled: false,
|
||||
show: true,
|
||||
key: 'table',
|
||||
},
|
||||
clickhouse: {
|
||||
name: 'clickhouse',
|
||||
label: 'Clickhouse',
|
||||
disabled: false,
|
||||
show: false,
|
||||
key: 'clickhouse',
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const isFilterApplied = useMemo(() => !isEmpty(listQuery?.filters.items), [
|
||||
listQuery,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Sentry.ErrorBoundary fallback={<ErrorBoundaryFallback />}>
|
||||
<div className="trace-explorer-page">
|
||||
@ -206,55 +247,87 @@ function TracesExplorer(): JSX.Element {
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card
|
||||
<div
|
||||
className={cx('trace-explorer', {
|
||||
'filters-expanded': isOpen,
|
||||
})}
|
||||
>
|
||||
<div className={`trace-explorer-header ${isOpen ? 'single-child' : ''}`}>
|
||||
{!isOpen && (
|
||||
<Tooltip title="Expand filters" placement="right">
|
||||
<Button
|
||||
onClick={(): void => setOpen(!isOpen)}
|
||||
className="filter-outlined-btn"
|
||||
data-testid="filter-uncollapse-btn"
|
||||
>
|
||||
<FilterOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<div className="trace-explorer-run-query">
|
||||
<RightToolbarActions onStageRunQuery={handleRunQuery} />
|
||||
<DateTimeSelector showAutoRefresh />
|
||||
</div>
|
||||
<div className="trace-explorer-header">
|
||||
<Toolbar
|
||||
showAutoRefresh
|
||||
leftActions={
|
||||
<LeftToolbarActions
|
||||
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);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
rightActions={<RightToolbarActions onStageRunQuery={handleRunQuery} />}
|
||||
// showOldCTA={false}
|
||||
/>
|
||||
</div>
|
||||
<ExplorerCard sourcepage={DataSource.TRACES}>
|
||||
{/* <QuerySection /> */}
|
||||
<QueryBuilderV2
|
||||
source={DataSource.TRACES}
|
||||
query={currentQuery.builder.queryData[0]}
|
||||
/>
|
||||
<div className="query-section-container">
|
||||
<QuerySection selectedView={currentTab} />
|
||||
</div>
|
||||
</ExplorerCard>
|
||||
|
||||
<Container className="traces-explorer-views">
|
||||
<ActionsWrapper>
|
||||
<ExportPanel query={exportDefaultQuery} onExport={handleExport} />
|
||||
</ActionsWrapper>
|
||||
|
||||
<Tabs
|
||||
defaultActiveKey={currentTab}
|
||||
activeKey={currentTab}
|
||||
items={tabsItems}
|
||||
onChange={handleExplorerTabChange}
|
||||
<div className="traces-explorer-views">
|
||||
<div className="traces-explorer-export-panel">
|
||||
<ExportPanel
|
||||
query={exportDefaultQuery}
|
||||
isLoading={false}
|
||||
onExport={handleExport}
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
{currentTab === PANEL_TYPES.LIST && (
|
||||
<div className="trace-explorer-list-view">
|
||||
<ListView isFilterApplied={isFilterApplied} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TRACE && (
|
||||
<div className="trace-explorer-traces-view">
|
||||
<TracesView isFilterApplied={isFilterApplied} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TIME_SERIES && (
|
||||
<div className="trace-explorer-time-series-view">
|
||||
<TimeSeriesView
|
||||
dataSource={DataSource.TRACES}
|
||||
isFilterApplied={isFilterApplied}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === PANEL_TYPES.TABLE && (
|
||||
<div className="trace-explorer-table-view">
|
||||
<TableView />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ExplorerOptionWrapper
|
||||
disabled={!stagedQuery}
|
||||
query={exportDefaultQuery}
|
||||
sourcepage={DataSource.TRACES}
|
||||
onExport={handleExport}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</Sentry.ErrorBoundary>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user