feat(webui/dashboard): init new dashboard

This commit is contained in:
Antoine Caron 2019-07-18 22:36:04 +02:00 committed by Traefiker Bot
parent 8e97af8dc3
commit 4d8dcdc623
8 changed files with 303 additions and 41 deletions

View file

@ -10,6 +10,8 @@
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"bulma": "^0.7.5",
"chart.js": "^2.8.0",
"core-js": "^2.6.5",
"vue": "^2.6.10",
"vue-router": "^3.0.3",

View file

@ -1,5 +1,17 @@
<template>
<div id="app">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/dashboard">
<img
src="./assets/images/traefik_logo@3x.svg"
alt="Traefik Webui"
width="112"
height="28"
/>
</a>
</div>
</nav>
<router-view />
</div>
</template>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -3,6 +3,8 @@ import App from "./App.vue";
import router from "./router";
import store from "./store";
import "bulma/css/bulma.min.css";
Vue.config.productionTip = false;
new Vue({

View file

@ -1,6 +1,6 @@
import Vue from "vue";
import Router from "vue-router";
import WIP from "./views/WIP.vue";
import Home from "./views/Home.vue";
Vue.use(Router);
@ -9,7 +9,7 @@ export default new Router({
{
path: "/",
name: "home",
component: WIP
component: Home
}
]
});

228
webui/src/views/Home.vue Normal file
View file

@ -0,0 +1,228 @@
<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>
</div>
</div>
</section>
<section class="container panel" v-if="entrypoints.length">
<p class="panel-heading ">Entrypoints</p>
<div class="panel-block">
<nav class="level" :style="{ flex: '1 1' }">
<div
class="level-item has-text-centered"
v-for="entrypoint in entrypoints"
:key="entrypoint.name"
>
<div>
<p class="heading">{{ entrypoint.name }}</p>
<p class="title">{{ entrypoint.address }}</p>
</div>
</div>
</nav>
</div>
</section>
<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="column is-4">
<canvas id="http-routers" />
</div>
<div class="column is-4">
<canvas id="http-middlewares" />
</div>
<div class="column is-4">
<canvas id="http-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="column is-4">
<canvas id="tcp-routers" />
</div>
<div class="column is-4">
<canvas id="tcp-services" />
</div>
</div>
</section>
<section class="container panel">
<p class="panel-heading">Features</p>
<div class="panel-block">
<div class="tile is-ancestor">
<div
class="tile is-parent"
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>
</div>
</div>
</section>
</main>
</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: "home",
data: () => ({
entrypoints: [],
overview: {
features: []
},
charts: {
http: {
routers: null,
middlewares: null,
services: null
},
tcp: {
routers: null,
services: null
}
},
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"
)
}
};
});
},
fetchEntrypoints() {
return fetch("/api/entrypoints")
.then(response => response.json())
.then(response => (this.entrypoints = response));
}
},
async mounted() {
await this.fetchOverview();
await this.fetchEntrypoints();
this.interval = setInterval(() => {
this.fetchOverview();
this.fetchEntrypoints();
}, 60000);
},
beforeDestroy() {
clearInterval(this.interval);
}
};
</script>
<style lang="scss">
.home section {
margin-bottom: 1.5rem;
}
</style>

View file

@ -1,39 +0,0 @@
<template>
<main class="wip">
<img src="../assets/images/traefik.logo.svg" alt="logo" />
<header>
<h1 class="title">
<i class="fa fa-exclamation-triangle"></i>
Work in progress...
</h1>
<p>
In the meantime, you can review your current configuration by using the
<a href="/api/rawdata">/api/rawdata</a> endpoint <br /><br />
Also, please keep your <i class="fa fa-eye"></i> on our
<a href="https://docs.traefik.io/v2.0/operations/dashboard/"
>documentation</a
>
to stay informed
</p>
<p></p>
</header>
</main>
</template>
<script>
export default {
name: "home"
};
</script>
<style lang="sass">
.wip
display: flex
flex-direction: column
align-items: center
justify-content: center
height: 100vh
.title
font-size: 4em
</style>

View file

@ -2058,6 +2058,11 @@ builtin-status-codes@^3.0.0:
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
bulma@^0.7.5:
version "0.7.5"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.7.5.tgz#35066c37f82c088b68f94450be758fc00a967208"
integrity sha512-cX98TIn0I6sKba/DhW0FBjtaDpxTelU166pf7ICXpCCuplHWyu6C9LYZmL5PEsnePIeJaiorsTEzzNk3Tsm1hw==
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -2272,6 +2277,29 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chart.js@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.8.0.tgz#b703b10d0f4ec5079eaefdcd6ca32dc8f826e0e9"
integrity sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chartjs-color-string@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
dependencies:
color-name "^1.0.0"
chartjs-color@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.3.0.tgz#0e7e1e8dba37eae8415fd3db38bf572007dd958f"
integrity sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==
dependencies:
chartjs-color-string "^0.6.0"
color-convert "^0.5.3"
check-types@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
@ -2453,6 +2481,11 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -6513,6 +6546,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
dependencies:
minimist "0.0.8"
moment@^2.10.2:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"