web/satellite: show loading screen when fetching frontend config

The satellite UI now shows a loading screen instead of the Vue router
view when fetching the frontend config. This prevents components that
rely on the config from being prematurely rendered.

References #5494

Change-Id: Ifeb06288a6895f98a7cab8f321cd68078c73c696
This commit is contained in:
Jeremy Wharton 2023-04-05 14:27:10 -05:00 committed by Storj Robot
parent 915f3952af
commit 857a292e52
3 changed files with 75 additions and 66 deletions

View File

@ -3,25 +3,29 @@
<template>
<div id="app">
<router-view />
<BrandedLoader v-if="isLoading" />
<router-view v-else />
<!-- Area for displaying notification -->
<NotificationArea />
</div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted } from 'vue';
import { onBeforeUnmount, onMounted, ref } from 'vue';
import { PartneredSatellite } from '@/types/common';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { MetaUtils } from '@/utils/meta';
import { useNotify, useStore } from '@/utils/hooks';
import BrandedLoader from '@/components/common/BrandedLoader.vue';
import NotificationArea from '@/components/notifications/NotificationArea.vue';
const store = useStore();
const notify = useNotify();
const isLoading = ref<boolean>(true);
/**
* Fixes the issue where view port height is taller than the visible viewport on
* mobile Safari/Webkit. See: https://bugs.webkit.org/show_bug.cgi?id=141832
@ -54,9 +58,9 @@ function updateViewportVariable(): void {
* Lifecycle hook after initial render.
* Sets up variables from meta tags from config such satellite name, etc.
*/
onMounted((): void => {
onMounted(async (): Promise<void> => {
try {
store.dispatch(APP_STATE_ACTIONS.FETCH_CONFIG);
await store.dispatch(APP_STATE_ACTIONS.FETCH_CONFIG);
} catch (error) {
// TODO: Use a harsher error-handling approach when the config is necessary
// for the frontend to function.
@ -101,6 +105,8 @@ onMounted((): void => {
}
fixViewportHeight();
isLoading.value = false;
});
onBeforeUnmount((): void => {

View File

@ -0,0 +1,63 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="loader">
<div class="loader__spinner" />
<LoaderImage class="loader__icon" />
</div>
</template>
<script setup lang="ts">
import LoaderImage from '@/../static/images/common/loadIcon.svg';
</script>
<style scoped lang="scss">
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loader {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
&__spinner {
width: 90px;
height: 90px;
margin: auto 0;
border: solid 3px var(--c-blue-3);
border-radius: 50%;
border-right-color: transparent;
border-bottom-color: transparent;
border-left-color: transparent;
transition: all 0.5s ease-in;
animation-name: rotate;
animation-duration: 1.2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
&__icon {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
}
</style>

View File

@ -3,10 +3,7 @@
<template>
<div class="dashboard">
<div v-if="isLoading" class="loading-overlay active">
<div class="load" />
<LoaderImage class="loading-icon" />
</div>
<BrandedLoader v-if="isLoading" />
<div v-else class="dashboard__wrap">
<div class="dashboard__wrap__main-area">
<NavigationArea v-if="!isNavigationHidden" class="dashboard__wrap__main-area__navigation" />
@ -139,8 +136,7 @@ import LimitWarningModal from '@/components/modals/LimitWarningModal.vue';
import VBanner from '@/components/common/VBanner.vue';
import UpgradeNotification from '@/components/notifications/UpgradeNotification.vue';
import ProjectLimitBanner from '@/components/notifications/ProjectLimitBanner.vue';
import LoaderImage from '@/../static/images/common/loadIcon.svg';
import BrandedLoader from '@/components/common/BrandedLoader.vue';
const {
SETUP_ACCOUNT,
@ -696,66 +692,10 @@ onBeforeUnmount(() => {
</script>
<style scoped lang="scss">
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
:deep(.notification-wrap) {
margin-top: 1rem;
}
.load {
width: 90px;
height: 90px;
margin: auto 0;
border: solid 3px var(--c-blue-3);
border-radius: 50%;
border-right-color: transparent;
border-bottom-color: transparent;
border-left-color: transparent;
transition: all 0.5s ease-in;
animation-name: rotate;
animation-duration: 1.2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.loading-overlay {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
visibility: hidden;
opacity: 0;
transition: all 0.5s linear;
}
.loading-overlay.active {
visibility: visible;
opacity: 1;
}
.loading-icon {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.dashboard {
height: 100%;
background-color: #f5f6fa;