From 4dee8c6b8db67e5ceee02cbf86b3f850faf6f8b1 Mon Sep 17 00:00:00 2001 From: tristanliu <37809633+sevenliu1896@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:38:28 +0800 Subject: [PATCH] [improvement][headless-fe] Added search functionality to model management. (#874) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [improvement][semantic-fe] Add model alias setting & Add view permission restrictions to the model permission management tab. [improvement][semantic-fe] Add permission control to the action buttons for the main domain; apply high sensitivity filtering to the authorization of metrics/dimensions. [improvement][semantic-fe] Optimize the editing mode in the dimension/metric/datasource components to use the modelId stored in the database for data, instead of relying on the data from the state manager. * [improvement][semantic-fe] Add time granularity setting in the data source configuration. * [improvement][semantic-fe] Dictionary import for dimension values supported in Q&A visibility * [improvement][semantic-fe] Modification of data source creation prompt wording" * [improvement][semantic-fe] metric market experience optimization * [improvement][semantic-fe] enhance the analysis of metric trends * [improvement][semantic-fe] optimize the presentation of metric trend permissions * [improvement][semantic-fe] add metric trend download functionality * [improvement][semantic-fe] fix the dimension initialization issue in metric correlation * [improvement][semantic-fe] Fix the issue of database changes not taking effect when creating based on an SQL data source. * [improvement][semantic-fe] Optimizing pagination logic and some CSS styles * [improvement][semantic-fe] Fixing the API for the indicator list by changing "current" to "pageNum" * [improvement][semantic-fe] Fixing the default value setting for the indicator list * [improvement][semantic-fe] Adding batch operations for indicators/dimensions/models * [improvement][semantic-fe] Replacing the single status update API for indicators/dimensions with a batch update API * [improvement][semantic-fe] Redesigning the indicator homepage to incorporate trend charts and table functionality for indicators * [improvement][semantic-fe] Optimizing the logic for setting dimension values and editing data sources, and adding system settings functionality * [improvement][semantic-fe] Upgrading antd version to 5.x, extracting the batch operation button component, optimizing the interaction for system settings, and expanding the configuration generation types for list-to-select component. * [improvement][semantic-fe] Adding the ability to filter dimensions based on whether they are tags or not. * [improvement][semantic-fe] Adding the ability to edit relationships between models in the canvas. * [improvement][semantic-fe] Updating the datePicker component to use dayjs instead. * [improvement][semantic-fe] Fixing the issue with passing the model ID for dimensions in the indicator market. * [improvement][semantic-fe] Fixing the abnormal state of the popup when creating a model. * [improvement][semantic-fe] Adding permission logic for bulk operations in the indicator market. * [improvement][semantic-fe] Adding the ability to download and transpose data. * [improvement][semantic-fe] Fixing the initialization issue with the date selection component in the indicator details page when switching time granularity. * [improvement][semantic-fe] Fixing the logic error in the dimension value setting. * [improvement][semantic-fe] Fixing the synchronization issue with the question and answer settings information. * [improvement][semantic-fe] Optimizing the canvas functionality for better performance and user experience. * [improvement][semantic-fe] Optimizing the update process for drawing model relationship edges in the canvas. * [improvement][semantic-fe] Changing the line type for canvas connections. * [improvement][semantic-fe] Replacing the initialization variable from "semantic" to "headless". * [improvement][semantic-fe] Fixing the missing migration issue for default drill-down dimension configuration in model editing. Additionally, optimizing the data retrieval method for initializing fields in the model. * [improvement][semantic-fe] Updating the logic for the fieldName. * [improvement][semantic-fe] Adjusting the position of the metrics tab. * [improvement][semantic-fe] Changing the 字段名称 to 英文名称. * [improvement][semantic-fe] Fix metric measurement deletion. * [improvement][semantic-fe] UI optimization for metric details page. * [improvement][semantic-fe] UI optimization for metric details page. * [improvement][semantic-fe] UI adjustment for metric details page. * [improvement][semantic-fe] The granularity field in the time type of model editing now supports setting it as empty. * [improvement][semantic-fe] Added field type and metric type to the metric creation options. * [improvement][semantic-fe] The organization structure selection feature has been added to the permission management. * [improvement][semantic-fe] Improved user experience for the metric list. * [improvement][semantic-fe] fix update the metric list. * [improvement][headless-fe] Added view management functionality. * [improvement][headless-fe] The view management functionality has been added. This feature allows users to create, edit, and manage different views within the system. * [improvement][headless-fe] Added model editing side effect detection. * [improvement][headless-fe] Fixed the logic error in view editing. * [improvement][headless-fe] Fixed the issue with initializing dimension associations in metric settings. * [improvement][headless-fe] Added the ability to hide the Q&A settings entry point. * [improvement][headless-fe] Fixed the issue with selecting search results in metric field creation. * [improvement][headless-fe] Added search functionality to the field list in model editing. * [improvement][headless-fe] fix the field list in model editing * [improvement][headless-fe] Restructured the data for the dimension value settings interface. * [improvement][headless-fe] Added dynamic variable functionality to model creation based on SQL scripts. * [improvement][headless-fe] Added support for passing dynamic variables as parameters in the executeSql function. * [improvement][headless-fe] Resolved the issue where users were unable to select all options for dimensions, metrics, and fields in the metric generation process. * [improvement][headless-fe] Replaced the term "view" with "dataset" * [improvement][headless-fe] Added the ability to export metrics and dimensions to a specific target. * [improvement][headless-fe] Enhanced dataset creation to support the tag mode. * [improvement][headless-fe] Added tag value setting. * [improvement][headless-fe] Optimized the tag setting system. * [improvement][headless-fe] Optimized the tag setting system. * [improvement][headless-fe] Updated the data initialization for model editing to use API requests instead. * [improvement][headless-fe] Added search functionality to model management. --- .../packages/supersonic-fe/config/routes.ts | 13 ++-- .../Datasource/components/ModelCreateForm.tsx | 24 +------- .../src/pages/SemanticModel/Metric/Market.tsx | 34 +++++------ .../XflowJsonSchemaFormDrawerForm.tsx | 4 +- .../SemanticModel/SemanticGraph/index.tsx | 4 +- .../components/ClassDimensionTable.tsx | 1 - ...eTypeModal.tsx => ClassModelTypeModal.tsx} | 59 ++++++++++++------- .../SemanticModel/components/ModelTable.tsx | 54 +++++++++++++++-- 8 files changed, 118 insertions(+), 75 deletions(-) rename webapp/packages/supersonic-fe/src/pages/SemanticModel/components/{ClassDataSourceTypeModal.tsx => ClassModelTypeModal.tsx} (82%) diff --git a/webapp/packages/supersonic-fe/config/routes.ts b/webapp/packages/supersonic-fe/config/routes.ts index a052d34a5..1b12c69c4 100644 --- a/webapp/packages/supersonic-fe/config/routes.ts +++ b/webapp/packages/supersonic-fe/config/routes.ts @@ -34,18 +34,19 @@ const ROUTES = [ component: './Agent', envEnableList: [ENV_KEY.CHAT], }, - { - path: '/model/:domainId?/:modelId?/:menuKey?', - component: './SemanticModel/DomainManager', - name: 'semanticModel', - envEnableList: [ENV_KEY.SEMANTIC], - }, { path: '/plugin', name: 'plugin', component: './ChatPlugin', envEnableList: [ENV_KEY.CHAT], }, + { + path: '/model/:domainId?/:modelId?/:menuKey?', + component: './SemanticModel/DomainManager', + name: 'semanticModel', + envEnableList: [ENV_KEY.SEMANTIC], + }, + { path: '/metric', name: 'metric', diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/ModelCreateForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/ModelCreateForm.tsx index 7d968546d..d1d19a50a 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/ModelCreateForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/ModelCreateForm.tsx @@ -11,7 +11,6 @@ import { getColumns, getUnAvailableItem, getTagObjectList, - getModelDetail, } from '../../service'; import type { Dispatch } from 'umi'; import type { StateType } from '../../model'; @@ -52,15 +51,15 @@ const ModelCreateForm: React.FC = ({ sql = '', sqlParams, onSubmit, - modelItem: modelBasicInfo, + modelItem, databaseId, basicInfoFormMode, onDataSourceBtnClick, onOpenDataSourceEdit, children, }) => { - const isEdit = !!modelBasicInfo?.id; - const [modelItem, setModelItem] = useState({}); + const isEdit = !!modelItem?.id; + const [fields, setFields] = useState([]); const [currentStep, setCurrentStep] = useState(0); const [saveLoading, setSaveLoading] = useState(false); @@ -104,26 +103,9 @@ const ModelCreateForm: React.FC = ({ queryTagObjectList(); }, []); - useEffect(() => { - if (modelBasicInfo?.id) { - queryModelDetail(modelBasicInfo.id); - } - }, [modelBasicInfo]); - const forward = () => setCurrentStep(currentStep + 1); const backward = () => setCurrentStep(currentStep - 1); - const queryModelDetail = async (modelId: number) => { - const { code, msg, data } = await getModelDetail({ - modelId, - }); - if (code === 200) { - setModelItem(data); - } else { - message.error(msg); - } - }; - const queryTagObjectList = async () => { const { code, msg, data } = await getTagObjectList({ domainId: domainData?.parentId || domainData?.id, diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/Market.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/Market.tsx index 244ea00ee..322cb920b 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/Market.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/Market.tsx @@ -218,26 +218,26 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { { dataIndex: 'sensitiveLevel', title: '敏感度', - width: 150, + // width: 150, valueEnum: SENSITIVE_LEVEL_ENUM, render: columnsConfig.sensitiveLevel.render, }, - { - dataIndex: 'isPublish', - title: '是否发布', - width: 100, - search: false, - render: (isPublish) => { - switch (isPublish) { - case 0: - return '否'; - case 1: - return ; - default: - return 未知; - } - }, - }, + // { + // dataIndex: 'isPublish', + // title: '是否发布', + // width: 100, + // search: false, + // render: (isPublish) => { + // switch (isPublish) { + // case 0: + // return '否'; + // case 1: + // return ; + // default: + // return 未知; + // } + // }, + // }, { dataIndex: 'description', diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx index 92aeda51f..c575dcd67 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticFlows/components/XflowJsonSchemaFormDrawerForm.tsx @@ -7,7 +7,7 @@ import { connect } from 'umi'; import { DATASOURCE_NODE_RENDER_ID } from '../constant'; import DataSourceRelationFormDrawer from './DataSourceRelationFormDrawer'; import ModelCreateForm from '../../Datasource/components/ModelCreateForm'; -// import ClassDataSourceTypeModal from '../../components/ClassDataSourceTypeModal1'; +// import ClassModelTypeModal from '../../components/ClassDataSourceTypeModal1'; import { GraphApi } from '../service'; import { SemanticNodeType } from '../../enum'; import type { StateType } from '../../model'; @@ -154,7 +154,7 @@ const XflowJsonSchemaFormDrawerForm: React.FC = (props) => { /> {/* { - { resetSelectedNode(); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx index 0eebba6e5..a7ecf890e 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/SemanticGraph/index.tsx @@ -30,7 +30,7 @@ import NodeInfoDrawer from './components/NodeInfoDrawer'; import DimensionInfoModal from '../components/DimensionInfoModal'; import MetricInfoCreateForm from '../components/MetricInfoCreateForm'; import DeleteConfirmModal from './components/DeleteConfirmModal'; -import ClassDataSourceTypeModal from '../components/ClassDataSourceTypeModal'; +import ClassModelTypeModal from '../components/ClassModelTypeModal'; import GraphToolBar from './components/GraphToolBar'; import GraphLegend from './components/GraphLegend'; import GraphLegendVisibleModeItem from './components/GraphLegendVisibleModeItem'; @@ -1115,7 +1115,7 @@ const DomainManger: React.FC = ({ domainManger, dispatch }) => { )} {createDataSourceModalOpen && ( - { setNodeDataSource(undefined); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx index bced42a6d..8b2b0c964 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDimensionTable.tsx @@ -18,7 +18,6 @@ import DimensionInfoModal from './DimensionInfoModal'; import DimensionValueSettingModal from './DimensionValueSettingModal'; import { ISemantic, IDataSource } from '../data'; import TableHeaderFilter from './TableHeaderFilter'; -import moment from 'moment'; import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton'; import { ColumnsConfig } from './TableColumnRender'; import styles from './style.less'; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTypeModal.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassModelTypeModal.tsx similarity index 82% rename from webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTypeModal.tsx rename to webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassModelTypeModal.tsx index 65e0af3e1..843a73de7 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassDataSourceTypeModal.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ClassModelTypeModal.tsx @@ -1,19 +1,19 @@ -import { Drawer, Modal, Card, Row, Col } from 'antd'; +import { Drawer, Modal, Card, Row, Col, message } from 'antd'; import { ConsoleSqlOutlined, CoffeeOutlined } from '@ant-design/icons'; import React, { useState, useEffect } from 'react'; import type { Dispatch } from 'umi'; import { connect } from 'umi'; import ModelCreateForm from '../Datasource/components/ModelCreateForm'; -import { excuteSql } from '../service'; +import { excuteSql, getModelDetail } from '../service'; import type { StateType } from '../model'; import DataSource from '../Datasource'; -import { IDataSource } from '../data'; +import { IDataSource, ISemantic } from '../data'; import styles from './style.less'; const { Meta } = Card; type Props = { open: boolean; - dataSourceItem: IDataSource.IDataSourceItem; + modelItem: ISemantic.IModelItem; onTypeChange?: (type: 'fast' | 'normal') => void; onSubmit?: () => void; onCancel?: () => void; @@ -21,11 +21,11 @@ type Props = { domainManger: StateType; }; -const ClassDataSourceTypeModal: React.FC = ({ +const ClassModelTypeModal: React.FC = ({ open, onTypeChange, onSubmit, - dataSourceItem, + modelItem: modelBasicItem, domainManger, onCancel, dispatch, @@ -43,17 +43,36 @@ const ClassDataSourceTypeModal: React.FC = ({ const [scriptColumns, setScriptColumns] = useState([]); const [sqlParams, setSqlParams] = useState([]); + const [modelItem, setModelItem] = useState({}); + useEffect(() => { - if (!dataSourceItem?.id || !open) { + if (!modelBasicItem?.id || !open) { setCreateDataSourceModalOpen(true); return; } - if (dataSourceItem?.modelDetail?.queryType === 'table_query') { - setDataSourceModalVisible(true); - } else { - setCreateModalVisible(true); + }, [modelBasicItem, open]); + + useEffect(() => { + if (modelBasicItem?.id) { + queryModelDetail(modelBasicItem.id); } - }, [dataSourceItem, open]); + }, [modelBasicItem]); + + const queryModelDetail = async (modelId: number) => { + const { code, msg, data } = await getModelDetail({ + modelId, + }); + if (code === 200) { + setModelItem(data); + if (data?.modelDetail?.queryType === 'table_query') { + setDataSourceModalVisible(true); + } else { + setCreateModalVisible(true); + } + } else { + message.error(msg); + } + }; const queryDataBaseExcuteSql = (tableName: string) => { const sql = `select * from ${tableName}`; @@ -73,10 +92,10 @@ const ClassDataSourceTypeModal: React.FC = ({ }; useEffect(() => { - // queryTableColumnListByScript(dataSourceItem); - setSql(dataSourceItem?.modelDetail?.sqlQuery); + // queryTableColumnListByScript(modelItem); + setSql(modelItem?.modelDetail?.sqlQuery); - const modelDetailFields = dataSourceItem?.modelDetail?.fields; + const modelDetailFields = modelItem?.modelDetail?.fields; if (Array.isArray(modelDetailFields)) { setScriptColumns( modelDetailFields.map((item) => { @@ -87,7 +106,7 @@ const ClassDataSourceTypeModal: React.FC = ({ }), ); } - }, [dataSourceItem]); + }, [modelItem]); return ( <> @@ -149,7 +168,7 @@ const ClassDataSourceTypeModal: React.FC = ({ { setDataSourceModalVisible(false); handleCancel(); @@ -169,7 +188,7 @@ const ClassDataSourceTypeModal: React.FC = ({ sql={sql} databaseId={currentDatabaseId} basicInfoFormMode="normal" - modelItem={dataSourceItem} + modelItem={modelItem} scriptColumns={scriptColumns} sqlParams={sqlParams} onCancel={() => { @@ -198,7 +217,7 @@ const ClassDataSourceTypeModal: React.FC = ({ footer={null} > { const { columns, sql, databaseId, sqlParams } = dataSourceInfo; setSql(sql); @@ -216,4 +235,4 @@ const ClassDataSourceTypeModal: React.FC = ({ }; export default connect(({ domainManger }: { domainManger: StateType }) => ({ domainManger, -}))(ClassDataSourceTypeModal); +}))(ClassModelTypeModal); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx index 957a30da0..cacbb7693 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/components/ModelTable.tsx @@ -1,15 +1,15 @@ import type { ActionType, ProColumns } from '@ant-design/pro-table'; import ProTable from '@ant-design/pro-table'; -import { message, Button, Space, Popconfirm, Input, Tag } from 'antd'; +import { message, Button, Space, Popconfirm, Input } from 'antd'; import React, { useRef, useState, useEffect } from 'react'; import { StatusEnum } from '../enum'; import type { Dispatch } from 'umi'; import { connect } from 'umi'; import type { StateType } from '../model'; import { deleteModel, updateModel } from '../service'; -import ClassDataSourceTypeModal from './ClassDataSourceTypeModal'; +import ClassModelTypeModal from './ClassModelTypeModal'; import { ColumnsConfig } from './TableColumnRender'; - +import TableHeaderFilter from './TableHeaderFilter'; import moment from 'moment'; import styles from './style.less'; import { ISemantic } from '../data'; @@ -25,9 +25,28 @@ type Props = { const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelChange }) => { const [modelItem, setModelItem] = useState(); const [saveLoading, setSaveLoading] = useState(false); + const [filterParams, setFilterParams] = useState>({}); const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false); const actionRef = useRef(); + const [tableData, setTableData] = useState([]); + + useEffect(() => { + if (!Array.isArray(modelList)) { + return; + } + setTableData(modelList); + }, [modelList]); + + useEffect(() => { + const { key } = filterParams; + if (key) { + setTableData(modelList.filter((item) => item.name.includes(key))); + } else { + setTableData(modelList); + } + }, [filterParams]); + const updateModelStatus = async (modelData: ISemantic.IModelItem) => { setSaveLoading(true); const { code, msg } = await updateModel({ @@ -177,10 +196,33 @@ const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelC rowKey="id" search={false} columns={columns} - dataSource={modelList} + dataSource={tableData} tableAlertRender={() => { return false; }} + headerTitle={ + { + setFilterParams((preState) => { + return { + ...preState, + key: value, + }; + }); + }} + /> + ), + }, + ]} + /> + } size="small" options={{ reload: false, density: false, fullScreen: false }} toolBarRender={() => @@ -201,9 +243,9 @@ const ModelTable: React.FC = ({ modelList, disabledEdit = false, onModelC } /> {createDataSourceModalOpen && ( - { onModelChange?.(); setCreateDataSourceModalOpen(false);