Skip to content

feat(calendar): provider-aware settings and connect UI shell (#1395) - #1425

Draft
h4yfans wants to merge 1 commit into
h4yfans/calendar-provider-credentials-settingsfrom
h4yfans/calendar-provider-ui-shell
Draft

feat(calendar): provider-aware settings and connect UI shell (#1395)#1425
h4yfans wants to merge 1 commit into
h4yfans/calendar-provider-credentials-settingsfrom
h4yfans/calendar-provider-ui-shell

Conversation

@h4yfans

@h4yfans h4yfans commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Closes #1395. Phase 0 of the multi-provider calendar epic #1390.

Stacked on #1424 (#1394) → #1423 (#1393) → #1422 (#1392) → #1407 (#1391). Base is h4yfans/calendar-provider-credentials-settings.

What

The Integrations page kept its own hardcoded calendar list, special-cased integration.id === 'google-calendar', and rendered a row whose every affordance assumed Google's capabilities.

Providers come from main. calendar:list-providers feeds the list; the static integration-registry.ts stops listing Google altogether, because a second entry there would render a capability-blind duplicate next to the live row.

GoogleCalendarIntegrationRowCalendarProviderRow, driven by provider.capabilities:

Capability Effect
!supportsWrite no "push events to provider" toggle — the engine refuses that write, so offering it would be a lie
!supportsMultiAccount no account list, no "Add account"; a single connection with a working disconnect
!supportsPush states the poll interval instead of claiming real-time sync

Query keys are ['calendar', providerId, …] throughout — status, sources, settings and the calendar list — so two providers can never share a cache slot. useGoogleCalendars becomes a Google-bound view of useProviderCalendars.

Connect dialog. google-calendar-connect-dialog.tsxcalendar-provider-connect-dialog.tsx, taking providerId and authFlow. oauth2 is the existing loopback flow; basic (server URL + username + app password) is filled in by the CalDAV UI issue and url (an ICS feed) by the ICS UI issue. The Google-named module stays as a re-export so the calendar toolbar pill and the agent composer's connected-tools tray keep their import paths.

Unknown providers render. A provider id this renderer has never heard of gets a labelled row, not a blank one — that is exactly what an older UI sees when main ships a provider ahead of it.

i18n

integrations.googleCalendar.* is renamed to integrations.calendarProvider.* across all 32 locales with every existing translation preserved (pushToGooglepushEvents inside it). Provider names and descriptions now come from integrations.registry.*, which gains ICS Subscription, CalDAV, Outlook / Microsoft 365 and an unknown-provider fallback. English strings that named Google interpolate {provider}.

New markup uses logical Tailwind classes (ms-*, end-*) per the RTL rule, and user-facing errors go through extractErrorMessage.

Two visible label changes

Called out because the acceptance criterion is "the Google row behaves identically from the user's point of view":

  • "Reconnect Google" → "Reconnect". Interpolating the provider name would have read "Reconnect Google Calendar"; the row header already names the provider, so the button drops it.
  • A new one-line cadence note under the description ("Changes arrive as they happen" for Google), so a poll-only or read-only provider can state what it actually does instead of letting users assume Google's behavior.

Behaviour — connect, reconnect, refresh, per-account disconnect, calendar selection, retry, both toggles, onboarding — is unchanged.

Verification

  • pnpm --filter @memry/desktop typecheck — green
  • pnpm --filter @memry/desktop i18n:checkok: i18n check passed
  • ESLint on the touched paths — 0 errors; Prettier clean
  • renderer project — 609 files, 6973 passed / 6 skipped

calendar-provider-row.test.tsx (renamed from google-calendar-integration-row.test.tsx) keeps all 17 original tests and adds 7 capability-driven ones: the push toggle is hidden for a read-only provider but the agent-access gate stays; a write-capable provider still gets the toggle; a single-connection provider has no "Add account" but does have a disconnect; a poll-only provider advertises "every 5 minutes" plus the read-only notice while a push-capable one says "as they happen"; one row per provider main reports; and an unrecognised provider id renders a labelled row.

That file was in the tsconfig.test.web.json exclude backlog. Renaming it took it out of the list, so its pre-existing type errors were fixed rather than re-excluded — the backlog shrank by one and did not grow.

Two other test files had their window.api.calendar mocks repointed to listProviderCalendars / retryCalendarSourceSync; assertions unchanged.

Docs

MEMRY_DOCS_IMPACT_SKIP=1 on push: Google remains the only provider, so nothing a user can reach changes except the two labels above. The user-facing multi-provider docs land with the first provider that actually ships (#1398).

@github-actions github-actions Bot added enhancement New feature or request test labels Aug 13, 2026
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

React Doctor found 1 new issue in 1 file · 1 warning · score 84 / 100 (Needs work) · 1 fixed · vs h4yfans/calendar-provider-credentials-settings

1 warning

src/renderer/src/hooks/use-ai-inline.ts

  • ⚠️ L46 State update after await in an effect no-set-state-after-await-in-effect

Reviewed by React Doctor for commit fc57c6f. See inline comments for fixes.

@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-credentials-settings branch from e5aeaf5 to f7aeaa4 Compare August 13, 2026 16:17
@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-ui-shell branch from da8a305 to 2c46af1 Compare August 13, 2026 16:17
@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-credentials-settings branch from f7aeaa4 to 57ac489 Compare August 13, 2026 16:19
@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-ui-shell branch from 2c46af1 to b03870c Compare August 13, 2026 16:19
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.50327% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../src/components/settings/calendar-provider-row.tsx 87.50% 9 Missing ⚠️
...ents/calendar/calendar-provider-connect-dialog.tsx 92.30% 1 Missing and 1 partial ⚠️
...ktop/src/renderer/src/services/calendar-service.ts 91.30% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

The Integrations page hardcoded its own calendar list, special-cased
`integration.id === 'google-calendar'`, and rendered a row whose every
affordance assumed Google's capabilities.

- Calendar providers now come from `calendar:list-providers`. Main is the only
  place that knows which providers this build ships and what each can do, so
  the static `integration-registry.ts` stops listing Google entirely.
- `GoogleCalendarIntegrationRow` becomes `CalendarProviderRow`, driven by
  `provider.capabilities`:
  - `!supportsWrite` hides the "push events to provider" toggle — the engine
    refuses that write, so offering it would be a lie
  - `!supportsMultiAccount` drops the account list and "Add account", keeping a
    single connection with a working disconnect
  - `!supportsPush` states the poll interval instead of claiming real-time sync
- Query keys are `['calendar', providerId, …]` throughout, so two providers can
  never share a cache slot. Same for `useProviderCalendars`.
- `google-calendar-connect-dialog.tsx` becomes
  `calendar-provider-connect-dialog.tsx`, taking `providerId` + `authFlow`.
  `oauth2` is the existing loopback flow; `basic` and `url` are filled in by
  the CalDAV and ICS UI issues. The Google-named module stays as a re-export so
  the toolbar pill and the agent tray keep their import paths.
- A provider id this renderer does not recognise renders a labelled row rather
  than a blank one — that is what an older UI sees when main ships a provider
  first.
- i18n: `integrations.googleCalendar.*` is renamed to
  `integrations.calendarProvider.*` across all 32 locales, translations
  preserved; provider names and descriptions come from
  `integrations.registry.*`, which gains ICS, CalDAV, Outlook and unknown
  entries. Strings that named Google now interpolate `{provider}`.

Two visible label changes: "Reconnect Google" is now "Reconnect" (the row
header already names the provider), and the calendar row carries a one-line
cadence note. Everything else in the Google row is unchanged.
@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-credentials-settings branch from 57ac489 to ccd6a4b Compare August 13, 2026 16:45
@h4yfans
h4yfans force-pushed the h4yfans/calendar-provider-ui-shell branch from b03870c to fc57c6f Compare August 13, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant