mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-18 08:17:18 +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:
@@ -10,6 +10,7 @@ import { createDatasource, updateDatasource, getColumns } from '../../service';
|
||||
import type { Dispatch } from 'umi';
|
||||
import type { StateType } from '../../model';
|
||||
import { connect } from 'umi';
|
||||
import { isUndefined } from 'lodash';
|
||||
|
||||
export type CreateFormProps = {
|
||||
domainManger: StateType;
|
||||
@@ -47,6 +48,7 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
const [fields, setFields] = useState<any[]>([]);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [saveLoading, setSaveLoading] = useState(false);
|
||||
const [hasEmptyNameField, setHasEmptyNameField] = useState<boolean>(false);
|
||||
const formValRef = useRef(initFormVal as any);
|
||||
const [form] = Form.useForm();
|
||||
const { dataBaseConfig } = domainManger;
|
||||
@@ -54,6 +56,17 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
formValRef.current = val;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const hasEmpty = fields.some((item) => {
|
||||
const { name, isCreateDimension, isCreateMetric } = item;
|
||||
if ((isCreateMetric || isCreateDimension) && !name) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
setHasEmptyNameField(hasEmpty);
|
||||
}, [fields]);
|
||||
|
||||
const [fieldColumns, setFieldColumns] = useState(scriptColumns || []);
|
||||
useEffect(() => {
|
||||
if (scriptColumns) {
|
||||
@@ -310,7 +323,12 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
上一步
|
||||
</Button>
|
||||
<Button onClick={onCancel}>取消</Button>
|
||||
<Button type="primary" loading={saveLoading} onClick={handleNext}>
|
||||
<Button
|
||||
type="primary"
|
||||
loading={saveLoading}
|
||||
onClick={handleNext}
|
||||
disabled={hasEmptyNameField}
|
||||
>
|
||||
完成
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Table, Select, Checkbox, Input } from 'antd';
|
||||
import type { FieldItem } from '../data';
|
||||
import { Table, Select, Checkbox, Input, Alert, Space, Tooltip } from 'antd';
|
||||
import TableTitleTooltips from '../../components/TableTitleTooltips';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
import Marquee from 'react-fast-marquee';
|
||||
import { TYPE_OPTIONS, DATE_FORMATTER, AGG_OPTIONS, EnumDataSourceType } from '../constants';
|
||||
import styles from '../style.less';
|
||||
|
||||
type FieldItem = {
|
||||
bizName: string;
|
||||
sqlType: string;
|
||||
name: string;
|
||||
type: EnumDataSourceType;
|
||||
agg?: string;
|
||||
checked?: number;
|
||||
dateFormat?: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
fields: FieldItem[];
|
||||
@@ -11,6 +24,16 @@ type Props = {
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const getCreateFieldName = (type: EnumDataSourceType) => {
|
||||
const isCreateName = [EnumDataSourceType.CATEGORICAL, EnumDataSourceType.TIME].includes(
|
||||
type as EnumDataSourceType,
|
||||
)
|
||||
? 'isCreateDimension'
|
||||
: 'isCreateMetric';
|
||||
return isCreateName;
|
||||
// const editState = !isUndefined(record[isCreateName]) ? !!record[isCreateName] : true;
|
||||
};
|
||||
|
||||
const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
const handleFieldChange = (record: FieldItem, fieldName: string, value: any) => {
|
||||
onFieldChange(record.bizName, {
|
||||
@@ -58,10 +81,14 @@ const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
timeGranularity: undefined,
|
||||
};
|
||||
}
|
||||
const isCreateName = getCreateFieldName(value);
|
||||
const editState = !isUndefined(record[isCreateName]) ? !!record[isCreateName] : true;
|
||||
// handleFieldChange(record, 'type', value);
|
||||
onFieldChange(record.bizName, {
|
||||
...record,
|
||||
type: value,
|
||||
name: '',
|
||||
[isCreateName]: editState,
|
||||
...defaultParams,
|
||||
});
|
||||
}}
|
||||
@@ -105,28 +132,38 @@ const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
if (type === EnumDataSourceType.TIME) {
|
||||
const dateFormat = fields.find((field) => field.bizName === record.bizName)?.dateFormat;
|
||||
return (
|
||||
<Select
|
||||
placeholder="时间格式"
|
||||
value={dateFormat}
|
||||
onChange={(value) => {
|
||||
handleFieldChange(record, 'dateFormat', value);
|
||||
}}
|
||||
defaultValue={DATE_FORMATTER[0]}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{DATE_FORMATTER.map((item) => (
|
||||
<Option key={item} value={item}>
|
||||
{item}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
<Space>
|
||||
<Select
|
||||
placeholder="时间格式"
|
||||
value={dateFormat}
|
||||
onChange={(value) => {
|
||||
handleFieldChange(record, 'dateFormat', value);
|
||||
}}
|
||||
defaultValue={DATE_FORMATTER[0]}
|
||||
style={{ minWidth: 180 }}
|
||||
>
|
||||
{DATE_FORMATTER.map((item) => (
|
||||
<Option key={item} value={item}>
|
||||
{item}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
<Tooltip title="请选择数据库中时间字段对应格式">
|
||||
<ExclamationCircleOutlined />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '快速创建',
|
||||
title: (
|
||||
<TableTitleTooltips
|
||||
title="快速创建"
|
||||
tooltips="若勾选快速创建并填写名称,将会把该维度/指标直接创建到维度/指标列表"
|
||||
/>
|
||||
),
|
||||
dataIndex: 'fastCreate',
|
||||
width: 100,
|
||||
render: (_: any, record: FieldItem) => {
|
||||
@@ -140,11 +177,7 @@ const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
EnumDataSourceType.MEASURES,
|
||||
].includes(type as EnumDataSourceType)
|
||||
) {
|
||||
const isCreateName = [EnumDataSourceType.CATEGORICAL, EnumDataSourceType.TIME].includes(
|
||||
type as EnumDataSourceType,
|
||||
)
|
||||
? 'isCreateDimension'
|
||||
: 'isCreateMetric';
|
||||
const isCreateName = getCreateFieldName(type);
|
||||
const editState = !isUndefined(record[isCreateName]) ? !!record[isCreateName] : true;
|
||||
return (
|
||||
<Checkbox
|
||||
@@ -155,14 +188,21 @@ const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
onFieldChange(record.bizName, {
|
||||
...record,
|
||||
name: '',
|
||||
checked: value,
|
||||
[isCreateName]: value,
|
||||
});
|
||||
} else {
|
||||
handleFieldChange(record, isCreateName, value);
|
||||
// handleFieldChange(record, isCreateName, value);
|
||||
onFieldChange(record.bizName, {
|
||||
...record,
|
||||
checked: value,
|
||||
[isCreateName]: value,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
className={!name && styles.dataSourceFieldsName}
|
||||
value={name}
|
||||
disabled={!editState}
|
||||
onChange={(e) => {
|
||||
@@ -186,10 +226,18 @@ const FieldForm: React.FC<Props> = ({ fields, onFieldChange }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Alert
|
||||
style={{ marginBottom: '10px' }}
|
||||
banner
|
||||
message={
|
||||
<Marquee pauseOnHover gradient={false}>
|
||||
为了保障同一个主题域下维度/指标列表唯一,消除歧义,若本主题域下的多个数据源存在相同的字段名并且都勾选了快速创建,系统默认这些相同字段的指标维度是同一个,同时列表中将只显示最后一次创建的指标/维度。
|
||||
</Marquee>
|
||||
}
|
||||
/>
|
||||
<Table<FieldItem>
|
||||
dataSource={fields}
|
||||
columns={columns}
|
||||
className="fields-table"
|
||||
rowKey="bizName"
|
||||
pagination={false}
|
||||
scroll={{ y: 500 }}
|
||||
|
||||
@@ -757,3 +757,17 @@
|
||||
height: 16px !important;
|
||||
margin: 0 3px 4px;
|
||||
}
|
||||
|
||||
.dataSourceFieldsName {
|
||||
background: #fff;
|
||||
border-color: #ff4d4f;
|
||||
&:hover {
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
&:focus {
|
||||
border-color: #ff7875;
|
||||
box-shadow: 0 0 0 2px #ff4d4f33;
|
||||
border-right-width: 1px;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user