Skip to content
This repository was archived by the owner on Apr 10, 2021. It is now read-only.

Dashboard #138

Merged
merged 19 commits into from
Jan 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions raw-cms-app/src/config/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,14 @@ const _router = new VueRouter({
},
],
},
{
path: '/about',
name: 'about',
component: async (res, rej) => {
const cmp = await import('/modules/core/views/about-view/about-view.js');
await cmp.default(res, rej);
},
},
],
});

Expand Down
5 changes: 5 additions & 0 deletions raw-cms-app/src/config/vue-chartjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const _vueChartJs = window.VueChartJs;

export const vueChartJs = _vueChartJs;
export const mixins = _vueChartJs.mixins;
export const Pie = _vueChartJs.Pie;
1 change: 1 addition & 0 deletions raw-cms-app/src/config/vuetify.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ const _vuetify = new Vuetify({
});

export const vuetify = _vuetify;
export const vuetifyColors = colors;
4 changes: 4 additions & 0 deletions raw-cms-app/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
<script src="https://cdn.jsdelivr.net/combine/npm/[email protected]/dist/validators.min.js,npm/[email protected]/dist/vuelidate.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lib/epic-spinners.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-formly.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs/dist/vue-chartjs.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-monaco.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.18.0/min/vs/loader.js"></script>

Expand Down
7 changes: 6 additions & 1 deletion raw-cms-app/src/modules/core/assets/i18n/i18n.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@
"title": "Entities"
},
"home": {
"helpText": "Welcome! Please select a menu entry on the left."
"apiCallsText": "API calls (last week):",
"entitiesNumText": "Entities number",
"recordsQuotaText": "Records quota",
"title": "Home",
"totalRecordsText": "Total records",
"welcomeText": "Welcome back! Here you can find some insights about your app."
},
"lambdas": {
"deleteConfirmMsgTpl": "Are you sure you want to delete lambda {name}?",
Expand Down
Binary file modified raw-cms-app/src/modules/core/assets/rawlogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions raw-cms-app/src/modules/core/components/dashboard/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { optionalChain } from '../../../../utils/object.utils.js';
import { SimplePieChart } from '../../../shared/components/charts/simple-pie-chart/simple-pie-chart.js';
import { dashboardService } from '../../services/dashboard.service.js';

const _DashboardDef = async () => {
const tpl = await RawCMS.loadComponentTpl(
'/modules/core/components/dashboard/dashboard.tpl.html'
);

return {
components: {
PieChart: SimplePieChart,
},
computed: {
totalRecordsNum: function() {
const quotasObj = optionalChain(() => this.info.recordQuotas);
if (quotasObj === undefined) {
return undefined;
}

return Object.keys(quotasObj)
.map(x => quotasObj[x])
.reduce((acc, v) => acc + v, 0);
},
recordQuotasChartData: function() {
const quotasObj = optionalChain(() => this.info.recordQuotas, { fallbackValue: {} });
const labels = [];
const data = [];
Object.keys(quotasObj).forEach(x => {
labels.push(x);
data.push(quotasObj[x]);
});

return { data, labels };
},
},
created: async function() {
this.info = await this.dashboardService.getDashboardInfo();
this.isLoading = false;
},
data: function() {
return {
chartOptions: {
lowerIsBetter: true,
},
dashboardService: dashboardService,
isLoading: true,
info: undefined,
optionalChain: optionalChain,
};
},
template: tpl,
};
};

const _Dashboard = async (res, rej) => {
const cmpDef = await _DashboardDef();
res(cmpDef);
};

export const DashboardDef = _DashboardDef;
export const Dashboard = _Dashboard;
export default _Dashboard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<v-row>
<v-col cols="3">
<v-card tile height="300" :loading="isLoading" class="mb-4">
<v-card-title>
{{ $t('core.home.totalRecordsText') }}
</v-card-title>
<v-card-text class="display-4 font-weight-black">
{{ totalRecordsNum }}
</v-card-text>
</v-card>
<v-card tile height="300" :loading="isLoading">
<v-card-title>
{{ $t('core.home.entitiesNumText') }}
</v-card-title>
<v-card-text class="display-4 font-weight-black">
{{ optionalChain(() => this.info.entitiesNum) }}
</v-card-text>
</v-card>
</v-col>
<v-col cols="9">
<v-card tile height="616" :loading="isLoading">
<v-card-title>
{{ $t('core.home.recordsQuotaText') }}
</v-card-title>
<v-card-text class="d-flex justify-center" style="height:552px">
<pie-chart :context="recordQuotasChartData" :options="chartOptions" />
</v-card-text>
</v-card>
</v-col>
</v-row>
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const _LeftMenu = async (resolve, reject) => {
isVisible: false,
isUserMenuVisible: false,
items: [
{ icon: 'mdi-home', text: 'Home', route: 'home' },
{ icon: 'mdi-account', text: 'Users', route: 'users' },
{ icon: 'mdi-cube', text: 'Entities', route: 'entities' },
{ icon: 'mdi-book-open', text: 'Collections', route: 'collections' },
Expand All @@ -35,6 +36,7 @@ const _LeftMenu = async (resolve, reject) => {
extLink: RawCMS.env.api.baseUrl,
},
],
bottomItem: { icon: 'mdi-information', text: 'About', route: 'about' },
};
},
methods: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,20 @@
</v-list-item>
</template>
</v-list>

<template v-slot:append>
<v-list dense>
<v-list-item
:class="{ 'router-link-active': isActive(bottomItem)}"
@click.stop="goTo(bottomItem)"
>
<v-list-item-action>
<v-icon>{{ bottomItem.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>{{ bottomItem.text }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</template>
</v-navigation-drawer>
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
</v-toolbar-title>

<v-spacer></v-spacer>
<div class="flex-grow-1"></div>
<v-avatar tile>
<img src="/modules/core/assets/rawlogo_small.png" alt="RawCMS Logo" />
</v-avatar>
</v-app-bar>
32 changes: 32 additions & 0 deletions raw-cms-app/src/modules/core/services/dashboard.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { sleep } from '../../../utils/time.utils.js';
import { BaseApiService } from '../../shared/services/base-api-service.js';

class DashboardService extends BaseApiService {
constructor() {
super();
}

async getDashboardInfo() {
// FIXME: For now we use mock data

await sleep(5000);

const quota = {
TEST: Math.floor(Math.random() * 100),
Items1: Math.floor(Math.random() * 100),
Items2: Math.floor(Math.random() * 100),
Items3: Math.floor(Math.random() * 100),
Items4: Math.floor(Math.random() * 100),
Items5: Math.floor(Math.random() * 100),
Items6: Math.floor(Math.random() * 100),
};
return {
recordQuotas: quota,
entitiesNum: Object.keys(quota).length,
lastWeekCallsNum: Math.floor(Math.random() * 500),
};
}
}

export const dashboardService = new DashboardService();
export default dashboardService;
10 changes: 10 additions & 0 deletions raw-cms-app/src/modules/core/views/about-view/about-view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const _AboutView = async (res, rej) => {
const tpl = await RawCMS.loadComponentTpl('/modules/core/views/about-view/about-view.tpl.html');

res({
template: tpl,
});
};

export const AboutView = _AboutView;
export default _AboutView;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<img src="/modules/core/assets/rawlogo.png" />
</v-row>
</v-container>
10 changes: 10 additions & 0 deletions raw-cms-app/src/modules/core/views/home-view/home-view.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { vuexStore } from '../../../../config/vuex.js';
import { DashboardDef } from '../../components/dashboard/dashboard.js';

const _HomeView = async (res, rej) => {
const tpl = await RawCMS.loadComponentTpl('/modules/core/views/home-view/home-view.tpl.html');
const dashboardDef = await DashboardDef();

res({
components: {
Dashboard: dashboardDef,
},
mounted() {
vuexStore.dispatch('core/updateTopBarTitle', this.$t('core.home.title'));
},
template: tpl,
});
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<v-container class="fill-height" fluid>
<v-row align="center" justify="center">
<img src="/modules/core/assets/rawlogo.png" />
<v-container fluid>
<v-row align="start">
<v-col>
{{ $t('core.home.welcomeText') }}
<dashboard></dashboard>
</v-col>
</v-row>
</v-container>
26 changes: 26 additions & 0 deletions raw-cms-app/src/modules/shared/components/charts/charts.utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { vuetifyColors } from '../../../../config/vuetify.js';
import { optionalChain } from '../../../../utils/object.utils.js';

const _transparentize = function(color, opacity) {
const alpha = opacity === undefined ? 0.5 : 1 - opacity;
return Color(color)
.alpha(alpha)
.rgbString();
};

const _colorize = function(value, { range = [0, 100], lowerIsBetter = false } = {}) {
const min = optionalChain(() => range[0], 0);
const max = optionalChain(() => range[1], 100);
let colors = [vuetifyColors.red.darken4, vuetifyColors.orange.base, vuetifyColors.green.base];
if (lowerIsBetter) {
colors = colors.reverse();
}
const colorMap = d3.piecewise(d3.interpolate, colors);
const interpolationValue = (value - min) / (max - min);

const c = colorMap(interpolationValue);
return c;
};

export const colorize = _colorize;
export const transparentize = _transparentize;
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Pie } from '../../../../../config/vue-chartjs.js';
import { optionalChain } from '../../../../../utils/object.utils.js';
import { colorize, transparentize } from '../charts.utils.js';

const _defaultChartOptions = {
lowerIsBetter: false,
};

const _SimplePieChart = {
computed: {
chartData: function() {
const data = this.sortedData;
const backColors = data.map(x => this.normalColorize(x));

const res = {
datasets: [
{
data: data,
backgroundColor: backColors,
hoverColor: backColors.map(x => this.hoverColorize(x)),
},
],
labels: this.context.labels,
};

return res;
},
sortedData: function() {
let data = optionalChain(() => [...this.context.data], { fallbackValue: [] }).sort(
(a, b) => a - b
);

if (this.options.lowerIsBetter) {
data = data.reverse();
}

return data;
},
},
extends: Pie,
methods: {
normalColorize: function(value) {
const data = this.sortedData;
const min = Math.min(...data) || 0;
const max = Math.max(...data) || 100;
return colorize(value, { range: [min, max], lowerIsBetter: this.options.lowerIsBetter });
},
hoverColorize: function(color) {
return transparentize(color);
},
refresh: function() {
this.styles = { width: '100%', height: '100%', position: 'relative', ...this.styles };
this.renderChart(this.chartData, {
maintainAspectRatio: false,
});
},
},
mounted() {
this.refresh();
},
props: {
context: {
type: Object,
default: {
data: [],
labels: [],
},
},
options: {
type: Object,
default: _defaultChartOptions,
},
},
watch: {
context: function() {
this.refresh();
},
},
};

export const SimplePieChart = _SimplePieChart;
export default _SimplePieChart;
17 changes: 17 additions & 0 deletions raw-cms-app/src/modules/shared/services/base-api-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { apiClient } from '../../core/api/api-client.js';

export class BaseApiService {
_apiClient;

constructor() {
this._apiClient = apiClient;
}

_checkGenericError(axiosRes) {
if (axiosRes.status !== 200) {
return false;
}

return true;
}
}
Loading