Vue Dashboard Tutorial Using Cube.js
Tags: tutorials, javascript, opensource, webdev
Published: 2019-05-23 14:49:14

---
title: Vue Dashboard Tutorial Using Cube.js
published: true
description: A step-by-step guide on building analytics dashboard using Vue and Cube.js
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ys70y1pdvh3bh22ueq47.png
tags: tutorials, javascript, opensource, webdev
canonical_url: https://cube.dev/blog/vue-dashboard-tutorial-using-cubejs/
---

There are a couple of popular front-end frameworks today. We recently covered how to build an analytics dashboard with [React](https://cube.dev/blog/cubejs-open-source-dashboard-framework-ultimate-guide/) and [Angular](https://cube.dev/blog/angular-dashboard-tutorial-with-cubejs/). What both of these guides share is [Cube.js](https://cube.dev)—an open-source analytics framework, which powers these dashboards with high-performance data. Being open-source, Cube.js is open to contributions, and you can find a [contribution guide](https://github.com/statsbotco/cube.js/blob/master/CONTRIBUTING.md) in the repository on Github.
One of the latest contributions from the community is a Cube.js client for Vue. It was built by Ricardo Tapia from Qualibrate and he's got a great [blog post about that process](https://cube.dev/blog/how-we-build-analytics-at-qualibrate-using-cubejs-and-vuejs/). In this tutorial, I'll touch on some details and provide a step-by-step guide on building your own analytics dashboard with [Vue](https://vuejs.org/).


We will be using [Vue](https://vuejs.org/), [Cube.js](https://cube.dev), and [Laue](https://laue.js.org/). You can find a final dashboard [here](https://statsbotco.github.io/cubejs/vue-dashboard/) and a CodeSandbox with the source code below.

{% codesandbox cubejs-vue-demo-9r5xl %}

## Setting up a Cube.js Backend
We covered this topic in other tutorials, so if you already have your Cube.js backend set up and running, you can skip this section.

You can install Cube.js CLI, which is used for various Cube.js workflows, via NPM or Yarn.

```bash
npm install -g cubejs-cli
```

Let's prepare a Cube.js Backend to serve data for the dashboard we're building. Cube.js supports many databases and deployment options. You can learn more about it in the [documentation](https://cube.dev/docs/deployment). For this tutorial, we’ll use a Postgres database and deploy Cube.js to Heroku. Let's create a new Cube.js application using the CLI we just installed.

```bash
cubejs new vue-demo -d postgres
cd vue-demo
```

In case you don't have a database for the dashboard yet, you can download our demo e-commerce dataset for Postgres.

```bash
curl http://cube.dev/downloads/ecom-dump.sql > ecom-dump.sql
createdb ecom
psql --dbname ecom -f ecom-dump.sql

```

The next step is to define a data model. In a production application, you most likely will have multiple schema files, but for our demo app we are going to have only one cube. If you're not familiar with Cube.js data schema, there's an in-depth tutorial [here](https://cube.dev/docs/getting-started-cubejs-schema).

```javascript
cube(`Users`, {
  sql: `SELECT * FROM users`,

  measures: {
    count: {
      sql: `id`,
      type: `count`
    }
  },

  dimensions: {
    city: {
      sql: `city`,
      type: `string`
    },

    signedUp: {
      sql: `created_at`,
      type: `time`
    },

    companyName: {
      sql: `company_name`,
      type: `string`
    }
  }
});
```

Cube.js uses data schema to generate and execute SQL in the connected database. We can test it out by sending a sample request to the Cube.js REST API endpoint.

```bash
curl \
 -H "Authorization: EXAMPLE-API-TOKEN" \
 -G \
 --data-urlencode 'query={"measures":["Users.count"]}' \
 http://localhost:4000/cubejs-api/v1/load
```

You can learn more about the Cube.js Query format [here](https://cube.dev/docs/query-format).

Finally, let’s deploy our backend to Heroku:

```bash
git init
git add -A
git commit -am "Initial commit"
heroku create cubejs-vue-demo
git push heroku master
```

You can find full deployment guide in the [documentation](https://cube.dev/docs/deployment#heroku).

## Create Vue App
When the backend is up and running, it's time to build the dashboard. Since we're using Vue, the best way to create a new app is by using `vue-cli`.

First, install vue-cli if you don't have it already: 

```bash
npm install -g @vue/cli
# or using yarn
yarn global add @vue/cli
```
To create an app, you can use your terminal or start a tool called [Vue UI](https://cli.vuejs.org/guide/creating-a-project.html#using-the-gui):

```bash
vue ui
```

This will run a website on your computer, which allows you to create apps, run, and monitor them. It also contains all links to documentation and other community resources.

To create an app using the terminal, all you need is a name:

```bash
vue create YOUR-APP-NAME
cd YOUR-APP-NAME
```

You can configure plugins for your application, but for the demo we'll use the default setup.

If you created the app using Vue UI, you can start it right there. If you're using the console, run the `serve` task:

```bash
npm run serve
# or using yarn
yarn serve
```

Now your application is running on your computer and is accessible via the browser.

## Setting up the dashboard

First, we'll add some basic styles using [Bootstrap](https://getbootstrap.com/). We'll install it from the CDN, but you can add it using npm or yarn. Open your `public/index.html` file and add Bootstrap resources:

```html
<head>
	...
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
	 crossorigin="anonymous">
</head>

```

Now when bootstrap is installed, we can create some basic structure for the app:

```html
<template>
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-4">
      </div>
      <div class="col-sm-4">
      </div>
      <div class="col-sm-4">
      </div>
    </div>
    <div class="row">
      <div class="col-sm-6">
      </div>
      <div class="col-sm-6">
      </div>
    </div>
  </div>
</template>

```
Now we need some data to show. There's a full [documentation](https://cube.dev/docs/@cubejs-client-vue) for the Cube.js Vue client where you can find additional options. First, we need to set up a Cube.js instance with our backend URL and API token:

```javascript
// App.vue
import cubejs from "@cubejs-client/core";
import { QueryBuilder } from "@cubejs-client/vue";

const cubejsApi = cubejs(
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.K9PiJkjegbhnw4Ca5pPlkTmZihoOm42w8bja9Qs2qJg",
  { apiUrl: "https://react-query-builder.herokuapp.com/cubejs-api/v1" }
);

```

Now let's set up our app to use a [QueryBuilder component](https://cube.dev/docs/@cubejs-client-vue#query-builder) and create a query counting all users:

```javascript
// App.vue

export default {
  name: "App",
  components: {
    Chart,
    QueryBuilder
  },
  data() {
    return {
      cubejsApi,
      usersQuery: { measures: ["Users.count"] }
  }
};
```

The Cube.js Vue Client allows child components to receive a [resultSet](https://cube.dev/docs/@cubejs-client-core#result-set) object for a given query. Let's create a new component called `Chart`:

```vue
# components/Chart.vue
<template>
  <div class="card">
    <div class="card-body">
      <h5 class="card-title">{{ title }}</h5>
      <div class="card-text">
        <div class="d-flex justify-content-center text-dark">
          <div class="spinner-border" role="status" v-if="loading">
            <span class="sr-only">Loading...</span>
          </div>
        </div>
        <h1
          v-if="!loading && type === 'number'"
          height="300"
        >{{ values[0][metrics[0]] }}</h1>
      </div>
    </div>
  </div>
</template>

<script>

export default {
  name: "Chart",
  props: {
    resultSet: Object,
    loading: Boolean,
    title: String,
  },
  computed: {
    values: function() {
      if (this.loading) return [];
      return this.resultSet.chartPivot();
    },
    metrics: function() {
      if (this.loading) return [""];
      return this.resultSet.seriesNames().map(x => x.key);
    }
  };
</script>

```

What we need here is to display a loading element while data is loading and show a number after. Let's get back to our `App.vue` component and create a first tile:

```html
<query-builder :cubejs-api="cubejsApi" :query="usersQuery">
  <template v-slot="{ loading, resultSet }">
    <Chart title="Total Users" :loading="loading" :result-set="resultSet"/>
  </template>
</query-builder>
```

We're using here a [QueryBuilder component](https://cube.dev/docs/@cubejs-client-vue#query-builder) that passes the data into the Chart component using [Vue Scoped Slot Props](https://vuejs.org/v2/guide/components-slots.html#Named-Slots). Now there's a counter on our dashboard showing total users. Let's add some charts!

Charts

To create a chart, we'll use the [Laue](https://laue.js.org/) library. It's pretty simple and has a great collection of examples online. First, we'll install Laue in our application:

```javascript
// main.js

import { Laue } from 'laue';

Vue.use(Laue);
```

This allows us to use all Laue items in any component. There are other installation methods in the [documentation](https://laue.js.org/guide). Now let's create a LineChart component:

```vue
<template>
  <la-cartesian autoresize :data="values" :padding="[0, 0, 5, 0]">
    <la-line curve :width="2" color="#7DB3FF" :prop="metrics[0]"/>
    <la-y-axis :nbTicks="4"></la-y-axis>
    <la-x-axis prop="x" :format="dateFormatter" :interval="6"></la-x-axis>
    <la-tooltip></la-tooltip>
  </la-cartesian>
</template>

<script>
import moment from "moment";
export default {
  name: "LineChart",
  props: {
    values: Array,
    metrics: Array
  },
  methods: {
    dateFormatter: function(value) {
      return moment(value).format("MMM YY");
    }
  }
};
</script>
```

To render chart, we'll use a type prop on our Chart component. Let's add a conditional render there:

```html
<line-chart v-if="!loading && type === 'line'" :values="values" :metrics="metrics"/>
```

Now our LineChart component is done! What we need now is to add a query for the line chart in our App.vue component:

```vue
<query-builder :cubejs-api="cubejsApi" :query="lineQuery">
  <template v-slot="{ loading, resultSet }">
    <Chart
      title="New Users Over Time"
      type="line"
      :loading="loading"
      :result-set="resultSet"
    />
  </template>
</query-builder>

<script>
...
data() {
  return {
    cubejsApi,
    usersQuery: { measures: ["Users.count"] },
    lineQuery: {
      measures: ["Users.count"],
      timeDimensions: [
        {
          dimension: "Users.createdAt",
          dateRange: ["2017-01-01", "2018-12-31"],
          granularity: "month"
        }
      ]
    }
  }
...
</script>
```
That's it for the line chart. The setup for the bar chart is pretty similar.

And the dashboard is complete! You can find the dashboard live [here](https://statsbotco.github.io/cubejs/vue-dashboard/) and the source code in this [CodeSandbox](https://codesandbox.io/s/cubejs-vue-demo-9r5xl). We hope you found this guide useful.