refactor(webui): use components to split Home concerns

This commit is contained in:
Antoine Caron 2019-07-22 11:06:04 +02:00 committed by Traefiker Bot
parent 28500989bc
commit 7c852fbf33
6 changed files with 184 additions and 138 deletions

View file

@ -18,6 +18,7 @@
"vuex": "^3.0.1"
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.9.0",
"@vue/cli-plugin-babel": "^3.9.0",
"@vue/cli-plugin-eslint": "^3.9.0",
"@vue/cli-plugin-unit-jest": "^3.9.0",

View file

@ -0,0 +1,79 @@
<template>
<canvas />
</template>
<script>
import Chart from "chart.js";
Chart.plugins.register({
afterDraw: function(chart) {
if (chart.data.datasets[0].data.reduce((acc, it) => acc + it, 0) === 0) {
var ctx = chart.chart.ctx;
var width = chart.chart.width;
var height = chart.chart.height;
chart.clear();
ctx.save();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "16px normal 'Helvetica Nueue'";
ctx.fillText(`No ${chart.options.title.text}`, width / 2, height / 2);
ctx.restore();
}
}
});
export default {
name: "EntityStateDoughnut",
props: {
entity: {
type: Object,
default: () => ({
errors: 0,
warnings: 0,
total: 0
})
},
title: {
type: String,
required: true
}
},
computed: {
data() {
return [
this.entity.errors,
this.entity.warnings,
this.entity.total - (this.entity.errors + this.entity.warnings)
];
}
},
mounted() {
new Chart(this.$el, {
type: "doughnut",
data: {
datasets: [
{
data: this.data,
backgroundColor: [
"hsl(348, 100%, 61%)",
"hsl(48, 100%, 67%)",
"hsl(141, 71%, 48%)"
]
}
],
labels: ["errors", "warnings", "success"]
},
options: {
title: {
display: true,
text: this.title
},
legend: {
display: false
}
}
});
}
};
</script>

View file

@ -0,0 +1,22 @@
<template>
<div class="tile is-parent">
<div class="tile is-child notification" :class="modifier">
<p class="title">{{ title }}</p>
</div>
</div>
</template>
<script>
export default {
props: {
modifier: {
type: Object,
default: () => ({})
},
title: {
type: String,
required: true
}
}
};
</script>

View file

@ -4,6 +4,8 @@ import router from "./router";
import store from "./store";
import "bulma/css/bulma.min.css";
import "@fortawesome/fontawesome-free";
import "@fortawesome/fontawesome-free/css/all.css";
Vue.config.productionTip = false;

View file

@ -1,27 +1,35 @@
<template>
<main class="home section">
<section class="container panel">
<p class="panel-heading ">🚧 Work in progress...</p>
<div class="panel-block">
<div>
<p>
In the meantime, you can review your current configuration by using
the <a href="/api/rawdata">/api/rawdata</a> endpoint.
</p>
<p>
Also, please keep your <i class="fa fa-eye" /> on our
<a href="https://docs.traefik.io/v2.0/operations/dashboard/"
>documentation</a
>
to stay informed
</p>
<section class="container hero is-info">
<div class="hero-body">
<div class="container">
<h1 class="title">
🚧 Work in progress...
</h1>
<h2 class="subtitle">
<p>
In the meantime, you can review your current configuration by
using the
<a href="/api/rawdata"
>/api/rawdata <i class="fas fa-external-link-alt"
/></a>
endpoint.
</p>
<p>
Also, please keep your <i class="fa fa-eye" /> on our
<a href="https://docs.traefik.io/v2.0/operations/dashboard/"
>documentation<i class="fas fa-external-link-alt"
/></a>
to stay informed
</p>
</h2>
</div>
</div>
</section>
<section class="container panel" v-if="entrypoints.length">
<p class="panel-heading ">Entrypoints</p>
<div class="panel-block">
<section class="container" v-if="entrypoints.length">
<p class="title is-4">Entrypoints</p>
<div class="tile is-child box columns">
<nav class="level" :style="{ flex: '1 1' }">
<div
class="level-item has-text-centered"
@ -39,47 +47,67 @@
<section class="container" v-if="overview.http">
<p class="title is-4">HTTP</p>
<div class="tile is-child box columns is-height-limited">
<div class="tile is-child box columns">
<div class="column is-4">
<canvas id="http-routers" />
<EntityStateDoughnut
:entity="overview.http.routers"
title="Routers"
/>
</div>
<div class="column is-4">
<canvas id="http-middlewares" />
<EntityStateDoughnut
:entity="overview.http.middlewares"
title="Middlewares"
/>
</div>
<div class="column is-4">
<canvas id="http-services" />
<EntityStateDoughnut
:entity="overview.http.services"
title="Services"
/>
</div>
</div>
</section>
<section class="container" v-if="overview.tcp">
<p class="title is-4">TCP</p>
<div class="tile is-child box columns is-height-limited">
<div class="tile is-child box columns">
<div class="column is-4">
<canvas id="tcp-routers" />
<EntityStateDoughnut :entity="overview.tcp.routers" title="Routers" />
</div>
<div class="column is-4">
<canvas id="tcp-services" />
<EntityStateDoughnut
:entity="overview.tcp.services"
title="Services"
/>
</div>
</div>
</section>
<section class="container panel">
<p class="panel-heading">Features</p>
<div class="panel-block">
<section class="container">
<p class="title is-4">Features</p>
<div class="tile is-child box columns">
<div class="tile is-ancestor">
<div
class="tile is-parent"
<Tile
v-for="(feature, key) of overview.features"
:key="key"
>
<div
class="tile is-child notification"
:class="{ 'is-success': feature, 'is-danger': !feature }"
>
<p class="title">{{ key }}</p>
</div>
</div>
:title="key"
:modifier="{ 'is-success': feature, 'is-danger': !feature }"
/>
</div>
</div>
</section>
<section class="container">
<p class="title is-4">Providers</p>
<div class="tile is-child box columns">
<div class="tile is-ancestor">
<Tile
v-for="provider of overview.providers"
:key="provider"
:title="provider"
:modifier="{ 'is-info': provider, 'is-3': provider }"
/>
</div>
</div>
</section>
@ -87,119 +115,28 @@
</template>
<script>
import Chart from "chart.js";
Chart.plugins.register({
afterDraw: function(chart) {
if (chart.data.datasets[0].data.reduce((acc, it) => acc + it, 0) === 0) {
var ctx = chart.chart.ctx;
var width = chart.chart.width;
var height = chart.chart.height
chart.clear();
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = "16px normal 'Helvetica Nueue'";
ctx.fillText(`No ${chart.options.title.text}`, width / 2, height / 2);
ctx.restore();
}
}
});
import Tile from "../components/Tile";
import EntityStateDoughnut from "../components/EntityStateDoughnut";
export default {
name: "home",
components: {
Tile,
EntityStateDoughnut
},
data: () => ({
entrypoints: [],
overview: {
features: []
},
charts: {
http: {
routers: null,
middlewares: null,
services: null
},
tcp: {
routers: null,
services: null
}
features: [],
providers: []
},
interval: null
}),
methods: {
buildDoughnutChart(
selector,
entity = { errors: 2, warnings: 2, total: 6 },
name
) {
return new Chart(this.$el.querySelector(selector), {
type: "doughnut",
data: {
datasets: [
{
data: [
entity.errors,
entity.warnings,
entity.total - (entity.errors + entity.warnings)
],
backgroundColor: [
"hsl(348, 100%, 61%)",
"hsl(48, 100%, 67%)",
"hsl(141, 71%, 48%)"
]
}
],
labels: ["errors", "warnings", "success"]
},
options: {
title: {
display: true,
text: name
},
legend: {
display: false
}
}
});
},
fetchOverview() {
return fetch("/api/overview")
.then(response => response.json())
.then(response => (this.overview = response))
.then(() => {
this.charts = {
http: {
routers: this.buildDoughnutChart(
"#http-routers",
this.overview.http.routers,
"Routers"
),
middlewares: this.buildDoughnutChart(
"#http-middlewares",
this.overview.http.middlewares,
"Middlewares"
),
services: this.buildDoughnutChart(
"#http-services",
this.overview.http.services,
"Services"
)
},
tcp: {
routers: this.buildDoughnutChart(
"#tcp-routers",
this.overview.tcp.routers,
"Routers"
),
services: this.buildDoughnutChart(
"#tcp-services",
this.overview.tcp.services,
"Services"
)
}
};
});
.then(response => (this.overview = response));
},
fetchEntrypoints() {
return fetch("/api/entrypoints")

View file

@ -670,6 +670,11 @@
lodash "^4.17.11"
to-fast-properties "^2.0.0"
"@fortawesome/fontawesome-free@^5.9.0":
version "5.9.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.9.0.tgz#1aa5c59efb1b8c6eb6277d1e3e8c8f31998b8c8e"
integrity sha512-g795BBEzM/Hq2SYNPm/NQTIp3IWd4eXSH0ds87Na2jnrAUFX3wkyZAI4Gwj9DOaWMuz2/01i8oWI7P7T/XLkhg==
"@hapi/address@2.x.x":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a"