feat: basic caldav support (#14372)

fix #13531 

#### PR Dependency Tree


* **PR #14372** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* CalDAV calendar integration: link and sync CalDAV-compatible calendars
(discovery, listing, event sync).
* New UI flow and dialog to link CalDAV accounts with provider
selection, credentials, and display name.

* **API / Config**
* Server exposes CalDAV provider presets in config and new GraphQL
mutation to link CalDAV accounts.
  * New calendar config section for CalDAV with validation and defaults.

* **Tests**
  * Comprehensive CalDAV integration test suite added.

* **Chores**
* Removed analytics tokens from build configuration and reduced Cloud
E2E test shards.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-02-05 03:04:21 +08:00
committed by GitHub
parent 403f16b404
commit a655b79166
34 changed files with 2995 additions and 217 deletions

View File

@@ -1,5 +1,11 @@
query calendarProviders {
serverConfig {
calendarCalDAVProviders {
id
label
requiresAppPassword
docsUrl
}
calendarProviders
}
}

View File

@@ -0,0 +1,15 @@
mutation linkCalDavAccount($input: LinkCalDAVAccountInput!) {
linkCalDAVAccount(input: $input) {
id
provider
providerAccountId
displayName
email
status
lastError
refreshIntervalMinutes
calendarsCount
createdAt
updatedAt
}
}

View File

@@ -656,11 +656,37 @@ export const calendarProvidersQuery = {
op: 'calendarProviders',
query: `query calendarProviders {
serverConfig {
calendarCalDAVProviders {
id
label
requiresAppPassword
docsUrl
}
calendarProviders
}
}`,
};
export const linkCalDavAccountMutation = {
id: 'linkCalDavAccountMutation' as const,
op: 'linkCalDavAccount',
query: `mutation linkCalDavAccount($input: LinkCalDAVAccountInput!) {
linkCalDAVAccount(input: $input) {
id
provider
providerAccountId
displayName
email
status
lastError
refreshIntervalMinutes
calendarsCount
createdAt
updatedAt
}
}`,
};
export const linkCalendarAccountMutation = {
id: 'linkCalendarAccountMutation' as const,
op: 'linkCalendarAccount',

View File

@@ -259,6 +259,14 @@ export interface CalendarAccountObjectType {
updatedAt: Scalars['DateTime']['output'];
}
export interface CalendarCalDavProviderPresetObjectType {
__typename?: 'CalendarCalDAVProviderPresetObjectType';
docsUrl: Maybe<Scalars['String']['output']>;
id: Scalars['String']['output'];
label: Scalars['String']['output'];
requiresAppPassword: Maybe<Scalars['Boolean']['output']>;
}
export interface CalendarEventObjectType {
__typename?: 'CalendarEventObjectType';
allDay: Scalars['Boolean']['output'];
@@ -1466,6 +1474,13 @@ export interface LimitedUserType {
hasPassword: Maybe<Scalars['Boolean']['output']>;
}
export interface LinkCalDavAccountInput {
displayName?: InputMaybe<Scalars['String']['input']>;
password: Scalars['String']['input'];
providerPresetId: Scalars['String']['input'];
username: Scalars['String']['input'];
}
export interface LinkCalendarAccountInput {
provider: CalendarProviderType;
redirectUri?: InputMaybe<Scalars['String']['input']>;
@@ -1632,6 +1647,7 @@ export interface Mutation {
installLicense: License;
inviteMembers: Array<InviteResult>;
leaveWorkspace: Scalars['Boolean']['output'];
linkCalDAVAccount: CalendarAccountObjectType;
linkCalendarAccount: Scalars['String']['output'];
/** mention user in a doc */
mentionUser: Scalars['ID']['output'];
@@ -1943,6 +1959,10 @@ export interface MutationLeaveWorkspaceArgs {
workspaceName?: InputMaybe<Scalars['String']['input']>;
}
export interface MutationLinkCalDavAccountArgs {
input: LinkCalDavAccountInput;
}
export interface MutationLinkCalendarAccountArgs {
input: LinkCalendarAccountInput;
}
@@ -2699,6 +2719,7 @@ export interface ServerConfigType {
availableWorkspaceFeatures: Array<FeatureType>;
/** server base url */
baseUrl: Scalars['String']['output'];
calendarCalDAVProviders: Array<CalendarCalDavProviderPresetObjectType>;
calendarProviders: Array<CalendarProviderType>;
/** credentials requirement */
credentialsRequirement: CredentialsRequirementType;
@@ -3956,6 +3977,35 @@ export type CalendarProvidersQuery = {
serverConfig: {
__typename?: 'ServerConfigType';
calendarProviders: Array<CalendarProviderType>;
calendarCalDAVProviders: Array<{
__typename?: 'CalendarCalDAVProviderPresetObjectType';
id: string;
label: string;
requiresAppPassword: boolean | null;
docsUrl: string | null;
}>;
};
};
export type LinkCalDavAccountMutationVariables = Exact<{
input: LinkCalDavAccountInput;
}>;
export type LinkCalDavAccountMutation = {
__typename?: 'Mutation';
linkCalDAVAccount: {
__typename?: 'CalendarAccountObjectType';
id: string;
provider: CalendarProviderType;
providerAccountId: string;
displayName: string | null;
email: string | null;
status: string;
lastError: string | null;
refreshIntervalMinutes: number;
calendarsCount: number;
createdAt: string;
updatedAt: string;
};
};
@@ -7656,6 +7706,11 @@ export type Mutations =
variables: CreateBlobUploadMutationVariables;
response: CreateBlobUploadMutation;
}
| {
name: 'linkCalDavAccountMutation';
variables: LinkCalDavAccountMutationVariables;
response: LinkCalDavAccountMutation;
}
| {
name: 'linkCalendarAccountMutation';
variables: LinkCalendarAccountMutationVariables;