Spike: Convert metrics dashboard into a SPA
This is a technical spike to allocate time for investigating what work is needed/how to breakdown an iterative approach of moving our current metrics dashboard architecture into a SPA as a means of reducing technical debt and improve testing coverage
Description of solution
We want our users to be able to bookmark different routes in our metrics dashboard as the navigate it. To achieve this we will leverage Vue Router, and define several pages of navigation
Pages and routes
We have our monitoring_app
as the top component where we define our store
and our router
, both of them are global to the application.
In the level below, we have a flat list of pages, each page is a component monitoring/page/*Page
. Note: For now, we don't consider nested routes, as our initial page structure is can be simple.
We namespace our app using /metrics/
, and we can emulate Rails routes in our navigation (with the exception of the dashboard that is) at the root level), as more entities are added to our application, we can add them after metrics:
-
/metrics/(:dashboard)
->DashboardPage
-
/metrics/new
-> DashboardNewPage -
/metrics/panel/new
->PanelNewPage
-
/metrics/panel/:panel_id
->PanelPage
-
/metrics/panel/:panel_id/edit
->PanelEditPage
/metrics/<other_entity>
Navigation between pages is done via the $router
API or via links that contain the :to
attribute. to
Docs.
Query Parameters
Query params are kept in sync with the store, differently from page parameters, only Page components should access them, other subcomponents should only fetch data from the store. The synchronization is done by:
- Setting up the store on
created()
- Why on
created
and notmounted
? This allows subcomponents to render with the desired store state immediately without passing through a default/invalid state.
- Why on
- Updating the browser bar when there are changes in the store (
watch
)
An example, of a stateParam
attributes that map to an example queryParam
:
export default {
// A Page component
// ...
computed: {
...mapState('monitoringDashboard', ['stateParam']),
},
created() {
// Read from the browser bar
this.setStateParam(this.$route.query.stateParam); // Vuex action updates the store
},
watch: {
// Update the browser bar on changes
stateParam(value) {
const query = { ...this.$route.query, queryParam: value }; // New query object with value
this.$router.push({
...this.$route,
query,
});
},
},
methods: {
...mapActions('monitoringDashboard', ['setStateParam']),
},
};
Integration Challenges
dashboard
dependant properties in the HTML dataset
In order for the frontend to load a new dashboard, they must load data related to it. Conversely, the frontend should not load data that is not related to the dashboard when requesting data for it.
However, properties are fetched twice by separate methods: once in the HTML of the page, and a second time in the dashboard API. The properties are in the metrics_data
function.
In order for the SPA to load a different dashboards, 3 things must happen:
- The dashboard related properties must be updated by the frontend in the store when a single dashboard is fetched.
- The properties should not be set from HTML into the store, so the backend should remove them.
all_dashboards
All dashboard could be loaded separately, so that switching between dashboards does not refresh the list of dashboard visible.
Implementation Steps
- TBD
Expected Outcomes
- Diagram of how the SPA will be designed
- Breakdown of how we can iterate through this assuming we have the full capacity of the frontend team