mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-07 12:00:46 +00:00
feat(web): Unified frontend code style (#1923)
Co-authored-by: Fangyin Cheng <staneyffer@gmail.com> Co-authored-by: 谨欣 <echo.cmy@antgroup.com> Co-authored-by: 严志勇 <yanzhiyong@tiansuixiansheng.com> Co-authored-by: yanzhiyong <932374019@qq.com>
This commit is contained in:
@@ -1,25 +1,24 @@
|
||||
import React, { ChangeEvent, Key, useEffect, useMemo, useState } from 'react';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Button, Select, Table, Tooltip } from 'antd';
|
||||
import Icon from '@ant-design/icons';
|
||||
import { Input, Tree } from 'antd';
|
||||
import type { DataNode } from 'antd/es/tree';
|
||||
import MonacoEditor, { ISession } from './monaco-editor';
|
||||
import { sendGetRequest, sendSpacePostRequest } from '@/utils/request';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import Icon from '@ant-design/icons';
|
||||
import { OnChange } from '@monaco-editor/react';
|
||||
import Header from './header';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Button, Input, Select, Table, Tooltip, Tree } from 'antd';
|
||||
import type { DataNode } from 'antd/es/tree';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { ChangeEvent, Key, useEffect, useMemo, useState } from 'react';
|
||||
import Chart from '../chart';
|
||||
import Header from './header';
|
||||
import MonacoEditor, { ISession } from './monaco-editor';
|
||||
|
||||
import SplitScreenHeight from '@/components/icons/split-screen-height';
|
||||
import SplitScreenWeight from '@/components/icons/split-screen-width';
|
||||
import { CaretRightOutlined, LeftOutlined, RightOutlined, SaveFilled } from '@ant-design/icons';
|
||||
import { ColumnType } from 'antd/es/table';
|
||||
import Database from '../icons/database';
|
||||
import TableIcon from '../icons/table';
|
||||
import Field from '../icons/field';
|
||||
import classNames from 'classnames';
|
||||
import MyEmpty from '../common/MyEmpty';
|
||||
import SplitScreenWeight from '@/components/icons/split-screen-width';
|
||||
import SplitScreenHeight from '@/components/icons/split-screen-height';
|
||||
import Database from '../icons/database';
|
||||
import Field from '../icons/field';
|
||||
import TableIcon from '../icons/table';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
@@ -64,20 +63,23 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tab
|
||||
const chartWrapper = useMemo(() => {
|
||||
if (!chartData) return null;
|
||||
return (
|
||||
<div className="flex-1 overflow-auto p-2" style={{ flexShrink: 0, overflow: 'hidden' }}>
|
||||
<div className='flex-1 overflow-auto p-2' style={{ flexShrink: 0, overflow: 'hidden' }}>
|
||||
<Chart chartsData={[chartData]} />
|
||||
</div>
|
||||
);
|
||||
}, [chartData]);
|
||||
|
||||
const { columns, dataSource } = useMemo<{ columns: ColumnType<any>[]; dataSource: Record<string, string | number>[] }>(() => {
|
||||
const { columns, dataSource } = useMemo<{
|
||||
columns: ColumnType<any>[];
|
||||
dataSource: Record<string, string | number>[];
|
||||
}>(() => {
|
||||
const { columns: cols = [], values: vals = [] } = tableData ?? {};
|
||||
const tbCols = cols.map<ColumnType<any>>((item) => ({
|
||||
const tbCols = cols.map<ColumnType<any>>(item => ({
|
||||
key: item,
|
||||
dataIndex: item,
|
||||
title: item,
|
||||
}));
|
||||
const tbDatas = vals.map((row) => {
|
||||
const tbDatas = vals.map(row => {
|
||||
return row.reduce<Record<string, string | number>>((acc, item, index) => {
|
||||
acc[cols[index]] = item;
|
||||
return acc;
|
||||
@@ -90,7 +92,7 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tab
|
||||
};
|
||||
}, [tableData]);
|
||||
const session: ISession = useMemo(() => {
|
||||
const map: Record<string, { columnName: string; columnType: string; }[]> = {};
|
||||
const map: Record<string, { columnName: string; columnType: string }[]> = {};
|
||||
const db = tables?.data;
|
||||
const tableList = db?.children;
|
||||
tableList?.forEach((table: ITableTreeItem) => {
|
||||
@@ -99,11 +101,11 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tab
|
||||
columnName: column.title,
|
||||
columnType: column.type,
|
||||
};
|
||||
})
|
||||
});
|
||||
});
|
||||
return {
|
||||
async getTableList(schemaName: any) {
|
||||
if (schemaName && schemaName!== db?.title) {
|
||||
if (schemaName && schemaName !== db?.title) {
|
||||
return [];
|
||||
}
|
||||
return tableList?.map((table: ITableTreeItem) => table.title) || [];
|
||||
@@ -113,9 +115,9 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tab
|
||||
},
|
||||
async getSchemaList() {
|
||||
return db?.title ? [db?.title] : [];
|
||||
}
|
||||
},
|
||||
};
|
||||
}, [tables])
|
||||
}, [tables]);
|
||||
return (
|
||||
<div
|
||||
className={classNames('flex w-full flex-1 h-full gap-2 overflow-hidden', {
|
||||
@@ -123,14 +125,20 @@ function DbEditorContent({ layout = 'LR', editorValue, chartData, tableData, tab
|
||||
'flex-row': layout === 'LR',
|
||||
})}
|
||||
>
|
||||
<div className="flex-1 flex overflow-hidden rounded">
|
||||
<MonacoEditor value={editorValue?.sql || ''} language="mysql" onChange={handleChange} thoughts={editorValue?.thoughts || ''} session={session} />
|
||||
<div className='flex-1 flex overflow-hidden rounded'>
|
||||
<MonacoEditor
|
||||
value={editorValue?.sql || ''}
|
||||
language='mysql'
|
||||
onChange={handleChange}
|
||||
thoughts={editorValue?.thoughts || ''}
|
||||
session={session}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 h-full overflow-auto bg-white dark:bg-theme-dark-container rounded p-4">
|
||||
{!!tableData?.values.length ? (
|
||||
<div className='flex-1 h-full overflow-auto bg-white dark:bg-theme-dark-container rounded p-4'>
|
||||
{tableData?.values.length ? (
|
||||
<Table bordered scroll={{ x: 'auto' }} rowKey={columns[0].key} columns={columns} dataSource={dataSource} />
|
||||
) : (
|
||||
<div className="h-full flex justify-center items-center">
|
||||
<div className='h-full flex justify-center items-center'>
|
||||
<MyEmpty />
|
||||
</div>
|
||||
)}
|
||||
@@ -157,13 +165,13 @@ function DbEditor() {
|
||||
const id = searchParams?.get('id');
|
||||
const scene = searchParams?.get('scene');
|
||||
|
||||
const { data: rounds, loading: roundsLoading } = useRequest(
|
||||
const { data: rounds } = useRequest(
|
||||
async () =>
|
||||
await sendGetRequest('/v1/editor/sql/rounds', {
|
||||
con_uid: id,
|
||||
}),
|
||||
{
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
const lastItem = res?.data?.[res?.data?.length - 1];
|
||||
if (lastItem) {
|
||||
setCurrentRound(lastItem?.round);
|
||||
@@ -182,7 +190,7 @@ function DbEditor() {
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
setTableData({
|
||||
columns: res?.data?.colunms,
|
||||
values: res?.data?.values,
|
||||
@@ -210,7 +218,7 @@ function DbEditor() {
|
||||
{
|
||||
manual: true,
|
||||
ready: !!newEditorValue?.sql,
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
if (res?.success) {
|
||||
setTableData({
|
||||
columns: res?.data?.sql_data?.colunms || [],
|
||||
@@ -246,7 +254,7 @@ function DbEditor() {
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
if (res?.success) {
|
||||
runSql();
|
||||
}
|
||||
@@ -261,7 +269,7 @@ function DbEditor() {
|
||||
conv_uid: id,
|
||||
chart_title: newEditorValue?.title,
|
||||
db_name,
|
||||
old_sql: editorValue?.[currentTabIndex]?.sql,
|
||||
old_sql: editorValue?.[currentTabIndex ?? 0]?.sql,
|
||||
new_chart_type: newEditorValue?.showcase,
|
||||
new_sql: newEditorValue?.sql,
|
||||
new_comment: newEditorValue?.thoughts?.match(/^\n--(.*)\n\n$/)?.[1]?.trim() || newEditorValue?.thoughts,
|
||||
@@ -270,7 +278,7 @@ function DbEditor() {
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
if (res?.success) {
|
||||
runCharts();
|
||||
}
|
||||
@@ -294,14 +302,14 @@ function DbEditor() {
|
||||
);
|
||||
|
||||
const { run: handleGetEditorSql } = useRequest(
|
||||
async (round) =>
|
||||
async round =>
|
||||
await sendGetRequest('/v1/editor/sql', {
|
||||
con_uid: id,
|
||||
round,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (res) => {
|
||||
onSuccess: res => {
|
||||
let sql = undefined;
|
||||
try {
|
||||
if (Array.isArray(res?.data)) {
|
||||
@@ -346,21 +354,25 @@ function DbEditor() {
|
||||
};
|
||||
const showTitle =
|
||||
index > -1 ? (
|
||||
<Tooltip title={(item?.comment || item?.title) + (item?.can_null === 'YES' ? '(can null)' : `(can't null)`)}>
|
||||
<div className="flex items-center">
|
||||
<Tooltip
|
||||
title={(item?.comment || item?.title) + (item?.can_null === 'YES' ? '(can null)' : `(can't null)`)}
|
||||
>
|
||||
<div className='flex items-center'>
|
||||
{renderIcon(item.type)}
|
||||
{beforeStr}
|
||||
<span className="text-[#1677ff]">{searchValue}</span>
|
||||
<span className='text-[#1677ff]'>{searchValue}</span>
|
||||
{afterStr}
|
||||
{item?.type && <div className="text-gray-400">{item?.type}</div>}
|
||||
{item?.type && <div className='text-gray-400'>{item?.type}</div>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title={(item?.comment || item?.title) + (item?.can_null === 'YES' ? '(can null)' : `(can't null)`)}>
|
||||
<div className="flex items-center">
|
||||
<Tooltip
|
||||
title={(item?.comment || item?.title) + (item?.can_null === 'YES' ? '(can null)' : `(can't null)`)}
|
||||
>
|
||||
<div className='flex items-center'>
|
||||
{renderIcon(item.type)}
|
||||
{strTitle}
|
||||
{item?.type && <div className="text-gray-400">{item?.type}</div>}
|
||||
{item?.type && <div className='text-gray-400'>{item?.type}</div>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -384,7 +396,7 @@ function DbEditor() {
|
||||
}, [searchValue, tables]);
|
||||
|
||||
const dataList = useMemo(() => {
|
||||
let res: { key: string | number; title: string; parentKey?: string | number }[] = [];
|
||||
const res: { key: string | number; title: string; parentKey?: string | number }[] = [];
|
||||
const generateList = (data: DataNode[], parentKey?: string | number) => {
|
||||
if (!data || data?.length <= 0) return;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
@@ -407,7 +419,7 @@ function DbEditor() {
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
const node = tree[i];
|
||||
if (node.children) {
|
||||
if (node.children.some((item) => item.key === key)) {
|
||||
if (node.children.some(item => item.key === key)) {
|
||||
parentKey = node.key;
|
||||
} else if (getParentKey(key, node.children)) {
|
||||
parentKey = getParentKey(key, node.children);
|
||||
@@ -424,7 +436,7 @@ function DbEditor() {
|
||||
setExpandedKeys([]);
|
||||
} else {
|
||||
const newExpandedKeys = dataList
|
||||
.map((item) => {
|
||||
.map(item => {
|
||||
if (item.title.indexOf(value) > -1) {
|
||||
return getParentKey(item.key, treeData);
|
||||
}
|
||||
@@ -471,20 +483,20 @@ function DbEditor() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full overflow-hidden">
|
||||
<div className='flex flex-col w-full h-full overflow-hidden'>
|
||||
<Header />
|
||||
<div className="relative flex flex-1 p-4 pt-0 overflow-hidden">
|
||||
<div className="relative flex overflow-hidden mr-4">
|
||||
<div className='relative flex flex-1 p-4 pt-0 overflow-hidden'>
|
||||
<div className='relative flex overflow-hidden mr-4'>
|
||||
<div
|
||||
className={classNames('h-full relative transition-[width] overflow-hidden', {
|
||||
'w-0': isMenuExpand,
|
||||
'w-64': !isMenuExpand,
|
||||
})}
|
||||
>
|
||||
<div className="relative w-64 h-full overflow-hidden flex flex-col rounded bg-white dark:bg-theme-dark-container p-4">
|
||||
<div className='relative w-64 h-full overflow-hidden flex flex-col rounded bg-white dark:bg-theme-dark-container p-4'>
|
||||
<Select
|
||||
size="middle"
|
||||
className="w-full mb-2"
|
||||
size='middle'
|
||||
className='w-full mb-2'
|
||||
value={currentRound}
|
||||
options={rounds?.data?.map((item: RoundProps) => {
|
||||
return {
|
||||
@@ -492,13 +504,13 @@ function DbEditor() {
|
||||
value: item.round,
|
||||
};
|
||||
})}
|
||||
onChange={(e) => {
|
||||
onChange={e => {
|
||||
setCurrentRound(e);
|
||||
}}
|
||||
/>
|
||||
<Search className="mb-2" placeholder="Search" onChange={onChange} />
|
||||
<Search className='mb-2' placeholder='Search' onChange={onChange} />
|
||||
{treeData && treeData.length > 0 && (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className='flex-1 overflow-y-auto'>
|
||||
<Tree
|
||||
onExpand={(newExpandedKeys: Key[]) => {
|
||||
setExpandedKeys(newExpandedKeys);
|
||||
@@ -515,9 +527,9 @@ function DbEditor() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute right-0 top-0 translate-x-full h-full flex items-center justify-center opacity-0 hover:opacity-100 group-hover/side:opacity-100 transition-opacity">
|
||||
<div className='absolute right-0 top-0 translate-x-full h-full flex items-center justify-center opacity-0 hover:opacity-100 group-hover/side:opacity-100 transition-opacity'>
|
||||
<div
|
||||
className="bg-white w-4 h-10 flex items-center justify-center dark:bg-theme-dark-container rounded-tr rounded-br z-10 text-xs cursor-pointer shadow-[4px_0_10px_rgba(0,0,0,0.06)] text-opacity-80"
|
||||
className='bg-white w-4 h-10 flex items-center justify-center dark:bg-theme-dark-container rounded-tr rounded-br z-10 text-xs cursor-pointer shadow-[4px_0_10px_rgba(0,0,0,0.06)] text-opacity-80'
|
||||
onClick={() => {
|
||||
setIsMenuExpand(!isMenuExpand);
|
||||
}}
|
||||
@@ -526,14 +538,14 @@ function DbEditor() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 max-w-full overflow-hidden">
|
||||
<div className='flex flex-col flex-1 max-w-full overflow-hidden'>
|
||||
{/* Actions */}
|
||||
<div className="mb-2 bg-white dark:bg-theme-dark-container p-2 flex justify-between items-center">
|
||||
<div className="flex gap-2">
|
||||
<div className='mb-2 bg-white dark:bg-theme-dark-container p-2 flex justify-between items-center'>
|
||||
<div className='flex gap-2'>
|
||||
<Button
|
||||
className="text-xs rounded-none"
|
||||
size="small"
|
||||
type="primary"
|
||||
className='text-xs rounded-none'
|
||||
size='small'
|
||||
type='primary'
|
||||
icon={<CaretRightOutlined />}
|
||||
loading={runLoading || runChartsLoading}
|
||||
onClick={async () => {
|
||||
@@ -547,9 +559,9 @@ function DbEditor() {
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
className="text-xs rounded-none"
|
||||
type="primary"
|
||||
size="small"
|
||||
className='text-xs rounded-none'
|
||||
type='primary'
|
||||
size='small'
|
||||
loading={submitLoading || submitChartLoading}
|
||||
icon={<SaveFilled />}
|
||||
onClick={async () => {
|
||||
@@ -563,7 +575,7 @@ function DbEditor() {
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className='flex gap-2'>
|
||||
<Icon
|
||||
className={classNames('flex items-center justify-center w-6 h-6 text-lg rounded', {
|
||||
'bg-theme-primary bg-opacity-10': layout === 'TB',
|
||||
@@ -586,10 +598,10 @@ function DbEditor() {
|
||||
</div>
|
||||
{/* Panel */}
|
||||
{Array.isArray(editorValue) ? (
|
||||
<div className="flex flex-col h-full overflow-hidden">
|
||||
<div className="w-full whitespace-nowrap overflow-x-auto bg-white dark:bg-theme-dark-container mb-2 text-[0px]">
|
||||
<div className='flex flex-col h-full overflow-hidden'>
|
||||
<div className='w-full whitespace-nowrap overflow-x-auto bg-white dark:bg-theme-dark-container mb-2 text-[0px]'>
|
||||
{editorValue.map((item, index) => (
|
||||
<Tooltip className="inline-block" key={item.title} title={item.title}>
|
||||
<Tooltip className='inline-block' key={item.title} title={item.title}>
|
||||
<div
|
||||
className={classNames(
|
||||
'max-w-[240px] px-3 h-10 text-ellipsis overflow-hidden whitespace-nowrap text-sm leading-10 cursor-pointer font-semibold hover:text-theme-primary transition-colors mr-2 last-of-type:mr-0',
|
||||
@@ -607,7 +619,7 @@ function DbEditor() {
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
<div className='flex flex-1 overflow-hidden'>
|
||||
{editorValue.map((item, index) => (
|
||||
<div
|
||||
key={item.title}
|
||||
@@ -619,9 +631,9 @@ function DbEditor() {
|
||||
<DbEditorContent
|
||||
layout={layout}
|
||||
editorValue={item}
|
||||
handleChange={(value) => {
|
||||
handleChange={value => {
|
||||
const { sql, thoughts } = resolveSqlAndThoughts(value);
|
||||
setNewEditorValue((old) => {
|
||||
setNewEditorValue(old => {
|
||||
return Object.assign({}, old, {
|
||||
sql,
|
||||
thoughts,
|
||||
@@ -639,9 +651,9 @@ function DbEditor() {
|
||||
<DbEditorContent
|
||||
layout={layout}
|
||||
editorValue={editorValue}
|
||||
handleChange={(value) => {
|
||||
handleChange={value => {
|
||||
const { sql, thoughts } = resolveSqlAndThoughts(value);
|
||||
setNewEditorValue((old) => {
|
||||
setNewEditorValue(old => {
|
||||
return Object.assign({}, old, {
|
||||
sql,
|
||||
thoughts,
|
||||
|
Reference in New Issue
Block a user