feat(webui/dashboard): init new dashboard
This commit is contained in:
parent
8e97af8dc3
commit
4d8dcdc623
8 changed files with 303 additions and 41 deletions
|
@ -10,6 +10,8 @@
|
||||||
"test:unit": "vue-cli-service test:unit"
|
"test:unit": "vue-cli-service test:unit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bulma": "^0.7.5",
|
||||||
|
"chart.js": "^2.8.0",
|
||||||
"core-js": "^2.6.5",
|
"core-js": "^2.6.5",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"vue-router": "^3.0.3",
|
"vue-router": "^3.0.3",
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<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 />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
19
webui/src/assets/images/traefik_logo@3x.svg
Normal file
19
webui/src/assets/images/traefik_logo@3x.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 13 KiB |
|
@ -3,6 +3,8 @@ import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
|
|
||||||
|
import "bulma/css/bulma.min.css";
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Router from "vue-router";
|
import Router from "vue-router";
|
||||||
import WIP from "./views/WIP.vue";
|
import Home from "./views/Home.vue";
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ export default new Router({
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "home",
|
name: "home",
|
||||||
component: WIP
|
component: Home
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
228
webui/src/views/Home.vue
Normal file
228
webui/src/views/Home.vue
Normal 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>
|
|
@ -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>
|
|
|
@ -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"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
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:
|
bytes@3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
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"
|
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
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:
|
check-types@^8.0.3:
|
||||||
version "8.0.3"
|
version "8.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
|
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"
|
map-visit "^1.0.0"
|
||||||
object-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:
|
color-convert@^1.9.0, color-convert@^1.9.1:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
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:
|
dependencies:
|
||||||
minimist "0.0.8"
|
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:
|
move-concurrently@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||||
|
|
Loading…
Reference in a new issue