web/storagenode: loading screen added

Change-Id: I7d966d2dfba1c275d98259eb7b368297559f9f2d
This commit is contained in:
NickolaiYurchenko 2020-06-23 20:51:11 +03:00 committed by Nikolay Yurchenko
parent 9dbd511396
commit 6c5d948b82
10 changed files with 197 additions and 0 deletions

View File

@ -10,12 +10,14 @@
<SNOFooter />
</div>
</div>
<LoadingScreen v-if="isLoading" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import LoadingScreen from '@/app/components/LoadingScreen.vue';
import SNOFooter from '@/app/components/SNOFooter.vue';
import SNOHeader from '@/app/components/SNOHeader.vue';
@ -42,15 +44,30 @@ const elementsClassesToRemoveOnScroll: string[] = [
@Component({
components: {
LoadingScreen,
SNOHeader,
SNOFooter,
},
})
export default class App extends Vue {
/**
* Indicates if loading screen is active.
*/
public get isLoading(): boolean {
return this.$store.state.appStateModule.isLoading;
}
public async beforeCreate(): Promise<void> {
document.body.classList.add('js-loading');
window.onload = () => {
document.body.classList.remove('js-loading');
};
// TODO: place key to server config.
await this.$telemetry.init('DTEcoJRlUAN2VylCWMiLrqoknW800GNO');
}
public onScroll(): void {
elementsIdsToRemoveOnScroll.forEach(id => {
this.removeElementById(id);
@ -120,6 +137,12 @@ export default class App extends Vue {
}
}
.js-loading *,
.js-loading *:before,
.js-loading *:after {
animation-play-state: paused !important;
}
@font-face {
font-display: swap;
font-family: 'font_regular';

View File

@ -0,0 +1,110 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<transition name="fade" mode="in-out">
<div class="loading-screen">
<StorjLogo class="logo"/>
<svg height="100" width="100" class="loader">
<circle cx="50" cy="50" r="40" class="background" />
<circle cx="50" cy="50" r="40" class="circle" />
</svg>
</div>
</transition>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import StorjLogo from '@/../static/images/LogoWithoutText.svg';
@Component({
components: {
StorjLogo,
},
})
export default class LoadingScreen extends Vue {}
</script>
<style scoped lang="scss">
.loading-screen {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100vh;
z-index: 99999;
background-color: var(--loading-screen-background-color);
opacity: 1;
.logo {
position: absolute;
top: 80px;
left: 50%;
transform: translateX(-50%);
}
}
.storj-logo {
path {
fill: var(--loader-logo-color);
}
}
.loader {
transform: rotate(180deg);
}
.circle {
fill: none;
stroke: #c4c4c4;
stroke-width: 20;
stroke-dasharray: 250;
stroke-dashoffset: 250;
stroke-linecap: round;
animation: rotate 2s linear infinite, fill 1s linear infinite;
}
.background {
fill: none;
stroke: rgba(206, 206, 206, 0.2);
stroke-width: 20;
}
@keyframes rotate {
50% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -250;
}
}
@keyframes fill {
0%,
100% {
stroke: #c4c4c4;
}
50% {
stroke: var(--loader-fill-color);
}
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@ -151,6 +151,8 @@ export default class SNOHeader extends Vue {
}
public async onRefresh(): Promise<void> {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, true);
const selectedSatellite = this.$store.state.node.selectedSatellite.id;
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
@ -161,6 +163,8 @@ export default class SNOHeader extends Vue {
} catch (error) {
console.error(`${error.message} satellite data.`);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
}
}
</script>

View File

@ -78,6 +78,8 @@ export default class SatelliteSelectionDropdown extends Vue {
* Fires on satellite click and selects it.
*/
public async onSatelliteClick(id: string): Promise<void> {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, true);
try {
await this.$store.dispatch(APPSTATE_ACTIONS.TOGGLE_SATELLITE_SELECTION);
await this.$store.dispatch(NODE_ACTIONS.SELECT_SATELLITE, id);
@ -85,12 +87,16 @@ export default class SatelliteSelectionDropdown extends Vue {
} catch (error) {
console.error(error.message);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
}
/**
* Fires on all satellites click and sets selected satellite id to null.
*/
public async onAllSatellitesClick(): Promise<void> {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, true);
try {
await this.$store.dispatch(APPSTATE_ACTIONS.TOGGLE_SATELLITE_SELECTION);
await this.$store.dispatch(NODE_ACTIONS.SELECT_SATELLITE, null);
@ -98,6 +104,8 @@ export default class SatelliteSelectionDropdown extends Vue {
} catch (error) {
console.error(error.message);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
}
/**

View File

@ -11,6 +11,7 @@ export const APPSTATE_MUTATIONS = {
CLOSE_ALL_POPUPS: 'CLOSE_ALL_POPUPS',
SET_DARK: 'SET_DARK',
SET_NO_PAYOUT_INFO: 'SET_NO_PAYOUT_INFO',
SET_LOADING_STATE: 'SET_LOADING_STATE',
};
export const APPSTATE_ACTIONS = {
@ -23,6 +24,7 @@ export const APPSTATE_ACTIONS = {
CLOSE_ALL_POPUPS: 'CLOSE_ALL_POPUPS',
SET_DARK_MODE: 'SET_DARK_MODE',
SET_NO_PAYOUT_DATA: 'SET_NO_PAYOUT_DATA',
SET_LOADING: 'SET_LOADING',
};
const {
@ -44,6 +46,7 @@ export const appStateModule = {
isPayoutCalendarShown: false,
isDarkMode: false,
isNoPayoutData: false,
isLoading: true,
},
mutations: {
[TOGGLE_SATELLITE_SELECTION](state: any): void {
@ -72,6 +75,9 @@ export const appStateModule = {
[APPSTATE_MUTATIONS.SET_NO_PAYOUT_INFO](state: any, value): void {
state.isNoPayoutData = value;
},
[APPSTATE_MUTATIONS.SET_LOADING_STATE](state: any, value): void {
state.isLoading = value;
},
[CLOSE_ALL_POPUPS](state: any): void {
state.isSatelliteSelectionShown = false;
},
@ -117,6 +123,10 @@ export const appStateModule = {
[APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA]: function ({commit}: any, value: boolean): void {
commit(APPSTATE_MUTATIONS.SET_NO_PAYOUT_INFO, value);
},
[APPSTATE_ACTIONS.SET_LOADING]: function ({commit}: any, value: boolean): void {
value ? commit(APPSTATE_MUTATIONS.SET_LOADING_STATE, value) :
setTimeout(() => { commit(APPSTATE_MUTATIONS.SET_LOADING_STATE, value); }, 1000);
},
[APPSTATE_ACTIONS.CLOSE_ADDITIONAL_CHARTS]: function ({commit}: any): void {
commit(APPSTATE_MUTATIONS.CLOSE_ADDITIONAL_CHARTS);
},

View File

@ -16,6 +16,7 @@ import { Component, Vue } from 'vue-property-decorator';
import SNOContentFilling from '@/app/components/SNOContentFilling.vue';
import SNOContentTitle from '@/app/components/SNOContentTitle.vue';
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
import { NODE_ACTIONS } from '@/app/store/modules/node';
import { NOTIFICATIONS_ACTIONS } from '@/app/store/modules/notifications';
import { PAYOUT_ACTIONS } from '@/app/store/modules/payout';
@ -34,6 +35,8 @@ export default class Dashboard extends Vue {
* Fetches notifications and total payout information for all satellites.
*/
public async mounted(): Promise<void> {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, true);
try {
await this.$store.dispatch(NODE_ACTIONS.SELECT_SATELLITE, null);
} catch (error) {
@ -52,6 +55,8 @@ export default class Dashboard extends Vue {
console.error(error);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
this.$telemetry.identify(this.$store.state.node.info.id);
this.$telemetry.view(TelemetryViews.MainPage);
}

View File

@ -47,6 +47,7 @@ import SatelliteSelection from '@/app/components/SatelliteSelection.vue';
import BackArrowIcon from '@/../static/images/notifications/backArrow.svg';
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
import { NODE_ACTIONS } from '@/app/store/modules/node';
import { NOTIFICATIONS_ACTIONS } from '@/app/store/modules/notifications';
import { PAYOUT_ACTIONS } from '@/app/store/modules/payout';
@ -70,6 +71,8 @@ export default class PayoutArea extends Vue {
* Fetches payout information.
*/
public async mounted(): Promise<any> {
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, true);
try {
await this.$store.dispatch(NODE_ACTIONS.SELECT_SATELLITE, null);
} catch (error) {
@ -87,6 +90,8 @@ export default class PayoutArea extends Vue {
} catch (error) {
console.error(error);
}
await this.$store.dispatch(APPSTATE_ACTIONS.SET_LOADING, false);
}
public get totalHeld(): number {

View File

@ -43,6 +43,9 @@
--egress-tooltip-info-background-color: rgba(211, 242, 204, 0.3);
--disk-stat-chart-text-color: #657284;
--expand-button-background-color: rgba(226, 236, 247, 0.45);
--loading-screen-background-color: #e9ecf2;
--loader-fill-color: #133e9c;
--loader-logo-color: #929baf;
--tooltip-background-path: url('../../static/images/tooltipBack.png');
--tooltip-arrow-path: url('../../static/images/tooltipArrow.png');
--info-image-arrow-middle-path: url('../../static/images/Message.png');
@ -92,6 +95,9 @@
--egress-tooltip-info-background-color: #212329;
--disk-stat-chart-text-color: white;
--expand-button-background-color: #31343d;
--loading-screen-background-color: #1e1e26;
--loader-fill-color: #4f97f7;
--loader-logo-color: #414148;
--tooltip-background-path: url('../../static/images/tooltipBackDark.png');
--tooltip-arrow-path: url('../../static/images/tooltipArrowDark.png');
--info-image-arrow-middle-path: url('../../static/images/MessageDark.png');

View File

@ -0,0 +1,14 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import LoadingScreen from '@/app/components/LoadingScreen.vue';
import { shallowMount } from '@vue/test-utils';
describe('LoadingScreen', (): void => {
it('renders correctly', (): void => {
const wrapper = shallowMount(LoadingScreen);
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -0,0 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LoadingScreen renders correctly 1`] = `
<transition-stub name="fade" mode="in-out">
<div class="loading-screen">
<storjlogo-stub class="logo"></storjlogo-stub> <svg height="100" width="100" class="loader">
<circle cx="50" cy="50" r="40" class="background"></circle>
<circle cx="50" cy="50" r="40" class="circle"></circle>
</svg>
</div>
</transition-stub>
`;