feat: Gitea Webhook, IMAP, Settings & Deployment docs

- Webhook route and Gitea integration
- IMAP service and Nextcloud/Porkbun setup docs
- Settings UI improvements and API updates
- SSH/Webhook fix prompt for emailsorter.webklar.com
- Bootstrap, config and AI sorter updates
This commit is contained in:
2026-01-31 15:00:00 +01:00
parent 7e7ec1013b
commit cbb225c001
24 changed files with 2173 additions and 32 deletions

View File

@@ -56,7 +56,7 @@ export const api = {
return fetchApi<Array<{
id: string
email: string
provider: 'gmail' | 'outlook'
provider: 'gmail' | 'outlook' | 'imap'
connected: boolean
lastSync?: string
}>>(`/email/accounts?userId=${userId}`)
@@ -69,6 +69,24 @@ export const api = {
})
},
async connectImapAccount(
userId: string,
params: { email: string; password: string; imapHost?: string; imapPort?: number; imapSecure?: boolean }
) {
return fetchApi<{ accountId: string }>('/email/connect', {
method: 'POST',
body: JSON.stringify({
userId,
provider: 'imap',
email: params.email,
accessToken: params.password,
imapHost: params.imapHost,
imapPort: params.imapPort,
imapSecure: params.imapSecure,
}),
})
},
async disconnectEmailAccount(accountId: string, userId: string) {
return fetchApi<{ success: boolean }>(`/email/accounts/${accountId}?userId=${userId}`, {
method: 'DELETE',
@@ -403,6 +421,49 @@ export const api = {
})
},
// ═══════════════════════════════════════════════════════════════════════════
// ME / ADMIN
// ═══════════════════════════════════════════════════════════════════════════
async getMe(email: string) {
return fetchApi<{ isAdmin: boolean }>(`/me?email=${encodeURIComponent(email)}`)
},
// ═══════════════════════════════════════════════════════════════════════════
// NAME LABELS (Workers Admin only)
// ═══════════════════════════════════════════════════════════════════════════
async getNameLabels(userId: string, email: string) {
return fetchApi<Array<{
id?: string
name: string
email?: string
keywords?: string[]
enabled: boolean
}>>(`/preferences/name-labels?userId=${userId}&email=${encodeURIComponent(email)}`)
},
async saveNameLabel(
userId: string,
userEmail: string,
nameLabel: { id?: string; name: string; email?: string; keywords?: string[]; enabled: boolean }
) {
return fetchApi<{ id?: string; name: string; email?: string; keywords?: string[]; enabled: boolean }>(
'/preferences/name-labels',
{
method: 'POST',
body: JSON.stringify({ userId, email: userEmail, nameLabel }),
}
)
},
async deleteNameLabel(userId: string, userEmail: string, labelId: string) {
return fetchApi<{ success: boolean }>(
`/preferences/name-labels/${labelId}?userId=${userId}&email=${encodeURIComponent(userEmail)}`,
{ method: 'DELETE' }
)
},
// ═══════════════════════════════════════════════════════════════════════════
// PRODUCTS & QUESTIONS (Legacy)
// ═══════════════════════════════════════════════════════════════════════════