plugin-postgresql-connector
Version:
NocoBase plugin for connecting to external PostgreSQL databases
240 lines (208 loc) • 6.64 kB
text/typescript
import { useState, useCallback, useEffect } from 'react';
import { useRequest } from '@nocobase/client';
import { message } from 'antd';
export interface ConnectionConfig {
name: string;
host: string;
port: number;
database: string;
username: string;
password: string;
ssl: boolean;
}
export interface Connection extends ConnectionConfig {
id: string;
isActive: boolean;
createdAt?: string;
updatedAt?: string;
}
export const useConnection = () => {
const [selectedConnection, setSelectedConnection] = useState<string>('');
const [connections, setConnections] = useState<Connection[]>([]);
// Fetch all connections
const {
data: connectionsData,
loading: loadingConnections,
run: refreshConnections,
} = useRequest({
url: '/postgresql-connections',
});
// Test connection
const { run: testConnection, loading: testingConnection } = useRequest(
(config: ConnectionConfig) => ({
url: '/postgresql-connections/test',
method: 'POST',
data: config,
}),
{
manual: true,
onSuccess: () => {
message.success('Kết nối thành công!');
},
onError: (error) => {
message.error(`Kết nối thất bại: ${error.message}`);
throw error;
},
}
);
// Create new connection
const { run: createConnection, loading: creatingConnection } = useRequest(
(config: ConnectionConfig) => ({
url: '/postgresql-connections',
method: 'POST',
data: config,
}),
{
manual: true,
onSuccess: (data) => {
message.success('Tạo kết nối thành công!');
refreshConnections();
return data;
},
onError: (error) => {
message.error(`Tạo kết nối thất bại: ${error.message}`);
throw error;
},
}
);
// Update connection
const { run: updateConnection, loading: updatingConnection } = useRequest(
({ id, config }: { id: string; config: ConnectionConfig }) => ({
url: `/postgresql-connections/${id}`,
method: 'PUT',
data: config,
}),
{
manual: true,
onSuccess: (data) => {
message.success('Cập nhật kết nối thành công!');
refreshConnections();
return data;
},
onError: (error) => {
message.error(`Cập nhật kết nối thất bại: ${error.message}`);
throw error;
},
}
);
// Delete connection
const { run: deleteConnection, loading: deletingConnection } = useRequest(
(id: string) => ({
url: `/postgresql-connections/${id}`,
method: 'DELETE',
}),
{
manual: true,
onSuccess: () => {
message.success('Xóa kết nối thành công!');
if (selectedConnection === id) {
setSelectedConnection('');
}
refreshConnections();
},
onError: (error) => {
message.error(`Xóa kết nối thất bại: ${error.message}`);
throw error;
},
}
);
// Get connection by ID
const getConnectionById = useCallback((id: string): Connection | undefined => {
return connections.find(conn => conn.id === id);
}, [connections]);
// Get active connections
const getActiveConnections = useCallback((): Connection[] => {
return connections.filter(conn => conn.isActive);
}, [connections]);
// Check if connection exists
const connectionExists = useCallback((name: string): boolean => {
return connections.some(conn => conn.name === name && conn.isActive);
}, [connections]);
// Validate connection config
const validateConnectionConfig = useCallback((config: Partial<ConnectionConfig>): string[] => {
const errors: string[] = [];
if (!config.name?.trim()) {
errors.push('Tên kết nối không được để trống');
} else if (config.name.length < 3) {
errors.push('Tên kết nối phải có ít nhất 3 ký tự');
}
if (!config.host?.trim()) {
errors.push('Host không được để trống');
}
if (!config.port || config.port < 1 || config.port > 65535) {
errors.push('Port phải từ 1 đến 65535');
}
if (!config.database?.trim()) {
errors.push('Tên database không được để trống');
}
if (!config.username?.trim()) {
errors.push('Username không được để trống');
}
if (!config.password?.trim()) {
errors.push('Password không được để trống');
}
return errors;
}, []);
// Test and create connection
const testAndCreateConnection = useCallback(async (config: ConnectionConfig) => {
try {
// First test the connection
await testConnection(config);
// If test successful, create the connection
const result = await createConnection(config);
return result;
} catch (error) {
throw error;
}
}, [testConnection, createConnection]);
// Test and update connection
const testAndUpdateConnection = useCallback(async (id: string, config: ConnectionConfig) => {
try {
// First test the connection
await testConnection(config);
// If test successful, update the connection
const result = await updateConnection({ id, config });
return result;
} catch (error) {
throw error;
}
}, [testConnection, updateConnection]);
// Update connections list when data changes
useEffect(() => {
if (connectionsData?.data) {
setConnections(connectionsData.data);
}
}, [connectionsData]);
// Auto-select first connection if none selected
useEffect(() => {
if (!selectedConnection && connections.length > 0) {
setSelectedConnection(connections[0].id);
}
}, [connections, selectedConnection]);
return {
// State
connections,
selectedConnection,
setSelectedConnection,
// Loading states
loadingConnections,
testingConnection,
creatingConnection,
updatingConnection,
deletingConnection,
// Actions
refreshConnections,
testConnection,
createConnection,
updateConnection,
deleteConnection,
testAndCreateConnection,
testAndUpdateConnection,
// Utilities
getConnectionById,
getActiveConnections,
connectionExists,
validateConnectionConfig,
};
};
export default useConnection;