diff --git a/web/storagenode/src/app/App.vue b/web/storagenode/src/app/App.vue index 64363c258..78199166a 100644 --- a/web/storagenode/src/app/App.vue +++ b/web/storagenode/src/app/App.vue @@ -10,12 +10,14 @@ + + + diff --git a/web/storagenode/src/app/components/SNOHeader.vue b/web/storagenode/src/app/components/SNOHeader.vue index bde262fd0..9af6403ff 100644 --- a/web/storagenode/src/app/components/SNOHeader.vue +++ b/web/storagenode/src/app/components/SNOHeader.vue @@ -151,6 +151,8 @@ export default class SNOHeader extends Vue { } public async onRefresh(): Promise { + 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); } } diff --git a/web/storagenode/src/app/components/SatelliteSelectionDropdown.vue b/web/storagenode/src/app/components/SatelliteSelectionDropdown.vue index 490f86945..44427e5da 100644 --- a/web/storagenode/src/app/components/SatelliteSelectionDropdown.vue +++ b/web/storagenode/src/app/components/SatelliteSelectionDropdown.vue @@ -78,6 +78,8 @@ export default class SatelliteSelectionDropdown extends Vue { * Fires on satellite click and selects it. */ public async onSatelliteClick(id: string): Promise { + 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 { + 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); } /** diff --git a/web/storagenode/src/app/store/modules/appState.ts b/web/storagenode/src/app/store/modules/appState.ts index a979076d7..93bd81818 100644 --- a/web/storagenode/src/app/store/modules/appState.ts +++ b/web/storagenode/src/app/store/modules/appState.ts @@ -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); }, diff --git a/web/storagenode/src/app/views/DashboardArea.vue b/web/storagenode/src/app/views/DashboardArea.vue index d77a10c65..5f0893b7a 100644 --- a/web/storagenode/src/app/views/DashboardArea.vue +++ b/web/storagenode/src/app/views/DashboardArea.vue @@ -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 { + 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); } diff --git a/web/storagenode/src/app/views/PayoutArea.vue b/web/storagenode/src/app/views/PayoutArea.vue index 0b37485ac..74bba8393 100644 --- a/web/storagenode/src/app/views/PayoutArea.vue +++ b/web/storagenode/src/app/views/PayoutArea.vue @@ -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 { + 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 { diff --git a/web/storagenode/static/styles/_variables.scss b/web/storagenode/static/styles/_variables.scss index 542864c29..94a02d32d 100644 --- a/web/storagenode/static/styles/_variables.scss +++ b/web/storagenode/static/styles/_variables.scss @@ -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'); diff --git a/web/storagenode/tests/unit/components/LoadingScreen.spec.ts b/web/storagenode/tests/unit/components/LoadingScreen.spec.ts new file mode 100644 index 000000000..c99df3a53 --- /dev/null +++ b/web/storagenode/tests/unit/components/LoadingScreen.spec.ts @@ -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(); + }); +}); diff --git a/web/storagenode/tests/unit/components/__snapshots__/LoadingScreen.spec.ts.snap b/web/storagenode/tests/unit/components/__snapshots__/LoadingScreen.spec.ts.snap new file mode 100644 index 000000000..935603f03 --- /dev/null +++ b/web/storagenode/tests/unit/components/__snapshots__/LoadingScreen.spec.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LoadingScreen renders correctly 1`] = ` + +
+ + + + +
+
+`;