feat: add Agrarmonitor integration module
- New backend module (agrarmonitor) with status check and device registration - Frontend settings tab with connection status display and registration form - Environment variables for base URLs, credentials, cookie path and encryption key - Docker Compose env passthrough for agrarmonitor config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -176,3 +176,19 @@ export const INBOX_ACTION_LABELS: Record<InboxActionType, string> = {
|
||||
EXPORT: 'Export (FTP/WebDAV)',
|
||||
PAPERLESS: 'In Paperless importieren',
|
||||
};
|
||||
|
||||
export interface AgrarmonitorStatusData {
|
||||
connected: boolean;
|
||||
registriert: boolean | null;
|
||||
freigeschaltet: boolean | null;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const agrarmonitorApi = {
|
||||
getStatus: () =>
|
||||
api.get<AgrarmonitorStatusData>('/api/agrarmonitor/status').then((r) => r.data),
|
||||
registerDevice: (pcName: string, agrarmonitorId: string) =>
|
||||
api
|
||||
.post<{ success: boolean; message: string }>('/api/agrarmonitor/register', { pcName, agrarmonitorId })
|
||||
.then((r) => r.data),
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
UserOutlined, FileTextOutlined, ThunderboltOutlined,
|
||||
PlusOutlined, DeleteOutlined, EditOutlined, CloudUploadOutlined,
|
||||
HistoryOutlined, MinusCircleOutlined, CopyOutlined, KeyOutlined,
|
||||
QrcodeOutlined, UnorderedListOutlined, PrinterOutlined,
|
||||
QrcodeOutlined, UnorderedListOutlined, PrinterOutlined, GlobalOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import type { FormInstance } from 'antd';
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
type SettingPostprocessingLog, type FilterGroup, type FilterCondition,
|
||||
INBOX_ACTION_LABELS,
|
||||
type InboxAction, type InboxActionType,
|
||||
agrarmonitorApi, type AgrarmonitorStatusData,
|
||||
} from '../api/settings';
|
||||
import { clientsApi, type Client } from '../api/inbox';
|
||||
import { apiKeysApi, type ApiKey } from '../api/api-keys';
|
||||
@@ -2221,6 +2222,130 @@ function BarcodeTemplatesTab() {
|
||||
}
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// Agrarmonitor Tab
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
function AgrarmonitorTab() {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [registering, setRegistering] = useState(false);
|
||||
const [status, setStatus] = useState<AgrarmonitorStatusData | null>(null);
|
||||
const [registerResult, setRegisterResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
|
||||
const handleLoadStatus = async () => {
|
||||
setLoading(true);
|
||||
setRegisterResult(null);
|
||||
try {
|
||||
const data = await agrarmonitorApi.getStatus();
|
||||
setStatus(data);
|
||||
} catch {
|
||||
setStatus({ connected: false, registriert: null, freigeschaltet: null, error: 'Netzwerkfehler' });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRegister = async () => {
|
||||
const values = await form.validateFields();
|
||||
setRegistering(true);
|
||||
setRegisterResult(null);
|
||||
try {
|
||||
const result = await agrarmonitorApi.registerDevice(values.pcName, values.agrarmonitorId);
|
||||
setRegisterResult(result);
|
||||
if (result.success) {
|
||||
message.success('Gerät erfolgreich registriert');
|
||||
await handleLoadStatus();
|
||||
}
|
||||
} catch {
|
||||
setRegisterResult({ success: false, message: 'Registrierung fehlgeschlagen' });
|
||||
} finally {
|
||||
setRegistering(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderStatusTag = (value: boolean | null, labelTrue: string, labelFalse: string) => {
|
||||
if (value === null) return <Tag>–</Tag>;
|
||||
return value
|
||||
? <Tag color="success">{labelTrue}</Tag>
|
||||
: <Tag color="error">{labelFalse}</Tag>;
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: 600 }}>
|
||||
<Typography.Title level={4}>Agrarmonitor</Typography.Title>
|
||||
<Typography.Paragraph type="secondary">
|
||||
Verbindungsstatus und Geräte-Registrierung für die Agrarmonitor-Schnittstelle.
|
||||
Zugangsdaten werden in der <code>.env</code> konfiguriert.
|
||||
</Typography.Paragraph>
|
||||
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Button loading={loading} onClick={handleLoadStatus}>
|
||||
Status abrufen
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{status && (
|
||||
<Card size="small" title="Status">
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<strong>Verbindung: </strong>
|
||||
{status.connected
|
||||
? <Tag color="success">Verbunden</Tag>
|
||||
: <Tag color="error">Nicht verbunden</Tag>}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Registriert: </strong>
|
||||
{renderStatusTag(status.registriert, 'Ja', 'Nein')}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Freigeschaltet: </strong>
|
||||
{renderStatusTag(status.freigeschaltet, 'Ja', 'Nein')}
|
||||
</div>
|
||||
{status.error && (
|
||||
<div style={{ color: '#ff4d4f' }}>{status.error}</div>
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{status?.registriert === false && (
|
||||
<Card size="small" title="Gerät registrieren">
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item
|
||||
name="pcName"
|
||||
label="PC-Name"
|
||||
rules={[{ required: true, message: 'Bitte PC-Name eingeben' }]}
|
||||
>
|
||||
<Input placeholder="BUERO-PC-01" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="agrarmonitorId"
|
||||
label="Agrarmonitor-ID / Firma"
|
||||
rules={[{ required: true, message: 'Bitte Agrarmonitor-ID eingeben' }]}
|
||||
>
|
||||
<Input placeholder="Agrarmonitor-ID" />
|
||||
</Form.Item>
|
||||
<Button type="primary" loading={registering} onClick={handleRegister}>
|
||||
Gerät registrieren
|
||||
</Button>
|
||||
</Form>
|
||||
{registerResult && (
|
||||
<div style={{ marginTop: 12 }}>
|
||||
<Tag color={registerResult.success ? 'success' : 'error'}>
|
||||
{registerResult.message}
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// Settings Page
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
@@ -2277,6 +2402,11 @@ export default function SettingsPage() {
|
||||
label: <span><KeyOutlined /> API-Keys</span>,
|
||||
children: <ApiKeysTab />,
|
||||
},
|
||||
{
|
||||
key: 'agrarmonitor',
|
||||
label: <span><GlobalOutlined /> Agrarmonitor</span>,
|
||||
children: <AgrarmonitorTab />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user