Skip to content

Commit

Permalink
Merge pull request #179 from abes-esr/ITEM-363-PAGE-DE-MAINTENANCE
Browse files Browse the repository at this point in the history
Item 363 page de maintenance
  • Loading branch information
pierre-maraval authored Nov 27, 2024
2 parents 6ed4b66 + 44a73f7 commit 1451fe4
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 85 deletions.
1 change: 1 addition & 0 deletions .env-dist
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
VITE_API_URL=
VITE_API_URL_IDREF=
VITE_MAINTENANCE=false
24 changes: 21 additions & 3 deletions README-developpement.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,55 @@ Le langage utilisé est JavaScript, avec le framework VueJs 3.

Ce dépôt héberge le code source de l'interface utilisateur de Item (développée en VueJS) codée en VueJs 3.
Cette interface utilisateur fonctionne en lien avec son API développée en Java : https://github.com/abes-esr/item-api/
L'application Item complète peut être déployée via Docker à l'aide de ce dépôt : https://github.com/abes-esr/item-docker/ .
L'application Item complète peut être déployée via Docker à l'aide de ce
dépôt : https://github.com/abes-esr/item-docker/ .
Les principaux plugins installés dans ce projet sont : Vite, Pinia, Vue-router, Vuetify et Axios.

## Installation du projet et démarrage

### Installation du projet

```
npm install
```
Une fois installé, il faut dupliquer le ``.env-dist`` puis renommer le duplicata en ``.env``. Completer ensuite les variables d'environnement dans le ``.env``.

Une fois installé, il faut dupliquer le ``.env-dist`` puis renommer le duplicata en ``.env``. Completer ensuite les
variables d'environnement dans le ``.env``.

### Compilation et rechargement à chaud pour le développement

```
npm run dev
```
Une fois cette commande lancée, l'url de l'application sera affichée (dans le terminal ou dans les logs, selon l'environnement de déploiement).

Une fois cette commande lancée, l'url de l'application sera affichée (dans le terminal ou dans les logs, selon
l'environnement de déploiement).

### Compilation complète

```
npm run build
```

### Compilation pour prévisualisation

```
npm run preview
```

### Compilation "prettier"

```
npm run prettier
```

### Configurations personnalisées

See [Configuration Reference](https://cli.vuejs.org/config/).

## Maintenance

Pour passer l'application en mode maintenance il suffit de passer la variable d'environement `VITE_MAINTENANCE` à
`true`.
Sinon pour passer en mode maintenance sur les serveurs, il suffit de passer la varable `ITEM_FRONT_MAINTENANCE` à `true`
du projet [Item-docker](https://github.com/abes-esr/item-docker).
4 changes: 4 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Paramètres par défaut du conteneur
export ITEM_FRONT_API_BASEURL=${ITEM_FRONT_API_BASEURL:='http://localhost:8081/'}
export ITEM_FRONT_IDREF_API_URL=${ITEM_FRONT_IDREF_API_URL:='http://localhost:8081/'}
export ITEM_FRONT_MAINTENANCE=${ITEM_FRONT_MAINTENANCE:='false'}


# Remplace les placeholders dans le code généré en prod
Expand All @@ -19,6 +20,9 @@ sed -i \
sed -i \
"s#ITEM_PLACEHOLDER_VITE_IDREF_API_URL#${ITEM_FRONT_IDREF_API_URL}#g" \
/usr/share/nginx/html/assets/*
sed -i \
"s#ITEM_PLACEHOLDER_VITE_MAINTENANCE#${ITEM_FRONT_MAINTENANCE}#g" \
/usr/share/nginx/html/assets/*

# execute nginx (cf CMD dans Dockerfile)
exec "$@"
1 change: 1 addition & 0 deletions docker/vuejs_env_placeholder
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
# et éviter ainsi d'avoir une URL de l'API en static dans l'image docker
VITE_API_URL=ITEM_PLACEHOLDER_VITE_API_URL
VITE_API_URL_IDREF=ITEM_PLACEHOLDER_VITE_IDREF_API_URL
VITE_MAINTENANCE=ITEM_PLACEHOLDER_VITE_MAINTENANCE
165 changes: 83 additions & 82 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,61 +1,62 @@
<template>
<v-app class="h-100 overflow-hidden">
<nav>
<Header @logout-success="onLogout" @toggle-drawer="toggleDrawer"/>
<Navbar :drawer="drawer" @close="drawer = false" />
</nav>
<v-main class="d-flex flex-column overflow-auto">
<div class="error-stack">
<v-alert
v-for="(error, index) in errorStack"
:key="index"
color="error"
icon="$error"
:title="error.message"
variant="flat"
border="start"
class="mb-2 custom-alert"
closable
@click:close="closeAlert(index)"
>
{{ error.description }}
</v-alert>
</div>
<div style="flex-grow: 10;">
<router-view v-slot="{ Component }">
<component
:is="Component"
@backendError="addError"
@backendSuccess="clearErrors"
/>
</router-view>
</div>
<InfoAppBanner v-if="!authenticated" />
<Footer style="flex-basis: 0;" />
</v-main>
</v-app>
<v-app class="h-100 overflow-hidden">
<maintenance/>
<nav>
<Header @logout-success="onLogout" @toggle-drawer="toggleDrawer"/>
<Navbar :drawer="drawer" @close="drawer = false"/>
</nav>
<v-main class="d-flex flex-column overflow-auto">
<div class="error-stack">
<v-alert
v-for="(error, index) in errorStack"
:key="index"
color="error"
icon="$error"
:title="error.message"
variant="flat"
border="start"
class="mb-2 custom-alert"
closable
@click:close="closeAlert(index)"
>
{{ error.description }}
</v-alert>
</div>
<div style="flex-grow: 10;">
<router-view v-slot="{ Component }">
<component
:is="Component"
@backendError="addError"
@backendSuccess="clearErrors"
/>
</router-view>
</div>
<InfoAppBanner v-if="!authenticated"/>
<Footer style="flex-basis: 0;"/>
</v-main>
</v-app>
</template>

<script setup>
import {computed, ref, watch} from 'vue'
import Header from '@/components/Structure/Header.vue'
import Navbar from '@/components/Structure/Navbar.vue'
import Footer from '@/components/Structure/Footer.vue'
import router from '@/router/index'
import {HttpStatusCode} from 'axios'
import InfoAppBanner from '@/components/Structure/InfoAppBanner.vue'
import {useAuthStore} from '@/store/authStore'
import {useRoute} from "vue-router";
const errorStack = ref([])
const drawer = ref(false)
const authStore = useAuthStore()
import { computed, ref, watch } from 'vue';
import Header from '@/components/Structure/Header.vue';
import Navbar from '@/components/Structure/Navbar.vue';
import Footer from '@/components/Structure/Footer.vue';
import router from '@/router/index';
import { HttpStatusCode } from 'axios';
import InfoAppBanner from '@/components/Structure/InfoAppBanner.vue';
import { useAuthStore } from '@/store/authStore';
import { useRoute } from 'vue-router';
import Maintenance from '@/components/Structure/Maintenance.vue';
const errorStack = ref([]);
const drawer = ref(false);
const authStore = useAuthStore();
const authenticated = computed(() => {
return authStore.isAuthenticated
})
return authStore.isAuthenticated;
});
const route = useRoute();
Expand All @@ -66,70 +67,70 @@ watch(
let newError = {
message: 'Erreur réseau',
description: 'Service indisponible : merci de réessayer ultérieurement.'
}
};
errorStack.value.push(newError);
}
},
{ immediate: true } // Option pour exécuter le watcher dès le montage du composant
);
function addError(error) {
let newError = {
message: 'Erreur',
description: ''
}
if(!error.response){
newError.message = 'Erreur réseau : ' + error.code
newError.description = 'Service indisponible : merci de réessayer ultérieurement.'
}else{
if (error.response.status === HttpStatusCode.NotFound){
newError.message = 'Impossible de récupérer les données'
newError.description = 'Vérifiez que vos urls d\'appel au serveur sont correctes ainsi que vos clés d\'autorisation ' + '(' + error.config.url + ')'
};
if (!error.response) {
newError.message = 'Erreur réseau : ' + error.code;
newError.description = 'Service indisponible : merci de réessayer ultérieurement.';
} else {
if (error.response.status === HttpStatusCode.NotFound) {
newError.message = 'Impossible de récupérer les données';
newError.description = 'Vérifiez que vos urls d\'appel au serveur sont correctes ainsi que vos clés d\'autorisation ' + '(' + error.config.url + ')';
}
if(error.response.status === HttpStatusCode.Forbidden){
newError.message = 'Accès rejeté'
newError.description = 'Vérifiez que vos urls d\'appel au serveur sont correctes ainsi que vos clés d\'autorisation ' + '(' + error.config.url + ')'
if (error.response.status === HttpStatusCode.Forbidden) {
newError.message = 'Accès rejeté';
newError.description = 'Vérifiez que vos urls d\'appel au serveur sont correctes ainsi que vos clés d\'autorisation ' + '(' + error.config.url + ')';
}
if(error.response.status === HttpStatusCode.Unauthorized){
newError.message = 'Accès refusé'
newError.description = error.response.data.message + '(' + error.config.url + ')'
if (error.response.status === HttpStatusCode.Unauthorized) {
newError.message = 'Accès refusé';
newError.description = error.response.data.message + '(' + error.config.url + ')';
}
if(error.response.status === HttpStatusCode.BadRequest){
newError.message = 'Accès rejeté'
newError.description = 'Mauvaise requête : contrôlez les paramètres de votre requête et observez les logs du serveur pour plus d\'informations ' + '(' + error.config.url + ')'
if (error.response.status === HttpStatusCode.BadRequest) {
newError.message = 'Accès rejeté';
newError.description = 'Mauvaise requête : contrôlez les paramètres de votre requête et observez les logs du serveur pour plus d\'informations ' + '(' + error.config.url + ')';
}
if(error.response.status.toString().startsWith('5')){
newError.message = 'Problème de disponibilité du serveur'
newError.description = 'Retentez plus tard. Vérifiez la disponibilité de la base de donnée (Etat des serveurs) en cliquant en bas à gauche sur l\'icone de paramètres. Si le problème perdure, contactez l\'assistance'
if (error.response.status.toString()
.startsWith('5')) {
newError.message = 'Problème de disponibilité du serveur';
newError.description = 'Retentez plus tard. Vérifiez la disponibilité de la base de donnée (Etat des serveurs) en cliquant en bas à gauche sur l\'icone de paramètres. Si le problème perdure, contactez l\'assistance';
}
newError.description = 'Erreur ' + error.response.status
newError.description = 'Erreur ' + error.response.status;
}
if (error?.response?.data?.detail) {
newError.description = error.response.data.detail;
} else if (error?.response?.data?.message) {
newError.description = error.response.data.message;
}
if(error.request.url){
newError.description = 'Problème de disponibilité du fichier demandé'
if (error.request.url) {
newError.description = 'Problème de disponibilité du fichier demandé';
}
errorStack.value.push(newError)
errorStack.value.push(newError);
}
function clearErrors() {
errorStack.value = []
errorStack.value = [];
}
function closeAlert(index) {
errorStack.value.splice(index, 1)
errorStack.value.splice(index, 1);
}
function onLogout() {
router.push('identification')
router.push('identification');
}
function toggleDrawer() {
drawer.value = !drawer.value
drawer.value = !drawer.value;
}
</script>
Expand Down
30 changes: 30 additions & 0 deletions src/components/Structure/Maintenance.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<v-overlay
absolute
v-model="warningDialog"
persistent
class="justify-center align-center"
>
<v-alert
type="warning"
prominent
border="left"
>
Service indisponible. Application en maintenance. Vous serez informé de la reprise du service.
</v-alert>
</v-overlay>
</template>
<script setup>
import { computed } from 'vue';
const warningDialog = computed(() => import.meta.env.VITE_MAINTENANCE === 'true');
</script>
<style>
v-alert {
padding-bottom: 0 !important;
margin-bottom: 0 !important;
}
</style>

0 comments on commit 1451fe4

Please sign in to comment.