mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-15 22:46:49 +00:00
[improvement][project] global refactor , code format , support llm , support fuzzy detect ,support query filter and so on.
This commit is contained in:
@@ -1,19 +1,102 @@
|
||||
import React from 'react';
|
||||
import { Form, Input, Spin } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Form, Input, Spin, Select, message } from 'antd';
|
||||
import type { FormInstance } from 'antd/lib/form';
|
||||
import { getDbNames, getTables } from '../../service';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
|
||||
type Props = {
|
||||
isEdit?: boolean;
|
||||
dataBaseConfig: any;
|
||||
form: FormInstance<any>;
|
||||
tableLoading?: boolean;
|
||||
mode?: 'normal' | 'fast';
|
||||
};
|
||||
|
||||
const DataSourceBasicForm: React.FC<Props> = ({ isEdit, tableLoading = false }) => {
|
||||
const DataSourceBasicForm: React.FC<Props> = ({
|
||||
isEdit,
|
||||
dataBaseConfig,
|
||||
tableLoading = false,
|
||||
mode = 'normal',
|
||||
}) => {
|
||||
const [dbNameList, setDbNameList] = useState<any[]>([]);
|
||||
const [tableNameList, setTableNameList] = useState<any[]>([]);
|
||||
const [currentDbName, setCurrentDbName] = useState<string>('');
|
||||
const [currentTableName, setCurrentTableName] = useState<string>('');
|
||||
const queryDbNameList = async (databaseId: number) => {
|
||||
const { code, data, msg } = await getDbNames(databaseId);
|
||||
if (code === 200) {
|
||||
const list = data?.resultList || [];
|
||||
setDbNameList(list);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
const queryTableNameList = async (databaseName: string) => {
|
||||
const { code, data, msg } = await getTables(dataBaseConfig.id, databaseName);
|
||||
if (code === 200) {
|
||||
const list = data?.resultList || [];
|
||||
setTableNameList(list);
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (dataBaseConfig?.id) {
|
||||
queryDbNameList(dataBaseConfig.id);
|
||||
}
|
||||
}, [dataBaseConfig]);
|
||||
|
||||
return (
|
||||
<Spin spinning={tableLoading}>
|
||||
{mode === 'fast' && (
|
||||
<>
|
||||
<FormItem
|
||||
name="dbName"
|
||||
label="数据库名"
|
||||
rules={[{ required: true, message: '请选择数据库/表' }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
placeholder="请选择数据库/表"
|
||||
disabled={isEdit}
|
||||
onChange={(dbName: string) => {
|
||||
queryTableNameList(dbName);
|
||||
setCurrentDbName(dbName);
|
||||
}}
|
||||
>
|
||||
{dbNameList.map((item) => (
|
||||
<Select.Option key={item.name} value={item.name}>
|
||||
{item.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="tableName"
|
||||
label="数据表名"
|
||||
rules={[{ required: true, message: '请选择数据库/表' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择数据库/表"
|
||||
disabled={isEdit}
|
||||
showSearch
|
||||
onChange={(tableName: string) => {
|
||||
// queryTableNameList(tableName);
|
||||
setCurrentTableName(tableName);
|
||||
}}
|
||||
>
|
||||
{tableNameList.map((item) => (
|
||||
<Select.Option key={item.name} value={item.name}>
|
||||
{item.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
<FormItem
|
||||
name="name"
|
||||
label="数据源中文名"
|
||||
|
||||
@@ -4,18 +4,25 @@ import BasicInfoForm from './DataSourceBasicForm';
|
||||
import FieldForm from './DataSourceFieldForm';
|
||||
import { formLayout } from '@/components/FormHelper/utils';
|
||||
import { EnumDataSourceType } from '../constants';
|
||||
import type { DataInstanceItem, FieldItem, SaveDataSetForm } from '../data';
|
||||
import type { DataInstanceItem } from '../data';
|
||||
import styles from '../style.less';
|
||||
import { createDatasource, updateDatasource } from '../../service';
|
||||
import { createDatasource, updateDatasource, getColumns } from '../../service';
|
||||
import type { Dispatch } from 'umi';
|
||||
import type { StateType } from '../../model';
|
||||
import { connect } from 'umi';
|
||||
|
||||
export type CreateFormProps = {
|
||||
domainManger: StateType;
|
||||
dispatch: Dispatch;
|
||||
createModalVisible: boolean;
|
||||
sql: string;
|
||||
sql?: string;
|
||||
domainId: number;
|
||||
dataSourceItem: DataInstanceItem | any;
|
||||
onCancel?: () => void;
|
||||
onSubmit?: (dataSourceInfo: any) => void;
|
||||
scriptColumns: any[];
|
||||
scriptColumns?: any[] | undefined;
|
||||
basicInfoFormMode?: 'normal' | 'fast';
|
||||
onDataBaseTableChange?: (tableName: string) => void;
|
||||
};
|
||||
const { Step } = Steps;
|
||||
|
||||
@@ -26,30 +33,40 @@ const initFormVal = {
|
||||
};
|
||||
|
||||
const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
domainManger,
|
||||
onCancel,
|
||||
createModalVisible,
|
||||
domainId,
|
||||
scriptColumns,
|
||||
sql,
|
||||
sql = '',
|
||||
onSubmit,
|
||||
dataSourceItem,
|
||||
basicInfoFormMode,
|
||||
}) => {
|
||||
const isEdit = !!dataSourceItem?.id;
|
||||
const [fields, setFields] = useState<FieldItem[]>([]);
|
||||
const [fields, setFields] = useState<any[]>([]);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [saveLoading, setSaveLoading] = useState(false);
|
||||
const formValRef = useRef(initFormVal as any);
|
||||
const [form] = Form.useForm();
|
||||
const updateFormVal = (val: SaveDataSetForm) => {
|
||||
const { dataBaseConfig } = domainManger;
|
||||
const updateFormVal = (val: any) => {
|
||||
formValRef.current = val;
|
||||
};
|
||||
|
||||
const [fieldColumns, setFieldColumns] = useState(scriptColumns || []);
|
||||
useEffect(() => {
|
||||
if (scriptColumns) {
|
||||
setFieldColumns(scriptColumns);
|
||||
}
|
||||
}, [scriptColumns]);
|
||||
|
||||
const forward = () => setCurrentStep(currentStep + 1);
|
||||
const backward = () => setCurrentStep(currentStep - 1);
|
||||
|
||||
const getFieldsClassify = (fieldsList: FieldItem[]) => {
|
||||
const getFieldsClassify = (fieldsList: any[]) => {
|
||||
const classify = fieldsList.reduce(
|
||||
(fieldsClassify, item: FieldItem) => {
|
||||
(fieldsClassify, item: any) => {
|
||||
const {
|
||||
type,
|
||||
bizName,
|
||||
@@ -126,11 +143,13 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
forward();
|
||||
} else {
|
||||
setSaveLoading(true);
|
||||
const { dbName, tableName } = submitForm;
|
||||
const queryParams = {
|
||||
...submitForm,
|
||||
sqlQuery: sql,
|
||||
databaseId: dataSourceItem.databaseId,
|
||||
queryType: 'sql_query',
|
||||
databaseId: dataSourceItem?.databaseId || dataBaseConfig.id,
|
||||
queryType: basicInfoFormMode === 'fast' ? 'table_query' : 'sql_query',
|
||||
tableQuery: dbName && tableName ? `${dbName}.${tableName}` : '',
|
||||
domainId,
|
||||
};
|
||||
const queryDatasource = isEdit ? updateDatasource : createDatasource;
|
||||
@@ -149,8 +168,8 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const initFields = (fieldsClassifyList: any[]) => {
|
||||
const columnFields: any[] = scriptColumns.map((item: any) => {
|
||||
const initFields = (fieldsClassifyList: any[], columns: any[]) => {
|
||||
const columnFields: any[] = columns.map((item: any) => {
|
||||
const { type, nameEn } = item;
|
||||
const oldItem = fieldsClassifyList.find((oItem) => oItem.bizName === item.nameEn) || {};
|
||||
return {
|
||||
@@ -181,13 +200,32 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const initData = () => {
|
||||
const initData = async () => {
|
||||
const { queryType, tableQuery } = dataSourceItem.datasourceDetail;
|
||||
let tableQueryInitValue = {};
|
||||
let columns = fieldColumns;
|
||||
if (queryType === 'table_query') {
|
||||
const tableQueryString = tableQuery || '';
|
||||
const [dbName, tableName] = tableQueryString.split('.');
|
||||
columns = await queryTableColumnList(dbName, tableName);
|
||||
tableQueryInitValue = {
|
||||
dbName,
|
||||
tableName,
|
||||
};
|
||||
}
|
||||
formatterInitData(columns, tableQueryInitValue);
|
||||
};
|
||||
|
||||
const formatterInitData = (columns: any[], extendParams: Record<string, any> = {}) => {
|
||||
const { id, name, bizName, description, datasourceDetail } = dataSourceItem as any;
|
||||
const { dimensions, identifiers, measures } = datasourceDetail;
|
||||
const initValue = {
|
||||
id,
|
||||
name,
|
||||
bizName,
|
||||
description,
|
||||
...extendParams,
|
||||
// ...tableQueryInitValue,
|
||||
};
|
||||
const editInitFormVal = {
|
||||
...formValRef.current,
|
||||
@@ -195,20 +233,19 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
};
|
||||
updateFormVal(editInitFormVal);
|
||||
form.setFieldsValue(initValue);
|
||||
const { dimensions, identifiers, measures } = datasourceDetail;
|
||||
const formatFields = [
|
||||
...formatterDimensions(dimensions || []),
|
||||
...(identifiers || []),
|
||||
...formatterMeasures(measures || []),
|
||||
];
|
||||
initFields(formatFields);
|
||||
initFields(formatFields, columns);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
initData();
|
||||
} else {
|
||||
initFields([]);
|
||||
initFields([], fieldColumns);
|
||||
}
|
||||
}, [dataSourceItem]);
|
||||
|
||||
@@ -227,11 +264,42 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
setFields(result);
|
||||
};
|
||||
|
||||
const queryTableColumnList = async (dbName: string, tableName: string) => {
|
||||
if (!dataBaseConfig?.id) {
|
||||
return;
|
||||
}
|
||||
const { code, data, msg } = await getColumns(dataBaseConfig.id, dbName, tableName);
|
||||
if (code === 200) {
|
||||
const list = data?.resultList || [];
|
||||
// setTableNameList(list);
|
||||
const columns = list.map((item: any) => {
|
||||
const { dataType, name } = item;
|
||||
return {
|
||||
nameEn: name,
|
||||
type: dataType,
|
||||
};
|
||||
});
|
||||
// setFields(columns);
|
||||
initFields([], columns);
|
||||
setFieldColumns(columns);
|
||||
return columns;
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
if (currentStep === 1) {
|
||||
return <FieldForm fields={fields} onFieldChange={handleFieldChange} />;
|
||||
}
|
||||
return <BasicInfoForm form={form} isEdit={isEdit} />;
|
||||
return (
|
||||
<BasicInfoForm
|
||||
form={form}
|
||||
isEdit={isEdit}
|
||||
mode={basicInfoFormMode}
|
||||
dataBaseConfig={dataBaseConfig}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
@@ -280,6 +348,13 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
initialValues={{
|
||||
...formValRef.current,
|
||||
}}
|
||||
onValuesChange={(value, values) => {
|
||||
const { tableName } = value;
|
||||
const { dbName } = values;
|
||||
if (tableName) {
|
||||
queryTableColumnList(dbName, tableName);
|
||||
}
|
||||
}}
|
||||
className={styles.form}
|
||||
>
|
||||
{renderContent()}
|
||||
@@ -288,4 +363,6 @@ const DataSourceCreateForm: React.FC<CreateFormProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default DataSourceCreateForm;
|
||||
export default connect(({ domainManger }: { domainManger: StateType }) => ({
|
||||
domainManger,
|
||||
}))(DataSourceCreateForm);
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Button, Table, message, Tooltip, Space, Dropdown } from 'antd';
|
||||
import SplitPane from 'react-split-pane';
|
||||
import Pane from 'react-split-pane/lib/Pane';
|
||||
import { connect } from 'umi';
|
||||
import sqlFormatter from 'sql-formatter';
|
||||
import {
|
||||
FullscreenOutlined,
|
||||
@@ -15,10 +16,12 @@ import {
|
||||
import { isFunction } from 'lodash';
|
||||
import FullScreen from '@/components/FullScreen';
|
||||
import SqlEditor from '@/components/SqlEditor';
|
||||
import type { TaskResultParams, TaskResultItem, DataInstanceItem, TaskResultColumn } from '../data';
|
||||
import { excuteSql } from '../service';
|
||||
import { getDatabaseByDomainId } from '../../service';
|
||||
import type { TaskResultItem, DataInstanceItem, TaskResultColumn } from '../data';
|
||||
import { excuteSql } from '@/pages/SemanticModel/service';
|
||||
// import { getDatabaseByDomainId } from '../../service';
|
||||
import DataSourceCreateForm from './DataSourceCreateForm';
|
||||
import type { Dispatch } from 'umi';
|
||||
import type { StateType } from '../../model';
|
||||
import styles from '../style.less';
|
||||
|
||||
import 'ace-builds/src-min-noconflict/ext-searchbox';
|
||||
@@ -27,7 +30,8 @@ import 'ace-builds/src-min-noconflict/theme-monokai';
|
||||
import 'ace-builds/src-min-noconflict/mode-sql';
|
||||
|
||||
type IProps = {
|
||||
oprType: 'add' | 'edit';
|
||||
domainManger: StateType;
|
||||
dispatch: Dispatch;
|
||||
dataSourceItem: DataInstanceItem;
|
||||
domainId: number;
|
||||
onUpdateSql?: (sql: string) => void;
|
||||
@@ -52,6 +56,7 @@ type JdbcSourceItems = {
|
||||
};
|
||||
|
||||
const SqlDetail: React.FC<IProps> = ({
|
||||
domainManger,
|
||||
dataSourceItem,
|
||||
onSubmitSuccess,
|
||||
domainId,
|
||||
@@ -59,6 +64,7 @@ const SqlDetail: React.FC<IProps> = ({
|
||||
onUpdateSql,
|
||||
onJdbcSourceChange,
|
||||
}) => {
|
||||
const { dataBaseConfig } = domainManger;
|
||||
const [resultTable, setResultTable] = useState<ResultTableItem[]>([]);
|
||||
const [resultTableLoading, setResultTableLoading] = useState(false);
|
||||
const [resultCols, setResultCols] = useState<ResultColItem[]>([]);
|
||||
@@ -111,20 +117,30 @@ const SqlDetail: React.FC<IProps> = ({
|
||||
// return 'ClickHouse';
|
||||
// });
|
||||
|
||||
const queryDatabaseConfig = async () => {
|
||||
const { code, data } = await getDatabaseByDomainId(domainId);
|
||||
if (code === 200) {
|
||||
setJdbcSourceItems([
|
||||
{
|
||||
label: data?.name,
|
||||
key: data?.id,
|
||||
},
|
||||
]);
|
||||
onJdbcSourceChange?.(data?.id && Number(data?.id));
|
||||
return;
|
||||
}
|
||||
message.error('数据库配置获取错误');
|
||||
};
|
||||
useEffect(() => {
|
||||
setJdbcSourceItems([
|
||||
{
|
||||
label: dataBaseConfig?.name,
|
||||
key: dataBaseConfig?.id,
|
||||
},
|
||||
]);
|
||||
onJdbcSourceChange?.(dataBaseConfig?.id && Number(dataBaseConfig?.id));
|
||||
}, [dataBaseConfig]);
|
||||
|
||||
// const queryDatabaseConfig = async () => {
|
||||
// const { code, data } = await getDatabaseByDomainId(domainId);
|
||||
// if (code === 200) {
|
||||
// setJdbcSourceItems([
|
||||
// {
|
||||
// label: data?.name,
|
||||
// key: data?.id,
|
||||
// },
|
||||
// ]);
|
||||
// onJdbcSourceChange?.(data?.id && Number(data?.id));
|
||||
// return;
|
||||
// }
|
||||
// message.error('数据库配置获取错误');
|
||||
// };
|
||||
|
||||
function creatCalcItem(key: string, data: string) {
|
||||
const line = document.createElement('div'); // 需要每条数据一行,这样避免数据换行的时候获得的宽度不准确
|
||||
@@ -185,7 +201,7 @@ const SqlDetail: React.FC<IProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTaskResult = (params: TaskResultParams) => {
|
||||
const fetchTaskResult = (params) => {
|
||||
setResultTable(
|
||||
params.resultList.map((item, index) => {
|
||||
return {
|
||||
@@ -367,7 +383,7 @@ const SqlDetail: React.FC<IProps> = ({
|
||||
}, [resultTable, isSqlResFullScreen]);
|
||||
|
||||
useEffect(() => {
|
||||
queryDatabaseConfig();
|
||||
// queryDatabaseConfig();
|
||||
const windowHeight = window.innerHeight;
|
||||
let size: ScreenSize = 'small';
|
||||
if (windowHeight > 1100) {
|
||||
@@ -527,4 +543,6 @@ const SqlDetail: React.FC<IProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default SqlDetail;
|
||||
export default connect(({ domainManger }: { domainManger: StateType }) => ({
|
||||
domainManger,
|
||||
}))(SqlDetail);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Tabs } from 'antd';
|
||||
import SqlDetail from './SqlDetail';
|
||||
import type { SqlItem } from '../data';
|
||||
|
||||
import styles from '../style.less';
|
||||
|
||||
@@ -11,7 +10,6 @@ type Panes = {
|
||||
type: 'add' | 'edit';
|
||||
scriptId?: number;
|
||||
sql?: string;
|
||||
sqlInfo?: SqlItem;
|
||||
isSave?: boolean; // 暂存提示保存
|
||||
};
|
||||
|
||||
|
||||
16
webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/data.d.ts
vendored
Normal file
16
webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/data.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// 数据类型
|
||||
export type DataInstanceItem = {
|
||||
sourceInstanceId: number; // 数据实例id
|
||||
sourceInstanceName: string; // 数据实例名
|
||||
defaultSourceId: number; // 查询表需要的默认datasource id
|
||||
bindSourceId: number;
|
||||
};
|
||||
|
||||
// 任务查询结果列
|
||||
export type TaskResultColumn = {
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
// 任务查询结果
|
||||
export type TaskResultItem = Record<string, string | number>;
|
||||
@@ -1,12 +0,0 @@
|
||||
import request from 'umi-request';
|
||||
|
||||
type ExcuteSqlParams = {
|
||||
sql: string;
|
||||
domainId: number;
|
||||
};
|
||||
|
||||
// 执行脚本
|
||||
export async function excuteSql(params: ExcuteSqlParams) {
|
||||
const data = { ...params };
|
||||
return request.post(`${process.env.API_BASE_URL}database/executeSql`, { data });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user