Skip to content

Commit a520554

Browse files
committed
fix data sources tab
1 parent d8ed715 commit a520554

File tree

6 files changed

+468
-225
lines changed

6 files changed

+468
-225
lines changed

client/packages/lowcoder/src/pages/setting/environments/WorkspaceDetail.tsx

+2-66
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { App } from "./types/app.types";
3535
import { getMergedApps } from "./utils/getMergedApps";
3636
import { connectManagedApp, unconnectManagedApp } from "./services/enterprise.service";
3737
import AppsTab from "./components/AppsTab";
38+
import DataSourcesTab from "./components/DataSourcesTab";
3839

3940
const { Title, Text } = Typography;
4041
const { TabPane } = Tabs;
@@ -58,16 +59,7 @@ const WorkspaceDetail: React.FC = () => {
5859
workspace,
5960
loading: workspaceLoading,
6061
error: workspaceError,
61-
refresh: refreshWorkspace
6262
} = useWorkspace(environment, workspaceId);
63-
64-
const {
65-
dataSources,
66-
loading: dataSourcesLoading,
67-
error: dataSourcesError,
68-
refresh: refreshDataSources,
69-
dataSourceStats,
70-
} = useWorkspaceDataSources(environment, workspaceId);
7163

7264
if (envLoading || workspaceLoading) {
7365
return (
@@ -139,63 +131,7 @@ const WorkspaceDetail: React.FC = () => {
139131
tab={<span><DatabaseOutlined /> Data Sources</span>}
140132
key="dataSources"
141133
>
142-
<Card>
143-
{/* Header with refresh button */}
144-
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
145-
<Title level={5}>Data Sources in this Workspace</Title>
146-
<Button
147-
icon={<SyncOutlined />}
148-
onClick={refreshDataSources}
149-
size="small"
150-
loading={dataSourcesLoading}
151-
>
152-
Refresh Data Sources
153-
</Button>
154-
</div>
155-
156-
{/* Data Source Statistics */}
157-
<Row gutter={16} style={{ marginBottom: '24px' }}>
158-
<Col span={8}>
159-
<Statistic
160-
title="Total Data Sources"
161-
value={dataSourceStats.total}
162-
prefix={<DatabaseOutlined />}
163-
/>
164-
</Col>
165-
<Col span={8}>
166-
<Statistic
167-
title="Data Source Types"
168-
value={dataSourceStats.types}
169-
prefix={<DatabaseOutlined />}
170-
/>
171-
</Col>
172-
</Row>
173-
174-
<Divider style={{ margin: '16px 0' }} />
175-
176-
{/* Show error if data sources loading failed */}
177-
{dataSourcesError && (
178-
<Alert
179-
message="Error loading data sources"
180-
description={dataSourcesError}
181-
type="error"
182-
showIcon
183-
style={{ marginBottom: '16px' }}
184-
action={
185-
<Button size="small" type="primary" onClick={refreshDataSources}>
186-
Try Again
187-
</Button>
188-
}
189-
/>
190-
)}
191-
192-
{/* Data Sources List */}
193-
<DataSourcesList
194-
dataSources={dataSources}
195-
loading={dataSourcesLoading}
196-
error={dataSourcesError}
197-
/>
198-
</Card>
134+
<DataSourcesTab environment={environment} workspaceId={workspaceId} />
199135
</TabPane>
200136

201137
<TabPane

client/packages/lowcoder/src/pages/setting/environments/components/DataSourcesList.tsx

+97-102
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,135 @@
1-
import React from 'react';
2-
import { Table, Tag, Empty, Spin, Badge, Tooltip } from 'antd';
3-
import {
4-
DatabaseOutlined,
5-
UserOutlined,
6-
CheckCircleOutlined,
7-
CloseCircleOutlined
8-
} from '@ant-design/icons';
9-
import { DataSourceWithMeta } from '../types/datasource.types';
1+
// components/DataSourcesList.tsx
2+
// Create this new file
3+
4+
import React, { useState } from 'react';
5+
import { Table, Switch, Button, Space, Tooltip, Tag } from 'antd';
6+
import { CloudUploadOutlined } from '@ant-design/icons';
7+
import { DataSource } from '../types/datasource.types';
8+
import { Environment } from '../types/environment.types';
9+
import { ColumnsType } from 'antd/lib/table';
10+
import DeployDataSourceModal from './DeployDataSourceModal';
1011

1112
interface DataSourcesListProps {
12-
dataSources: DataSourceWithMeta[];
13+
dataSources: DataSource[];
1314
loading: boolean;
14-
error?: string | null;
15+
error: string | null;
16+
environment: Environment;
17+
onToggleManaged: (dataSource: DataSource, checked: boolean) => Promise<void>;
18+
onRefresh?: () => void;
1519
}
1620

17-
/**
18-
* Component to display a list of data sources in a table
19-
*/
2021
const DataSourcesList: React.FC<DataSourcesListProps> = ({
2122
dataSources,
2223
loading,
2324
error,
25+
environment,
26+
onToggleManaged,
27+
onRefresh,
2428
}) => {
25-
// Format timestamp to date string
26-
const formatDate = (timestamp?: number): string => {
27-
if (!timestamp) return 'N/A';
28-
const date = new Date(timestamp);
29-
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
30-
};
29+
const [deployModalVisible, setDeployModalVisible] = useState(false);
30+
const [selectedDataSource, setSelectedDataSource] = useState<DataSource | null>(null);
3131

32-
// Get icon for data source type
33-
const getDataSourceTypeIcon = (type: string) => {
34-
return <DatabaseOutlined />;
32+
const handleDeploy = (dataSource: DataSource) => {
33+
setSelectedDataSource(dataSource);
34+
setDeployModalVisible(true);
3535
};
3636

37-
// Get color for data source status
38-
const getStatusColor = (status: string) => {
39-
switch (status) {
40-
case 'NORMAL':
41-
return 'green';
42-
case 'ERROR':
43-
return 'red';
44-
case 'WARNING':
45-
return 'orange';
46-
default:
47-
return 'default';
48-
}
49-
};
50-
51-
// Table columns definition
52-
const columns = [
37+
const columns: ColumnsType<DataSource> = [
5338
{
5439
title: 'Name',
40+
dataIndex: 'name',
5541
key: 'name',
56-
render: (record: DataSourceWithMeta) => (
57-
<div style={{ display: 'flex', alignItems: 'center' }}>
58-
{getDataSourceTypeIcon(record.datasource.type)}
59-
<span style={{ marginLeft: 8 }}>{record.datasource.name}</span>
60-
</div>
61-
),
42+
sorter: (a, b) => a.name.localeCompare(b.name),
6243
},
6344
{
6445
title: 'Type',
65-
dataIndex: ['datasource', 'type'],
46+
dataIndex: 'type',
6647
key: 'type',
67-
render: (type: string) => (
68-
<Tag color="blue">{type.toUpperCase()}</Tag>
69-
),
48+
filters: Array.from(new Set(dataSources.map(ds => ds.type)))
49+
.map(type => ({ text: type, value: type })),
50+
onFilter: (value, record) => record.type === value,
7051
},
7152
{
72-
title: 'Created By',
73-
dataIndex: 'creatorName',
74-
key: 'creatorName',
75-
render: (creatorName: string) => (
76-
<div style={{ display: 'flex', alignItems: 'center' }}>
77-
<UserOutlined style={{ marginRight: 8 }} />
78-
<span>{creatorName}</span>
79-
</div>
53+
title: 'Status',
54+
dataIndex: 'datasourceStatus',
55+
key: 'status',
56+
render: (status: string) => (
57+
<Tag color={status === 'ACTIVE' ? 'green' : 'orange'}>
58+
{status}
59+
</Tag>
8060
),
61+
filters: Array.from(new Set(dataSources.map(ds => ds.datasourceStatus)))
62+
.map(status => ({ text: status, value: status })),
63+
onFilter: (value, record) => record.datasourceStatus === value,
8164
},
8265
{
83-
title: 'Created',
84-
key: 'createTime',
85-
render: (record: DataSourceWithMeta) => formatDate(record.datasource.createTime),
66+
title: 'DB Name',
67+
dataIndex: ['datasourceConfig', 'database'],
68+
key: 'database',
69+
render: (database: string | null) => database || 'N/A',
8670
},
8771
{
88-
title: 'Status',
89-
key: 'status',
90-
render: (record: DataSourceWithMeta) => (
91-
<Tag color={getStatusColor(record.datasource.datasourceStatus)}>
92-
{record.datasource.datasourceStatus}
93-
</Tag>
72+
title: 'Managed',
73+
dataIndex: 'managed',
74+
key: 'managed',
75+
render: (managed: boolean, record: DataSource) => (
76+
<Space>
77+
<Switch
78+
checked={managed}
79+
onChange={(checked) => onToggleManaged(record, checked)}
80+
/>
81+
<Tag color={managed ? 'blue' : 'gray'}>
82+
{managed ? 'Managed' : 'Unmanaged'}
83+
</Tag>
84+
</Space>
9485
),
86+
filters: [
87+
{ text: 'Managed', value: true },
88+
{ text: 'Unmanaged', value: false },
89+
],
90+
onFilter: (value, record) => record.managed === Boolean(value),
9591
},
9692
{
97-
title: 'Edit Access',
98-
dataIndex: 'edit',
99-
key: 'edit',
100-
render: (edit: boolean) => (
101-
<Tooltip title={edit ? 'You can edit this data source' : 'You cannot edit this data source'}>
102-
{edit ?
103-
<CheckCircleOutlined style={{ color: '#52c41a' }} /> :
104-
<CloseCircleOutlined style={{ color: '#f5222d' }} />
105-
}
106-
</Tooltip>
93+
title: 'Actions',
94+
key: 'actions',
95+
render: (_, record: DataSource) => (
96+
<Space>
97+
<Tooltip title="Deploy to another environment">
98+
<Button
99+
icon={<CloudUploadOutlined />}
100+
onClick={() => handleDeploy(record)}
101+
type="primary"
102+
ghost
103+
>
104+
Deploy
105+
</Button>
106+
</Tooltip>
107+
</Space>
107108
),
108109
},
109110
];
110111

111-
// If loading, show spinner
112-
if (loading) {
113-
return (
114-
<div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}>
115-
<Spin tip="Loading data sources..." />
116-
</div>
117-
);
118-
}
119-
120-
// If no data sources or error, show empty state
121-
if (!dataSources || dataSources.length === 0 || error) {
122-
return (
123-
<Empty
124-
description={error || "No data sources found"}
125-
image={Empty.PRESENTED_IMAGE_SIMPLE}
126-
/>
127-
);
128-
}
129-
130112
return (
131-
<Table
132-
columns={columns}
133-
dataSource={dataSources}
134-
rowKey={(record) => record.datasource.id}
135-
pagination={{ pageSize: 10 }}
136-
size="middle"
137-
/>
113+
<>
114+
<Table
115+
dataSource={dataSources}
116+
columns={columns}
117+
rowKey="id"
118+
loading={loading}
119+
pagination={{ pageSize: 10 }}
120+
locale={{
121+
emptyText: error ? error : 'No data sources found',
122+
}}
123+
/>
124+
125+
<DeployDataSourceModal
126+
visible={deployModalVisible}
127+
dataSource={selectedDataSource}
128+
currentEnvironment={environment}
129+
onClose={() => setDeployModalVisible(false)}
130+
onSuccess={onRefresh}
131+
/>
132+
</>
138133
);
139134
};
140135

0 commit comments

Comments
 (0)