@lobehub/chat 1.51.1 → 1.51.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/Dockerfile +1 -1
- package/Dockerfile.database +1 -1
- package/changelog/v1.json +21 -0
- package/docs/usage/providers/wenxin.mdx +16 -13
- package/docs/usage/providers/wenxin.zh-CN.mdx +11 -8
- package/next.config.ts +6 -0
- package/package.json +1 -2
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +2 -4
- package/src/config/aiModels/ai360.ts +22 -2
- package/src/config/aiModels/fireworksai.ts +3 -0
- package/src/config/aiModels/giteeai.ts +60 -0
- package/src/config/aiModels/github.ts +7 -0
- package/src/config/aiModels/google.ts +2 -0
- package/src/config/aiModels/groq.ts +12 -0
- package/src/config/aiModels/huggingface.ts +6 -0
- package/src/config/aiModels/internlm.ts +19 -2
- package/src/config/aiModels/ollama.ts +1 -0
- package/src/config/aiModels/openai.ts +10 -0
- package/src/config/aiModels/perplexity.ts +3 -0
- package/src/config/aiModels/qwen.ts +2 -0
- package/src/config/aiModels/siliconcloud.ts +4 -0
- package/src/config/aiModels/togetherai.ts +64 -1
- package/src/config/aiModels/wenxin.ts +125 -19
- package/src/config/aiModels/zhipu.ts +3 -0
- package/src/config/llm.ts +3 -5
- package/src/config/modelProviders/wenxin.ts +100 -23
- package/src/const/auth.ts +0 -3
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +0 -3
- package/src/features/Conversation/components/ChatItem/utils.test.ts +284 -0
- package/src/features/Conversation/components/ChatItem/utils.ts +39 -8
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/rehypePlugin.test.ts +125 -0
- package/src/features/DevPanel/CacheViewer/DataTable/index.tsx +33 -0
- package/src/features/DevPanel/CacheViewer/cacheProvider.tsx +64 -0
- package/src/features/DevPanel/CacheViewer/getCacheEntries.ts +52 -0
- package/src/features/DevPanel/CacheViewer/index.tsx +25 -0
- package/src/features/DevPanel/CacheViewer/schema.ts +49 -0
- package/src/features/DevPanel/FeatureFlagViewer/Form.tsx +93 -0
- package/src/features/DevPanel/FeatureFlagViewer/index.tsx +11 -0
- package/src/features/DevPanel/MetadataViewer/Ld.tsx +25 -0
- package/src/features/DevPanel/MetadataViewer/MetaData.tsx +30 -0
- package/src/features/DevPanel/MetadataViewer/Og.tsx +75 -0
- package/src/features/DevPanel/MetadataViewer/index.tsx +80 -0
- package/src/features/DevPanel/MetadataViewer/useHead.ts +16 -0
- package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +39 -49
- package/src/features/DevPanel/PostgresViewer/{TableColumns.tsx → SchemaSidebar/Columns.tsx} +6 -4
- package/src/features/DevPanel/PostgresViewer/{Schema.tsx → SchemaSidebar/index.tsx} +49 -55
- package/src/features/DevPanel/PostgresViewer/index.tsx +4 -2
- package/src/features/DevPanel/features/FloatPanel.tsx +218 -0
- package/src/features/DevPanel/features/Header.tsx +50 -0
- package/src/features/DevPanel/features/Table/TableCell.tsx +73 -0
- package/src/features/DevPanel/features/Table/TooltipContent.tsx +39 -0
- package/src/features/DevPanel/{PostgresViewer/DataTable/Table.tsx → features/Table/index.tsx} +12 -14
- package/src/features/DevPanel/index.tsx +29 -5
- package/src/libs/agent-runtime/AgentRuntime.test.ts +0 -1
- package/src/libs/agent-runtime/AgentRuntime.ts +7 -0
- package/src/libs/agent-runtime/wenxin/index.ts +10 -107
- package/src/locales/default/modelProvider.ts +0 -20
- package/src/server/modules/AgentRuntime/index.test.ts +0 -21
- package/src/services/_auth.ts +0 -14
- package/src/store/chat/slices/portal/selectors.test.ts +169 -3
- package/src/store/chat/slices/portal/selectors.ts +6 -1
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -2
- package/src/types/aiProvider.ts +0 -1
- package/src/types/user/settings/keyVaults.ts +1 -6
- package/src/app/(backend)/webapi/chat/wenxin/route.test.ts +0 -27
- package/src/app/(backend)/webapi/chat/wenxin/route.ts +0 -30
- package/src/app/(main)/settings/llm/ProviderList/Wenxin/index.tsx +0 -44
- package/src/app/(main)/settings/provider/(detail)/wenxin/page.tsx +0 -61
- package/src/features/Conversation/Error/APIKeyForm/Wenxin.tsx +0 -49
- package/src/features/DevPanel/FloatPanel.tsx +0 -136
- package/src/features/DevPanel/PostgresViewer/DataTable/TableCell.tsx +0 -34
- package/src/libs/agent-runtime/utils/streams/wenxin.test.ts +0 -153
- package/src/libs/agent-runtime/utils/streams/wenxin.ts +0 -38
- package/src/libs/agent-runtime/wenxin/type.ts +0 -84
@@ -0,0 +1,49 @@
|
|
1
|
+
import { z } from 'zod';
|
2
|
+
|
3
|
+
const unstableCacheFileSchema = z.object({
|
4
|
+
data: z.object({
|
5
|
+
body: z.string(),
|
6
|
+
headers: z.object({}).transform(() => null),
|
7
|
+
status: z.number(),
|
8
|
+
url: z.literal(''),
|
9
|
+
}),
|
10
|
+
kind: z.union([z.literal('FETCH'), z.unknown()]),
|
11
|
+
revalidate: z.number().optional(),
|
12
|
+
tags: z.array(z.string()).optional().default([]),
|
13
|
+
});
|
14
|
+
|
15
|
+
const fetchCacheFileSchema = z.object({
|
16
|
+
data: z.object({
|
17
|
+
body: z.string(),
|
18
|
+
headers: z.record(z.string(), z.string()),
|
19
|
+
status: z.number(),
|
20
|
+
url: z.string().url(),
|
21
|
+
}),
|
22
|
+
id: z.string(),
|
23
|
+
kind: z.union([z.literal('FETCH'), z.unknown()]),
|
24
|
+
revalidate: z.number().optional(),
|
25
|
+
tags: z.array(z.string()).optional().default([]),
|
26
|
+
});
|
27
|
+
|
28
|
+
const atou = (str: string, type: string) => {
|
29
|
+
if (type.startsWith('image/')) return `data:${type};base64,${str}`;
|
30
|
+
return Buffer.from(str, 'base64').toString();
|
31
|
+
};
|
32
|
+
export const nextCacheFileSchema = z
|
33
|
+
.union([unstableCacheFileSchema, fetchCacheFileSchema])
|
34
|
+
.transform((item) => {
|
35
|
+
const { data, ...cacheEntry } = item;
|
36
|
+
const body =
|
37
|
+
data.url !== ''
|
38
|
+
? atou(data.body, data.headers ? data.headers['content-type'] : '')
|
39
|
+
: data.body;
|
40
|
+
return {
|
41
|
+
...cacheEntry,
|
42
|
+
...data,
|
43
|
+
body,
|
44
|
+
timestamp: data.headers?.date ? new Date(data.headers?.date) : new Date(),
|
45
|
+
url: data.url === '' ? 'unstable_cache' : data.url,
|
46
|
+
};
|
47
|
+
});
|
48
|
+
|
49
|
+
export type NextCacheFileData = z.infer<typeof nextCacheFileSchema>;
|
@@ -0,0 +1,93 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { Form, Highlighter } from '@lobehub/ui';
|
4
|
+
import { Switch } from 'antd';
|
5
|
+
import { createStyles } from 'antd-style';
|
6
|
+
import { snakeCase } from 'lodash-es';
|
7
|
+
import { ListRestartIcon } from 'lucide-react';
|
8
|
+
import { memo, useMemo, useState } from 'react';
|
9
|
+
import { Flexbox } from 'react-layout-kit';
|
10
|
+
|
11
|
+
import { DEFAULT_FEATURE_FLAGS } from '@/config/featureFlags';
|
12
|
+
|
13
|
+
import Header from '../features/Header';
|
14
|
+
|
15
|
+
const useStyles = createStyles(({ css, token, prefixCls }) => ({
|
16
|
+
container: css`
|
17
|
+
* {
|
18
|
+
font-family: ${token.fontFamilyCode};
|
19
|
+
font-size: 12px;
|
20
|
+
}
|
21
|
+
.${prefixCls}-form-item {
|
22
|
+
padding-block: 4px !important;
|
23
|
+
}
|
24
|
+
`,
|
25
|
+
}));
|
26
|
+
|
27
|
+
const FeatureFlagForm = memo<{ flags: any }>(({ flags }) => {
|
28
|
+
const { styles } = useStyles();
|
29
|
+
const [data, setData] = useState(flags);
|
30
|
+
const [form] = Form.useForm();
|
31
|
+
|
32
|
+
const output = useMemo(
|
33
|
+
() =>
|
34
|
+
Object.entries(data).map(([key, value]) => {
|
35
|
+
const flag = snakeCase(key);
|
36
|
+
// @ts-ignore
|
37
|
+
if (DEFAULT_FEATURE_FLAGS[flag] === value) return false;
|
38
|
+
if (value === true) return `+${flag}`;
|
39
|
+
return `-${flag}`;
|
40
|
+
}),
|
41
|
+
[data],
|
42
|
+
);
|
43
|
+
|
44
|
+
return (
|
45
|
+
<>
|
46
|
+
<Header
|
47
|
+
actions={[
|
48
|
+
{
|
49
|
+
icon: ListRestartIcon,
|
50
|
+
onClick: () => {
|
51
|
+
form.resetFields();
|
52
|
+
setData(flags);
|
53
|
+
},
|
54
|
+
title: 'Reset',
|
55
|
+
},
|
56
|
+
]}
|
57
|
+
title={'Feature Flag Env'}
|
58
|
+
/>
|
59
|
+
<Flexbox
|
60
|
+
className={styles.container}
|
61
|
+
height={'100%'}
|
62
|
+
paddingInline={16}
|
63
|
+
style={{ overflow: 'auto', position: 'relative' }}
|
64
|
+
width={'100%'}
|
65
|
+
>
|
66
|
+
<Form
|
67
|
+
form={form}
|
68
|
+
initialValues={flags}
|
69
|
+
itemMinWidth={'max(75%,240px)'}
|
70
|
+
items={Object.keys(flags).map((key) => {
|
71
|
+
return {
|
72
|
+
children: <Switch size={'small'} />,
|
73
|
+
label: snakeCase(key),
|
74
|
+
minWidth: undefined,
|
75
|
+
name: key,
|
76
|
+
valuePropName: 'checked',
|
77
|
+
};
|
78
|
+
})}
|
79
|
+
itemsType={'flat'}
|
80
|
+
onValuesChange={(_, v) => setData(v)}
|
81
|
+
variant={'pure'}
|
82
|
+
/>
|
83
|
+
</Flexbox>
|
84
|
+
<Highlighter
|
85
|
+
language={'env'}
|
86
|
+
style={{ flex: 'none', fontSize: 12 }}
|
87
|
+
wrap
|
88
|
+
>{`FEATURE_FLAGS="${output.filter(Boolean).join(',')}"`}</Highlighter>
|
89
|
+
</>
|
90
|
+
);
|
91
|
+
});
|
92
|
+
|
93
|
+
export default FeatureFlagForm;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { getServerFeatureFlagsValue } from '@/config/featureFlags';
|
2
|
+
|
3
|
+
import FeatureFlagForm from './Form';
|
4
|
+
|
5
|
+
const FeatureFlagViewer = () => {
|
6
|
+
const serverFeatureFlags = getServerFeatureFlagsValue();
|
7
|
+
|
8
|
+
return <FeatureFlagForm flags={serverFeatureFlags} />;
|
9
|
+
};
|
10
|
+
|
11
|
+
export default FeatureFlagViewer;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Highlighter } from '@lobehub/ui';
|
2
|
+
import { Empty } from 'antd';
|
3
|
+
import { memo } from 'react';
|
4
|
+
import { Center } from 'react-layout-kit';
|
5
|
+
|
6
|
+
import { useLd } from './useHead';
|
7
|
+
|
8
|
+
const Ld = memo(() => {
|
9
|
+
const ld = useLd();
|
10
|
+
|
11
|
+
if (!ld)
|
12
|
+
return (
|
13
|
+
<Center height={'80%'}>
|
14
|
+
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
15
|
+
</Center>
|
16
|
+
);
|
17
|
+
|
18
|
+
return (
|
19
|
+
<Highlighter language="json" type={'pure'}>
|
20
|
+
{JSON.stringify(JSON.parse(ld), null, 2)}
|
21
|
+
</Highlighter>
|
22
|
+
);
|
23
|
+
});
|
24
|
+
|
25
|
+
export default Ld;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { Form } from '@lobehub/ui';
|
2
|
+
import { Input } from 'antd';
|
3
|
+
import { memo } from 'react';
|
4
|
+
|
5
|
+
import { useHead, useTitle } from './useHead';
|
6
|
+
|
7
|
+
const MetaData = memo(() => {
|
8
|
+
const title = useTitle();
|
9
|
+
const description = useHead('name', 'description');
|
10
|
+
|
11
|
+
return (
|
12
|
+
<Form
|
13
|
+
itemMinWidth={'max(75%,240px)'}
|
14
|
+
items={[
|
15
|
+
{
|
16
|
+
children: <Input value={title} variant={'filled'} />,
|
17
|
+
label: `Title (${title.length})`,
|
18
|
+
},
|
19
|
+
{
|
20
|
+
children: <Input.TextArea rows={2} value={description} variant={'filled'} />,
|
21
|
+
label: `Description (${description.length})`,
|
22
|
+
},
|
23
|
+
]}
|
24
|
+
itemsType={'flat'}
|
25
|
+
variant={'pure'}
|
26
|
+
/>
|
27
|
+
);
|
28
|
+
});
|
29
|
+
|
30
|
+
export default MetaData;
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { Form } from '@lobehub/ui';
|
2
|
+
import { Input } from 'antd';
|
3
|
+
import Image from 'next/image';
|
4
|
+
import { memo } from 'react';
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
6
|
+
|
7
|
+
import { useHead } from './useHead';
|
8
|
+
|
9
|
+
const MetaData = memo(() => {
|
10
|
+
const ogTitle = useHead('property', 'og:title');
|
11
|
+
const ogDescription = useHead('property', 'og:description');
|
12
|
+
const ogImage = useHead('property', 'og:image');
|
13
|
+
|
14
|
+
return (
|
15
|
+
<Form
|
16
|
+
itemMinWidth={'max(75%,240px)'}
|
17
|
+
items={[
|
18
|
+
{
|
19
|
+
children: <Input value={ogTitle} variant={'filled'} />,
|
20
|
+
label: `OG Title (${ogTitle.length})`,
|
21
|
+
},
|
22
|
+
{
|
23
|
+
children: <Input.TextArea rows={2} value={ogDescription} variant={'filled'} />,
|
24
|
+
label: `OG Description (${ogDescription.length})`,
|
25
|
+
},
|
26
|
+
{
|
27
|
+
children: (
|
28
|
+
<Flexbox
|
29
|
+
height={186}
|
30
|
+
style={{
|
31
|
+
background: 'rgba(0, 0, 0, .5)',
|
32
|
+
borderRadius: 14,
|
33
|
+
overflow: 'hidden',
|
34
|
+
position: 'relative',
|
35
|
+
}}
|
36
|
+
width={358}
|
37
|
+
>
|
38
|
+
<div
|
39
|
+
style={{
|
40
|
+
background: 'rgba(0, 0, 0, .5)',
|
41
|
+
borderRadius: 4,
|
42
|
+
bottom: 10,
|
43
|
+
left: 10,
|
44
|
+
lineHeight: 1.3,
|
45
|
+
padding: '2px 6px',
|
46
|
+
position: 'absolute',
|
47
|
+
zIndex: 10,
|
48
|
+
}}
|
49
|
+
>
|
50
|
+
lobehub.com
|
51
|
+
</div>
|
52
|
+
<Image
|
53
|
+
alt={'og'}
|
54
|
+
fill
|
55
|
+
src={ogImage}
|
56
|
+
style={{ objectFit: 'cover' }}
|
57
|
+
unoptimized={true}
|
58
|
+
/>
|
59
|
+
</Flexbox>
|
60
|
+
),
|
61
|
+
label: 'Og Image',
|
62
|
+
minWidth: undefined,
|
63
|
+
},
|
64
|
+
{
|
65
|
+
children: <Input value={ogImage} variant={'filled'} />,
|
66
|
+
label: 'Og Image Url',
|
67
|
+
},
|
68
|
+
]}
|
69
|
+
itemsType={'flat'}
|
70
|
+
variant={'pure'}
|
71
|
+
/>
|
72
|
+
);
|
73
|
+
});
|
74
|
+
|
75
|
+
export default MetaData;
|
@@ -0,0 +1,80 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { TabsNav } from '@lobehub/ui';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { memo, useState } from 'react';
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
7
|
+
|
8
|
+
import Header from '../features/Header';
|
9
|
+
import Ld from './Ld';
|
10
|
+
import MetaData from './MetaData';
|
11
|
+
import Og from './Og';
|
12
|
+
|
13
|
+
const useStyles = createStyles(({ css, prefixCls }) => ({
|
14
|
+
container: css`
|
15
|
+
* {
|
16
|
+
font-size: 12px;
|
17
|
+
}
|
18
|
+
.${prefixCls}-form-item {
|
19
|
+
padding-block: 8px;
|
20
|
+
}
|
21
|
+
`,
|
22
|
+
}));
|
23
|
+
|
24
|
+
enum Tab {
|
25
|
+
Ld = 'ld',
|
26
|
+
Meta = 'meta',
|
27
|
+
Og = 'og',
|
28
|
+
}
|
29
|
+
|
30
|
+
const MetadataViewer = memo(() => {
|
31
|
+
const { styles } = useStyles();
|
32
|
+
const [active, setActive] = useState<Tab>(Tab.Og);
|
33
|
+
return (
|
34
|
+
<Flexbox
|
35
|
+
className={styles.container}
|
36
|
+
height={'100%'}
|
37
|
+
style={{ overflow: 'hidden', position: 'relative' }}
|
38
|
+
width={'100%'}
|
39
|
+
>
|
40
|
+
<Header
|
41
|
+
style={{ paddingInlineStart: 0 }}
|
42
|
+
title={
|
43
|
+
<TabsNav
|
44
|
+
activeKey={active}
|
45
|
+
items={[
|
46
|
+
{
|
47
|
+
key: Tab.Og,
|
48
|
+
label: 'OG',
|
49
|
+
},
|
50
|
+
{
|
51
|
+
key: Tab.Meta,
|
52
|
+
label: 'MetaData',
|
53
|
+
},
|
54
|
+
{
|
55
|
+
key: Tab.Ld,
|
56
|
+
label: 'StructuredData',
|
57
|
+
},
|
58
|
+
]}
|
59
|
+
onChange={(v) => setActive(v as Tab)}
|
60
|
+
style={{ margin: 16 }}
|
61
|
+
variant={'compact'}
|
62
|
+
/>
|
63
|
+
}
|
64
|
+
/>
|
65
|
+
<Flexbox
|
66
|
+
flex={1}
|
67
|
+
height={'100%'}
|
68
|
+
paddingInline={16}
|
69
|
+
style={{ overflow: 'auto', paddingBottom: 16, position: 'relative' }}
|
70
|
+
width={'100%'}
|
71
|
+
>
|
72
|
+
{active === Tab.Og && <Og />}
|
73
|
+
{active === Tab.Meta && <MetaData />}
|
74
|
+
{active === Tab.Ld && <Ld />}
|
75
|
+
</Flexbox>
|
76
|
+
</Flexbox>
|
77
|
+
);
|
78
|
+
});
|
79
|
+
|
80
|
+
export default MetadataViewer;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { isOnServerSide } from '@/utils/env';
|
2
|
+
|
3
|
+
export const useHead = (prop: string, name: string) => {
|
4
|
+
if (isOnServerSide) return '';
|
5
|
+
return document.querySelector(`meta[${prop}='${name}']`)?.getAttribute('content') || '';
|
6
|
+
};
|
7
|
+
|
8
|
+
export const useTitle = () => {
|
9
|
+
if (isOnServerSide) return '';
|
10
|
+
return document.querySelector(`title`)?.innerHTML || '';
|
11
|
+
};
|
12
|
+
|
13
|
+
export const useLd = () => {
|
14
|
+
if (isOnServerSide) return '';
|
15
|
+
return document.querySelector(`script[type='application/ld+json']`)?.innerHTML || '';
|
16
|
+
};
|
@@ -1,42 +1,19 @@
|
|
1
|
-
import {
|
2
|
-
import { Button } from 'antd';
|
1
|
+
import { Empty } from 'antd';
|
3
2
|
import { createStyles } from 'antd-style';
|
4
3
|
import { Download, Filter, RefreshCw } from 'lucide-react';
|
5
4
|
import React from 'react';
|
5
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
6
6
|
import { mutate } from 'swr';
|
7
7
|
|
8
|
-
import
|
9
|
-
import Table from '
|
8
|
+
import Header from '../../features/Header';
|
9
|
+
import Table from '../../features/Table';
|
10
|
+
import { FETCH_TABLE_DATA_KEY, usePgTable, useTableColumns } from '../usePgTable';
|
10
11
|
|
11
12
|
const useStyles = createStyles(({ token, css }) => ({
|
12
13
|
dataPanel: css`
|
13
14
|
overflow: hidden;
|
14
|
-
display: flex;
|
15
|
-
flex: 1;
|
16
|
-
flex-direction: column;
|
17
|
-
|
18
|
-
height: 100%;
|
19
|
-
|
20
15
|
background: ${token.colorBgContainer};
|
21
16
|
`,
|
22
|
-
toolbar: css`
|
23
|
-
display: flex;
|
24
|
-
align-items: center;
|
25
|
-
justify-content: space-between;
|
26
|
-
|
27
|
-
padding-block: 12px;
|
28
|
-
padding-inline: 16px;
|
29
|
-
border-block-end: 1px solid ${token.colorBorderSecondary};
|
30
|
-
`,
|
31
|
-
toolbarButtons: css`
|
32
|
-
display: flex;
|
33
|
-
gap: 4px;
|
34
|
-
`,
|
35
|
-
toolbarTitle: css`
|
36
|
-
font-size: ${token.fontSizeLG}px;
|
37
|
-
font-weight: ${token.fontWeightStrong};
|
38
|
-
color: ${token.colorText};
|
39
|
-
`,
|
40
17
|
}));
|
41
18
|
|
42
19
|
interface DataTableProps {
|
@@ -46,29 +23,42 @@ interface DataTableProps {
|
|
46
23
|
const DataTable = ({ tableName }: DataTableProps) => {
|
47
24
|
const { styles } = useStyles();
|
48
25
|
|
26
|
+
const tableColumns = useTableColumns(tableName);
|
27
|
+
const tableData = usePgTable(tableName);
|
28
|
+
const columns = tableColumns.data?.map((t) => t.name) || [];
|
29
|
+
const isLoading = tableColumns.isLoading || tableData.isLoading;
|
30
|
+
const dataSource = tableData.data?.data || [];
|
31
|
+
|
49
32
|
return (
|
50
|
-
<
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
33
|
+
<Flexbox className={styles.dataPanel} flex={1} height={'100%'}>
|
34
|
+
<Header
|
35
|
+
actions={[
|
36
|
+
{
|
37
|
+
icon: Filter,
|
38
|
+
title: 'Filter',
|
39
|
+
},
|
40
|
+
{
|
41
|
+
icon: Download,
|
42
|
+
title: 'Export',
|
43
|
+
},
|
44
|
+
{
|
45
|
+
icon: RefreshCw,
|
46
|
+
onClick: async () => {
|
62
47
|
await mutate(FETCH_TABLE_DATA_KEY(tableName));
|
63
|
-
}
|
64
|
-
title
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
{
|
70
|
-
|
71
|
-
|
48
|
+
},
|
49
|
+
title: 'Refresh',
|
50
|
+
},
|
51
|
+
]}
|
52
|
+
title={tableName || 'Select a table'}
|
53
|
+
/>
|
54
|
+
{tableName ? (
|
55
|
+
<Table columns={columns} dataSource={dataSource} loading={isLoading} />
|
56
|
+
) : (
|
57
|
+
<Center height={'80%'}>
|
58
|
+
<Empty description={'Select a table to view data'} image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
59
|
+
</Center>
|
60
|
+
)}
|
61
|
+
</Flexbox>
|
72
62
|
);
|
73
63
|
};
|
74
64
|
|
@@ -3,7 +3,7 @@ import { createStyles } from 'antd-style';
|
|
3
3
|
import React from 'react';
|
4
4
|
import { Flexbox } from 'react-layout-kit';
|
5
5
|
|
6
|
-
import { useTableColumns } from '
|
6
|
+
import { useTableColumns } from '../usePgTable';
|
7
7
|
|
8
8
|
const useStyles = createStyles(({ token, css }) => ({
|
9
9
|
container: css`
|
@@ -26,7 +26,7 @@ interface TableColumnsProps {
|
|
26
26
|
tableName: string;
|
27
27
|
}
|
28
28
|
|
29
|
-
const
|
29
|
+
const Columns = ({ tableName }: TableColumnsProps) => {
|
30
30
|
const { styles } = useStyles();
|
31
31
|
|
32
32
|
const { data, isLoading } = useTableColumns(tableName);
|
@@ -34,7 +34,9 @@ const TableColumns = ({ tableName }: TableColumnsProps) => {
|
|
34
34
|
return (
|
35
35
|
<div className={styles.container}>
|
36
36
|
{isLoading ? (
|
37
|
-
<
|
37
|
+
` <Center width={'100%'}>
|
38
|
+
<Icon icon={Loader2Icon} spin />
|
39
|
+
</Center>`
|
38
40
|
) : (
|
39
41
|
<Flexbox>
|
40
42
|
{data?.map((column) => (
|
@@ -64,4 +66,4 @@ const TableColumns = ({ tableName }: TableColumnsProps) => {
|
|
64
66
|
);
|
65
67
|
};
|
66
68
|
|
67
|
-
export default
|
69
|
+
export default Columns;
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import { Icon } from '@lobehub/ui';
|
1
|
+
import { DraggablePanel, DraggablePanelBody, Icon } from '@lobehub/ui';
|
2
2
|
import { createStyles } from 'antd-style';
|
3
|
-
import { ChevronDown, ChevronRight, Database, Table as TableIcon } from 'lucide-react';
|
3
|
+
import { ChevronDown, ChevronRight, Database, Loader2Icon, Table as TableIcon } from 'lucide-react';
|
4
4
|
import React, { useState } from 'react';
|
5
|
-
import { Flexbox } from 'react-layout-kit';
|
5
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
6
6
|
|
7
|
-
import
|
8
|
-
import
|
7
|
+
import { useFetchTables } from '../usePgTable';
|
8
|
+
import Columns from './Columns';
|
9
9
|
|
10
10
|
const useStyles = createStyles(({ token, css }) => ({
|
11
11
|
button: css`
|
@@ -51,24 +51,7 @@ const useStyles = createStyles(({ token, css }) => ({
|
|
51
51
|
color: ${token.colorTextTertiary};
|
52
52
|
`,
|
53
53
|
schemaHeader: css`
|
54
|
-
display: flex;
|
55
|
-
gap: 8px;
|
56
|
-
align-items: center;
|
57
|
-
|
58
|
-
padding-block: 12px;
|
59
|
-
padding-inline: 16px;
|
60
|
-
|
61
54
|
font-weight: ${token.fontWeightStrong};
|
62
|
-
color: ${token.colorText};
|
63
|
-
`,
|
64
|
-
schemaPanel: css`
|
65
|
-
overflow: scroll;
|
66
|
-
|
67
|
-
width: 280px;
|
68
|
-
height: 100%;
|
69
|
-
border-inline-end: 1px solid ${token.colorBorderSecondary};
|
70
|
-
|
71
|
-
background: ${token.colorBgContainer};
|
72
55
|
`,
|
73
56
|
selected: css`
|
74
57
|
background: ${token.colorFillSecondary};
|
@@ -146,41 +129,52 @@ const SchemaPanel = ({ onTableSelect, selectedTable }: SchemaPanelProps) => {
|
|
146
129
|
};
|
147
130
|
|
148
131
|
return (
|
149
|
-
<
|
150
|
-
<
|
151
|
-
<
|
152
|
-
|
153
|
-
|
154
|
-
|
132
|
+
<DraggablePanel placement={'left'}>
|
133
|
+
<Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }}>
|
134
|
+
<Flexbox
|
135
|
+
align={'center'}
|
136
|
+
className={styles.schemaHeader}
|
137
|
+
gap={8}
|
138
|
+
horizontal
|
139
|
+
paddingBlock={12}
|
140
|
+
paddingInline={16}
|
141
|
+
>
|
142
|
+
<Database size={16} />
|
143
|
+
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
144
|
+
<span>Tables {data?.length}</span>
|
145
|
+
<span className={styles.schema}>public</span>
|
146
|
+
</Flexbox>
|
155
147
|
</Flexbox>
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
<
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
<
|
175
|
-
|
148
|
+
<DraggablePanelBody style={{ padding: 0 }}>
|
149
|
+
{isLoading ? (
|
150
|
+
<Center height={'100%'} width={'100%'}>
|
151
|
+
<Icon icon={Loader2Icon} spin />
|
152
|
+
</Center>
|
153
|
+
) : (
|
154
|
+
data?.map((table) => (
|
155
|
+
<div key={table.name}>
|
156
|
+
<Flexbox
|
157
|
+
className={cx(styles.tableItem, selectedTable === table.name && styles.selected)}
|
158
|
+
horizontal
|
159
|
+
onClick={() => {
|
160
|
+
toggleTable(table.name);
|
161
|
+
onTableSelect(table.name);
|
162
|
+
}}
|
163
|
+
>
|
164
|
+
<Icon icon={expandedTables.has(table.name) ? ChevronDown : ChevronRight} />
|
165
|
+
<TableIcon size={16} />
|
166
|
+
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
167
|
+
<span>{table.name}</span>
|
168
|
+
<span className={styles.count}>{table.count}</span>
|
169
|
+
</Flexbox>
|
176
170
|
</Flexbox>
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
)
|
181
|
-
</
|
182
|
-
|
183
|
-
</
|
171
|
+
{expandedTables.has(table.name) && <Columns tableName={table.name} />}
|
172
|
+
</div>
|
173
|
+
))
|
174
|
+
)}
|
175
|
+
</DraggablePanelBody>
|
176
|
+
</Flexbox>
|
177
|
+
</DraggablePanel>
|
184
178
|
);
|
185
179
|
};
|
186
180
|
|
@@ -1,8 +1,10 @@
|
|
1
|
+
'use client';
|
2
|
+
|
1
3
|
import React, { useState } from 'react';
|
2
4
|
import { Flexbox } from 'react-layout-kit';
|
3
5
|
|
4
6
|
import DataTable from './DataTable';
|
5
|
-
import
|
7
|
+
import SchemaSidebar from './SchemaSidebar';
|
6
8
|
|
7
9
|
// Main Database Panel Component
|
8
10
|
const DatabasePanel = () => {
|
@@ -10,7 +12,7 @@ const DatabasePanel = () => {
|
|
10
12
|
|
11
13
|
return (
|
12
14
|
<Flexbox height={'100%'} horizontal>
|
13
|
-
<
|
15
|
+
<SchemaSidebar onTableSelect={setSelectedTable} selectedTable={selectedTable} />
|
14
16
|
<DataTable tableName={selectedTable} />
|
15
17
|
</Flexbox>
|
16
18
|
);
|