mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-21 06:04:19 +08:00
[improvement][headless-fe] Revamped the interaction for semantic modeling routing and successfully implemented the switching between dimension and dataset management. (#1934)
Co-authored-by: tristanliu <tristanliu@tencent.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import styles from '../../components/style.less';
|
||||
import { ISemantic } from '../../data';
|
||||
import { ColumnsConfig } from '../../components/TableColumnRender';
|
||||
import ViewSearchFormModal from './ViewSearchFormModal';
|
||||
import { toDatasetEditPage } from '@/pages/SemanticModel/utils';
|
||||
|
||||
type Props = {
|
||||
// dataSetList: ISemantic.IDatasetItem[];
|
||||
@@ -90,9 +91,10 @@ const DataSetTable: React.FC<Props> = ({ disabledEdit = false }) => {
|
||||
return (
|
||||
<a
|
||||
onClick={() => {
|
||||
setEditFormStep(1);
|
||||
setViewItem(record);
|
||||
setCreateDataSourceModalOpen(true);
|
||||
toDatasetEditPage(record.domainId, record.id, 'relation');
|
||||
// setEditFormStep(1);
|
||||
// setViewItem(record);
|
||||
// setCreateDataSourceModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
@@ -143,9 +145,10 @@ const DataSetTable: React.FC<Props> = ({ disabledEdit = false }) => {
|
||||
<a
|
||||
key="metricEditBtn"
|
||||
onClick={() => {
|
||||
setEditFormStep(0);
|
||||
setViewItem(record);
|
||||
setCreateDataSourceModalOpen(true);
|
||||
toDatasetEditPage(record.domainId, record.id);
|
||||
// setEditFormStep(0);
|
||||
// setViewItem(record);
|
||||
// setCreateDataSourceModalOpen(true);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
|
||||
import { Form, Input, Select, Spin, Space } from 'antd';
|
||||
import type { Ref } from 'react';
|
||||
import styles from '../../components/style.less';
|
||||
import { message } from 'antd';
|
||||
import { formLayout } from '@/components/FormHelper/utils';
|
||||
import { createView, updateView, getDimensionList, queryMetric } from '../../service';
|
||||
import { ISemantic } from '../../data';
|
||||
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
||||
import SelectTMEPerson from '@/components/SelectTMEPerson';
|
||||
import ViewModelConfigTransfer from './ViewModelConfigTransfer';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
export type ModelCreateFormModalProps = {
|
||||
activeKey: string;
|
||||
domainId: number;
|
||||
datasetItem: any;
|
||||
modelList: ISemantic.IModelItem[];
|
||||
onCancel: () => void;
|
||||
onSubmit: (values: any) => void;
|
||||
};
|
||||
|
||||
const DatasetCreateForm: React.FC<ModelCreateFormModalProps> = forwardRef(
|
||||
(
|
||||
{ activeKey, datasetItem, domainId, onCancel, onSubmit, modelList }: ModelCreateFormModalProps,
|
||||
ref: Ref<any>,
|
||||
) => {
|
||||
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
||||
const [dimensionLoading, setDimensionLoading] = useState<boolean>(false);
|
||||
const [selectedModelItem, setSelectedModelItem] = useState<ISemantic.IModelItem | undefined>(
|
||||
modelList[0],
|
||||
);
|
||||
const [form] = Form.useForm();
|
||||
const configTableRef = useRef<any>();
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
onSave: () => {
|
||||
return handleConfirm();
|
||||
},
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (Array.isArray(modelList) || !selectedModelItem) {
|
||||
setSelectedModelItem(modelList[0]);
|
||||
}
|
||||
}, [modelList]);
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue({
|
||||
...datasetItem,
|
||||
});
|
||||
}, [datasetItem]);
|
||||
|
||||
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>();
|
||||
const [metricList, setMetricList] = useState<ISemantic.IMetricItem[]>();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedModelItem?.id) {
|
||||
queryDimensionList(selectedModelItem.id);
|
||||
queryMetricList(selectedModelItem.id);
|
||||
}
|
||||
}, [selectedModelItem]);
|
||||
|
||||
const queryDimensionList = async (modelId: number) => {
|
||||
setDimensionLoading(true);
|
||||
const { code, data, msg } = await getDimensionList({ modelId });
|
||||
setDimensionLoading(false);
|
||||
if (code === 200 && Array.isArray(data?.list)) {
|
||||
setDimensionList(data.list);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const queryMetricList = async (modelId: number) => {
|
||||
const { code, data, msg } = await queryMetric({ modelId });
|
||||
if (code === 200 && Array.isArray(data?.list)) {
|
||||
setMetricList(data.list);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
const fieldsValue = await form.validateFields();
|
||||
const viewModelConfigsMap = configTableRef?.current.getViewModelConfigs() || {};
|
||||
|
||||
const queryData: ISemantic.IModelItem = {
|
||||
...datasetItem,
|
||||
...fieldsValue,
|
||||
dataSetDetail: {
|
||||
dataSetModelConfigs: Object.values(viewModelConfigsMap),
|
||||
},
|
||||
domainId,
|
||||
};
|
||||
setSaveLoading(true);
|
||||
const { code, msg } = await (!queryData.id ? createView : updateView)(queryData);
|
||||
setSaveLoading(false);
|
||||
if (code === 200) {
|
||||
onSubmit?.(queryData);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: activeKey === 'relation' ? 'block' : 'none' }}>
|
||||
<Spin spinning={dimensionLoading}>
|
||||
<ViewModelConfigTransfer
|
||||
toolbarSolt={
|
||||
<Space>
|
||||
<span>切换模型: </span>
|
||||
<Select
|
||||
style={{
|
||||
minWidth: 150,
|
||||
textAlign: 'left',
|
||||
}}
|
||||
value={selectedModelItem?.id}
|
||||
placeholder="请选择模型,获取当前模型下指标维度信息"
|
||||
onChange={(val) => {
|
||||
setDimensionList(undefined);
|
||||
setMetricList(undefined);
|
||||
const modelItem = modelList.find((item) => item.id === val);
|
||||
setSelectedModelItem(modelItem);
|
||||
}}
|
||||
options={modelList.map((item) => {
|
||||
return { label: item.name, value: item.id };
|
||||
})}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
dimensionList={dimensionList}
|
||||
metricList={metricList}
|
||||
modelItem={selectedModelItem}
|
||||
viewItem={datasetItem}
|
||||
ref={configTableRef}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
<div style={{ display: activeKey === 'basic' ? 'block' : 'none' }}>
|
||||
<FormItem
|
||||
name="name"
|
||||
label="数据集名称"
|
||||
rules={[{ required: true, message: '请输入数据集名称!' }]}
|
||||
>
|
||||
<Input placeholder="数据集名称不可重复" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="bizName"
|
||||
label="数据集英文名称"
|
||||
rules={[{ required: true, message: '请输入数据集英文名称!' }]}
|
||||
>
|
||||
<Input placeholder="请输入数据集英文名称" />
|
||||
</FormItem>
|
||||
{/* <FormItem
|
||||
name="alias"
|
||||
label="别名"
|
||||
getValueFromEvent={(value) => {
|
||||
return Array.isArray(value) ? value.join(',') : '';
|
||||
}}
|
||||
getValueProps={(value) => {
|
||||
return {
|
||||
value: isString(value) ? value.split(',') : [],
|
||||
};
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
|
||||
tokenSeparators={[',']}
|
||||
maxTagCount={9}
|
||||
/>
|
||||
</FormItem> */}
|
||||
<FormItem name="admins" label={<FormItemTitle title={'责任人'} />}>
|
||||
<SelectTMEPerson placeholder="请邀请团队成员" />
|
||||
</FormItem>
|
||||
<FormItem name="description" label="数据集描述">
|
||||
<Input.TextArea placeholder="数据集描述" />
|
||||
</FormItem>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
{...formLayout}
|
||||
form={form}
|
||||
onValuesChange={(value, values) => {}}
|
||||
className={styles.form}
|
||||
>
|
||||
{renderContent()}
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
export default DatasetCreateForm;
|
||||
@@ -0,0 +1,122 @@
|
||||
import { message, Form } from 'antd';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useParams, useModel, Helmet } from '@umijs/max';
|
||||
import { BASE_TITLE } from '@/common/constants';
|
||||
import { ISemantic } from '../../data';
|
||||
import { getAllModelByDomainId, getDataSetDetail } from '../../service';
|
||||
import DetailContainer from '@/pages/SemanticModel/components/DetailContainer';
|
||||
import DetailSider from '@/pages/SemanticModel/components/DetailContainer/DetailSider';
|
||||
import { ProjectOutlined, ConsoleSqlOutlined } from '@ant-design/icons';
|
||||
import DatasetCreateForm from './DatasetCreateForm';
|
||||
import DetailFormWrapper from '@/pages/SemanticModel/components/DetailContainer/DetailFormWrapper';
|
||||
|
||||
type Props = Record<string, any>;
|
||||
|
||||
const DataSetDetail: React.FC<Props> = () => {
|
||||
const settingList = [
|
||||
{
|
||||
icon: <ProjectOutlined />,
|
||||
key: 'basic',
|
||||
text: '基本信息',
|
||||
},
|
||||
{
|
||||
icon: <ConsoleSqlOutlined />,
|
||||
key: 'relation',
|
||||
text: '关联信息',
|
||||
},
|
||||
];
|
||||
const params: any = useParams();
|
||||
const detailId = params.datasetId;
|
||||
const menuKey = params.menuKey;
|
||||
const [detailData, setDetailData] = useState<ISemantic.IDatasetItem>();
|
||||
const domainModel = useModel('SemanticModel.domainData');
|
||||
const { selectDomainId, setSelectDataSet } = domainModel;
|
||||
const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
|
||||
const [activeMenu, setActiveMenu] = useState<any>(() => {
|
||||
if (menuKey) {
|
||||
const target = settingList.find((item) => item.key === menuKey);
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return settingList[0];
|
||||
});
|
||||
const detailFormRef = useRef<any>();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setSelectDataSet(undefined);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!detailId) {
|
||||
return;
|
||||
}
|
||||
queryDetailData(detailId);
|
||||
}, [detailId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectDomainId) {
|
||||
return;
|
||||
}
|
||||
queryDomainAllModel();
|
||||
}, [selectDomainId]);
|
||||
|
||||
const queryDomainAllModel = async () => {
|
||||
const { code, data, msg } = await getAllModelByDomainId(selectDomainId);
|
||||
if (code === 200) {
|
||||
setModelList(data);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const queryDetailData = async (id: number) => {
|
||||
const { code, data, msg } = await getDataSetDetail(id);
|
||||
if (code === 200) {
|
||||
setDetailData(data);
|
||||
setSelectDataSet(data);
|
||||
return;
|
||||
}
|
||||
message.error(msg);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet title={`[数据集]${detailData?.name}-${BASE_TITLE}`} />
|
||||
<DetailContainer
|
||||
siderNode={
|
||||
<DetailSider
|
||||
menuKey={activeMenu.key}
|
||||
menuList={settingList}
|
||||
detailData={detailData}
|
||||
onMenuKeyChange={(key: string, menu) => {
|
||||
// setSettingKey(key);
|
||||
setActiveMenu(menu);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
containerNode={
|
||||
<DetailFormWrapper
|
||||
currentMenu={activeMenu}
|
||||
onSave={() => {
|
||||
detailFormRef.current.onSave();
|
||||
}}
|
||||
>
|
||||
<DatasetCreateForm
|
||||
ref={detailFormRef}
|
||||
activeKey={activeMenu.key}
|
||||
domainId={selectDomainId}
|
||||
datasetItem={detailData}
|
||||
modelList={modelList}
|
||||
/>
|
||||
</DetailFormWrapper>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataSetDetail;
|
||||
@@ -165,7 +165,6 @@ const ViewCreateFormModal: React.FC<ModelCreateFormModalProps> = ({
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
return (
|
||||
<>
|
||||
@@ -262,7 +261,6 @@ const ViewCreateFormModal: React.FC<ModelCreateFormModalProps> = ({
|
||||
<Steps style={{ marginBottom: 28 }} size="small" current={currentStep}>
|
||||
<Step title="基本信息" />
|
||||
<Step title="关联信息" />
|
||||
{/* <Step title="进阶设置" /> */}
|
||||
</Steps>
|
||||
<Form
|
||||
{...formLayout}
|
||||
|
||||
@@ -161,7 +161,7 @@ const ViewModelConfigTransfer: React.FC<Props> = forwardRef(
|
||||
setSelectedTransferKeys(transferKeys);
|
||||
setViewModelConfigsMap(viewConfigMap);
|
||||
}
|
||||
}, [queryType]);
|
||||
}, [queryType, viewItem]);
|
||||
|
||||
useEffect(() => {
|
||||
if (queryType !== TransType.METRIC) {
|
||||
|
||||
Reference in New Issue
Block a user