feat(calendar): add domain field and test-connection button to Exchange sources

- Prisma: domain String? added to CalendarSource model (db push applied)
- DTOs: domain in CreateCalendarSourceDto, UpdateCalendarSourceDto, new TestCalendarSourceConfigDto
- Service: domain in SOURCE_SAFE_SELECT, addSource, updateSource; new testConnectionFromConfig method
- Controller: POST /calendar/sources/test-config (before :id routes to avoid collision)
- ExchangeProvider: domain in all source interfaces; passed as 3rd arg to EWS WebCredentials
- Frontend: domain in CalendarSource/CreateSourcePayload/UpdateSourcePayload; testSourceConfig API fn
- Form: domain field (Exchange-only), "Test connection" button with idle/loading/success/error states
- i18n: de+en keys for formFieldDomain, formFieldDomainHint, formTestConnection, formTesting, formTestSuccess, formTestFailed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 13:15:13 +02:00
parent 2e0e7290ba
commit 42daa87e5e
12 changed files with 214 additions and 6 deletions
+25
View File
@@ -22,6 +22,7 @@ export interface CalendarSource {
name: string;
type: 'caldav' | 'ics' | 'exchange';
exchangeMode?: string | null;
domain?: string | null;
url: string;
username?: string | null;
color?: string | null;
@@ -59,6 +60,7 @@ export interface CreateSourcePayload {
username?: string;
password?: string;
exchangeMode?: string;
domain?: string;
color?: string;
}
@@ -73,6 +75,7 @@ export interface UpdateSourcePayload {
username?: string;
password?: string;
exchangeMode?: string;
domain?: string;
color?: string;
isVisible?: boolean;
}
@@ -138,6 +141,28 @@ export async function deleteSource(id: string): Promise<void> {
if (!res.ok) throw new Error('Failed to delete calendar source');
}
/**
* Test a calendar configuration without saving it.
* POST /calendar/sources/test-config
*/
export async function testSourceConfig(config: {
type: string;
url: string;
username?: string;
password?: string;
exchangeMode?: string;
domain?: string;
}): Promise<{ success: boolean; error?: string }> {
const res = await fetch(`${API_URL}/calendar/sources/test-config`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(config),
});
if (!res.ok) throw new Error('Test request failed');
return res.json();
}
/**
* Test connection to a calendar source.
* POST /calendar/sources/:id/test