From 32cfafc88a0fd557f3fb999b72fa53f88fd4c97e Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 15:16:02 -0500 Subject: [PATCH 01/30] Add release task --- tasks.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tasks.py diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..44c4c94 --- /dev/null +++ b/tasks.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8; -*- +""" +Tasks for myweather +""" + +import os +import json + +from invoke import task + + +here = os.path.dirname(__file__) + + +@task +def release(c): + """ + Release a new version of myweather + """ + # figure out current package version + package_json = os.path.join(here, 'package.json') + with open(package_json, 'rt') as f: + js = json.load(f) + version = js['version'] + + # build the app, create zip archive + c.run('npm run build') + os.chdir('dist') + filename = f'myweather-{version}.zip' + c.run(f'zip --recurse-paths {filename} *') + os.chdir(os.pardir) + + # upload zip archive to server + c.run(f'scp dist/{filename} weather.edbob.org:/srv/myweather/releases/{filename}') + c.run(f"ssh weather.edbob.org 'cd /srv/myweather/releases; ln -sf {filename} latest.zip'") From 866742130dd441619ed68b03af75fcbcfe37c8c4 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 18:36:44 -0500 Subject: [PATCH 02/30] Add radar panel for Weather view --- src/views/WeatherView.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/views/WeatherView.vue b/src/views/WeatherView.vue index 78a167d..64ce820 100644 --- a/src/views/WeatherView.vue +++ b/src/views/WeatherView.vue @@ -25,6 +25,14 @@ export default { generated = generated.toLocaleTimeString('en-US', {timeStyle: 'short'}) return `Forecast @ ${generated}` }, + + radarURL() { + if (this.weatherStore.weather) { + const station = this.weatherStore.weather.properties.radarStation + return `https://radar.weather.gov/ridge/standard/${station}_loop.gif` + } + }, + }, activated() { @@ -114,6 +122,16 @@ export default { + + + From d28c4f73951e3b810be679d3b4ded56a6a3760a8 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 18:38:27 -0500 Subject: [PATCH 03/30] Update changelog --- CHANGELOG.md | 16 ++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..00eaae4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.1.1 - 2024-06-08 +### Added +- Add radar panel for Weather view. + +## 0.1.0 - 2024-06-07 +### Added +- Initial release, very basic. diff --git a/package-lock.json b/package-lock.json index fe4e88a..4c94a2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index 8d50395..c853483 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.0", + "version": "0.1.1", "private": true, "type": "module", "scripts": { From d17ab853af7ee84d295a1df2ab07eca23c79cd6d Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 18:40:14 -0500 Subject: [PATCH 04/30] Upgrade server when pushing release since that is really the only point of doing a release, for now --- tasks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks.py b/tasks.py index 44c4c94..a33596f 100644 --- a/tasks.py +++ b/tasks.py @@ -33,3 +33,6 @@ def release(c): # upload zip archive to server c.run(f'scp dist/{filename} weather.edbob.org:/srv/myweather/releases/{filename}') c.run(f"ssh weather.edbob.org 'cd /srv/myweather/releases; ln -sf {filename} latest.zip'") + + # run upgrade on server + c.run('ssh weather.edbob.org /srv/myweather/upgrade.sh') From de9980b0143ed64365ef715f8807789431865168 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:02:41 -0500 Subject: [PATCH 05/30] Show both "latest" and "loop" radar images --- src/stores/weather.js | 8 ++++++++ src/views/WeatherView.vue | 17 ++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/stores/weather.js b/src/stores/weather.js index b157459..c8c91ab 100644 --- a/src/stores/weather.js +++ b/src/stores/weather.js @@ -11,6 +11,8 @@ const getDefaults = () => { cityState, weather: null, forecast: null, + radarLatestURL: null, + radarLoopURL: null, } } @@ -28,6 +30,8 @@ export const useWeatherStore = defineStore('weather', { this.setCityState(null) this.setWeather(null) this.setForecast(null) + this.radarLatestURL = null + this.radarLoopURL = null }, async getWeather() { @@ -48,6 +52,10 @@ export const useWeatherStore = defineStore('weather', { this.setCityState(cityState) } + const station = weather.properties.radarStation + this.radarLatestURL = `https://radar.weather.gov/ridge/standard/${station}_0.gif` + this.radarLoopURL = `https://radar.weather.gov/ridge/standard/${station}_loop.gif` + this.setWeather(weather) } diff --git a/src/views/WeatherView.vue b/src/views/WeatherView.vue index 64ce820..3c1a66c 100644 --- a/src/views/WeatherView.vue +++ b/src/views/WeatherView.vue @@ -25,14 +25,6 @@ export default { generated = generated.toLocaleTimeString('en-US', {timeStyle: 'short'}) return `Forecast @ ${generated}` }, - - radarURL() { - if (this.weatherStore.weather) { - const station = this.weatherStore.weather.properties.radarStation - return `https://radar.weather.gov/ridge/standard/${station}_loop.gif` - } - }, - }, activated() { @@ -128,7 +120,14 @@ export default { Radar

- +
+
+ +
+
+ +
+
From 6df6f84afe78671d4e0f51b763809a6b2aa2bb2c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:02:51 -0500 Subject: [PATCH 06/30] Add "use my current location" button to home page --- src/views/HomeView.vue | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index c704a46..33b6d30 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -20,6 +20,18 @@ export default { methods: { + useCurrentLocation() { + + if (location.protocol == 'http:') { + alert("Sorry, this only works for secure sites.") + } + + navigator.geolocation.getCurrentPosition(loc => { + this.coordinates = `${loc.coords.latitude},${loc.coords.longitude}` + this.loadCoordinates() + }) + }, + editLocations() { this.$router.push('/edit-list') }, @@ -124,6 +136,16 @@ export default { +
+
+ + Use My Current Location + +
+ From c2e6bfcfdd8f9f0f2858fd17d4c19edbfda5d030 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:03:44 -0500 Subject: [PATCH 07/30] Update changelog --- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00eaae4..0d5bbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.1.2 - 2024-06-08 +### Added +- Add "use my current location" button to home page. +### Changed +- Show both "latest" and "loop" radar images. + ## 0.1.1 - 2024-06-08 ### Added - Add radar panel for Weather view. diff --git a/package-lock.json b/package-lock.json index 4c94a2b..0a8f273 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.1", + "version": "0.1.2", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index c853483..33a440a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.1", + "version": "0.1.2", "private": true, "type": "module", "scripts": { From 5d079e12080196c3e8b071acb74cc79697c910cc Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:35:03 -0500 Subject: [PATCH 08/30] Tell user to refresh the page, if access to location has failed at least in my local firefox on laptop, it would not prompt user again until page was refreshed --- src/views/HomeView.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 33b6d30..55872e0 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -11,6 +11,7 @@ export default { return { coordinates: null, loading: false, + locationAccessBlocked: false, } }, @@ -22,13 +23,19 @@ export default { useCurrentLocation() { - if (location.protocol == 'http:') { - alert("Sorry, this only works for secure sites.") + if (this.locationAccessBlocked) { + alert("You must refresh the page first, then try again.") + return } navigator.geolocation.getCurrentPosition(loc => { this.coordinates = `${loc.coords.latitude},${loc.coords.longitude}` this.loadCoordinates() + }, error => { + if (error.code == 1) { // PERMISSION_DENIED + this.locationAccessBlocked = true + } + alert(`error.code = ${error.code}\n\n${error.message}`) }) }, From b983a34bc99175fc85b255e7097972c5ac930450 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:35:45 -0500 Subject: [PATCH 09/30] Make buttons half-wide on home screen (desktop mode) having a button take up full screen width is a bit much --- src/views/HomeView.vue | 58 +++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 55872e0..5f26d36 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -123,34 +123,40 @@ export default { -
- - {{ location.cityState }} - -
+
+
-
- - Edit List - -
+
+ + {{ location.cityState }} + +
-
-
- - Use My Current Location - +
+ + Edit List + +
+ +
+
+ + Use My Current Location + +
+ +
From fe411cd27c2a66cdbd097e4c402058fdfed41e5a Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:37:04 -0500 Subject: [PATCH 10/30] Update changelog --- CHANGELOG.md | 5 +++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d5bbfb..4161ed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.1.3 - 2024-06-08 +### Changed +- Tell user to refresh the page, if access to location has failed. +- Make buttons half-wide on home screen (desktop mode). + ## 0.1.2 - 2024-06-08 ### Added - Add "use my current location" button to home page. diff --git a/package-lock.json b/package-lock.json index 0a8f273..a6dee2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.2", + "version": "0.1.3", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index 33a440a..50074e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.2", + "version": "0.1.3", "private": true, "type": "module", "scripts": { From f82540c677e3234821fecffd2a38833dfdb1a215 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:58:21 -0500 Subject: [PATCH 11/30] Fix horizontal scroll for main forecast panel --- src/views/WeatherView.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/WeatherView.vue b/src/views/WeatherView.vue index 3c1a66c..2d46308 100644 --- a/src/views/WeatherView.vue +++ b/src/views/WeatherView.vue @@ -82,7 +82,7 @@ export default {
+ style="display: flex; overflow-x: scroll;">
.weather-period { - width: 100px; + min-width: 100px; display: flex; flex-direction: column; align-items: center; From 757e5ce6c8e0b41cd800fe733aff82860639e82a Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 19:58:59 -0500 Subject: [PATCH 12/30] Update changelog --- CHANGELOG.md | 4 ++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4161ed0..a7907dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.1.4 - 2024-06-08 +### Changed +- Fix horizontal scroll for main forecast panel. + ## 0.1.3 - 2024-06-08 ### Changed - Tell user to refresh the page, if access to location has failed. diff --git a/package-lock.json b/package-lock.json index a6dee2f..61bad3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.3", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.3", + "version": "0.1.4", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index 50074e1..ea0e9b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.3", + "version": "0.1.4", "private": true, "type": "module", "scripts": { From aa12f028a575615b992b41f35d3b5a3d26c27883 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 20:32:02 -0500 Subject: [PATCH 13/30] Tighten up the forecast period panels a bit --- src/views/WeatherView.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/views/WeatherView.vue b/src/views/WeatherView.vue index 2d46308..2c144a5 100644 --- a/src/views/WeatherView.vue +++ b/src/views/WeatherView.vue @@ -50,6 +50,10 @@ export default { this.coordinates = this.weatherStore.coordinates }, + getShortForecast(period) { + return period.shortForecast.replace(/Showers And Thunderstorms/g, 'T-storms') + }, + showHourly(period) { this.$router.push('/hourly') }, @@ -96,7 +100,7 @@ export default {
-

{{ period.shortForecast }}

+

{{ getShortForecast(period) }}

Hi @@ -138,7 +142,8 @@ export default { From 7ed314b5bf2e9eca6426427d971823e8f719810c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 21:31:18 -0500 Subject: [PATCH 16/30] Update changelog --- CHANGELOG.md | 4 ++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b9cce9..bf57eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.1.6 - 2024-06-08 +### Changed +- Add proper About page. + ## 0.1.5 - 2024-06-08 ### Changed - Tighten up the forecast period panels a bit. diff --git a/package-lock.json b/package-lock.json index a58ac28..da7cc0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.5", + "version": "0.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.5", + "version": "0.1.6", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index 0f433a3..c12ea00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.5", + "version": "0.1.6", "private": true, "type": "module", "scripts": { From 0710f2238cb3f0239c17f2a8466e9b3a20312044 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sat, 8 Jun 2024 23:16:29 -0500 Subject: [PATCH 17/30] Add basic support for active weather alerts yikes nobody should stake their life on how well this works, but it does seem to basically work.. --- src/router/index.js | 6 ++++ src/stores/weather.js | 67 +++++++++++++++++++++++++++++++++++++-- src/views/AlertsView.vue | 51 +++++++++++++++++++++++++++++ src/views/WeatherView.vue | 12 +++++++ 4 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/views/AlertsView.vue diff --git a/src/router/index.js b/src/router/index.js index 464d998..7430367 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' import WeatherView from '../views/WeatherView.vue' +import AlertsView from '../views/AlertsView.vue' import HourlyView from '../views/HourlyView.vue' import EditListView from '../views/EditListView.vue' @@ -17,6 +18,11 @@ const router = createRouter({ name: 'weather', component: WeatherView, }, + { + path: '/alerts', + name: 'alerts', + component: AlertsView, + }, { path: '/hourly', name: 'hourly', diff --git a/src/stores/weather.js b/src/stores/weather.js index c8c91ab..cf79fcf 100644 --- a/src/stores/weather.js +++ b/src/stores/weather.js @@ -10,6 +10,7 @@ const getDefaults = () => { coordinates, cityState, weather: null, + alerts: null, forecast: null, radarLatestURL: null, radarLoopURL: null, @@ -32,14 +33,17 @@ export const useWeatherStore = defineStore('weather', { this.setForecast(null) this.radarLatestURL = null this.radarLoopURL = null + this.alerts = null }, async getWeather() { if (!this.weather) { + let url + let response - const url = `https://api.weather.gov/points/${this.coordinates}` - const response = await fetch(url) + url = `https://api.weather.gov/points/${this.coordinates}` + response = await fetch(url) const weather = await response.json() if (weather.status == 404) { throw new Error(`Data not found for ${this.coordinates}`) @@ -57,6 +61,65 @@ export const useWeatherStore = defineStore('weather', { this.radarLoopURL = `https://radar.weather.gov/ridge/standard/${station}_loop.gif` this.setWeather(weather) + + // fetch zone to get its official id + url = weather.properties.forecastZone + response = await fetch(url) + const zone = await response.json() + + // fetch alerts for zone + url = `https://api.weather.gov/alerts/active/zone/${zone.properties.id}` + response = await fetch(url) + const zoneAlerts = await response.json() + + // fetch county to get its official id + url = weather.properties.county + response = await fetch(url) + const county = await response.json() + + // fetch alerts for county + url = `https://api.weather.gov/alerts/active/zone/${county.properties.id}` + response = await fetch(url) + const countyAlerts = await response.json() + + const newAlerts = {} + + // use latest timestamp from either zone or county + newAlerts.updated = zoneAlerts.updated + if (countyAlerts.updated > zoneAlerts.updated) { + newAlerts.updated = countyAlerts.updated + } + + // collect all alert "features" but de-duplicate them + newAlerts.features = {} + for (let feature of zoneAlerts.features) { + newAlerts.features[feature.properties.id] = feature + } + for (let feature of countyAlerts.features) { + newAlerts.features[feature.properties.id] = feature + } + newAlerts.features = Object.values(newAlerts.features) + + // put "likely" before "possible" alerts + newAlerts.features.sort((a, b) => { + + if (a.properties.certainty == 'Likely' && b.properties.certainty == 'Possible') { + return -1 + } + if (a.properties.certainty == 'Possible' && b.properties.certainty == 'Likely') { + return 1 + } + + // if (a.properties.certainty == b.properties.certainty) { + // return 0 + // } + + // TODO: what else should this do? + return 0 + }) + + // we have our final alerts + this.alerts = newAlerts } return this.weather diff --git a/src/views/AlertsView.vue b/src/views/AlertsView.vue new file mode 100644 index 0000000..a397565 --- /dev/null +++ b/src/views/AlertsView.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/views/WeatherView.vue b/src/views/WeatherView.vue index 2c144a5..4d30a98 100644 --- a/src/views/WeatherView.vue +++ b/src/views/WeatherView.vue @@ -10,6 +10,7 @@ export default { data() { return { coordinates: null, + alerts: null, } }, @@ -48,6 +49,7 @@ export default { const forecast = await this.weatherStore.getForecast() this.coordinates = this.weatherStore.coordinates + this.alerts = this.weatherStore.alerts }, getShortForecast(period) { @@ -77,6 +79,16 @@ export default { +

+ +

Watches In Effect

+

Updated {{ new Date(alerts.updated).toLocaleTimeString('en-US', {timeStyle: 'short'}) }}

+
+
+