[improvement][semantic-fe] Redesigning the indicator homepage to incorporate trend charts and table functionality for indicators (#347)

* [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
This commit is contained in:
tristanliu
2023-11-09 05:37:36 -06:00
committed by GitHub
parent 4e139c837a
commit 18aa14118c
27 changed files with 1654 additions and 916 deletions

View File

@@ -1,27 +1,44 @@
import React, { useEffect, useState } from 'react';
import { Modal, Button } from 'antd';
import { Modal, Button, message } from 'antd';
import DimensionMetricRelationTableTransfer from './DimensionMetricRelationTableTransfer';
import { ISemantic } from '../data';
import { updateExprMetric } from '../service';
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
type Props = {
onCancel: () => void;
open: boolean;
metricItem: ISemantic.IMetricItem;
metricItem?: ISemantic.IMetricItem;
relationsInitialValue?: ISemantic.IDrillDownDimensionItem[];
onSubmit: (relations: ISemantic.IDrillDownDimensionItem[]) => void;
};
const DimensionAndMetricRelationModal: React.FC<Props> = ({
open,
metricItem,
metricItem = {},
relationsInitialValue,
onCancel,
onSubmit,
}) => {
const [relationList, setRelationList] = useState<ISemantic.IDrillDownDimensionItem[]>([]);
const saveMetric = async (relationList: any) => {
const queryParams = {
...metricItem,
relateDimension: {
...(metricItem?.relateDimension || {}),
drillDownDimensions: relationList,
},
};
const { code, msg } = await updateExprMetric(queryParams);
if (code === 200) {
// message.success('编辑指标成功');
// onSubmit?.(queryParams);
return;
}
message.error(msg);
};
const renderFooter = () => {
return (
<>
@@ -30,6 +47,7 @@ const DimensionAndMetricRelationModal: React.FC<Props> = ({
type="primary"
onClick={() => {
onSubmit(relationList);
saveMetric(relationList);
}}
>

View File

@@ -33,7 +33,7 @@ const DimensionMetricRelationTableTransfer: React.FC<Props> = ({
onChange,
}) => {
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const { selectModelId: modelId, selectDomainId } = domainManger;
const { selectModelId: modelId } = domainManger;
const [checkedMap, setCheckedMap] = useState<Record<string, ISemantic.IDrillDownDimensionItem>>(
{},
);
@@ -42,7 +42,7 @@ const DimensionMetricRelationTableTransfer: React.FC<Props> = ({
useEffect(() => {
queryDimensionList();
}, []);
}, [metricItem, relationsInitialValue]);
const queryDimensionList = async () => {
const { code, data, msg } = await getDimensionList({ modelId: metricItem?.modelId || modelId });

View File

@@ -1,5 +1,5 @@
import { DownOutlined, PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { Input, message, Tree, Popconfirm, Space, Tooltip, Row, Col } from 'antd';
import { Input, message, Tree, Popconfirm, Space, Tooltip, Row, Col, Button } from 'antd';
import type { DataNode } from 'antd/lib/tree';
import { useEffect, useState } from 'react';
import type { FC, Key } from 'react';
@@ -119,7 +119,7 @@ const DomainListTree: FC<DomainListProps> = ({
return (
<div className={styles.projectItem}>
<span
className={styles.title}
className={styles.projectItemTitle}
onClick={() => {
handleSelect(id, name);
}}
@@ -180,17 +180,31 @@ const DomainListTree: FC<DomainListProps> = ({
return (
<div className={styles.domainList}>
<Row>
<Col flex="1 1 200px">
<Col flex="1 1 auto">
{/* <Space> */}
<Search
allowClear
className={styles.search}
placeholder="请输入主题域名称进行查询"
onSearch={onSearch}
/>
{/* </Space> */}
</Col>
{createDomainBtnVisible && (
<Col flex="0 1 50px">
<Col flex="0 0 40px" style={{ display: 'flex', alignItems: 'center' }}>
<Tooltip title="新增顶级域">
<Button
type="primary"
icon={<PlusOutlined />}
size="small"
onClick={() => {
setProjectInfoParams({ type: 'top', modelType: 'add' });
setProjectInfoModalVisible(true);
onCreateDomainBtnClick?.();
}}
/>
</Tooltip>
{/* <Tooltip title="新增顶级域">
<PlusCircleOutlined
onClick={() => {
setProjectInfoParams({ type: 'top', modelType: 'add' });
@@ -199,7 +213,7 @@ const DomainListTree: FC<DomainListProps> = ({
}}
className={styles.addBtn}
/>
</Tooltip>
</Tooltip> */}
</Col>
)}
</Row>

View File

@@ -6,7 +6,6 @@ import ClassDataSourceTable from './ClassDataSourceTable';
import ClassDimensionTable from './ClassDimensionTable';
import ClassMetricTable from './ClassMetricTable';
import PermissionSection from './Permission/PermissionSection';
// import DatabaseSection from './Database/DatabaseSection';
import EntitySettingSection from './Entity/EntitySettingSection';
import ChatSettingSection from '../ChatSetting/ChatSettingSection';
import OverView from './OverView';
@@ -16,6 +15,7 @@ import { LeftOutlined } from '@ant-design/icons';
import { ISemantic } from '../data';
import SemanticGraphCanvas from '../SemanticGraphCanvas';
import RecommendedQuestionsSection from '../components/Entity/RecommendedQuestionsSection';
import DatabaseTable from '../components/Database/DatabaseTable';
import type { Dispatch } from 'umi';
@@ -39,10 +39,10 @@ const DomainManagerTab: React.FC<Props> = ({
onMenuChange,
}) => {
const defaultTabKey = 'xflow';
const { selectDomainId, domainList } = domainManger;
const { selectDomainId, domainList, selectModelId } = domainManger;
const tabItem = [
{
label: '模型',
label: '模型管理',
key: 'overview',
children: (
<OverView
@@ -53,16 +53,16 @@ const DomainManagerTab: React.FC<Props> = ({
/>
),
},
// {
// label: '数据库',
// key: 'dataBase',
// children: <DatabaseSection />,
// },
{
label: '权限管理',
key: 'permissonSetting',
children: <PermissionSection permissionTarget={'domain'} />,
},
{
label: '数据库管理',
key: 'database',
children: <DatabaseTable />,
},
].filter((item) => {
const target = domainList.find((domain) => domain.id === selectDomainId);
if (target?.hasEditPermission) {
@@ -76,7 +76,7 @@ const DomainManagerTab: React.FC<Props> = ({
label: '画布',
key: 'xflow',
children: (
<div style={{ width: '100%', marginTop: -20 }}>
<div style={{ width: '100%' }}>
<SemanticGraphCanvas />
</div>
),
@@ -131,20 +131,35 @@ const DomainManagerTab: React.FC<Props> = ({
items={!isModel ? tabItem : isModelItem}
activeKey={activeKey || defaultTabKey}
destroyInactiveTabPane
tabBarExtraContent={
isModel ? (
<Button
type="primary"
icon={<LeftOutlined />}
onClick={() => {
onBackDomainBtnClick?.();
}}
style={{ marginRight: 10 }}
>
</Button>
) : undefined
}
size="large"
tabBarExtraContent={{
left: (
<>
{!!selectModelId && (
<div
className={styles.backBtn}
onClick={() => {
onBackDomainBtnClick?.();
}}
>
<LeftOutlined />
</div>
)}
</>
),
// right: isModel ? (
// <Button
// type="primary"
// icon={<LeftOutlined />}
// onClick={() => {
// onBackDomainBtnClick?.();
// }}
// style={{ marginRight: 10, marginBottom: 5 }}
// >
// 返回主题域
// </Button>
// ) : undefined,
}}
onChange={(menuKey: string) => {
onMenuChange?.(menuKey);
}}

View File

@@ -43,7 +43,7 @@ const EntitySettingSection: React.FC<Props> = ({ domainManger }) => {
}, [modelId]);
return (
<div style={{ width: 800, margin: '0 auto' }}>
<div style={{ width: 800, margin: '20px auto' }}>
<Space direction="vertical" style={{ width: '100%' }} size={20}>
{
<ProCard title="实体" bordered>

View File

@@ -72,7 +72,7 @@ const RecommendedQuestionsSection: React.FC<Props> = ({ domainManger }) => {
}, [modelId]);
return (
<div style={{ width: 800, margin: '0 auto' }}>
<div style={{ width: 800, margin: '20px auto' }}>
<ProCard bordered title="问题推荐列表">
<TextAreaCommonEditList
value={questionData}

View File

@@ -144,6 +144,7 @@ const ModelCreateFormModal: React.FC<ModelCreateFormModalProps> = (props) => {
subTitle={'配置之后,可在指标主页和问答指标卡处选择用来对指标进行下钻和过滤'}
/>
}
hidden={!basicInfo?.id}
>
<Select
mode="multiple"

View File

@@ -10,9 +10,79 @@
min-height: calc(100vh - 48px);
// background: #f8f9fb;
background-color: #fff;
display: flex;
position: relative;
.sider {
flex: 0 0 350px;
border-right: 5px solid #eee;
.domainTitle {
margin-bottom: 0;
font-size: 20px;
border-bottom: 1px solid #f0f0f0;
display: flex;
font-weight: 500;
padding: 12px 0 12px 35px;
}
.addBtn {
cursor: pointer;
width: 100%;
font-size: 18px;
margin-top: 18px;
&:hover {
color: #296DF3;
}
}
.treeTitle {
margin-bottom: 0;
padding: 20px;
line-height: 34px;
text-align: right;
background: #fff;
// border-bottom: 1px solid #d9d9d9;
.title {
float: left;
}
}
.search {
width: calc(100% - 60px);
margin: 10px 0 10px 35px;
}
.tree {
flex: 1;
padding: 10px;
.projectItem {
display: flex;
width: 100%;
cursor: auto;
line-height: 30px;
height: 30px;
.projectItemTitle {
font-size: 16px;
flex: 1;
cursor: pointer;
}
.operation {
.icon {
margin-left: 6px;
cursor: pointer;
}
}
}
}
}
.content {
flex: 1 1 auto;
}
.collapseLeftBtn {
position: absolute;
top: calc(50% + 45px);
@@ -41,20 +111,20 @@
padding: 20px;
padding-left: 30px;
}
.backBtn {
background-color: #f8f8f8;
padding: 5px;
color: #b0b4bc;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
&:hover {
background-color: #7599e5;
color: #fff;
}
}
// .backBtn {
// background-color: #f8f8f8;
// padding: 5px;
// color: #b0b4bc;
// cursor: pointer;
// display: flex;
// justify-content: center;
// align-items: center;
// transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
// &:hover {
// background-color: #7599e5;
// color: #fff;
// }
// }
.tab {
:global {
.ant-tabs-tab-btn {
@@ -66,6 +136,24 @@
.ant-tabs-nav {
margin-bottom: 0;
}
.ant-tabs-tab {
padding-bottom:15px;
}
}
.backBtn {
height: 56px;
background-color: #f8f8f8;
padding: 5px;
color: #b0b4bc;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
&:hover {
background-color: #7599e5;
color: #fff;
}
}
}
.chatSettingSectionTab {
@@ -87,164 +175,42 @@
.ant-card-body {
padding: 0 !important;
}
.ant-tabs-content-holder {
padding-top: 20px;
}
}
.resource {
display: flex;
.tree {
flex: 1;
.headOperation {
.btn {
margin-right: 18px;
}
}
.resourceSearch {
margin: 10px 0;
}
}
.view {
width: 480px;
padding-left: 20px;
}
.selectTypesBtn {
margin-right: 8px;
}
}
}
}
.domainTreeSelect {
// width: 300px;
}
.domainList {
display: flex;
flex-direction: column;
width: 400px;
// width: 400px;
width: 100%;
overflow: hidden;
// min-height: calc(100vh - 48px);
.addBtn {
cursor: pointer;
width: 100%;
font-size: 18px;
margin-top: 18px;
&:hover {
color: #296DF3;
}
}
.treeTitle {
margin-bottom: 0;
padding: 20px;
line-height: 34px;
text-align: right;
background: #fff;
border-bottom: 1px solid #d9d9d9;
.title {
float: left;
}
}
.search {
width: calc(100% - 20px);
margin: 10px;
}
.tree {
flex: 1;
padding: 10px;
.projectItem {
display: flex;
width: 100%;
cursor: auto;
.title {
flex: 1;
cursor: pointer;
}
.operation {
.icon {
margin-left: 6px;
cursor: pointer;
}
}
}
}
}
.user {
display: grid;
}
// .user {
// display: grid;
// }
.search{
width: 50%;
margin-bottom: 20px;
}
.paramsName{
margin-right: 10px;
}
.deleteBtn{
margin-left: 5px;
}
.authBtn{
cursor: pointer;
}
.selectedResource{
font-size: 12px;
color: darkgrey;
margin-top: 4px;
}
// .search{
// width: 50%;
// margin-bottom: 20px;
// }
.switch{
// min-width: 900px;
// max-width: 1200px;
// width: 100%;
display: flex;
justify-content: flex-start;
.switchUser {
width: 200px;
margin-left: 33px;
:global {
.ant-select {
width: 100% !important;
}
}
}
}
.dimensionIntentionForm {
margin-bottom: -24px !important;
margin-top: 10px;
margin-left: 26px;
}
// .authBtn{
// cursor: pointer;
// }
.classTable {
:global {
.ant-pro-table-search-query-filter {
padding-left: 0 !important;
// padding-bottom: 24px !important;
.ant-pro-form-query-filter {
.ant-form-item {
// margin-bottom: 0;
}
}
}
.ant-table-tbody > tr.ant-table-row-selected > td {
background: none;
@@ -275,8 +241,6 @@
padding: 0 11px;
cursor: pointer;
position: relative;
// background-color: #fff;
// border: 1px solid #d9d9d9;
border-radius: 4px;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
color: #000a24d9;