Merge fixes and improvements (#1910)

Co-authored-by: tristanliu <tristanliu@tencent.com>
This commit is contained in:
Jun Zhang
2024-11-16 13:57:54 +08:00
committed by GitHub
parent 5e22b412c6
commit ba1938f04b
40 changed files with 1382 additions and 2784 deletions

View File

@@ -1,10 +1,12 @@
import { Spin, Switch, Tooltip } from 'antd';
import { Space, Spin, Switch, Tooltip, message } from 'antd';
import { CheckCircleFilled, InfoCircleOutlined } from '@ant-design/icons';
import { PREFIX_CLS, MsgContentTypeEnum } from '../../common/constants';
import { MsgDataType } from '../../common/type';
import ChatMsg from '../ChatMsg';
import WebPage from '../ChatMsg/WebPage';
import Loading from './Loading';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { solarizedlight } from 'react-syntax-highlighter/dist/esm/styles/prism';
import React, { ReactNode, useState } from 'react';
type Props = {
@@ -43,10 +45,10 @@ const ExecuteItem: React.FC<Props> = ({
const prefixCls = `${PREFIX_CLS}-item`;
const [showMsgContentTable, setShowMsgContentTable] = useState<boolean>(false);
const [msgContentType, setMsgContentType] = useState<MsgContentTypeEnum>();
const [showErrMsg, setShowErrMsg] = useState<boolean>(false);
const titlePrefix = queryMode === 'PLAIN_TEXT' || queryMode === 'WEB_SERVICE' ? '问答' : '数据';
const getNodeTip = (title: ReactNode, tip?: string) => {
const getNodeTip = (title: ReactNode, tip?: string | ReactNode) => {
return (
<>
<div className={`${prefixCls}-title-bar`}>
@@ -65,21 +67,38 @@ const ExecuteItem: React.FC<Props> = ({
return getNodeTip(`${titlePrefix}查询中`);
}
const handleCopy = (_: string, result: any) => {
result ? message.success('复制SQL成功', 1) : message.error('复制SQL失败', 1);
};
if (executeTip) {
return getNodeTip(
<>
<span>{titlePrefix}</span>
{executeErrorMsg && (
<Tooltip title={executeErrorMsg}>
<Space>
<InfoCircleOutlined style={{ marginLeft: 5, color: 'red' }} />
</Tooltip>
<a
onClick={() => {
setShowErrMsg(!showErrMsg);
}}
>
{!showErrMsg ? '查看' : '收起'}
</a>
</Space>
)}
{!!data?.queryTimeCost && isDeveloper && (
<span className={`${prefixCls}-title-tip`}>(: {data.queryTimeCost}ms)</span>
)}
</>,
executeTip
<>
{showErrMsg && (
<SyntaxHighlighter className={`${prefixCls}-code`} language="sql" style={solarizedlight}>
{executeErrorMsg}
</SyntaxHighlighter>
)}
</>
);
}

View File

@@ -443,7 +443,6 @@ const ChatItem: React.FC<Props> = ({
: ''}
</div>
<div className={contentClass}>
{/* {!isSimpleMode && ( */}
<>
{currentAgent?.enableFeedback === 1 && !questionId && showExpandParseTip && (
<div style={{ marginBottom: 10 }}>
@@ -489,7 +488,6 @@ const ChatItem: React.FC<Props> = ({
/>
)}
</>
{/* )} */}
{executeMode && (
<Spin spinning={entitySwitchLoading}>

View File

@@ -207,6 +207,15 @@
color: var(--text-color);
}
&-code {
margin-top: 10px !important;
padding: 6px 14px 8px !important;
border: 1px solid var(--border-color-base) !important;
border-radius: 4px !important;
background: #f5f8fb !important;
max-width: calc(100vw - 410px);
}
&-execute-title-bar {
display: flex;
align-items: center;

View File

@@ -13,11 +13,12 @@ import moment from 'moment';
type Props = {
data: MsgDataType;
size?: SizeType;
question: string;
loading?: boolean;
onApplyAuth?: (model: string) => void;
};
const Table: React.FC<Props> = ({ data, size, loading, onApplyAuth }) => {
const Table: React.FC<Props> = ({ data, size, loading, question, onApplyAuth }) => {
const { entityInfo, queryColumns, queryResults } = data;
const prefixCls = `${CLS_PREFIX}-table`;
@@ -27,6 +28,13 @@ const Table: React.FC<Props> = ({ data, size, loading, onApplyAuth }) => {
dataIndex: nameEn,
key: nameEn,
title: name || nameEn,
defaultSortOrder: 'descend',
sorter:
showType === 'NUMBER'
? (a, b) => {
return a[nameEn] - b[nameEn];
}
: undefined,
render: (value: string | number) => {
if (!authorized) {
return (
@@ -76,9 +84,11 @@ const Table: React.FC<Props> = ({ data, size, loading, onApplyAuth }) => {
const dataSource = dateColumn
? queryResults.sort((a, b) => moment(a[dateColumn.nameEn]).diff(moment(b[dateColumn.nameEn])))
: queryResults;
return (
<div className={prefixCls}>
<div className={`${prefixCls}-top-bar`}>
<div className={`${prefixCls}-indicator-name`}>{question}</div>
</div>
<AntTable
pagination={
queryResults.length <= 10 ? false : { defaultPageSize: 10, position: ['bottomCenter'] }

View File

@@ -26,6 +26,22 @@
color: var(--text-color-third);
}
&-top-bar {
display: flex;
align-items: baseline;
flex-wrap: wrap;
column-gap: 8px;
row-gap: 12px;
font-style: italic;
margin-bottom: 15px;
}
&-indicator-name {
font-size: 14px;
color: var(--text-color);
font-weight: 500;
margin-top: 2px;
}
&-filter-item {
display: flex;
align-items: center;

View File

@@ -180,6 +180,7 @@ const ChatMsg: React.FC<Props> = ({
case MsgContentTypeEnum.TABLE:
return (
<Table
question={question}
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
loading={loading}
/>
@@ -221,6 +222,7 @@ const ChatMsg: React.FC<Props> = ({
default:
return (
<Table
question={question}
data={{ ...data, queryColumns: columns, queryResults: dataSource }}
loading={loading}
/>

View File

@@ -18,6 +18,7 @@ export default defineConfig({
API_BASE_URL: '/api/semantic/', // 直接在define中挂载裸露的全局变量还需要配置eslintts相关配置才能导致在使用中不会飘红冗余较高这里挂在进程环境下
CHAT_API_BASE_URL: '/api/chat/',
AUTH_API_BASE_URL: '/api/auth/',
SHOW_TAG: false,
...ENV_CONFIG,
},
},

View File

@@ -115,12 +115,12 @@ const ROUTES = [
},
],
},
{
path: '/tag',
name: 'tag',
component: './SemanticModel/Insights',
envEnableList: [ENV_KEY.SEMANTIC],
hideInMenu: process.env.SHOW_TAG ? false : true,
routes: [
{
path: '/tag',

View File

@@ -69,7 +69,7 @@
"@umijs/route-utils": "2.2.2",
"ace-builds": "^1.4.12",
"ahooks": "^3.7.7",
"antd": "5.11.2",
"antd": "^5.17.4",
"classnames": "^2.2.6",
"compression-webpack-plugin": "^11.0.0",
"copy-to-clipboard": "^3.3.1",

View File

@@ -38,6 +38,7 @@ const BatchCtrlDropDownButton: FC<BatchCtrlDropDownButtonProps> = ({
exportTagButton: {
key: 'exportTagButton',
label: '导出为标签',
hidden: !!!process.env.SHOW_TAG,
icon: <ExportOutlined />,
disabled: disabledList?.includes('exportTagButton'),
},
@@ -142,9 +143,11 @@ const BatchCtrlDropDownButton: FC<BatchCtrlDropDownButtonProps> = ({
icon: <DeleteOutlined />,
disabled: disabledList?.includes('batchDelete'),
},
].filter((item) => {
return !hiddenList.includes(item.key);
});
]
.filter((item) => {
return !hiddenList.includes(item.key);
})
.filter((item) => !!!item.hidden);
const popoverConfig = {
title: '选择下载区间',

View File

@@ -217,7 +217,11 @@ const MemorySection = ({ agentId }: Props) => {
};
const loadMemoryList = async (
{ filtersValue, current }: { filtersValue?: any; current?: number } = {},
{
filtersValue,
current,
pageSize,
}: { filtersValue?: any; current?: number; pageSize?: number } = {},
sort?: any,
) => {
if (!agentId) {
@@ -249,10 +253,11 @@ const MemorySection = ({ agentId }: Props) => {
agentId,
chatMemoryFilter: filtersValue || filters,
current: current || 1,
pageSize,
...sortParams,
});
setLoading(false);
const { list, total, pageSize, pageNum } = res.data;
const { list, total, pageNum } = res.data;
setDataSource(list);
setPagination({
pageSize,

View File

@@ -35,15 +35,20 @@ export function getMetricList(modelId: number) {
});
}
export function getMemeoryList(data: { agentId: number; chatMemoryFilter: any; current: number }) {
const { agentId, chatMemoryFilter, current } = data;
export function getMemeoryList(data: {
agentId: number;
chatMemoryFilter: any;
current: number;
pageSize: number;
}) {
const { agentId, chatMemoryFilter, current, pageSize } = data;
return request<Result<{ list: MetricType[] }>>('/api/chat/memory/pageMemories', {
method: 'POST',
data: {
...data,
chatMemoryFilter: { agentId, ...chatMemoryFilter },
current,
pageSize: 10,
pageSize: pageSize || 10,
sort: 'desc',
// orderCondition: 'updatedAt',
},

View File

@@ -190,14 +190,14 @@ const ModelBasicForm: React.FC<Props> = ({
<FormItem name="description" label="模型描述">
<TextArea placeholder="请输入模型描述" />
</FormItem>
<FormItem name={['ext', 'usId']} label="调度任务ID">
{/* <FormItem name={['ext', 'usId']} label="调度任务ID">
<Select
mode="tags"
placeholder="输入ID后回车确认多ID输入、复制粘贴支持英文逗号自动分隔"
tokenSeparators={[',']}
maxTagCount={9}
/>
</FormItem>
</FormItem> */}
</Spin>
);
};

View File

@@ -229,7 +229,9 @@ const ModelFieldForm: React.FC<Props> = ({
);
}
if (type === EnumDataSourceType.MEASURES) {
const agg = fields.find((field) => field.expr === record.expr)?.agg;
const agg = record.expr
? fields.find((field) => field.expr === record.expr)?.agg
: undefined;
return (
<Select
placeholder="度量算子"
@@ -249,26 +251,52 @@ const ModelFieldForm: React.FC<Props> = ({
</Select>
);
}
if (type === EnumDataSourceType.CATEGORICAL) {
const isTag = fields.find((field) => field.bizName === record.bizName)?.isTag;
return (
<Space>
if (process.env.SHOW_TAG) {
if (type === EnumDataSourceType.CATEGORICAL) {
const isTag = fields.find((field) => field.bizName === record.bizName)?.isTag;
return (
<Space>
<span>:</span>
<Switch
defaultChecked
size="small"
checked={!!isTag}
onChange={(value) => {
handleFieldChange(record, 'isTag', value);
}}
/>
<Tooltip title="如果勾选,代表维度的取值都是一种“标签”,可用作对实体的圈选">
<ExclamationCircleOutlined />
</Tooltip>
<Space>
<span>:</span>
<Switch
defaultChecked
size="small"
checked={!!isTag}
onChange={(value) => {
handleFieldChange(record, 'isTag', value);
}}
/>
<Tooltip title="如果勾选,代表维度的取值都是一种“标签”,可用作对实体的圈选">
<ExclamationCircleOutlined />
</Tooltip>
</Space>
</Space>
</Space>
);
);
}
}
if (process.env.SHOW_TAG) {
if (type === EnumDataSourceType.CATEGORICAL) {
const isTag = fields.find((field) => field.bizName === record.bizName)?.isTag;
return (
<Space>
<Space>
<span>:</span>
<Switch
defaultChecked
size="small"
checked={!!isTag}
onChange={(value) => {
handleFieldChange(record, 'isTag', value);
}}
/>
<Tooltip title="如果勾选,代表维度的取值都是一种“标签”,可用作对实体的圈选">
<ExclamationCircleOutlined />
</Tooltip>
</Space>
</Space>
);
}
}
if ([EnumDataSourceType.TIME, EnumDataSourceType.PARTITION_TIME].includes(type)) {
const dateFormat = fields.find((field) => field.bizName === record.bizName)?.dateFormat;

View File

@@ -33,14 +33,14 @@ export const modelDataClass = {
};
export const DIM_OPTIONS = [
{
label: '主键',
value: EnumDataSourceType.PRIMARY_KEY,
},
{
label: '外键',
value: EnumDataSourceType.FOREIGN_KEY,
},
// {
// label: '主键',
// value: EnumDataSourceType.PRIMARY_KEY,
// },
// {
// label: '外键',
// value: EnumDataSourceType.FOREIGN_KEY,
// },
{
label: '枚举',
value: EnumDataSourceType.CATEGORICAL,

View File

@@ -78,6 +78,9 @@ const TagInfoCreateForm: React.FC<CreateFormProps> = ({
const backward = () => setCurrentStep(currentStep - 1);
const queryModelDetail = async (modelId) => {
if (!modelId) {
return;
}
const { code, data } = await getModelDetail({ modelId });
if (code === 200) {
if (Array.isArray(data?.modelDetail?.fields)) {

View File

@@ -728,6 +728,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
<FormItem
name="isTag"
valuePropName="checked"
hidden={!!!process.env.SHOW_TAG}
getValueFromEvent={(value) => {
return value === true ? 1 : 0;
}}
@@ -749,8 +750,9 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
<Switch />
</Col>
</Row>
<Divider />
</FormItem>
<Divider />
<FormItem>
<Row gutter={20}>
<Col flex="1 1 200px">

View File

@@ -48,6 +48,9 @@ const ModelRelationFormDrawer: React.FC<ModelRelationFormDrawerProps> = ({
}, [relationData]);
const queryModelDetail = async (modelId: number, isSource: boolean) => {
if (!modelId) {
return;
}
const { code, data } = await getModelDetail({ modelId });
if (code === 200) {
if (Array.isArray(data?.modelDetail?.identifiers)) {

View File

@@ -172,6 +172,7 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
dataIndex: 'isTag',
title: '是否标签',
// width: 90,
hideInTable: !!!process.env.SHOW_TAG,
render: (isTag) => {
switch (isTag) {
case 0:
@@ -324,66 +325,69 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
headerTitle={
<div style={{ marginLeft: 15 }}>
<TableHeaderFilter
components={[
{
label: '维度搜索',
component: (
<Input.Search
style={{ width: 280 }}
placeholder="请输入ID/维度名称/英文名称"
onSearch={(value) => {
setFilterParams((preState) => {
return {
...preState,
key: value,
};
});
}}
/>
),
},
{
label: '敏感度',
component: (
<Select
style={{ width: 140 }}
options={SENSITIVE_LEVEL_OPTIONS}
placeholder="请选择敏感度"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
sensitiveLevel: value,
};
});
}}
/>
),
},
{
label: '是否为标签',
component: (
<Select
style={{ width: 145 }}
placeholder="请选择标签状态"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
isTag: value,
};
});
}}
options={[
{ value: 1, label: '是' },
{ value: 0, label: '否' },
]}
/>
),
},
]}
components={
[
{
label: '维度搜索',
component: (
<Input.Search
style={{ width: 280 }}
placeholder="请输入ID/维度名称/英文名称"
onSearch={(value) => {
setFilterParams((preState) => {
return {
...preState,
key: value,
};
});
}}
/>
),
},
{
label: '敏感度',
component: (
<Select
style={{ width: 140 }}
options={SENSITIVE_LEVEL_OPTIONS}
placeholder="请选择敏感度"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
sensitiveLevel: value,
};
});
}}
/>
),
},
{
label: '是否为标签',
hidden: !!!process.env.SHOW_TAG,
component: (
<Select
style={{ width: 145 }}
placeholder="请选择标签状态"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
isTag: value,
};
});
}}
options={[
{ value: 1, label: '是' },
{ value: 0, label: '否' },
]}
/>
),
},
].filter((item) => !!!item.hidden) as any
}
/>
</div>
}

View File

@@ -177,7 +177,7 @@ const ClassMetricTable: React.FC<Props> = ({ onEmptyMetricData }) => {
{
dataIndex: 'isTag',
title: '是否标签',
// width: 90,
hideInTable: !!!process.env.SHOW_TAG,
render: (isTag) => {
switch (isTag) {
case 0:
@@ -353,66 +353,69 @@ const ClassMetricTable: React.FC<Props> = ({ onEmptyMetricData }) => {
headerTitle={
<div style={{ marginLeft: 15 }}>
<TableHeaderFilter
components={[
{
label: '指标搜索',
component: (
<Input.Search
style={{ width: 280 }}
placeholder="请输入ID/指标名称/英文名称/标签"
onSearch={(value) => {
setFilterParams((preState) => {
return {
...preState,
key: value,
};
});
}}
/>
),
},
{
label: '敏感度',
component: (
<Select
style={{ width: 140 }}
options={SENSITIVE_LEVEL_OPTIONS}
placeholder="请选择敏感度"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
sensitiveLevel: value,
};
});
}}
/>
),
},
{
label: '是否为标签',
component: (
<Select
style={{ width: 145 }}
placeholder="请选择标签状态"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
isTag: value,
};
});
}}
options={[
{ value: 1, label: '是' },
{ value: 0, label: '否' },
]}
/>
),
},
]}
components={
[
{
label: '指标搜索',
component: (
<Input.Search
style={{ width: 280 }}
placeholder="请输入ID/指标名称/英文名称"
onSearch={(value) => {
setFilterParams((preState) => {
return {
...preState,
key: value,
};
});
}}
/>
),
},
{
label: '敏感度',
component: (
<Select
style={{ width: 140 }}
options={SENSITIVE_LEVEL_OPTIONS}
placeholder="请选择敏感度"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
sensitiveLevel: value,
};
});
}}
/>
),
},
{
label: '是否为标签',
hidden: !!!process.env.SHOW_TAG,
component: (
<Select
style={{ width: 145 }}
placeholder="请选择标签状态"
allowClear
onChange={(value) => {
setFilterParams((preState) => {
return {
...preState,
isTag: value,
};
});
}}
options={[
{ value: 1, label: '是' },
{ value: 0, label: '否' },
]}
/>
),
},
].filter((item) => !!!item.hidden) as any
}
/>
</div>
}

View File

@@ -305,6 +305,7 @@ const DimensionInfoModal: React.FC<CreateFormProps> = ({
<InfoTagList />
</FormItem> */}
<Form.Item
hidden={!!!process.env.SHOW_TAG}
label={
<FormItemTitle
title={`设为标签`}

View File

@@ -73,7 +73,7 @@ const DomainManagerTab: React.FC<Props> = ({
{
label: '标签对象管理',
key: 'tagObjectManage',
hidden: !!domainData?.parentId,
hidden: !!!process.env.SHOW_TAG ? true : !!domainData?.parentId,
children: <TagObjectTable />,
},
{

View File

@@ -53,7 +53,7 @@ const DimensionMetricVisibleTableTransfer: React.FC<Props> = ({
{
dataIndex: 'isTag',
title: '是否标签',
// hidden: true,
hidden: true,
render: (isTag) => {
if (isTag) {
return <span style={{ color: '#0958d9' }}></span>;

View File

@@ -213,7 +213,7 @@ const DimensionValueSettingForm: React.FC<Props> = ({
>
{dimensionVisible && (
<Space size={20} style={{ marginBottom: 20 }}>
<Tooltip title={`立即将${KnowledgeConfigTypeWordingMap[type]}值导入字典`}>
<Tooltip title={`维度值可见后将定期启动导入任务,如果想立即启动可手动触发`}>
<Button
type="link"
size="small"

View File

@@ -713,6 +713,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
</FormItem>
<Form.Item
hidden={!!!process.env.SHOW_TAG}
label={
<FormItemTitle
title={`设为标签`}

View File

@@ -452,6 +452,9 @@ export function getUnAvailableItem(data: any): Promise<any> {
}
export function getModelDetail(data: any): Promise<any> {
if (!data.modelId) {
return;
}
return request.get(`${process.env.API_BASE_URL}model/getModel/${data.modelId}`);
}

3568
webapp/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff