@lobehub/chat 1.51.2 → 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 +41 -0
- package/Dockerfile +1 -1
- package/Dockerfile.database +1 -1
- package/changelog/v1.json +12 -0
- package/docs/usage/providers/wenxin.mdx +16 -13
- package/docs/usage/providers/wenxin.zh-CN.mdx +11 -8
- package/package.json +1 -2
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +2 -4
- package/src/config/aiModels/wenxin.ts +125 -19
- 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
@@ -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
|
);
|
@@ -0,0 +1,218 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { ActionIcon, FluentEmoji, Icon, SideNav } from '@lobehub/ui';
|
4
|
+
import { Dropdown, FloatButton } from 'antd';
|
5
|
+
import { createStyles } from 'antd-style';
|
6
|
+
import { BugIcon, BugOff, XIcon } from 'lucide-react';
|
7
|
+
import { ReactNode, memo, useEffect, useState } from 'react';
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
9
|
+
import { Rnd } from 'react-rnd';
|
10
|
+
|
11
|
+
import { BRANDING_NAME } from '@/const/branding';
|
12
|
+
|
13
|
+
// 定义样式
|
14
|
+
const useStyles = createStyles(({ token, css, prefixCls }) => {
|
15
|
+
return {
|
16
|
+
collapsed: css`
|
17
|
+
pointer-events: none;
|
18
|
+
transform: scale(0.8);
|
19
|
+
opacity: 0;
|
20
|
+
`,
|
21
|
+
expanded: css`
|
22
|
+
pointer-events: auto;
|
23
|
+
transform: scale(1);
|
24
|
+
opacity: 1;
|
25
|
+
`,
|
26
|
+
floatButton: css`
|
27
|
+
inset-block-end: 16px;
|
28
|
+
inset-inline-end: 16px;
|
29
|
+
|
30
|
+
width: 36px;
|
31
|
+
height: 36px;
|
32
|
+
border: 1px solid ${token.colorBorderSecondary};
|
33
|
+
|
34
|
+
font-size: 20px;
|
35
|
+
.${prefixCls}-float-btn-body {
|
36
|
+
background: ${token.colorBgLayout};
|
37
|
+
|
38
|
+
&:hover {
|
39
|
+
width: auto;
|
40
|
+
background: ${token.colorBgElevated};
|
41
|
+
}
|
42
|
+
}
|
43
|
+
`,
|
44
|
+
header: css`
|
45
|
+
cursor: move;
|
46
|
+
user-select: none;
|
47
|
+
|
48
|
+
padding-block: 8px;
|
49
|
+
padding-inline: 16px;
|
50
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
51
|
+
|
52
|
+
color: ${token.colorText};
|
53
|
+
|
54
|
+
background: ${token.colorFillAlter};
|
55
|
+
`,
|
56
|
+
panel: css`
|
57
|
+
position: fixed;
|
58
|
+
z-index: 1000;
|
59
|
+
|
60
|
+
overflow: hidden;
|
61
|
+
display: flex;
|
62
|
+
|
63
|
+
border: 1px solid ${token.colorBorderSecondary};
|
64
|
+
border-radius: 12px;
|
65
|
+
|
66
|
+
background: ${token.colorBgContainer};
|
67
|
+
box-shadow: ${token.boxShadow};
|
68
|
+
|
69
|
+
transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};
|
70
|
+
`,
|
71
|
+
};
|
72
|
+
});
|
73
|
+
|
74
|
+
const minWidth = 800;
|
75
|
+
const minHeight = 600;
|
76
|
+
|
77
|
+
interface CollapsibleFloatPanelProps {
|
78
|
+
items: { children: ReactNode; icon: ReactNode; key: string }[];
|
79
|
+
}
|
80
|
+
|
81
|
+
const CollapsibleFloatPanel = memo<CollapsibleFloatPanelProps>(({ items }) => {
|
82
|
+
const { styles, theme } = useStyles();
|
83
|
+
const [tab, setTab] = useState<string>(items[0].key);
|
84
|
+
const [isHide, setIsHide] = useState(false);
|
85
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
86
|
+
const [position, setPosition] = useState({ x: 100, y: 100 });
|
87
|
+
const [size, setSize] = useState({ height: minHeight, width: minWidth });
|
88
|
+
|
89
|
+
useEffect(() => {
|
90
|
+
try {
|
91
|
+
const localStoragePosition = localStorage.getItem('debug-panel-position');
|
92
|
+
if (localStoragePosition && JSON.parse(localStoragePosition)) {
|
93
|
+
setPosition(JSON.parse(localStoragePosition));
|
94
|
+
}
|
95
|
+
} catch {
|
96
|
+
/* empty */
|
97
|
+
}
|
98
|
+
|
99
|
+
try {
|
100
|
+
const localStorageSize = localStorage.getItem('debug-panel-size');
|
101
|
+
if (localStorageSize && JSON.parse(localStorageSize)) {
|
102
|
+
setSize(JSON.parse(localStorageSize));
|
103
|
+
}
|
104
|
+
} catch {
|
105
|
+
/* empty */
|
106
|
+
}
|
107
|
+
}, []);
|
108
|
+
|
109
|
+
return (
|
110
|
+
<>
|
111
|
+
{!isHide && (
|
112
|
+
<Dropdown
|
113
|
+
menu={{
|
114
|
+
items: [
|
115
|
+
{
|
116
|
+
icon: (
|
117
|
+
<Icon color={theme.colorTextSecondary} icon={BugOff} size={{ fontSize: 16 }} />
|
118
|
+
),
|
119
|
+
key: 'hide',
|
120
|
+
label: 'Hide Toolbar',
|
121
|
+
onClick: () => setIsHide(true),
|
122
|
+
},
|
123
|
+
],
|
124
|
+
}}
|
125
|
+
trigger={['hover']}
|
126
|
+
>
|
127
|
+
<FloatButton
|
128
|
+
className={styles.floatButton}
|
129
|
+
icon={<Icon icon={isExpanded ? BugOff : BugIcon} />}
|
130
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
131
|
+
/>
|
132
|
+
</Dropdown>
|
133
|
+
)}
|
134
|
+
{isExpanded && (
|
135
|
+
<Rnd
|
136
|
+
bounds="window"
|
137
|
+
className={`${styles.panel} ${isExpanded ? styles.expanded : styles.collapsed}`}
|
138
|
+
dragHandleClassName="panel-drag-handle"
|
139
|
+
minHeight={minHeight}
|
140
|
+
minWidth={minWidth}
|
141
|
+
onDragStop={(e, d) => {
|
142
|
+
setPosition({ x: d.x, y: d.y });
|
143
|
+
}}
|
144
|
+
onResizeStop={(e, direction, ref, delta, position) => {
|
145
|
+
setSize({
|
146
|
+
height: Number(ref.style.height),
|
147
|
+
width: Number(ref.style.width),
|
148
|
+
});
|
149
|
+
setPosition(position);
|
150
|
+
}}
|
151
|
+
position={position}
|
152
|
+
size={size}
|
153
|
+
>
|
154
|
+
<Flexbox
|
155
|
+
height={'100%'}
|
156
|
+
horizontal
|
157
|
+
style={{ overflow: 'hidden', position: 'relative' }}
|
158
|
+
width={'100%'}
|
159
|
+
>
|
160
|
+
<SideNav
|
161
|
+
avatar={<FluentEmoji emoji={'🧰'} size={24} />}
|
162
|
+
bottomActions={[]}
|
163
|
+
style={{
|
164
|
+
paddingBlock: 12,
|
165
|
+
width: 48,
|
166
|
+
}}
|
167
|
+
topActions={items.map((item) => (
|
168
|
+
<ActionIcon
|
169
|
+
active={tab === item.key}
|
170
|
+
key={item.key}
|
171
|
+
onClick={() => setTab(item.key)}
|
172
|
+
placement={'right'}
|
173
|
+
title={item.key}
|
174
|
+
>
|
175
|
+
{item.icon}
|
176
|
+
</ActionIcon>
|
177
|
+
))}
|
178
|
+
/>
|
179
|
+
<Flexbox
|
180
|
+
height={'100%'}
|
181
|
+
style={{ overflow: 'hidden', position: 'relative' }}
|
182
|
+
width={'100%'}
|
183
|
+
>
|
184
|
+
<Flexbox
|
185
|
+
align={'center'}
|
186
|
+
className={`panel-drag-handle ${styles.header}`}
|
187
|
+
horizontal
|
188
|
+
justify={'space-between'}
|
189
|
+
>
|
190
|
+
<Flexbox align={'baseline'} gap={6} horizontal>
|
191
|
+
<b>{BRANDING_NAME} Dev Tools</b>
|
192
|
+
<span style={{ color: theme.colorTextDescription }}>/</span>
|
193
|
+
<span style={{ color: theme.colorTextDescription }}>{tab}</span>
|
194
|
+
</Flexbox>
|
195
|
+
<ActionIcon icon={XIcon} onClick={() => setIsExpanded(false)} />
|
196
|
+
</Flexbox>
|
197
|
+
{items.map((item) => (
|
198
|
+
<Flexbox
|
199
|
+
flex={1}
|
200
|
+
height={'100%'}
|
201
|
+
key={item.key}
|
202
|
+
style={{
|
203
|
+
display: tab === item.key ? 'flex' : 'none',
|
204
|
+
overflow: 'hidden',
|
205
|
+
}}
|
206
|
+
>
|
207
|
+
{item.children}
|
208
|
+
</Flexbox>
|
209
|
+
))}
|
210
|
+
</Flexbox>
|
211
|
+
</Flexbox>
|
212
|
+
</Rnd>
|
213
|
+
)}
|
214
|
+
</>
|
215
|
+
);
|
216
|
+
});
|
217
|
+
|
218
|
+
export default CollapsibleFloatPanel;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { ActionIcon, type ActionIconProps } from '@lobehub/ui';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import React, { ReactNode } from 'react';
|
4
|
+
import { Flexbox, FlexboxProps } from 'react-layout-kit';
|
5
|
+
|
6
|
+
const useStyles = createStyles(({ token, css }) => ({
|
7
|
+
header: css`
|
8
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
9
|
+
`,
|
10
|
+
title: css`
|
11
|
+
font-weight: 550;
|
12
|
+
`,
|
13
|
+
}));
|
14
|
+
|
15
|
+
interface HeaderProps extends Omit<FlexboxProps, 'title' | 'children'> {
|
16
|
+
actions?: ActionIconProps[];
|
17
|
+
extra?: ReactNode;
|
18
|
+
title?: ReactNode;
|
19
|
+
}
|
20
|
+
|
21
|
+
const Header = ({ title, actions = [], extra, ...rest }: HeaderProps) => {
|
22
|
+
const { styles } = useStyles();
|
23
|
+
|
24
|
+
return (
|
25
|
+
<Flexbox
|
26
|
+
align={'center'}
|
27
|
+
className={styles.header}
|
28
|
+
flex={'none'}
|
29
|
+
height={46}
|
30
|
+
horizontal
|
31
|
+
justify={'space-between'}
|
32
|
+
paddingInline={16}
|
33
|
+
{...rest}
|
34
|
+
>
|
35
|
+
<div className={styles.title}>{title}</div>
|
36
|
+
<Flexbox align={'center'} gap={4} horizontal>
|
37
|
+
{extra}
|
38
|
+
{actions.map((action, index) => (
|
39
|
+
<ActionIcon
|
40
|
+
{...action}
|
41
|
+
key={action.title || index}
|
42
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
43
|
+
/>
|
44
|
+
))}
|
45
|
+
</Flexbox>
|
46
|
+
</Flexbox>
|
47
|
+
);
|
48
|
+
};
|
49
|
+
|
50
|
+
export default Header;
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import { Typography } from 'antd';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import dayjs from 'dayjs';
|
4
|
+
import { get, isDate } from 'lodash-es';
|
5
|
+
import React, { useMemo } from 'react';
|
6
|
+
|
7
|
+
import TooltipContent from './TooltipContent';
|
8
|
+
|
9
|
+
const { Text } = Typography;
|
10
|
+
|
11
|
+
const useStyles = createStyles(({ token, css }) => ({
|
12
|
+
cell: css`
|
13
|
+
font-family: ${token.fontFamilyCode};
|
14
|
+
font-size: ${token.fontSizeSM}px;
|
15
|
+
`,
|
16
|
+
tooltip: css`
|
17
|
+
border: 1px solid ${token.colorBorder};
|
18
|
+
|
19
|
+
font-family: ${token.fontFamilyCode};
|
20
|
+
font-size: ${token.fontSizeSM}px;
|
21
|
+
color: ${token.colorText} !important;
|
22
|
+
word-break: break-all;
|
23
|
+
|
24
|
+
background: ${token.colorBgElevated} !important;
|
25
|
+
`,
|
26
|
+
}));
|
27
|
+
|
28
|
+
interface TableCellProps {
|
29
|
+
column: string;
|
30
|
+
dataItem: any;
|
31
|
+
rowIndex: number;
|
32
|
+
}
|
33
|
+
|
34
|
+
const TableCell = ({ dataItem, column, rowIndex }: TableCellProps) => {
|
35
|
+
const { styles } = useStyles();
|
36
|
+
const data = get(dataItem, column);
|
37
|
+
const content = useMemo(() => {
|
38
|
+
if (isDate(data)) return dayjs(data).format('YYYY-MM-DD HH:mm:ss');
|
39
|
+
|
40
|
+
switch (typeof data) {
|
41
|
+
case 'object': {
|
42
|
+
return JSON.stringify(data);
|
43
|
+
}
|
44
|
+
|
45
|
+
case 'boolean': {
|
46
|
+
return data ? 'True' : 'False';
|
47
|
+
}
|
48
|
+
|
49
|
+
default: {
|
50
|
+
return data;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}, [data]);
|
54
|
+
|
55
|
+
return (
|
56
|
+
<td key={column} onDoubleClick={() => console.log('Edit cell:', rowIndex, column)}>
|
57
|
+
<Text
|
58
|
+
className={styles.cell}
|
59
|
+
ellipsis={{
|
60
|
+
tooltip: {
|
61
|
+
arrow: false,
|
62
|
+
classNames: { body: styles.tooltip },
|
63
|
+
title: <TooltipContent>{content}</TooltipContent>,
|
64
|
+
},
|
65
|
+
}}
|
66
|
+
>
|
67
|
+
{content}
|
68
|
+
</Text>
|
69
|
+
</td>
|
70
|
+
);
|
71
|
+
};
|
72
|
+
|
73
|
+
export default TableCell;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Highlighter } from '@lobehub/ui';
|
2
|
+
import Link from 'next/link';
|
3
|
+
import { ReactNode, memo } from 'react';
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
5
|
+
|
6
|
+
const TooltipContent = memo<{ children: ReactNode }>(({ children }) => {
|
7
|
+
if (typeof children !== 'string') return children;
|
8
|
+
|
9
|
+
if (children.startsWith('data:image')) {
|
10
|
+
return <img src={children} style={{ height: 'auto', maxWidth: '100%' }} />;
|
11
|
+
}
|
12
|
+
|
13
|
+
if (children.startsWith('http'))
|
14
|
+
return (
|
15
|
+
<Link href={children} target={'_blank'}>
|
16
|
+
{children}
|
17
|
+
</Link>
|
18
|
+
);
|
19
|
+
|
20
|
+
const code = children.trim().trimEnd();
|
21
|
+
|
22
|
+
if ((code.startsWith('{') && code.endsWith('}')) || (code.startsWith('[') && code.endsWith(']')))
|
23
|
+
return (
|
24
|
+
<Highlighter
|
25
|
+
language={'json'}
|
26
|
+
style={{
|
27
|
+
maxHeight: 400,
|
28
|
+
overflow: 'auto',
|
29
|
+
}}
|
30
|
+
type={'pure'}
|
31
|
+
>
|
32
|
+
{JSON.stringify(JSON.parse(code), null, 2)}
|
33
|
+
</Highlighter>
|
34
|
+
);
|
35
|
+
|
36
|
+
return <Flexbox>{children}</Flexbox>;
|
37
|
+
});
|
38
|
+
|
39
|
+
export default TooltipContent;
|