From 031bb1806787f2a4ffe087fd9d321ba863339cdf Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Thu, 20 Aug 2026 07:27:42 +0200 Subject: [PATCH] =?UTF-8?q?fix(calendar):=20en=20tom=20kalender=20skal=20s?= =?UTF-8?q?ige=20hvorfor,=20ikke=20bare=20v=C3=A6re=20tom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At vælge en kalender er nogen, der siger "vis mig den her". At gemme valget og lade gitteret stå tomt, til fejeren kommer forbi et kvarter senere, er en kalender, der påstår, at fjorten dage er fri — og personen står på siden med knappen under hånden. Gemningen henter nu selv. Og er der forbundet en konto uden at der er valgt nogen kalendere, siger visningen dét. "Der er ikke valgt en kalender" og "der er ikke booket noget" ser ens ud, og kun den ene er noget at gøre noget ved. --- web/e2e/smoke.spec.js | 10 +++++++++- web/src/lib/locales/da.js | 1 + web/src/lib/locales/en.js | 1 + .../indstillinger/integrationer/+page.svelte | 13 ++++++++++++- web/src/routes/kalender/+page.svelte | 17 ++++++++++++++++- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/web/e2e/smoke.spec.js b/web/e2e/smoke.spec.js index a4f1b6d..b82d005 100644 --- a/web/e2e/smoke.spec.js +++ b/web/e2e/smoke.spec.js @@ -1072,7 +1072,9 @@ test('kalenderen viser Googles begivenheder over egne opgaver, og kun opgaven ka read_only: true, has_client: true, redirect_uri: 'http://localhost/oauth/calendar/callback', - calendars: [] + calendars: [ + { id: 'c1', remote_id: 'fam', name: 'Arbejde', colour: '#0b8043', shown: true } + ] } }) ); @@ -1109,6 +1111,12 @@ test('kalenderen viser Googles begivenheder over egne opgaver, og kun opgaven ka } await expect(cell, `uge-visningen nåede aldrig frem til ${day}`).toBeVisible(); + // Connected, with a calendar ticked — so neither of the two "there is nothing + // here" notices belongs on the screen. They exist so an empty grid is never + // unexplained, and an explanation for a state you are not in is noise. + await expect(page.getByText('Ingen kalender er forbundet endnu.')).toBeHidden(); + await expect(page.getByText('Ingen af kontoens kalendere er valgt endnu.')).toBeHidden(); + // Both kinds are in the same cell, which is the whole point of the view. const event = cell.locator('.event').filter({ hasText: 'Bestyrelsesmøde' }); const allDay = cell.locator('.event').filter({ hasText: 'Feriedag' }); diff --git a/web/src/lib/locales/da.js b/web/src/lib/locales/da.js index 69909b5..06035aa 100644 --- a/web/src/lib/locales/da.js +++ b/web/src/lib/locales/da.js @@ -630,6 +630,7 @@ export const da = { 'cal.notConnected': 'Ingen kalender er forbundet endnu. Det gøres under Indstillinger → Integrationer.', 'cal.settings': 'Indstillinger', + 'cal.noneChosen': 'Ingen af kontoens kalendere er valgt endnu.', 'cal.allDay': 'Hele dagen', 'cal.openInGoogle': 'Åbn i Google Kalender', 'cal.beyondWindow': diff --git a/web/src/lib/locales/en.js b/web/src/lib/locales/en.js index e3c6c08..0e8709f 100644 --- a/web/src/lib/locales/en.js +++ b/web/src/lib/locales/en.js @@ -623,6 +623,7 @@ export const en = { 'cal.title': 'Calendar', 'cal.notConnected': 'No calendar is connected yet. That is done under Settings → Integrations.', 'cal.settings': 'Settings', + 'cal.noneChosen': 'None of the account’s calendars are chosen yet.', 'cal.allDay': 'All day', 'cal.openInGoogle': 'Open in Google Calendar', 'cal.beyondWindow': diff --git a/web/src/routes/indstillinger/integrationer/+page.svelte b/web/src/routes/indstillinger/integrationer/+page.svelte index f23158c..5a57c04 100644 --- a/web/src/routes/indstillinger/integrationer/+page.svelte +++ b/web/src/routes/indstillinger/integrationer/+page.svelte @@ -197,8 +197,19 @@ calendarsSaved = false; try { await api.setCalendars(shownCalendars); - await loadCalendar(); calendarsSaved = true; + // And fetch, without being asked again. + // + // Ticking a calendar is somebody saying "show me this one". Saving the + // choice and leaving the grid empty until the sweep comes round a quarter + // of an hour later is a calendar that says a fortnight is clear — and the + // person is on this page, watching, with the button under their hand. + // Also what refreshes the panel: syncCalendarNow reloads it when it is done. + if (shownCalendars.length) { + await syncCalendarNow(); + } else { + await loadCalendar(); + } } catch (e) { app.toast(humanMessage(e)); } finally { diff --git a/web/src/routes/kalender/+page.svelte b/web/src/routes/kalender/+page.svelte index 81e2c84..2d55f0a 100644 --- a/web/src/routes/kalender/+page.svelte +++ b/web/src/routes/kalender/+page.svelte @@ -22,13 +22,18 @@ /** Null until the first answer, so nothing flashes before it is known. */ let window_ = $state(null); let connected = $state(null); + /** Whether any calendar in the connected account is ticked. */ + let anyShown = $state(false); /** The dates the grid is showing, so the notice below can compare against them. */ let showing = $state(null); $effect(() => { api .getCalendar() - .then((status) => (connected = status.connected)) + .then((status) => { + connected = status.connected; + anyShown = (status.calendars ?? []).some((c) => c.shown); + }) .catch(() => { // A calendar that could not be asked about is not a reason to withhold // the grid: the tasks in it are verdande's own and do not depend on @@ -101,6 +106,16 @@

{/if} + + {#if connected && !anyShown} +

+ {t('cal.noneChosen')} + {t('cal.settings')} +

+ {/if} + {#if beyond}

{t('cal.beyondWindow', { from: window_.from, to: window_.to })}

{/if}