From bacd591dee928af928f5a501d5aa1c0850377340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 28 Jun 2026 17:36:21 +0200 Subject: [PATCH] feat(environment): frame overrides as location periods and surface effective-from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings → Environment now reads the override list as "location periods": a place plus a date range that covers a trip OR corrects a stretch of earlier history, overriding the home for the days it spans. Show the home's effective-from date and prefill the backfill start with it, so the default span matches what the server will actually store. Strings updated across all six locales. --- messages/de.json | 19 ++++----- messages/en.json | 19 ++++----- messages/es.json | 19 ++++----- messages/fr.json | 19 ++++----- messages/it.json | 19 ++++----- messages/pl.json | 19 ++++----- .../settings/environment-section.tsx | 39 +++++++++++++------ 7 files changed, 88 insertions(+), 65 deletions(-) diff --git a/messages/de.json b/messages/de.json index d971d07b8..c20c079b3 100644 --- a/messages/de.json +++ b/messages/de.json @@ -4292,8 +4292,8 @@ "select": "Auswählen", "saveError": "Änderung konnte nicht gespeichert werden.", "homeSaved": "Heimatort gespeichert.", - "travelAdded": "Reise-Ausnahme hinzugefügt.", - "travelRemoved": "Reise-Ausnahme entfernt.", + "travelAdded": "Ortszeitraum hinzugefügt.", + "travelRemoved": "Ortszeitraum entfernt.", "backfillQueued": "Nacherfassung eingeplant.", "backfillError": "Nacherfassung konnte nicht gestartet werden.", "startDate": "Startdatum", @@ -4301,20 +4301,21 @@ "storedDays": "{count} Tage Wetter gespeichert.", "home": { "title": "Heimatort", - "description": "Ein grober Ort auf Stadtebene – niemals ein genauer Standortverlauf. Wetter und Tageslicht werden für diesen Ort an allen Tagen ohne Reise-Ausnahme abgerufen.", + "description": "Ein grober Standort auf Stadtebene – niemals eine genaue Spur. Wetter und Tageslicht werden für diesen Ort an Tagen ohne Ortszeitraum abgerufen, ab dem Tag der Festlegung.", "current": "Aktuell: {label}", - "none": "Noch kein Heimatort festgelegt." + "none": "Noch kein Heimatort festgelegt.", + "since": "Wetter wird ab {date} erfasst. Frühere Tage bleiben leer, bis du einen Ortszeitraum hinzufügst." }, "travel": { - "title": "Reise-Ausnahmen", - "description": "Für einen Zeitraum, den du woanders verbracht hast, den Ort festlegen, damit das Wetter zu deinem tatsächlichen Aufenthalt passt.", - "none": "Keine Reise-Ausnahmen.", + "title": "Ortszeiträume", + "description": "Füge einen Ort und einen Zeitraum hinzu – eine Reise oder einen früheren Abschnitt deiner Verlaufsdaten. Der Zeitraum überschreibt für seine Tage deinen Wohnort, damit das Wetter zu deinem tatsächlichen Aufenthalt passt. So korrigierst du die Vergangenheit.", + "none": "Noch keine Ortszeiträume.", "add": "{label} hinzufügen", - "remove": "Reise-Ausnahme entfernen" + "remove": "Ortszeitraum entfernen" }, "backfill": { "title": "Vergangene Tage nacherfassen", - "description": "Wetter für einen vergangenen Zeitraum abrufen und speichern, damit ältere Tage in die Korrelationen einfließen.", + "description": "Rufe Wetter für einen vergangenen Zeitraum ab und speichere es, damit ältere Tage in die Korrelationen einfließen. Der Start steht standardmäßig auf dem Gültigkeitsdatum deines Wohnorts; um weiter zurückzureichen, füge zuerst einen Ortszeitraum für diesen Bereich hinzu.", "run": "Nacherfassen" } } diff --git a/messages/en.json b/messages/en.json index 5c88e09b7..f894cbae5 100644 --- a/messages/en.json +++ b/messages/en.json @@ -4292,8 +4292,8 @@ "select": "Select", "saveError": "Could not save your change.", "homeSaved": "Home location saved.", - "travelAdded": "Travel override added.", - "travelRemoved": "Travel override removed.", + "travelAdded": "Location period added.", + "travelRemoved": "Location period removed.", "backfillQueued": "Backfill queued.", "backfillError": "Could not start the backfill.", "startDate": "Start date", @@ -4301,20 +4301,21 @@ "storedDays": "{count} days of weather stored.", "home": { "title": "Home location", - "description": "A coarse, city-level location — never a precise track. Weather and daylight are fetched for this place on days no travel override applies.", + "description": "A coarse, city-level location — never a precise track. Weather and daylight are fetched for this place on days no location period applies, from the date you set it onward.", "current": "Current: {label}", - "none": "No home location set yet." + "none": "No home location set yet.", + "since": "Weather tracked from {date} onward. Earlier days stay empty until you add a location period." }, "travel": { - "title": "Travel overrides", - "description": "For a date range you spent elsewhere, set the location so the weather matches where you actually were.", - "none": "No travel overrides.", + "title": "Location periods", + "description": "Add a place and a date range — a trip, or a stretch of earlier history. The period overrides your home for the days it covers, so weather matches where you actually were. This is how you correct the past.", + "none": "No location periods yet.", "add": "Add {label}", - "remove": "Remove travel override" + "remove": "Remove location period" }, "backfill": { "title": "Backfill past days", - "description": "Fetch and store weather for a past date range so older days can join the correlations.", + "description": "Fetch and store weather for a past date range so older days join the correlations. The start defaults to your home's effective date; to reach further back, add a location period for that range first.", "run": "Backfill" } } diff --git a/messages/es.json b/messages/es.json index 82610e32b..3a1e009ab 100644 --- a/messages/es.json +++ b/messages/es.json @@ -4292,8 +4292,8 @@ "select": "Seleccionar", "saveError": "No se pudo guardar el cambio.", "homeSaved": "Ubicación principal guardada.", - "travelAdded": "Excepción de viaje añadida.", - "travelRemoved": "Excepción de viaje eliminada.", + "travelAdded": "Periodo de ubicación añadido.", + "travelRemoved": "Periodo de ubicación eliminado.", "backfillQueued": "Relleno programado.", "backfillError": "No se pudo iniciar el relleno.", "startDate": "Fecha de inicio", @@ -4301,20 +4301,21 @@ "storedDays": "{count} días de tiempo almacenados.", "home": { "title": "Ubicación principal", - "description": "Una ubicación aproximada a nivel de ciudad, nunca un rastro preciso. El tiempo y las horas de luz se obtienen para este lugar los días sin excepción de viaje.", + "description": "Una ubicación aproximada a nivel de ciudad, nunca un rastro preciso. El tiempo y la luz diurna se obtienen para este lugar en los días sin un periodo de ubicación, desde la fecha en que lo configuras.", "current": "Actual: {label}", - "none": "Aún no hay ubicación principal." + "none": "Aún no hay ubicación principal.", + "since": "Tiempo registrado desde {date}. Los días anteriores quedan vacíos hasta que añadas un periodo de ubicación." }, "travel": { - "title": "Excepciones de viaje", - "description": "Para un rango de fechas que pasaste en otro sitio, define la ubicación para que el tiempo coincida con dónde estuviste realmente.", - "none": "Sin excepciones de viaje.", + "title": "Periodos de ubicación", + "description": "Añade un lugar y un rango de fechas: un viaje o un tramo de tu historial anterior. El periodo anula tu hogar en los días que cubre, para que el tiempo coincida con donde estuviste realmente. Así corriges el pasado.", + "none": "Aún no hay periodos de ubicación.", "add": "Añadir {label}", - "remove": "Eliminar excepción de viaje" + "remove": "Eliminar periodo de ubicación" }, "backfill": { "title": "Rellenar días pasados", - "description": "Obtén y guarda el tiempo de un rango de fechas pasado para que los días anteriores entren en las correlaciones.", + "description": "Obtén y guarda el tiempo de un rango de fechas pasado para que los días antiguos entren en las correlaciones. El inicio toma por defecto la fecha de vigencia de tu hogar; para llegar más atrás, añade primero un periodo de ubicación para ese rango.", "run": "Rellenar" } } diff --git a/messages/fr.json b/messages/fr.json index a7a2052d7..c190687f2 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -4292,8 +4292,8 @@ "select": "Sélectionner", "saveError": "Impossible d'enregistrer la modification.", "homeSaved": "Lieu de référence enregistré.", - "travelAdded": "Exception de voyage ajoutée.", - "travelRemoved": "Exception de voyage supprimée.", + "travelAdded": "Période de localisation ajoutée.", + "travelRemoved": "Période de localisation supprimée.", "backfillQueued": "Récupération planifiée.", "backfillError": "Impossible de lancer la récupération.", "startDate": "Date de début", @@ -4301,20 +4301,21 @@ "storedDays": "{count} jours de météo enregistrés.", "home": { "title": "Lieu de référence", - "description": "Un lieu approximatif à l'échelle de la ville, jamais un suivi précis. La météo et la durée du jour sont récupérées pour ce lieu les jours sans exception de voyage.", + "description": "Une localisation approximative à l'échelle de la ville, jamais un tracé précis. La météo et la lumière du jour sont récupérées pour ce lieu les jours sans période de localisation, à partir de la date où vous le définissez.", "current": "Actuel : {label}", - "none": "Aucun lieu de référence défini." + "none": "Aucun lieu de référence défini.", + "since": "Météo enregistrée à partir du {date}. Les jours antérieurs restent vides jusqu'à ce que vous ajoutiez une période de localisation." }, "travel": { - "title": "Exceptions de voyage", - "description": "Pour une période passée ailleurs, définissez le lieu afin que la météo corresponde à l'endroit où vous étiez réellement.", - "none": "Aucune exception de voyage.", + "title": "Périodes de localisation", + "description": "Ajoutez un lieu et une plage de dates : un voyage ou une portion de votre historique passé. La période remplace votre domicile pour les jours qu'elle couvre, afin que la météo corresponde à l'endroit où vous étiez réellement. C'est ainsi que vous corrigez le passé.", + "none": "Aucune période de localisation pour l'instant.", "add": "Ajouter {label}", - "remove": "Supprimer l'exception de voyage" + "remove": "Supprimer la période de localisation" }, "backfill": { "title": "Récupérer les jours passés", - "description": "Récupérez et enregistrez la météo d'une période passée pour que les jours plus anciens entrent dans les corrélations.", + "description": "Récupérez et enregistrez la météo d'une plage de dates passée pour que les jours anciens rejoignent les corrélations. Le début reprend par défaut la date d'effet de votre domicile ; pour remonter plus loin, ajoutez d'abord une période de localisation pour cette plage.", "run": "Récupérer" } } diff --git a/messages/it.json b/messages/it.json index 94885be49..dbed40ed6 100644 --- a/messages/it.json +++ b/messages/it.json @@ -4292,8 +4292,8 @@ "select": "Seleziona", "saveError": "Impossibile salvare la modifica.", "homeSaved": "Posizione principale salvata.", - "travelAdded": "Eccezione di viaggio aggiunta.", - "travelRemoved": "Eccezione di viaggio rimossa.", + "travelAdded": "Periodo di posizione aggiunto.", + "travelRemoved": "Periodo di posizione rimosso.", "backfillQueued": "Recupero pianificato.", "backfillError": "Impossibile avviare il recupero.", "startDate": "Data di inizio", @@ -4301,20 +4301,21 @@ "storedDays": "{count} giorni di meteo salvati.", "home": { "title": "Posizione principale", - "description": "Una posizione approssimativa a livello di città, mai un tracciamento preciso. Il meteo e le ore di luce vengono recuperati per questo luogo nei giorni senza eccezioni di viaggio.", + "description": "Una posizione approssimativa a livello di città, mai un tracciato preciso. Meteo e luce diurna vengono recuperati per questo luogo nei giorni senza un periodo di posizione, a partire dalla data in cui lo imposti.", "current": "Attuale: {label}", - "none": "Nessuna posizione principale impostata." + "none": "Nessuna posizione principale impostata.", + "since": "Meteo registrato dal {date}. I giorni precedenti restano vuoti finché non aggiungi un periodo di posizione." }, "travel": { - "title": "Eccezioni di viaggio", - "description": "Per un intervallo di date trascorso altrove, imposta la posizione in modo che il meteo corrisponda a dove eri davvero.", - "none": "Nessuna eccezione di viaggio.", + "title": "Periodi di posizione", + "description": "Aggiungi un luogo e un intervallo di date: un viaggio o un tratto della tua cronologia passata. Il periodo prevale sulla tua residenza nei giorni che copre, così il meteo corrisponde a dove ti trovavi davvero. È così che correggi il passato.", + "none": "Nessun periodo di posizione.", "add": "Aggiungi {label}", - "remove": "Rimuovi eccezione di viaggio" + "remove": "Rimuovi periodo di posizione" }, "backfill": { "title": "Recupera i giorni passati", - "description": "Recupera e salva il meteo di un intervallo di date passato così i giorni più vecchi entrano nelle correlazioni.", + "description": "Recupera e salva il meteo di un intervallo di date passato così i giorni più vecchi entrano nelle correlazioni. L'inizio è impostato in modo predefinito sulla data di validità della tua residenza; per andare più indietro, aggiungi prima un periodo di posizione per quell'intervallo.", "run": "Recupera" } } diff --git a/messages/pl.json b/messages/pl.json index 70a7fea64..b8e0e201e 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -4292,8 +4292,8 @@ "select": "Wybierz", "saveError": "Nie udało się zapisać zmiany.", "homeSaved": "Zapisano lokalizację domową.", - "travelAdded": "Dodano wyjątek podróży.", - "travelRemoved": "Usunięto wyjątek podróży.", + "travelAdded": "Dodano okres lokalizacji.", + "travelRemoved": "Usunięto okres lokalizacji.", "backfillQueued": "Zaplanowano uzupełnianie.", "backfillError": "Nie udało się rozpocząć uzupełniania.", "startDate": "Data początkowa", @@ -4301,20 +4301,21 @@ "storedDays": "Zapisano dni pogody: {count}.", "home": { "title": "Lokalizacja domowa", - "description": "Przybliżona lokalizacja na poziomie miasta — nigdy dokładny ślad. Pogoda i długość dnia są pobierane dla tego miejsca w dni bez wyjątku podróży.", + "description": "Przybliżona lokalizacja na poziomie miasta – nigdy dokładny ślad. Pogoda i światło dzienne są pobierane dla tego miejsca w dni bez okresu lokalizacji, od dnia jego ustawienia.", "current": "Obecnie: {label}", - "none": "Nie ustawiono jeszcze lokalizacji domowej." + "none": "Nie ustawiono jeszcze lokalizacji domowej.", + "since": "Pogoda zapisywana od {date}. Wcześniejsze dni pozostają puste, dopóki nie dodasz okresu lokalizacji." }, "travel": { - "title": "Wyjątki podróży", - "description": "Dla zakresu dat spędzonego gdzie indziej ustaw lokalizację, aby pogoda odpowiadała temu, gdzie naprawdę byłeś.", - "none": "Brak wyjątków podróży.", + "title": "Okresy lokalizacji", + "description": "Dodaj miejsce i zakres dat: podróż lub fragment wcześniejszej historii. Okres zastępuje Twój dom w dniach, które obejmuje, aby pogoda odpowiadała miejscu, w którym naprawdę byłeś. W ten sposób korygujesz przeszłość.", + "none": "Brak okresów lokalizacji.", "add": "Dodaj {label}", - "remove": "Usuń wyjątek podróży" + "remove": "Usuń okres lokalizacji" }, "backfill": { "title": "Uzupełnij minione dni", - "description": "Pobierz i zapisz pogodę dla minionego zakresu dat, aby starsze dni weszły do korelacji.", + "description": "Pobierz i zapisz pogodę dla minionego zakresu dat, aby starsze dni weszły do korelacji. Początek domyślnie przyjmuje datę obowiązywania Twojego domu; aby sięgnąć dalej wstecz, najpierw dodaj okres lokalizacji dla tego zakresu.", "run": "Uzupełnij" } } diff --git a/src/components/settings/environment-section.tsx b/src/components/settings/environment-section.tsx index 68cc87b37..5f66bc2fb 100644 --- a/src/components/settings/environment-section.tsx +++ b/src/components/settings/environment-section.tsx @@ -52,6 +52,9 @@ interface EnvironmentOverview { lon: number; label: string | null; timezone: string; + /** ISO instant the home became effective (drives the conservative backfill + * default + the "tracked since" label). */ + since: string | null; } | null; travel: TravelDTO[]; context: { @@ -162,9 +165,9 @@ export function EnvironmentSection() { const backfill = useMutation({ mutationKey: queryKeys.environment(), - mutationFn: () => + mutationFn: (startDate: string) => apiPost("/api/environment/backfill", { - startDate: backfillStart, + startDate, endDate: backfillEnd, }), onSuccess: () => { @@ -192,6 +195,11 @@ export function EnvironmentSection() { const data = overview.data; const home = data?.home ?? null; + // Conservative default: backfill starts at the home's effective-from date. The + // user can still type an earlier start, but pre-home days resolve to SKIP on + // the server — to fill the deep past they add an explicit location period. + const effectiveBackfillStart = + backfillStart || home?.since?.slice(0, 10) || ""; return (
@@ -207,11 +215,20 @@ export function EnvironmentSection() {

{home ? ( -

- {t("settings.sections.environment.home.current", { - label: home.label ?? `${home.lat}, ${home.lon}`, - })} -

+
+

+ {t("settings.sections.environment.home.current", { + label: home.label ?? `${home.lat}, ${home.lon}`, + })} +

+ {home.since && ( +

+ {t("settings.sections.environment.home.since", { + date: home.since.slice(0, 10), + })} +

+ )} +
) : (

{t("settings.sections.environment.home.none")} @@ -394,7 +411,7 @@ export function EnvironmentSection() { setBackfillStart(e.target.value)} />

@@ -413,11 +430,11 @@ export function EnvironmentSection() { type="button" disabled={ !home || - backfillStart.length === 0 || - backfillStart > backfillEnd || + effectiveBackfillStart.length === 0 || + effectiveBackfillStart > backfillEnd || backfill.isPending } - onClick={() => backfill.mutate()} + onClick={() => backfill.mutate(effectiveBackfillStart)} > {t("settings.sections.environment.backfill.run")}