mainmatter / breethe-client Goto Github PK
View Code? Open in Web Editor NEWAir Quality Data for Locations around the World
Home Page: https://breethe.app
Air Quality Data for Locations around the World
Home Page: https://breethe.app
Besides supporting to search for a location by name, we should also allow using the phone's location to get a list of the closest measurement stations.
I'd like to use css-blocks for this.
Loading ot the location data does till not work in a number of cases. This should fix all of the various scenarios.
We should always display all the attributes in the Location
component but keeping in mind that all or some of them could be null. E.g. in these cases (using production API) we should display an —
for the updated-at dates and one for each missing measurement (still showing all of the measurement labels):
We need to add a footer saying
Some of the measurements are not actually particles but gases (PM10/PM25 are particles, the others are gases). We need to add a gas effect similar to the particles one to reflect that.
A good approach might be to just something based on images: https://codepen.io/Ravyre/pen/gXawyY. An alternative could be something like this: https://codepen.io/asistapl/pen/ezpadZ
I believe what needs to be done for the Search
component (see #36) needs to be done for the Location
component as well.
There are 2 main models that I could see:
Location
for locations of measurement stations (measurements are very much location-specific - one street might have really bad air, another street only 1km further away might have much better air)Measurement
for representing actual measurements of different values at a certain point in time. Different locations measure different valuesLocation
from the Phoenix migration:
def change do
create table(:locations) do
add :identifier, :string
add :city, :string
add :country, :string
add :last_updated, :utc_datetime
add :available_parameters, {:array, :parameter}
add :coordinates, :geometry
timestamps()
end
end
Measurement
from the Phoenix migration:
def change do
create table(:measurements) do
add :parameter, :parameter
add :location_id, references(:locations), null: false
add :measured_id, :utc_datetime
add :value, :float
add :unit, :unit
add :coordinates, :geometry
timestamps()
end
end
The API will server JSON:API. Obviously everything will be read-only from the client side for now as we're only displaying data in the PWA.
As we're using Glimmer.js, there's no Ember Data. Instead, I'd look at https://github.com/orbitjs/orbit which should also help with offline support via IndexedDB.
As a user, after selecting a position from the list I'd like to see the available measurements for that position in a separate route. When I'm in the route with my matched locations and I click in one of them, I'm taken to another route that displays the measurements resolved by the server.
It works fine in Chrome and on Android but of course iOS is somehow special…
Whenever we read new data for anything, we should clear old data so we don't keep growing IndexedDB. In particular old measurement points are never used again and can be replaces completely with newer as they are received from the API.
Recent locations should be populated with the data stored in IndexedDB at the time the app is accessed.
To do so we have to somehow mark the element cached on the individual view as recent.
I thought that #96 had fixed that but I'm seeing high GPU load again when going to e.g. https://breethe.app/location/101. Open Activity Monitor.app and go to Window -> GPU to get the live GPU load. I'm not sure whether we can force the animation to not run on the GPU but we somehow need to fix that.
Some of the UI is not functional without the app being started in the client and that should be reflected in the UI to not make it look like the app is broken.
The number and color of the particles as well as the intensity and color of the gases must be dependent on the reported data to actually make sense. We should have some non-intense and bright default effect that gets more intense and darker when entering the location route if the data is really bad. It need to fade in and out when entering and leaving the location route.
We need to be able to run Pretender in Glimmer tests but I cannot figure out how to import the package in Typescript. I ran out of ideas on how to address this issue, my problem is reported here: pretenderjs/pretender#229
This issue has become a big blocker because I cannot write the tests for all the other features without this setup. Any ideas on alternatives or any work around that could work?
This being a PWA, it needs to work offline of course. This means
index.html
but only serve the index.html
if requesting it fails; all other assets can be served from service worker cache at all times as they are fingerprinted)We need to add an application manifest so this looks nice when installed as an app. I think this means we need to add JSON config file, several icons etc.
We need to track errors so we should add the Sentry JS so we can.
The fog animation slows mobile devices significantly so that the app feels slow. We need to find an alternative that requires less computing effort (while at the same time not adding a big dependency). I think options might be
We need to disable the gas and particles effect in the pre-rendered response as we have no way of syncing the animations in the pre-rendered response and when the app reboots in the client which could make it look pretty weird. It's better when the pre-rendered response does not include it at all and then the effect fades in once the app boots in the client.
In order to relase this we need to
I realized that images are not fingerprinted which is obviously a problem with caching…
Glimmer doesn't have a stable routing solution yet. So we have to figure out what to do. From what I researched there's two routes to route.
Glimmer API website showcases a routing mechanism in https://github.com/glimmerjs/glimmer-api-docs/blob/master/src/ui/components/GlimmerApiDocs/component.ts
glimmer-router
is an initiative to have a declarative router in glimmer à la react-router
. https://github.com/glimmer-router/glimmer-router
The mechanism implemente din the Glimmer API website seems quite temporal and custom. It's also tightly coupled
I think glimmer-router
is more promising. I've forked the repo and updated the dependencies to work with the latest Glimmer. However, there is a glimmer-related issue with the way services notify computed properties that the services are dirty. I'll submit a PR to the original repo as the author is interested in continuing the project now that Glimmer is more stable.
Currently, the complete application without JS except for the search form. We could make that work without JS as well though relatively easily.
If we made the search form a GET
form with <form method="GET" action="/search">
, if the browser has JS switched off (or the app has not started so the onsubmit
handler is not attached yet), that form would submit as e.g. /search?search-term=munich
which we could simply redirect to /search/munich
in the SSR server. /search/munich
is already handled by the SSR server so searching by search term without JS enabled works 🚀
Without JS, we cannot get the users's coordinates in the browser. We can however, guess their rough coordinates based on their IP on the server side. So making searching by coordinates work without JS could simply work by making the current "Show nearby locations" a link to e.g. /search-by-coordinates
(that is handled by the app in the browsers via onclick
once the app has started). When the SSR server sees a request to that path, it could simply get the user's coordinates based on their IP and redirect to e.g. /search/23.3,45.5
which is already handled by the SSR server. Thus, searching for nearby locations would work without JS as well 🚀
Currently, we're not optimizing the CSS we're shipping in production.
How that we have different routes, we want to have a single shared store across the routes. In React we would have to use HOCs, but in Glimmer we can register service-like entities.
This Gist provides some guidelines on how services can be added to glimmer: https://gist.github.com/mixonic/acbc9b8d57819e2f2c77b206ab7f422e. I recently tested and it seems like the strategy it uses to dirty the service to use in computed properties no longer works. However, that is not important for us because we'll just use the store to handle our data; we don't need to track properties in the service.
Currently, when showing the search component for the search term, the component shows the message "we could not find locations" initially before showing the actual data after that has been loaded. We need to show a loading state instead and only show the message if no data was found.
I think the best solution is probably to load all data in the parent PPMClient
component and only pass the current state (e.g. in this case loading
/loaded with data
/loaded with no data
) to the Search
and Location
child components.
mainmatter/breethe-server#69 adds dedicated location labels so that we do not have to show the rather poor labels that we get from OpenAQ. We need to support that new field and show that instead of what we currently show.
I have data from 1.6.2018 for this location in IndexedDB: https://breethe.app/location/29. However, there is data available for this location from openaq from 4.6.2018. What happens when requesting https://breethe.app/location/29 is that the server responds with the fresh data from 4.6.2018 but then the client replaces that with the old data from 1.6.2018 apparently.
I've spent a lot of time trying to figure out a way to make Orbit work for the case of fetching the measurements for a location. It's such a trivial task but it's extremely hard with Orbit, or so it seems.
There's two scenarios that I've been unable to resolve:
What's the problem?
Orbit's filter
can only be applied on attributes of the model. Orbit necessarily performs a local filter of results at the query level with no option to customize this behavior.
It is not possible to use arbitrary query params in an Orbit query: orbitjs/orbit#486
Alternative for measurements
Using findRelatedRecords
in theory would allow us to fetch the related measurements of a location through GET /locations/1/measurements
. The call is performed correctly by Orbit and the results are stored in the store, but the query returns an empty array all the time. I assume there is some check happening in the background that discards the results as legitimate related records but I've been unable to understand how to make it work. I've tried for hours many combinations of factors in the schema without luck.
I don't know what else to try. Perhaps somebody has experimented with Orbit at some point and can give some insight?
As a user I'd like to search for a location by inputting a string in an input box. When hitting enter, I'm taken to a new route in which all the matching locations are displayed. If I refresh the page, the box should stay prefilled and the matching results should be displayed.
I used aXe Chrome extension to check accessibility issues on our app. The audit by this tool reported 8 issues regarding missing aria attributes, content landmarks and color contrasts.
I'm planning to address these known issues now.
For the future, would it be worth it to incorporate an accessibility audit tool as part of our test suite?
I'm not sure how much we're planning to extend the app in the future so I'm not sure if we should do it. Perhaps it's enough to run an audit tool manually an address the resulting issues.
If we want to incorporate an audit tool, there's several we could use. I've found we could use aXe
with mocca
or Google Chrome's accessibility-developer-tools
with puppeteer
. There's several interesting options we can go with.
During EmberFest, @rondale_sc told me that it is now possible to pass variables to the test template context. This enables us to write several integration tests that we had pending.
The values don't mean anything by themselves without a scale.
My suggestion would be a bar graph running from left to right on each measurement. So like
PM10 ====== 12.99 <--- this bar would be yellow because 12.99 PM10 is average
PM25 ========== 8.5 <--- this bar would be red because 8.5 PM25 is ☠️
(I moonlight as a designer)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.