[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:
tristanliu
2023-07-21 15:30:38 +08:00
committed by GitHub
parent 6492316e23
commit 078a81038f
39 changed files with 1541 additions and 1161 deletions

View File

@@ -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>
</>

View File

@@ -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 }}

View File

@@ -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;
}
}