From 1ab88360ace3812387bb5542b81bf41cbbed18f8 Mon Sep 17 00:00:00 2001 From: tristanliu <37809633+sevenliu1896@users.noreply.github.com> Date: Fri, 29 Mar 2024 14:33:35 +0800 Subject: [PATCH] [improvement][headless-fe] Optimized the tag setting system. (#868) 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. --- .../packages/supersonic-fe/config/routes.ts | 13 +- .../components/DataSourceCreateForm.tsx | 6 +- .../components/DataSourceFieldForm.tsx | 1 - .../pages/SemanticModel/Insights/Market.tsx | 113 ++++++---- .../Insights/components/TagFilter.tsx | 92 ++++++-- .../pages/SemanticModel/Insights/style.less | 2 +- .../src/pages/SemanticModel/Metric/Detail.tsx | 16 +- .../src/pages/SemanticModel/Metric/Market.tsx | 53 +++++ .../SemanticModel/Metric/MetricInfoSider.tsx | 10 +- .../Metric/components/MetricBasicInfo.tsx | 207 ++++++++++++++++++ .../Metric/components/MetricFilter.tsx | 11 +- .../Metric/components/MetricRemark.tsx | 187 ++++++++++++++++ .../Metric/components/MetricTrendSection.tsx | 34 ++- .../src/pages/SemanticModel/Metric/style.less | 51 ++++- .../pages/SemanticModel/OverviewContainer.tsx | 5 +- .../View/components/DefaultSettingForm.tsx | 80 ++++--- .../components/DefaultSettingForm_tag.tsx | 190 ++++++++++++++++ .../View/components/ViewSearchFormModal.tsx | 56 ++--- .../components/ViewSearchFormModal_tag.tsx | 179 +++++++++++++++ .../View/components/ViewTable.tsx | 4 +- .../components/ClassDimensionTable.tsx | 9 +- .../components/ClassMetricTable.tsx | 81 ++++++- .../components/DimensionInfoModal.tsx | 10 +- .../components/DomainManagerTab.tsx | 27 ++- .../components/DomainTreeSelect.tsx | 109 +++++---- .../components/MetricInfoCreateForm.tsx | 18 +- .../components/MetricMeasuresFormTable.tsx | 4 +- .../components/TableColumnRender.tsx | 12 +- .../pages/SemanticModel/components/style.less | 18 +- .../src/pages/SemanticModel/data.d.ts | 7 +- .../src/pages/SemanticModel/service.ts | 60 ++--- 31 files changed, 1364 insertions(+), 301 deletions(-) create mode 100644 webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/components/MetricBasicInfo.tsx create mode 100644 webapp/packages/supersonic-fe/src/pages/SemanticModel/Metric/components/MetricRemark.tsx create mode 100644 webapp/packages/supersonic-fe/src/pages/SemanticModel/View/components/DefaultSettingForm_tag.tsx create mode 100644 webapp/packages/supersonic-fe/src/pages/SemanticModel/View/components/ViewSearchFormModal_tag.tsx diff --git a/webapp/packages/supersonic-fe/config/routes.ts b/webapp/packages/supersonic-fe/config/routes.ts index e867876ff..a052d34a5 100644 --- a/webapp/packages/supersonic-fe/config/routes.ts +++ b/webapp/packages/supersonic-fe/config/routes.ts @@ -40,7 +40,12 @@ const ROUTES = [ name: 'semanticModel', envEnableList: [ENV_KEY.SEMANTIC], }, - + { + path: '/plugin', + name: 'plugin', + component: './ChatPlugin', + envEnableList: [ENV_KEY.CHAT], + }, { path: '/metric', name: 'metric', @@ -93,12 +98,6 @@ const ROUTES = [ ], }, - { - path: '/plugin', - name: 'plugin', - component: './ChatPlugin', - envEnableList: [ENV_KEY.CHAT], - }, { path: '/login', name: 'login', diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceCreateForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceCreateForm.tsx index f1a725dff..9cfc81a24 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceCreateForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceCreateForm.tsx @@ -73,7 +73,7 @@ const DataSourceCreateForm: React.FC = ({ const [tagObjectIdState, setTagObjectIdState] = useState(modelItem?.tagObjectId); const formValRef = useRef(initFormVal as any); const [form] = Form.useForm(); - const { databaseConfigList, selectModelId: modelId, selectDomainId } = domainManger; + const { databaseConfigList, selectModelId: modelId, selectDomainId, domainData } = domainManger; const updateFormVal = (val: any) => { formValRef.current = val; }; @@ -106,7 +106,9 @@ const DataSourceCreateForm: React.FC = ({ const backward = () => setCurrentStep(currentStep - 1); const queryTagObjectList = async () => { - const { code, msg, data } = await getTagObjectList({ domainId: selectDomainId }); + const { code, msg, data } = await getTagObjectList({ + domainId: domainData?.parentId || domainData?.id, + }); if (code === 200) { setTagObjectList(data); diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceFieldForm.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceFieldForm.tsx index 599aca339..16beae74f 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceFieldForm.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Datasource/components/DataSourceFieldForm.tsx @@ -136,7 +136,6 @@ const DataSourceFieldForm: React.FC = ({ width: 185, render: (_: any, record: FieldItem) => { const { type } = record; - console.log(record, 3333); if (type === EnumDataSourceType.PRIMARY) { return ( diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/Market.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/Market.tsx index 95176013e..f52b38bc6 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/Market.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/Market.tsx @@ -6,7 +6,7 @@ import type { Dispatch } from 'umi'; import { connect, useModel } from 'umi'; import type { StateType } from '../model'; import { SENSITIVE_LEVEL_ENUM } from '../constant'; -import { getTagList, deleteTag, batchUpdateTagStatus, getTagObjectList } from '../service'; +import { getTagList, deleteTag, batchDeleteTag, getTagObjectList } from '../service'; import TagFilter from './components/TagFilter'; import TagInfoCreateForm from './components/TagInfoCreateForm'; import { StatusEnum } from '../enum'; @@ -46,9 +46,7 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { const [dataSource, setDataSource] = useState([]); const [tagItem, setTagItem] = useState(); const [selectedRowKeys, setSelectedRowKeys] = useState([]); - const [filterParams, setFilterParams] = useState>({ - showType: localStorage.getItem('metricMarketShowType') === '1' ? true : false, - }); + const [filterParams, setFilterParams] = useState>({}); const [downloadLoading, setDownloadLoading] = useState(false); @@ -66,23 +64,36 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { const { code, msg, data } = await getTagObjectList({}); if (code === 200) { setTagObjectList(data); - const target = data[0]; - if (target) { - queryTagList({ ...filterParams, tagObjectId: target.id }); - } + // const target = data[0]; + // if (target) { + // queryTagList({ ...filterParams, tagObjectId: target.id }); + // } return; } message.error(msg); }; - const queryBatchUpdateStatus = async (ids: React.Key[], status: StatusEnum) => { + // const getTagList = (ids: React.Key[])=>{ + // const filterItem = dataSource.filter((item)=>{ + // return ids.includes(item.id); + // }); + // const dimension = { + + // } + // filterItem.forEach((item)=>{ + + // }) + // } + + const queryBatchDeleteTag = async (ids: React.Key[]) => { if (Array.isArray(ids) && ids.length === 0) { return; } - const { code, msg } = await batchUpdateTagStatus({ - ids, - status, - }); + const { code, msg } = await batchDeleteTag([ + { + ids, + }, + ]); if (code === 200) { queryTagList(filterParams); return; @@ -94,6 +105,11 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { if (!disabledLoading) { setLoading(true); } + if (!params.tagObjectId) { + setLoading(false); + setDataSource([]); + return; + } const { code, data, msg } = await getTagList({ ...pagination, ...params, @@ -191,12 +207,12 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { // }, { dataIndex: 'domainName', - title: '所属主题域', + title: '主题域', search: false, }, { dataIndex: 'tagObjectName', - title: '所属对象', + title: '标签对象', search: false, }, { @@ -221,14 +237,14 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { if (record.hasAdminRes) { return ( - { handleMetricEdit(record); }} > 编辑 - + */} = ({ domainManger, dispatch }) => { // }), }; - const onMenuClick = (key: string) => { - switch (key) { - case 'batchStart': - queryBatchUpdateStatus(selectedRowKeys, StatusEnum.ONLINE); - break; - case 'batchStop': - queryBatchUpdateStatus(selectedRowKeys, StatusEnum.OFFLINE); - break; - default: - break; - } - }; + // const onMenuClick = (key: string) => { + // switch (key) { + // case 'batchStart': + // queryBatchUpdateStatus(selectedRowKeys, StatusEnum.ONLINE); + // break; + // case 'batchStop': + // queryBatchUpdateStatus(selectedRowKeys, StatusEnum.OFFLINE); + // break; + // default: + // break; + // } + // }; return ( <> @@ -322,6 +338,13 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { { + setFilterParams({ + ...filterParams, + ...values, + }); + queryTagList(values); + }} onFiltersChange={(_, values) => { if (_.showType !== undefined) { setLoading(true); @@ -346,22 +369,22 @@ const ClassMetricTable: React.FC = ({ domainManger, dispatch }) => { return false; }} sticky={{ offsetHeader: 0 }} - // rowSelection={{ - // type: 'checkbox', - // ...rowSelection, - // }} - // toolBarRender={() => [ - // { - // queryBatchUpdateStatus(selectedRowKeys, StatusEnum.DELETED); - // }} - // hiddenList={['batchDownload', 'batchStart', 'batchStop']} - // disabledList={hasAllPermission ? [] : ['batchStart', 'batchDelete']} - // onMenuClick={onMenuClick} - // />, - // ]} + rowSelection={{ + type: 'checkbox', + ...rowSelection, + }} + toolBarRender={() => [ + { + queryBatchDeleteTag(selectedRowKeys); + }} + hiddenList={['batchDownload', 'batchStart', 'batchStop']} + disabledList={hasAllPermission ? [] : ['batchStart', 'batchDelete']} + // onMenuClick={onMenuClick} + />, + ]} loading={loading} onChange={(data: any) => { const { current, pageSize, total } = data; diff --git a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/components/TagFilter.tsx b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/components/TagFilter.tsx index fd06e8f23..7a411948d 100644 --- a/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/components/TagFilter.tsx +++ b/webapp/packages/supersonic-fe/src/pages/SemanticModel/Insights/components/TagFilter.tsx @@ -1,7 +1,7 @@ import { Form, Input, Space, Row, Col, Switch, Select } from 'antd'; import StandardFormRow from '@/components/StandardFormRow'; import TagSelect from '@/components/TagSelect'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { SENSITIVE_LEVEL_OPTIONS } from '../../constant'; import { SearchOutlined } from '@ant-design/icons'; import DomainTreeSelect from '../../components/DomainTreeSelect'; @@ -13,10 +13,16 @@ const FormItem = Form.Item; type Props = { tagObjectList: ISemantic.ITagObjectItem[]; initFilterValues?: any; + onFilterInit?: (values: any) => void; onFiltersChange: (_: any, values: any) => void; }; -const TagFilter: React.FC = ({ tagObjectList, initFilterValues = {}, onFiltersChange }) => { +const TagFilter: React.FC = ({ + tagObjectList, + initFilterValues = {}, + onFilterInit, + onFiltersChange, +}) => { const [form] = Form.useForm(); useEffect(() => { @@ -25,16 +31,45 @@ const TagFilter: React.FC = ({ tagObjectList, initFilterValues = {}, onFi }); }, [form]); + const [currentDomainId, setCurrentDomainId] = useState(); + + const [tagObjectOptions, setTagObjectOptions] = useState([]); + + const initState = useRef(false); + useEffect(() => { - const target = tagObjectList?.[0]; - if (!target) { - return; + const options = tagObjectList + .filter((item) => { + if (currentDomainId) { + return item.domainId === currentDomainId; + } else { + return true; + } + }) + .map((item: ISemantic.ITagObjectItem) => { + return { + label: item.name, + value: item.id, + }; + }); + setTagObjectOptions(options); + const target = options[0]; + form.setFieldValue('tagObjectId', target?.value); + + if (currentDomainId && target?.value && !initState.current) { + initState.current = true; + const data = form.getFieldsValue(); + onFilterInit?.({ ...data, tagObjectId: target?.value }); } - form.setFieldValue('tagObjectId', target.id); - }, [tagObjectList]); + }, [currentDomainId, tagObjectList]); + + // useEffect(() => { + // if (currentDomainId) { + // onFilterInit?.(); + // } + // }, [currentDomainId]) const handleValuesChange = (value: any, values: any) => { - localStorage.setItem('metricMarketShowType', !!values.showType ? '1' : '0'); onFiltersChange(value, values); }; @@ -73,6 +108,22 @@ const TagFilter: React.FC = ({ tagObjectList, initFilterValues = {}, onFi if (value.key) { return; } + if (value.domainId) { + setCurrentDomainId(value.domainId); + const options = tagObjectList.filter((item) => { + if (value.domainId) { + return item.domainId === value.domainId; + } else { + return true; + } + }); + handleValuesChange(value, { + ...values, + tagObjectId: options[0]?.id, + }); + return; + } + handleValuesChange(value, values); }} > @@ -108,17 +159,23 @@ const TagFilter: React.FC = ({ tagObjectList, initFilterValues = {}, onFi - + + + { + setCurrentDomainId(value); + }} + /> + + +