adding authentication and state management
This commit is contained in:
parent
b1207d0b6f
commit
3191fe5c04
1
.env
1
.env
@ -4,3 +4,4 @@ VITE_API_PATH_LIST=/list/today
|
|||||||
VITE_API_PATH_WHITELIST=/whitelist
|
VITE_API_PATH_WHITELIST=/whitelist
|
||||||
VITE_API_PATH_NOW_SESSIONS=/ivao/sessions/now
|
VITE_API_PATH_NOW_SESSIONS=/ivao/sessions/now
|
||||||
VITE_API_PATH_NOW_FLIGHTPLANS=/ivao/flightplans/latest
|
VITE_API_PATH_NOW_FLIGHTPLANS=/ivao/flightplans/latest
|
||||||
|
VITE_API_PATH_AUTHENTICATION=/admin/user/authenticate
|
68
package-lock.json
generated
68
package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"bootstrap": "^5.2.3",
|
"bootstrap": "^5.2.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"pinia": "^2.0.29",
|
||||||
"redis": "^4.5.1",
|
"redis": "^4.5.1",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-loading-overlay": "^6.0.2",
|
"vue-loading-overlay": "^6.0.2",
|
||||||
@ -2269,6 +2270,56 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pinia": {
|
||||||
|
"version": "2.0.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.29.tgz",
|
||||||
|
"integrity": "sha512-5z/KpFecq/cIgfeTnulJXldiLcTITRkTe3N58RKYSj0Pc1EdR6oyCdnf5A9jLoVwBqX5LtHhd0kGlpzWvk9oiQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/devtools-api": "^6.4.5",
|
||||||
|
"vue-demi": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/posva"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.4.0",
|
||||||
|
"typescript": ">=4.4.4",
|
||||||
|
"vue": "^2.6.14 || ^3.2.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pinia/node_modules/vue-demi": {
|
||||||
|
"version": "0.13.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||||
|
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/portfinder": {
|
"node_modules/portfinder": {
|
||||||
"version": "1.0.32",
|
"version": "1.0.32",
|
||||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
|
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
|
||||||
@ -4559,6 +4610,23 @@
|
|||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"pinia": {
|
||||||
|
"version": "2.0.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.29.tgz",
|
||||||
|
"integrity": "sha512-5z/KpFecq/cIgfeTnulJXldiLcTITRkTe3N58RKYSj0Pc1EdR6oyCdnf5A9jLoVwBqX5LtHhd0kGlpzWvk9oiQ==",
|
||||||
|
"requires": {
|
||||||
|
"@vue/devtools-api": "^6.4.5",
|
||||||
|
"vue-demi": "*"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": {
|
||||||
|
"version": "0.13.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||||
|
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"portfinder": {
|
"portfinder": {
|
||||||
"version": "1.0.32",
|
"version": "1.0.32",
|
||||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
|
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"bootstrap": "^5.2.3",
|
"bootstrap": "^5.2.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"pinia": "^2.0.29",
|
||||||
"redis": "^4.5.1",
|
"redis": "^4.5.1",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-loading-overlay": "^6.0.2",
|
"vue-loading-overlay": "^6.0.2",
|
||||||
|
164
src/App.vue
164
src/App.vue
@ -1,18 +1,62 @@
|
|||||||
<script>
|
<script>
|
||||||
// import { RouterLink, RouterView } from "vue-router";
|
// import { RouterLink, RouterView } from "vue-router";
|
||||||
|
// import { useAuth0 } from '@auth0/auth0-vue';
|
||||||
|
|
||||||
|
import { useSessionStore } from './stores/session-store';
|
||||||
|
import { authenticate, isAlive, logout } from './data/http/auth';
|
||||||
|
import { mapState } from 'pinia';
|
||||||
export default {
|
export default {
|
||||||
|
setup() {
|
||||||
|
const store = useSessionStore();
|
||||||
|
|
||||||
|
const { setUser, logoutUser, hasRoles } = store;
|
||||||
|
|
||||||
|
return {
|
||||||
|
logoutUser,
|
||||||
|
setUser,
|
||||||
|
hasRoles
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
const user = await isAlive();
|
||||||
|
if (user) {
|
||||||
|
this.setUser(user);
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
loading: true,
|
loading: true,
|
||||||
list: [],
|
list: [],
|
||||||
whitelist: [],
|
whitelist: [],
|
||||||
isNavMobileOpen: false,
|
isNavMobileOpen: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed:{
|
||||||
|
...mapState(useSessionStore, ['user', 'isAuthenticated']),
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleNavMobile() {
|
toggleNavMobile() {
|
||||||
this.isNavMobileOpen = !this.isNavMobileOpen;
|
this.isNavMobileOpen = !this.isNavMobileOpen;
|
||||||
|
},
|
||||||
|
async login() {
|
||||||
|
if (!this.username.trim() || !this.password.trim()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const user = await authenticate(this.username, this.password);
|
||||||
|
this.setUser(user);
|
||||||
|
console.log('user :>> ', user);
|
||||||
|
this.username = '';
|
||||||
|
this.password = '';
|
||||||
|
},
|
||||||
|
async logout() {
|
||||||
|
await logout();
|
||||||
|
this.logoutUser();
|
||||||
|
this.$router.push('/');
|
||||||
|
},
|
||||||
|
async check() {
|
||||||
|
await isAlive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,40 +81,45 @@ export default {
|
|||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<router-link class="navbar-item" to="/">ICAO</router-link>
|
<router-link class="navbar-item" to="/">ICAO</router-link>
|
||||||
<router-link class="navbar-item" to="/acars">Acars</router-link>
|
<router-link class="navbar-item" to="/acars">Acars</router-link>
|
||||||
|
|
||||||
|
<router-link v-if="hasRoles(['cabal'])" class="navbar-item" to="/cabal">Capt Cabal</router-link>
|
||||||
|
<router-link v-if="hasRoles(['admin'])" class="navbar-item" to="/admin">Admin</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div class="navbar-item">
|
||||||
|
<div class="field is-horizontal">
|
||||||
|
<div v-if="!isAuthenticated" class="field-body">
|
||||||
|
<div class="field">
|
||||||
|
<p class="control is-expanded">
|
||||||
|
<input class="input is-small input-login" @keyup.enter="login" v-model="username" type="text" placeholder="Username">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<p class="control is-expanded">
|
||||||
|
<input class="input is-small input-login" @keyup.enter="login" v-model="password" type="password" placeholder="Password">
|
||||||
|
</p>
|
||||||
|
<p class="control">
|
||||||
|
<a class="button is-small is-light" @click="login">
|
||||||
|
Login
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isAuthenticated" class="field-body">
|
||||||
|
<div class="is-6 mr-2 mt-1">{{ user.firstname }} {{ user.lastname }}</div>
|
||||||
|
<p class="control">
|
||||||
|
<a class="button is-small is-light" @click="logout">
|
||||||
|
Logout
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div> <RouterView /> </div>
|
<div> <RouterView /> </div>
|
||||||
<!-- <section class="section">
|
|
||||||
<h1 class="title">Pilotos activos con mas de 200 horas en ACARS</h1>
|
|
||||||
<table class="table is-striped is-hoverable is-fullwidth">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="has-text-centered">VID</th>
|
|
||||||
<th class="">Nombre</th>
|
|
||||||
<th class="has-text-centered">Total Vuelos</th>
|
|
||||||
<th class="has-text-centered">Horas totales</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="item in whitelist" :key="item.vid">
|
|
||||||
<td class="has-text-centered">
|
|
||||||
{{ item.vid }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ item.name }}
|
|
||||||
</td>
|
|
||||||
<td class="has-text-centered">
|
|
||||||
{{ item.flights }}
|
|
||||||
</td>
|
|
||||||
<td class="has-text-centered">
|
|
||||||
<FormatTime :value="item.flightTime" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@ -83,60 +132,7 @@ export default {
|
|||||||
.tag {
|
.tag {
|
||||||
font-size: 60% !important;
|
font-size: 60% !important;
|
||||||
}
|
}
|
||||||
/* header {
|
.input-login {
|
||||||
line-height: 1.5;
|
width: 100px;
|
||||||
max-height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
|
||||||
width: 100%;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a.router-link-exact-active {
|
|
||||||
color: var(--color-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a.router-link-exact-active:hover {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0 1rem;
|
|
||||||
border-left: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav a:first-of-type {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
header {
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
padding-right: calc(var(--section-gap) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
margin: 0 2rem 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header .wrapper {
|
|
||||||
display: flex;
|
|
||||||
place-items: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav {
|
|
||||||
text-align: left;
|
|
||||||
margin-left: -1rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
|
|
||||||
padding: 1rem 0;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
interval: undefined,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
list: [],
|
list: [],
|
||||||
board: undefined,
|
board: undefined,
|
||||||
@ -47,9 +48,12 @@
|
|||||||
await this.loadData();
|
await this.loadData();
|
||||||
this.startLoop();
|
this.startLoop();
|
||||||
},
|
},
|
||||||
|
unmounted() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
startLoop() {
|
startLoop() {
|
||||||
setInterval(this.loadData, 10000)
|
this.interval = setInterval(this.loadData, 1000 * 30)
|
||||||
},
|
},
|
||||||
async loadData() {
|
async loadData() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
22
src/data/http/auth.js
Normal file
22
src/data/http/auth.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {get, post } from './requests.js';
|
||||||
|
|
||||||
|
export async function isAlive() {
|
||||||
|
const { VITE_API_BASE } =
|
||||||
|
import.meta.env;
|
||||||
|
const response = await get(`${VITE_API_BASE}/admin/user/alive`);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authenticate(username, password) {
|
||||||
|
const { VITE_API_BASE, VITE_API_PATH_AUTHENTICATION } =
|
||||||
|
import.meta.env;
|
||||||
|
const response = await post(`${VITE_API_BASE}${VITE_API_PATH_AUTHENTICATION}`, { username, password });
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function logout() {
|
||||||
|
const { VITE_API_BASE } =
|
||||||
|
import.meta.env;
|
||||||
|
const response = await get(`${VITE_API_BASE}/admin/user/logout`);
|
||||||
|
return response;
|
||||||
|
}
|
@ -1,26 +1,26 @@
|
|||||||
import { request } from './requests.js';
|
import {get } from './requests.js';
|
||||||
|
|
||||||
export async function getMonthlyList() {
|
export async function getMonthlyList() {
|
||||||
const { VITE_API_BASE, VITE_API_PATH_LIST } =
|
const { VITE_API_BASE, VITE_API_PATH_LIST } =
|
||||||
import.meta.env;
|
import.meta.env;
|
||||||
const response = await request(`${VITE_API_BASE}${VITE_API_PATH_LIST}`);
|
const response = await get(`${VITE_API_BASE}${VITE_API_PATH_LIST}`);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
export async function getWhitelist() {
|
export async function getWhitelist() {
|
||||||
const { VITE_API_BASE, VITE_API_PATH_WHITELIST } =
|
const { VITE_API_BASE, VITE_API_PATH_WHITELIST } =
|
||||||
import.meta.env;
|
import.meta.env;
|
||||||
const response = await request(`${VITE_API_BASE}${VITE_API_PATH_WHITELIST}`);
|
const response = await get(`${VITE_API_BASE}${VITE_API_PATH_WHITELIST}`);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
export async function getInSessionNow() {
|
export async function getInSessionNow() {
|
||||||
const { VITE_API_BASE, VITE_API_PATH_NOW_SESSIONS } =
|
const { VITE_API_BASE, VITE_API_PATH_NOW_SESSIONS } =
|
||||||
import.meta.env;
|
import.meta.env;
|
||||||
const response = await request(`${VITE_API_BASE}${VITE_API_PATH_NOW_SESSIONS}`);
|
const response = await get(`${VITE_API_BASE}${VITE_API_PATH_NOW_SESSIONS}`);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
export async function getFlightplansNow() {
|
export async function getFlightplansNow() {
|
||||||
const { VITE_API_BASE, VITE_API_PATH_NOW_FLIGHTPLANS } =
|
const { VITE_API_BASE, VITE_API_PATH_NOW_FLIGHTPLANS } =
|
||||||
import.meta.env;
|
import.meta.env;
|
||||||
const response = await request(`${VITE_API_BASE}${VITE_API_PATH_NOW_FLIGHTPLANS}`);
|
const response = await get(`${VITE_API_BASE}${VITE_API_PATH_NOW_FLIGHTPLANS}`);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
@ -1,6 +1,15 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const request = async(url, options) => {
|
export const get = async(url) => {
|
||||||
const response = await axios.get(url, options);
|
const response = await axios.get(url, { withCredentials: true });
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const post = async(url, data) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(url, data, { withCredentials: true });
|
||||||
|
return response.data;
|
||||||
|
} catch (err) {
|
||||||
|
console.log('err :>> ', err.response);
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,17 @@
|
|||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import VueMobileDetection from 'vue-mobile-detection';
|
import VueMobileDetection from 'vue-mobile-detection';
|
||||||
|
|
||||||
import './assets/css/main.css';
|
import './assets/css/main.css';
|
||||||
|
|
||||||
|
const pinia = createPinia();
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(pinia);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(VueMobileDetection);
|
app.use(VueMobileDetection);
|
||||||
|
|
||||||
|
|
||||||
app.mount('#app');
|
app.mount('#app');
|
@ -1,6 +1,7 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
import TableAcars from '../components/TableAcars.vue';
|
import TableAcars from '../components/TableAcars.vue';
|
||||||
import IvaoView from '../views/IvaoView.vue';
|
import IvaoView from '../views/IvaoView.vue';
|
||||||
|
import CabalView from '../views/CabalView.vue';
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(
|
history: createWebHistory(
|
||||||
@ -15,6 +16,11 @@ const router = createRouter({
|
|||||||
name: 'acars',
|
name: 'acars',
|
||||||
component: TableAcars,
|
component: TableAcars,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/cabal',
|
||||||
|
name: 'cabal',
|
||||||
|
component: CabalView,
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// path: '/about',
|
// path: '/about',
|
||||||
// name: 'about',
|
// name: 'about',
|
||||||
|
26
src/stores/session-store.js
Normal file
26
src/stores/session-store.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useSessionStore = defineStore('user', {
|
||||||
|
state: () => ({ _user: {}, _isAuthenticated: false }),
|
||||||
|
getters: {
|
||||||
|
user: (state) => state._user,
|
||||||
|
isAuthenticated: (state) => state._isAuthenticated,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setUser(user) {
|
||||||
|
this._isAuthenticated = !!user;
|
||||||
|
this._user = user;
|
||||||
|
},
|
||||||
|
logoutUser() {
|
||||||
|
this._isAuthenticated = false;
|
||||||
|
this._user = '';
|
||||||
|
},
|
||||||
|
hasRoles(roles = []) {
|
||||||
|
let hasRole = false;
|
||||||
|
roles.forEach(role => {
|
||||||
|
hasRole = hasRole || (this._user.roles || []).indexOf(role) !== -1;
|
||||||
|
})
|
||||||
|
return hasRole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
8
src/views/CabalView.vue
Normal file
8
src/views/CabalView.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<script setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main class="section">
|
||||||
|
<h1 class="title is-2"> Capitán Cabal Hub</h1>
|
||||||
|
</main>
|
||||||
|
</template>
|
@ -1,9 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import TheWelcome from "../components/TheWelcome.vue";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<main>
|
|
||||||
<TheWelcome />
|
|
||||||
</main>
|
|
||||||
</template>
|
|
@ -4,7 +4,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main>
|
<main class="section">
|
||||||
<InSessionNow v-if="!$isMobile()" />
|
<InSessionNow v-if="!$isMobile()" />
|
||||||
<TableIvao />
|
<TableIvao />
|
||||||
</main>
|
</main>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user