feat: add OpenWeatherMap provider, retry transport, and forecast config UI
Add OpenWeatherMap One Call API 3.0 as alternative weather provider with configurable selection in the Forecast tab. Includes server-side retry transport with exponential backoff for all weather providers, structured error responses with type classification, auto-fetch on stale dashboard data, and improved error UX with specific messages.
This commit is contained in:
@@ -375,7 +375,29 @@
|
||||
<!-- Forecast tab -->
|
||||
<section id="tab-forecast" class="tab-panel hidden">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">{{t "setup.forecast.help"}}</p>
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-3">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-4">
|
||||
<!-- Provider config -->
|
||||
<form id="forecast-config-form" class="space-y-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">{{t "setup.forecast.provider"}}</label>
|
||||
<select id="forecast-provider-select" class="w-full px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
||||
<option value="openmeteo">Open-Meteo ({{t "setup.forecast.free"}})</option>
|
||||
<option value="openweathermap">OpenWeatherMap</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="forecast-apikey-group" class="hidden">
|
||||
<label class="block text-sm font-medium mb-1">{{t "setup.forecast.apiKey"}}</label>
|
||||
<input type="password" id="forecast-api-key" placeholder="{{t "setup.forecast.apiKeyPlaceholder"}}" class="w-full px-3 py-1.5 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div id="forecast-provider-hint" class="text-xs text-gray-400"></div>
|
||||
<button type="submit" class="px-4 py-1.5 text-sm bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition">{{t "setup.forecast.saveConfig"}}</button>
|
||||
</form>
|
||||
|
||||
<hr class="border-gray-200 dark:border-gray-700">
|
||||
|
||||
<!-- Fetch button -->
|
||||
<div class="flex items-center gap-4">
|
||||
<button id="fetch-forecast-btn" class="px-4 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition text-sm">
|
||||
{{t "setup.forecast.fetch"}}
|
||||
@@ -385,7 +407,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div id="forecast-spinner" class="hidden text-sm text-gray-500 dark:text-gray-400">
|
||||
<span class="inline-block animate-spin mr-2">↻</span> {{t "setup.forecast.fetching"}}
|
||||
<span class="inline-block animate-spin mr-2">↻</span> {{t "setup.forecast.fetching"}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user