(feature)(webapp) add show case and support multiple selection and deletion of filter conditions (#251)

This commit is contained in:
williamhliu
2023-10-18 09:56:35 +08:00
committed by GitHub
parent 8d81f63e08
commit 36052cb4f2
36 changed files with 492 additions and 134 deletions

View File

@@ -28,11 +28,7 @@ const MetricCard: React.FC<Props> = ({ data, loading, onApplyAuth }) => {
const prefixCls = `${PREFIX_CLS}-metric-card`;
const matricCardClass = classNames(prefixCls, {
[`${PREFIX_CLS}-metric-card-dsl`]: queryMode === 'DSL',
});
const indicatorClass = classNames(`${prefixCls}-indicator`, {
[`${prefixCls}-indicator-period-compare`]: metricInfos?.length > 0,
[`${PREFIX_CLS}-metric-card-dsl`]: queryMode === 'LLM_S2QL',
});
const [isNumber, setIsNumber] = useState(false);
@@ -50,7 +46,7 @@ const MetricCard: React.FC<Props> = ({ data, loading, onApplyAuth }) => {
)}
</div>
<Spin spinning={loading}>
<div className={indicatorClass}>
<div className={`${prefixCls}-indicator`}>
{indicatorColumn && !indicatorColumn?.authorized ? (
<ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />
) : (

View File

@@ -55,12 +55,8 @@
&-indicator {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
&-indicator-period-compare {
align-items: flex-start;
justify-content: flex-start;
}
&-date-range {
@@ -90,6 +86,7 @@
column-gap: 40px;
font-size: 13px;
overflow-x: auto;
margin-bottom: 12px;
}
&-period-compare-item {

View File

@@ -13,6 +13,7 @@ import moment from 'moment';
import { ColumnType } from '../../../common/type';
import NoPermissionChart from '../NoPermissionChart';
import classNames from 'classnames';
import { isArray } from 'lodash';
type Props = {
model?: string;
@@ -83,7 +84,9 @@ const MetricTrendChart: React.FC<Props> = ({
});
const xData = groupData[sortedGroupKeys[0]]?.map((item: any) => {
const date = `${item[dateColumnName]}`;
const date = isArray(item[dateColumnName])
? item[dateColumnName].join('-')
: `${item[dateColumnName]}`;
return date.length === 10 ? moment(date).format('MM-DD') : date;
});

View File

@@ -0,0 +1,148 @@
import { CHART_SECONDARY_COLOR, CLS_PREFIX, THEME_COLOR_LIST } from '../../../common/constants';
import { getFormattedValue } from '../../../utils/utils';
import type { ECharts } from 'echarts';
import * as echarts from 'echarts';
import React, { useEffect, useRef, useState } from 'react';
import moment from 'moment';
import { ColumnType } from '../../../common/type';
import { isArray } from 'lodash';
type Props = {
dateColumnName: string;
metricFields: ColumnType[];
resultList: any[];
triggerResize?: boolean;
};
const MultiMetricsTrendChart: React.FC<Props> = ({
dateColumnName,
metricFields,
resultList,
triggerResize,
}) => {
const chartRef = useRef<any>();
const [instance, setInstance] = useState<ECharts>();
const renderChart = () => {
let instanceObj: any;
if (!instance) {
instanceObj = echarts.init(chartRef.current);
setInstance(instanceObj);
} else {
instanceObj = instance;
instanceObj.clear();
}
const xData = resultList?.map((item: any) => {
const date = isArray(item[dateColumnName])
? item[dateColumnName].join('-')
: `${item[dateColumnName]}`;
return date.length === 10 ? moment(date).format('MM-DD') : date;
});
instanceObj.setOption({
legend: {
left: 0,
top: 0,
icon: 'rect',
itemWidth: 15,
itemHeight: 5,
type: 'scroll',
},
xAxis: {
type: 'category',
axisTick: {
alignWithLabel: true,
lineStyle: {
color: CHART_SECONDARY_COLOR,
},
},
axisLine: {
lineStyle: {
color: CHART_SECONDARY_COLOR,
},
},
axisLabel: {
showMaxLabel: true,
color: '#999',
},
data: xData,
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
opacity: 0.3,
},
},
axisLabel: {
formatter: function (value: any) {
return value === 0 ? 0 : getFormattedValue(value);
},
},
},
tooltip: {
trigger: 'axis',
formatter: function (params: any[]) {
const param = params[0];
const valueLabels = params
.sort((a, b) => b.value - a.value)
.map(
(item: any) =>
`<div style="margin-top: 3px;">${
item.marker
} <span style="display: inline-block; width: 70px; margin-right: 12px;">${
item.seriesName
}</span><span style="display: inline-block; width: 90px; text-align: right; font-weight: 500;">${
item.value === '' ? '-' : getFormattedValue(item.value)
}</span></div>`
)
.join('');
return `${param.name}<br />${valueLabels}`;
},
},
grid: {
left: '1%',
right: '4%',
bottom: '3%',
top: 45,
containLabel: true,
},
series: metricFields.map((metricField, index) => {
return {
type: 'line',
name: metricField.name,
symbol: 'circle',
showSymbol: resultList.length === 1,
smooth: true,
data: resultList.map((item: any) => {
const value = item[metricField.nameEn];
return (metricField.dataFormatType === 'percent' ||
metricField.dataFormatType === 'decimal') &&
metricField.dataFormat?.needMultiply100
? value * 100
: value;
}),
color: THEME_COLOR_LIST[index],
};
}),
});
instanceObj.resize();
};
useEffect(() => {
renderChart();
}, [resultList]);
useEffect(() => {
if (triggerResize && instance) {
instance.resize();
}
}, [triggerResize]);
const prefixCls = `${CLS_PREFIX}-metric-trend`;
return <div className={`${prefixCls}-flow-trend-chart`} ref={chartRef} />;
};
export default MultiMetricsTrendChart;

View File

@@ -1,11 +1,12 @@
import { CLS_PREFIX } from '../../../common/constants';
import { FieldType, MsgDataType } from '../../../common/type';
import { DrillDownDimensionType, FieldType, MsgDataType } from '../../../common/type';
import { isMobile } from '../../../utils/utils';
import MetricTrendChart from './MetricTrendChart';
import { Spin } from 'antd';
import Table from '../Table';
import MetricInfo from './MetricInfo';
import DateOptions from '../DateOptions';
import MultiMetricsTrendChart from './MultiMetricsTrendChart';
type Props = {
data: MsgDataType;
@@ -13,6 +14,7 @@ type Props = {
triggerResize?: boolean;
loading: boolean;
activeMetricField?: FieldType;
drillDownDimension?: DrillDownDimensionType;
currentDateOption?: number;
onApplyAuth?: (model: string) => void;
onSelectDateOption: (value: number) => void;
@@ -24,6 +26,7 @@ const MetricTrend: React.FC<Props> = ({
triggerResize,
loading,
activeMetricField,
drillDownDimension,
currentDateOption,
onApplyAuth,
onSelectDateOption,
@@ -36,6 +39,7 @@ const MetricTrend: React.FC<Props> = ({
const dateColumnName = dateField?.nameEn || '';
const categoryColumnName =
queryColumns?.find((column: any) => column.showType === 'CATEGORY')?.nameEn || '';
const metricFields = queryColumns?.filter((column: any) => column.showType === 'NUMBER');
const currentMetricField = queryColumns?.find((column: any) => column.showType === 'NUMBER');
@@ -48,19 +52,23 @@ const MetricTrend: React.FC<Props> = ({
return (
<div className={prefixCls}>
<div className={`${prefixCls}-charts`}>
<div className={`${prefixCls}-top-bar`}>
<div
className={`${prefixCls}-metric-fields ${prefixCls}-metric-field-single`}
key={activeMetricField?.bizName}
>
{activeMetricField?.name}
{metricFields?.length === 1 && (
<div className={`${prefixCls}-top-bar`}>
<div
className={`${prefixCls}-metric-fields ${prefixCls}-metric-field-single`}
key={activeMetricField?.bizName}
>
{activeMetricField?.name}
</div>
</div>
</div>
)}
<Spin spinning={loading}>
<div className={`${prefixCls}-content`}>
{!isMobile && aggregateInfo?.metricInfos?.length > 0 && (
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
)}
{!isMobile &&
aggregateInfo?.metricInfos?.length > 0 &&
drillDownDimension === undefined && (
<MetricInfo aggregateInfo={aggregateInfo} currentMetricField={currentMetricField} />
)}
<DateOptions
chatContext={chatContext}
currentDateOption={currentDateOption}
@@ -68,6 +76,13 @@ const MetricTrend: React.FC<Props> = ({
/>
{queryResults?.length === 1 || chartIndex % 2 === 1 ? (
<Table data={{ ...data, queryResults }} onApplyAuth={onApplyAuth} />
) : metricFields.length > 1 ? (
<MultiMetricsTrendChart
dateColumnName={dateColumnName}
metricFields={metricFields}
resultList={queryResults}
triggerResize={triggerResize}
/>
) : (
<MetricTrendChart
model={entityInfo?.modelInfo.name}

View File

@@ -59,11 +59,9 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
const metricFields = columns.filter(item => item.showType === 'NUMBER');
const isDslMetricCard =
queryMode === 'DSL' && singleData && metricFields.length === 1 && columns.length === 1;
queryMode === 'LLM_S2QL' && singleData && metricFields.length === 1 && columns.length === 1;
const isMetricCard =
(queryMode.includes('METRIC') || isDslMetricCard) &&
(singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate);
const isMetricCard = (queryMode.includes('METRIC') || isDslMetricCard) && singleData;
const isText =
columns.length === 1 &&
@@ -95,24 +93,27 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
if (isTable) {
return <Table data={{ ...data, queryColumns: columns, queryResults: dataSource }} />;
}
if (dateField && metricFields.length > 0) {
if (!dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn])) {
return (
<MetricTrend
data={{
...data,
queryColumns: columns,
queryResults: dataSource,
}}
loading={loading}
chartIndex={chartIndex}
triggerResize={triggerResize}
activeMetricField={activeMetricField}
currentDateOption={currentDateOption}
onSelectDateOption={selectDateOption}
/>
);
}
if (
dateField &&
metricFields.length > 0 &&
!dataSource.every(item => item[dateField.nameEn] === dataSource[0][dateField.nameEn])
) {
return (
<MetricTrend
data={{
...data,
queryColumns: columns,
queryResults: dataSource,
}}
loading={loading}
chartIndex={chartIndex}
triggerResize={triggerResize}
activeMetricField={activeMetricField}
drillDownDimension={drillDownDimension}
currentDateOption={currentDateOption}
onSelectDateOption={selectDateOption}
/>
);
}
if (categoryField?.length > 0 && metricFields?.length > 0) {
return (
@@ -209,7 +210,11 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
<div>
{getMsgContent()}
{(isMultipleMetric || existDrillDownDimension) && (
<div className={`${prefixCls}-bottom-tools`}>
<div
className={`${prefixCls}-bottom-tools ${
isMetricCard ? `${prefixCls}-metric-card-tools` : ''
}`}
>
{isMultipleMetric && (
<MetricOptions
metrics={chatContext.metrics}
@@ -221,6 +226,7 @@ const ChatMsg: React.FC<Props> = ({ queryId, data, chartIndex, triggerResize })
{existDrillDownDimension && (
<DrillDownDimensions
modelId={chatContext.modelId}
metricId={activeMetricField?.id || defaultMetricField?.id}
drillDownDimension={drillDownDimension}
originDimensions={chatContext.dimensions}
dimensionFilters={chatContext.dimensionFilters}

View File

@@ -14,5 +14,10 @@
column-gap: 20px;
font-size: 14px;
margin-top: 6px;
margin-bottom: 2px;
}
&-metric-card-tools {
margin-top: 0;
}
}