This commit is contained in:
parent
a859871265
commit
645a10477d
@ -0,0 +1,7 @@
|
||||
{
|
||||
"useTabs":false,
|
||||
"semi":true,
|
||||
"trailingComma":"es5",
|
||||
"arrowParens":"always",
|
||||
"tabWidth":4
|
||||
}
|
@ -1,29 +1,29 @@
|
||||
import eslint from '@eslint/js';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||
import eslintPluginVue from 'eslint-plugin-vue';
|
||||
import globals from 'globals';
|
||||
import typescriptEslint from 'typescript-eslint';
|
||||
import eslint from "@eslint/js";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import eslintPluginVue from "eslint-plugin-vue";
|
||||
import globals from "globals";
|
||||
import typescriptEslint from "typescript-eslint";
|
||||
|
||||
export default typescriptEslint.config(
|
||||
{ ignores: ['*.d.ts', '**/coverage', '**/dist'] },
|
||||
{ ignores: ["*.d.ts", "**/coverage", "**/dist"] },
|
||||
{
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
...typescriptEslint.configs.recommended,
|
||||
...eslintPluginVue.configs['flat/recommended'],
|
||||
...eslintPluginVue.configs["flat/recommended"],
|
||||
],
|
||||
files: ['**/*.{ts,vue}'],
|
||||
files: ["**/*.{ts,vue}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
parser: typescriptEslint.parser,
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// your rules
|
||||
},
|
||||
},
|
||||
eslintConfigPrettier
|
||||
);
|
||||
);
|
||||
|
1397
front/MyINPulse-front/package-lock.json
generated
1397
front/MyINPulse-front/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,7 @@
|
||||
"globals": "^15.14.0",
|
||||
"jiti": "^2.4.2",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"prettier": "3.5.0",
|
||||
"typescript": "~5.7.3",
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"vite": "^6.0.11",
|
||||
|
@ -1,49 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import { RouterView } from "vue-router";
|
||||
import ErrorWrapper from "@/views/errorWrapper.vue";
|
||||
import ProjectComponent from "@/components/ProjectComponent.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<HeaderComponent />
|
||||
<error-wrapper></error-wrapper>
|
||||
<div id="main">
|
||||
<ProjectComponent
|
||||
v-for="(project, index) in projects"
|
||||
:key="index"
|
||||
:project-name="project.name"
|
||||
/>
|
||||
<HeaderComponent />
|
||||
<error-wrapper></error-wrapper>
|
||||
<div id="main">
|
||||
<ProjectComponent
|
||||
v-for="(project, index) in projects"
|
||||
:key="index"
|
||||
:project-name="project.name"
|
||||
/>
|
||||
</div>
|
||||
<RouterView />
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import HeaderComponent from "@/components/HeaderComponent.vue";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
HeaderComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [
|
||||
{
|
||||
name: 'Projet Alpha',
|
||||
//link: './project-alpha.html',
|
||||
//members: ['Alice', 'Bob', 'Charlie'],
|
||||
},
|
||||
{
|
||||
name: 'Projet Beta',
|
||||
//link: './project-beta.html',
|
||||
//members: ['David', 'Eve', 'Frank'],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
name: "App",
|
||||
components: {
|
||||
HeaderComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
projects: [
|
||||
{
|
||||
name: "Projet Alpha",
|
||||
//link: './project-alpha.html',
|
||||
//members: ['Alice', 'Bob', 'Charlie'],
|
||||
},
|
||||
{
|
||||
name: "Projet Beta",
|
||||
//link: './project-beta.html',
|
||||
//members: ['David', 'Eve', 'Frank'],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<header>
|
||||
<img src="./icons/logo inpulse.png" alt="INPulse" />
|
||||
<img src="./icons/logo inpulse.png" alt="INPulse" />
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'HeaderComponent',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
header img {
|
||||
width: 100px;
|
||||
}
|
||||
</template>
|
||||
|
||||
header{
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "HeaderComponent",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
header img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #fff;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
@ -3,21 +3,19 @@
|
||||
<div class="project-header">
|
||||
<h2>{{ projectName }}</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import type {PropType} from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
export default {
|
||||
name: 'ProjectComponent',
|
||||
name: "ProjectComponent",
|
||||
props: {
|
||||
projectName: {
|
||||
type: Object as PropType<string>,
|
||||
required: true
|
||||
type: Object as PropType<string>,
|
||||
required: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,29 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import {color} from "@/services/popupDisplayer.ts";
|
||||
import type {PropType} from "vue";
|
||||
import { color } from "@/services/popupDisplayer.ts";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
defineProps({
|
||||
errorMessage: {
|
||||
type: Object as PropType<string>,
|
||||
required: true
|
||||
},
|
||||
errorColor: {
|
||||
type: Object as PropType<color>,
|
||||
default: color.Red
|
||||
}
|
||||
errorMessage: {
|
||||
type: Object as PropType<string>,
|
||||
required: true,
|
||||
},
|
||||
errorColor: {
|
||||
type: Object as PropType<color>,
|
||||
default: color.Red,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class='["red", "yellow", "blue", "green"][errorColor]' class="error-modal">
|
||||
<p>{{["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][errorColor]}}</p>
|
||||
<p>{{errorMessage}}</p>
|
||||
<div class="loading" :class='["red-loader", "yellow-loader", "blue-loader", "green-loader"][errorColor]'></div>
|
||||
</div>
|
||||
<div
|
||||
:class="['red', 'yellow', 'blue', 'green'][errorColor]"
|
||||
class="error-modal"
|
||||
>
|
||||
<p>
|
||||
{{
|
||||
["Erreur :(", "Warning :|", "Info :)", "Succes ;)"][errorColor]
|
||||
}}
|
||||
</p>
|
||||
<p>{{ errorMessage }}</p>
|
||||
<div
|
||||
class="loading"
|
||||
:class="
|
||||
['red-loader', 'yellow-loader', 'blue-loader', 'green-loader'][
|
||||
errorColor
|
||||
]
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.error-modal{
|
||||
.error-modal {
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 1em;
|
||||
@ -31,41 +45,45 @@ defineProps({
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
animation: disappear 5s linear forwards;
|
||||
}
|
||||
}
|
||||
|
||||
.red{
|
||||
.red {
|
||||
background-color: #ee6055;
|
||||
color: white;
|
||||
}
|
||||
.red-loader {
|
||||
}
|
||||
|
||||
.red-loader {
|
||||
background-color: #fa8383;
|
||||
}
|
||||
}
|
||||
|
||||
.yellow{
|
||||
background-color: #FF9D23;
|
||||
color: white;
|
||||
}
|
||||
.yellow-loader{
|
||||
.yellow {
|
||||
background-color: #ff9d23;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.yellow-loader {
|
||||
background-color: #ffbf81;
|
||||
}
|
||||
}
|
||||
|
||||
.blue {
|
||||
.blue {
|
||||
background-color: #809bce;
|
||||
color: white;
|
||||
}
|
||||
.blue-loader{
|
||||
background-color: #95b8d1;
|
||||
}
|
||||
}
|
||||
|
||||
.green {
|
||||
.blue-loader {
|
||||
background-color: #95b8d1;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
.green-loader {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
.green-loader {
|
||||
background-color: darkgreen;
|
||||
}
|
||||
|
||||
.loading {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
@ -74,33 +92,33 @@ defineProps({
|
||||
height: 1em;
|
||||
width: 0;
|
||||
animation: loading 4s linear forwards;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation for the loading bar */
|
||||
@keyframes loading {
|
||||
/* Animation for the loading bar */
|
||||
@keyframes loading {
|
||||
0% {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
100% {
|
||||
width: 0;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes disappear {
|
||||
@keyframes disappear {
|
||||
0% {
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
80% {
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
}
|
||||
100% {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
@ -1,17 +1,16 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router/router.ts'
|
||||
import {createPinia} from "pinia";
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import keycloakService from './services/keycloak';
|
||||
import {type AuthStore, useAuthStore} from "@/stores/authStore.ts";
|
||||
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router/router.ts";
|
||||
import { createPinia } from "pinia";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
import keycloakService from "./services/keycloak";
|
||||
import { type AuthStore, useAuthStore } from "@/stores/authStore.ts";
|
||||
|
||||
let store: AuthStore;
|
||||
|
||||
keycloakService.CallInit(() => {
|
||||
try {
|
||||
const app = createApp(App)
|
||||
const app = createApp(App);
|
||||
|
||||
// Setup pinia store, allowing user to keep logged in status after refresh
|
||||
const pinia = createPinia();
|
||||
@ -19,19 +18,14 @@ keycloakService.CallInit(() => {
|
||||
app.use(pinia);
|
||||
store = useAuthStore();
|
||||
keycloakService.CallInitStore(store);
|
||||
app.use(router)
|
||||
app.use(router);
|
||||
|
||||
app.mount('#app');
|
||||
app.mount("#app");
|
||||
} catch (e) {
|
||||
console.error("Error while initiating Keycloak.")
|
||||
console.error(e)
|
||||
createApp(App).mount('#app');
|
||||
console.error("Error while initiating Keycloak.");
|
||||
console.error(e);
|
||||
createApp(App).mount("#app");
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export {store};
|
||||
export { store };
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/test',
|
||||
name: 'test',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/testComponent.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/test",
|
||||
name: "test",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import("../views/testComponent.vue"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default router
|
||||
export default router;
|
||||
|
@ -1,31 +1,36 @@
|
||||
import axios, {type AxiosError, type AxiosResponse} from "axios";
|
||||
import {store} from "@/main.ts";
|
||||
import {addNewMessage, color} from "@/services/popupDisplayer.ts";
|
||||
import axios, { type AxiosError, type AxiosResponse } from "axios";
|
||||
import { store } from "@/main.ts";
|
||||
import { addNewMessage, color } from "@/services/popupDisplayer.ts";
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: import.meta.env.VITE_BACKEND_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
response => response, // Directly return successful responses.
|
||||
async error => {
|
||||
(response) => response, // Directly return successful responses.
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
if (error.response.status === 401 && !originalRequest._retry && store.authenticated) {
|
||||
if (
|
||||
error.response.status === 401 &&
|
||||
!originalRequest._retry &&
|
||||
store.authenticated
|
||||
) {
|
||||
originalRequest._retry = true; // Mark the request as retried to avoid infinite loops.
|
||||
try {
|
||||
await store.refreshUserToken();
|
||||
// Update the authorization header with the new access token.
|
||||
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${store.user.token}`;
|
||||
axiosInstance.defaults.headers.common["Authorization"] =
|
||||
`Bearer ${store.user.token}`;
|
||||
return axiosInstance(originalRequest); // Retry the original request with the new access token.
|
||||
} catch (refreshError) {
|
||||
// Handle refresh token errors by clearing stored tokens and redirecting to the login page.
|
||||
console.error('Token refresh failed:', refreshError);
|
||||
localStorage.removeItem('accessToken');
|
||||
localStorage.removeItem('refreshToken');
|
||||
window.location.href = '/login';
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
localStorage.removeItem("accessToken");
|
||||
localStorage.removeItem("refreshToken");
|
||||
window.location.href = "/login";
|
||||
return Promise.reject(refreshError);
|
||||
}
|
||||
}
|
||||
@ -34,20 +39,29 @@ axiosInstance.interceptors.response.use(
|
||||
);
|
||||
|
||||
// TODO: spawn a error modal
|
||||
function defaultApiErrorHandler(err: AxiosError){
|
||||
function defaultApiErrorHandler(err: AxiosError) {
|
||||
addNewMessage(err.message, color.Red);
|
||||
}
|
||||
|
||||
function defaultApiSuccessHandler(response: AxiosResponse){
|
||||
addNewMessage(response.data, color.Green)
|
||||
}
|
||||
function callApi(endpoint: string, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void): void {
|
||||
axiosInstance.get(endpoint).then(
|
||||
onSuccessHandler == null ? defaultApiSuccessHandler : onSuccessHandler
|
||||
).catch(
|
||||
onErrorHandler == null ? defaultApiErrorHandler: onErrorHandler
|
||||
)
|
||||
function defaultApiSuccessHandler(response: AxiosResponse) {
|
||||
addNewMessage(response.data, color.Green);
|
||||
}
|
||||
|
||||
function callApi(
|
||||
endpoint: string,
|
||||
onSuccessHandler?: (response: AxiosResponse) => void,
|
||||
onErrorHandler?: (error: AxiosError) => void
|
||||
): void {
|
||||
axiosInstance
|
||||
.get(endpoint)
|
||||
.then(
|
||||
onSuccessHandler == null
|
||||
? defaultApiSuccessHandler
|
||||
: onSuccessHandler
|
||||
)
|
||||
.catch(
|
||||
onErrorHandler == null ? defaultApiErrorHandler : onErrorHandler
|
||||
);
|
||||
}
|
||||
|
||||
export {callApi}
|
||||
export { callApi };
|
||||
|
@ -1,34 +1,31 @@
|
||||
import Keycloak from 'keycloak-js';
|
||||
import type {AuthStore} from "@/stores/authStore.ts";
|
||||
import Keycloak from "keycloak-js";
|
||||
import type { AuthStore } from "@/stores/authStore.ts";
|
||||
|
||||
const options = {
|
||||
url: import.meta.env.VITE_KEYCLOAK_URL,
|
||||
clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,
|
||||
realm: import.meta.env.VITE_KEYCLOAK_REALM
|
||||
}
|
||||
|
||||
realm: import.meta.env.VITE_KEYCLOAK_REALM,
|
||||
};
|
||||
|
||||
const keycloak = new Keycloak(options);
|
||||
let authenticated: boolean | undefined;
|
||||
let store = null;
|
||||
|
||||
async function login(){
|
||||
async function login() {
|
||||
try {
|
||||
await keycloak.login() // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
await keycloak.login(); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function signup(){
|
||||
async function signup() {
|
||||
try {
|
||||
await keycloak.login(
|
||||
{action: "register"}
|
||||
) // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
await keycloak.login({ action: "register" }); // https://www.keycloak.org/securing-apps/javascript-adapter#:~:text=when%20initialization%20completes.-,login(options),-Redirects%20to%20login
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,13 +40,13 @@ async function init(onInitCallback: () => void) {
|
||||
onLoad: "check-sso",
|
||||
silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.htm`,
|
||||
responseMode: "query",
|
||||
})
|
||||
onInitCallback()
|
||||
});
|
||||
onInitCallback();
|
||||
} catch (error) {
|
||||
console.error("Keycloak init failed")
|
||||
console.error(error)
|
||||
console.error("Keycloak init failed");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes store with Keycloak user data
|
||||
@ -57,17 +54,19 @@ async function init(onInitCallback: () => void) {
|
||||
*/
|
||||
async function initStore(storeInstance: AuthStore) {
|
||||
try {
|
||||
store = storeInstance
|
||||
console.log(keycloak)
|
||||
await store.initOauth(keycloak)
|
||||
store = storeInstance;
|
||||
console.log(keycloak);
|
||||
await store.initOauth(keycloak);
|
||||
|
||||
// Show alert if user is not authenticated
|
||||
if (!authenticated) { console.warn("not authenticated") }
|
||||
if (!authenticated) {
|
||||
console.warn("not authenticated");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Keycloak init failed")
|
||||
console.error(error)
|
||||
console.error("Keycloak init failed");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user
|
||||
@ -84,7 +83,7 @@ async function refreshToken() {
|
||||
await keycloak.updateToken(480);
|
||||
return keycloak;
|
||||
} catch (error) {
|
||||
console.error('Failed to refresh token');
|
||||
console.error("Failed to refresh token");
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
@ -98,4 +97,4 @@ const KeycloakService = {
|
||||
callSignup: signup,
|
||||
};
|
||||
|
||||
export default KeycloakService;
|
||||
export default KeycloakService;
|
||||
|
@ -1,6 +1,11 @@
|
||||
import {ref} from "vue";
|
||||
import {type Ref} from "vue";
|
||||
enum color {Red, Yellow, Blue, Green}
|
||||
import { ref, type Ref } from "vue";
|
||||
|
||||
enum color {
|
||||
Red,
|
||||
Yellow,
|
||||
Blue,
|
||||
Green,
|
||||
}
|
||||
|
||||
type ErrorMessageContent = {
|
||||
message: string;
|
||||
@ -11,23 +16,28 @@ type ErrorMessageContent = {
|
||||
|
||||
let id: number = 0;
|
||||
const getId = () => {
|
||||
id = id+1;
|
||||
id = id + 1;
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
function addNewMessage(errorMessage: string, type?: color, timeout?: number){
|
||||
if (timeout == null){
|
||||
function addNewMessage(errorMessage: string, type?: color, timeout?: number) {
|
||||
if (timeout == null) {
|
||||
timeout = 5000;
|
||||
}
|
||||
if (type == null){
|
||||
if (type == null) {
|
||||
type = color.Red;
|
||||
}
|
||||
|
||||
const data: ErrorMessageContent = {message: errorMessage, timeout: timeout, color: type, id: getId()};
|
||||
errorList.value.push(data)
|
||||
setTimeout(() => errorList.value.slice(0, 1), timeout)
|
||||
const data: ErrorMessageContent = {
|
||||
message: errorMessage,
|
||||
timeout: timeout,
|
||||
color: type,
|
||||
id: getId(),
|
||||
};
|
||||
errorList.value.push(data);
|
||||
setTimeout(() => errorList.value.slice(0, 1), timeout);
|
||||
}
|
||||
|
||||
const errorList: Ref<ErrorMessageContent[]>= ref([])
|
||||
const errorList: Ref<ErrorMessageContent[]> = ref([]);
|
||||
|
||||
export {addNewMessage, errorList, color, type ErrorMessageContent}
|
||||
export { addNewMessage, errorList, color, type ErrorMessageContent };
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { defineStore } from "pinia";
|
||||
import keycloakService from '@/services/keycloak';
|
||||
import keycloakService from "@/services/keycloak";
|
||||
import type Keycloak from "keycloak-js";
|
||||
|
||||
const useAuthStore = defineStore("storeAuth", {
|
||||
@ -11,44 +11,51 @@ const useAuthStore = defineStore("storeAuth", {
|
||||
refreshToken: "",
|
||||
username: "",
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
persist: true,
|
||||
getters: {},
|
||||
actions: {
|
||||
// Initialize Keycloak OAuth
|
||||
async initOauth(keycloak: Keycloak, clearData = true) {
|
||||
if(clearData) { await this.clearUserData(); }
|
||||
if (clearData) {
|
||||
await this.clearUserData();
|
||||
}
|
||||
|
||||
this.authenticated = !!keycloak.authenticated; // the !! removes undefined
|
||||
if (this.authenticated && keycloak.token && keycloak.idTokenParsed && keycloak.refreshToken){
|
||||
if (
|
||||
this.authenticated &&
|
||||
keycloak.token &&
|
||||
keycloak.idTokenParsed &&
|
||||
keycloak.refreshToken
|
||||
) {
|
||||
this.user.username = keycloak.idTokenParsed.given_name;
|
||||
this.user.token = keycloak.token;
|
||||
this.user.refreshToken = keycloak.refreshToken;
|
||||
}
|
||||
},
|
||||
async login(){
|
||||
async login() {
|
||||
try {
|
||||
const keycloak = await keycloakService.callLogin();
|
||||
if (keycloak)
|
||||
await this.initOauth(keycloak);
|
||||
if (keycloak) await this.initOauth(keycloak);
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
async signup() {
|
||||
try {
|
||||
const keycloak = await keycloakService.callSignup();
|
||||
if (keycloak)
|
||||
await this.initOauth(keycloak);
|
||||
if (keycloak) await this.initOauth(keycloak);
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
// Logout user
|
||||
async logout() {
|
||||
try {
|
||||
await keycloakService.CallLogout(import.meta.env.VITE_APP_URL + "/test");
|
||||
await keycloakService.CallLogout(
|
||||
import.meta.env.VITE_APP_URL + "/test"
|
||||
);
|
||||
await this.clearUserData();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@ -58,8 +65,7 @@ const useAuthStore = defineStore("storeAuth", {
|
||||
async refreshUserToken() {
|
||||
try {
|
||||
const keycloak = await keycloakService.CallTokenRefresh();
|
||||
if (keycloak)
|
||||
await this.initOauth(keycloak, false);
|
||||
if (keycloak) await this.initOauth(keycloak, false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@ -69,13 +75,13 @@ const useAuthStore = defineStore("storeAuth", {
|
||||
this.authenticated = false;
|
||||
this.user = {
|
||||
token: "",
|
||||
refreshToken: "",
|
||||
username: "",
|
||||
refreshToken: "",
|
||||
username: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
type AuthStore = ReturnType<typeof useAuthStore>
|
||||
type AuthStore = ReturnType<typeof useAuthStore>;
|
||||
|
||||
export {useAuthStore, type AuthStore}
|
||||
export { useAuthStore, type AuthStore };
|
||||
|
@ -1,22 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {errorList} from "@/services/popupDisplayer.ts";
|
||||
import { errorList } from "@/services/popupDisplayer.ts";
|
||||
import ErrorModal from "@/components/errorModal.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="error-wrapper">
|
||||
<error-modal v-for="elm in errorList" :key="elm.id" :error-message=elm.message :error-color="elm.color"></error-modal>
|
||||
</div>
|
||||
<div class="error-wrapper">
|
||||
<error-modal
|
||||
v-for="elm in errorList"
|
||||
:key="elm.id"
|
||||
:error-message="elm.message"
|
||||
:error-color="elm.color"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.error-wrapper{
|
||||
position: absolute;
|
||||
left: 70%;
|
||||
//background-color: blue;
|
||||
height: 100%;
|
||||
width: 30%;
|
||||
|
||||
.error-wrapper {
|
||||
position: absolute;
|
||||
left: 70%;
|
||||
//background-color: blue;
|
||||
height: 100%;
|
||||
width: 30%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -1,66 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
import {store} from "../main.ts";
|
||||
import {callApi} from "@/services/api.ts";
|
||||
<script lang="ts" setup>
|
||||
import { store } from "../main.ts";
|
||||
import { callApi } from "@/services/api.ts";
|
||||
import TempModal from "@/components/temp-modal.vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>Test page</h1>
|
||||
<table class="test" style="width:100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Is Currently Authenticated ? </td>
|
||||
<td>{{store.authenticated}}</td>
|
||||
<td><button @click="store.login">Login</button></td>
|
||||
<td><button @click="store.logout">Logout</button></td>
|
||||
<td><button @click="store.signup">Signup</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>current token</td>
|
||||
<td>{{store.user.token}}</td>
|
||||
<td><button @click="store.refreshUserToken">Refresh</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current refresh token</td>
|
||||
<td>{{store.user.refreshToken}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Entrepreneur API call</td>
|
||||
<td><button @click="callApi('random')">call</button></td>
|
||||
<td>res</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Admin API call</td>
|
||||
<td><button @click="callApi('random2')">call</button></td>
|
||||
<td>res</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unauth API call</td>
|
||||
<td><button @click="callApi('random3')">call</button></td>
|
||||
<td>res</td>
|
||||
<td id="3"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<temp-modal></temp-modal>
|
||||
<h1>Test page</h1>
|
||||
<table class="test" style="width: 100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Is Currently Authenticated ?</td>
|
||||
<td>{{ store.authenticated }}</td>
|
||||
<td>
|
||||
<button @click="store.login">Login</button>
|
||||
</td>
|
||||
<td>
|
||||
<button @click="store.logout">Logout</button>
|
||||
</td>
|
||||
<td>
|
||||
<button @click="store.signup">Signup</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>current token</td>
|
||||
<td>{{ store.user.token }}</td>
|
||||
<td>
|
||||
<button @click="store.refreshUserToken">Refresh</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current refresh token</td>
|
||||
<td>{{ store.user.refreshToken }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Entrepreneur API call</td>
|
||||
<td>
|
||||
<button @click="callApi('random')">call</button>
|
||||
</td>
|
||||
<td>res</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Admin API call</td>
|
||||
<td>
|
||||
<button @click="callApi('random2')">call</button>
|
||||
</td>
|
||||
<td>res</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unauth API call</td>
|
||||
<td>
|
||||
<button @click="callApi('random3')">call</button>
|
||||
</td>
|
||||
<td>res</td>
|
||||
<td id="3"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<temp-modal></temp-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
table {
|
||||
width: 100px;
|
||||
table-layout: fixed
|
||||
}
|
||||
tr {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
td {
|
||||
}
|
||||
|
||||
td {
|
||||
border: solid 1px black;
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user