// Importing necessary libraries and components const axios = require('axios'); // Axios for HTTP requests import Vue from 'vue'; // Vue.js framework import App from './App.vue'; // Main Vue component import './registerServiceWorker'; // Service worker registration import router from '@/router'; // Application router import store from '@/store'; // Vuex store for state management // Importing CSS for styling import './assets/styles/base.css'; // Base styles import './assets/resources/semantic-ui-2.4.2/semantic.min.css'; // Semantic UI for UI components import '@fortawesome/fontawesome-free/css/all.css'; // Font Awesome for icons import '@fortawesome/fontawesome-free/js/all.js'; // Font Awesome JS import 'ol/ol.css'; // OpenLayers CSS for maps import '@/assets/styles/openlayers-custom.css'; // Custom styles for OpenLayers import '@/assets/styles/sidebar-layers.css'; // Styles for sidebar layers // Font Awesome library setup import { library } from '@fortawesome/fontawesome-svg-core'; import { fas } from '@fortawesome/free-solid-svg-icons'; // Importing solid icons import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; // Font Awesome component // Vue Multiselect CSS import 'vue-multiselect/dist/vue-multiselect.min.css'; // Multiselect component styles // Adding Font Awesome icons to the library library.add(fas); // Registering Font Awesome as a Vue component for use in templates Vue.component('FontAwesomeIcon', FontAwesomeIcon); // Setting Vue's production tip configuration Vue.config.productionTip = false; Vue.config.ignoredElements = ['geor-header']; // Handling service worker updates and precaching var refreshing = false; // Flag to prevent multiple refreshes if (navigator.serviceWorker) { navigator.serviceWorker.addEventListener('controllerchange', () => { // Check if the page is already refreshing to prevent duplicate refreshes if (refreshing) { return; } refreshing = true; // Reload the page to activate the new service worker window.location.reload(); }); } /** * Dynamically loads a font from Google Fonts and sets CSS variables. * @param {string} fontNames - A comma-separated list of font names, where the first font is the one to be imported and others are fallbacks. * @param {string} headerColor - The color to be used for headers. * @param {string} primaryColor - The primary color for the application. * @param {string} primaryHighlightColor - The primary color to highlight elements in the application. */ const setAppTheme = (fontNames, headerColor, primaryColor, primaryHighlightColor) => { // Set CSS variables for header and primary color. if (headerColor) { document.documentElement.style.setProperty('--header-color', headerColor); } if (primaryColor) { document.documentElement.style.setProperty('--primary-color', primaryColor); } if (primaryHighlightColor) { document.documentElement.style.setProperty('--primary-highlight-color', primaryHighlightColor); } // Proceed to load the font if fontNames is provided. if (fontNames) { const fontNameToImport = fontNames.split(',')[0].trim(); const link = document.createElement('link'); link.href = `https://fonts.googleapis.com/css?family=${fontNameToImport.replace(/ /g, '+')}:400,700&display=swap`; link.rel = 'stylesheet'; document.head.appendChild(link); // Set the CSS variable for font family. document.documentElement.style.setProperty('--font-family', fontNames); } }; /** * Sets the favicon of the application. * @param {string} favicoUrl - The URL of the favicon to be set. */ const setFavicon = (favicoUrl) => { const link = document.createElement('link'); link.id = 'dynamic-favicon'; link.rel = 'shortcut icon'; link.href = favicoUrl; document.head.appendChild(link); }; /** * Regularly updates the online status of the application. */ const updateOnlineStatus = () => { setInterval(() => { store.commit('SET_IS_ONLINE', navigator.onLine); }, 2000); }; /** * Regularly updates the user status if using external auth to keep the frontend updated with backend. */ function handleLogout() { if (store.state.user) { store.dispatch('LOGOUT'); store.commit('DISPLAY_MESSAGE', { level: 'negative', comment: `Vous avez été déconnecté du service d'authentification. Reconnectez-vous ou continuez en mode anonyme.` }); store.dispatch('GET_USER_LEVEL_PROJECTS'); } } const updateUserStatus = () => { setInterval(() => { if (navigator.onLine) { axios .get(`${store.state.configuration.VUE_APP_DJANGO_API_BASE}user_info/`) .then((response) => { const user = response.data?.user || null; if (response.status === 302) { console.warn("Redirection détectée vers :", response.headers.location || response.request.responseURL); } if (response.status === 200 && user) { // Cas où l'utilisateur est bien authentifié if (!store.state.user) { store.commit('SET_USER', user); store.commit('DISPLAY_MESSAGE', { level: 'positive', comment: 'Bienvenue à nouveau ! Vous êtes reconnecté au service d\'authentification' }); store.dispatch('GET_USER_LEVEL_PERMISSIONS'); store.dispatch('GET_USER_LEVEL_PROJECTS'); } } else if (!user) { // Lorsqu'un utilisateur est déconnecté du SSO, la requête de vérification de session envoyée à l'API de l'application échoue avec une erreur 400. // On force la déconnexion de l'utilisateur dans ce cas. handleLogout(); } }) .catch(error => { console.error("Erreur API :", error); handleLogout(); }); } }, 10000); }; /** * Fetches initial data for the application and initializes the Vue instance. */ const fetchDataAndInitializeApp = async () => { await Promise.all([ store.dispatch('GET_USER_INFO'), store.dispatch('GET_STATIC_PAGES'), store.dispatch('map/GET_AVAILABLE_LAYERS'), store.dispatch('GET_LEVELS_PERMISSIONS'), store.dispatch('GET_PROJECT_ATTRIBUTES'), ]); new Vue({ router, store, render: h => h(App) }).$mount('#app'); }; /** * Initializes the application configuration. * @param {object} config - Configuration object with application settings. */ const onConfigLoaded = async (config) => { // Set application configuration in the store. store.commit('SET_CONFIG', config); // Update the online status at regular intervals. updateOnlineStatus(); // Update the user status at regular intervals to check if backend session expired. updateUserStatus(); // Set the document title and favicon from the configuration. document.title = `${config.VUE_APP_APPLICATION_NAME} ${config.VUE_APP_APPLICATION_ABSTRACT}`; setFavicon(config.VUE_APP_APPLICATION_FAVICO); // Apply the application theme settings using values specified in the configuration. setAppTheme( config.VUE_APP_FONT_FAMILY, config.VUE_APP_HEADER_COLOR, config.VUE_APP_PRIMARY_COLOR, config.VUE_APP_PRIMARY_HIGHLIGHT_COLOR ); // Set a global proxy URL based on the configuration. window.proxy_url = config.VUE_APP_DJANGO_API_BASE + 'proxy/'; // Fetch initial data and initialize the Vue application. await fetchDataAndInitializeApp(); }; // Attempt to load the application configuration from an external JSON file. axios.get('./config/config.json') .catch((error) => { // Log an error if the configuration file cannot be loaded. console.error(error); console.log('Attempting to get config from Localstorage'); // Attempt to retrieve the configuration from local storage as a fallback. const conf = localStorage.getItem('geontrib_conf'); if (conf) { // If a configuration is found in local storage, parse it and load the config. onConfigLoaded(JSON.parse(conf)); } }) .then((response) => { // Check if the response is valid and the request was successful. if (response && response.status === 200) { // Store the retrieved configuration in local storage for future use. localStorage.setItem('geontrib_conf', JSON.stringify(response.data)); // Load the configuration into the application. onConfigLoaded(response.data); } }) .catch((error) => { // Throw an error if there are issues processing the response. throw error; });