Skip to content
Snippets Groups Projects
Verified Commit 15429d18 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Improve lifecycle of SPA

parent 84edf371
No related branches found
No related tags found
3 merge requests!1237Release 3.0,!1211Improve lifecycle of SPA,!1183Release 3.0
Pipeline #121276 failed
......@@ -15,11 +15,19 @@ Added
* GraphQL schema for Rooms
* [Dev] UpdateIndicator Vue Component to display the status of interactive pages
Changed
~~~~~~~
* Show message on successful logout to inform users properly.
Fixed
~~~~~
* GraphQL endpoints for groups, persons, and notifications didn't expose all necessary fields.
* Loading indicator in toolbar was not shown at the complete loading progress.
* 404 page was sometimes shown while the page was still loading.
* Setting of page height in the iframe was not working correctly.
* App switched to offline state when the user was logged out/in.
`3.0b3`_ - 2023-03-19
---------------------
......
......@@ -3,6 +3,7 @@ from typing import Any, Optional
import django.apps
from django.apps import apps
from django.conf import settings
from django.contrib import messages
from django.http import HttpRequest
from django.utils.module_loading import autodiscover_modules
from django.utils.translation import gettext as _
......@@ -144,6 +145,11 @@ class CoreConfig(AppConfig):
# Save the associated person to pick up defaults
user.person.save()
def user_logged_out(
self, sender: type, request: Optional[HttpRequest], user: "User", **kwargs
) -> None:
messages.success(request, _("You have been logged out successfully."))
@classmethod
def get_all_scopes(cls) -> dict[str, str]:
scopes = {
......
......@@ -70,7 +70,7 @@ const apolloOpts = {
}
// Add a snackbar on all errors returned by the GraphQL endpoint
// If App is offline, don't add snackbar since only the ping query is active
if (!vm.$root.offline) {
if (!vm.$root.offline && !vm.$root.invalidation) {
vm.$root.snackbarItems.push({
id: crypto.randomUUID(),
timeout: 5000,
......@@ -79,7 +79,7 @@ const apolloOpts = {
});
}
}
if (networkError) {
if (networkError && !vm.$root.invalidation) {
// Set app offline globally on network errors
// This will cause the offline logic to kick in, starting a ping check or
// similar recovery strategies depending on the app/navigator state
......
......@@ -78,12 +78,23 @@ export default {
this.$root.$setPageTitle(title);
// Adapt height of IFrame according to the height of its contents once and observe height changes
this.iFrameHeight =
this.$refs.contentIFrame.contentDocument.body.scrollHeight;
new ResizeObserver(() => {
if (
this.$refs.contentIFrame.contentDocument &&
this.$refs.contentIFrame.contentDocument.body
) {
this.iFrameHeight =
this.$refs.contentIFrame.contentDocument.body.scrollHeight;
}).observe(this.$refs.contentIFrame.contentDocument.body);
new ResizeObserver(() => {
if (
this.$refs.contentIFrame &&
this.$refs.contentIFrame.contentDocument &&
this.$refs.contentIFrame.contentDocument.body
) {
this.iFrameHeight =
this.$refs.contentIFrame.contentDocument.body.scrollHeight;
}
}).observe(this.$refs.contentIFrame.contentDocument.body);
}
this.$root.contentLoading = false;
},
......
......@@ -45,7 +45,10 @@
>
<v-icon>mdi-update</v-icon>
</v-btn>
<div v-if="whoAmI && whoAmI.isAuthenticated" class="d-flex">
<div
v-if="whoAmI && whoAmI.isAuthenticated && whoAmI.person"
class="d-flex"
>
<notification-list v-if="!whoAmI.person.isDummy" />
<account-menu
:account-menu="accountMenu"
......@@ -83,7 +86,7 @@
</div>
<error-page
v-if="error404"
v-if="error404 && !$root.contentLoading"
short-error-message-key="network_errors.error_404"
long-error-message-key="network_errors.page_not_found"
redirect-button-text-key="network_errors.back_to_start"
......@@ -97,6 +100,7 @@
checkPermission($route.meta.permission) ||
$route.name === 'dashboard'
"
@mounted="routeComponentMounted"
/>
<error-page
v-else-if="
......@@ -253,6 +257,13 @@ export default {
pollInterval: 1000,
},
},
methods: {
routeComponentMounted() {
if (!this.$root.isLegacyBaseTemplate) {
this.$root.contentLoading = false;
}
},
},
watch: {
systemProperties: function (newProperties) {
this.$vuetify.theme.themes.light.primary =
......@@ -272,7 +283,7 @@ export default {
},
$route: {
handler(newRoute) {
if (newRoute.matched.length == 0) {
if (newRoute.matched.length === 0) {
this.error404 = true;
} else {
this.error404 = false;
......
......@@ -65,11 +65,25 @@ const app = new Vue({
render: (h) => h(App),
data: () => ({
showCacheAlert: false,
contentLoading: false,
contentLoading: true,
offline: false,
backgroundActive: true,
invalidation: false,
snackbarItems: [],
}),
computed: {
matchedComponents() {
if (this.$route.matched.length > 0) {
return this.$route.matched.map(
(route) => route.components.default.name
);
}
return [];
},
isLegacyBaseTemplate() {
return this.matchedComponents.includes("LegacyBaseTemplate");
},
},
router,
i18n,
});
......
......@@ -20,7 +20,7 @@ const aleksisMixin = {
},
},
mounted() {
this.$root.contentLoading = false;
this.$emit("mounted");
},
beforeDestroy() {
// Unregister all safely added event listeners as to not leak them
......
......@@ -123,15 +123,19 @@ AleksisVue.install = function (Vue) {
Vue.prototype.$invalidateState = function () {
console.info("Invalidating application state");
this.invalidation = true;
this.$apollo
.getClient()
.resetStore()
.then(
function () {
() => {
console.info("GraphQL cache cleared");
this.invalidation = false;
},
function (error) {
(error) => {
console.error("Could not clear GraphQL cache:", error);
this.invalidation = false;
}
);
};
......@@ -156,6 +160,12 @@ AleksisVue.install = function (Vue) {
// eslint-disable-next-line no-unused-vars
this.$router.afterEach((to, from) => {
if (vm.isLegacyBaseTemplate) {
// Skip resetting loading state for legacy pages
// as they are probably not finished with loading yet
// LegacyBaseTemplate will reset the loading state later
return;
}
vm.contentLoading = false;
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment