added oldLogin.vue to modify Login.vue
This commit is contained in:
36331
package-lock.json
generated
36331
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
120
package.json
120
package.json
@@ -1,60 +1,60 @@
|
||||
{
|
||||
"name": "lrc",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.17",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.8.1",
|
||||
"@fortawesome/vue-fontawesome": "^0.1.6",
|
||||
"@vue/cli": "^3.6.3",
|
||||
"axios": "^0.18.1",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.15",
|
||||
"i": "^0.3.6",
|
||||
"jquery": "^3.4.1",
|
||||
"js-cookie": "^2.2.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"npm": "^6.13.1",
|
||||
"npm-sass": "^2.3.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"sass": "^1.26.10",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"vee-validate": "^2.2.4",
|
||||
"vue": "^2.6.10",
|
||||
"vue-axios": "^2.1.4",
|
||||
"vue-class-component": "^6.0.0",
|
||||
"vue-cookies": "^1.5.13",
|
||||
"vue-flag-icon": "^1.0.6",
|
||||
"vue-i18n": "^8.9.0",
|
||||
"vue-moment": "^4.0.0",
|
||||
"vue-property-decorator": "^7.0.0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-socket.io-extended": "^4.0.1",
|
||||
"vue-spinner": "^1.0.3",
|
||||
"vue-sweetalert2": "^1.6.4",
|
||||
"vuejs-logger": "^1.5.3",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-persistedstate": "^2.5.4",
|
||||
"vuex-typex": "^3.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.0",
|
||||
"@types/mocha": "^5.2.4",
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
"@vue/cli-plugin-typescript": "^3.4.0",
|
||||
"@vue/cli-plugin-unit-mocha": "^3.4.0",
|
||||
"@vue/cli-service": "^3.6.0",
|
||||
"@vue/test-utils": "^1.0.0-beta.20",
|
||||
"bootstrap-sass": "^3.4.1",
|
||||
"chai": "^4.1.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"typescript": "^3.0.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "lrc",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.17",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.8.1",
|
||||
"@fortawesome/vue-fontawesome": "^0.1.6",
|
||||
"@vue/cli": "^3.6.3",
|
||||
"axios": "^0.18.1",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.15",
|
||||
"i": "^0.3.6",
|
||||
"jquery": "^3.5.1",
|
||||
"js-cookie": "^2.2.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"npm": "^6.14.7",
|
||||
"npm-sass": "^2.3.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"sass": "^1.26.10",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"vee-validate": "^2.2.4",
|
||||
"vue": "^2.6.10",
|
||||
"vue-axios": "^2.1.4",
|
||||
"vue-class-component": "^6.0.0",
|
||||
"vue-cookies": "^1.5.13",
|
||||
"vue-flag-icon": "^1.0.6",
|
||||
"vue-i18n": "^8.9.0",
|
||||
"vue-moment": "^4.1.0",
|
||||
"vue-property-decorator": "^7.0.0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-socket.io-extended": "^4.0.1",
|
||||
"vue-spinner": "^1.0.3",
|
||||
"vue-sweetalert2": "^1.6.4",
|
||||
"vuejs-logger": "^1.5.3",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-persistedstate": "^2.5.4",
|
||||
"vuex-typex": "^3.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.0",
|
||||
"@types/mocha": "^5.2.4",
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
"@vue/cli-plugin-typescript": "^3.4.0",
|
||||
"@vue/cli-plugin-unit-mocha": "^3.4.0",
|
||||
"@vue/cli-service": "^3.6.0",
|
||||
"@vue/test-utils": "^1.0.0-beta.20",
|
||||
"bootstrap-sass": "^3.4.1",
|
||||
"chai": "^4.1.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"typescript": "^3.0.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
}
|
||||
}
|
||||
|
||||
512
src/App.vue
512
src/App.vue
@@ -1,256 +1,256 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="bg">
|
||||
<img src="./assets/lens.jpg" alt="">
|
||||
</div>
|
||||
<sync-loader :loading="isLoading"></sync-loader>
|
||||
<b-alert
|
||||
:show="dismissCountDown"
|
||||
dismissible
|
||||
variant="danger"
|
||||
@dismissed="dismissCountDown=0"
|
||||
@dismiss-count-down="countDownChanged"
|
||||
>
|
||||
{{alertMessage}}
|
||||
<b-progress
|
||||
variant="error"
|
||||
:max="dismissSecs"
|
||||
:value="dismissCountDown"
|
||||
height="4px"
|
||||
></b-progress>
|
||||
</b-alert>
|
||||
<div id="nav">
|
||||
<b-navbar toggleable="lg" type="dark" variant="dark">
|
||||
<b-navbar-brand to="/">
|
||||
<img src="https://placekitten.com/g/30/30" class="d-inline-block align-top" alt="Kitten">
|
||||
LRC - <strong>L</strong>ecture <strong>R</strong>ecord <strong>C</strong>ontrol
|
||||
</b-navbar-brand>
|
||||
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav>
|
||||
<b-nav-item to="/about">About</b-nav-item>
|
||||
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'rooms'}">{{ $t('Rooms') }}</b-nav-item>
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'recorders'}">{{ $t('Recorders') }}</b-nav-item>
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'commands'}">{{ $t('Commands') }}</b-nav-item>
|
||||
<b-nav-item :to="{name: 'test'}">Test</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
|
||||
<!-- Right aligned nav items -->
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-form>
|
||||
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
|
||||
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
|
||||
</b-nav-form>
|
||||
|
||||
<b-nav-item-dropdown split split-to="admin" variant="outline-danger" :text="$t('admin')">
|
||||
<b-dropdown-item :to="{name: 'admin.user'}">{{ $t('user') }}</b-dropdown-item>
|
||||
<b-dropdown-item :to="{name: 'admin.group'}">{{ $t('group') }}</b-dropdown-item>
|
||||
<b-dropdown-item href="#">Something else here...</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
|
||||
<b-nav-item-dropdown text="Lang" right>
|
||||
<b-dropdown-item v-for="(lang, i) in langs"
|
||||
v-bind:key="lang"
|
||||
@click="$i18n.locale=lang">{{ lang }}
|
||||
</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
|
||||
<b-nav-item-dropdown v-if="authenticated" right>
|
||||
<!-- Using 'button-content' slot -->
|
||||
<template slot="button-content"><em>User</em></template>
|
||||
<b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item>
|
||||
<b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
<b-nav-item v-else to="/login">Login</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
|
||||
<span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span>
|
||||
<span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~"
|
||||
@click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span>
|
||||
<span v-if="refreshTokenValidity"> | ({{refreshTokenValidity}})
|
||||
<input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession">
|
||||
<label for="auto_renew_cb">{{$t('auto renew session')}}</label>
|
||||
</span>
|
||||
<span v-else>{{$t('Can\'t renew session – please login again!')}}</span>
|
||||
</div>
|
||||
<div id="content_frame">
|
||||
<router-view :style="main_style"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus, getRemainingJwtValiditySeconds} from '@/utils';
|
||||
import SyncLoader from 'vue-spinner/src/SyncLoader.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SyncLoader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
tokenValidity: -1,
|
||||
refreshFailed: false,
|
||||
refreshTokenValidity: -1,
|
||||
showAlert: true,
|
||||
alertMessage: 'NO MESSAGE PROVIDED',
|
||||
langs: ['de', 'en', 'es'],
|
||||
dismissSecs: 5,
|
||||
dismissCountDown: 0,
|
||||
autoRenewSession: true,
|
||||
main_style: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showErrorMessage(msg) {
|
||||
this.isLoading = false;
|
||||
this.dismissCountDown = this.dismissSecs;
|
||||
this.alertMessage = msg;
|
||||
},
|
||||
countDownChanged(dismissCountDown) {
|
||||
this.dismissCountDown = dismissCountDown;
|
||||
},
|
||||
|
||||
logout() {
|
||||
this.$store.dispatch('logout', {revokeRefreshToken: true});
|
||||
this.$router.push({name: 'home'});
|
||||
},
|
||||
refreshToken() {
|
||||
this.$store.dispatch('refreshToken');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('failedLoadingRecorders', (msg) => {
|
||||
this.showErrorMessage(msg);
|
||||
});
|
||||
EventBus.$on('failedLoadingRooms', (msg) => {
|
||||
this.showErrorMessage(msg);
|
||||
});
|
||||
EventBus.$on('failedRefreshingToken', (msg) => {
|
||||
this.refreshFailed = true;
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
window.setInterval(() => {
|
||||
// this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token));
|
||||
const tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token);
|
||||
|
||||
// this.tokenValidity = this.tokenValidity.format('mm:ss');
|
||||
const refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
|
||||
|
||||
// this.$log.debug(this.$store.state);
|
||||
if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) {
|
||||
this.$store.dispatch('refreshToken'); // renew access token
|
||||
}
|
||||
if (this.autoRenewSession && this.refreshFailed) {
|
||||
this.$store.dispatch('resetToken'); // delete all token info if refresh fails
|
||||
this.$router.push({name: 'login'});
|
||||
this.refreshFailed = false;
|
||||
}
|
||||
if (isNaN(tokenValidity)) {
|
||||
this.tokenValidity = false;
|
||||
} else {
|
||||
this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5);
|
||||
}
|
||||
if (isNaN(tokenValidity)) {
|
||||
this.refreshTokenValidity = false;
|
||||
} else {
|
||||
this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8);
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
computed: {
|
||||
authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
},
|
||||
profile() {
|
||||
return this.$store.state.profile;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../node_modules/bootstrap/scss/bootstrap.scss';
|
||||
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #385875;
|
||||
}
|
||||
|
||||
#bg {
|
||||
z-index: -100;
|
||||
position: fixed;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
}
|
||||
#bg img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
min-width: 50%;
|
||||
min-height: 50%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #275d37;
|
||||
}
|
||||
|
||||
#nav {
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: #7ea8d6;
|
||||
|
||||
&.router-link-exact-active {
|
||||
color: #42b983;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Absolute Center Spinner */
|
||||
.v-spinner {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
// height: 2em;
|
||||
// width: 2em;
|
||||
overflow: visible;
|
||||
margin: auto;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Transparent Overlay */
|
||||
.v-spinner:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="bg">
|
||||
<img src="./assets/lens.jpg" alt="">
|
||||
</div>
|
||||
<sync-loader :loading="isLoading"></sync-loader>
|
||||
<b-alert
|
||||
:show="dismissCountDown"
|
||||
dismissible
|
||||
variant="danger"
|
||||
@dismissed="dismissCountDown=0"
|
||||
@dismiss-count-down="countDownChanged"
|
||||
>
|
||||
{{alertMessage}}
|
||||
<b-progress
|
||||
variant="error"
|
||||
:max="dismissSecs"
|
||||
:value="dismissCountDown"
|
||||
height="4px"
|
||||
></b-progress>
|
||||
</b-alert>
|
||||
<div id="nav">
|
||||
<b-navbar toggleable="lg" type="dark" variant="dark">
|
||||
<b-navbar-brand to="/">
|
||||
<img src="https://placekitten.com/g/30/30" class="d-inline-block align-top" alt="Kitten">
|
||||
LRC - <strong>L</strong>ecture <strong>R</strong>ecord <strong>C</strong>ontrol
|
||||
</b-navbar-brand>
|
||||
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav>
|
||||
<b-nav-item to="/about">About</b-nav-item>
|
||||
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'rooms'}">{{ $t('Rooms') }}</b-nav-item>
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'recorders'}">{{ $t('Recorders') }}</b-nav-item>
|
||||
<b-nav-item v-if="authenticated" :to="{name: 'commands'}">{{ $t('Commands') }}</b-nav-item>
|
||||
<b-nav-item :to="{name: 'test'}">Test</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
|
||||
<!-- Right aligned nav items -->
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-form>
|
||||
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
|
||||
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
|
||||
</b-nav-form>
|
||||
|
||||
<b-nav-item-dropdown split split-to="admin" variant="outline-danger" :text="$t('admin')">
|
||||
<b-dropdown-item :to="{name: 'admin.user'}">{{ $t('user') }}</b-dropdown-item>
|
||||
<b-dropdown-item :to="{name: 'admin.group'}">{{ $t('group') }}</b-dropdown-item>
|
||||
<b-dropdown-item href="#">Something else here...</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
|
||||
<b-nav-item-dropdown text="Lang" right>
|
||||
<b-dropdown-item v-for="(lang, i) in langs"
|
||||
v-bind:key="lang"
|
||||
@click="$i18n.locale=lang">{{ lang }}
|
||||
</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
|
||||
<b-nav-item-dropdown v-if="authenticated" right>
|
||||
<!-- Using 'button-content' slot -->
|
||||
<template slot="button-content"><em>User</em></template>
|
||||
<b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item>
|
||||
<b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
<b-nav-item v-else to="/login">Login</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
|
||||
<span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span>
|
||||
<span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~"
|
||||
@click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span>
|
||||
<span v-if="refreshTokenValidity"> | ({{refreshTokenValidity}})
|
||||
<input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession">
|
||||
<label for="auto_renew_cb">{{$t('auto renew session')}}</label>
|
||||
</span>
|
||||
<span v-else>{{$t('Can\'t renew session – please login again!')}}</span>
|
||||
</div>
|
||||
<div id="content_frame">
|
||||
<router-view :style="main_style"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus, getRemainingJwtValiditySeconds} from '@/utils';
|
||||
import SyncLoader from 'vue-spinner/src/SyncLoader.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SyncLoader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
tokenValidity: -1,
|
||||
refreshFailed: false,
|
||||
refreshTokenValidity: -1,
|
||||
showAlert: true,
|
||||
alertMessage: 'NO MESSAGE PROVIDED',
|
||||
langs: ['de', 'en', 'es'],
|
||||
dismissSecs: 5,
|
||||
dismissCountDown: 0,
|
||||
autoRenewSession: true,
|
||||
main_style: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showErrorMessage(msg) {
|
||||
this.isLoading = false;
|
||||
this.dismissCountDown = this.dismissSecs;
|
||||
this.alertMessage = msg;
|
||||
},
|
||||
countDownChanged(dismissCountDown) {
|
||||
this.dismissCountDown = dismissCountDown;
|
||||
},
|
||||
|
||||
logout() {
|
||||
this.$store.dispatch('logout', {revokeRefreshToken: true});
|
||||
this.$router.push({name: 'home'});
|
||||
},
|
||||
refreshToken() {
|
||||
this.$store.dispatch('refreshToken');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
EventBus.$on('failedLoadingRecorders', (msg) => {
|
||||
this.showErrorMessage(msg);
|
||||
});
|
||||
EventBus.$on('failedLoadingRooms', (msg) => {
|
||||
this.showErrorMessage(msg);
|
||||
});
|
||||
EventBus.$on('failedRefreshingToken', (msg) => {
|
||||
this.refreshFailed = true;
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
window.setInterval(() => {
|
||||
// this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token));
|
||||
const tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token);
|
||||
|
||||
// this.tokenValidity = this.tokenValidity.format('mm:ss');
|
||||
const refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
|
||||
|
||||
// this.$log.debug(this.$store.state);
|
||||
if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) {
|
||||
this.$store.dispatch('refreshToken'); // renew access token
|
||||
}
|
||||
if (this.autoRenewSession && this.refreshFailed) {
|
||||
this.$store.dispatch('resetToken'); // delete all token info if refresh fails
|
||||
this.$router.push({name: 'login'});
|
||||
this.refreshFailed = false;
|
||||
}
|
||||
if (isNaN(tokenValidity)) {
|
||||
this.tokenValidity = false;
|
||||
} else {
|
||||
this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5);
|
||||
}
|
||||
if (isNaN(tokenValidity)) {
|
||||
this.refreshTokenValidity = false;
|
||||
} else {
|
||||
this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8);
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
computed: {
|
||||
authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
},
|
||||
profile() {
|
||||
return this.$store.state.profile;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../node_modules/bootstrap/scss/bootstrap.scss';
|
||||
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #385875;
|
||||
}
|
||||
|
||||
#bg {
|
||||
z-index: -100;
|
||||
position: fixed;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
}
|
||||
#bg img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
min-width: 50%;
|
||||
min-height: 50%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #275d37;
|
||||
}
|
||||
|
||||
#nav {
|
||||
padding: 0px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
color: #7ea8d6;
|
||||
|
||||
&.router-link-exact-active {
|
||||
color: #42b983;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Absolute Center Spinner */
|
||||
.v-spinner {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
// height: 2em;
|
||||
// width: 2em;
|
||||
overflow: visible;
|
||||
margin: auto;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Transparent Overlay */
|
||||
.v-spinner:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// groupRepository.ts
|
||||
|
||||
// @ts-ignore
|
||||
import Repository from './Repository';
|
||||
|
||||
const recorderStateResource = '/state/recorder';
|
||||
|
||||
|
||||
export default {
|
||||
getRecordersStates() {
|
||||
return Repository.get(`${recorderStateResource}`);
|
||||
},
|
||||
|
||||
getRecorderState(recorderId: number) {
|
||||
return Repository.get(`${recorderStateResource}/${recorderId}`);
|
||||
},
|
||||
};
|
||||
// groupRepository.ts
|
||||
|
||||
// @ts-ignore
|
||||
import Repository from './Repository';
|
||||
|
||||
const recorderStateResource = '/state/recorder';
|
||||
|
||||
|
||||
export default {
|
||||
getRecordersStates() {
|
||||
return Repository.get(`${recorderStateResource}`);
|
||||
},
|
||||
|
||||
getRecorderState(recorderId: number) {
|
||||
return Repository.get(`${recorderStateResource}/${recorderId}`);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
// groupRepository.ts
|
||||
|
||||
// @ts-ignore
|
||||
import Repository from './Repository';
|
||||
|
||||
const virtualCommandResource = '/virtual_command';
|
||||
|
||||
import {dictEmptyValToNull} from '@/utils';
|
||||
|
||||
export default {
|
||||
|
||||
getVirtualCommands() {
|
||||
return Repository.get(`${virtualCommandResource}`);
|
||||
},
|
||||
|
||||
getVirtualCommand(virtualCommandId: number) {
|
||||
return Repository.get(`${virtualCommandResource}/${virtualCommandId}`);
|
||||
},
|
||||
|
||||
deleteVirtualCommand(virtualCommandId: number) {
|
||||
return Repository.delete(`${virtualCommandResource}/${virtualCommandId}`);
|
||||
},
|
||||
|
||||
createVirtualCommand(virtualCommandData: any) {
|
||||
return Repository.post(`${virtualCommandResource}`, dictEmptyValToNull(virtualCommandData));
|
||||
},
|
||||
|
||||
updateVirtualCommand(virtualCommandId: number, virtualCommandData: any) {
|
||||
return Repository.put(`${virtualCommandResource}/${virtualCommandId}`,
|
||||
dictEmptyValToNull(virtualCommandData));
|
||||
},
|
||||
};
|
||||
// groupRepository.ts
|
||||
|
||||
// @ts-ignore
|
||||
import Repository from './Repository';
|
||||
|
||||
const virtualCommandResource = '/virtual_command';
|
||||
|
||||
import {dictEmptyValToNull} from '@/utils';
|
||||
|
||||
export default {
|
||||
|
||||
getVirtualCommands() {
|
||||
return Repository.get(`${virtualCommandResource}`);
|
||||
},
|
||||
|
||||
getVirtualCommand(virtualCommandId: number) {
|
||||
return Repository.get(`${virtualCommandResource}/${virtualCommandId}`);
|
||||
},
|
||||
|
||||
deleteVirtualCommand(virtualCommandId: number) {
|
||||
return Repository.delete(`${virtualCommandResource}/${virtualCommandId}`);
|
||||
},
|
||||
|
||||
createVirtualCommand(virtualCommandData: any) {
|
||||
return Repository.post(`${virtualCommandResource}`, dictEmptyValToNull(virtualCommandData));
|
||||
},
|
||||
|
||||
updateVirtualCommand(virtualCommandId: number, virtualCommandData: any) {
|
||||
return Repository.put(`${virtualCommandResource}/${virtualCommandId}`,
|
||||
dictEmptyValToNull(virtualCommandData));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,341 +1,341 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
|
||||
|
||||
<h1 class="title">{{ $t('Manage Commands') }}</h1>
|
||||
<p class="lead">
|
||||
{{ $t('List, create and delete') }} <strong>{{ $t('commands') }}</strong>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
<b-tabs v-model="tabIndex" card>
|
||||
<b-tab title="Command list" active>
|
||||
<template slot="title">
|
||||
<font-awesome-icon icon="list"/> <font-awesome-icon icon="cogs"/>
|
||||
<strong>command</strong> <i>list</i>
|
||||
</template>
|
||||
<p>{{ $t('There are')}} {{commands.length}} {{ $t('recorder commands defined')}}:</p>
|
||||
<b-card-group deck>
|
||||
<b-card class="mb-2" style="max-width: 30rem; min-width:20rem;" v-for="(command) in commands"
|
||||
:header="command.name + ' (' +command.recorder_model.name+ ')'" v-bind:key="command.id">
|
||||
<b-card-text>
|
||||
<h5 class="card-title">{{ $t('name') }}:
|
||||
<span>{{command.name}} </span>
|
||||
</h5>
|
||||
|
||||
<p class="card-text">
|
||||
<small><strong>{{ $t('alternative_name') }}:</strong>
|
||||
<span v-if="!formEditField[command.id+'_alternative_name']">{{command.alternative_name}}
|
||||
<a class="float-right badge badge-pill badge-primary">
|
||||
<font-awesome-icon
|
||||
@click="initRecCommandUpdate(command, 'alternative_name')"
|
||||
icon="pencil-alt"/>
|
||||
</a>
|
||||
</span>
|
||||
<b-input-group v-else>
|
||||
<b-form-input :id="command.id+'_alternative_name'" name="alternative_name"
|
||||
v-model="updateValues[command.id+'_alternative_name']"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('alternative_name'), 'is-invalid': errors.has('alternative_name')}"
|
||||
class="form-control" type="text"
|
||||
:placeholder="'Alternative name ('+command.alternative_name +')'"
|
||||
required></b-form-input>
|
||||
<b-input-group-append>
|
||||
<b-button :disabled="errors.has('alternative_name')"
|
||||
@click="updateRecCommand(command.id, 'alternative_name')"
|
||||
variant="outline-success">
|
||||
<font-awesome-icon icon="check"></font-awesome-icon>
|
||||
</b-button>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</small>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<small><strong>{{ $t('description') }}:</strong>
|
||||
<span v-if="!formEditField[command.id+'_description']">{{command.description}}
|
||||
<a class="float-right badge badge-pill badge-info">
|
||||
<font-awesome-icon
|
||||
@click="initRecCommandUpdate(command, 'description')"
|
||||
icon="pencil-alt"/>
|
||||
</a>
|
||||
</span>
|
||||
<textarea class="textarea form-control" v-else name="comment"
|
||||
v-model="updateValues[command.id+'_description']"
|
||||
:placeholder="'Comment ('+command.description +')'"
|
||||
@blur="updateRecCommand(command.id, 'description')"></textarea>
|
||||
</small>
|
||||
</p>
|
||||
<hr/>
|
||||
|
||||
<div v-if="command.recorder_model">
|
||||
<p class="card-text"><strong>{{ $t('Recorder') }} {{ $t('model') }}:</strong> {{command.recorder_model.name}} </p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="card-text"><strong>{{ $t('Recorder') }}:</strong> {{
|
||||
$t('no_recorder_model_defined')}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</b-card-text>
|
||||
<div slot="footer">
|
||||
<small class="text-muted">
|
||||
<p>{{ $t('created')}}: {{command.created_at | moment("dddd, MMMM Do YYYY")}}
|
||||
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
</b-card>
|
||||
</b-card-group>
|
||||
</b-tab>
|
||||
|
||||
<b-tab title="Create command">
|
||||
<template slot="title">
|
||||
<font-awesome-icon icon="plus"/>
|
||||
<i>{{$t('create')}}</i> <font-awesome-icon icon="cogs"/>
|
||||
<strong>{{$t('virtual')}} {{$t('command')}}</strong>
|
||||
</template>
|
||||
<b-card-text>
|
||||
<p>{{ $t('Create a new command')}}:</p>
|
||||
<!-- form starts here -->
|
||||
<form v-on:submit.prevent="savecommand()">
|
||||
<section class="form">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label required col-sm-2 col-form-label">{{ $t('name') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="name"
|
||||
v-model="form.name"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('name'), 'is-invalid': errors.has('name')}"
|
||||
class="form-control" type="text" placeholder="command name" required>
|
||||
</div>
|
||||
<p class="col-sm-4" v-show="errors.has('name')">
|
||||
{{ errors.first('name') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('alternate_name') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="alternate_name"
|
||||
v-model="form.alternate_name"
|
||||
class="form-control" type="text" placeholder="Alternate name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label required col-sm-2 col-form-label">{{ $t('number') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="number"
|
||||
v-model="form.number"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('number'), 'is-invalid': errors.has('number')}"
|
||||
class="form-control" type="text" placeholder="command number" required>
|
||||
</div>
|
||||
<p class="col-sm-4" v-show="errors.has('number')">
|
||||
{{ errors.first('number') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('comment') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<textarea class="textarea form-control" placeholder="Comments, remarks, notes, etc."
|
||||
v-model="form.comment"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('recorder') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-control" v-model="form.recorder_id">
|
||||
<option value="">No recorder selected</option>
|
||||
<option v-for="recorder in recorders" v-bind:value="recorder.id">
|
||||
{{ recorder.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button
|
||||
v-bind:disabled="errors.any()"
|
||||
type="submit"
|
||||
class="btn btn-primary">
|
||||
Create command
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</form>
|
||||
</b-card-text>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
|
||||
<!--
|
||||
<div class="column">
|
||||
<section class="section" id="results">
|
||||
<div class="box">
|
||||
<ul>
|
||||
<li v-for="(item, k) in form">
|
||||
<strong>{{ k }}:</strong> {{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<section class="section">
|
||||
{{recorders}}
|
||||
</section>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus} from '@/utils';
|
||||
import PulseLoader from 'vue-spinner/src/PulseLoader.vue';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const recorderRepository = getRepository('recorder');
|
||||
const commandRepository = getRepository('command');
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PulseLoader,
|
||||
},
|
||||
props: [],
|
||||
data() {
|
||||
return {
|
||||
tabIndex: 0,
|
||||
updateValues: {},
|
||||
formEditField: {},
|
||||
show_assigned_recorders: false,
|
||||
form: {
|
||||
name: null,
|
||||
alternate_name: null,
|
||||
number: null,
|
||||
comment: null,
|
||||
recorder_id: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
saveCommand() {
|
||||
this.$parent.$data.isLoading = true;
|
||||
commandRepository.createCommand(this.form)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.tabIndex = 0;
|
||||
});
|
||||
}).catch((msg) => {
|
||||
this.showErrorMessage('Could not safe command!');
|
||||
this.$log.warn(msg);
|
||||
});
|
||||
},
|
||||
initCommandUpdate(command, fieldName) {
|
||||
this.$set(this.formEditField, command.id + '_' + fieldName, true);
|
||||
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
|
||||
},
|
||||
updateCommand(id, fieldName) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
const data = {};
|
||||
data[fieldName] = this.updateValues[id + '_' + fieldName];
|
||||
commandRepository.updateCommand(id, data)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.formEditField[id + '_' + fieldName] = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
deleteCommand(id) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
commandRepository.deleteCommand(id)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
initRecCommandUpdate(command, fieldName) {
|
||||
this.$set(this.formEditField, command.id + '_' + fieldName, true);
|
||||
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
|
||||
},
|
||||
updateRecCommand(id, fieldName) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
const data = {};
|
||||
data[fieldName] = this.updateValues[id + '_' + fieldName];
|
||||
recorderRepository.updateRecorderCommand(id, data)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadRecorderCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.formEditField[id + '_' + fieldName] = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
showErrorMessage(msg) {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.$parent.$data.showAlert = true;
|
||||
this.$parent.$data.alertMessage = msg;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$parent.$data.isLoading = true;
|
||||
this.$parent.$data.showAlert = false;
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadRecorders')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
return {
|
||||
recorders: [
|
||||
{value: 8, text: 'SMP 351 AudiMax'},
|
||||
{value: 13, text: 'SMP 351 HMU'},
|
||||
],
|
||||
};
|
||||
},
|
||||
commands() {
|
||||
return this.$store.state.recorderCommands;
|
||||
},
|
||||
recorders() {
|
||||
return this.$store.state.recorders;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.comment {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.required:after {
|
||||
content: " *";
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
|
||||
|
||||
<h1 class="title">{{ $t('Manage Commands') }}</h1>
|
||||
<p class="lead">
|
||||
{{ $t('List, create and delete') }} <strong>{{ $t('commands') }}</strong>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
<b-tabs v-model="tabIndex" card>
|
||||
<b-tab title="Command list" active>
|
||||
<template slot="title">
|
||||
<font-awesome-icon icon="list"/> <font-awesome-icon icon="cogs"/>
|
||||
<strong>command</strong> <i>list</i>
|
||||
</template>
|
||||
<p>{{ $t('There are')}} {{commands.length}} {{ $t('recorder commands defined')}}:</p>
|
||||
<b-card-group deck>
|
||||
<b-card class="mb-2" style="max-width: 30rem; min-width:20rem;" v-for="(command) in commands"
|
||||
:header="command.name + ' (' +command.recorder_model.name+ ')'" v-bind:key="command.id">
|
||||
<b-card-text>
|
||||
<h5 class="card-title">{{ $t('name') }}:
|
||||
<span>{{command.name}} </span>
|
||||
</h5>
|
||||
|
||||
<p class="card-text">
|
||||
<small><strong>{{ $t('alternative_name') }}:</strong>
|
||||
<span v-if="!formEditField[command.id+'_alternative_name']">{{command.alternative_name}}
|
||||
<a class="float-right badge badge-pill badge-primary">
|
||||
<font-awesome-icon
|
||||
@click="initRecCommandUpdate(command, 'alternative_name')"
|
||||
icon="pencil-alt"/>
|
||||
</a>
|
||||
</span>
|
||||
<b-input-group v-else>
|
||||
<b-form-input :id="command.id+'_alternative_name'" name="alternative_name"
|
||||
v-model="updateValues[command.id+'_alternative_name']"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('alternative_name'), 'is-invalid': errors.has('alternative_name')}"
|
||||
class="form-control" type="text"
|
||||
:placeholder="'Alternative name ('+command.alternative_name +')'"
|
||||
required></b-form-input>
|
||||
<b-input-group-append>
|
||||
<b-button :disabled="errors.has('alternative_name')"
|
||||
@click="updateRecCommand(command.id, 'alternative_name')"
|
||||
variant="outline-success">
|
||||
<font-awesome-icon icon="check"></font-awesome-icon>
|
||||
</b-button>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</small>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<small><strong>{{ $t('description') }}:</strong>
|
||||
<span v-if="!formEditField[command.id+'_description']">{{command.description}}
|
||||
<a class="float-right badge badge-pill badge-info">
|
||||
<font-awesome-icon
|
||||
@click="initRecCommandUpdate(command, 'description')"
|
||||
icon="pencil-alt"/>
|
||||
</a>
|
||||
</span>
|
||||
<textarea class="textarea form-control" v-else name="comment"
|
||||
v-model="updateValues[command.id+'_description']"
|
||||
:placeholder="'Comment ('+command.description +')'"
|
||||
@blur="updateRecCommand(command.id, 'description')"></textarea>
|
||||
</small>
|
||||
</p>
|
||||
<hr/>
|
||||
|
||||
<div v-if="command.recorder_model">
|
||||
<p class="card-text"><strong>{{ $t('Recorder') }} {{ $t('model') }}:</strong> {{command.recorder_model.name}} </p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="card-text"><strong>{{ $t('Recorder') }}:</strong> {{
|
||||
$t('no_recorder_model_defined')}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</b-card-text>
|
||||
<div slot="footer">
|
||||
<small class="text-muted">
|
||||
<p>{{ $t('created')}}: {{command.created_at | moment("dddd, MMMM Do YYYY")}}
|
||||
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
</b-card>
|
||||
</b-card-group>
|
||||
</b-tab>
|
||||
|
||||
<b-tab title="Create command">
|
||||
<template slot="title">
|
||||
<font-awesome-icon icon="plus"/>
|
||||
<i>{{$t('create')}}</i> <font-awesome-icon icon="cogs"/>
|
||||
<strong>{{$t('virtual')}} {{$t('command')}}</strong>
|
||||
</template>
|
||||
<b-card-text>
|
||||
<p>{{ $t('Create a new command')}}:</p>
|
||||
<!-- form starts here -->
|
||||
<form v-on:submit.prevent="savecommand()">
|
||||
<section class="form">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label required col-sm-2 col-form-label">{{ $t('name') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="name"
|
||||
v-model="form.name"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('name'), 'is-invalid': errors.has('name')}"
|
||||
class="form-control" type="text" placeholder="command name" required>
|
||||
</div>
|
||||
<p class="col-sm-4" v-show="errors.has('name')">
|
||||
{{ errors.first('name') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('alternate_name') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="alternate_name"
|
||||
v-model="form.alternate_name"
|
||||
class="form-control" type="text" placeholder="Alternate name">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label required col-sm-2 col-form-label">{{ $t('number') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<input name="number"
|
||||
v-model="form.number"
|
||||
v-validate="'required|min:3'"
|
||||
v-bind:class="{'is-danger': errors.has('number'), 'is-invalid': errors.has('number')}"
|
||||
class="form-control" type="text" placeholder="command number" required>
|
||||
</div>
|
||||
<p class="col-sm-4" v-show="errors.has('number')">
|
||||
{{ errors.first('number') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('comment') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<textarea class="textarea form-control" placeholder="Comments, remarks, notes, etc."
|
||||
v-model="form.comment"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="label col-sm-2 col-form-label">{{ $t('recorder') }}</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-control" v-model="form.recorder_id">
|
||||
<option value="">No recorder selected</option>
|
||||
<option v-for="recorder in recorders" v-bind:value="recorder.id">
|
||||
{{ recorder.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button
|
||||
v-bind:disabled="errors.any()"
|
||||
type="submit"
|
||||
class="btn btn-primary">
|
||||
Create command
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</form>
|
||||
</b-card-text>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
|
||||
<!--
|
||||
<div class="column">
|
||||
<section class="section" id="results">
|
||||
<div class="box">
|
||||
<ul>
|
||||
<li v-for="(item, k) in form">
|
||||
<strong>{{ k }}:</strong> {{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<section class="section">
|
||||
{{recorders}}
|
||||
</section>
|
||||
</div>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus} from '@/utils';
|
||||
import PulseLoader from 'vue-spinner/src/PulseLoader.vue';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const recorderRepository = getRepository('recorder');
|
||||
const commandRepository = getRepository('command');
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PulseLoader,
|
||||
},
|
||||
props: [],
|
||||
data() {
|
||||
return {
|
||||
tabIndex: 0,
|
||||
updateValues: {},
|
||||
formEditField: {},
|
||||
show_assigned_recorders: false,
|
||||
form: {
|
||||
name: null,
|
||||
alternate_name: null,
|
||||
number: null,
|
||||
comment: null,
|
||||
recorder_id: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
saveCommand() {
|
||||
this.$parent.$data.isLoading = true;
|
||||
commandRepository.createCommand(this.form)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.tabIndex = 0;
|
||||
});
|
||||
}).catch((msg) => {
|
||||
this.showErrorMessage('Could not safe command!');
|
||||
this.$log.warn(msg);
|
||||
});
|
||||
},
|
||||
initCommandUpdate(command, fieldName) {
|
||||
this.$set(this.formEditField, command.id + '_' + fieldName, true);
|
||||
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
|
||||
},
|
||||
updateCommand(id, fieldName) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
const data = {};
|
||||
data[fieldName] = this.updateValues[id + '_' + fieldName];
|
||||
commandRepository.updateCommand(id, data)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.formEditField[id + '_' + fieldName] = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
deleteCommand(id) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
commandRepository.deleteCommand(id)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
initRecCommandUpdate(command, fieldName) {
|
||||
this.$set(this.formEditField, command.id + '_' + fieldName, true);
|
||||
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
|
||||
},
|
||||
updateRecCommand(id, fieldName) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
const data = {};
|
||||
data[fieldName] = this.updateValues[id + '_' + fieldName];
|
||||
recorderRepository.updateRecorderCommand(id, data)
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadRecorderCommands')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.formEditField[id + '_' + fieldName] = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
showErrorMessage(msg) {
|
||||
this.$parent.$data.isLoading = false;
|
||||
this.$parent.$data.showAlert = true;
|
||||
this.$parent.$data.alertMessage = msg;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$parent.$data.isLoading = true;
|
||||
this.$parent.$data.showAlert = false;
|
||||
this.$store.dispatch('loadCommands')
|
||||
.then(() => {
|
||||
this.$store.dispatch('loadRecorders')
|
||||
.then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
return {
|
||||
recorders: [
|
||||
{value: 8, text: 'SMP 351 AudiMax'},
|
||||
{value: 13, text: 'SMP 351 HMU'},
|
||||
],
|
||||
};
|
||||
},
|
||||
commands() {
|
||||
return this.$store.state.recorderCommands;
|
||||
},
|
||||
recorders() {
|
||||
return this.$store.state.recorders;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.comment {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.required:after {
|
||||
content: " *";
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,71 +1,71 @@
|
||||
<template>
|
||||
<div v-if="authenticated && faulty_recorders_states.length > 0">
|
||||
<h2>Recorders with detected problems:</h2>
|
||||
<b-card-group deck>
|
||||
<b-card bg-variant="danger" text-variant="white" v-for="r_s in faulty_recorders_states" class="mb-2" style="max-width: 30rem; min-width:20rem;"
|
||||
:header="r_s.name"
|
||||
v-bind:key="r_s.id">
|
||||
<b-card-text>
|
||||
<h5 class="card-title">
|
||||
<strong>{{$t('Problem')}}:</strong> {{r_s.msg}}
|
||||
</h5>
|
||||
<b-button :to="{name: 'recorder', params: {recorder_id: r_s.id}}" variant="primary">Go to recorder
|
||||
</b-button>
|
||||
</b-card-text>
|
||||
<div slot="footer">
|
||||
<small>
|
||||
<p>
|
||||
<span v-if="r_s.time_stamp"><strong>{{$t('time stamp')}}:</strong> {{r_s.time_stamp}}</span>
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
</b-card>
|
||||
</b-card-group>
|
||||
<hr/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>You must be signed in in order to see recorders!</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component, Prop, Vue} from 'vue-property-decorator';
|
||||
import StateRepository from '@/api/stateRepository';
|
||||
import VirtualCommandRepository from "@/api/virtualCommandRepository";
|
||||
|
||||
@Component
|
||||
export default class ErroneousRecorders extends Vue {
|
||||
|
||||
get authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
}
|
||||
|
||||
get faulty_recorders_states() {
|
||||
return this.$store.state.recorderStates.filter((s: any) => {
|
||||
return !s.state_ok
|
||||
});
|
||||
}
|
||||
|
||||
private mounted() {
|
||||
this.$store.dispatch('loadRecorderStates');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div v-if="authenticated && faulty_recorders_states.length > 0">
|
||||
<h2>Recorders with detected problems:</h2>
|
||||
<b-card-group deck>
|
||||
<b-card bg-variant="danger" text-variant="white" v-for="r_s in faulty_recorders_states" class="mb-2" style="max-width: 30rem; min-width:20rem;"
|
||||
:header="r_s.name"
|
||||
v-bind:key="r_s.id">
|
||||
<b-card-text>
|
||||
<h5 class="card-title">
|
||||
<strong>{{$t('Problem')}}:</strong> {{r_s.msg}}
|
||||
</h5>
|
||||
<b-button :to="{name: 'recorder', params: {recorder_id: r_s.id}}" variant="primary">Go to recorder
|
||||
</b-button>
|
||||
</b-card-text>
|
||||
<div slot="footer">
|
||||
<small>
|
||||
<p>
|
||||
<span v-if="r_s.time_stamp"><strong>{{$t('time stamp')}}:</strong> {{r_s.time_stamp}}</span>
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
</b-card>
|
||||
</b-card-group>
|
||||
<hr/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>You must be signed in in order to see recorders!</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Component, Prop, Vue} from 'vue-property-decorator';
|
||||
import StateRepository from '@/api/stateRepository';
|
||||
import VirtualCommandRepository from "@/api/virtualCommandRepository";
|
||||
|
||||
@Component
|
||||
export default class ErroneousRecorders extends Vue {
|
||||
|
||||
get authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
}
|
||||
|
||||
get faulty_recorders_states() {
|
||||
return this.$store.state.recorderStates.filter((s: any) => {
|
||||
return !s.state_ok
|
||||
});
|
||||
}
|
||||
|
||||
private mounted() {
|
||||
this.$store.dispatch('loadRecorderStates');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -9,23 +9,18 @@
|
||||
<p class="subtitle error-msg">{{ errorMsg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="(provider, index) in loginProviders" v-bind:id="index">
|
||||
<a :href="provider.url">{{ index }} ({{provider.type}})</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Users</h3>
|
||||
<ul>
|
||||
<li v-for="(user) in users">
|
||||
<a href="#">({{user.id}}) {{user.first_name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button v-on:click="oidc_login">Login via OIDC</button>
|
||||
<a href="http://localhost:5443/api/auth/oidc?redirect_url=/login">OIDC with redirect</a>
|
||||
</section>
|
||||
<section class="section">
|
||||
|
||||
<div class="container">
|
||||
<ul>
|
||||
<li v-for="(provider, index) in loginProviders" v-bind:id="index">
|
||||
<a :href="provider.url">{{ index }} ({{provider.type}})</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<button v-on:click="oidc_login">Login via OIDC</button>
|
||||
<a href="http://localhost:5443/api/auth/oidc?redirect_url=/login">OIDC with redirect</a>
|
||||
<div class="field">
|
||||
<label class="label is-large" for="email">Email:</label>
|
||||
<div class="control">
|
||||
|
||||
153
src/components/OldLogin.vue
Normal file
153
src/components/OldLogin.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<!-- components/Login.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="!authenticated">
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h2 class="title">Login or Register</h2>
|
||||
<p class="subtitle error-msg">{{ errorMsg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="(provider, index) in loginProviders" v-bind:id="index">
|
||||
<a :href="provider.url">{{ index }} ({{provider.type}})</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Users</h3>
|
||||
<ul>
|
||||
<li v-for="(user) in users">
|
||||
<a href="#">({{user.id}}) {{user.first_name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button v-on:click="oidc_login">Login via OIDC</button>
|
||||
<a href="http://localhost:5443/api/auth/oidc?redirect_url=/login">OIDC with redirect</a>
|
||||
</section>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="field">
|
||||
<label class="label is-large" for="email">Email:</label>
|
||||
<div class="control">
|
||||
<input type="email" class="input is-large" id="email" v-model="email">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label is-large" for="password">Password:</label>
|
||||
<div class="control">
|
||||
<input type="password" class="input is-large" id="password" v-model="password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-large is-primary" @click="authenticate">Login</a>
|
||||
<a class="button is-large is-success" @click="register">Register</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h1>{{ $t('You are already logged in!') }}</h1>
|
||||
<h2>{{$t('Redirecting you to')}} <router-link :to="{name: redirectTarget}">{{redirectTarget}}</router-link> {{$t('in')}} {{redirectTime}} {{$t('seconds')}}.</h2>
|
||||
<p><a href="" @click.prevent="logout()">{{$t('logout')}}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus} from '@/utils';
|
||||
|
||||
export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
errorMsg: '',
|
||||
redirectMsg: '',
|
||||
redirectTarget: 'profile',
|
||||
redirectTime: 5,
|
||||
loginProviders: [],
|
||||
redirect_interval: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
authenticate() {
|
||||
this.$store.dispatch('login', {email: this.email, password: this.password})
|
||||
.then(() => this.$router.push('/'));
|
||||
},
|
||||
register() {
|
||||
this.$store.dispatch('register', {email: this.email, password: this.password})
|
||||
.then(() => this.$router.push('/'));
|
||||
},
|
||||
oidc_login() {
|
||||
this.$store.dispatch('oidc_login', '\\oidc_login_redirection');
|
||||
},
|
||||
logout() {
|
||||
this.$store.dispatch('logout', {revokeRefreshToken: true});
|
||||
this.$router.push({name: 'home'});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.$parent.$data.isLoading = true;
|
||||
EventBus.$on('failedRegistering', (msg) => {
|
||||
this.errorMsg = msg;
|
||||
});
|
||||
EventBus.$on('failedAuthentication', (msg) => {
|
||||
this.errorMsg = msg;
|
||||
});
|
||||
EventBus.$on('loginProvidersLoaded', (providers) => {
|
||||
this.loginProviders = providers;
|
||||
});
|
||||
EventBus.$on('storedTokens', () => {
|
||||
this.$store.dispatch('loadUsers');
|
||||
this.$store.dispatch('loadProfile');
|
||||
});
|
||||
|
||||
this.$store.dispatch('loadLoginProviders');
|
||||
|
||||
// get tokens
|
||||
if (this.$cookies.isKey('tokens')) {
|
||||
this.$store.dispatch('storeTokens', JSON.parse(atob(this.$cookies.get('tokens'))));
|
||||
this.$cookies.remove('tokens');
|
||||
}
|
||||
this.$log.debug(this.$cookies.keys());
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.authenticated) {
|
||||
if (this.$route.query.redirectionTarget) {
|
||||
this.redirectTarget = this.$route.query.redirectionTarget;
|
||||
}
|
||||
this.redirect_interval = window.setInterval(() => {
|
||||
this.redirectTime = this.redirectTime - 1;
|
||||
if (this.redirectTime < 0) {
|
||||
clearInterval(this.redirect_interval);
|
||||
this.$router.push({name: this.redirectTarget});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.redirect_interval);
|
||||
EventBus.$off('failedRegistering');
|
||||
EventBus.$off('failedAuthentication');
|
||||
},
|
||||
computed: {
|
||||
users() {
|
||||
return this.$store.state.users;
|
||||
},
|
||||
authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.error-msg {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
@@ -1,323 +1,323 @@
|
||||
<!-- components/Profile.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h3>
|
||||
<div class="text-center">
|
||||
<font-awesome-icon class="float-left" icon="arrow-circle-left" @click="previousRecorder()"/>
|
||||
<input type="number" style="font-size: small; max-width: 48px; text-align: center;"
|
||||
v-model="new_recorder_id" @blur="manually_set_recorder_id()"
|
||||
@input="manually_set_recorder_id()">
|
||||
<font-awesome-icon class="float-right" icon="arrow-circle-right" @click="nextRecorder()"/>
|
||||
</div>
|
||||
</h3>
|
||||
|
||||
<div class="clearfix">
|
||||
<!--Route params: {{$route.params.recorder_id}}-->
|
||||
<b-img left style="margin-right: 20px;" src="https://picsum.photos/164/164/?image=58"
|
||||
alt="Left image"></b-img>
|
||||
<h2 class="title">
|
||||
<font-awesome-icon v-if="recorder.locked" style="color: red;" icon="lock"
|
||||
@dblclick="unlock()"/>
|
||||
<font-awesome-icon v-else icon="lock-open" style="color: green;" @click="lock()"/>
|
||||
{{recorder.name}}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<span v-b-tooltip.hover :title="$t('model_name')">
|
||||
<font-awesome-icon icon="tag"/> {{recorder.model_name ? recorder.model_name : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('firmware_version')">
|
||||
<font-awesome-icon icon="code"/> {{recorder.firmware_version ? recorder.firmware_version : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('additional_camera_connected')">
|
||||
<font-awesome-icon icon="video"/> {{recorder.additional_camera_connected ? $t("yes") : $t("no")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('serial_number')">
|
||||
<font-awesome-icon icon="barcode"/> {{recorder.serial_number ? recorder.serial_number : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('room')">
|
||||
<font-awesome-icon icon="home"/> {{recorder.room ? recorder.room.name : $t("undefined")}}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<strong>{{$t('created_at')}}: </strong>{{recorder.created_at}}<br/>
|
||||
<strong>{{$t('last_time_modified')}}: </strong>{{recorder.last_time_modified}}<br/>
|
||||
|
||||
<strong>State: </strong>
|
||||
<span v-if="state">
|
||||
<font-awesome-icon v-if="state.state_ok" style="color: green;" icon="thumbs-up"/>
|
||||
<font-awesome-icon v-else icon="thumbs-down" style="color: red;"/>
|
||||
{{state.msg}} <small>(Last update: {{state.time_stamp}})</small>
|
||||
</span>
|
||||
<span v-else>{{$t('State is unknown')}}!</span>
|
||||
<br/>
|
||||
|
||||
|
||||
<hr/>
|
||||
<h3 style="color: orangered;" v-if="recorder.offline">
|
||||
<font-awesome-icon icon="wrench"/>
|
||||
{{recorder.offline ? 'The recorder is in offline / maintenance mode' : ''}}
|
||||
</h3>
|
||||
<hr v-if="recorder.offline"/>
|
||||
|
||||
<h3 style="color: red;" v-if="recorder.lock_message">
|
||||
<font-awesome-icon icon="lock"/>
|
||||
{{recorder.lock_message}}
|
||||
</h3>
|
||||
<hr v-if="recorder.lock_message"/>
|
||||
|
||||
|
||||
<div role="tablist">
|
||||
<b-card no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-1 variant="info">Network</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-1" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<strong>{{$t('ip')}}: </strong>{{recorder.ip}}<br/>
|
||||
<strong>{{$t('mac')}}: </strong>{{recorder.mac}}<br/>
|
||||
<strong>{{$t('network_name')}}: </strong>{{recorder.network_name}}<br/>
|
||||
|
||||
<strong>{{$t('ssh_port')}}: </strong>{{recorder.ssh_port}}<br/>
|
||||
<strong>{{$t('telnet_port')}}: </strong>{{recorder.telnet_port}}<br/>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorder.description" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-2 variant="info">Description</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<b-card-text>{{recorder.description}}</b-card-text>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorderModel" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-2 variant="outline-primary">Model /
|
||||
Recorder Adapter Info
|
||||
</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<strong>{{$t('name')}}: </strong>{{recorderModel.name}}<br/>
|
||||
<strong>{{$t('created_at')}}: </strong>{{recorderModel.created_at}}<br/>
|
||||
<strong>{{$t('last_time_modified')}}: </strong>{{recorderModel.last_time_modified
|
||||
? recorderModel.last_time_modified : 'never'}}<br/>
|
||||
<strong>{{$t('requires_username')}}: </strong>{{recorderModel.requires_username
|
||||
? 'Yes' : 'No'}}<br/>
|
||||
<strong>{{$t('requires_password')}}: </strong>{{recorderModel.requires_password
|
||||
? 'Yes' : 'No'}}<br/>
|
||||
<span v-if="recorderModel.notes"><strong>{{$t('notes')}}: </strong>{{recorderModel.notes}}<br/></span>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorderModel" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-3 variant="danger">
|
||||
<span>Commands</span>
|
||||
<span v-if="recorder.locked"> ({{$t('locked')}})</span>
|
||||
<span v-if="recorder.offline"> ({{$t('offline')}})</span>
|
||||
</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-3" visible accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
{{cmd_params}}
|
||||
<b-list-group style="max-height: 400px; overflow-y:scroll;"
|
||||
v-if="!(recorder.locked || recorder.offline)">
|
||||
<b-list-group-item v-for="command in recorderModel.commands"
|
||||
v-bind:key="command.id">
|
||||
<h5>{{command.name}}</h5>
|
||||
<b-row>
|
||||
<b-col sm="3" v-for="(a_type, arg) in command.parameters"
|
||||
v-bind:key="arg"
|
||||
v-if="command.parameters !== null">
|
||||
<b-form-input @focus="setup_params(command.id, arg)"
|
||||
@blur="set_param(command.id, arg, $event.target.value)"
|
||||
:placeholder="arg + ' ('+a_type+')'"
|
||||
:type="a_type==='int'?'number':'text'"
|
||||
style="margin-right: 10px;">
|
||||
<small>{{arg}}: {{a_type}}</small>
|
||||
</b-form-input>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<button class="float-right" @click="execute_command(command.id)">
|
||||
<font-awesome-icon icon="play"/>
|
||||
</button>
|
||||
<p v-if="cmd_res[command.id]">
|
||||
<font-awesome-icon style="color: green;" v-if="cmd_res[command.id].ok"
|
||||
icon="smile"/>
|
||||
<font-awesome-icon style="color: red;" v-else icon="frown"/>
|
||||
<span>{{cmd_res[command.id].time | moment("HH:mm:ss")}}</span>
|
||||
- Output:
|
||||
<strong>
|
||||
<span v-if="cmd_res[command.id].ok">{{cmd_res[command.id].output}}</span>
|
||||
<span v-else>{{cmd_res[command.id].error}}</span>
|
||||
</strong>
|
||||
</p>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<span v-else>The recorder is either locked or in offline mode – commands are disabled!</span>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus} from '@/utils';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const controlRepository = getRepository('control');
|
||||
|
||||
export default {
|
||||
props: ['recorder_id'],
|
||||
data() {
|
||||
return {
|
||||
current_recorder_id: this.recorder_id == null ? 1 : parseInt(this.recorder_id),
|
||||
current_recorder_index: null,
|
||||
new_recorder_id: this.current_recorder_id,
|
||||
cmd_params: {},
|
||||
cmd_res: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setup_params(command_id, argument) {
|
||||
if (!(command_id in this.cmd_params)) {
|
||||
this.$set(this.cmd_params, command_id, {});
|
||||
}
|
||||
this.$set(this.cmd_params[command_id], argument, null)
|
||||
},
|
||||
set_param(command_id, argument, val) {
|
||||
this.$set(this.cmd_params[command_id], argument, val)
|
||||
},
|
||||
manually_set_recorder_id() {
|
||||
if (this.new_recorder_id == null || this.new_recorder_id === '') {
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
return;
|
||||
}
|
||||
if (this.recorderIds.includes(parseInt(this.new_recorder_id))) {
|
||||
this.current_recorder_id = parseInt(this.new_recorder_id);
|
||||
}
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
lock() {
|
||||
this.recorder.locked = true;
|
||||
},
|
||||
unlock() {
|
||||
this.recorder.locked = false;
|
||||
},
|
||||
calculate_current_recorder_index() {
|
||||
this.current_recorder_index = this.recorderIds.findIndex((id) => {
|
||||
return id === this.current_recorder_id
|
||||
});
|
||||
},
|
||||
previousRecorder() {
|
||||
if (null == this.current_recorder_index) {
|
||||
this.calculate_current_recorder_index();
|
||||
}
|
||||
if (this.current_recorder_index === 0) this.current_recorder_index = this.recorderIds.length - 1;
|
||||
else this.current_recorder_index = this.current_recorder_index - 1;
|
||||
this.current_recorder_id = this.recorderIds[this.current_recorder_index];
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
nextRecorder() {
|
||||
if (null == this.current_recorder_index) {
|
||||
this.calculate_current_recorder_index();
|
||||
}
|
||||
if (this.current_recorder_index === this.recorderIds.length - 1) this.current_recorder_index = 0;
|
||||
else this.current_recorder_index = this.current_recorder_index + 1;
|
||||
this.current_recorder_id = this.recorderIds[this.current_recorder_index];
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
execute_command(command_id) {
|
||||
console.log("recorder: " + this.current_recorder_id + "; " + command_id);
|
||||
console.log(this.cmd_params);
|
||||
console.log(this.cmd_params[command_id]);
|
||||
this.$parent.$data.isLoading = true;
|
||||
controlRepository.runRecorderCommand(this.current_recorder_id, command_id, this.cmd_params[command_id]).then((out) => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
console.log(out.data);
|
||||
this.$set(this.cmd_res, command_id, out.data);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('loadRecorders');
|
||||
this.$store.dispatch('loadRecorderModels');
|
||||
this.$store.dispatch('loadRecorderState', this.current_recorder_id);
|
||||
},
|
||||
beforeDestroy() {
|
||||
EventBus.$off('failedLoadingProfile');
|
||||
},
|
||||
computed: {
|
||||
recorders() {
|
||||
return this.$store.state.recorders;
|
||||
},
|
||||
recorderIds() {
|
||||
let ids = [];
|
||||
this.recorders.forEach((elem) => {
|
||||
ids.push(parseInt(elem.id));
|
||||
});
|
||||
return ids;
|
||||
},
|
||||
recorder() {
|
||||
const recorder = this.$store.state.recorders.filter((item) => {
|
||||
return parseInt(item.id) === this.current_recorder_id;
|
||||
});
|
||||
if (recorder.length < 1) {
|
||||
this.$router.replace({name: 'notFound'});
|
||||
return {};
|
||||
}
|
||||
return recorder.shift();
|
||||
},
|
||||
recorderModel() {
|
||||
if (!this.recorder || !this.recorder.recorder_model) return null;
|
||||
const model = this.recorderModels.filter((item) => {
|
||||
return parseInt(item.id) === this.recorder.recorder_model.id;
|
||||
});
|
||||
if (model.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return model.shift();
|
||||
},
|
||||
recorderModels() {
|
||||
return this.$store.state.recorderModels;
|
||||
},
|
||||
access_token() {
|
||||
return this.$store.state.access_token;
|
||||
},
|
||||
state() {
|
||||
return this.$store.state.recorderStates.filter((s) => {
|
||||
return parseInt(s.id) === this.current_recorder_id
|
||||
}).pop();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.error-msg {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lang-btn {
|
||||
padding: 15px;
|
||||
border: 2px solid green;
|
||||
font-size: 18px;
|
||||
margin: 15px;
|
||||
}
|
||||
</style>
|
||||
<!-- components/Profile.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h3>
|
||||
<div class="text-center">
|
||||
<font-awesome-icon class="float-left" icon="arrow-circle-left" @click="previousRecorder()"/>
|
||||
<input type="number" style="font-size: small; max-width: 48px; text-align: center;"
|
||||
v-model="new_recorder_id" @blur="manually_set_recorder_id()"
|
||||
@input="manually_set_recorder_id()">
|
||||
<font-awesome-icon class="float-right" icon="arrow-circle-right" @click="nextRecorder()"/>
|
||||
</div>
|
||||
</h3>
|
||||
|
||||
<div class="clearfix">
|
||||
<!--Route params: {{$route.params.recorder_id}}-->
|
||||
<b-img left style="margin-right: 20px;" src="https://picsum.photos/164/164/?image=58"
|
||||
alt="Left image"></b-img>
|
||||
<h2 class="title">
|
||||
<font-awesome-icon v-if="recorder.locked" style="color: red;" icon="lock"
|
||||
@dblclick="unlock()"/>
|
||||
<font-awesome-icon v-else icon="lock-open" style="color: green;" @click="lock()"/>
|
||||
{{recorder.name}}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<span v-b-tooltip.hover :title="$t('model_name')">
|
||||
<font-awesome-icon icon="tag"/> {{recorder.model_name ? recorder.model_name : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('firmware_version')">
|
||||
<font-awesome-icon icon="code"/> {{recorder.firmware_version ? recorder.firmware_version : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('additional_camera_connected')">
|
||||
<font-awesome-icon icon="video"/> {{recorder.additional_camera_connected ? $t("yes") : $t("no")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('serial_number')">
|
||||
<font-awesome-icon icon="barcode"/> {{recorder.serial_number ? recorder.serial_number : $t("undefined")}}<br/>
|
||||
</span>
|
||||
<span v-b-tooltip.hover :title="$t('room')">
|
||||
<font-awesome-icon icon="home"/> {{recorder.room ? recorder.room.name : $t("undefined")}}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<strong>{{$t('created_at')}}: </strong>{{recorder.created_at}}<br/>
|
||||
<strong>{{$t('last_time_modified')}}: </strong>{{recorder.last_time_modified}}<br/>
|
||||
|
||||
<strong>State: </strong>
|
||||
<span v-if="state">
|
||||
<font-awesome-icon v-if="state.state_ok" style="color: green;" icon="thumbs-up"/>
|
||||
<font-awesome-icon v-else icon="thumbs-down" style="color: red;"/>
|
||||
{{state.msg}} <small>(Last update: {{state.time_stamp}})</small>
|
||||
</span>
|
||||
<span v-else>{{$t('State is unknown')}}!</span>
|
||||
<br/>
|
||||
|
||||
|
||||
<hr/>
|
||||
<h3 style="color: orangered;" v-if="recorder.offline">
|
||||
<font-awesome-icon icon="wrench"/>
|
||||
{{recorder.offline ? 'The recorder is in offline / maintenance mode' : ''}}
|
||||
</h3>
|
||||
<hr v-if="recorder.offline"/>
|
||||
|
||||
<h3 style="color: red;" v-if="recorder.lock_message">
|
||||
<font-awesome-icon icon="lock"/>
|
||||
{{recorder.lock_message}}
|
||||
</h3>
|
||||
<hr v-if="recorder.lock_message"/>
|
||||
|
||||
|
||||
<div role="tablist">
|
||||
<b-card no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-1 variant="info">Network</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-1" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<strong>{{$t('ip')}}: </strong>{{recorder.ip}}<br/>
|
||||
<strong>{{$t('mac')}}: </strong>{{recorder.mac}}<br/>
|
||||
<strong>{{$t('network_name')}}: </strong>{{recorder.network_name}}<br/>
|
||||
|
||||
<strong>{{$t('ssh_port')}}: </strong>{{recorder.ssh_port}}<br/>
|
||||
<strong>{{$t('telnet_port')}}: </strong>{{recorder.telnet_port}}<br/>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorder.description" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-2 variant="info">Description</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<b-card-text>{{recorder.description}}</b-card-text>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorderModel" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-2 variant="outline-primary">Model /
|
||||
Recorder Adapter Info
|
||||
</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
<strong>{{$t('name')}}: </strong>{{recorderModel.name}}<br/>
|
||||
<strong>{{$t('created_at')}}: </strong>{{recorderModel.created_at}}<br/>
|
||||
<strong>{{$t('last_time_modified')}}: </strong>{{recorderModel.last_time_modified
|
||||
? recorderModel.last_time_modified : 'never'}}<br/>
|
||||
<strong>{{$t('requires_username')}}: </strong>{{recorderModel.requires_username
|
||||
? 'Yes' : 'No'}}<br/>
|
||||
<strong>{{$t('requires_password')}}: </strong>{{recorderModel.requires_password
|
||||
? 'Yes' : 'No'}}<br/>
|
||||
<span v-if="recorderModel.notes"><strong>{{$t('notes')}}: </strong>{{recorderModel.notes}}<br/></span>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
|
||||
<b-card v-if="recorderModel" no-body class="mb-1">
|
||||
<b-card-header header-tag="header" class="p-1" role="tab">
|
||||
<b-button block href="#" v-b-toggle.accordion-3 variant="danger">
|
||||
<span>Commands</span>
|
||||
<span v-if="recorder.locked"> ({{$t('locked')}})</span>
|
||||
<span v-if="recorder.offline"> ({{$t('offline')}})</span>
|
||||
</b-button>
|
||||
</b-card-header>
|
||||
<b-collapse id="accordion-3" visible accordion="my-accordion" role="tabpanel">
|
||||
<b-card-body>
|
||||
{{cmd_params}}
|
||||
<b-list-group style="max-height: 400px; overflow-y:scroll;"
|
||||
v-if="!(recorder.locked || recorder.offline)">
|
||||
<b-list-group-item v-for="command in recorderModel.commands"
|
||||
v-bind:key="command.id">
|
||||
<h5>{{command.name}}</h5>
|
||||
<b-row>
|
||||
<b-col sm="3" v-for="(a_type, arg) in command.parameters"
|
||||
v-bind:key="arg"
|
||||
v-if="command.parameters !== null">
|
||||
<b-form-input @focus="setup_params(command.id, arg)"
|
||||
@blur="set_param(command.id, arg, $event.target.value)"
|
||||
:placeholder="arg + ' ('+a_type+')'"
|
||||
:type="a_type==='int'?'number':'text'"
|
||||
style="margin-right: 10px;">
|
||||
<small>{{arg}}: {{a_type}}</small>
|
||||
</b-form-input>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<button class="float-right" @click="execute_command(command.id)">
|
||||
<font-awesome-icon icon="play"/>
|
||||
</button>
|
||||
<p v-if="cmd_res[command.id]">
|
||||
<font-awesome-icon style="color: green;" v-if="cmd_res[command.id].ok"
|
||||
icon="smile"/>
|
||||
<font-awesome-icon style="color: red;" v-else icon="frown"/>
|
||||
<span>{{cmd_res[command.id].time | moment("HH:mm:ss")}}</span>
|
||||
- Output:
|
||||
<strong>
|
||||
<span v-if="cmd_res[command.id].ok">{{cmd_res[command.id].output}}</span>
|
||||
<span v-else>{{cmd_res[command.id].error}}</span>
|
||||
</strong>
|
||||
</p>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<span v-else>The recorder is either locked or in offline mode – commands are disabled!</span>
|
||||
</b-card-body>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {EventBus} from '@/utils';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const controlRepository = getRepository('control');
|
||||
|
||||
export default {
|
||||
props: ['recorder_id'],
|
||||
data() {
|
||||
return {
|
||||
current_recorder_id: this.recorder_id == null ? 1 : parseInt(this.recorder_id),
|
||||
current_recorder_index: null,
|
||||
new_recorder_id: this.current_recorder_id,
|
||||
cmd_params: {},
|
||||
cmd_res: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setup_params(command_id, argument) {
|
||||
if (!(command_id in this.cmd_params)) {
|
||||
this.$set(this.cmd_params, command_id, {});
|
||||
}
|
||||
this.$set(this.cmd_params[command_id], argument, null)
|
||||
},
|
||||
set_param(command_id, argument, val) {
|
||||
this.$set(this.cmd_params[command_id], argument, val)
|
||||
},
|
||||
manually_set_recorder_id() {
|
||||
if (this.new_recorder_id == null || this.new_recorder_id === '') {
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
return;
|
||||
}
|
||||
if (this.recorderIds.includes(parseInt(this.new_recorder_id))) {
|
||||
this.current_recorder_id = parseInt(this.new_recorder_id);
|
||||
}
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
lock() {
|
||||
this.recorder.locked = true;
|
||||
},
|
||||
unlock() {
|
||||
this.recorder.locked = false;
|
||||
},
|
||||
calculate_current_recorder_index() {
|
||||
this.current_recorder_index = this.recorderIds.findIndex((id) => {
|
||||
return id === this.current_recorder_id
|
||||
});
|
||||
},
|
||||
previousRecorder() {
|
||||
if (null == this.current_recorder_index) {
|
||||
this.calculate_current_recorder_index();
|
||||
}
|
||||
if (this.current_recorder_index === 0) this.current_recorder_index = this.recorderIds.length - 1;
|
||||
else this.current_recorder_index = this.current_recorder_index - 1;
|
||||
this.current_recorder_id = this.recorderIds[this.current_recorder_index];
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
nextRecorder() {
|
||||
if (null == this.current_recorder_index) {
|
||||
this.calculate_current_recorder_index();
|
||||
}
|
||||
if (this.current_recorder_index === this.recorderIds.length - 1) this.current_recorder_index = 0;
|
||||
else this.current_recorder_index = this.current_recorder_index + 1;
|
||||
this.current_recorder_id = this.recorderIds[this.current_recorder_index];
|
||||
this.new_recorder_id = this.current_recorder_id;
|
||||
},
|
||||
execute_command(command_id) {
|
||||
console.log("recorder: " + this.current_recorder_id + "; " + command_id);
|
||||
console.log(this.cmd_params);
|
||||
console.log(this.cmd_params[command_id]);
|
||||
this.$parent.$data.isLoading = true;
|
||||
controlRepository.runRecorderCommand(this.current_recorder_id, command_id, this.cmd_params[command_id]).then((out) => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
console.log(out.data);
|
||||
this.$set(this.cmd_res, command_id, out.data);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('loadRecorders');
|
||||
this.$store.dispatch('loadRecorderModels');
|
||||
this.$store.dispatch('loadRecorderState', this.current_recorder_id);
|
||||
},
|
||||
beforeDestroy() {
|
||||
EventBus.$off('failedLoadingProfile');
|
||||
},
|
||||
computed: {
|
||||
recorders() {
|
||||
return this.$store.state.recorders;
|
||||
},
|
||||
recorderIds() {
|
||||
let ids = [];
|
||||
this.recorders.forEach((elem) => {
|
||||
ids.push(parseInt(elem.id));
|
||||
});
|
||||
return ids;
|
||||
},
|
||||
recorder() {
|
||||
const recorder = this.$store.state.recorders.filter((item) => {
|
||||
return parseInt(item.id) === this.current_recorder_id;
|
||||
});
|
||||
if (recorder.length < 1) {
|
||||
this.$router.replace({name: 'notFound'});
|
||||
return {};
|
||||
}
|
||||
return recorder.shift();
|
||||
},
|
||||
recorderModel() {
|
||||
if (!this.recorder || !this.recorder.recorder_model) return null;
|
||||
const model = this.recorderModels.filter((item) => {
|
||||
return parseInt(item.id) === this.recorder.recorder_model.id;
|
||||
});
|
||||
if (model.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return model.shift();
|
||||
},
|
||||
recorderModels() {
|
||||
return this.$store.state.recorderModels;
|
||||
},
|
||||
access_token() {
|
||||
return this.$store.state.access_token;
|
||||
},
|
||||
state() {
|
||||
return this.$store.state.recorderStates.filter((s) => {
|
||||
return parseInt(s.id) === this.current_recorder_id
|
||||
}).pop();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.error-msg {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lang-btn {
|
||||
padding: 15px;
|
||||
border: 2px solid green;
|
||||
font-size: 18px;
|
||||
margin: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
242
src/main.ts
242
src/main.ts
@@ -1,121 +1,121 @@
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import VueAxios from 'vue-axios';
|
||||
import BootstrapVue from 'bootstrap-vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import VueSweetalert2 from 'vue-sweetalert2';
|
||||
import VueCookies from 'vue-cookies';
|
||||
import VueLogger from 'vuejs-logger';
|
||||
import VueSocketIOExt from 'vue-socket.io-extended';
|
||||
import io from 'socket.io-client';
|
||||
import i18n from '@/plugins/i18n';
|
||||
import VeeValidate from 'vee-validate';
|
||||
// @ts-ignore
|
||||
import FlagIcon from 'vue-flag-icon';
|
||||
// @ts-ignore
|
||||
import VueMoment from 'vue-moment';
|
||||
// following is to avoid missing type definitions
|
||||
// const FlagIcon = require('vue-flag-icon');
|
||||
|
||||
import {library} from '@fortawesome/fontawesome-svg-core';
|
||||
import {
|
||||
faCoffee,
|
||||
faDoorOpen,
|
||||
faCheck,
|
||||
faPlus,
|
||||
faScroll,
|
||||
faCircle,
|
||||
faArrowCircleLeft,
|
||||
faArrowCircleRight,
|
||||
faList,
|
||||
faTrash,
|
||||
faPencilAlt,
|
||||
faCogs,
|
||||
faAt,
|
||||
faUser,
|
||||
faEnvelope,
|
||||
faHome,
|
||||
faSync,
|
||||
faCode,
|
||||
faBarcode,
|
||||
faTag,
|
||||
faTags,
|
||||
faVideo,
|
||||
faLock,
|
||||
faLockOpen,
|
||||
faWrench,
|
||||
faPlay,
|
||||
faFrown,
|
||||
faSmile,
|
||||
faUserTag,
|
||||
faExternalLinkAlt,
|
||||
faThumbsUp,
|
||||
faThumbsDown,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
|
||||
|
||||
|
||||
// import 'bootstrap';
|
||||
// import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
library.add(faCoffee, faTrash, faPencilAlt, faScroll, faCheck, faCircle, faList, faPlus, faDoorOpen, faCogs, faAt,
|
||||
faUser, faEnvelope, faUserTag, faExternalLinkAlt, faSync, faHome, faCode, faBarcode, faTag, faTags, faVideo, faLock,
|
||||
faLockOpen, faArrowCircleLeft, faArrowCircleRight, faWrench, faPlay, faFrown, faSmile, faThumbsUp, faThumbsDown);
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon);
|
||||
|
||||
const options = {
|
||||
isEnabled: true,
|
||||
// logLevel : isProduction ? 'error' : 'debug',
|
||||
logLevel: 'debug',
|
||||
stringifyArguments: false,
|
||||
showLogLevel: true,
|
||||
showMethodName: true,
|
||||
separator: '|',
|
||||
showConsoleColors: true,
|
||||
};
|
||||
|
||||
Vue.use(VueLogger, options);
|
||||
Vue.use(VueAxios, axios);
|
||||
Vue.use(BootstrapVue);
|
||||
Vue.use(FlagIcon);
|
||||
Vue.use(VueCookies);
|
||||
Vue.use(VueSweetalert2);
|
||||
Vue.use(VeeValidate);
|
||||
Vue.use(VueMoment);
|
||||
|
||||
// const socket = io('ws://localhost:5000',{autoConnect: false, reconnectionAttempts: 3});
|
||||
const socket = io('ws://localhost:5443', {
|
||||
autoConnect: false,
|
||||
reconnectionAttempts: 3,
|
||||
query: {jwt: store.state.access_token},
|
||||
});
|
||||
Vue.use(VueSocketIOExt, socket);
|
||||
|
||||
|
||||
// setup fake backend
|
||||
// import { configureFakeBackend } from './helpers';
|
||||
// configureFakeBackend();
|
||||
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
String.prototype.isEmpty = function() {
|
||||
return (this.length === 0 || !this.trim());
|
||||
};
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
router,
|
||||
store,
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import VueAxios from 'vue-axios';
|
||||
import BootstrapVue from 'bootstrap-vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import VueSweetalert2 from 'vue-sweetalert2';
|
||||
import VueCookies from 'vue-cookies';
|
||||
import VueLogger from 'vuejs-logger';
|
||||
import VueSocketIOExt from 'vue-socket.io-extended';
|
||||
import io from 'socket.io-client';
|
||||
import i18n from '@/plugins/i18n';
|
||||
import VeeValidate from 'vee-validate';
|
||||
// @ts-ignore
|
||||
import FlagIcon from 'vue-flag-icon';
|
||||
// @ts-ignore
|
||||
import VueMoment from 'vue-moment';
|
||||
// following is to avoid missing type definitions
|
||||
// const FlagIcon = require('vue-flag-icon');
|
||||
|
||||
import {library} from '@fortawesome/fontawesome-svg-core';
|
||||
import {
|
||||
faCoffee,
|
||||
faDoorOpen,
|
||||
faCheck,
|
||||
faPlus,
|
||||
faScroll,
|
||||
faCircle,
|
||||
faArrowCircleLeft,
|
||||
faArrowCircleRight,
|
||||
faList,
|
||||
faTrash,
|
||||
faPencilAlt,
|
||||
faCogs,
|
||||
faAt,
|
||||
faUser,
|
||||
faEnvelope,
|
||||
faHome,
|
||||
faSync,
|
||||
faCode,
|
||||
faBarcode,
|
||||
faTag,
|
||||
faTags,
|
||||
faVideo,
|
||||
faLock,
|
||||
faLockOpen,
|
||||
faWrench,
|
||||
faPlay,
|
||||
faFrown,
|
||||
faSmile,
|
||||
faUserTag,
|
||||
faExternalLinkAlt,
|
||||
faThumbsUp,
|
||||
faThumbsDown,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
|
||||
|
||||
|
||||
// import 'bootstrap';
|
||||
// import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
library.add(faCoffee, faTrash, faPencilAlt, faScroll, faCheck, faCircle, faList, faPlus, faDoorOpen, faCogs, faAt,
|
||||
faUser, faEnvelope, faUserTag, faExternalLinkAlt, faSync, faHome, faCode, faBarcode, faTag, faTags, faVideo, faLock,
|
||||
faLockOpen, faArrowCircleLeft, faArrowCircleRight, faWrench, faPlay, faFrown, faSmile, faThumbsUp, faThumbsDown);
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon);
|
||||
|
||||
const options = {
|
||||
isEnabled: true,
|
||||
// logLevel : isProduction ? 'error' : 'debug',
|
||||
logLevel: 'debug',
|
||||
stringifyArguments: false,
|
||||
showLogLevel: true,
|
||||
showMethodName: true,
|
||||
separator: '|',
|
||||
showConsoleColors: true,
|
||||
};
|
||||
|
||||
Vue.use(VueLogger, options);
|
||||
Vue.use(VueAxios, axios);
|
||||
Vue.use(BootstrapVue);
|
||||
Vue.use(FlagIcon);
|
||||
Vue.use(VueCookies);
|
||||
Vue.use(VueSweetalert2);
|
||||
Vue.use(VeeValidate);
|
||||
Vue.use(VueMoment);
|
||||
|
||||
// const socket = io('ws://localhost:5000',{autoConnect: false, reconnectionAttempts: 3});
|
||||
const socket = io('ws://localhost:5443', {
|
||||
autoConnect: false,
|
||||
reconnectionAttempts: 3,
|
||||
query: {jwt: store.state.access_token},
|
||||
});
|
||||
Vue.use(VueSocketIOExt, socket);
|
||||
|
||||
|
||||
// setup fake backend
|
||||
// import { configureFakeBackend } from './helpers';
|
||||
// configureFakeBackend();
|
||||
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
String.prototype.isEmpty = function() {
|
||||
return (this.length === 0 || !this.trim());
|
||||
};
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
router,
|
||||
store,
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
|
||||
824
src/store.ts
824
src/store.ts
@@ -1,412 +1,412 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import createPersistedState from 'vuex-persistedstate';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
import RoomRepository from '@/api/roomRepository';
|
||||
import RecordRepository from '@/api/recorderRepository';
|
||||
import VirtualCommandRepository from '@/api/virtualCommandRepository';
|
||||
import StateRepository from '@/api/stateRepository';
|
||||
|
||||
// imports of AJAX functions will go here
|
||||
import {
|
||||
fetchSurveys,
|
||||
fetchSurvey,
|
||||
getProviders,
|
||||
saveSurveyResponse,
|
||||
postNewSurvey,
|
||||
authenticate,
|
||||
register,
|
||||
oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey,
|
||||
} from '@/api';
|
||||
import {isValidJwt, EventBus} from '@/utils';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const state = {
|
||||
// single source of data
|
||||
surveys: [],
|
||||
rooms: [],
|
||||
recorders: [],
|
||||
recorderModels: [],
|
||||
recorderCommands: [],
|
||||
recorderStates: [],
|
||||
virtualCommands: [],
|
||||
loginProviders: [],
|
||||
currentSurvey: {},
|
||||
profile: {},
|
||||
users: [],
|
||||
userGroups: [],
|
||||
access_token: '',
|
||||
refresh_token: '',
|
||||
};
|
||||
|
||||
|
||||
// const RoomRepository = getRepository('room');
|
||||
|
||||
|
||||
const actions = {
|
||||
// asynchronous operations
|
||||
loadRooms(context: any) {
|
||||
return RoomRepository.getRooms()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRooms', {rooms: response.data});
|
||||
EventBus.$emit('roomsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading rooms!', error);
|
||||
EventBus.$emit('failedLoadingRooms', error);
|
||||
});
|
||||
},
|
||||
loadRecorders(context: any) {
|
||||
return RecordRepository.getRecorders()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorders', {recorders: response.data});
|
||||
EventBus.$emit('recordersLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders!', error);
|
||||
EventBus.$emit('failedLoadingRecorders', error);
|
||||
});
|
||||
},
|
||||
loadRecorderStates(context: any) {
|
||||
return StateRepository.getRecordersStates()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderStates', {recorderStates: response.data});
|
||||
EventBus.$emit('recorderStatesLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders states!', error);
|
||||
EventBus.$emit('failedLoadingRecorderStates', error);
|
||||
});
|
||||
},
|
||||
loadRecorderState(context: any, recorder_id: number) {
|
||||
return StateRepository.getRecorderState(recorder_id)
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderState', {recorderState: response.data});
|
||||
EventBus.$emit('recorderStateLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders states!', error);
|
||||
EventBus.$emit('failedLoadingRecorderStates', error);
|
||||
});
|
||||
},
|
||||
loadRecorderModels(context: any) {
|
||||
return RecordRepository.getRecorderModels()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
Vue.$log.debug('Loaded recorder models');
|
||||
context.commit('setRecorderModels', {recorderModels: response.data});
|
||||
EventBus.$emit('recorderModelsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorder models!', error);
|
||||
EventBus.$emit('failedLoadingRecorderModels', error);
|
||||
});
|
||||
},
|
||||
loadRecorderCommands(context: any) {
|
||||
return RecordRepository.getRecorderCommands()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderCommands', {recorderCommands: response.data});
|
||||
EventBus.$emit('recorderCommandsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorder commands!', error);
|
||||
EventBus.$emit('failedLoadingRecorderCommands', error);
|
||||
});
|
||||
},
|
||||
loadVirtualCommands(context: any) {
|
||||
return VirtualCommandRepository.getVirtualCommands()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setVirtualCommands', {virtualCommands: response.data});
|
||||
EventBus.$emit('virtualCommandsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading virtual commands!', error);
|
||||
EventBus.$emit('failedLoadingVirtualCommands', error);
|
||||
});
|
||||
},
|
||||
loadCommands(context: any) {
|
||||
return context.dispatch('loadRecorderCommands').then(() => {
|
||||
return context.dispatch('loadVirtualCommands');
|
||||
});
|
||||
},
|
||||
loadUsers(context: any) {
|
||||
return fetchUsers(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setUsers', {users: response.data});
|
||||
EventBus.$emit('usersLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading users!', error);
|
||||
EventBus.$emit('failedLoadingUsers', error);
|
||||
});
|
||||
},
|
||||
loadUserGroups(context: any) {
|
||||
return fetchUserGroups(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setUserGroups', {groups: response.data});
|
||||
EventBus.$emit('groupsLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading user groups!', error);
|
||||
EventBus.$emit('failedLoadingUserGroups', error);
|
||||
});
|
||||
},
|
||||
loadProfileAuthCheck(context: any) {
|
||||
if (!getters.isAuthenticated) {
|
||||
EventBus.$emit('accessTokenInvalid');
|
||||
if (!getters.isRefreshTokenValid) {
|
||||
Vue.$log.warn('Access and refresh token invalid! User must login again!');
|
||||
EventBus.$emit('refreshTokenInvalid');
|
||||
EventBus.$emit('accessAndRefreshTokenInvalid');
|
||||
} else {
|
||||
return context.dispatch('refreshToken').then(() => {
|
||||
context.commit('loadProfile');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
context.commit('loadProfile');
|
||||
}
|
||||
},
|
||||
loadProfile(context: any) {
|
||||
return fetchProfile(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setProfile', {profile: response.data});
|
||||
EventBus.$emit('profileLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading profile!', error);
|
||||
EventBus.$emit('failedLoadingProfile', error);
|
||||
});
|
||||
},
|
||||
loadLoginProviders(context: any) {
|
||||
return getProviders()
|
||||
.then((response) => {
|
||||
context.commit('setLoginProviderData', {providers: response.data});
|
||||
EventBus.$emit('loginProvidersLoaded', response.data);
|
||||
});
|
||||
},
|
||||
login(context: any, userData: any) {
|
||||
context.commit('setUserData', {userData});
|
||||
return authenticate(userData)
|
||||
.then((response) => context.commit('setJwtToken', {tokens: response.data}))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating: ', error);
|
||||
EventBus.$emit('failedAuthentication', error);
|
||||
});
|
||||
},
|
||||
logout(context: any, revokeRefreshToken: any) {
|
||||
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
|
||||
if (revokeRefreshToken) {
|
||||
return revokeRefreshKey(context.state.access_token)
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error);
|
||||
EventBus.$emit('failedRevokingRefreshToken', error);
|
||||
});
|
||||
}
|
||||
// this.clearAll();
|
||||
},
|
||||
oidc_login(context: any, redirectionUrl: any) {
|
||||
// context.commit('setUserData', { userData });
|
||||
return oidc_login(redirectionUrl)
|
||||
.then((response) => context.commit('setJwtToken', {tokens: response.data}))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating: ', error);
|
||||
EventBus.$emit('failedAuthentication', error);
|
||||
});
|
||||
},
|
||||
refreshToken(context: any) {
|
||||
EventBus.$emit('refreshingToken');
|
||||
Vue.$log.debug('Refreshing tokens!');
|
||||
return getFreshToken(context.state.refresh_token)
|
||||
.then((response) => {
|
||||
context.commit('setTokens', {tokens: response.data});
|
||||
Vue.$log.debug('Tokens refreshed!');
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Refreshing token: ', error);
|
||||
EventBus.$emit('failedRefreshingToken', error);
|
||||
});
|
||||
},
|
||||
resetToken(context: any) {
|
||||
EventBus.$emit('resettingTokens');
|
||||
Vue.$log.debug('Resetting tokens!');
|
||||
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
|
||||
EventBus.$emit('tokensReset');
|
||||
Vue.$log.debug('Tokens reset!');
|
||||
},
|
||||
storeTokens(context: any, tokens: any) {
|
||||
context.commit('setTokens', {tokens});
|
||||
EventBus.$emit('storedTokens');
|
||||
},
|
||||
register(context: any, userData: any) {
|
||||
context.commit('setUserData', {userData});
|
||||
return register(userData)
|
||||
.then(context.dispatch('login', userData))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Registering: ', error);
|
||||
EventBus.$emit('failedRegistering: ', error);
|
||||
});
|
||||
},
|
||||
submitNewSurvey(context: any, survey: any) {
|
||||
return postNewSurvey(survey, context.state.access_token);
|
||||
},
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
// isolated data mutations
|
||||
setSurveys(sState: any, payload: any) {
|
||||
sState.surveys = payload.surveys;
|
||||
},
|
||||
setSurvey(sState: any, payload: any) {
|
||||
const nQuestions = payload.survey.questions.length;
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
payload.survey.questions[i].choice = null;
|
||||
}
|
||||
sState.currentSurvey = payload.survey;
|
||||
},
|
||||
setRooms(sState: any, payload: any) {
|
||||
sState.rooms = payload.rooms;
|
||||
},
|
||||
setRecorders(sState: any, payload: any) {
|
||||
sState.recorders = payload.recorders;
|
||||
},
|
||||
setRecorderModels(sState: any, payload: any) {
|
||||
sState.recorderModels = payload.recorderModels;
|
||||
},
|
||||
setRecorderCommands(sState: any, payload: any) {
|
||||
sState.recorderCommands = payload.recorderCommands;
|
||||
},
|
||||
setRecorderStates(sState: any, payload: any) {
|
||||
sState.recorderStates = payload.recorderStates;
|
||||
},
|
||||
setRecorderState(sState: any, payload: any) {
|
||||
const n_rec_states = sState.recorderStates.length;
|
||||
const rec_id = payload.recorderState.id;
|
||||
let found = false;
|
||||
for (let i = 0; i < n_rec_states; i++) {
|
||||
if (sState.recorderStates[i].id === rec_id) {
|
||||
sState.recorderStates[i] = payload.recorderState;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
sState.recorderStates.push(payload.recorderState);
|
||||
}
|
||||
},
|
||||
setVirtualCommands(sState: any, payload: any) {
|
||||
sState.virtualCommands = payload.virtualCommands;
|
||||
},
|
||||
setUsers(sState: any, payload: any) {
|
||||
sState.users = payload.users;
|
||||
},
|
||||
setUserGroups(sState: any, payload: any) {
|
||||
sState.userGroups = payload.groups;
|
||||
},
|
||||
setChoice(sState: any, payload: any) {
|
||||
const {questionId, choice} = payload;
|
||||
const nQuestions = sState.currentSurvey.questions.length;
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
if (sState.currentSurvey.questions[i].id === questionId) {
|
||||
sState.currentSurvey.questions[i].choice = choice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
setLoginProviderData(sState: any, payload: any) {
|
||||
Vue.$log.debug('got loginProviders = ', payload);
|
||||
sState.loginProviders = payload.providers;
|
||||
},
|
||||
// probably old ...
|
||||
setUserData(sState: any, payload: any) {
|
||||
Vue.$log.debug('setUserData payload = ', payload);
|
||||
sState.userData = payload.userData;
|
||||
},
|
||||
setProfile(sState: any, payload: any) {
|
||||
Vue.$log.debug('setProfile payload = ', payload);
|
||||
sState.profile = payload.profile;
|
||||
},
|
||||
setJwtToken(sState: any, payload: any) {
|
||||
Vue.$log.debug('setJwtToken payload = ', payload);
|
||||
localStorage.tokens = payload.tokens;
|
||||
sState.access_token = payload.tokens.access_token;
|
||||
sState.refresh_token = payload.tokens.refresh_token;
|
||||
},
|
||||
setTokens(sState: any, payload: any) {
|
||||
Vue.$log.debug('setTokens payload = ', payload);
|
||||
if ('access_token' in payload.tokens) {
|
||||
sState.access_token = payload.tokens.access_token;
|
||||
}
|
||||
if ('refresh_token' in payload.tokens) {
|
||||
sState.refresh_token = payload.tokens.refresh_token;
|
||||
}
|
||||
Vue.$log.debug('access_token: ' + sState.access_token);
|
||||
Vue.$log.debug('refresh_token: ' + sState.refresh_token);
|
||||
},
|
||||
};
|
||||
|
||||
const getters = {
|
||||
// reusable data accessors
|
||||
isAuthenticated(sState: any) {
|
||||
const valid = isValidJwt(sState.access_token);
|
||||
Vue.$log.debug('Access token is valid?: ', valid);
|
||||
Vue.$log.debug(sState.access_token);
|
||||
return valid;
|
||||
},
|
||||
isRefreshTokenValid(sState: any) {
|
||||
const valid = isValidJwt(sState.refresh_token);
|
||||
Vue.$log.debug('Refresh token is valid?: ', valid);
|
||||
Vue.$log.debug('sState.refresh_token');
|
||||
return valid;
|
||||
},
|
||||
getLoginProviders(sState: any) {
|
||||
return sState.loginProviders;
|
||||
},
|
||||
getUserName(sState: any) {
|
||||
if (sState.profile == null || Object.keys(sState.profile).length === 0) {
|
||||
return '';
|
||||
}
|
||||
if (sState.profile.nickname) {
|
||||
return sState.profile.nickname;
|
||||
}
|
||||
return sState.profile.first_name + ' ' + sState.profile.last_name;
|
||||
},
|
||||
// this is probably wrong!!
|
||||
hasAccessRight(sState: any) {
|
||||
(requestedPermission: string) => {
|
||||
return sState.profile.effective_permissions.find((permission: any) => {
|
||||
permission.name === requestedPermission;
|
||||
});
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
actions,
|
||||
mutations,
|
||||
getters,
|
||||
plugins: [createPersistedState()],
|
||||
});
|
||||
|
||||
export default store;
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import createPersistedState from 'vuex-persistedstate';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
import RoomRepository from '@/api/roomRepository';
|
||||
import RecordRepository from '@/api/recorderRepository';
|
||||
import VirtualCommandRepository from '@/api/virtualCommandRepository';
|
||||
import StateRepository from '@/api/stateRepository';
|
||||
|
||||
// imports of AJAX functions will go here
|
||||
import {
|
||||
fetchSurveys,
|
||||
fetchSurvey,
|
||||
getProviders,
|
||||
saveSurveyResponse,
|
||||
postNewSurvey,
|
||||
authenticate,
|
||||
register,
|
||||
oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey,
|
||||
} from '@/api';
|
||||
import {isValidJwt, EventBus} from '@/utils';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const state = {
|
||||
// single source of data
|
||||
surveys: [],
|
||||
rooms: [],
|
||||
recorders: [],
|
||||
recorderModels: [],
|
||||
recorderCommands: [],
|
||||
recorderStates: [],
|
||||
virtualCommands: [],
|
||||
loginProviders: [],
|
||||
currentSurvey: {},
|
||||
profile: {},
|
||||
users: [],
|
||||
userGroups: [],
|
||||
access_token: '',
|
||||
refresh_token: '',
|
||||
};
|
||||
|
||||
|
||||
// const RoomRepository = getRepository('room');
|
||||
|
||||
|
||||
const actions = {
|
||||
// asynchronous operations
|
||||
loadRooms(context: any) {
|
||||
return RoomRepository.getRooms()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRooms', {rooms: response.data});
|
||||
EventBus.$emit('roomsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading rooms!', error);
|
||||
EventBus.$emit('failedLoadingRooms', error);
|
||||
});
|
||||
},
|
||||
loadRecorders(context: any) {
|
||||
return RecordRepository.getRecorders()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorders', {recorders: response.data});
|
||||
EventBus.$emit('recordersLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders!', error);
|
||||
EventBus.$emit('failedLoadingRecorders', error);
|
||||
});
|
||||
},
|
||||
loadRecorderStates(context: any) {
|
||||
return StateRepository.getRecordersStates()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderStates', {recorderStates: response.data});
|
||||
EventBus.$emit('recorderStatesLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders states!', error);
|
||||
EventBus.$emit('failedLoadingRecorderStates', error);
|
||||
});
|
||||
},
|
||||
loadRecorderState(context: any, recorder_id: number) {
|
||||
return StateRepository.getRecorderState(recorder_id)
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderState', {recorderState: response.data});
|
||||
EventBus.$emit('recorderStateLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorders states!', error);
|
||||
EventBus.$emit('failedLoadingRecorderStates', error);
|
||||
});
|
||||
},
|
||||
loadRecorderModels(context: any) {
|
||||
return RecordRepository.getRecorderModels()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
Vue.$log.debug('Loaded recorder models');
|
||||
context.commit('setRecorderModels', {recorderModels: response.data});
|
||||
EventBus.$emit('recorderModelsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorder models!', error);
|
||||
EventBus.$emit('failedLoadingRecorderModels', error);
|
||||
});
|
||||
},
|
||||
loadRecorderCommands(context: any) {
|
||||
return RecordRepository.getRecorderCommands()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setRecorderCommands', {recorderCommands: response.data});
|
||||
EventBus.$emit('recorderCommandsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading recorder commands!', error);
|
||||
EventBus.$emit('failedLoadingRecorderCommands', error);
|
||||
});
|
||||
},
|
||||
loadVirtualCommands(context: any) {
|
||||
return VirtualCommandRepository.getVirtualCommands()
|
||||
.then((response: any) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setVirtualCommands', {virtualCommands: response.data});
|
||||
EventBus.$emit('virtualCommandsLoaded', response.data);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
Vue.$log.warn('Error loading virtual commands!', error);
|
||||
EventBus.$emit('failedLoadingVirtualCommands', error);
|
||||
});
|
||||
},
|
||||
loadCommands(context: any) {
|
||||
return context.dispatch('loadRecorderCommands').then(() => {
|
||||
return context.dispatch('loadVirtualCommands');
|
||||
});
|
||||
},
|
||||
loadUsers(context: any) {
|
||||
return fetchUsers(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setUsers', {users: response.data});
|
||||
EventBus.$emit('usersLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading users!', error);
|
||||
EventBus.$emit('failedLoadingUsers', error);
|
||||
});
|
||||
},
|
||||
loadUserGroups(context: any) {
|
||||
return fetchUserGroups(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setUserGroups', {groups: response.data});
|
||||
EventBus.$emit('groupsLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading user groups!', error);
|
||||
EventBus.$emit('failedLoadingUserGroups', error);
|
||||
});
|
||||
},
|
||||
loadProfileAuthCheck(context: any) {
|
||||
if (!getters.isAuthenticated) {
|
||||
EventBus.$emit('accessTokenInvalid');
|
||||
if (!getters.isRefreshTokenValid) {
|
||||
Vue.$log.warn('Access and refresh token invalid! User must login again!');
|
||||
EventBus.$emit('refreshTokenInvalid');
|
||||
EventBus.$emit('accessAndRefreshTokenInvalid');
|
||||
} else {
|
||||
return context.dispatch('refreshToken').then(() => {
|
||||
context.commit('loadProfile');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
context.commit('loadProfile');
|
||||
}
|
||||
},
|
||||
loadProfile(context: any) {
|
||||
return fetchProfile(context.state.access_token)
|
||||
.then((response) => {
|
||||
Vue.$log.debug(response);
|
||||
Vue.$log.debug(response.data);
|
||||
context.commit('setProfile', {profile: response.data});
|
||||
EventBus.$emit('profileLoaded', response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error loading profile!', error);
|
||||
EventBus.$emit('failedLoadingProfile', error);
|
||||
});
|
||||
},
|
||||
loadLoginProviders(context: any) {
|
||||
return getProviders()
|
||||
.then((response) => {
|
||||
context.commit('setLoginProviderData', {providers: response.data});
|
||||
EventBus.$emit('loginProvidersLoaded', response.data);
|
||||
});
|
||||
},
|
||||
login(context: any, userData: any) {
|
||||
context.commit('setUserData', {userData});
|
||||
return authenticate(userData)
|
||||
.then((response) => context.commit('setJwtToken', {tokens: response.data}))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating: ', error);
|
||||
EventBus.$emit('failedAuthentication', error);
|
||||
});
|
||||
},
|
||||
logout(context: any, revokeRefreshToken: any) {
|
||||
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
|
||||
if (revokeRefreshToken) {
|
||||
return revokeRefreshKey(context.state.access_token)
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error);
|
||||
EventBus.$emit('failedRevokingRefreshToken', error);
|
||||
});
|
||||
}
|
||||
// this.clearAll();
|
||||
},
|
||||
oidc_login(context: any, redirectionUrl: any) {
|
||||
// context.commit('setUserData', { userData });
|
||||
return oidc_login(redirectionUrl)
|
||||
.then((response) => context.commit('setJwtToken', {tokens: response.data}))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Authenticating: ', error);
|
||||
EventBus.$emit('failedAuthentication', error);
|
||||
});
|
||||
},
|
||||
refreshToken(context: any) {
|
||||
EventBus.$emit('refreshingToken');
|
||||
Vue.$log.debug('Refreshing tokens!');
|
||||
return getFreshToken(context.state.refresh_token)
|
||||
.then((response) => {
|
||||
context.commit('setTokens', {tokens: response.data});
|
||||
Vue.$log.debug('Tokens refreshed!');
|
||||
})
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Refreshing token: ', error);
|
||||
EventBus.$emit('failedRefreshingToken', error);
|
||||
});
|
||||
},
|
||||
resetToken(context: any) {
|
||||
EventBus.$emit('resettingTokens');
|
||||
Vue.$log.debug('Resetting tokens!');
|
||||
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
|
||||
EventBus.$emit('tokensReset');
|
||||
Vue.$log.debug('Tokens reset!');
|
||||
},
|
||||
storeTokens(context: any, tokens: any) {
|
||||
context.commit('setTokens', {tokens});
|
||||
EventBus.$emit('storedTokens');
|
||||
},
|
||||
register(context: any, userData: any) {
|
||||
context.commit('setUserData', {userData});
|
||||
return register(userData)
|
||||
.then(context.dispatch('login', userData))
|
||||
.catch((error) => {
|
||||
Vue.$log.warn('Error Registering: ', error);
|
||||
EventBus.$emit('failedRegistering: ', error);
|
||||
});
|
||||
},
|
||||
submitNewSurvey(context: any, survey: any) {
|
||||
return postNewSurvey(survey, context.state.access_token);
|
||||
},
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
// isolated data mutations
|
||||
setSurveys(sState: any, payload: any) {
|
||||
sState.surveys = payload.surveys;
|
||||
},
|
||||
setSurvey(sState: any, payload: any) {
|
||||
const nQuestions = payload.survey.questions.length;
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
payload.survey.questions[i].choice = null;
|
||||
}
|
||||
sState.currentSurvey = payload.survey;
|
||||
},
|
||||
setRooms(sState: any, payload: any) {
|
||||
sState.rooms = payload.rooms;
|
||||
},
|
||||
setRecorders(sState: any, payload: any) {
|
||||
sState.recorders = payload.recorders;
|
||||
},
|
||||
setRecorderModels(sState: any, payload: any) {
|
||||
sState.recorderModels = payload.recorderModels;
|
||||
},
|
||||
setRecorderCommands(sState: any, payload: any) {
|
||||
sState.recorderCommands = payload.recorderCommands;
|
||||
},
|
||||
setRecorderStates(sState: any, payload: any) {
|
||||
sState.recorderStates = payload.recorderStates;
|
||||
},
|
||||
setRecorderState(sState: any, payload: any) {
|
||||
const n_rec_states = sState.recorderStates.length;
|
||||
const rec_id = payload.recorderState.id;
|
||||
let found = false;
|
||||
for (let i = 0; i < n_rec_states; i++) {
|
||||
if (sState.recorderStates[i].id === rec_id) {
|
||||
sState.recorderStates[i] = payload.recorderState;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
sState.recorderStates.push(payload.recorderState);
|
||||
}
|
||||
},
|
||||
setVirtualCommands(sState: any, payload: any) {
|
||||
sState.virtualCommands = payload.virtualCommands;
|
||||
},
|
||||
setUsers(sState: any, payload: any) {
|
||||
sState.users = payload.users;
|
||||
},
|
||||
setUserGroups(sState: any, payload: any) {
|
||||
sState.userGroups = payload.groups;
|
||||
},
|
||||
setChoice(sState: any, payload: any) {
|
||||
const {questionId, choice} = payload;
|
||||
const nQuestions = sState.currentSurvey.questions.length;
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
if (sState.currentSurvey.questions[i].id === questionId) {
|
||||
sState.currentSurvey.questions[i].choice = choice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
setLoginProviderData(sState: any, payload: any) {
|
||||
Vue.$log.debug('got loginProviders = ', payload);
|
||||
sState.loginProviders = payload.providers;
|
||||
},
|
||||
// probably old ...
|
||||
setUserData(sState: any, payload: any) {
|
||||
Vue.$log.debug('setUserData payload = ', payload);
|
||||
sState.userData = payload.userData;
|
||||
},
|
||||
setProfile(sState: any, payload: any) {
|
||||
Vue.$log.debug('setProfile payload = ', payload);
|
||||
sState.profile = payload.profile;
|
||||
},
|
||||
setJwtToken(sState: any, payload: any) {
|
||||
Vue.$log.debug('setJwtToken payload = ', payload);
|
||||
localStorage.tokens = payload.tokens;
|
||||
sState.access_token = payload.tokens.access_token;
|
||||
sState.refresh_token = payload.tokens.refresh_token;
|
||||
},
|
||||
setTokens(sState: any, payload: any) {
|
||||
Vue.$log.debug('setTokens payload = ', payload);
|
||||
if ('access_token' in payload.tokens) {
|
||||
sState.access_token = payload.tokens.access_token;
|
||||
}
|
||||
if ('refresh_token' in payload.tokens) {
|
||||
sState.refresh_token = payload.tokens.refresh_token;
|
||||
}
|
||||
Vue.$log.debug('access_token: ' + sState.access_token);
|
||||
Vue.$log.debug('refresh_token: ' + sState.refresh_token);
|
||||
},
|
||||
};
|
||||
|
||||
const getters = {
|
||||
// reusable data accessors
|
||||
isAuthenticated(sState: any) {
|
||||
const valid = isValidJwt(sState.access_token);
|
||||
Vue.$log.debug('Access token is valid?: ', valid);
|
||||
Vue.$log.debug(sState.access_token);
|
||||
return valid;
|
||||
},
|
||||
isRefreshTokenValid(sState: any) {
|
||||
const valid = isValidJwt(sState.refresh_token);
|
||||
Vue.$log.debug('Refresh token is valid?: ', valid);
|
||||
Vue.$log.debug('sState.refresh_token');
|
||||
return valid;
|
||||
},
|
||||
getLoginProviders(sState: any) {
|
||||
return sState.loginProviders;
|
||||
},
|
||||
getUserName(sState: any) {
|
||||
if (sState.profile == null || Object.keys(sState.profile).length === 0) {
|
||||
return '';
|
||||
}
|
||||
if (sState.profile.nickname) {
|
||||
return sState.profile.nickname;
|
||||
}
|
||||
return sState.profile.first_name + ' ' + sState.profile.last_name;
|
||||
},
|
||||
// this is probably wrong!!
|
||||
hasAccessRight(sState: any) {
|
||||
(requestedPermission: string) => {
|
||||
return sState.profile.effective_permissions.find((permission: any) => {
|
||||
permission.name === requestedPermission;
|
||||
});
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
actions,
|
||||
mutations,
|
||||
getters,
|
||||
plugins: [createPersistedState()],
|
||||
});
|
||||
|
||||
export default store;
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<HelloWorld v-if="!authenticated" msg="You are not authenticated!"/>
|
||||
<div v-else>
|
||||
<h1>Welcome <span v-if="profile.last_seen!=null">back</span> {{$store.getters.getUserName}}!
|
||||
</h1>
|
||||
<h4 v-if="profile.last_seen!=null">Last login: {{profile.last_seen | moment("dddd, MMMM Do YYYY")}}</h4>
|
||||
<hr/>
|
||||
<ErroneousRecorders/>
|
||||
|
||||
<h2>{{$t('Favorite recorders:')}}</h2>
|
||||
<p>{{$t('Add favorite recorder:')}}</p>
|
||||
<SelectRecorder @recorderSelected="addFavoriteRecorderToProfile"/>
|
||||
<br/>
|
||||
<div v-if="profile.favorite_recorders.length >0">
|
||||
<b-card-group deck>
|
||||
<RecorderState v-for="recorder in profile.favorite_recorders" :recorder="recorder" v-bind:key="recorder.id"/>
|
||||
</b-card-group>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<router-link :to="{name: 'recorder', params: {recorder_id: 1}}">rec 1</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, Vue} from 'vue-property-decorator';
|
||||
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
|
||||
import i18n from '@/plugins/i18n';
|
||||
import ErroneousRecorders from '@/components/ErroneousRecorders.vue';
|
||||
import SelectRecorder from '@/components/SelectRecorder.vue';
|
||||
import RecorderState from '@/components/RecorderState.vue';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const userRepository = getRepository('user');
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
ErroneousRecorders,
|
||||
RecorderState,
|
||||
SelectRecorder,
|
||||
HelloWorld,
|
||||
},
|
||||
})
|
||||
export default class Home extends Vue {
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (this.authenticated) {
|
||||
if (this.profile == null || Object.keys(this.profile).length === 0) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
this.$store.dispatch('loadProfile').then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addFavoriteRecorderToProfile(recorder) {
|
||||
userRepository.addFavoriteRecorder(recorder.recorder_id).then(() => {
|
||||
this.$store.dispatch('loadProfile');
|
||||
});
|
||||
}
|
||||
|
||||
get authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
}
|
||||
|
||||
get profile() {
|
||||
return this.$store.state.profile;
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
border-radius: 25px;
|
||||
padding: 20px;
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
background-color: hsla(0, 0%, 100%, 0.51);
|
||||
fill: #044b94;
|
||||
fill-opacity: 0.9;
|
||||
}
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div class="home">
|
||||
<div class="container">
|
||||
<section class="section">
|
||||
<HelloWorld v-if="!authenticated" msg="You are not authenticated!"/>
|
||||
<div v-else>
|
||||
<h1>Welcome <span v-if="profile.last_seen!=null">back</span> {{$store.getters.getUserName}}!
|
||||
</h1>
|
||||
<h4 v-if="profile.last_seen!=null">Last login: {{profile.last_seen | moment("dddd, MMMM Do YYYY")}}</h4>
|
||||
<hr/>
|
||||
<ErroneousRecorders/>
|
||||
|
||||
<h2>{{$t('Favorite recorders:')}}</h2>
|
||||
<p>{{$t('Add favorite recorder:')}}</p>
|
||||
<SelectRecorder @recorderSelected="addFavoriteRecorderToProfile"/>
|
||||
<br/>
|
||||
<div v-if="profile.favorite_recorders.length >0">
|
||||
<b-card-group deck>
|
||||
<RecorderState v-for="recorder in profile.favorite_recorders" :recorder="recorder" v-bind:key="recorder.id"/>
|
||||
</b-card-group>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<router-link :to="{name: 'recorder', params: {recorder_id: 1}}">rec 1</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Component, Vue} from 'vue-property-decorator';
|
||||
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
|
||||
import i18n from '@/plugins/i18n';
|
||||
import ErroneousRecorders from '@/components/ErroneousRecorders.vue';
|
||||
import SelectRecorder from '@/components/SelectRecorder.vue';
|
||||
import RecorderState from '@/components/RecorderState.vue';
|
||||
import getRepository from '@/api/RepositoryFactory';
|
||||
|
||||
const userRepository = getRepository('user');
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
ErroneousRecorders,
|
||||
RecorderState,
|
||||
SelectRecorder,
|
||||
HelloWorld,
|
||||
},
|
||||
})
|
||||
export default class Home extends Vue {
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (this.authenticated) {
|
||||
if (this.profile == null || Object.keys(this.profile).length === 0) {
|
||||
this.$parent.$data.isLoading = true;
|
||||
this.$store.dispatch('loadProfile').then(() => {
|
||||
this.$parent.$data.isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addFavoriteRecorderToProfile(recorder) {
|
||||
userRepository.addFavoriteRecorder(recorder.recorder_id).then(() => {
|
||||
this.$store.dispatch('loadProfile');
|
||||
});
|
||||
}
|
||||
|
||||
get authenticated() {
|
||||
return this.$store.getters.isAuthenticated;
|
||||
}
|
||||
|
||||
get profile() {
|
||||
return this.$store.state.profile;
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
border-radius: 25px;
|
||||
padding: 20px;
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
background-color: hsla(0, 0%, 100%, 0.51);
|
||||
fill: #044b94;
|
||||
fill-opacity: 0.9;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<p>404 - Not Found -> have you meant... blabla (GT)</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
created() {
|
||||
// window.location.href = "/my-new-404-page.html";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<p>404 - Not Found -> have you meant... blabla (GT)</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
created() {
|
||||
// window.location.href = "/my-new-404-page.html";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user