feat(frontend): add Odoo configuration page
Add OdooConfig page component with form for Odoo connection settings (URL, database, username, API key) and test connection functionality. Integrate into main navigation with ApiOutlined icon. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
BarChartOutlined,
|
||||
FileTextOutlined,
|
||||
GlobalOutlined,
|
||||
ApiOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useAuthStore } from '../store/auth';
|
||||
import Dashboard from '../pages/Dashboard';
|
||||
@@ -26,6 +27,7 @@ import FlowTemplates from '../pages/FlowTemplates';
|
||||
import GlobalVariables from '../pages/GlobalVariables';
|
||||
import Queues from '../pages/Queues';
|
||||
import SupervisorDashboard from '../pages/SupervisorDashboard';
|
||||
import OdooConfig from '../pages/OdooConfig';
|
||||
|
||||
const { Header, Sider, Content } = Layout;
|
||||
const { Text } = Typography;
|
||||
@@ -82,6 +84,11 @@ export default function MainLayout() {
|
||||
icon: <BarChartOutlined />,
|
||||
label: 'Supervisor',
|
||||
},
|
||||
{
|
||||
key: '/odoo',
|
||||
icon: <ApiOutlined />,
|
||||
label: 'Odoo',
|
||||
},
|
||||
{
|
||||
key: '/settings',
|
||||
icon: <SettingOutlined />,
|
||||
@@ -194,6 +201,7 @@ export default function MainLayout() {
|
||||
<Route path="/variables" element={<GlobalVariables />} />
|
||||
<Route path="/queues" element={<Queues />} />
|
||||
<Route path="/supervisor" element={<SupervisorDashboard />} />
|
||||
<Route path="/odoo" element={<OdooConfig />} />
|
||||
<Route path="/settings" element={<div>Configuración (próximamente)</div>} />
|
||||
</Routes>
|
||||
</Content>
|
||||
|
||||
182
frontend/src/pages/OdooConfig.tsx
Normal file
182
frontend/src/pages/OdooConfig.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Card,
|
||||
Form,
|
||||
Input,
|
||||
Button,
|
||||
Space,
|
||||
Typography,
|
||||
Alert,
|
||||
Spin,
|
||||
Tag,
|
||||
message,
|
||||
} from 'antd';
|
||||
import {
|
||||
LinkOutlined,
|
||||
CheckCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
ReloadOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { apiClient } from '../api/client';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
interface OdooConfig {
|
||||
url: string;
|
||||
database: string;
|
||||
username: string;
|
||||
is_connected: boolean;
|
||||
}
|
||||
|
||||
interface OdooConfigUpdate {
|
||||
url: string;
|
||||
database: string;
|
||||
username: string;
|
||||
api_key?: string;
|
||||
}
|
||||
|
||||
export default function OdooConfig() {
|
||||
const [form] = Form.useForm();
|
||||
const queryClient = useQueryClient();
|
||||
const [testStatus, setTestStatus] = useState<'idle' | 'testing' | 'success' | 'error'>('idle');
|
||||
|
||||
const { data: config, isLoading } = useQuery({
|
||||
queryKey: ['odoo-config'],
|
||||
queryFn: () => apiClient.get<OdooConfig>('/api/integrations/odoo/config'),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (config) {
|
||||
form.setFieldsValue({
|
||||
url: config.url,
|
||||
database: config.database,
|
||||
username: config.username,
|
||||
});
|
||||
}
|
||||
}, [config, form]);
|
||||
|
||||
const saveMutation = useMutation({
|
||||
mutationFn: (data: OdooConfigUpdate) =>
|
||||
apiClient.put('/api/integrations/odoo/config', data),
|
||||
onSuccess: () => {
|
||||
message.success('Configuracion guardada');
|
||||
queryClient.invalidateQueries({ queryKey: ['odoo-config'] });
|
||||
},
|
||||
onError: () => {
|
||||
message.error('Error al guardar');
|
||||
},
|
||||
});
|
||||
|
||||
const testMutation = useMutation({
|
||||
mutationFn: () => apiClient.post('/api/integrations/odoo/test', {}),
|
||||
onSuccess: () => {
|
||||
setTestStatus('success');
|
||||
message.success('Conexion exitosa');
|
||||
queryClient.invalidateQueries({ queryKey: ['odoo-config'] });
|
||||
},
|
||||
onError: () => {
|
||||
setTestStatus('error');
|
||||
message.error('Error de conexion');
|
||||
},
|
||||
});
|
||||
|
||||
const handleTest = () => {
|
||||
setTestStatus('testing');
|
||||
testMutation.mutate();
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
const values = await form.validateFields();
|
||||
saveMutation.mutate(values);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 24 }}>
|
||||
<Title level={4} style={{ margin: 0 }}>Configuracion Odoo</Title>
|
||||
<Space>
|
||||
{config?.is_connected ? (
|
||||
<Tag icon={<CheckCircleOutlined />} color="success">Conectado</Tag>
|
||||
) : (
|
||||
<Tag icon={<CloseCircleOutlined />} color="error">Desconectado</Tag>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<Form form={form} layout="vertical" style={{ maxWidth: 500 }}>
|
||||
<Form.Item
|
||||
name="url"
|
||||
label="URL de Odoo"
|
||||
rules={[{ required: true, message: 'Ingrese la URL' }]}
|
||||
>
|
||||
<Input
|
||||
prefix={<LinkOutlined />}
|
||||
placeholder="https://tu-empresa.odoo.com"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="database"
|
||||
label="Base de Datos"
|
||||
rules={[{ required: true, message: 'Ingrese el nombre de la base de datos' }]}
|
||||
>
|
||||
<Input placeholder="nombre_bd" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
label="Usuario (Email)"
|
||||
rules={[{ required: true, message: 'Ingrese el usuario' }]}
|
||||
>
|
||||
<Input placeholder="usuario@empresa.com" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="api_key"
|
||||
label="API Key"
|
||||
extra="Dejar vacio para mantener la actual"
|
||||
>
|
||||
<Input.Password placeholder="Nueva API Key (opcional)" />
|
||||
</Form.Item>
|
||||
|
||||
<Alert
|
||||
message="Como obtener la API Key"
|
||||
description={
|
||||
<ol style={{ paddingLeft: 20, margin: 0 }}>
|
||||
<li>Inicia sesion en Odoo</li>
|
||||
<li>Ve a Ajustes - Usuarios</li>
|
||||
<li>Selecciona tu usuario</li>
|
||||
<li>En la pestana Preferencias, genera una API Key</li>
|
||||
</ol>
|
||||
}
|
||||
type="info"
|
||||
style={{ marginBottom: 24 }}
|
||||
/>
|
||||
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handleSave}
|
||||
loading={saveMutation.isPending}
|
||||
>
|
||||
Guardar
|
||||
</Button>
|
||||
<Button
|
||||
icon={<ReloadOutlined spin={testStatus === 'testing'} />}
|
||||
onClick={handleTest}
|
||||
loading={testMutation.isPending}
|
||||
>
|
||||
Probar Conexion
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user