mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-17 07:32:59 +00:00
[improvement][semantic-fe] Added an editing component to set filtering rules for Q&A. Now, the SQL editor will be accompanied by a list for display and control, to resolve ambiguity when using comma-separated values.
[improvement][semantic-fe] Improved validation logic and prompt copywriting for data source/dimension/metric editing and creation. [improvement][semantic-fe] Improved user experience for visual modeling. Now, when using the legend to control the display/hide of data sources and their associated metric dimensions, the canvas will be re-layout based on the activated data source in the legend. Co-authored-by: tristanliu <tristanliu@tencent.com>
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Modal, message } from 'antd';
|
||||
import { addDomainExtend, editDomainExtend, getDomainExtendDetailConfig } from '../../service';
|
||||
import DimensionMetricVisibleTransfer from './DimensionMetricVisibleTransfer';
|
||||
import { exChangeRichEntityListToIds } from './utils';
|
||||
|
||||
type Props = {
|
||||
domainId: number;
|
||||
themeData: any;
|
||||
settingType: 'dimension' | 'metric';
|
||||
settingSourceList: any[];
|
||||
onCancel: () => void;
|
||||
visible: boolean;
|
||||
onSubmit: (params?: any) => void;
|
||||
};
|
||||
|
||||
const dimensionConfig = {
|
||||
blackIdListKey: 'blackDimIdList',
|
||||
visibleIdListKey: 'whiteDimIdList',
|
||||
modalTitle: '问答可见维度信息',
|
||||
titles: ['不可见维度', '可见维度'],
|
||||
};
|
||||
|
||||
const metricConfig = {
|
||||
blackIdListKey: 'blackMetricIdList',
|
||||
visibleIdListKey: 'whiteMetricIdList',
|
||||
modalTitle: '问答可见指标信息',
|
||||
titles: ['不可见指标', '可见指标'],
|
||||
};
|
||||
|
||||
const DimensionMetricVisibleModal: React.FC<Props> = ({
|
||||
domainId,
|
||||
visible,
|
||||
themeData = {},
|
||||
settingType,
|
||||
settingSourceList,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}) => {
|
||||
const [sourceList, setSourceList] = useState<any[]>([]);
|
||||
const [selectedKeyList, setSelectedKeyList] = useState<string[]>([]);
|
||||
const settingTypeConfig = settingType === 'dimension' ? dimensionConfig : metricConfig;
|
||||
useEffect(() => {
|
||||
const list = settingSourceList.map((item: any) => {
|
||||
const { id, name } = item;
|
||||
return { id, name, type: settingType };
|
||||
});
|
||||
setSourceList(list);
|
||||
}, [settingSourceList]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedKeyList(themeData.visibility?.[settingTypeConfig.visibleIdListKey] || []);
|
||||
}, [themeData]);
|
||||
|
||||
const saveEntity = async () => {
|
||||
const { id, entity } = themeData;
|
||||
let saveDomainExtendQuery = addDomainExtend;
|
||||
if (id) {
|
||||
saveDomainExtendQuery = editDomainExtend;
|
||||
}
|
||||
const blackIdList = settingSourceList.reduce((list, item: any) => {
|
||||
const { id: targetId } = item;
|
||||
if (!selectedKeyList.includes(targetId)) {
|
||||
list.push(targetId);
|
||||
}
|
||||
return list;
|
||||
}, []);
|
||||
const entityParams = exChangeRichEntityListToIds(entity);
|
||||
themeData.entity = entityParams;
|
||||
const params = {
|
||||
...themeData,
|
||||
visibility: themeData.visibility || {},
|
||||
};
|
||||
params.visibility[settingTypeConfig.blackIdListKey] = blackIdList;
|
||||
|
||||
if (!params.visibility.blackDimIdList) {
|
||||
params.visibility.blackDimIdList = [];
|
||||
}
|
||||
if (!params.visibility.blackMetricIdList) {
|
||||
params.visibility.blackMetricIdList = [];
|
||||
}
|
||||
|
||||
const { code, msg } = await saveDomainExtendQuery({
|
||||
...params,
|
||||
id,
|
||||
domainId,
|
||||
});
|
||||
if (code === 200) {
|
||||
onSubmit?.();
|
||||
message.success('保存成功');
|
||||
return;
|
||||
}
|
||||
message.error(msg);
|
||||
};
|
||||
|
||||
const handleTransferChange = (newTargetKeys: string[]) => {
|
||||
setSelectedKeyList(newTargetKeys);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={onCancel}>取消</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
saveEntity();
|
||||
}}
|
||||
>
|
||||
完成
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
width={1200}
|
||||
destroyOnClose
|
||||
title={settingTypeConfig.modalTitle}
|
||||
maskClosable={false}
|
||||
open={visible}
|
||||
footer={renderFooter()}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<DimensionMetricVisibleTransfer
|
||||
titles={settingTypeConfig.titles}
|
||||
sourceList={sourceList}
|
||||
targetList={selectedKeyList}
|
||||
onChange={(newTargetKeys) => {
|
||||
handleTransferChange(newTargetKeys);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DimensionMetricVisibleModal;
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Space, Table, Transfer, Checkbox, Tooltip, Button } from 'antd';
|
||||
import { Table, Transfer, Checkbox, Button } from 'antd';
|
||||
import type { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
|
||||
import type { TransferItem } from 'antd/es/transfer';
|
||||
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
import difference from 'lodash/difference';
|
||||
import React, { useState } from 'react';
|
||||
import type { IChatConfig } from '../../data';
|
||||
import DimensionValueSettingModal from './DimensionValueSettingModal';
|
||||
import TransTypeTag from '../TransTypeTag';
|
||||
import { TransType } from '../../enum';
|
||||
import TableTitleTooltips from '../../components/TableTitleTooltips';
|
||||
|
||||
interface RecordType {
|
||||
id: number;
|
||||
@@ -72,12 +72,10 @@ const DimensionMetricVisibleTableTransfer: React.FC<Props> = ({
|
||||
{
|
||||
dataIndex: 'y',
|
||||
title: (
|
||||
<Space>
|
||||
<span>维度值可见</span>
|
||||
<Tooltip title="勾选可见后,维度值将在搜索时可以被联想出来">
|
||||
<ExclamationCircleOutlined />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
<TableTitleTooltips
|
||||
title="维度值可见"
|
||||
tooltips="勾选可见后,维度值将在搜索时可以被联想出来"
|
||||
/>
|
||||
),
|
||||
width: 120,
|
||||
render: (_, record) => {
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Modal, message, Space } from 'antd';
|
||||
import ProCard from '@ant-design/pro-card';
|
||||
import { addDomainExtend, editDomainExtend } from '../../service';
|
||||
import DimensionMetricVisibleTransfer from './DimensionMetricVisibleTransfer';
|
||||
import SqlEditor from '@/components/SqlEditor';
|
||||
type Props = {
|
||||
domainId: number;
|
||||
themeData: any;
|
||||
settingSourceList: any[];
|
||||
onCancel: () => void;
|
||||
visible: boolean;
|
||||
onSubmit: (params?: any) => void;
|
||||
};
|
||||
|
||||
const DimensionSearchVisibleModal: React.FC<Props> = ({
|
||||
domainId,
|
||||
themeData,
|
||||
visible,
|
||||
settingSourceList,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}) => {
|
||||
const [sourceList, setSourceList] = useState<any[]>([]);
|
||||
const [selectedKeyList, setSelectedKeyList] = useState<string[]>([]);
|
||||
const [dictRules, setDictRules] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
const knowledgeInfos = themeData?.knowledgeInfos;
|
||||
if (Array.isArray(knowledgeInfos)) {
|
||||
const target = knowledgeInfos[0];
|
||||
if (Array.isArray(target?.ruleList)) {
|
||||
setDictRules(target.ruleList[0]);
|
||||
}
|
||||
const selectKeys = knowledgeInfos.map((item: any) => {
|
||||
return item.itemId;
|
||||
});
|
||||
setSelectedKeyList(selectKeys);
|
||||
}
|
||||
}, [themeData]);
|
||||
|
||||
useEffect(() => {
|
||||
const list = settingSourceList.map((item: any) => {
|
||||
const { id, name } = item;
|
||||
return { id, name, type: 'dimension' };
|
||||
});
|
||||
setSourceList(list);
|
||||
}, [settingSourceList]);
|
||||
|
||||
const saveDictBatch = async () => {
|
||||
const knowledgeInfos = selectedKeyList.map((key: string) => {
|
||||
return {
|
||||
itemId: key,
|
||||
type: 'DIMENSION',
|
||||
isDictInfo: true,
|
||||
ruleList: dictRules ? [dictRules] : [],
|
||||
};
|
||||
});
|
||||
const id = themeData?.id;
|
||||
let saveDomainExtendQuery = addDomainExtend;
|
||||
if (id) {
|
||||
saveDomainExtendQuery = editDomainExtend;
|
||||
}
|
||||
const { code, msg } = await saveDomainExtendQuery({
|
||||
knowledgeInfos,
|
||||
domainId,
|
||||
id,
|
||||
});
|
||||
|
||||
if (code === 200) {
|
||||
message.success('保存可见维度值成功');
|
||||
onSubmit?.();
|
||||
return;
|
||||
}
|
||||
message.error(msg);
|
||||
};
|
||||
|
||||
const saveDictSetting = async () => {
|
||||
await saveDictBatch();
|
||||
};
|
||||
|
||||
const handleTransferChange = (newTargetKeys: string[]) => {
|
||||
setSelectedKeyList(newTargetKeys);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={onCancel}>取消</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
saveDictSetting();
|
||||
}}
|
||||
>
|
||||
完成
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
width={1200}
|
||||
destroyOnClose
|
||||
title={'可见维度值设置'}
|
||||
maskClosable={false}
|
||||
open={visible}
|
||||
footer={renderFooter()}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={20}>
|
||||
<ProCard bordered title="可见设置">
|
||||
<DimensionMetricVisibleTransfer
|
||||
titles={['不可见维度值', '可见维度值']}
|
||||
sourceList={sourceList}
|
||||
targetList={selectedKeyList}
|
||||
onChange={(newTargetKeys) => {
|
||||
handleTransferChange(newTargetKeys);
|
||||
}}
|
||||
/>
|
||||
</ProCard>
|
||||
<ProCard bordered title="维度值过滤">
|
||||
<SqlEditor
|
||||
height={'150px'}
|
||||
value={dictRules}
|
||||
onChange={(sql: string) => {
|
||||
setDictRules(sql);
|
||||
}}
|
||||
/>
|
||||
</ProCard>
|
||||
</Space>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DimensionSearchVisibleModal;
|
||||
@@ -5,7 +5,7 @@ import { Form, Input } from 'antd';
|
||||
import { formLayout } from '@/components/FormHelper/utils';
|
||||
import { isString } from 'lodash';
|
||||
import styles from '../style.less';
|
||||
|
||||
import CommonEditList from '../../components/CommonEditList/index';
|
||||
import SqlEditor from '@/components/SqlEditor';
|
||||
type Props = {
|
||||
initialValues: any;
|
||||
@@ -17,7 +17,7 @@ const FormItem = Form.Item;
|
||||
const EntityCreateForm: ForwardRefRenderFunction<any, Props> = ({ initialValues }, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const exchangeFields = ['blackList', 'whiteList', 'ruleList'];
|
||||
const exchangeFields = ['blackList', 'whiteList'];
|
||||
|
||||
const getFormValidateFields = async () => {
|
||||
const fields = await form.validateFields();
|
||||
@@ -69,8 +69,9 @@ const EntityCreateForm: ForwardRefRenderFunction<any, Props> = ({ initialValues
|
||||
<Input placeholder="多个维度值用英文逗号隔开" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem name="ruleList" label="过滤规则">
|
||||
<SqlEditor height={'150px'} />
|
||||
<FormItem name="ruleList">
|
||||
{/* <SqlEditor height={'150px'} /> */}
|
||||
<CommonEditList title="过滤规则" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</>
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react';
|
||||
import type { ForwardRefRenderFunction } from 'react';
|
||||
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
||||
import { formLayout } from '@/components/FormHelper/utils';
|
||||
import { message, Form, Input, Select, Button, InputNumber } from 'antd';
|
||||
import { addDomainExtend, editDomainExtend } from '../../service';
|
||||
|
||||
import styles from '../style.less';
|
||||
type Props = {
|
||||
themeData: any;
|
||||
metricList: any[];
|
||||
domainId: number;
|
||||
onSubmit: (params?: any) => void;
|
||||
};
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
const MetricSettingForm: ForwardRefRenderFunction<any, Props> = (
|
||||
{ metricList, domainId, themeData: uniqueMetricData, onSubmit },
|
||||
ref,
|
||||
) => {
|
||||
const [form] = Form.useForm();
|
||||
const [metricListOptions, setMetricListOptions] = useState<any>([]);
|
||||
const [unitState, setUnit] = useState<number | null>();
|
||||
const [periodState, setPeriod] = useState<string>();
|
||||
const getFormValidateFields = async () => {
|
||||
return await form.validateFields();
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getFormValidateFields,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
form.resetFields();
|
||||
setUnit(null);
|
||||
setPeriod('');
|
||||
if (Object.keys(uniqueMetricData).length === 0) {
|
||||
return;
|
||||
}
|
||||
const { defaultMetrics = [], id } = uniqueMetricData;
|
||||
const defaultMetric = defaultMetrics[0];
|
||||
const recordId = id === -1 ? undefined : id;
|
||||
if (defaultMetric) {
|
||||
const { period, unit } = defaultMetric;
|
||||
setUnit(unit);
|
||||
setPeriod(period);
|
||||
form.setFieldsValue({
|
||||
...defaultMetric,
|
||||
id: recordId,
|
||||
});
|
||||
} else {
|
||||
form.setFieldsValue({
|
||||
id: recordId,
|
||||
});
|
||||
}
|
||||
}, [uniqueMetricData]);
|
||||
|
||||
useEffect(() => {
|
||||
const metricOption = metricList.map((item: any) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
};
|
||||
});
|
||||
setMetricListOptions(metricOption);
|
||||
}, [metricList]);
|
||||
|
||||
const saveEntity = async () => {
|
||||
const values = await form.validateFields();
|
||||
const { id } = values;
|
||||
let saveDomainExtendQuery = addDomainExtend;
|
||||
if (id) {
|
||||
saveDomainExtendQuery = editDomainExtend;
|
||||
}
|
||||
const { code, msg, data } = await saveDomainExtendQuery({
|
||||
defaultMetrics: [{ ...values }],
|
||||
domainId,
|
||||
id,
|
||||
});
|
||||
|
||||
if (code === 200) {
|
||||
form.setFieldValue('id', data);
|
||||
onSubmit?.();
|
||||
message.success('保存成功');
|
||||
return;
|
||||
}
|
||||
message.error(msg);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
{...formLayout}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
className={styles.form}
|
||||
initialValues={{
|
||||
unit: 7,
|
||||
period: 'DAY',
|
||||
}}
|
||||
>
|
||||
<FormItem hidden={true} name="id" label="ID">
|
||||
<Input placeholder="id" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name={'metricId'}
|
||||
label={
|
||||
<FormItemTitle
|
||||
title={'指标'}
|
||||
subTitle={'问答搜索结果选择中,如果没有指定指标,将会采用默认指标进行展示'}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Select
|
||||
allowClear
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
filterOption={(inputValue: string, item: any) => {
|
||||
const { label } = item;
|
||||
if (label.includes(inputValue)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
placeholder="请选择展示指标信息"
|
||||
options={metricListOptions}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label={
|
||||
<FormItemTitle
|
||||
title={'时间范围'}
|
||||
subTitle={'问答搜索结果选择中,如果没有指定时间范围,将会采用默认时间范围'}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Input.Group compact>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
lineHeight: '32px',
|
||||
marginRight: '8px',
|
||||
}}
|
||||
>
|
||||
最近
|
||||
</span>
|
||||
<InputNumber
|
||||
value={unitState}
|
||||
style={{ width: '120px' }}
|
||||
onChange={(value) => {
|
||||
setUnit(value);
|
||||
form.setFieldValue('unit', value);
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
value={periodState}
|
||||
style={{ width: '100px' }}
|
||||
onChange={(value) => {
|
||||
form.setFieldValue('period', value);
|
||||
setPeriod(value);
|
||||
}}
|
||||
>
|
||||
<Option value="DAY">天</Option>
|
||||
<Option value="WEEK">周</Option>
|
||||
<Option value="MONTH">月</Option>
|
||||
<Option value="YEAR">年</Option>
|
||||
</Select>
|
||||
</Input.Group>
|
||||
</FormItem>
|
||||
|
||||
<FormItem name="unit" hidden={true}>
|
||||
<InputNumber />
|
||||
</FormItem>
|
||||
<FormItem name="period" hidden={true}>
|
||||
<Input />
|
||||
</FormItem>
|
||||
|
||||
<FormItem>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
saveEntity();
|
||||
}}
|
||||
>
|
||||
保 存
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default forwardRef(MetricSettingForm);
|
||||
Reference in New Issue
Block a user