chore(webui): Migrate to Quasar 2.x and Vue.js 3.x

This commit is contained in:
Andi Sardina Ramos 2024-02-26 16:02:04 +02:00 committed by GitHub
parent 153765f99f
commit f7edb394f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
65 changed files with 4374 additions and 7999 deletions

View file

@ -1 +1,7 @@
/dist
/src-capacitor
/src-cordova
/.quasar
/node_modules
.eslintrc.cjs
/quasar.config.*.temporary.compiled*

View file

@ -2,21 +2,24 @@ module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
parser: '@babel/eslint-parser',
ecmaVersion: 2021, // Allows for the parsing of modern ECMAScript features
},
env: {
node: true,
browser: true,
mocha: true
mocha: true,
'vue/setup-compiler-macros': true
},
extends: [
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
'plugin:vue/essential',
'@vue/standard',
'plugin:mocha/recommended'
'plugin:vue/vue3-essential',
'plugin:vue/vue3-recommended',
'plugin:mocha/recommended',
'standard'
],
// required to lint *.vue files
@ -26,10 +29,16 @@ module.exports = {
],
globals: {
'ga': true, // Google Analytics
'cordova': true,
'__statics': true,
'process': true
ga: 'readonly', // Google Analytics
cordova: 'readonly',
__statics: 'readonly',
__QUASAR_SSR__: 'readonly',
__QUASAR_SSR_SERVER__: 'readonly',
__QUASAR_SSR_CLIENT__: 'readonly',
__QUASAR_SSR_PWA__: 'readonly',
process: 'readonly',
Capacitor: 'readonly',
chrome: 'readonly'
},
// add your custom rules here
@ -39,6 +48,8 @@ module.exports = {
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'no-void': 'off',
'multiline-ternary': 'off',
'import/first': 'off',
'import/named': 'error',
@ -49,6 +60,7 @@ module.exports = {
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'vue/multi-word-component-names': 'off',
// allow console.log during development only
//'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
@ -56,3 +68,4 @@ module.exports = {
//'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}

16
webui/babel.config.cjs Normal file
View file

@ -0,0 +1,16 @@
/* eslint-disable */
module.exports = api => {
return {
presets: [
[
'@quasar/babel-preset-app',
api.caller(caller => caller && caller.target === 'node')
? { targets: { node: 'current' } }
: {}
]
]
}
}

View file

@ -1,5 +0,0 @@
module.exports = {
presets: [
'@quasar/babel-preset-app'
]
}

View file

@ -20,7 +20,6 @@
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-icon-180x180.png">
</head>
<body>
<!-- DO NOT touch the following DIV -->
<div id="q-app"></div>
<!-- quasar:entry-point -->
</body>
</html>

39
webui/jsconfig.json Normal file
View file

@ -0,0 +1,39 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": [
"src/*"
],
"app/*": [
"*"
],
"components/*": [
"src/components/*"
],
"layouts/*": [
"src/layouts/*"
],
"pages/*": [
"src/pages/*"
],
"assets/*": [
"src/assets/*"
],
"boot/*": [
"src/boot/*"
],
"stores/*": [
"src/stores/*"
],
"vue$": [
"node_modules/vue/dist/vue.runtime.esm-bundler.js"
]
}
},
"exclude": [
"dist",
".quasar",
"node_modules"
]
}

View file

@ -16,42 +16,45 @@
"build:nc": "yarn build"
},
"dependencies": {
"@quasar/extras": "^1.11.2",
"axios": "^0.21.1",
"bowser": "^2.5.2",
"chart.js": "^2.8.0",
"dot-prop": "^5.2.0",
"@quasar/extras": "^1.16.9",
"axios": "^1.6.7",
"bowser": "^2.11.0",
"chart.js": "^4.4.1",
"core-js": "^3.35.1",
"iframe-resizer": "^4.2.11",
"dot-prop": "^8.0.2",
"iframe-resizer": "^4.3.9",
"lodash.isequal": "4.5.0",
"moment": "^2.24.0",
"quasar": "^1.22.10",
"query-string": "^6.13.1",
"moment": "^2.30.1",
"quasar": "^2.14.3",
"query-string": "^8.1.0",
"vh-check": "^2.0.5",
"vue-chartjs": "^3.4.2",
"vuex-map-fields": "^1.3.4"
"vue": "^3.0.0",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.0.12",
"vuex": "^4.1.0",
"vuex-map-fields": "^1.4.1"
},
"devDependencies": {
"@quasar/app": "^2.4.3",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-eslint": "^10.0.1",
"chai": "4.2.0",
"eslint": "^5.10.0",
"eslint-loader": "^2.1.1",
"eslint-plugin-prettier": "3.1.1",
"eslint-plugin-mocha": "6.2.1",
"eslint-plugin-vue": "^5.0.0",
"mocha": "^6.2.2",
"mocha-webpack": "^2.0.0-beta.0",
"prettier": "1.19.1"
"@babel/core": "^7.23.9",
"@babel/eslint-parser": "^7.23.10",
"@quasar/app-vite": "^1.4.3",
"@quasar/babel-preset-app": "^2.0.2",
"@vue/test-utils": "^2.4.4",
"autoprefixer": "^10.4.2",
"chai": "5.0.3",
"eslint": "^8.11.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-mocha": "^10.2.0",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-vue": "^9.0.0",
"mocha": "^10.2.0",
"postcss": "^8.4.14"
},
"engines": {
"node": ">= 8.9.0",
"npm": ">= 5.6.0",
"yarn": ">= 1.6.0"
},
"browserslist": [
"last 1 version, not dead, ie >= 11"
]
"node": "^20 || ^18 || ^16",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
}
}

27
webui/postcss.config.cjs Normal file
View file

@ -0,0 +1,27 @@
/* eslint-disable */
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: [
// https://github.com/postcss/autoprefixer
require('autoprefixer')({
overrideBrowserslist: [
'last 4 Chrome versions',
'last 4 Firefox versions',
'last 4 Edge versions',
'last 4 Safari versions',
'last 4 Android versions',
'last 4 ChromeAndroid versions',
'last 4 FirefoxAndroid versions',
'last 4 iOS versions'
]
})
// https://github.com/elchininet/postcss-rtlcss
// If you want to support RTL css, then
// 1. yarn/npm install postcss-rtlcss
// 2. optionally set quasar.config.js > framework > lang to an RTL language
// 3. uncomment the following line:
// require('postcss-rtlcss')
]
}

View file

@ -1,12 +1,18 @@
// Configuration for your app
// https://quasar.dev/quasar-cli/quasar-conf-js
module.exports = function (ctx) {
const { configure } = require('quasar/wrappers')
module.exports = configure(function (ctx) {
return {
eslint: {
warnings: true,
errors: true
},
// app boot file (/src/boot)
// --> boot files are part of "main.js"
boot: [
'_globals',
'api',
'_hacks',
'_init'
@ -114,6 +120,17 @@ module.exports = function (ctx) {
supportIE: false,
build: {
viteVuePluginOptions: {
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('hub-')
}
}
},
target: {
browser: ['edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node20'
},
publicPath: process.env.APP_PUBLIC_PATH || '',
env: process.env.APP_ENV === 'development'
? { // staging:
@ -131,22 +148,7 @@ module.exports = function (ctx) {
}
},
scopeHoisting: true,
// vueRouterMode: 'history',
// vueCompiler: true,
// gzip: true,
// analyze: true,
// extractCSS: false,
extendWebpack (cfg) {
cfg.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/,
options: {
formatter: require('eslint').CLIEngine.getFormatter('stylish')
}
})
}
vueRouterMode: 'hash' // available values: 'hash', 'history'
},
devServer: {
@ -166,16 +168,24 @@ module.exports = function (ctx) {
animations: [],
ssr: {
pwa: false
pwa: false,
},
pwa: {
workboxMode: 'injectManifest', // or 'generateSW'
// workboxPluginMode: 'InjectManifest',
// workboxOptions: {}, // only for NON InjectManifest
workboxOptions: {
skipWaiting: true,
clientsClaim: true
},
chainWebpackCustomSW (chain) {
chain.plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js'] }])
},
manifest: {
// name: 'Traefik',
// short_name: 'Traefik',
@ -247,4 +257,4 @@ module.exports = function (ctx) {
}
}
}
}
})

View file

@ -13,6 +13,11 @@ export default {
computed: {
...mapGetters('core', { coreVersion: 'version' })
},
watch: {
'$q.dark.isActive' (val) {
localStorage.setItem('traefik-dark', val)
}
},
beforeCreate () {
// Set vue instance
APP.vue = () => this.$root
@ -21,11 +26,6 @@ export default {
console.log('Quasar -> ', this.$q.version)
this.$q.dark.set(localStorage.getItem('traefik-dark') === 'true')
},
watch: {
'$q.dark.isActive' (val) {
localStorage.setItem('traefik-dark', val)
}
}
}
</script>

View file

@ -1,8 +1,16 @@
import Vue from 'vue'
import iFrameResize from 'iframe-resizer/js/iframeResizer'
import iframeResize from 'iframe-resizer/js/iframeResizer'
Vue.directive('resize', {
bind: function (el, { value = {} }) {
el.addEventListener('load', () => iFrameResize(value, el))
const resize = {
mounted (el, binding) {
const options = binding.value || {}
el.addEventListener('load', () => iframeResize(options, el))
},
unmounted (el) {
const resizableEl = el
if (resizableEl.iFrameResizer) {
resizableEl.iFrameResizer.removeListeners()
}
})
}
}
export default resize

View file

@ -22,7 +22,7 @@ class Errors {
static handleResponse (error) {
console.log('handleResponse', error, error.response)
let body = error.response.data
const body = error.response.data
if (error.response.status === 401) {
// TODO - actions...
}

View file

@ -1,4 +1,4 @@
import { get } from 'dot-prop'
import { getProperty } from 'dot-prop'
class Helps {
// Getters
@ -11,7 +11,7 @@ class Helps {
// ------------------------------------------------------------------------
static get (obj, prop, def = undefined) {
return get(obj, prop, def)
return getProperty(obj, prop, def)
}
static hasIn (obj, prop) {
@ -39,13 +39,12 @@ class Helps {
}
static removeEmptyObjects (objects) {
const obj = {}
Object.entries(objects).map(item => {
if (item[1] !== '') {
obj[item[0]] = item[1]
}
})
return obj
Object.entries(objects)
.filter(item => item[1] !== '')
.reduce((acc, item) => {
acc[item[0]] = item[1]
return acc
}, {})
}
// Helps -> Numbers

View file

@ -1,8 +1,8 @@
import { set, get } from 'dot-prop'
import { setProperty, getProperty } from 'dot-prop'
export const withPagination = (type, opts = {}) => (state, data) => {
const { isSameContext, statePath } = opts
const currentState = get(state, statePath)
const currentState = getProperty(state, statePath)
let newState
@ -13,7 +13,7 @@ export const withPagination = (type, opts = {}) => (state, data) => {
loading: true
}
break
case 'success':
case 'success': {
const { body, page } = data
newState = {
...currentState,
@ -28,6 +28,7 @@ export const withPagination = (type, opts = {}) => (state, data) => {
loading: false
}
break
}
case 'failure':
newState = {
...currentState,
@ -39,6 +40,6 @@ export const withPagination = (type, opts = {}) => (state, data) => {
}
if (newState) {
set(state, statePath, newState)
setProperty(state, statePath, newState)
}
}

View file

@ -4,6 +4,11 @@ import Helps from '../_helpers/Helps'
const Boot = {
install (Vue, options) {
Vue.mixin({
filters: {
capFirstLetter (value) {
return Helps.capFirstLetter(value)
}
},
data () {
return {
}
@ -28,14 +33,9 @@ const Boot = {
}
}
},
methods: {
},
filters: {
capFirstLetter (value) {
return Helps.capFirstLetter(value)
}
},
created () {
},
methods: {
}
})
}

View file

@ -1,9 +1,9 @@
import { get } from 'dot-prop'
import { getProperty } from 'dot-prop'
import { QChip } from 'quasar'
import Chips from '../components/_commons/Chips'
import ProviderIcon from '../components/_commons/ProviderIcon'
import AvatarState from '../components/_commons/AvatarState'
import TLSState from '../components/_commons/TLSState'
import Chips from '../components/_commons/Chips.vue'
import ProviderIcon from '../components/_commons/ProviderIcon.vue'
import AvatarState from '../components/_commons/AvatarState.vue'
import TLSState from '../components/_commons/TLSState.vue'
const allColumns = [
{
@ -141,7 +141,7 @@ const GetTablePropsMixin = {
path: `/${type.replace('-', '/', 'gi')}/${encodeURIComponent(row.name)}`
}),
columns: allColumns.filter(c =>
get(propsByType, `${type}.columns`, []).includes(c.name)
getProperty(propsByType, `${type}.columns`, []).includes(c.name)
)
}
}

View file

@ -1,4 +1,4 @@
import { get } from 'dot-prop'
import { getProperty } from 'dot-prop'
export default function PaginationMixin (opts = {}) {
const { pollingIntervalTime, rowsPerPage = 10 } = opts
@ -28,7 +28,7 @@ export default function PaginationMixin (opts = {}) {
currentPage = page
currentLimit = limit || rowsPerPage
const fetchMethod = get(this, opts.fetchMethod)
const fetchMethod = getProperty(this, opts.fetchMethod)
return fetchMethod({
...params,
@ -41,7 +41,7 @@ export default function PaginationMixin (opts = {}) {
})
},
initFetch (params) {
const scrollerRef = get(this.$refs, opts.scrollerRef)
const scrollerRef = getProperty(this.$refs, opts.scrollerRef)
if (scrollerRef) {
scrollerRef.stop()

View file

@ -1,8 +1,8 @@
import { APP } from '../_helpers/APP'
import Boot from '../_middleware/Boot'
export default async ({ app, router, store, Vue }) => {
Vue.use(Boot)
export default async ({ app, router, store }) => {
app.use(Boot)
APP.root = app
APP.router = router

View file

@ -1,10 +1,14 @@
import { APP } from '../_helpers/APP'
import errors from '../_helpers/Errors'
import resize from '../_directives/resize'
export default async ({ app, router }) => {
// Directives
app.directive('resize', resize)
export default async ({ Vue }) => {
// Router
// ----------------------------------------------
APP.router.beforeEach(async (to, from, next) => {
router.beforeEach(async (to, from, next) => {
// Set APP
APP.routeTo = to
APP.routeFrom = from

View file

@ -1,12 +1,16 @@
import { boot } from 'quasar/wrappers'
import axios from 'axios'
import { APP } from '../_helpers/APP'
// Set config defaults when creating the instance
const API = axios.create({
const api = axios.create({
baseURL: APP.config.apiUrl
})
export default async ({ app, Vue }) => {
Vue.prototype.$api = app.api = APP.api = API
}
export default boot(({ app }) => {
app.config.globalProperties.$axios = axios
app.config.globalProperties.$api = api
APP.api = api
})
export { api }

View file

@ -1,16 +1,32 @@
<template>
<q-avatar :color="state" text-color="white">
<q-icon v-if="state === 'positive'" name="eva-checkmark-circle-2" />
<q-icon v-if="state === 'warning'" name="eva-alert-circle" />
<q-icon v-if="state === 'negative'" name="eva-alert-triangle" />
<q-avatar
:color="state"
text-color="white"
>
<q-icon
v-if="state === 'positive'"
name="eva-checkmark-circle-2"
/>
<q-icon
v-if="state === 'warning'"
name="eva-alert-circle"
/>
<q-icon
v-if="state === 'negative'"
name="eva-alert-triangle"
/>
</q-avatar>
</template>
<script>
export default {
import { defineComponent } from 'vue'
export default defineComponent({
name: 'AvatarState',
props: ['state']
}
props: {
state: String
}
})
</script>
<style scoped lang="scss">

View file

@ -1,18 +1,36 @@
<template>
<div class="block-right-text">
<q-avatar :color="value ? 'positive' : 'negative'" text-color="white">
<q-icon v-if="value" name="eva-toggle-right" />
<q-icon v-if="!value" name="eva-toggle-left" />
<q-avatar
:color="value ? 'positive' : 'negative'"
text-color="white"
>
<q-icon
v-if="value"
name="eva-toggle-right"
/>
<q-icon
v-if="!value"
name="eva-toggle-left"
/>
</q-avatar>
<div v-bind:class="['block-right-text-label', `block-right-text-label-${!!value}`]">{{value ? 'True' : 'False'}}</div>
<div :class="['block-right-text-label', `block-right-text-label-${!!value}`]">
{{ value ? 'True' : 'False' }}
</div>
</div>
</template>
<script>
export default {
import { defineComponent } from 'vue'
export default defineComponent({
name: 'BooleanState',
props: ['value']
}
props: {
value: {
type: Boolean,
default: true
}
}
})
</script>
<style scoped lang="scss">

View file

@ -4,7 +4,8 @@
v-for="(chip, index) in list"
:key="index"
:dense="dense"
:class="classNames">
:class="classNames"
>
{{ chip }}
</q-chip>
</div>
@ -12,6 +13,10 @@
<script>
export default {
props: ['dense', 'classNames', 'list']
props: {
dense: Boolean,
classNames: Array[String],
list: Array[Object]
}
}
</script>

View file

@ -1,13 +1,18 @@
<template>
<div class="table-wrapper">
<q-infinite-scroll @load="handleLoadMore" :offset="250" ref="scroller">
<q-infinite-scroll
ref="scroller"
:offset="250"
@load="handleLoadMore"
>
<q-markup-table>
<thead>
<tr class="table-header">
<th
v-for="column in columns"
v-bind:class="`text-${column.align}`"
v-bind:key="column.name">
:key="column.name"
:class="`text-${column.align}`"
>
{{ column.label }}
</th>
</tr>
@ -15,16 +20,28 @@
<tfoot v-if="!data || !data.length">
<tr>
<td colspan="100%">
<q-icon name="warning" style="font-size: 1.5rem"/> No data available
<q-icon
name="warning"
style="font-size: 1.5rem"
/> No data available
</td>
</tr>
</tfoot>
<tbody>
<tr v-for="row in data" :key="row.name" class="cursor-pointer" @click="onRowClick(row)">
<tr
v-for="row in data"
:key="row.name"
class="cursor-pointer"
@click="onRowClick(row)"
>
<template v-for="column in columns">
<td :key="column.name" v-if="getColumn(column.name).component" v-bind:class="`text-${getColumn(column.name).align}`">
<td
v-if="getColumn(column.name).component"
:key="column.name"
:class="`text-${getColumn(column.name).align}`"
>
<component
v-bind:is="getColumn(column.name).component"
:is="getColumn(column.name).component"
v-bind="getColumn(column.name).fieldToProps(row)"
>
<template v-if="getColumn(column.name).content">
@ -33,27 +50,41 @@
</component>
</td>
<td
:key="column.name"
v-if="!getColumn(column.name).component"
v-bind:class="`text-${getColumn(column.name).align}`"
:key="column.name"
:class="`text-${getColumn(column.name).align}`"
v-bind="getColumn(column.name).fieldToProps(row)"
>
<span>
{{getColumn(column.name).content ? getColumn(column.name).content(row) : row[column.name]}}
{{ getColumn(column.name).content ? getColumn(column.name).content(row) : row[column.name] }}
</span>
</td>
</template>
</tr>
</tbody>
</q-markup-table>
<template v-slot:loading v-if="loading">
<template
v-if="loading"
#loading
>
<div class="row justify-center q-my-md">
<q-spinner-dots color="app-grey" size="40px" />
<q-spinner-dots
color="app-grey"
size="40px"
/>
</div>
</template>
</q-infinite-scroll>
<q-page-scroller position="bottom" :scroll-offset="150" class="back-to-top" v-if="endReached">
<q-btn color="primary" small>
<q-page-scroller
v-if="endReached"
position="bottom"
:scroll-offset="150"
class="back-to-top"
>
<q-btn
color="primary"
small
>
Back to top
</q-btn>
</q-page-scroller>
@ -61,28 +92,40 @@
</template>
<script>
import { defineComponent } from 'vue'
import { QMarkupTable, QInfiniteScroll, QSpinnerDots, QPageScroller } from 'quasar'
export default {
export default defineComponent({
name: 'MainTable',
props: ['data', 'columns', 'loading', 'onLoadMore', 'endReached', 'onRowClick'],
components: {
QMarkupTable,
QInfiniteScroll,
QSpinnerDots,
QPageScroller
},
props: {
data: Object,
columns: Array[Object],
loading: Boolean,
onLoadMore: Function,
endReached: Boolean,
onRowClick: Function
},
methods: {
getColumn (columnName) {
return this.columns.find(c => c.name === columnName) || {}
},
handleLoadMore (index, done) {
if (!this?.onLoadMore) {
done()
} else {
this.onLoadMore({ page: index })
.then(() => done())
.catch(() => done(true))
}
}
}
}
})
</script>
<style scoped lang="scss">

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
<template>
<q-page>
<slot/>
<slot />
</q-page>
</template>

View file

@ -1,21 +1,40 @@
<template>
<q-card flat bordered v-bind:class="['panel-health-check', {'panel-health-check-dense':isDense}]">
<q-scroll-area :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-health-check', {'panel-health-check-dense':isDense}]"
>
<q-scroll-area
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section v-if="data.scheme || data.interval">
<div class="row items-start no-wrap">
<div class="col" v-if="data.scheme">
<div class="text-subtitle2">SCHEME</div>
<div
v-if="data.scheme"
class="col"
>
<div class="text-subtitle2">
SCHEME
</div>
<q-chip
dense
class="app-chip app-chip-options">
class="app-chip app-chip-options"
>
{{ data.scheme }}
</q-chip>
</div>
<div class="col" v-if="data.interval">
<div class="text-subtitle2">INTERVAL</div>
<div
v-if="data.interval"
class="col"
>
<div class="text-subtitle2">
INTERVAL
</div>
<q-chip
dense
class="app-chip app-chip-interval">
class="app-chip app-chip-interval"
>
{{ data.interval }}
</q-chip>
</div>
@ -23,19 +42,31 @@
</q-card-section>
<q-card-section v-if="data.path || data.timeout">
<div class="row items-start no-wrap">
<div class="col" v-if="data.path">
<div class="text-subtitle2">PATH</div>
<div
v-if="data.path"
class="col"
>
<div class="text-subtitle2">
PATH
</div>
<q-chip
dense
class="app-chip app-chip-entry-points">
class="app-chip app-chip-entry-points"
>
{{ data.path }}
</q-chip>
</div>
<div class="col" v-if="data.timeout">
<div class="text-subtitle2">TIMEOUT</div>
<div
v-if="data.timeout"
class="col"
>
<div class="text-subtitle2">
TIMEOUT
</div>
<q-chip
dense
class="app-chip app-chip-interval">
class="app-chip app-chip-interval"
>
{{ data.timeout }}
</q-chip>
</div>
@ -43,19 +74,31 @@
</q-card-section>
<q-card-section v-if="data.port || data.hostname">
<div class="row items-start no-wrap">
<div class="col" v-if="data.port">
<div class="text-subtitle2">PORT</div>
<div
v-if="data.port"
class="col"
>
<div class="text-subtitle2">
PORT
</div>
<q-chip
dense
class="app-chip app-chip-name">
class="app-chip app-chip-name"
>
{{ data.port }}
</q-chip>
</div>
<div class="col" v-if="data.hostname">
<div class="text-subtitle2">HOSTNAME</div>
<div
v-if="data.hostname"
class="col"
>
<div class="text-subtitle2">
HOSTNAME
</div>
<q-chip
dense
class="app-chip app-chip-rule">
class="app-chip app-chip-rule"
>
{{ data.hostname }}
</q-chip>
</div>
@ -64,12 +107,19 @@
<q-card-section v-if="data.headers">
<div class="row items-start">
<div class="col-12">
<div class="text-subtitle2">HEADERS</div>
<div class="text-subtitle2">
HEADERS
</div>
<div v-for="(header, index) in data.headers" :key="index" class="col-12">
</div>
<div
v-for="(header, index) in data.headers"
:key="index"
class="col-12"
>
<q-chip
dense
class="app-chip app-chip-wrap app-chip-service">
class="app-chip app-chip-wrap app-chip-service"
>
{{ index }}: {{ header }}
</q-chip>
</div>
@ -82,15 +132,18 @@
<script>
export default {
name: 'PanelHealthCheck',
props: ['data', 'dense'],
components: {
},
filters: {
},
props: {
data: Object,
dense: Boolean
},
computed: {
isDense () {
return this.dense !== undefined
}
},
filters: {
}
}
</script>

File diff suppressed because it is too large Load diff

View file

@ -1,29 +1,52 @@
<template>
<q-card flat bordered v-bind:class="['panel-services', {'panel-services-dense':isDense}]">
<q-scroll-area :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-services', {'panel-services-dense':isDense}]"
>
<q-scroll-area
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col-6">
<div class="text-subtitle2 text-table">Name</div>
<div class="text-subtitle2 text-table">
Name
</div>
</div>
<div class="col-3">
<div class="text-subtitle2 text-table" style="text-align: right">Percent</div>
<div
class="text-subtitle2 text-table"
style="text-align: right"
>
Percent
</div>
</div>
<div class="col-3">
<div class="text-subtitle2 text-table" style="text-align: right">Provider</div>
<div
class="text-subtitle2 text-table"
style="text-align: right"
>
Provider
</div>
</div>
</div>
</q-card-section>
<q-separator />
<div v-for="(service, index) in data.mirroring.mirrors" :key="index">
<div
v-for="(service, index) in data.mirroring.mirrors"
:key="index"
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col-6">
<q-chip
dense
class="app-chip app-chip-rule app-chip-overflow">
class="app-chip app-chip-rule app-chip-overflow"
>
{{ service.name }}
<q-tooltip>{{service.name}}</q-tooltip>
<q-tooltip>{{ service.name }}</q-tooltip>
</q-chip>
</div>
<div class="col-3 text-right">
@ -46,8 +69,10 @@
export default {
name: 'PanelMirroringServices',
props: ['data', 'dense'],
components: {},
props: {
data: Object,
dense: Boolean
},
computed: {
isDense () {
return this.dense !== undefined
@ -70,13 +95,13 @@ export default {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
return 'providers/nomad.svg'
}
return `providers/${name}.svg`

View file

@ -1,22 +1,37 @@
<template>
<q-card flat bordered v-bind:class="['panel-router-details']">
<q-scroll-area :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-router-details']"
>
<q-scroll-area
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">STATUS</div>
<div class="text-subtitle2">
STATUS
</div>
<div class="block-right-text">
<avatar-state :state="data.status | status "/>
<div v-bind:class="['block-right-text-label', `block-right-text-label-${data.status}`]">{{data.status | statusLabel}}</div>
<avatar-state :state="status(data.status)" />
<div :class="['block-right-text-label', `block-right-text-label-${data.status}`]">
{{ statusLabel(data.status) }}
</div>
</div>
</div>
<div class="col">
<div class="text-subtitle2">PROVIDER</div>
<div class="text-subtitle2">
PROVIDER
</div>
<div class="block-right-text">
<q-avatar class="provider-logo">
<q-icon :name="`img:${getProviderLogoPath}`" />
</q-avatar>
<div class="block-right-text-label">{{data.provider}}</div>
<div class="block-right-text-label">
{{ data.provider }}
</div>
</div>
</div>
</div>
@ -24,10 +39,13 @@
<q-card-section v-if="data.rule">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">RULE</div>
<div class="text-subtitle2">
RULE
</div>
<q-chip
dense
class="app-chip app-chip-wrap app-chip-rule">
class="app-chip app-chip-wrap app-chip-rule"
>
{{ data.rule }}
</q-chip>
</div>
@ -36,10 +54,13 @@
<q-card-section v-if="data.name">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">NAME</div>
<div class="text-subtitle2">
NAME
</div>
<q-chip
dense
class="app-chip app-chip-wrap app-chip-name">
class="app-chip app-chip-wrap app-chip-name"
>
{{ data.name }}
</q-chip>
</div>
@ -48,11 +69,15 @@
<q-card-section v-if="data.using">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">ENTRYPOINTS</div>
<div class="text-subtitle2">
ENTRYPOINTS
</div>
<q-chip
v-for="(entryPoint, index) in data.using" :key="index"
v-for="(entryPoint, index) in data.using"
:key="index"
dense
class="app-chip app-chip-entry-points">
class="app-chip app-chip-entry-points"
>
{{ entryPoint }}
</q-chip>
</div>
@ -61,12 +86,15 @@
<q-card-section v-if="data.service">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">SERVICE</div>
<div class="text-subtitle2">
SERVICE
</div>
<q-chip
dense
clickable
@click.native="$router.push({ path: `/${protocol}/services/${getServiceId()}`})"
class="app-chip app-chip-wrap app-chip-service app-chip-overflow">
class="app-chip app-chip-wrap app-chip-service app-chip-overflow"
@click="$router.push({ path: `/${protocol}/services/${getServiceId()}`})"
>
{{ data.service }}
<q-tooltip>{{ data.service }}</q-tooltip>
</q-chip>
@ -76,10 +104,14 @@
<q-card-section v-if="data.error">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">ERRORS</div>
<div class="text-subtitle2">
ERRORS
</div>
<q-chip
v-for="(errorMsg, index) in data.error" :key="index"
class="app-chip app-chip-error">
v-for="(errorMsg, index) in data.error"
:key="index"
class="app-chip app-chip-error"
>
{{ errorMsg }}
</q-chip>
</div>
@ -90,14 +122,38 @@
</template>
<script>
import AvatarState from './AvatarState'
import { defineComponent } from 'vue'
import AvatarState from './AvatarState.vue'
export default {
export default defineComponent({
name: 'PanelRouterDetails',
props: ['data', 'protocol'],
components: {
AvatarState
},
props: {
data: Object,
protocol: String
},
computed: {
getProviderLogoPath () {
const name = this.data.provider.toLowerCase()
if (name.startsWith('plugin-')) {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return 'providers/nomad.svg'
}
return `providers/${name}.svg`
}
},
methods: {
getServiceId () {
const words = this.data.service.split('@')
@ -106,9 +162,7 @@ export default {
}
return `${this.data.service}@${this.data.provider}`
}
},
filters: {
status (value) {
if (value === 'enabled') {
return 'positive'
@ -127,28 +181,8 @@ export default {
}
return value
}
},
computed: {
getProviderLogoPath () {
const name = this.data.provider.toLowerCase()
if (name.startsWith('plugin-')) {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
}
return `providers/${name}.svg`
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,31 +1,59 @@
<template>
<q-card flat bordered v-bind:class="['panel-servers', {'panel-servers-dense':isDense}]">
<q-scroll-area v-if="data.loadBalancer.servers" :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-servers', {'panel-servers-dense':isDense}]"
>
<q-scroll-area
v-if="data.loadBalancer.servers"
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col-3" v-if="showStatus">
<div class="text-subtitle2 text-table">Status</div>
<div
v-if="showStatus"
class="col-3"
>
<div class="text-subtitle2 text-table">
Status
</div>
</div>
<div class="col-9">
<div class="text-subtitle2 text-table">URL</div>
<div class="text-subtitle2 text-table">
URL
</div>
</div>
</div>
</q-card-section>
<q-separator />
<div v-for="(server, index) in data.loadBalancer.servers" :key="index">
<div
v-for="(server, index) in data.loadBalancer.servers"
:key="index"
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col-3" v-if="showStatus">
<div
v-if="showStatus"
class="col-3"
>
<div class="block-right-text">
<avatar-state v-if="data.serverStatus" :state="data.serverStatus[server.url || server.address] | status "/>
<avatar-state v-if="!data.serverStatus" :state="'DOWN' | status"/>
<avatar-state
v-if="data.serverStatus"
:state="status(data.serverStatus[server.url || server.address])"
/>
<avatar-state
v-if="!data.serverStatus"
:state="status('DOWN')"
/>
</div>
</div>
<div class="col-9">
<q-chip
dense
class="app-chip app-chip-rule">
{{ server.url || server.address}}
class="app-chip app-chip-rule"
>
{{ server.url || server.address }}
</q-chip>
</div>
</div>
@ -33,15 +61,31 @@
<q-separator />
</div>
</q-scroll-area>
<q-card-section v-else style="height: 100%">
<div class="row items-center" style="height: 100%">
<q-card-section
v-else
style="height: 100%"
>
<div
class="row items-center"
style="height: 100%"
>
<div class="col-12">
<div class="block-empty"></div>
<div class="block-empty" />
<div class="q-pb-lg block-empty-logo">
<img v-if="$q.dark.isActive" alt="empty" src="~assets/middlewares-empty-dark.svg">
<img v-else alt="empty" src="~assets/middlewares-empty.svg">
<img
v-if="$q.dark.isActive"
alt="empty"
src="~assets/middlewares-empty-dark.svg"
>
<img
v-else
alt="empty"
src="~assets/middlewares-empty.svg"
>
</div>
<div class="block-empty-label">
There is no<br>Server available
</div>
<div class="block-empty-label">There is no<br>Server available</div>
</div>
</div>
</q-card-section>
@ -49,14 +93,19 @@
</template>
<script>
import AvatarState from './AvatarState'
import { defineComponent } from 'vue'
import AvatarState from './AvatarState.vue'
export default {
export default defineComponent({
name: 'PanelServers',
props: ['data', 'dense', 'hasStatus'],
components: {
AvatarState
},
props: {
data: Object,
dense: Boolean,
hasStatus: Boolean
},
computed: {
isDense () {
return this.dense !== undefined
@ -65,7 +114,7 @@ export default {
return this.hasStatus !== undefined
}
},
filters: {
methods: {
status (value) {
if (value === 'UP') {
return 'positive'
@ -73,7 +122,7 @@ export default {
return 'negative'
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,23 +1,40 @@
<template>
<q-card flat bordered v-bind:class="['panel-service-details', {'panel-service-details-dense':isDense}]">
<q-scroll-area :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-service-details', {'panel-service-details-dense':isDense}]"
>
<q-scroll-area
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col" v-if="data.type">
<div class="text-subtitle2">TYPE</div>
<div
v-if="data.type"
class="col"
>
<div class="text-subtitle2">
TYPE
</div>
<q-chip
dense
class="app-chip app-chip-entry-points">
class="app-chip app-chip-entry-points"
>
{{ data.type }}
</q-chip>
</div>
<div class="col">
<div class="text-subtitle2">PROVIDER</div>
<div class="text-subtitle2">
PROVIDER
</div>
<div class="block-right-text">
<q-avatar class="provider-logo">
<q-icon :name="`img:${getProviderLogoPath}`" />
</q-avatar>
<div class="block-right-text-label">{{data.provider}}</div>
<div class="block-right-text-label">
{{ data.provider }}
</div>
</div>
</div>
</div>
@ -25,10 +42,14 @@
<q-card-section>
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">STATUS</div>
<div class="text-subtitle2">
STATUS
</div>
<div class="block-right-text">
<avatar-state :state="data.status | status "/>
<div v-bind:class="['block-right-text-label', `block-right-text-label-${data.status}`]">{{data.status | statusLabel}}</div>
<avatar-state :state="status(data.status)" />
<div :class="['block-right-text-label', `block-right-text-label-${data.status}`]">
{{ statusLabel(data.status) }}
</div>
</div>
</div>
</div>
@ -36,10 +57,13 @@
<q-card-section v-if="data.mirroring">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Main Service</div>
<div class="text-subtitle2">
Main Service
</div>
<q-chip
dense
class="app-chip app-chip-name app-chip-overflow">
class="app-chip app-chip-name app-chip-overflow"
>
{{ data.mirroring.service }}
<q-tooltip>{{ data.mirroring.service }}</q-tooltip>
</q-chip>
@ -49,8 +73,10 @@
<q-card-section v-if="data.loadBalancer && $route.meta.protocol !== 'tcp'">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Pass Host Header</div>
<boolean-state :value="data.loadBalancer.passHostHeader"/>
<div class="text-subtitle2">
Pass Host Header
</div>
<boolean-state :value="data.loadBalancer.passHostHeader" />
</div>
</div>
</q-card-section>
@ -58,10 +84,13 @@
<q-card-section v-if="data.loadBalancer && data.loadBalancer.terminationDelay">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Termination Delay</div>
<div class="text-subtitle2">
Termination Delay
</div>
<q-chip
dense
class="app-chip app-chip-name">
class="app-chip app-chip-name"
>
{{ data.loadBalancer.terminationDelay }} ms
</q-chip>
</div>
@ -71,10 +100,13 @@
<q-card-section v-if="data.loadBalancer && data.loadBalancer.proxyProtocol">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Proxy Protocol</div>
<div class="text-subtitle2">
Proxy Protocol
</div>
<q-chip
dense
class="app-chip app-chip-name">
class="app-chip app-chip-name"
>
Version {{ data.loadBalancer.proxyProtocol.version }}
</q-chip>
</div>
@ -84,10 +116,13 @@
<q-card-section v-if="data.failover && data.failover.service">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Main Service</div>
<div class="text-subtitle2">
Main Service
</div>
<q-chip
dense
class="app-chip app-chip-name app-chip-overflow">
class="app-chip app-chip-name app-chip-overflow"
>
{{ data.failover.service }}
<q-tooltip>{{ data.failover.service }}</q-tooltip>
</q-chip>
@ -98,10 +133,13 @@
<q-card-section v-if="data.failover && data.failover.fallback">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">Fallback Service</div>
<div class="text-subtitle2">
Fallback Service
</div>
<q-chip
dense
class="app-chip app-chip-name app-chip-overflow">
class="app-chip app-chip-name app-chip-overflow"
>
{{ data.failover.fallback }}
<q-tooltip>{{ data.failover.fallback }}</q-tooltip>
</q-chip>
@ -110,24 +148,32 @@
</q-card-section>
<q-separator v-if="sticky" />
<StickyServiceDetails v-if="sticky" :sticky="sticky" :dense="dense"/>
<StickyServiceDetails
v-if="sticky"
:sticky="sticky"
:dense="dense"
/>
</q-scroll-area>
</q-card>
</template>
<script>
import AvatarState from './AvatarState'
import BooleanState from './BooleanState'
import StickyServiceDetails from './StickyServiceDetails'
import { defineComponent } from 'vue'
import AvatarState from './AvatarState.vue'
import BooleanState from './BooleanState.vue'
import StickyServiceDetails from './StickyServiceDetails.vue'
export default {
export default defineComponent({
name: 'PanelServiceDetails',
props: ['data', 'dense'],
components: {
BooleanState,
AvatarState,
StickyServiceDetails
},
props: {
data: Object,
dense: Boolean
},
computed: {
isDense () {
return this.dense !== undefined
@ -150,19 +196,19 @@ export default {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
return 'providers/nomad.svg'
}
return `providers/${name}.svg`
}
},
filters: {
methods: {
status (value) {
if (value === 'enabled') {
return 'positive'
@ -182,7 +228,7 @@ export default {
return value || 'error'
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,21 +1,34 @@
<template>
<q-card flat bordered v-bind:class="['panel-tls']">
<q-scroll-area v-if="data" :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-tls']"
>
<q-scroll-area
v-if="data"
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section v-if="data">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">TLS</div>
<boolean-state :value="!!data"/>
<div class="text-subtitle2">
TLS
</div>
<boolean-state :value="!!data" />
</div>
</div>
</q-card-section>
<q-card-section v-if="data.options">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">OPTIONS</div>
<div class="text-subtitle2">
OPTIONS
</div>
<q-chip
dense
class="app-chip app-chip-options">
class="app-chip app-chip-options"
>
{{ data.options }}
</q-chip>
</div>
@ -24,18 +37,23 @@
<q-card-section v-if="protocol === 'tcp'">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">PASSTHROUGH</div>
<boolean-state :value="data.passthrough"></boolean-state>
<div class="text-subtitle2">
PASSTHROUGH
</div>
<boolean-state :value="data.passthrough" />
</div>
</div>
</q-card-section>
<q-card-section v-if="data.certResolver">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">CERTIFICATE RESOLVER</div>
<div class="text-subtitle2">
CERTIFICATE RESOLVER
</div>
<q-chip
dense
class="app-chip app-chip-service">
class="app-chip app-chip-service"
>
{{ data.certResolver }}
</q-chip>
</div>
@ -44,17 +62,26 @@
<q-card-section v-if="data.domains">
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">DOMAINS</div>
<div v-for="(domain, key) in data.domains" :key="key" class="flex">
<div class="text-subtitle2">
DOMAINS
</div>
<div
v-for="(domain, key) in data.domains"
:key="key"
class="flex"
>
<q-chip
dense
class="app-chip app-chip-rule">
class="app-chip app-chip-rule"
>
{{ domain.main }}
</q-chip>
<q-chip
v-for="(domain, key) in domain.sans" :key="key"
v-for="(domain, key) in domain.sans"
:key="key"
dense
class="app-chip app-chip-entry-points">
class="app-chip app-chip-entry-points"
>
{{ domain }}
</q-chip>
</div>
@ -62,15 +89,31 @@
</div>
</q-card-section>
</q-scroll-area>
<q-card-section v-else style="height: 100%">
<div class="row items-center" style="height: 100%">
<q-card-section
v-else
style="height: 100%"
>
<div
class="row items-center"
style="height: 100%"
>
<div class="col-12">
<div class="block-empty"></div>
<div class="block-empty" />
<div class="q-pb-lg block-empty-logo">
<img v-if="$q.dark.isActive" alt="empty" src="~assets/middlewares-empty-dark.svg">
<img v-else alt="empty" src="~assets/middlewares-empty.svg">
<img
v-if="$q.dark.isActive"
alt="empty"
src="~assets/middlewares-empty-dark.svg"
>
<img
v-else
alt="empty"
src="~assets/middlewares-empty.svg"
>
</div>
<div class="block-empty-label">
There is no<br>TLS configured
</div>
<div class="block-empty-label">There is no<br>TLS configured</div>
</div>
</div>
</q-card-section>
@ -78,15 +121,19 @@
</template>
<script>
import BooleanState from './BooleanState'
import { defineComponent } from 'vue'
import BooleanState from './BooleanState.vue'
export default {
export default defineComponent({
name: 'PanelTLS',
components: {
BooleanState
},
props: ['data', 'protocol']
}
props: {
data: Object,
protocol: String
}
})
</script>
<style scoped lang="scss">

View file

@ -1,29 +1,46 @@
<template>
<q-card flat bordered v-bind:class="['panel-services', {'panel-services-dense':isDense}]">
<q-scroll-area :thumb-style="appThumbStyle" style="height:100%;">
<q-card
flat
bordered
:class="['panel-services', {'panel-services-dense':isDense}]"
>
<q-scroll-area
:thumb-style="appThumbStyle"
style="height:100%;"
>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col-7">
<div class="text-subtitle2 text-table">Name</div>
<div class="text-subtitle2 text-table">
Name
</div>
</div>
<div class="col-3">
<div class="text-subtitle2 text-table">Weight</div>
<div class="text-subtitle2 text-table">
Weight
</div>
</div>
<div class="col-4">
<div class="text-subtitle2 text-table">Provider</div>
<div class="text-subtitle2 text-table">
Provider
</div>
</div>
</div>
</q-card-section>
<q-separator />
<div v-for="(service, index) in data.weighted.services" :key="index">
<div
v-for="(service, index) in data.weighted.services"
:key="index"
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col-7">
<q-chip
dense
class="app-chip app-chip-rule app-chip-overflow">
class="app-chip app-chip-rule app-chip-overflow"
>
{{ service.name }}
<q-tooltip>{{service.name}}</q-tooltip>
<q-tooltip>{{ service.name }}</q-tooltip>
</q-chip>
</div>
<div class="col-3">
@ -43,11 +60,15 @@
</template>
<script>
import { defineComponent } from 'vue'
export default {
export default defineComponent({
name: 'PanelWeightedServices',
props: ['data', 'dense'],
components: {},
props: {
data: Object,
dense: Boolean
},
computed: {
isDense () {
return this.dense !== undefined
@ -70,19 +91,19 @@ export default {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
return 'providers/nomad.svg'
}
return `providers/${name}.svg`
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -5,8 +5,12 @@
</template>
<script>
export default {
props: ['name'],
import { defineComponent } from 'vue'
export default defineComponent({
props: {
name: String
},
computed: {
getLogoPath () {
const name = this.name.toLowerCase()
@ -15,19 +19,19 @@ export default {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
return 'providers/nomad.svg'
}
return `providers/${name}.svg`
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,27 +1,34 @@
<template>
<div class="panel">
<div
v-if="isOpen"
class="panel-backdrop"
@click="close"
v-if="isOpen"
></div>
/>
<transition name="slide">
<div v-if="isOpen" class="panel-content">
<slot></slot>
<div
v-if="isOpen"
class="panel-content"
>
<slot />
</div>
</transition>
</div>
</template>
<script>
export default {
props: ['isOpen'],
<script>
import { defineComponent } from 'vue'
export default defineComponent({
props: {
isOpen: Boolean
},
methods: {
close () {
this.$emit('onClose')
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,13 +1,13 @@
<template>
<span
:style="{ height, width: computedWidth }"
v-bind:class="['SkeletonBox']"
:class="['SkeletonBox']"
/>
</template>
<script>
export default {
name: `SkeletonBox`,
name: 'SkeletonBox',
props: {
maxWidth: {
default: 100,
@ -18,7 +18,7 @@ export default {
type: Number
},
height: {
default: `2em`,
default: '2em',
type: String
},
width: {

View file

@ -2,16 +2,24 @@
<div>
<q-card-section>
<div class="row items-start no-wrap">
<div class="text-subtitle1">Sticky: Cookie </div>
<div class="text-subtitle1">
Sticky: Cookie
</div>
</div>
</q-card-section>
<q-card-section>
<div class="row items-start no-wrap">
<div class="col" v-if="sticky.cookie && sticky.cookie.name">
<div class="text-subtitle2">NAME</div>
<div
v-if="sticky.cookie && sticky.cookie.name"
class="col"
>
<div class="text-subtitle2">
NAME
</div>
<q-chip
dense
class="app-chip app-chip-entry-points">
class="app-chip app-chip-entry-points"
>
{{ sticky.cookie.name }}
</q-chip>
</div>
@ -20,13 +28,17 @@
<q-card-section>
<div class="row items-start no-wrap">
<div class="col">
<div class="text-subtitle2">SECURE</div>
<boolean-state :value="sticky.cookie.secure"/>
<div class="text-subtitle2">
SECURE
</div>
<boolean-state :value="sticky.cookie.secure" />
</div>
<div class="col">
<div class="text-subtitle2">HTTP Only</div>
<boolean-state :value="sticky.cookie.httpOnly"/>
<div class="text-subtitle2">
HTTP Only
</div>
<boolean-state :value="sticky.cookie.httpOnly" />
</div>
</div>
</q-card-section>
@ -34,16 +46,21 @@
</template>
<script>
import BooleanState from './BooleanState'
import { defineComponent } from 'vue'
import BooleanState from './BooleanState.vue'
export default {
export default defineComponent({
name: 'StickyServiceDetails',
components: {
BooleanState
},
props: ['sticky', 'dense']
}
props: {
sticky: Object,
dense: Boolean
}
})
</script>
<style scoped lang="scss">
@import "../../css/sass/variables";

View file

@ -1,14 +1,21 @@
<template>
<q-avatar text-color="dark">
<q-icon v-if="isTLS" name="eva-shield" />
<q-icon
v-if="isTLS"
name="eva-shield"
/>
</q-avatar>
</template>
<script>
export default {
import { defineComponent } from 'vue'
export default defineComponent({
name: 'TLSState',
props: ['isTLS']
}
props: {
isTLS: Boolean
}
})
</script>
<style scoped lang="scss">

View file

@ -1,23 +1,57 @@
<template>
<q-toolbar class="row no-wrap items-center">
<q-tabs align="left" inline-label indicator-color="transparent" stretch>
<q-route-tab :to="`/${protocol}/routers`" no-caps :label="`${protocolLabel} Routers`">
<q-badge v-if="routerTotal !== 0" align="middle" :label="routerTotal" class="q-ml-sm"/>
<q-tabs
align="left"
inline-label
indicator-color="transparent"
stretch
>
<q-route-tab
:to="`/${protocol}/routers`"
no-caps
:label="`${protocolLabel} Routers`"
>
<q-badge
v-if="routerTotal !== 0"
align="middle"
:label="routerTotal"
class="q-ml-sm"
/>
</q-route-tab>
<q-route-tab :to="`/${protocol}/services`" no-caps :label="`${protocolLabel} Services`">
<q-badge v-if="servicesTotal !== 0" align="middle" :label="servicesTotal" class="q-ml-sm"/>
<q-route-tab
:to="`/${protocol}/services`"
no-caps
:label="`${protocolLabel} Services`"
>
<q-badge
v-if="servicesTotal !== 0"
align="middle"
:label="servicesTotal"
class="q-ml-sm"
/>
</q-route-tab>
<q-route-tab v-if="protocol !== 'udp'" :to="`/${protocol}/middlewares`" no-caps :label="`${protocolLabel} Middlewares`">
<q-badge v-if="middlewaresTotal !== 0" align="middle" :label="middlewaresTotal" class="q-ml-sm"/>
<q-route-tab
v-if="protocol !== 'udp'"
:to="`/${protocol}/middlewares`"
no-caps
:label="`${protocolLabel} Middlewares`"
>
<q-badge
v-if="middlewaresTotal !== 0"
align="middle"
:label="middlewaresTotal"
class="q-ml-sm"
/>
</q-route-tab>
</q-tabs>
</q-toolbar>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { defineComponent } from 'vue'
import { useStore, mapActions, mapGetters } from 'vuex'
export default {
export default defineComponent({
name: 'ToolBar',
data () {
return {
@ -47,6 +81,16 @@ export default {
return (data && data.middlewares && data.middlewares.total) || 0
}
},
created () {
this.refreshAll()
this.intervalRefresh = setInterval(this.onGetAll, this.intervalRefreshTime)
},
beforeUnmount () {
const $store = useStore()
clearInterval(this.intervalRefresh)
$store.commit('core/getOverviewClear')
},
methods: {
...mapActions('core', { getOverview: 'getOverview' }),
refreshAll () {
@ -64,16 +108,8 @@ export default {
console.log('Error -> toolbar/overview', error)
})
}
},
created () {
this.refreshAll()
this.intervalRefresh = setInterval(this.onGetAll, this.intervalRefreshTime)
},
beforeDestroy () {
clearInterval(this.intervalRefresh)
this.$store.commit('core/getOverviewClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -17,8 +17,18 @@
]"
/>
<q-space />
<q-input v-model="getFilter" rounded dense outlined type="search" debounce="500" placeholder="Search" :bg-color="$q.dark.isActive ? undefined : 'white'" class="bar-search">
<template v-slot:append>
<q-input
v-model="getFilter"
rounded
dense
outlined
type="search"
debounce="500"
placeholder="Search"
:bg-color="$q.dark.isActive ? undefined : 'white'"
class="bar-search"
>
<template #append>
<q-icon name="eva-search-outline" />
</template>
</q-input>
@ -26,20 +36,14 @@
</template>
<script>
import { defineComponent } from 'vue'
import Helps from '../../_helpers/Helps'
export default {
export default defineComponent({
name: 'ToolBarTable',
props: ['status', 'filter'],
components: {
},
data () {
return {
}
},
mounted () {
this.routeToState(this.$route)
props: {
status: String,
filter: String
},
computed: {
getStatus: {
@ -66,6 +70,9 @@ export default {
this.routeToState(to)
}
},
mounted () {
this.routeToState(this.$route)
},
methods: {
routeToState (route) {
for (const query in route.query) {
@ -81,11 +88,8 @@ export default {
})
})
}
},
created () {
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,58 +1,98 @@
<template>
<q-card flat bordered>
<q-card
flat
bordered
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col">
<div class="text-h6 text-weight-bold">{{getName}}</div>
<div class="text-h6 text-weight-bold">
{{ getName }}
</div>
</div>
<div class="col-auto">
<q-btn :to="getUrl" color="accent" dense flat icon-right="eva-arrow-forward-outline" no-caps label="Explore" size="md" class="text-weight-bold"/>
<q-btn
:to="getUrl"
color="accent"
dense
flat
icon-right="eva-arrow-forward-outline"
no-caps
label="Explore"
size="md"
class="text-weight-bold"
/>
</div>
</div>
</q-card-section>
<q-card-section>
<div class="row items-center q-col-gutter-md">
<div class="col-12 col-sm-6">
<ChartDoughnut
:chartdata="getChartdata()"
:options="options"/>
<Doughnut
:data="getChartdata()"
:options="options"
/>
</div>
<div class="col-12 col-sm-6">
<q-list>
<q-item class="label-state">
<q-item-section avatar>
<avatar-state state="positive"/>
<avatar-state state="positive" />
</q-item-section>
<q-item-section class="label-state-text">
<q-item-label>Success</q-item-label>
<q-item-label caption lines="1">{{getSuccess(true)}}%</q-item-label>
<q-item-label
caption
lines="1"
>
{{ getSuccess(true) }}%
</q-item-label>
</q-item-section>
<q-item-section side class="label-state-side">
{{getSuccess()}}
<q-item-section
side
class="label-state-side"
>
{{ getSuccess() }}
</q-item-section>
</q-item>
<q-item class="label-state">
<q-item-section avatar>
<avatar-state state="warning"/>
<avatar-state state="warning" />
</q-item-section>
<q-item-section class="label-state-text">
<q-item-label>Warnings</q-item-label>
<q-item-label caption lines="1">{{getWarnings(true)}}%</q-item-label>
<q-item-label
caption
lines="1"
>
{{ getWarnings(true) }}%
</q-item-label>
</q-item-section>
<q-item-section side class="label-state-side">
{{getWarnings()}}
<q-item-section
side
class="label-state-side"
>
{{ getWarnings() }}
</q-item-section>
</q-item>
<q-item class="label-state">
<q-item-section avatar>
<avatar-state state="negative"/>
<avatar-state state="negative" />
</q-item-section>
<q-item-section class="label-state-text">
<q-item-label>Errors</q-item-label>
<q-item-label caption lines="1">{{getErrors(true)}}%</q-item-label>
<q-item-label
caption
lines="1"
>
{{ getErrors(true) }}%
</q-item-label>
</q-item-section>
<q-item-section side class="label-state-side">
{{getErrors()}}
<q-item-section
side
class="label-state-side"
>
{{ getErrors() }}
</q-item-section>
</q-item>
</q-list>
@ -63,23 +103,33 @@
</template>
<script>
import { defineComponent } from 'vue'
import Helps from '../../_helpers/Helps'
import ChartDoughnut from '../_commons/ChartDoughnut'
import AvatarState from '../_commons/AvatarState'
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'
import { Doughnut } from 'vue-chartjs'
import AvatarState from '../_commons/AvatarState.vue'
export default {
ChartJS.register(ArcElement, Tooltip, Legend)
export default defineComponent({
name: 'PanelChart',
props: ['name', 'data', 'type'],
components: {
ChartDoughnut,
Doughnut,
AvatarState
},
props: {
name: String,
data: Object,
type: String
},
data () {
return {
loading: true,
options: {
plugins: {
legend: {
display: false
}
},
animation: {
duration: 1000
@ -171,7 +221,7 @@ export default {
}
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,26 +1,40 @@
<template>
<q-card flat bordered v-bind:class="['panel-entry', {'panel-entry-detail':type === 'detail'}, {'panel-entry-focus':focus}, {'panel-entry-ex-size':exSize}]">
<q-card
flat
bordered
:class="['panel-entry', {'panel-entry-detail':type === 'detail'}, {'panel-entry-focus':focus}, {'panel-entry-ex-size':exSize}]"
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col">
<div class="text-subtitle2">{{name}}</div>
<div class="text-subtitle2">
{{ name }}
</div>
</div>
</div>
</q-card-section>
<q-card-section>
<div class="text-h3 text-center text-weight-bold ellipsis">
<span>{{address}}</span>
<q-tooltip>{{address}}</q-tooltip>
<span>{{ address }}</span>
<q-tooltip>{{ address }}</q-tooltip>
</div>
</q-card-section>
</q-card>
</template>
<script>
export default {
import { defineComponent } from 'vue'
export default defineComponent({
name: 'PanelEntry',
props: ['address', 'name', 'type', 'focus', 'exSize']
}
props: {
address: String,
name: String,
type: String,
focus: Boolean,
exSize: Number
}
})
</script>
<style scoped lang="scss">

View file

@ -1,17 +1,24 @@
<template>
<q-card flat bordered v-bind:class="['panel-feature']">
<q-card
flat
bordered
:class="['panel-feature']"
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col">
<div class="text-subtitle2">{{featureKey}}</div>
<div class="text-subtitle2">
{{ featureKey }}
</div>
</div>
</div>
</q-card-section>
<q-card-section>
<div class="text-h3 text-center text-weight-bold">
<q-chip
v-bind:class="['feature-chip', {'feature-chip-string':isString}, {'feature-chip-boolean':isBoolean}, {'feature-chip-boolean-true':isTrue}]">
{{getVal}}
:class="['feature-chip', {'feature-chip-string':isString}, {'feature-chip-boolean':isBoolean}, {'feature-chip-boolean-true':isTrue}]"
>
{{ getVal }}
</q-chip>
</div>
</q-card-section>

View file

@ -1,5 +1,8 @@
<template>
<q-card flat bordered>
<q-card
flat
bordered
>
<q-card-section>
<div class="row items-center no-wrap">
<div class="col text-center">
@ -11,16 +14,20 @@
</q-card-section>
<q-card-section>
<div class="text-h6 text-center text-weight-bold">
{{getName}}
{{ getName }}
</div>
</q-card-section>
</q-card>
</template>
<script>
export default {
import { defineComponent } from 'vue'
export default defineComponent({
name: 'PanelProvider',
props: ['name'],
props: {
name: String
},
computed: {
getName () {
return this.name
@ -32,19 +39,19 @@ export default {
return 'providers/plugin.svg'
}
if (name.startsWith('consul-')) {
return `providers/consul.svg`
return 'providers/consul.svg'
}
if (name.startsWith('consulcatalog-')) {
return `providers/consulcatalog.svg`
return 'providers/consulcatalog.svg'
}
if (name.startsWith('nomad-')) {
return `providers/nomad.svg`
return 'providers/nomad.svg'
}
return `providers/${name}.svg`
}
}
}
})
</script>
<style scoped lang="scss">

View file

@ -9,14 +9,14 @@
// to match your app's branding.
// Tip: Use the "Theme Builder" on Quasar's documentation website.
$primary = #06102a
$secondary = #2A2A2B
$accent = #1e54d5
$primary : #06102a;
$secondary : #2A2A2B;
$accent : #1e54d5;
$positive = #00a697
$negative = #ff0039
$info = #31CCEC
$warning = #db7d11
$positive : #00a697;
$negative : #ff0039;
$info : #31CCEC;
$warning : #db7d11;
$separator-color = rgba(0, 0, 0, .12)
$separator-dark-color = rgba(255, 255, 255, .28)
$separator-color : rgba(0, 0, 0, .12);
$separator-dark-color : rgba(255, 255, 255, .28);

View file

@ -1,6 +1,5 @@
<template>
<q-layout view="hHh lpR fFf">
<nav-bar>
<router-view name="NavBar" />
</nav-bar>
@ -8,12 +7,11 @@
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<script>
import NavBar from '../components/_commons/NavBar'
import NavBar from '../components/_commons/NavBar.vue'
export default {
name: 'Default',

View file

@ -1,12 +1,18 @@
<template>
<div class="fixed-center text-center q-pa-md">
<h1 class="q-ma-md"><strong>404</strong></h1>
<h5 class="q-ma-md">I'm sorry, nothing around here ...</h5>
<h1 class="q-ma-md">
<strong>404</strong>
</h1>
<h5 class="q-ma-md">
I'm sorry, nothing around here ...
</h5>
<q-btn
color="secondary"
style="width:200px;"
@click="$router.push('/')"
>Go back</q-btn>
>
Go back
</q-btn>
</div>
</template>

View file

@ -1,82 +1,121 @@
<template>
<page-default>
<section v-if="!loading" class="app-section">
<section
v-if="!loading"
class="app-section"
>
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-sm">
<div v-if="middlewareByName.item" class="row no-wrap items-center app-title">
<div class="app-title-label" style="font-size: 26px">{{ middlewareByName.item.name }}</div>
<div
v-if="middlewareByName.item"
class="row no-wrap items-center app-title"
>
<div
class="app-title-label"
style="font-size: 26px"
>
{{ middlewareByName.item.name }}
</div>
</div>
</div>
</section>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-sm q-pb-lg">
<div v-if="!loading" class="row items-start q-col-gutter-md">
<div v-if="middlewareByName.item" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="!loading"
class="row items-start q-col-gutter-md"
>
<div
v-if="middlewareByName.item"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-middlewares dense :data="[middlewareByName.item]" />
<panel-middlewares
dense
:data="[middlewareByName.item]"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="row items-start q-mt-xl">
<div
v-else
class="row items-start q-mt-xl"
>
<div class="col-12">
<p v-for="n in 4" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 4"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
</div>
</section>
<section v-if="!loading && allRouters.length" class="app-section">
<section
v-if="!loading && allRouters.length"
class="app-section"
>
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-xl">
<div class="row no-wrap items-center q-mb-lg app-title">
<div class="app-title-label">Used by Routers</div>
<div class="app-title-label">
Used by Routers
</div>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
<main-table
:data="allRouters"
v-bind="getTableProps({ type: `${protocol}-routers` })"
v-model:pagination="routersPagination"
:data="allRouters"
:request="()=>{}"
:loading="routersLoading"
:pagination.sync="routersPagination"
:filter="routersFilter"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PageDefault from '../../components/_commons/PageDefault'
import SkeletonBox from '../../components/_commons/SkeletonBox'
import PanelMiddlewares from '../../components/_commons/PanelMiddlewares'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import SkeletonBox from '../../components/_commons/SkeletonBox.vue'
import PanelMiddlewares from '../../components/_commons/PanelMiddlewares.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageMiddlewareDetail',
props: ['name', 'type'],
mixins: [GetTablePropsMixin],
components: {
PageDefault,
SkeletonBox,
PanelMiddlewares,
MainTable
},
mixins: [GetTablePropsMixin],
props: {
name: String,
type: String
},
data () {
return {
loading: true,
@ -110,6 +149,14 @@ export default {
return this[`${this.protocol}_getRouterByName`]
}
},
created () {
this.refreshAll()
},
beforeUnmount () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getMiddlewareByNameClear')
this.$store.commit('tcp/getMiddlewareByNameClear')
},
methods: {
...mapActions('http', { http_getMiddlewareByName: 'getMiddlewareByName', http_getRouterByName: 'getRouterByName' }),
...mapActions('tcp', { tcp_getMiddlewareByName: 'getMiddlewareByName', tcp_getRouterByName: 'getRouterByName' }),
@ -129,7 +176,7 @@ export default {
// Get routers
if (body.usedBy) {
for (const router in body.usedBy) {
if (body.usedBy.hasOwnProperty(router)) {
if (Object.getOwnPropertyDescriptor(body.usedBy, router)) {
this.getRouterByName(body.usedBy[router])
.then(body => {
if (body) {
@ -152,19 +199,8 @@ export default {
console.log('Error -> middleware/byName', error)
})
}
},
created () {
this.refreshAll()
},
mounted () {
},
beforeDestroy () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getMiddlewareByNameClear')
this.$store.commit('tcp/getMiddlewareByNameClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,90 +1,158 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div v-if="!loading" class="row items-start">
<div v-if="entryPoints.length" class="col-12 col-md-3 q-mb-lg path-block">
<div
v-if="!loading"
class="row items-start"
>
<div
v-if="entryPoints.length"
class="col-12 col-md-3 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-log-in-outline"></q-icon>
<div class="app-title-label">Entrypoints</div>
<q-icon name="eva-log-in-outline" />
<div class="app-title-label">
Entrypoints
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12 col-md-8">
<div class="row items-start q-col-gutter-md">
<div v-for="(entryPoint, index) in entryPoints" :key="index" class="col-12">
<panel-entry type="detail" exSize="true" :name="entryPoint.name" :address="entryPoint.address"/>
<div
v-for="(entryPoint, index) in entryPoints"
:key="index"
class="col-12"
>
<panel-entry
type="detail"
ex-size="true"
:name="entryPoint.name"
:address="entryPoint.address"
/>
</div>
</div>
</div>
<div class="col-12 col-md-4 xs-hide sm-hide">
<q-icon name="eva-arrow-forward-outline" class="arrow"></q-icon>
<q-icon
name="eva-arrow-forward-outline"
class="arrow"
/>
</div>
</div>
</div>
<div v-if="routerByName.item.name" class="col-12 col-md-3 q-mb-lg path-block">
<div
v-if="routerByName.item.name"
class="col-12 col-md-3 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-outline"></q-icon>
<div class="app-title-label">{{ routerType }}</div>
<q-icon name="eva-globe-outline" />
<div class="app-title-label">
{{ routerType }}
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12 col-md-8">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-entry focus="true" type="detail" name="router" :address="routerByName.item.name"/>
<panel-entry
focus="true"
type="detail"
name="router"
:address="routerByName.item.name"
/>
</div>
</div>
</div>
<div class="col-12 col-md-4 xs-hide sm-hide">
<q-icon name="eva-arrow-forward-outline" class="arrow"></q-icon>
<q-icon
name="eva-arrow-forward-outline"
class="arrow"
/>
</div>
</div>
</div>
<div v-if="hasMiddlewares" class="col-12 col-md-3 q-mb-lg path-block">
<div
v-if="hasMiddlewares"
class="col-12 col-md-3 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-layers"></q-icon>
<div class="app-title-label">{{ middlewareType }}</div>
<q-icon name="eva-layers" />
<div class="app-title-label">
{{ middlewareType }}
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12 col-md-8">
<div class="row items-start q-col-gutter-md">
<div v-for="(middleware, index) in middlewares" :key="index" class="col-12">
<panel-entry type="detail" name="Middleware" :address="middleware.type"/>
<div
v-for="(middleware, index) in middlewares"
:key="index"
class="col-12"
>
<panel-entry
type="detail"
name="Middleware"
:address="middleware.type"
/>
</div>
</div>
</div>
<div class="col-12 col-md-4 xs-hide sm-hide">
<q-icon name="eva-arrow-forward-outline" class="arrow"></q-icon>
<q-icon
name="eva-arrow-forward-outline"
class="arrow"
/>
</div>
</div>
</div>
<div v-if="routerByName.item.service"
<div
v-if="routerByName.item.service"
class="service col-12 col-md-3 q-mb-lg path-block"
@click="$router.push({ path: `/${protocol}/services/${getServiceId(routerByName.item)}`})">
@click="$router.push({ path: `/${protocol}/services/${getServiceId(routerByName.item)}`})"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-flash"></q-icon>
<div class="app-title-label">Service</div>
<q-icon name="eva-flash" />
<div class="app-title-label">
Service
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12 col-md-8">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-entry type="detail" name="Service" :address="routerByName.item.service"/>
<panel-entry
type="detail"
name="Service"
:address="routerByName.item.service"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="row items-start">
<div
v-else
class="row items-start"
>
<div class="col-12">
<p v-for="n in 4" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 4"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -93,82 +161,117 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div v-if="!loading" class="row items-start q-col-gutter-md">
<div v-if="routerByName.item" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="!loading"
class="row items-start q-col-gutter-md"
>
<div
v-if="routerByName.item"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-info"></q-icon>
<div class="app-title-label">Router Details</div>
<q-icon name="eva-info" />
<div class="app-title-label">
Router Details
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-router-details :data="routerByName.item" :protocol="protocol"/>
<panel-router-details
:data="routerByName.item"
:protocol="protocol"
/>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-4 q-mb-lg path-block" v-if="protocol !== 'udp'">
<div
v-if="protocol !== 'udp'"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-shield"></q-icon>
<div class="app-title-label">TLS</div>
<q-icon name="eva-shield" />
<div class="app-title-label">
TLS
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-t-l-s :data="routerByName.item.tls" :protocol="protocol"/>
<panel-t-l-s
:data="routerByName.item.tls"
:protocol="protocol"
/>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-4 q-mb-lg path-block" v-if="protocol !== 'udp'">
<div
v-if="protocol !== 'udp'"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-layers"></q-icon>
<div class="app-title-label">Middlewares</div>
<q-icon name="eva-layers" />
<div class="app-title-label">
Middlewares
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-middlewares :data="middlewares"/>
<panel-middlewares :data="middlewares" />
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="row items-start">
<div
v-else
class="row items-start"
>
<div class="col-12">
<p v-for="n in 4" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 4"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import PageDefault from '../../components/_commons/PageDefault'
import SkeletonBox from '../../components/_commons/SkeletonBox'
import PanelEntry from '../../components/dashboard/PanelEntry'
import PanelRouterDetails from '../../components/_commons/PanelRouterDetails'
import PanelTLS from '../../components/_commons/PanelTLS'
import PanelMiddlewares from '../../components/_commons/PanelMiddlewares'
import PageDefault from '../../components/_commons/PageDefault.vue'
import SkeletonBox from '../../components/_commons/SkeletonBox.vue'
import PanelEntry from '../../components/dashboard/PanelEntry.vue'
import PanelRouterDetails from '../../components/_commons/PanelRouterDetails.vue'
import PanelTLS from '../../components/_commons/PanelTLS.vue'
import PanelMiddlewares from '../../components/_commons/PanelMiddlewares.vue'
export default {
export default defineComponent({
name: 'PageRouterDetail',
props: ['name', 'type'],
components: {
PageDefault,
SkeletonBox,
@ -177,6 +280,10 @@ export default {
PanelTLS,
PanelMiddlewares
},
props: {
name: String,
type: String
},
data () {
return {
loading: true,
@ -214,6 +321,15 @@ export default {
return this[`${this.protocol}_getMiddlewareByName`]
}
},
created () {
this.refreshAll()
},
beforeUnmount () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getRouterByNameClear')
this.$store.commit('tcp/getRouterByNameClear')
this.$store.commit('udp/getRouterByNameClear')
},
methods: {
...mapActions('http', { http_getRouterByName: 'getRouterByName', http_getMiddlewareByName: 'getMiddlewareByName' }),
...mapActions('tcp', { tcp_getRouterByName: 'getRouterByName', tcp_getMiddlewareByName: 'getMiddlewareByName' }),
@ -235,7 +351,7 @@ export default {
// Get entryPoints
if (body.using) {
for (const entryPoint in body.using) {
if (body.using.hasOwnProperty(entryPoint)) {
if (Object.getOwnPropertyDescriptor(body.using, entryPoint)) {
this.getEntrypointsByName(body.using[entryPoint])
.then(body => {
if (body) {
@ -251,7 +367,7 @@ export default {
// Get middlewares
if (body.middlewares) {
for (const middleware in body.middlewares) {
if (body.middlewares.hasOwnProperty(middleware)) {
if (Object.getOwnPropertyDescriptor(body.middlewares, middleware)) {
this.getMiddlewareByName(body.middlewares[middleware])
.then(body => {
if (body) {
@ -281,20 +397,8 @@ export default {
return `${encodeURIComponent(data.service)}@${data.provider}`
}
},
created () {
this.refreshAll()
},
mounted () {
},
beforeDestroy () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getRouterByNameClear')
this.$store.commit('tcp/getRouterByNameClear')
this.$store.commit('udp/getRouterByNameClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,148 +1,217 @@
<template>
<page-default>
<section v-if="!loading" class="app-section">
<section
v-if="!loading"
class="app-section"
>
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-lg">
<div v-if="serviceByName.item" class="row no-wrap items-center app-title">
<div class="app-title-label" style="font-size: 26px">{{ serviceByName.item.name }}</div>
<div
v-if="serviceByName.item"
class="row no-wrap items-center app-title"
>
<div
class="app-title-label"
style="font-size: 26px"
>
{{ serviceByName.item.name }}
</div>
</div>
</div>
</section>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-lg">
<div v-if="!loading" class="row items-start q-col-gutter-md">
<div v-if="serviceByName.item" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="!loading"
class="row items-start q-col-gutter-md"
>
<div
v-if="serviceByName.item"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-info"></q-icon>
<div class="app-title-label">Service Details</div>
<q-icon name="eva-info" />
<div class="app-title-label">
Service Details
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-service-details dense :data="serviceByName.item" />
<panel-service-details
dense
:data="serviceByName.item"
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="serviceByName.item.loadBalancer && serviceByName.item.loadBalancer.healthCheck" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="serviceByName.item.loadBalancer && serviceByName.item.loadBalancer.healthCheck"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-shield"></q-icon>
<div class="app-title-label">Health Check</div>
<q-icon name="eva-shield" />
<div class="app-title-label">
Health Check
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-health-check dense :data="serviceByName.item.loadBalancer.healthCheck"/>
<panel-health-check
dense
:data="serviceByName.item.loadBalancer.healthCheck"
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="serviceByName.item.loadBalancer" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="serviceByName.item.loadBalancer"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-outline"></q-icon>
<div class="app-title-label">Servers</div>
<q-icon name="eva-globe-outline" />
<div class="app-title-label">
Servers
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-servers dense :data="serviceByName.item" :hasStatus="serviceByName.item.serverStatus"/>
<panel-servers
dense
:data="serviceByName.item"
:has-status="serviceByName.item.serverStatus"
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="serviceByName.item.weighted && serviceByName.item.weighted.services" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="serviceByName.item.weighted && serviceByName.item.weighted.services"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-outline"></q-icon>
<div class="app-title-label">Services</div>
<q-icon name="eva-globe-outline" />
<div class="app-title-label">
Services
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-weighted-services dense :data="serviceByName.item"/>
<panel-weighted-services
dense
:data="serviceByName.item"
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="serviceByName.item.mirroring && serviceByName.item.mirroring.mirrors" class="col-12 col-md-4 q-mb-lg path-block">
<div
v-if="serviceByName.item.mirroring && serviceByName.item.mirroring.mirrors"
class="col-12 col-md-4 q-mb-lg path-block"
>
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-outline"></q-icon>
<div class="app-title-label">Mirror Services</div>
<q-icon name="eva-globe-outline" />
<div class="app-title-label">
Mirror Services
</div>
</div>
<div class="row items-start q-col-gutter-lg">
<div class="col-12">
<div class="row items-start q-col-gutter-md">
<div class="col-12">
<panel-mirroring-services dense :data="serviceByName.item"/>
<panel-mirroring-services
dense
:data="serviceByName.item"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="row items-start q-mt-xl">
<div
v-else
class="row items-start q-mt-xl"
>
<div class="col-12">
<p v-for="n in 4" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 4"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
</div>
</section>
<section v-if="!loading && allRouters.length" class="app-section">
<section
v-if="!loading && allRouters.length"
class="app-section"
>
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-xl">
<div class="row no-wrap items-center q-mb-lg app-title">
<div class="app-title-label">Used by Routers</div>
<div class="app-title-label">
Used by Routers
</div>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
<main-table
:data="allRouters"
v-bind="getTableProps({ type: `${protocol}-routers` })"
v-model:pagination="routersPagination"
:data="allRouters"
:request="()=>{}"
:loading="routersLoading"
:pagination.sync="routersPagination"
:filter="routersFilter"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PageDefault from '../../components/_commons/PageDefault'
import SkeletonBox from '../../components/_commons/SkeletonBox'
import PanelServiceDetails from '../../components/_commons/PanelServiceDetails'
import PanelHealthCheck from '../../components/_commons/PanelHealthCheck'
import PanelServers from '../../components/_commons/PanelServers'
import MainTable from '../../components/_commons/MainTable'
import PanelWeightedServices from '../../components/_commons/PanelWeightedServices'
import PanelMirroringServices from '../../components/_commons/PanelMirroringServices'
import PageDefault from '../../components/_commons/PageDefault.vue'
import SkeletonBox from '../../components/_commons/SkeletonBox.vue'
import PanelServiceDetails from '../../components/_commons/PanelServiceDetails.vue'
import PanelHealthCheck from '../../components/_commons/PanelHealthCheck.vue'
import PanelServers from '../../components/_commons/PanelServers.vue'
import MainTable from '../../components/_commons/MainTable.vue'
import PanelWeightedServices from '../../components/_commons/PanelWeightedServices.vue'
import PanelMirroringServices from '../../components/_commons/PanelMirroringServices.vue'
export default {
export default defineComponent({
name: 'PageServiceDetail',
props: ['name', 'type'],
mixins: [GetTablePropsMixin],
components: {
PanelMirroringServices,
PanelWeightedServices,
@ -153,6 +222,11 @@ export default {
PanelServers,
MainTable
},
mixins: [GetTablePropsMixin],
props: {
name: String,
type: String
},
data () {
return {
loading: true,
@ -187,6 +261,15 @@ export default {
return this[`${this.protocol}_getRouterByName`]
}
},
created () {
this.refreshAll()
},
beforeUnmount () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getServiceByNameClear')
this.$store.commit('tcp/getServiceByNameClear')
this.$store.commit('udp/getServiceByNameClear')
},
methods: {
...mapActions('http', { http_getServiceByName: 'getServiceByName', http_getRouterByName: 'getRouterByName' }),
...mapActions('tcp', { tcp_getServiceByName: 'getServiceByName', tcp_getRouterByName: 'getRouterByName' }),
@ -207,7 +290,7 @@ export default {
// Get routers
if (body.usedBy) {
for (const router in body.usedBy) {
if (body.usedBy.hasOwnProperty(router)) {
if (Object.getOwnPropertyDescriptor(body.usedBy, router)) {
this.getRouterByName(body.usedBy[router])
.then(body => {
if (body) {
@ -230,20 +313,8 @@ export default {
console.log('Error -> service/byName', error)
})
}
},
created () {
this.refreshAll()
},
mounted () {
},
beforeDestroy () {
clearInterval(this.timeOutGetAll)
this.$store.commit('http/getServiceByNameClear')
this.$store.commit('tcp/getServiceByNameClear')
this.$store.commit('udp/getServiceByNameClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -3,20 +3,44 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-lg">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-log-in-outline"></q-icon>
<div class="app-title-label">Entrypoints</div>
<q-icon name="eva-log-in-outline" />
<div class="app-title-label">
Entrypoints
</div>
</div>
<div v-if="!loadingEntryGetAll" class="row items-center q-col-gutter-lg">
<div
v-for="(entryItems, index) in entryAll.items" :key="index"
class="col-12 col-sm-6 col-md-2">
<panel-entry :name="entryItems.name" :address="entryItems.address"/>
v-if="!loadingEntryGetAll"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(entryItems, index) in entryAll.items"
:key="index"
class="col-12 col-sm-6 col-md-2"
>
<panel-entry
:name="entryItems.name"
:address="entryItems.address"
/>
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-2">
<p v-for="n in 3" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 3"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -26,20 +50,45 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-lg">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-outline"></q-icon>
<div class="app-title-label">HTTP</div>
<q-icon name="eva-globe-outline" />
<div class="app-title-label">
HTTP
</div>
</div>
<div v-if="!loadingOverview" class="row items-center q-col-gutter-lg">
<div
v-for="(overviewHTTP, index) in allHTTP" :key="index"
class="col-12 col-sm-6 col-md-4">
<panel-chart :name="index" :data="overviewHTTP" type="http"/>
v-if="!loadingOverview"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(overviewHTTP, index) in allHTTP"
:key="index"
class="col-12 col-sm-6 col-md-4"
>
<panel-chart
:name="index"
:data="overviewHTTP"
type="http"
/>
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-4">
<p v-for="n in 6" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 6"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -49,20 +98,45 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-lg">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-3"></q-icon>
<div class="app-title-label">TCP</div>
<q-icon name="eva-globe-3" />
<div class="app-title-label">
TCP
</div>
</div>
<div v-if="!loadingOverview" class="row items-center q-col-gutter-lg">
<div
v-for="(overviewTCP, index) in allTCP" :key="index"
class="col-12 col-sm-6 col-md-4">
<panel-chart :name="index" :data="overviewTCP" type="tcp"/>
v-if="!loadingOverview"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(overviewTCP, index) in allTCP"
:key="index"
class="col-12 col-sm-6 col-md-4"
>
<panel-chart
:name="index"
:data="overviewTCP"
type="tcp"
/>
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-4">
<p v-for="n in 6" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 6"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -72,20 +146,45 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-lg">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-globe-3"></q-icon>
<div class="app-title-label">UDP</div>
<q-icon name="eva-globe-3" />
<div class="app-title-label">
UDP
</div>
</div>
<div v-if="!loadingOverview" class="row items-center q-col-gutter-lg">
<div
v-for="(overviewUDP, index) in allUDP" :key="index"
class="col-12 col-sm-6 col-md-4">
<panel-chart :name="index" :data="overviewUDP" type="udp"/>
v-if="!loadingOverview"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(overviewUDP, index) in allUDP"
:key="index"
class="col-12 col-sm-6 col-md-4"
>
<panel-chart
:name="index"
:data="overviewUDP"
type="udp"
/>
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-4">
<p v-for="n in 6" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 6"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -95,20 +194,44 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-lg">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-toggle-right"></q-icon>
<div class="app-title-label">Features</div>
<q-icon name="eva-toggle-right" />
<div class="app-title-label">
Features
</div>
</div>
<div v-if="!loadingOverview" class="row items-center q-col-gutter-lg">
<div
v-for="(overviewFeature, index) in allFeatures" :key="index"
class="col-12 col-sm-6 col-md-2">
<panel-feature :feature-key="index" :feature-val="overviewFeature"/>
v-if="!loadingOverview"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(overviewFeature, index) in allFeatures"
:key="index"
class="col-12 col-sm-6 col-md-2"
>
<panel-feature
:feature-key="index"
:feature-val="overviewFeature"
/>
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-2">
<p v-for="n in 3" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 3"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
@ -118,39 +241,60 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-lg q-pb-xl">
<div class="row no-wrap items-center q-mb-lg app-title">
<q-icon name="eva-cube"></q-icon>
<div class="app-title-label">Providers</div>
<q-icon name="eva-cube" />
<div class="app-title-label">
Providers
</div>
</div>
<div v-if="!loadingOverview" class="row items-center q-col-gutter-lg">
<div
v-for="(overviewProvider, index) in allProviders" :key="index"
class="col-12 col-sm-6 col-md-2">
<panel-provider :name="overviewProvider"/>
v-if="!loadingOverview"
class="row items-center q-col-gutter-lg"
>
<div
v-for="(overviewProvider, index) in allProviders"
:key="index"
class="col-12 col-sm-6 col-md-2"
>
<panel-provider :name="overviewProvider" />
</div>
</div>
<div v-else class="row items-center q-col-gutter-lg">
<div
v-else
class="row items-center q-col-gutter-lg"
>
<div class="col-12 col-sm-6 col-md-2">
<p v-for="n in 3" :key="n" class="flex">
<SkeletonBox :min-width="15" :max-width="15" style="margin-right: 2%"/> <SkeletonBox :min-width="50" :max-width="83"/>
<p
v-for="n in 3"
:key="n"
class="flex"
>
<SkeletonBox
:min-width="15"
:max-width="15"
style="margin-right: 2%"
/> <SkeletonBox
:min-width="50"
:max-width="83"
/>
</p>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import PageDefault from '../../components/_commons/PageDefault'
import SkeletonBox from '../../components/_commons/SkeletonBox'
import PanelEntry from '../../components/dashboard/PanelEntry'
import PanelChart from '../../components/dashboard/PanelChart'
import PanelFeature from '../../components/dashboard/PanelFeature'
import PanelProvider from '../../components/dashboard/PanelProvider'
import PageDefault from '../../components/_commons/PageDefault.vue'
import SkeletonBox from '../../components/_commons/SkeletonBox.vue'
import PanelEntry from '../../components/dashboard/PanelEntry.vue'
import PanelChart from '../../components/dashboard/PanelChart.vue'
import PanelFeature from '../../components/dashboard/PanelFeature.vue'
import PanelProvider from '../../components/dashboard/PanelProvider.vue'
export default {
export default defineComponent({
name: 'PageDashboardIndex',
components: {
PageDefault,
@ -189,6 +333,17 @@ export default {
return this.overviewAll.items.providers
}
},
created () {
this.fetchAll()
this.intervalRefresh = setInterval(this.fetchOverview, this.intervalRefreshTime)
},
beforeUnmount () {
clearInterval(this.intervalRefresh)
clearTimeout(this.timeOutEntryGetAll)
clearTimeout(this.timeOutOverviewAll)
this.$store.commit('entrypoints/getAllClear')
this.$store.commit('core/getOverviewClear')
},
methods: {
...mapActions('entrypoints', { entryGetAll: 'getAll' }),
...mapActions('core', { getOverview: 'getOverview' }),
@ -222,19 +377,8 @@ export default {
this.fetchEntries()
this.fetchOverview()
}
},
created () {
this.fetchAll()
this.intervalRefresh = setInterval(this.fetchOverview, this.intervalRefreshTime)
},
beforeDestroy () {
clearInterval(this.intervalRefresh)
clearTimeout(this.timeOutEntryGetAll)
clearTimeout(this.timeOutOverviewAll)
this.$store.commit('entrypoints/getAllClear')
this.$store.commit('core/getOverviewClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'http-middlewares' })"
:data="allMiddlewares.items"
:onLoadMore="handleLoadMore"
:endReached="allMiddlewares.endReached"
:on-load-more="handleLoadMore"
:end-reached="allMiddlewares.endReached"
:loading="allMiddlewares.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageHTTPMiddlewares',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('http', { allMiddlewares: 'allMiddlewares' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('http/getAllMiddlewaresClear')
},
methods: {
...mapActions('http', { getAllMiddlewares: 'getAllMiddlewares' }),
getAllMiddlewaresWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('http/getAllMiddlewaresClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'http-routers' })"
:data="allRouters.items"
:onLoadMore="handleLoadMore"
:endReached="allRouters.endReached"
:on-load-more="handleLoadMore"
:end-reached="allRouters.endReached"
:loading="allRouters.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageHTTPRouters',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('http', { allRouters: 'allRouters' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('http/getAllRoutersClear')
},
methods: {
...mapActions('http', { getAllRouters: 'getAllRouters' }),
getAllRoutersWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('http/getAllRoutersClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'http-services' })"
:data="allServices.items"
:onLoadMore="handleLoadMore"
:endReached="allServices.endReached"
:on-load-more="handleLoadMore"
:end-reached="allServices.endReached"
:loading="allServices.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageHTTPServices',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('http', { allServices: 'allServices' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('http/getAllServicesClear')
},
methods: {
...mapActions('http', { getAllServices: 'getAllServices' }),
getAllServicesWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('http/getAllServicesClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'tcp-middlewares' })"
:data="allMiddlewares.items"
:onLoadMore="handleLoadMore"
:endReached="allMiddlewares.endReached"
:on-load-more="handleLoadMore"
:end-reached="allMiddlewares.endReached"
:loading="allMiddlewares.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageTCPMiddlewares',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('tcp', { allMiddlewares: 'allMiddlewares' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('tcp/getAllMiddlewaresClear')
},
methods: {
...mapActions('tcp', { getAllMiddlewares: 'getAllMiddlewares' }),
getAllMiddlewaresWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('tcp/getAllMiddlewaresClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'tcp-routers' })"
:data="allRouters.items"
:onLoadMore="handleLoadMore"
:endReached="allRouters.endReached"
:on-load-more="handleLoadMore"
:end-reached="allRouters.endReached"
:loading="allRouters.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageTCPRouters',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('tcp', { allRouters: 'allRouters' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('tcp/getAllRoutersClear')
},
methods: {
...mapActions('tcp', { getAllRouters: 'getAllRouters' }),
getAllRoutersWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('tcp/getAllRoutersClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,15 +14,14 @@
ref="mainTable"
v-bind="getTableProps({ type: 'tcp-services' })"
:data="allServices.items"
:onLoadMore="handleLoadMore"
:endReached="allServices.endReached"
:on-load-more="handleLoadMore"
:end-reached="allServices.endReached"
:loading="allServices.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
@ -28,12 +29,17 @@
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
name: 'PageTCPServices',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +48,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +57,17 @@ export default {
computed: {
...mapGetters('tcp', { allServices: 'allServices' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('tcp/getAllServicesClear')
},
methods: {
...mapActions('tcp', { getAllServices: 'getAllServices' }),
getAllServicesWithParams (params) {
@ -75,17 +87,6 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('tcp/getAllServicesClear')
}
}
</script>

View file

@ -3,7 +3,10 @@
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -11,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'udp-routers' })"
:data="allRouters.items"
:onLoadMore="handleLoadMore"
:endReached="allRouters.endReached"
:on-load-more="handleLoadMore"
:end-reached="allRouters.endReached"
:loading="allRouters.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageUDPRouters',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -41,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -55,6 +58,17 @@ export default {
computed: {
...mapGetters('udp', { allRouters: 'allRouters' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('udp/getAllRoutersClear')
},
methods: {
...mapActions('udp', { getAllRouters: 'getAllRouters' }),
getAllRoutersWithParams (params) {
@ -74,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('udp/getAllRoutersClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,10 +1,12 @@
<template>
<page-default>
<section class="app-section">
<div class="app-section-wrap app-boxed app-boxed-xl q-pl-md q-pr-md q-pt-xl q-pb-xl">
<div class="row no-wrap items-center q-mb-lg">
<tool-bar-table :status.sync="status" :filter.sync="filter"/>
<tool-bar-table
v-model:status="status"
v-model:filter="filter"
/>
</div>
<div class="row items-center q-col-gutter-lg">
<div class="col-12">
@ -12,28 +14,33 @@
ref="mainTable"
v-bind="getTableProps({ type: 'udp-services' })"
:data="allServices.items"
:onLoadMore="handleLoadMore"
:endReached="allServices.endReached"
:on-load-more="handleLoadMore"
:end-reached="allServices.endReached"
:loading="allServices.loading"
/>
</div>
</div>
</div>
</section>
</page-default>
</template>
<script>
import { defineComponent } from 'vue'
import { mapActions, mapGetters } from 'vuex'
import GetTablePropsMixin from '../../_mixins/GetTableProps'
import PaginationMixin from '../../_mixins/Pagination'
import PageDefault from '../../components/_commons/PageDefault'
import ToolBarTable from '../../components/_commons/ToolBarTable'
import MainTable from '../../components/_commons/MainTable'
import PageDefault from '../../components/_commons/PageDefault.vue'
import ToolBarTable from '../../components/_commons/ToolBarTable.vue'
import MainTable from '../../components/_commons/MainTable.vue'
export default {
export default defineComponent({
name: 'PageUDPServices',
components: {
PageDefault,
ToolBarTable,
MainTable
},
mixins: [
GetTablePropsMixin,
PaginationMixin({
@ -42,11 +49,6 @@ export default {
pollingIntervalTime: 5000
})
],
components: {
PageDefault,
ToolBarTable,
MainTable
},
data () {
return {
filter: '',
@ -56,6 +58,17 @@ export default {
computed: {
...mapGetters('udp', { allServices: 'allServices' })
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeUnmount () {
this.$store.commit('udp/getAllServicesClear')
},
methods: {
...mapActions('udp', { getAllServices: 'getAllServices' }),
getAllServicesWithParams (params) {
@ -75,19 +88,8 @@ export default {
handleLoadMore ({ page = 1 } = {}) {
return this.fetchMore({ page })
}
},
watch: {
'status' () {
this.refreshAll()
},
'filter' () {
this.refreshAll()
}
},
beforeDestroy () {
this.$store.commit('udp/getAllServicesClear')
}
}
})
</script>
<style scoped lang="scss">

View file

@ -1,26 +1,18 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import { route } from 'quasar/wrappers'
import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router'
import routes from './routes'
Vue.use(VueRouter)
export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
/*
* If not building with SSR mode, you can
* directly export the Router instantiation
*/
export default function (/* { store, ssrContext } */) {
const Router = new VueRouter({
scrollBehavior: () => ({ x: 0, y: 0 }),
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
// Leave these as is and change from quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
history: createHistory(process.env.MODE === 'ssr' ? undefined : process.env.VUE_ROUTER_BASE)
})
return Router
}
})

View file

@ -1,3 +1,5 @@
import Error404 from 'pages/_commons/Error404.vue'
const LayoutDefault = () => import('layouts/Default.vue')
const routes = [
@ -249,8 +251,8 @@ const routes = [
// Always leave this as last one
if (process.env.MODE !== 'ssr') {
routes.push({
path: '*',
component: () => import('pages/_commons/Error404.vue'),
path: '/:catchAll(.*)*',
component: Error404,
meta: {
title: '404'
}

View file

@ -1,5 +1,5 @@
import Vue from 'vue'
import Vuex from 'vuex'
import { createStore } from 'vuex'
import { store } from 'quasar/wrappers'
import core from './core'
import entrypoints from './entrypoints'
@ -8,15 +8,13 @@ import tcp from './tcp'
import udp from './udp'
import platform from './platform'
Vue.use(Vuex)
/*
* If not building with SSR mode, you can
* directly export the Store instantiation
*/
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
export default store((/* { ssrContext } */) => {
const Store = createStore({
modules: {
core,
entrypoints,
@ -32,4 +30,4 @@ export default function (/* { ssrContext } */) {
})
return Store
}
})

File diff suppressed because it is too large Load diff