added oldLogin.vue to modify Login.vue

This commit is contained in:
2020-07-24 16:46:31 +02:00
parent d3df9d5a30
commit f701797639
15 changed files with 21477 additions and 20110 deletions

36331
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +1,60 @@
{ {
"name": "lrc", "name": "lrc",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit" "test:unit": "vue-cli-service test:unit"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.17", "@fortawesome/fontawesome-svg-core": "^1.2.17",
"@fortawesome/free-solid-svg-icons": "^5.8.1", "@fortawesome/free-solid-svg-icons": "^5.8.1",
"@fortawesome/vue-fontawesome": "^0.1.6", "@fortawesome/vue-fontawesome": "^0.1.6",
"@vue/cli": "^3.6.3", "@vue/cli": "^3.6.3",
"axios": "^0.18.1", "axios": "^0.18.1",
"bootstrap": "^4.3.1", "bootstrap": "^4.3.1",
"bootstrap-vue": "^2.0.0-rc.15", "bootstrap-vue": "^2.0.0-rc.15",
"i": "^0.3.6", "i": "^0.3.6",
"jquery": "^3.4.1", "jquery": "^3.5.1",
"js-cookie": "^2.2.0", "js-cookie": "^2.2.0",
"node-sass": "^4.13.0", "node-sass": "^4.14.1",
"npm": "^6.13.1", "npm": "^6.14.7",
"npm-sass": "^2.3.0", "npm-sass": "^2.3.0",
"popper.js": "^1.15.0", "popper.js": "^1.15.0",
"sass": "^1.26.10", "sass": "^1.26.10",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"vee-validate": "^2.2.4", "vee-validate": "^2.2.4",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-axios": "^2.1.4", "vue-axios": "^2.1.4",
"vue-class-component": "^6.0.0", "vue-class-component": "^6.0.0",
"vue-cookies": "^1.5.13", "vue-cookies": "^1.5.13",
"vue-flag-icon": "^1.0.6", "vue-flag-icon": "^1.0.6",
"vue-i18n": "^8.9.0", "vue-i18n": "^8.9.0",
"vue-moment": "^4.0.0", "vue-moment": "^4.1.0",
"vue-property-decorator": "^7.0.0", "vue-property-decorator": "^7.0.0",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue-socket.io-extended": "^4.0.1", "vue-socket.io-extended": "^4.0.1",
"vue-spinner": "^1.0.3", "vue-spinner": "^1.0.3",
"vue-sweetalert2": "^1.6.4", "vue-sweetalert2": "^1.6.4",
"vuejs-logger": "^1.5.3", "vuejs-logger": "^1.5.3",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-persistedstate": "^2.5.4", "vuex-persistedstate": "^2.5.4",
"vuex-typex": "^3.1.4" "vuex-typex": "^3.1.4"
}, },
"devDependencies": { "devDependencies": {
"@types/chai": "^4.1.0", "@types/chai": "^4.1.0",
"@types/mocha": "^5.2.4", "@types/mocha": "^5.2.4",
"@vue/cli-plugin-babel": "^3.4.0", "@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-typescript": "^3.4.0", "@vue/cli-plugin-typescript": "^3.4.0",
"@vue/cli-plugin-unit-mocha": "^3.4.0", "@vue/cli-plugin-unit-mocha": "^3.4.0",
"@vue/cli-service": "^3.6.0", "@vue/cli-service": "^3.6.0",
"@vue/test-utils": "^1.0.0-beta.20", "@vue/test-utils": "^1.0.0-beta.20",
"bootstrap-sass": "^3.4.1", "bootstrap-sass": "^3.4.1",
"chai": "^4.1.2", "chai": "^4.1.2",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"typescript": "^3.0.0", "typescript": "^3.0.0",
"vue-template-compiler": "^2.6.10" "vue-template-compiler": "^2.6.10"
} }
} }

View File

@@ -1,256 +1,256 @@
<template> <template>
<div id="app"> <div id="app">
<div id="bg"> <div id="bg">
<img src="./assets/lens.jpg" alt=""> <img src="./assets/lens.jpg" alt="">
</div> </div>
<sync-loader :loading="isLoading"></sync-loader> <sync-loader :loading="isLoading"></sync-loader>
<b-alert <b-alert
:show="dismissCountDown" :show="dismissCountDown"
dismissible dismissible
variant="danger" variant="danger"
@dismissed="dismissCountDown=0" @dismissed="dismissCountDown=0"
@dismiss-count-down="countDownChanged" @dismiss-count-down="countDownChanged"
> >
{{alertMessage}} {{alertMessage}}
<b-progress <b-progress
variant="error" variant="error"
:max="dismissSecs" :max="dismissSecs"
:value="dismissCountDown" :value="dismissCountDown"
height="4px" height="4px"
></b-progress> ></b-progress>
</b-alert> </b-alert>
<div id="nav"> <div id="nav">
<b-navbar toggleable="lg" type="dark" variant="dark"> <b-navbar toggleable="lg" type="dark" variant="dark">
<b-navbar-brand to="/"> <b-navbar-brand to="/">
<img src="https://placekitten.com/g/30/30" class="d-inline-block align-top" alt="Kitten"> <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 LRC - <strong>L</strong>ecture <strong>R</strong>ecord <strong>C</strong>ontrol
</b-navbar-brand> </b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle> <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav> <b-collapse id="nav-collapse" is-nav>
<b-navbar-nav> <b-navbar-nav>
<b-nav-item to="/about">About</b-nav-item> <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: '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: 'recorders'}">{{ $t('Recorders') }}</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'commands'}">{{ $t('Commands') }}</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-nav-item :to="{name: 'test'}">Test</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
<!-- Right aligned nav items --> <!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto"> <b-navbar-nav class="ml-auto">
<b-nav-form> <b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input> <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-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
</b-nav-form> </b-nav-form>
<b-nav-item-dropdown split split-to="admin" variant="outline-danger" :text="$t('admin')"> <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.user'}">{{ $t('user') }}</b-dropdown-item>
<b-dropdown-item :to="{name: 'admin.group'}">{{ $t('group') }}</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-dropdown-item href="#">Something else here...</b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
<b-nav-item-dropdown text="Lang" right> <b-nav-item-dropdown text="Lang" right>
<b-dropdown-item v-for="(lang, i) in langs" <b-dropdown-item v-for="(lang, i) in langs"
v-bind:key="lang" v-bind:key="lang"
@click="$i18n.locale=lang">{{ lang }} @click="$i18n.locale=lang">{{ lang }}
</b-dropdown-item> </b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
<b-nav-item-dropdown v-if="authenticated" right> <b-nav-item-dropdown v-if="authenticated" right>
<!-- Using 'button-content' slot --> <!-- Using 'button-content' slot -->
<template slot="button-content"><em>User</em></template> <template slot="button-content"><em>User</em></template>
<b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item> <b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item>
<b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item> <b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item>
</b-nav-item-dropdown> </b-nav-item-dropdown>
<b-nav-item v-else to="/login">Login</b-nav-item> <b-nav-item v-else to="/login">Login</b-nav-item>
</b-navbar-nav> </b-navbar-nav>
</b-collapse> </b-collapse>
</b-navbar> </b-navbar>
<span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span> <span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span>
<span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~" <span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~"
@click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span> @click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span>
<span v-if="refreshTokenValidity">&nbsp;|&nbsp;({{refreshTokenValidity}}) <span v-if="refreshTokenValidity">&nbsp;|&nbsp;({{refreshTokenValidity}})
<input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession"> <input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession">
<label for="auto_renew_cb">{{$t('auto renew session')}}</label> <label for="auto_renew_cb">{{$t('auto renew session')}}</label>
</span> </span>
<span v-else>{{$t('Can\'t renew session please login again!')}}</span> <span v-else>{{$t('Can\'t renew session please login again!')}}</span>
</div> </div>
<div id="content_frame"> <div id="content_frame">
<router-view :style="main_style"/> <router-view :style="main_style"/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {EventBus, getRemainingJwtValiditySeconds} from '@/utils'; import {EventBus, getRemainingJwtValiditySeconds} from '@/utils';
import SyncLoader from 'vue-spinner/src/SyncLoader.vue'; import SyncLoader from 'vue-spinner/src/SyncLoader.vue';
export default { export default {
components: { components: {
SyncLoader, SyncLoader,
}, },
data() { data() {
return { return {
isLoading: false, isLoading: false,
tokenValidity: -1, tokenValidity: -1,
refreshFailed: false, refreshFailed: false,
refreshTokenValidity: -1, refreshTokenValidity: -1,
showAlert: true, showAlert: true,
alertMessage: 'NO MESSAGE PROVIDED', alertMessage: 'NO MESSAGE PROVIDED',
langs: ['de', 'en', 'es'], langs: ['de', 'en', 'es'],
dismissSecs: 5, dismissSecs: 5,
dismissCountDown: 0, dismissCountDown: 0,
autoRenewSession: true, autoRenewSession: true,
main_style: {} main_style: {}
}; };
}, },
methods: { methods: {
showErrorMessage(msg) { showErrorMessage(msg) {
this.isLoading = false; this.isLoading = false;
this.dismissCountDown = this.dismissSecs; this.dismissCountDown = this.dismissSecs;
this.alertMessage = msg; this.alertMessage = msg;
}, },
countDownChanged(dismissCountDown) { countDownChanged(dismissCountDown) {
this.dismissCountDown = dismissCountDown; this.dismissCountDown = dismissCountDown;
}, },
logout() { logout() {
this.$store.dispatch('logout', {revokeRefreshToken: true}); this.$store.dispatch('logout', {revokeRefreshToken: true});
this.$router.push({name: 'home'}); this.$router.push({name: 'home'});
}, },
refreshToken() { refreshToken() {
this.$store.dispatch('refreshToken'); this.$store.dispatch('refreshToken');
}, },
}, },
mounted() { mounted() {
EventBus.$on('failedLoadingRecorders', (msg) => { EventBus.$on('failedLoadingRecorders', (msg) => {
this.showErrorMessage(msg); this.showErrorMessage(msg);
}); });
EventBus.$on('failedLoadingRooms', (msg) => { EventBus.$on('failedLoadingRooms', (msg) => {
this.showErrorMessage(msg); this.showErrorMessage(msg);
}); });
EventBus.$on('failedRefreshingToken', (msg) => { EventBus.$on('failedRefreshingToken', (msg) => {
this.refreshFailed = true; this.refreshFailed = true;
}); });
this.$nextTick(() => { this.$nextTick(() => {
window.setInterval(() => { window.setInterval(() => {
// this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token)); // this.$log.debug(getRemainingJwtValiditySeconds(this.$store.state.access_token));
const tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token); const tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token);
// this.tokenValidity = this.tokenValidity.format('mm:ss'); // this.tokenValidity = this.tokenValidity.format('mm:ss');
const refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token); const refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
// this.$log.debug(this.$store.state); // this.$log.debug(this.$store.state);
if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) { if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) {
this.$store.dispatch('refreshToken'); // renew access token this.$store.dispatch('refreshToken'); // renew access token
} }
if (this.autoRenewSession && this.refreshFailed) { if (this.autoRenewSession && this.refreshFailed) {
this.$store.dispatch('resetToken'); // delete all token info if refresh fails this.$store.dispatch('resetToken'); // delete all token info if refresh fails
this.$router.push({name: 'login'}); this.$router.push({name: 'login'});
this.refreshFailed = false; this.refreshFailed = false;
} }
if (isNaN(tokenValidity)) { if (isNaN(tokenValidity)) {
this.tokenValidity = false; this.tokenValidity = false;
} else { } else {
this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5); this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5);
} }
if (isNaN(tokenValidity)) { if (isNaN(tokenValidity)) {
this.refreshTokenValidity = false; this.refreshTokenValidity = false;
} else { } else {
this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8); this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8);
} }
}, 1000); }, 1000);
}); });
}, },
computed: { computed: {
authenticated() { authenticated() {
return this.$store.getters.isAuthenticated; return this.$store.getters.isAuthenticated;
}, },
profile() { profile() {
return this.$store.state.profile; return this.$store.state.profile;
}, },
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
@import '../node_modules/bootstrap/scss/bootstrap.scss'; @import '../node_modules/bootstrap/scss/bootstrap.scss';
#app { #app {
font-family: 'Avenir', Helvetica, Arial, sans-serif; font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: #385875; color: #385875;
} }
#bg { #bg {
z-index: -100; z-index: -100;
position: fixed; position: fixed;
top: -50%; top: -50%;
left: -50%; left: -50%;
width: 200%; width: 200%;
height: 200%; height: 200%;
} }
#bg img { #bg img {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
margin: auto; margin: auto;
min-width: 50%; min-width: 50%;
min-height: 50%; min-height: 50%;
} }
h1 { h1 {
color: #275d37; color: #275d37;
} }
#nav { #nav {
padding: 0px; padding: 0px;
text-align: center; text-align: center;
a { a {
font-weight: bold; font-weight: bold;
color: #7ea8d6; color: #7ea8d6;
&.router-link-exact-active { &.router-link-exact-active {
color: #42b983; color: #42b983;
} }
} }
} }
/* Absolute Center Spinner */ /* Absolute Center Spinner */
.v-spinner { .v-spinner {
position: fixed; position: fixed;
z-index: 999; z-index: 999;
// height: 2em; // height: 2em;
// width: 2em; // width: 2em;
overflow: visible; overflow: visible;
margin: auto; margin: auto;
top: 50%; top: 50%;
left: 50%; left: 50%;
bottom: 0; bottom: 0;
right: 0; right: 0;
} }
/* Transparent Overlay */ /* Transparent Overlay */
.v-spinner:before { .v-spinner:before {
content: ''; content: '';
display: block; display: block;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(0, 0, 0, 0.2);
} }
</style> </style>

View File

@@ -1,17 +1,17 @@
// groupRepository.ts // groupRepository.ts
// @ts-ignore // @ts-ignore
import Repository from './Repository'; import Repository from './Repository';
const recorderStateResource = '/state/recorder'; const recorderStateResource = '/state/recorder';
export default { export default {
getRecordersStates() { getRecordersStates() {
return Repository.get(`${recorderStateResource}`); return Repository.get(`${recorderStateResource}`);
}, },
getRecorderState(recorderId: number) { getRecorderState(recorderId: number) {
return Repository.get(`${recorderStateResource}/${recorderId}`); return Repository.get(`${recorderStateResource}/${recorderId}`);
}, },
}; };

View File

@@ -1,32 +1,32 @@
// groupRepository.ts // groupRepository.ts
// @ts-ignore // @ts-ignore
import Repository from './Repository'; import Repository from './Repository';
const virtualCommandResource = '/virtual_command'; const virtualCommandResource = '/virtual_command';
import {dictEmptyValToNull} from '@/utils'; import {dictEmptyValToNull} from '@/utils';
export default { export default {
getVirtualCommands() { getVirtualCommands() {
return Repository.get(`${virtualCommandResource}`); return Repository.get(`${virtualCommandResource}`);
}, },
getVirtualCommand(virtualCommandId: number) { getVirtualCommand(virtualCommandId: number) {
return Repository.get(`${virtualCommandResource}/${virtualCommandId}`); return Repository.get(`${virtualCommandResource}/${virtualCommandId}`);
}, },
deleteVirtualCommand(virtualCommandId: number) { deleteVirtualCommand(virtualCommandId: number) {
return Repository.delete(`${virtualCommandResource}/${virtualCommandId}`); return Repository.delete(`${virtualCommandResource}/${virtualCommandId}`);
}, },
createVirtualCommand(virtualCommandData: any) { createVirtualCommand(virtualCommandData: any) {
return Repository.post(`${virtualCommandResource}`, dictEmptyValToNull(virtualCommandData)); return Repository.post(`${virtualCommandResource}`, dictEmptyValToNull(virtualCommandData));
}, },
updateVirtualCommand(virtualCommandId: number, virtualCommandData: any) { updateVirtualCommand(virtualCommandId: number, virtualCommandData: any) {
return Repository.put(`${virtualCommandResource}/${virtualCommandId}`, return Repository.put(`${virtualCommandResource}/${virtualCommandId}`,
dictEmptyValToNull(virtualCommandData)); dictEmptyValToNull(virtualCommandData));
}, },
}; };

View File

@@ -1,341 +1,341 @@
<template> <template>
<div class="container"> <div class="container">
<section class="section"> <section class="section">
<h1 class="title">{{ $t('Manage Commands') }}</h1> <h1 class="title">{{ $t('Manage Commands') }}</h1>
<p class="lead"> <p class="lead">
{{ $t('List, create and delete') }} <strong>{{ $t('commands') }}</strong> {{ $t('List, create and delete') }} <strong>{{ $t('commands') }}</strong>
</p> </p>
<br/> <br/>
<b-tabs v-model="tabIndex" card> <b-tabs v-model="tabIndex" card>
<b-tab title="Command list" active> <b-tab title="Command list" active>
<template slot="title"> <template slot="title">
<font-awesome-icon icon="list"/>&nbsp;<font-awesome-icon icon="cogs"/> <font-awesome-icon icon="list"/>&nbsp;<font-awesome-icon icon="cogs"/>
<strong>command</strong>&nbsp;<i>list</i> <strong>command</strong>&nbsp;<i>list</i>
</template> </template>
<p>{{ $t('There are')}}&nbsp;{{commands.length}}&nbsp;{{ $t('recorder commands defined')}}:</p> <p>{{ $t('There are')}}&nbsp;{{commands.length}}&nbsp;{{ $t('recorder commands defined')}}:</p>
<b-card-group deck> <b-card-group deck>
<b-card class="mb-2" style="max-width: 30rem; min-width:20rem;" v-for="(command) in commands" <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"> :header="command.name + ' (' +command.recorder_model.name+ ')'" v-bind:key="command.id">
<b-card-text> <b-card-text>
<h5 class="card-title">{{ $t('name') }}:&nbsp; <h5 class="card-title">{{ $t('name') }}:&nbsp;
<span>{{command.name}}&nbsp;</span> <span>{{command.name}}&nbsp;</span>
</h5> </h5>
<p class="card-text"> <p class="card-text">
<small><strong>{{ $t('alternative_name') }}:</strong>&nbsp; <small><strong>{{ $t('alternative_name') }}:</strong>&nbsp;
<span v-if="!formEditField[command.id+'_alternative_name']">{{command.alternative_name}}&nbsp; <span v-if="!formEditField[command.id+'_alternative_name']">{{command.alternative_name}}&nbsp;
<a class="float-right badge badge-pill badge-primary"> <a class="float-right badge badge-pill badge-primary">
<font-awesome-icon <font-awesome-icon
@click="initRecCommandUpdate(command, 'alternative_name')" @click="initRecCommandUpdate(command, 'alternative_name')"
icon="pencil-alt"/> icon="pencil-alt"/>
</a> </a>
</span> </span>
<b-input-group v-else> <b-input-group v-else>
<b-form-input :id="command.id+'_alternative_name'" name="alternative_name" <b-form-input :id="command.id+'_alternative_name'" name="alternative_name"
v-model="updateValues[command.id+'_alternative_name']" v-model="updateValues[command.id+'_alternative_name']"
v-validate="'required|min:3'" v-validate="'required|min:3'"
v-bind:class="{'is-danger': errors.has('alternative_name'), 'is-invalid': errors.has('alternative_name')}" v-bind:class="{'is-danger': errors.has('alternative_name'), 'is-invalid': errors.has('alternative_name')}"
class="form-control" type="text" class="form-control" type="text"
:placeholder="'Alternative name ('+command.alternative_name +')'" :placeholder="'Alternative name ('+command.alternative_name +')'"
required></b-form-input> required></b-form-input>
<b-input-group-append> <b-input-group-append>
<b-button :disabled="errors.has('alternative_name')" <b-button :disabled="errors.has('alternative_name')"
@click="updateRecCommand(command.id, 'alternative_name')" @click="updateRecCommand(command.id, 'alternative_name')"
variant="outline-success"> variant="outline-success">
<font-awesome-icon icon="check"></font-awesome-icon> <font-awesome-icon icon="check"></font-awesome-icon>
</b-button> </b-button>
</b-input-group-append> </b-input-group-append>
</b-input-group> </b-input-group>
</small> </small>
</p> </p>
<p class="card-text"> <p class="card-text">
<small><strong>{{ $t('description') }}:</strong>&nbsp; <small><strong>{{ $t('description') }}:</strong>&nbsp;
<span v-if="!formEditField[command.id+'_description']">{{command.description}}&nbsp; <span v-if="!formEditField[command.id+'_description']">{{command.description}}&nbsp;
<a class="float-right badge badge-pill badge-info"> <a class="float-right badge badge-pill badge-info">
<font-awesome-icon <font-awesome-icon
@click="initRecCommandUpdate(command, 'description')" @click="initRecCommandUpdate(command, 'description')"
icon="pencil-alt"/> icon="pencil-alt"/>
</a> </a>
</span> </span>
<textarea class="textarea form-control" v-else name="comment" <textarea class="textarea form-control" v-else name="comment"
v-model="updateValues[command.id+'_description']" v-model="updateValues[command.id+'_description']"
:placeholder="'Comment ('+command.description +')'" :placeholder="'Comment ('+command.description +')'"
@blur="updateRecCommand(command.id, 'description')"></textarea> @blur="updateRecCommand(command.id, 'description')"></textarea>
</small> </small>
</p> </p>
<hr/> <hr/>
<div v-if="command.recorder_model"> <div v-if="command.recorder_model">
<p class="card-text"><strong>{{ $t('Recorder') }} {{ $t('model') }}:</strong>&nbsp;{{command.recorder_model.name}}&nbsp;</p> <p class="card-text"><strong>{{ $t('Recorder') }} {{ $t('model') }}:</strong>&nbsp;{{command.recorder_model.name}}&nbsp;</p>
</div> </div>
<div v-else> <div v-else>
<p class="card-text"><strong>{{ $t('Recorder') }}:</strong>&nbsp;{{ <p class="card-text"><strong>{{ $t('Recorder') }}:</strong>&nbsp;{{
$t('no_recorder_model_defined')}}</p> $t('no_recorder_model_defined')}}</p>
</div> </div>
</b-card-text> </b-card-text>
<div slot="footer"> <div slot="footer">
<small class="text-muted"> <small class="text-muted">
<p>{{ $t('created')}}: {{command.created_at | moment("dddd, MMMM Do YYYY")}} <p>{{ $t('created')}}: {{command.created_at | moment("dddd, MMMM Do YYYY")}}
</p> </p>
</small> </small>
</div> </div>
</b-card> </b-card>
</b-card-group> </b-card-group>
</b-tab> </b-tab>
<b-tab title="Create command"> <b-tab title="Create command">
<template slot="title"> <template slot="title">
<font-awesome-icon icon="plus"/> <font-awesome-icon icon="plus"/>
<i>{{$t('create')}}</i>&nbsp;<font-awesome-icon icon="cogs"/> <i>{{$t('create')}}</i>&nbsp;<font-awesome-icon icon="cogs"/>
<strong>{{$t('virtual')}} {{$t('command')}}</strong> <strong>{{$t('virtual')}} {{$t('command')}}</strong>
</template> </template>
<b-card-text> <b-card-text>
<p>{{ $t('Create a new command')}}:</p> <p>{{ $t('Create a new command')}}:</p>
<!-- form starts here --> <!-- form starts here -->
<form v-on:submit.prevent="savecommand()"> <form v-on:submit.prevent="savecommand()">
<section class="form"> <section class="form">
<div class="form-group row"> <div class="form-group row">
<label class="label required col-sm-2 col-form-label">{{ $t('name') }}</label> <label class="label required col-sm-2 col-form-label">{{ $t('name') }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input name="name" <input name="name"
v-model="form.name" v-model="form.name"
v-validate="'required|min:3'" v-validate="'required|min:3'"
v-bind:class="{'is-danger': errors.has('name'), 'is-invalid': errors.has('name')}" v-bind:class="{'is-danger': errors.has('name'), 'is-invalid': errors.has('name')}"
class="form-control" type="text" placeholder="command name" required> class="form-control" type="text" placeholder="command name" required>
</div> </div>
<p class="col-sm-4" v-show="errors.has('name')"> <p class="col-sm-4" v-show="errors.has('name')">
{{ errors.first('name') }} {{ errors.first('name') }}
</p> </p>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="label col-sm-2 col-form-label">{{ $t('alternate_name') }}</label> <label class="label col-sm-2 col-form-label">{{ $t('alternate_name') }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input name="alternate_name" <input name="alternate_name"
v-model="form.alternate_name" v-model="form.alternate_name"
class="form-control" type="text" placeholder="Alternate name"> class="form-control" type="text" placeholder="Alternate name">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="label required col-sm-2 col-form-label">{{ $t('number') }}</label> <label class="label required col-sm-2 col-form-label">{{ $t('number') }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input name="number" <input name="number"
v-model="form.number" v-model="form.number"
v-validate="'required|min:3'" v-validate="'required|min:3'"
v-bind:class="{'is-danger': errors.has('number'), 'is-invalid': errors.has('number')}" v-bind:class="{'is-danger': errors.has('number'), 'is-invalid': errors.has('number')}"
class="form-control" type="text" placeholder="command number" required> class="form-control" type="text" placeholder="command number" required>
</div> </div>
<p class="col-sm-4" v-show="errors.has('number')"> <p class="col-sm-4" v-show="errors.has('number')">
{{ errors.first('number') }} {{ errors.first('number') }}
</p> </p>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="label col-sm-2 col-form-label">{{ $t('comment') }}</label> <label class="label col-sm-2 col-form-label">{{ $t('comment') }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<textarea class="textarea form-control" placeholder="Comments, remarks, notes, etc." <textarea class="textarea form-control" placeholder="Comments, remarks, notes, etc."
v-model="form.comment"></textarea> v-model="form.comment"></textarea>
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="label col-sm-2 col-form-label">{{ $t('recorder') }}</label> <label class="label col-sm-2 col-form-label">{{ $t('recorder') }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<select class="form-control" v-model="form.recorder_id"> <select class="form-control" v-model="form.recorder_id">
<option value="">No recorder selected</option> <option value="">No recorder selected</option>
<option v-for="recorder in recorders" v-bind:value="recorder.id"> <option v-for="recorder in recorders" v-bind:value="recorder.id">
{{ recorder.name }} {{ recorder.name }}
</option> </option>
</select> </select>
</div> </div>
</div> </div>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
<button <button
v-bind:disabled="errors.any()" v-bind:disabled="errors.any()"
type="submit" type="submit"
class="btn btn-primary"> class="btn btn-primary">
Create command Create command
</button> </button>
</div> </div>
</div> </div>
</section> </section>
</form> </form>
</b-card-text> </b-card-text>
</b-tab> </b-tab>
</b-tabs> </b-tabs>
</section> </section>
<hr> <hr>
<!-- <!--
<div class="column"> <div class="column">
<section class="section" id="results"> <section class="section" id="results">
<div class="box"> <div class="box">
<ul> <ul>
<li v-for="(item, k) in form"> <li v-for="(item, k) in form">
<strong>{{ k }}:</strong> {{ item }} <strong>{{ k }}:</strong> {{ item }}
</li> </li>
</ul> </ul>
</div> </div>
</section> </section>
</div> </div>
<div class="column"> <div class="column">
<section class="section"> <section class="section">
{{recorders}} {{recorders}}
</section> </section>
</div> </div>
--> -->
</div> </div>
</template> </template>
<script> <script>
import {EventBus} from '@/utils'; import {EventBus} from '@/utils';
import PulseLoader from 'vue-spinner/src/PulseLoader.vue'; import PulseLoader from 'vue-spinner/src/PulseLoader.vue';
import getRepository from '@/api/RepositoryFactory'; import getRepository from '@/api/RepositoryFactory';
const recorderRepository = getRepository('recorder'); const recorderRepository = getRepository('recorder');
const commandRepository = getRepository('command'); const commandRepository = getRepository('command');
export default { export default {
components: { components: {
PulseLoader, PulseLoader,
}, },
props: [], props: [],
data() { data() {
return { return {
tabIndex: 0, tabIndex: 0,
updateValues: {}, updateValues: {},
formEditField: {}, formEditField: {},
show_assigned_recorders: false, show_assigned_recorders: false,
form: { form: {
name: null, name: null,
alternate_name: null, alternate_name: null,
number: null, number: null,
comment: null, comment: null,
recorder_id: null, recorder_id: null,
}, },
}; };
}, },
methods: { methods: {
saveCommand() { saveCommand() {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
commandRepository.createCommand(this.form) commandRepository.createCommand(this.form)
.then(() => { .then(() => {
this.$store.dispatch('loadCommands') this.$store.dispatch('loadCommands')
.then(() => { .then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
this.tabIndex = 0; this.tabIndex = 0;
}); });
}).catch((msg) => { }).catch((msg) => {
this.showErrorMessage('Could not safe command!'); this.showErrorMessage('Could not safe command!');
this.$log.warn(msg); this.$log.warn(msg);
}); });
}, },
initCommandUpdate(command, fieldName) { initCommandUpdate(command, fieldName) {
this.$set(this.formEditField, command.id + '_' + fieldName, true); this.$set(this.formEditField, command.id + '_' + fieldName, true);
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]); this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
}, },
updateCommand(id, fieldName) { updateCommand(id, fieldName) {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
const data = {}; const data = {};
data[fieldName] = this.updateValues[id + '_' + fieldName]; data[fieldName] = this.updateValues[id + '_' + fieldName];
commandRepository.updateCommand(id, data) commandRepository.updateCommand(id, data)
.then(() => { .then(() => {
this.$store.dispatch('loadCommands') this.$store.dispatch('loadCommands')
.then(() => { .then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
this.formEditField[id + '_' + fieldName] = false; this.formEditField[id + '_' + fieldName] = false;
}); });
}); });
}, },
deleteCommand(id) { deleteCommand(id) {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
commandRepository.deleteCommand(id) commandRepository.deleteCommand(id)
.then(() => { .then(() => {
this.$store.dispatch('loadCommands') this.$store.dispatch('loadCommands')
.then(() => { .then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
}); });
}); });
}, },
initRecCommandUpdate(command, fieldName) { initRecCommandUpdate(command, fieldName) {
this.$set(this.formEditField, command.id + '_' + fieldName, true); this.$set(this.formEditField, command.id + '_' + fieldName, true);
this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]); this.$set(this.updateValues, command.id + '_' + fieldName, command[fieldName]);
}, },
updateRecCommand(id, fieldName) { updateRecCommand(id, fieldName) {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
const data = {}; const data = {};
data[fieldName] = this.updateValues[id + '_' + fieldName]; data[fieldName] = this.updateValues[id + '_' + fieldName];
recorderRepository.updateRecorderCommand(id, data) recorderRepository.updateRecorderCommand(id, data)
.then(() => { .then(() => {
this.$store.dispatch('loadRecorderCommands') this.$store.dispatch('loadRecorderCommands')
.then(() => { .then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
this.formEditField[id + '_' + fieldName] = false; this.formEditField[id + '_' + fieldName] = false;
}); });
}); });
}, },
showErrorMessage(msg) { showErrorMessage(msg) {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
this.$parent.$data.showAlert = true; this.$parent.$data.showAlert = true;
this.$parent.$data.alertMessage = msg; this.$parent.$data.alertMessage = msg;
}, },
}, },
mounted() { mounted() {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
this.$parent.$data.showAlert = false; this.$parent.$data.showAlert = false;
this.$store.dispatch('loadCommands') this.$store.dispatch('loadCommands')
.then(() => { .then(() => {
this.$store.dispatch('loadRecorders') this.$store.dispatch('loadRecorders')
.then(() => { .then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
}); });
}); });
}, },
computed: { computed: {
options() { options() {
return { return {
recorders: [ recorders: [
{value: 8, text: 'SMP 351 AudiMax'}, {value: 8, text: 'SMP 351 AudiMax'},
{value: 13, text: 'SMP 351 HMU'}, {value: 13, text: 'SMP 351 HMU'},
], ],
}; };
}, },
commands() { commands() {
return this.$store.state.recorderCommands; return this.$store.state.recorderCommands;
}, },
recorders() { recorders() {
return this.$store.state.recorders; return this.$store.state.recorders;
}, },
}, },
}; };
</script> </script>
<style> <style>
.comment { .comment {
white-space: pre-wrap; white-space: pre-wrap;
} }
.card:hover { .card:hover {
background-color: whitesmoke; background-color: whitesmoke;
} }
.required:after { .required:after {
content: " *"; content: " *";
} }
</style> </style>

View File

@@ -1,71 +1,71 @@
<template> <template>
<div v-if="authenticated && faulty_recorders_states.length > 0"> <div v-if="authenticated && faulty_recorders_states.length > 0">
<h2>Recorders with detected problems:</h2> <h2>Recorders with detected problems:</h2>
<b-card-group deck> <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;" <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" :header="r_s.name"
v-bind:key="r_s.id"> v-bind:key="r_s.id">
<b-card-text> <b-card-text>
<h5 class="card-title"> <h5 class="card-title">
<strong>{{$t('Problem')}}:</strong>&nbsp;{{r_s.msg}} <strong>{{$t('Problem')}}:</strong>&nbsp;{{r_s.msg}}
</h5> </h5>
<b-button :to="{name: 'recorder', params: {recorder_id: r_s.id}}" variant="primary">Go to recorder <b-button :to="{name: 'recorder', params: {recorder_id: r_s.id}}" variant="primary">Go to recorder
</b-button> </b-button>
</b-card-text> </b-card-text>
<div slot="footer"> <div slot="footer">
<small> <small>
<p> <p>
<span v-if="r_s.time_stamp"><strong>{{$t('time stamp')}}:</strong>&nbsp;{{r_s.time_stamp}}</span> <span v-if="r_s.time_stamp"><strong>{{$t('time stamp')}}:</strong>&nbsp;{{r_s.time_stamp}}</span>
</p> </p>
</small> </small>
</div> </div>
</b-card> </b-card>
</b-card-group> </b-card-group>
<hr/> <hr/>
</div> </div>
<div v-else> <div v-else>
<p>You must be signed in in order to see recorders!</p> <p>You must be signed in in order to see recorders!</p>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator'; import {Component, Prop, Vue} from 'vue-property-decorator';
import StateRepository from '@/api/stateRepository'; import StateRepository from '@/api/stateRepository';
import VirtualCommandRepository from "@/api/virtualCommandRepository"; import VirtualCommandRepository from "@/api/virtualCommandRepository";
@Component @Component
export default class ErroneousRecorders extends Vue { export default class ErroneousRecorders extends Vue {
get authenticated() { get authenticated() {
return this.$store.getters.isAuthenticated; return this.$store.getters.isAuthenticated;
} }
get faulty_recorders_states() { get faulty_recorders_states() {
return this.$store.state.recorderStates.filter((s: any) => { return this.$store.state.recorderStates.filter((s: any) => {
return !s.state_ok return !s.state_ok
}); });
} }
private mounted() { private mounted() {
this.$store.dispatch('loadRecorderStates'); this.$store.dispatch('loadRecorderStates');
} }
} }
</script> </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"> <style scoped lang="scss">
h3 { h3 {
margin: 40px 0 0; margin: 40px 0 0;
} }
ul { ul {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
} }
li { li {
display: inline-block; display: inline-block;
margin: 0 10px; margin: 0 10px;
} }
</style> </style>

View File

@@ -9,23 +9,18 @@
<p class="subtitle error-msg">{{ errorMsg }}</p> <p class="subtitle error-msg">{{ errorMsg }}</p>
</div> </div>
</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="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"> <div class="field">
<label class="label is-large" for="email">Email:</label> <label class="label is-large" for="email">Email:</label>
<div class="control"> <div class="control">

153
src/components/OldLogin.vue Normal file
View 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>

View File

@@ -1,323 +1,323 @@
<!-- components/Profile.vue --> <!-- components/Profile.vue -->
<template> <template>
<div> <div>
<section class="hero is-primary"> <section class="hero is-primary">
<div class="hero-body"> <div class="hero-body">
<div class="container has-text-centered"> <div class="container has-text-centered">
<h3> <h3>
<div class="text-center"> <div class="text-center">
<font-awesome-icon class="float-left" icon="arrow-circle-left" @click="previousRecorder()"/> <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;" <input type="number" style="font-size: small; max-width: 48px; text-align: center;"
v-model="new_recorder_id" @blur="manually_set_recorder_id()" v-model="new_recorder_id" @blur="manually_set_recorder_id()"
@input="manually_set_recorder_id()"> @input="manually_set_recorder_id()">
<font-awesome-icon class="float-right" icon="arrow-circle-right" @click="nextRecorder()"/> <font-awesome-icon class="float-right" icon="arrow-circle-right" @click="nextRecorder()"/>
</div> </div>
</h3> </h3>
<div class="clearfix"> <div class="clearfix">
<!--Route params: {{$route.params.recorder_id}}--> <!--Route params: {{$route.params.recorder_id}}-->
<b-img left style="margin-right: 20px;" src="https://picsum.photos/164/164/?image=58" <b-img left style="margin-right: 20px;" src="https://picsum.photos/164/164/?image=58"
alt="Left image"></b-img> alt="Left image"></b-img>
<h2 class="title"> <h2 class="title">
<font-awesome-icon v-if="recorder.locked" style="color: red;" icon="lock" <font-awesome-icon v-if="recorder.locked" style="color: red;" icon="lock"
@dblclick="unlock()"/> @dblclick="unlock()"/>
<font-awesome-icon v-else icon="lock-open" style="color: green;" @click="lock()"/> <font-awesome-icon v-else icon="lock-open" style="color: green;" @click="lock()"/>
&nbsp;{{recorder.name}} &nbsp;{{recorder.name}}
</h2> </h2>
<p> <p>
<span v-b-tooltip.hover :title="$t('model_name')"> <span v-b-tooltip.hover :title="$t('model_name')">
<font-awesome-icon icon="tag"/>&nbsp;{{recorder.model_name ? recorder.model_name : $t("undefined")}}<br/> <font-awesome-icon icon="tag"/>&nbsp;{{recorder.model_name ? recorder.model_name : $t("undefined")}}<br/>
</span> </span>
<span v-b-tooltip.hover :title="$t('firmware_version')"> <span v-b-tooltip.hover :title="$t('firmware_version')">
<font-awesome-icon icon="code"/>&nbsp;{{recorder.firmware_version ? recorder.firmware_version : $t("undefined")}}<br/> <font-awesome-icon icon="code"/>&nbsp;{{recorder.firmware_version ? recorder.firmware_version : $t("undefined")}}<br/>
</span> </span>
<span v-b-tooltip.hover :title="$t('additional_camera_connected')"> <span v-b-tooltip.hover :title="$t('additional_camera_connected')">
<font-awesome-icon icon="video"/>&nbsp;{{recorder.additional_camera_connected ? $t("yes") : $t("no")}}<br/> <font-awesome-icon icon="video"/>&nbsp;{{recorder.additional_camera_connected ? $t("yes") : $t("no")}}<br/>
</span> </span>
<span v-b-tooltip.hover :title="$t('serial_number')"> <span v-b-tooltip.hover :title="$t('serial_number')">
<font-awesome-icon icon="barcode"/>&nbsp;{{recorder.serial_number ? recorder.serial_number : $t("undefined")}}<br/> <font-awesome-icon icon="barcode"/>&nbsp;{{recorder.serial_number ? recorder.serial_number : $t("undefined")}}<br/>
</span> </span>
<span v-b-tooltip.hover :title="$t('room')"> <span v-b-tooltip.hover :title="$t('room')">
<font-awesome-icon icon="home"/>&nbsp;{{recorder.room ? recorder.room.name : $t("undefined")}} <font-awesome-icon icon="home"/>&nbsp;{{recorder.room ? recorder.room.name : $t("undefined")}}
</span> </span>
</p> </p>
</div> </div>
<strong>{{$t('created_at')}}:&nbsp</strong>{{recorder.created_at}}<br/> <strong>{{$t('created_at')}}:&nbsp</strong>{{recorder.created_at}}<br/>
<strong>{{$t('last_time_modified')}}:&nbsp</strong>{{recorder.last_time_modified}}<br/> <strong>{{$t('last_time_modified')}}:&nbsp</strong>{{recorder.last_time_modified}}<br/>
<strong>State:&nbsp;</strong> <strong>State:&nbsp;</strong>
<span v-if="state"> <span v-if="state">
<font-awesome-icon v-if="state.state_ok" style="color: green;" icon="thumbs-up"/> <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;"/> <font-awesome-icon v-else icon="thumbs-down" style="color: red;"/>
&nbsp;{{state.msg}} <small>(Last update: {{state.time_stamp}})</small> &nbsp;{{state.msg}} <small>(Last update: {{state.time_stamp}})</small>
</span> </span>
<span v-else>{{$t('State is unknown')}}!</span> <span v-else>{{$t('State is unknown')}}!</span>
<br/> <br/>
<hr/> <hr/>
<h3 style="color: orangered;" v-if="recorder.offline"> <h3 style="color: orangered;" v-if="recorder.offline">
<font-awesome-icon icon="wrench"/>&nbsp; <font-awesome-icon icon="wrench"/>&nbsp;
{{recorder.offline ? 'The recorder is in offline / maintenance mode' : ''}} {{recorder.offline ? 'The recorder is in offline / maintenance mode' : ''}}
</h3> </h3>
<hr v-if="recorder.offline"/> <hr v-if="recorder.offline"/>
<h3 style="color: red;" v-if="recorder.lock_message"> <h3 style="color: red;" v-if="recorder.lock_message">
<font-awesome-icon icon="lock"/>&nbsp; <font-awesome-icon icon="lock"/>&nbsp;
{{recorder.lock_message}} {{recorder.lock_message}}
</h3> </h3>
<hr v-if="recorder.lock_message"/> <hr v-if="recorder.lock_message"/>
<div role="tablist"> <div role="tablist">
<b-card no-body class="mb-1"> <b-card no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab"> <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-button block href="#" v-b-toggle.accordion-1 variant="info">Network</b-button>
</b-card-header> </b-card-header>
<b-collapse id="accordion-1" accordion="my-accordion" role="tabpanel"> <b-collapse id="accordion-1" accordion="my-accordion" role="tabpanel">
<b-card-body> <b-card-body>
<strong>{{$t('ip')}}:&nbsp</strong>{{recorder.ip}}<br/> <strong>{{$t('ip')}}:&nbsp</strong>{{recorder.ip}}<br/>
<strong>{{$t('mac')}}:&nbsp</strong>{{recorder.mac}}<br/> <strong>{{$t('mac')}}:&nbsp</strong>{{recorder.mac}}<br/>
<strong>{{$t('network_name')}}:&nbsp</strong>{{recorder.network_name}}<br/> <strong>{{$t('network_name')}}:&nbsp</strong>{{recorder.network_name}}<br/>
<strong>{{$t('ssh_port')}}:&nbsp</strong>{{recorder.ssh_port}}<br/> <strong>{{$t('ssh_port')}}:&nbsp</strong>{{recorder.ssh_port}}<br/>
<strong>{{$t('telnet_port')}}:&nbsp</strong>{{recorder.telnet_port}}<br/> <strong>{{$t('telnet_port')}}:&nbsp</strong>{{recorder.telnet_port}}<br/>
</b-card-body> </b-card-body>
</b-collapse> </b-collapse>
</b-card> </b-card>
<b-card v-if="recorder.description" no-body class="mb-1"> <b-card v-if="recorder.description" no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab"> <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-button block href="#" v-b-toggle.accordion-2 variant="info">Description</b-button>
</b-card-header> </b-card-header>
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel"> <b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
<b-card-body> <b-card-body>
<b-card-text>{{recorder.description}}</b-card-text> <b-card-text>{{recorder.description}}</b-card-text>
</b-card-body> </b-card-body>
</b-collapse> </b-collapse>
</b-card> </b-card>
<b-card v-if="recorderModel" no-body class="mb-1"> <b-card v-if="recorderModel" no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab"> <b-card-header header-tag="header" class="p-1" role="tab">
<b-button block href="#" v-b-toggle.accordion-2 variant="outline-primary">Model / <b-button block href="#" v-b-toggle.accordion-2 variant="outline-primary">Model /
Recorder Adapter Info Recorder Adapter Info
</b-button> </b-button>
</b-card-header> </b-card-header>
<b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel"> <b-collapse id="accordion-2" accordion="my-accordion" role="tabpanel">
<b-card-body> <b-card-body>
<strong>{{$t('name')}}:&nbsp</strong>{{recorderModel.name}}<br/> <strong>{{$t('name')}}:&nbsp</strong>{{recorderModel.name}}<br/>
<strong>{{$t('created_at')}}:&nbsp</strong>{{recorderModel.created_at}}<br/> <strong>{{$t('created_at')}}:&nbsp</strong>{{recorderModel.created_at}}<br/>
<strong>{{$t('last_time_modified')}}:&nbsp</strong>{{recorderModel.last_time_modified <strong>{{$t('last_time_modified')}}:&nbsp</strong>{{recorderModel.last_time_modified
? recorderModel.last_time_modified : 'never'}}<br/> ? recorderModel.last_time_modified : 'never'}}<br/>
<strong>{{$t('requires_username')}}:&nbsp</strong>{{recorderModel.requires_username <strong>{{$t('requires_username')}}:&nbsp</strong>{{recorderModel.requires_username
? 'Yes' : 'No'}}<br/> ? 'Yes' : 'No'}}<br/>
<strong>{{$t('requires_password')}}:&nbsp</strong>{{recorderModel.requires_password <strong>{{$t('requires_password')}}:&nbsp</strong>{{recorderModel.requires_password
? 'Yes' : 'No'}}<br/> ? 'Yes' : 'No'}}<br/>
<span v-if="recorderModel.notes"><strong>{{$t('notes')}}:&nbsp</strong>{{recorderModel.notes}}<br/></span> <span v-if="recorderModel.notes"><strong>{{$t('notes')}}:&nbsp</strong>{{recorderModel.notes}}<br/></span>
</b-card-body> </b-card-body>
</b-collapse> </b-collapse>
</b-card> </b-card>
<b-card v-if="recorderModel" no-body class="mb-1"> <b-card v-if="recorderModel" no-body class="mb-1">
<b-card-header header-tag="header" class="p-1" role="tab"> <b-card-header header-tag="header" class="p-1" role="tab">
<b-button block href="#" v-b-toggle.accordion-3 variant="danger"> <b-button block href="#" v-b-toggle.accordion-3 variant="danger">
<span>Commands</span> <span>Commands</span>
<span v-if="recorder.locked">&nbsp;({{$t('locked')}})</span> <span v-if="recorder.locked">&nbsp;({{$t('locked')}})</span>
<span v-if="recorder.offline">&nbsp;({{$t('offline')}})</span> <span v-if="recorder.offline">&nbsp;({{$t('offline')}})</span>
</b-button> </b-button>
</b-card-header> </b-card-header>
<b-collapse id="accordion-3" visible accordion="my-accordion" role="tabpanel"> <b-collapse id="accordion-3" visible accordion="my-accordion" role="tabpanel">
<b-card-body> <b-card-body>
{{cmd_params}} {{cmd_params}}
<b-list-group style="max-height: 400px; overflow-y:scroll;" <b-list-group style="max-height: 400px; overflow-y:scroll;"
v-if="!(recorder.locked || recorder.offline)"> v-if="!(recorder.locked || recorder.offline)">
<b-list-group-item v-for="command in recorderModel.commands" <b-list-group-item v-for="command in recorderModel.commands"
v-bind:key="command.id"> v-bind:key="command.id">
<h5>{{command.name}}</h5> <h5>{{command.name}}</h5>
<b-row> <b-row>
<b-col sm="3" v-for="(a_type, arg) in command.parameters" <b-col sm="3" v-for="(a_type, arg) in command.parameters"
v-bind:key="arg" v-bind:key="arg"
v-if="command.parameters !== null"> v-if="command.parameters !== null">
<b-form-input @focus="setup_params(command.id, arg)" <b-form-input @focus="setup_params(command.id, arg)"
@blur="set_param(command.id, arg, $event.target.value)" @blur="set_param(command.id, arg, $event.target.value)"
:placeholder="arg + ' ('+a_type+')'" :placeholder="arg + ' ('+a_type+')'"
:type="a_type==='int'?'number':'text'" :type="a_type==='int'?'number':'text'"
style="margin-right: 10px;"> style="margin-right: 10px;">
<small>{{arg}}:&nbsp;{{a_type}}</small> <small>{{arg}}:&nbsp;{{a_type}}</small>
</b-form-input> </b-form-input>
</b-col> </b-col>
</b-row> </b-row>
<button class="float-right" @click="execute_command(command.id)"> <button class="float-right" @click="execute_command(command.id)">
<font-awesome-icon icon="play"/> <font-awesome-icon icon="play"/>
</button> </button>
<p v-if="cmd_res[command.id]"> <p v-if="cmd_res[command.id]">
<font-awesome-icon style="color: green;" v-if="cmd_res[command.id].ok" <font-awesome-icon style="color: green;" v-if="cmd_res[command.id].ok"
icon="smile"/> icon="smile"/>
<font-awesome-icon style="color: red;" v-else icon="frown"/> <font-awesome-icon style="color: red;" v-else icon="frown"/>
&nbsp;<span>{{cmd_res[command.id].time | moment("HH:mm:ss")}}</span> &nbsp;<span>{{cmd_res[command.id].time | moment("HH:mm:ss")}}</span>
&nbsp;-&nbsp;Output: &nbsp;-&nbsp;Output:
<strong> <strong>
<span v-if="cmd_res[command.id].ok">{{cmd_res[command.id].output}}</span> <span v-if="cmd_res[command.id].ok">{{cmd_res[command.id].output}}</span>
<span v-else>{{cmd_res[command.id].error}}</span> <span v-else>{{cmd_res[command.id].error}}</span>
</strong> </strong>
</p> </p>
</b-list-group-item> </b-list-group-item>
</b-list-group> </b-list-group>
<span v-else>The recorder is either locked or in offline mode commands are disabled!</span> <span v-else>The recorder is either locked or in offline mode commands are disabled!</span>
</b-card-body> </b-card-body>
</b-collapse> </b-collapse>
</b-card> </b-card>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</div> </div>
</template> </template>
<script> <script>
import {EventBus} from '@/utils'; import {EventBus} from '@/utils';
import getRepository from '@/api/RepositoryFactory'; import getRepository from '@/api/RepositoryFactory';
const controlRepository = getRepository('control'); const controlRepository = getRepository('control');
export default { export default {
props: ['recorder_id'], props: ['recorder_id'],
data() { data() {
return { return {
current_recorder_id: this.recorder_id == null ? 1 : parseInt(this.recorder_id), current_recorder_id: this.recorder_id == null ? 1 : parseInt(this.recorder_id),
current_recorder_index: null, current_recorder_index: null,
new_recorder_id: this.current_recorder_id, new_recorder_id: this.current_recorder_id,
cmd_params: {}, cmd_params: {},
cmd_res: {} cmd_res: {}
}; };
}, },
methods: { methods: {
setup_params(command_id, argument) { setup_params(command_id, argument) {
if (!(command_id in this.cmd_params)) { if (!(command_id in this.cmd_params)) {
this.$set(this.cmd_params, command_id, {}); this.$set(this.cmd_params, command_id, {});
} }
this.$set(this.cmd_params[command_id], argument, null) this.$set(this.cmd_params[command_id], argument, null)
}, },
set_param(command_id, argument, val) { set_param(command_id, argument, val) {
this.$set(this.cmd_params[command_id], argument, val) this.$set(this.cmd_params[command_id], argument, val)
}, },
manually_set_recorder_id() { manually_set_recorder_id() {
if (this.new_recorder_id == null || this.new_recorder_id === '') { if (this.new_recorder_id == null || this.new_recorder_id === '') {
this.new_recorder_id = this.current_recorder_id; this.new_recorder_id = this.current_recorder_id;
return; return;
} }
if (this.recorderIds.includes(parseInt(this.new_recorder_id))) { if (this.recorderIds.includes(parseInt(this.new_recorder_id))) {
this.current_recorder_id = parseInt(this.new_recorder_id); this.current_recorder_id = parseInt(this.new_recorder_id);
} }
this.new_recorder_id = this.current_recorder_id; this.new_recorder_id = this.current_recorder_id;
}, },
lock() { lock() {
this.recorder.locked = true; this.recorder.locked = true;
}, },
unlock() { unlock() {
this.recorder.locked = false; this.recorder.locked = false;
}, },
calculate_current_recorder_index() { calculate_current_recorder_index() {
this.current_recorder_index = this.recorderIds.findIndex((id) => { this.current_recorder_index = this.recorderIds.findIndex((id) => {
return id === this.current_recorder_id return id === this.current_recorder_id
}); });
}, },
previousRecorder() { previousRecorder() {
if (null == this.current_recorder_index) { if (null == this.current_recorder_index) {
this.calculate_current_recorder_index(); this.calculate_current_recorder_index();
} }
if (this.current_recorder_index === 0) this.current_recorder_index = this.recorderIds.length - 1; if (this.current_recorder_index === 0) this.current_recorder_index = this.recorderIds.length - 1;
else this.current_recorder_index = this.current_recorder_index - 1; else this.current_recorder_index = this.current_recorder_index - 1;
this.current_recorder_id = this.recorderIds[this.current_recorder_index]; this.current_recorder_id = this.recorderIds[this.current_recorder_index];
this.new_recorder_id = this.current_recorder_id; this.new_recorder_id = this.current_recorder_id;
}, },
nextRecorder() { nextRecorder() {
if (null == this.current_recorder_index) { if (null == this.current_recorder_index) {
this.calculate_current_recorder_index(); this.calculate_current_recorder_index();
} }
if (this.current_recorder_index === this.recorderIds.length - 1) this.current_recorder_index = 0; if (this.current_recorder_index === this.recorderIds.length - 1) this.current_recorder_index = 0;
else this.current_recorder_index = this.current_recorder_index + 1; else this.current_recorder_index = this.current_recorder_index + 1;
this.current_recorder_id = this.recorderIds[this.current_recorder_index]; this.current_recorder_id = this.recorderIds[this.current_recorder_index];
this.new_recorder_id = this.current_recorder_id; this.new_recorder_id = this.current_recorder_id;
}, },
execute_command(command_id) { execute_command(command_id) {
console.log("recorder: " + this.current_recorder_id + "; " + command_id); console.log("recorder: " + this.current_recorder_id + "; " + command_id);
console.log(this.cmd_params); console.log(this.cmd_params);
console.log(this.cmd_params[command_id]); console.log(this.cmd_params[command_id]);
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
controlRepository.runRecorderCommand(this.current_recorder_id, command_id, this.cmd_params[command_id]).then((out) => { controlRepository.runRecorderCommand(this.current_recorder_id, command_id, this.cmd_params[command_id]).then((out) => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
console.log(out.data); console.log(out.data);
this.$set(this.cmd_res, command_id, out.data); this.$set(this.cmd_res, command_id, out.data);
}); });
}, },
}, },
mounted() { mounted() {
this.$store.dispatch('loadRecorders'); this.$store.dispatch('loadRecorders');
this.$store.dispatch('loadRecorderModels'); this.$store.dispatch('loadRecorderModels');
this.$store.dispatch('loadRecorderState', this.current_recorder_id); this.$store.dispatch('loadRecorderState', this.current_recorder_id);
}, },
beforeDestroy() { beforeDestroy() {
EventBus.$off('failedLoadingProfile'); EventBus.$off('failedLoadingProfile');
}, },
computed: { computed: {
recorders() { recorders() {
return this.$store.state.recorders; return this.$store.state.recorders;
}, },
recorderIds() { recorderIds() {
let ids = []; let ids = [];
this.recorders.forEach((elem) => { this.recorders.forEach((elem) => {
ids.push(parseInt(elem.id)); ids.push(parseInt(elem.id));
}); });
return ids; return ids;
}, },
recorder() { recorder() {
const recorder = this.$store.state.recorders.filter((item) => { const recorder = this.$store.state.recorders.filter((item) => {
return parseInt(item.id) === this.current_recorder_id; return parseInt(item.id) === this.current_recorder_id;
}); });
if (recorder.length < 1) { if (recorder.length < 1) {
this.$router.replace({name: 'notFound'}); this.$router.replace({name: 'notFound'});
return {}; return {};
} }
return recorder.shift(); return recorder.shift();
}, },
recorderModel() { recorderModel() {
if (!this.recorder || !this.recorder.recorder_model) return null; if (!this.recorder || !this.recorder.recorder_model) return null;
const model = this.recorderModels.filter((item) => { const model = this.recorderModels.filter((item) => {
return parseInt(item.id) === this.recorder.recorder_model.id; return parseInt(item.id) === this.recorder.recorder_model.id;
}); });
if (model.length < 1) { if (model.length < 1) {
return null; return null;
} }
return model.shift(); return model.shift();
}, },
recorderModels() { recorderModels() {
return this.$store.state.recorderModels; return this.$store.state.recorderModels;
}, },
access_token() { access_token() {
return this.$store.state.access_token; return this.$store.state.access_token;
}, },
state() { state() {
return this.$store.state.recorderStates.filter((s) => { return this.$store.state.recorderStates.filter((s) => {
return parseInt(s.id) === this.current_recorder_id return parseInt(s.id) === this.current_recorder_id
}).pop(); }).pop();
} }
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.error-msg { .error-msg {
color: red; color: red;
font-weight: bold; font-weight: bold;
} }
.lang-btn { .lang-btn {
padding: 15px; padding: 15px;
border: 2px solid green; border: 2px solid green;
font-size: 18px; font-size: 18px;
margin: 15px; margin: 15px;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,121 +1,121 @@
import Vue from 'vue'; import Vue from 'vue';
import axios from 'axios'; import axios from 'axios';
import VueAxios from 'vue-axios'; import VueAxios from 'vue-axios';
import BootstrapVue from 'bootstrap-vue'; import BootstrapVue from 'bootstrap-vue';
import App from './App.vue'; import App from './App.vue';
import router from './router'; import router from './router';
import store from './store'; import store from './store';
import VueSweetalert2 from 'vue-sweetalert2'; import VueSweetalert2 from 'vue-sweetalert2';
import VueCookies from 'vue-cookies'; import VueCookies from 'vue-cookies';
import VueLogger from 'vuejs-logger'; import VueLogger from 'vuejs-logger';
import VueSocketIOExt from 'vue-socket.io-extended'; import VueSocketIOExt from 'vue-socket.io-extended';
import io from 'socket.io-client'; import io from 'socket.io-client';
import i18n from '@/plugins/i18n'; import i18n from '@/plugins/i18n';
import VeeValidate from 'vee-validate'; import VeeValidate from 'vee-validate';
// @ts-ignore // @ts-ignore
import FlagIcon from 'vue-flag-icon'; import FlagIcon from 'vue-flag-icon';
// @ts-ignore // @ts-ignore
import VueMoment from 'vue-moment'; import VueMoment from 'vue-moment';
// following is to avoid missing type definitions // following is to avoid missing type definitions
// const FlagIcon = require('vue-flag-icon'); // const FlagIcon = require('vue-flag-icon');
import {library} from '@fortawesome/fontawesome-svg-core'; import {library} from '@fortawesome/fontawesome-svg-core';
import { import {
faCoffee, faCoffee,
faDoorOpen, faDoorOpen,
faCheck, faCheck,
faPlus, faPlus,
faScroll, faScroll,
faCircle, faCircle,
faArrowCircleLeft, faArrowCircleLeft,
faArrowCircleRight, faArrowCircleRight,
faList, faList,
faTrash, faTrash,
faPencilAlt, faPencilAlt,
faCogs, faCogs,
faAt, faAt,
faUser, faUser,
faEnvelope, faEnvelope,
faHome, faHome,
faSync, faSync,
faCode, faCode,
faBarcode, faBarcode,
faTag, faTag,
faTags, faTags,
faVideo, faVideo,
faLock, faLock,
faLockOpen, faLockOpen,
faWrench, faWrench,
faPlay, faPlay,
faFrown, faFrown,
faSmile, faSmile,
faUserTag, faUserTag,
faExternalLinkAlt, faExternalLinkAlt,
faThumbsUp, faThumbsUp,
faThumbsDown, faThumbsDown,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'; import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
// import 'bootstrap'; // import 'bootstrap';
// import 'bootstrap/dist/css/bootstrap.min.css'; // import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/css/bootstrap.css'; import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css'; import 'bootstrap-vue/dist/bootstrap-vue.css';
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';
library.add(faCoffee, faTrash, faPencilAlt, faScroll, faCheck, faCircle, faList, faPlus, faDoorOpen, faCogs, faAt, 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, faUser, faEnvelope, faUserTag, faExternalLinkAlt, faSync, faHome, faCode, faBarcode, faTag, faTags, faVideo, faLock,
faLockOpen, faArrowCircleLeft, faArrowCircleRight, faWrench, faPlay, faFrown, faSmile, faThumbsUp, faThumbsDown); faLockOpen, faArrowCircleLeft, faArrowCircleRight, faWrench, faPlay, faFrown, faSmile, faThumbsUp, faThumbsDown);
Vue.component('font-awesome-icon', FontAwesomeIcon); Vue.component('font-awesome-icon', FontAwesomeIcon);
const options = { const options = {
isEnabled: true, isEnabled: true,
// logLevel : isProduction ? 'error' : 'debug', // logLevel : isProduction ? 'error' : 'debug',
logLevel: 'debug', logLevel: 'debug',
stringifyArguments: false, stringifyArguments: false,
showLogLevel: true, showLogLevel: true,
showMethodName: true, showMethodName: true,
separator: '|', separator: '|',
showConsoleColors: true, showConsoleColors: true,
}; };
Vue.use(VueLogger, options); Vue.use(VueLogger, options);
Vue.use(VueAxios, axios); Vue.use(VueAxios, axios);
Vue.use(BootstrapVue); Vue.use(BootstrapVue);
Vue.use(FlagIcon); Vue.use(FlagIcon);
Vue.use(VueCookies); Vue.use(VueCookies);
Vue.use(VueSweetalert2); Vue.use(VueSweetalert2);
Vue.use(VeeValidate); Vue.use(VeeValidate);
Vue.use(VueMoment); Vue.use(VueMoment);
// const socket = io('ws://localhost:5000',{autoConnect: false, reconnectionAttempts: 3}); // const socket = io('ws://localhost:5000',{autoConnect: false, reconnectionAttempts: 3});
const socket = io('ws://localhost:5443', { const socket = io('ws://localhost:5443', {
autoConnect: false, autoConnect: false,
reconnectionAttempts: 3, reconnectionAttempts: 3,
query: {jwt: store.state.access_token}, query: {jwt: store.state.access_token},
}); });
Vue.use(VueSocketIOExt, socket); Vue.use(VueSocketIOExt, socket);
// setup fake backend // setup fake backend
// import { configureFakeBackend } from './helpers'; // import { configureFakeBackend } from './helpers';
// configureFakeBackend(); // configureFakeBackend();
Vue.config.productionTip = false; Vue.config.productionTip = false;
// @ts-ignore // @ts-ignore
String.prototype.isEmpty = function() { String.prototype.isEmpty = function() {
return (this.length === 0 || !this.trim()); return (this.length === 0 || !this.trim());
}; };
new Vue({ new Vue({
i18n, i18n,
router, router,
store, store,
render: (h) => h(App), render: (h) => h(App),
}).$mount('#app'); }).$mount('#app');

View File

@@ -1,412 +1,412 @@
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate'; import createPersistedState from 'vuex-persistedstate';
import getRepository from '@/api/RepositoryFactory'; import getRepository from '@/api/RepositoryFactory';
import RoomRepository from '@/api/roomRepository'; import RoomRepository from '@/api/roomRepository';
import RecordRepository from '@/api/recorderRepository'; import RecordRepository from '@/api/recorderRepository';
import VirtualCommandRepository from '@/api/virtualCommandRepository'; import VirtualCommandRepository from '@/api/virtualCommandRepository';
import StateRepository from '@/api/stateRepository'; import StateRepository from '@/api/stateRepository';
// imports of AJAX functions will go here // imports of AJAX functions will go here
import { import {
fetchSurveys, fetchSurveys,
fetchSurvey, fetchSurvey,
getProviders, getProviders,
saveSurveyResponse, saveSurveyResponse,
postNewSurvey, postNewSurvey,
authenticate, authenticate,
register, register,
oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey, oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups, revokeRefreshKey,
} from '@/api'; } from '@/api';
import {isValidJwt, EventBus} from '@/utils'; import {isValidJwt, EventBus} from '@/utils';
Vue.use(Vuex); Vue.use(Vuex);
const state = { const state = {
// single source of data // single source of data
surveys: [], surveys: [],
rooms: [], rooms: [],
recorders: [], recorders: [],
recorderModels: [], recorderModels: [],
recorderCommands: [], recorderCommands: [],
recorderStates: [], recorderStates: [],
virtualCommands: [], virtualCommands: [],
loginProviders: [], loginProviders: [],
currentSurvey: {}, currentSurvey: {},
profile: {}, profile: {},
users: [], users: [],
userGroups: [], userGroups: [],
access_token: '', access_token: '',
refresh_token: '', refresh_token: '',
}; };
// const RoomRepository = getRepository('room'); // const RoomRepository = getRepository('room');
const actions = { const actions = {
// asynchronous operations // asynchronous operations
loadRooms(context: any) { loadRooms(context: any) {
return RoomRepository.getRooms() return RoomRepository.getRooms()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setRooms', {rooms: response.data}); context.commit('setRooms', {rooms: response.data});
EventBus.$emit('roomsLoaded', response.data); EventBus.$emit('roomsLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading rooms!', error); Vue.$log.warn('Error loading rooms!', error);
EventBus.$emit('failedLoadingRooms', error); EventBus.$emit('failedLoadingRooms', error);
}); });
}, },
loadRecorders(context: any) { loadRecorders(context: any) {
return RecordRepository.getRecorders() return RecordRepository.getRecorders()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setRecorders', {recorders: response.data}); context.commit('setRecorders', {recorders: response.data});
EventBus.$emit('recordersLoaded', response.data); EventBus.$emit('recordersLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading recorders!', error); Vue.$log.warn('Error loading recorders!', error);
EventBus.$emit('failedLoadingRecorders', error); EventBus.$emit('failedLoadingRecorders', error);
}); });
}, },
loadRecorderStates(context: any) { loadRecorderStates(context: any) {
return StateRepository.getRecordersStates() return StateRepository.getRecordersStates()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setRecorderStates', {recorderStates: response.data}); context.commit('setRecorderStates', {recorderStates: response.data});
EventBus.$emit('recorderStatesLoaded', response.data); EventBus.$emit('recorderStatesLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading recorders states!', error); Vue.$log.warn('Error loading recorders states!', error);
EventBus.$emit('failedLoadingRecorderStates', error); EventBus.$emit('failedLoadingRecorderStates', error);
}); });
}, },
loadRecorderState(context: any, recorder_id: number) { loadRecorderState(context: any, recorder_id: number) {
return StateRepository.getRecorderState(recorder_id) return StateRepository.getRecorderState(recorder_id)
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setRecorderState', {recorderState: response.data}); context.commit('setRecorderState', {recorderState: response.data});
EventBus.$emit('recorderStateLoaded', response.data); EventBus.$emit('recorderStateLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading recorders states!', error); Vue.$log.warn('Error loading recorders states!', error);
EventBus.$emit('failedLoadingRecorderStates', error); EventBus.$emit('failedLoadingRecorderStates', error);
}); });
}, },
loadRecorderModels(context: any) { loadRecorderModels(context: any) {
return RecordRepository.getRecorderModels() return RecordRepository.getRecorderModels()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
Vue.$log.debug('Loaded recorder models'); Vue.$log.debug('Loaded recorder models');
context.commit('setRecorderModels', {recorderModels: response.data}); context.commit('setRecorderModels', {recorderModels: response.data});
EventBus.$emit('recorderModelsLoaded', response.data); EventBus.$emit('recorderModelsLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading recorder models!', error); Vue.$log.warn('Error loading recorder models!', error);
EventBus.$emit('failedLoadingRecorderModels', error); EventBus.$emit('failedLoadingRecorderModels', error);
}); });
}, },
loadRecorderCommands(context: any) { loadRecorderCommands(context: any) {
return RecordRepository.getRecorderCommands() return RecordRepository.getRecorderCommands()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setRecorderCommands', {recorderCommands: response.data}); context.commit('setRecorderCommands', {recorderCommands: response.data});
EventBus.$emit('recorderCommandsLoaded', response.data); EventBus.$emit('recorderCommandsLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading recorder commands!', error); Vue.$log.warn('Error loading recorder commands!', error);
EventBus.$emit('failedLoadingRecorderCommands', error); EventBus.$emit('failedLoadingRecorderCommands', error);
}); });
}, },
loadVirtualCommands(context: any) { loadVirtualCommands(context: any) {
return VirtualCommandRepository.getVirtualCommands() return VirtualCommandRepository.getVirtualCommands()
.then((response: any) => { .then((response: any) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setVirtualCommands', {virtualCommands: response.data}); context.commit('setVirtualCommands', {virtualCommands: response.data});
EventBus.$emit('virtualCommandsLoaded', response.data); EventBus.$emit('virtualCommandsLoaded', response.data);
}) })
.catch((error: any) => { .catch((error: any) => {
Vue.$log.warn('Error loading virtual commands!', error); Vue.$log.warn('Error loading virtual commands!', error);
EventBus.$emit('failedLoadingVirtualCommands', error); EventBus.$emit('failedLoadingVirtualCommands', error);
}); });
}, },
loadCommands(context: any) { loadCommands(context: any) {
return context.dispatch('loadRecorderCommands').then(() => { return context.dispatch('loadRecorderCommands').then(() => {
return context.dispatch('loadVirtualCommands'); return context.dispatch('loadVirtualCommands');
}); });
}, },
loadUsers(context: any) { loadUsers(context: any) {
return fetchUsers(context.state.access_token) return fetchUsers(context.state.access_token)
.then((response) => { .then((response) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setUsers', {users: response.data}); context.commit('setUsers', {users: response.data});
EventBus.$emit('usersLoaded', response.data); EventBus.$emit('usersLoaded', response.data);
}) })
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error loading users!', error); Vue.$log.warn('Error loading users!', error);
EventBus.$emit('failedLoadingUsers', error); EventBus.$emit('failedLoadingUsers', error);
}); });
}, },
loadUserGroups(context: any) { loadUserGroups(context: any) {
return fetchUserGroups(context.state.access_token) return fetchUserGroups(context.state.access_token)
.then((response) => { .then((response) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setUserGroups', {groups: response.data}); context.commit('setUserGroups', {groups: response.data});
EventBus.$emit('groupsLoaded', response.data); EventBus.$emit('groupsLoaded', response.data);
}) })
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error loading user groups!', error); Vue.$log.warn('Error loading user groups!', error);
EventBus.$emit('failedLoadingUserGroups', error); EventBus.$emit('failedLoadingUserGroups', error);
}); });
}, },
loadProfileAuthCheck(context: any) { loadProfileAuthCheck(context: any) {
if (!getters.isAuthenticated) { if (!getters.isAuthenticated) {
EventBus.$emit('accessTokenInvalid'); EventBus.$emit('accessTokenInvalid');
if (!getters.isRefreshTokenValid) { if (!getters.isRefreshTokenValid) {
Vue.$log.warn('Access and refresh token invalid! User must login again!'); Vue.$log.warn('Access and refresh token invalid! User must login again!');
EventBus.$emit('refreshTokenInvalid'); EventBus.$emit('refreshTokenInvalid');
EventBus.$emit('accessAndRefreshTokenInvalid'); EventBus.$emit('accessAndRefreshTokenInvalid');
} else { } else {
return context.dispatch('refreshToken').then(() => { return context.dispatch('refreshToken').then(() => {
context.commit('loadProfile'); context.commit('loadProfile');
}); });
} }
} else { } else {
context.commit('loadProfile'); context.commit('loadProfile');
} }
}, },
loadProfile(context: any) { loadProfile(context: any) {
return fetchProfile(context.state.access_token) return fetchProfile(context.state.access_token)
.then((response) => { .then((response) => {
Vue.$log.debug(response); Vue.$log.debug(response);
Vue.$log.debug(response.data); Vue.$log.debug(response.data);
context.commit('setProfile', {profile: response.data}); context.commit('setProfile', {profile: response.data});
EventBus.$emit('profileLoaded', response.data); EventBus.$emit('profileLoaded', response.data);
}) })
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error loading profile!', error); Vue.$log.warn('Error loading profile!', error);
EventBus.$emit('failedLoadingProfile', error); EventBus.$emit('failedLoadingProfile', error);
}); });
}, },
loadLoginProviders(context: any) { loadLoginProviders(context: any) {
return getProviders() return getProviders()
.then((response) => { .then((response) => {
context.commit('setLoginProviderData', {providers: response.data}); context.commit('setLoginProviderData', {providers: response.data});
EventBus.$emit('loginProvidersLoaded', response.data); EventBus.$emit('loginProvidersLoaded', response.data);
}); });
}, },
login(context: any, userData: any) { login(context: any, userData: any) {
context.commit('setUserData', {userData}); context.commit('setUserData', {userData});
return authenticate(userData) return authenticate(userData)
.then((response) => context.commit('setJwtToken', {tokens: response.data})) .then((response) => context.commit('setJwtToken', {tokens: response.data}))
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error Authenticating: ', error); Vue.$log.warn('Error Authenticating: ', error);
EventBus.$emit('failedAuthentication', error); EventBus.$emit('failedAuthentication', error);
}); });
}, },
logout(context: any, revokeRefreshToken: any) { logout(context: any, revokeRefreshToken: any) {
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}}); context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
if (revokeRefreshToken) { if (revokeRefreshToken) {
return revokeRefreshKey(context.state.access_token) return revokeRefreshKey(context.state.access_token)
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error); Vue.$log.warn('Error Authenticating (Could not revoke refresh token): ', error);
EventBus.$emit('failedRevokingRefreshToken', error); EventBus.$emit('failedRevokingRefreshToken', error);
}); });
} }
// this.clearAll(); // this.clearAll();
}, },
oidc_login(context: any, redirectionUrl: any) { oidc_login(context: any, redirectionUrl: any) {
// context.commit('setUserData', { userData }); // context.commit('setUserData', { userData });
return oidc_login(redirectionUrl) return oidc_login(redirectionUrl)
.then((response) => context.commit('setJwtToken', {tokens: response.data})) .then((response) => context.commit('setJwtToken', {tokens: response.data}))
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error Authenticating: ', error); Vue.$log.warn('Error Authenticating: ', error);
EventBus.$emit('failedAuthentication', error); EventBus.$emit('failedAuthentication', error);
}); });
}, },
refreshToken(context: any) { refreshToken(context: any) {
EventBus.$emit('refreshingToken'); EventBus.$emit('refreshingToken');
Vue.$log.debug('Refreshing tokens!'); Vue.$log.debug('Refreshing tokens!');
return getFreshToken(context.state.refresh_token) return getFreshToken(context.state.refresh_token)
.then((response) => { .then((response) => {
context.commit('setTokens', {tokens: response.data}); context.commit('setTokens', {tokens: response.data});
Vue.$log.debug('Tokens refreshed!'); Vue.$log.debug('Tokens refreshed!');
}) })
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error Refreshing token: ', error); Vue.$log.warn('Error Refreshing token: ', error);
EventBus.$emit('failedRefreshingToken', error); EventBus.$emit('failedRefreshingToken', error);
}); });
}, },
resetToken(context: any) { resetToken(context: any) {
EventBus.$emit('resettingTokens'); EventBus.$emit('resettingTokens');
Vue.$log.debug('Resetting tokens!'); Vue.$log.debug('Resetting tokens!');
context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}}); context.commit('setTokens', {tokens: {access_token: '', refresh_token: ''}});
EventBus.$emit('tokensReset'); EventBus.$emit('tokensReset');
Vue.$log.debug('Tokens reset!'); Vue.$log.debug('Tokens reset!');
}, },
storeTokens(context: any, tokens: any) { storeTokens(context: any, tokens: any) {
context.commit('setTokens', {tokens}); context.commit('setTokens', {tokens});
EventBus.$emit('storedTokens'); EventBus.$emit('storedTokens');
}, },
register(context: any, userData: any) { register(context: any, userData: any) {
context.commit('setUserData', {userData}); context.commit('setUserData', {userData});
return register(userData) return register(userData)
.then(context.dispatch('login', userData)) .then(context.dispatch('login', userData))
.catch((error) => { .catch((error) => {
Vue.$log.warn('Error Registering: ', error); Vue.$log.warn('Error Registering: ', error);
EventBus.$emit('failedRegistering: ', error); EventBus.$emit('failedRegistering: ', error);
}); });
}, },
submitNewSurvey(context: any, survey: any) { submitNewSurvey(context: any, survey: any) {
return postNewSurvey(survey, context.state.access_token); return postNewSurvey(survey, context.state.access_token);
}, },
}; };
const mutations = { const mutations = {
// isolated data mutations // isolated data mutations
setSurveys(sState: any, payload: any) { setSurveys(sState: any, payload: any) {
sState.surveys = payload.surveys; sState.surveys = payload.surveys;
}, },
setSurvey(sState: any, payload: any) { setSurvey(sState: any, payload: any) {
const nQuestions = payload.survey.questions.length; const nQuestions = payload.survey.questions.length;
for (let i = 0; i < nQuestions; i++) { for (let i = 0; i < nQuestions; i++) {
payload.survey.questions[i].choice = null; payload.survey.questions[i].choice = null;
} }
sState.currentSurvey = payload.survey; sState.currentSurvey = payload.survey;
}, },
setRooms(sState: any, payload: any) { setRooms(sState: any, payload: any) {
sState.rooms = payload.rooms; sState.rooms = payload.rooms;
}, },
setRecorders(sState: any, payload: any) { setRecorders(sState: any, payload: any) {
sState.recorders = payload.recorders; sState.recorders = payload.recorders;
}, },
setRecorderModels(sState: any, payload: any) { setRecorderModels(sState: any, payload: any) {
sState.recorderModels = payload.recorderModels; sState.recorderModels = payload.recorderModels;
}, },
setRecorderCommands(sState: any, payload: any) { setRecorderCommands(sState: any, payload: any) {
sState.recorderCommands = payload.recorderCommands; sState.recorderCommands = payload.recorderCommands;
}, },
setRecorderStates(sState: any, payload: any) { setRecorderStates(sState: any, payload: any) {
sState.recorderStates = payload.recorderStates; sState.recorderStates = payload.recorderStates;
}, },
setRecorderState(sState: any, payload: any) { setRecorderState(sState: any, payload: any) {
const n_rec_states = sState.recorderStates.length; const n_rec_states = sState.recorderStates.length;
const rec_id = payload.recorderState.id; const rec_id = payload.recorderState.id;
let found = false; let found = false;
for (let i = 0; i < n_rec_states; i++) { for (let i = 0; i < n_rec_states; i++) {
if (sState.recorderStates[i].id === rec_id) { if (sState.recorderStates[i].id === rec_id) {
sState.recorderStates[i] = payload.recorderState; sState.recorderStates[i] = payload.recorderState;
found = true; found = true;
break; break;
} }
} }
if(!found){ if(!found){
sState.recorderStates.push(payload.recorderState); sState.recorderStates.push(payload.recorderState);
} }
}, },
setVirtualCommands(sState: any, payload: any) { setVirtualCommands(sState: any, payload: any) {
sState.virtualCommands = payload.virtualCommands; sState.virtualCommands = payload.virtualCommands;
}, },
setUsers(sState: any, payload: any) { setUsers(sState: any, payload: any) {
sState.users = payload.users; sState.users = payload.users;
}, },
setUserGroups(sState: any, payload: any) { setUserGroups(sState: any, payload: any) {
sState.userGroups = payload.groups; sState.userGroups = payload.groups;
}, },
setChoice(sState: any, payload: any) { setChoice(sState: any, payload: any) {
const {questionId, choice} = payload; const {questionId, choice} = payload;
const nQuestions = sState.currentSurvey.questions.length; const nQuestions = sState.currentSurvey.questions.length;
for (let i = 0; i < nQuestions; i++) { for (let i = 0; i < nQuestions; i++) {
if (sState.currentSurvey.questions[i].id === questionId) { if (sState.currentSurvey.questions[i].id === questionId) {
sState.currentSurvey.questions[i].choice = choice; sState.currentSurvey.questions[i].choice = choice;
break; break;
} }
} }
}, },
setLoginProviderData(sState: any, payload: any) { setLoginProviderData(sState: any, payload: any) {
Vue.$log.debug('got loginProviders = ', payload); Vue.$log.debug('got loginProviders = ', payload);
sState.loginProviders = payload.providers; sState.loginProviders = payload.providers;
}, },
// probably old ... // probably old ...
setUserData(sState: any, payload: any) { setUserData(sState: any, payload: any) {
Vue.$log.debug('setUserData payload = ', payload); Vue.$log.debug('setUserData payload = ', payload);
sState.userData = payload.userData; sState.userData = payload.userData;
}, },
setProfile(sState: any, payload: any) { setProfile(sState: any, payload: any) {
Vue.$log.debug('setProfile payload = ', payload); Vue.$log.debug('setProfile payload = ', payload);
sState.profile = payload.profile; sState.profile = payload.profile;
}, },
setJwtToken(sState: any, payload: any) { setJwtToken(sState: any, payload: any) {
Vue.$log.debug('setJwtToken payload = ', payload); Vue.$log.debug('setJwtToken payload = ', payload);
localStorage.tokens = payload.tokens; localStorage.tokens = payload.tokens;
sState.access_token = payload.tokens.access_token; sState.access_token = payload.tokens.access_token;
sState.refresh_token = payload.tokens.refresh_token; sState.refresh_token = payload.tokens.refresh_token;
}, },
setTokens(sState: any, payload: any) { setTokens(sState: any, payload: any) {
Vue.$log.debug('setTokens payload = ', payload); Vue.$log.debug('setTokens payload = ', payload);
if ('access_token' in payload.tokens) { if ('access_token' in payload.tokens) {
sState.access_token = payload.tokens.access_token; sState.access_token = payload.tokens.access_token;
} }
if ('refresh_token' in payload.tokens) { if ('refresh_token' in payload.tokens) {
sState.refresh_token = payload.tokens.refresh_token; sState.refresh_token = payload.tokens.refresh_token;
} }
Vue.$log.debug('access_token: ' + sState.access_token); Vue.$log.debug('access_token: ' + sState.access_token);
Vue.$log.debug('refresh_token: ' + sState.refresh_token); Vue.$log.debug('refresh_token: ' + sState.refresh_token);
}, },
}; };
const getters = { const getters = {
// reusable data accessors // reusable data accessors
isAuthenticated(sState: any) { isAuthenticated(sState: any) {
const valid = isValidJwt(sState.access_token); const valid = isValidJwt(sState.access_token);
Vue.$log.debug('Access token is valid?: ', valid); Vue.$log.debug('Access token is valid?: ', valid);
Vue.$log.debug(sState.access_token); Vue.$log.debug(sState.access_token);
return valid; return valid;
}, },
isRefreshTokenValid(sState: any) { isRefreshTokenValid(sState: any) {
const valid = isValidJwt(sState.refresh_token); const valid = isValidJwt(sState.refresh_token);
Vue.$log.debug('Refresh token is valid?: ', valid); Vue.$log.debug('Refresh token is valid?: ', valid);
Vue.$log.debug('sState.refresh_token'); Vue.$log.debug('sState.refresh_token');
return valid; return valid;
}, },
getLoginProviders(sState: any) { getLoginProviders(sState: any) {
return sState.loginProviders; return sState.loginProviders;
}, },
getUserName(sState: any) { getUserName(sState: any) {
if (sState.profile == null || Object.keys(sState.profile).length === 0) { if (sState.profile == null || Object.keys(sState.profile).length === 0) {
return ''; return '';
} }
if (sState.profile.nickname) { if (sState.profile.nickname) {
return sState.profile.nickname; return sState.profile.nickname;
} }
return sState.profile.first_name + ' ' + sState.profile.last_name; return sState.profile.first_name + ' ' + sState.profile.last_name;
}, },
// this is probably wrong!! // this is probably wrong!!
hasAccessRight(sState: any) { hasAccessRight(sState: any) {
(requestedPermission: string) => { (requestedPermission: string) => {
return sState.profile.effective_permissions.find((permission: any) => { return sState.profile.effective_permissions.find((permission: any) => {
permission.name === requestedPermission; permission.name === requestedPermission;
}); });
}; };
}, },
}; };
const store = new Vuex.Store({ const store = new Vuex.Store({
state, state,
actions, actions,
mutations, mutations,
getters, getters,
plugins: [createPersistedState()], plugins: [createPersistedState()],
}); });
export default store; export default store;

View File

@@ -1,93 +1,93 @@
<template> <template>
<div class="home"> <div class="home">
<div class="container"> <div class="container">
<section class="section"> <section class="section">
<HelloWorld v-if="!authenticated" msg="You are not authenticated!"/> <HelloWorld v-if="!authenticated" msg="You are not authenticated!"/>
<div v-else> <div v-else>
<h1>Welcome <span v-if="profile.last_seen!=null">back</span> {{$store.getters.getUserName}}! <h1>Welcome <span v-if="profile.last_seen!=null">back</span> {{$store.getters.getUserName}}!
</h1> </h1>
<h4 v-if="profile.last_seen!=null">Last login: {{profile.last_seen | moment("dddd, MMMM Do YYYY")}}</h4> <h4 v-if="profile.last_seen!=null">Last login: {{profile.last_seen | moment("dddd, MMMM Do YYYY")}}</h4>
<hr/> <hr/>
<ErroneousRecorders/> <ErroneousRecorders/>
<h2>{{$t('Favorite recorders:')}}</h2> <h2>{{$t('Favorite recorders:')}}</h2>
<p>{{$t('Add favorite recorder:')}}</p> <p>{{$t('Add favorite recorder:')}}</p>
<SelectRecorder @recorderSelected="addFavoriteRecorderToProfile"/> <SelectRecorder @recorderSelected="addFavoriteRecorderToProfile"/>
<br/> <br/>
<div v-if="profile.favorite_recorders.length >0"> <div v-if="profile.favorite_recorders.length >0">
<b-card-group deck> <b-card-group deck>
<RecorderState v-for="recorder in profile.favorite_recorders" :recorder="recorder" v-bind:key="recorder.id"/> <RecorderState v-for="recorder in profile.favorite_recorders" :recorder="recorder" v-bind:key="recorder.id"/>
</b-card-group> </b-card-group>
</div> </div>
</div> </div>
</section> </section>
</div> </div>
<router-link :to="{name: 'recorder', params: {recorder_id: 1}}">rec 1</router-link> <router-link :to="{name: 'recorder', params: {recorder_id: 1}}">rec 1</router-link>
</div> </div>
</template> </template>
<script> <script>
import {Component, Vue} from 'vue-property-decorator'; import {Component, Vue} from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
import i18n from '@/plugins/i18n'; import i18n from '@/plugins/i18n';
import ErroneousRecorders from '@/components/ErroneousRecorders.vue'; import ErroneousRecorders from '@/components/ErroneousRecorders.vue';
import SelectRecorder from '@/components/SelectRecorder.vue'; import SelectRecorder from '@/components/SelectRecorder.vue';
import RecorderState from '@/components/RecorderState.vue'; import RecorderState from '@/components/RecorderState.vue';
import getRepository from '@/api/RepositoryFactory'; import getRepository from '@/api/RepositoryFactory';
const userRepository = getRepository('user'); const userRepository = getRepository('user');
@Component({ @Component({
components: { components: {
ErroneousRecorders, ErroneousRecorders,
RecorderState, RecorderState,
SelectRecorder, SelectRecorder,
HelloWorld, HelloWorld,
}, },
}) })
export default class Home extends Vue { export default class Home extends Vue {
data() { data() {
return {}; return {};
} }
mounted() { mounted() {
if (this.authenticated) { if (this.authenticated) {
if (this.profile == null || Object.keys(this.profile).length === 0) { if (this.profile == null || Object.keys(this.profile).length === 0) {
this.$parent.$data.isLoading = true; this.$parent.$data.isLoading = true;
this.$store.dispatch('loadProfile').then(() => { this.$store.dispatch('loadProfile').then(() => {
this.$parent.$data.isLoading = false; this.$parent.$data.isLoading = false;
}); });
} }
} }
} }
addFavoriteRecorderToProfile(recorder) { addFavoriteRecorderToProfile(recorder) {
userRepository.addFavoriteRecorder(recorder.recorder_id).then(() => { userRepository.addFavoriteRecorder(recorder.recorder_id).then(() => {
this.$store.dispatch('loadProfile'); this.$store.dispatch('loadProfile');
}); });
} }
get authenticated() { get authenticated() {
return this.$store.getters.isAuthenticated; return this.$store.getters.isAuthenticated;
} }
get profile() { get profile() {
return this.$store.state.profile; return this.$store.state.profile;
} }
} }
</script> </script>
<style> <style>
.container { .container {
border-radius: 25px; border-radius: 25px;
padding: 20px; padding: 20px;
margin: auto; margin: auto;
width: 80%; width: 80%;
background-color: hsla(0, 0%, 100%, 0.51); background-color: hsla(0, 0%, 100%, 0.51);
fill: #044b94; fill: #044b94;
fill-opacity: 0.9; fill-opacity: 0.9;
} }
</style> </style>

View File

@@ -1,13 +1,13 @@
<template> <template>
<div> <div>
<p>404 - Not Found -> have you meant... blabla (GT)</p> <p>404 - Not Found -> have you meant... blabla (GT)</p>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
created() { created() {
// window.location.href = "/my-new-404-page.html"; // window.location.href = "/my-new-404-page.html";
} }
}; };
</script> </script>