From ed28fa3ff9edfaad5572c1fc421b06a6c872636d Mon Sep 17 00:00:00 2001 From: Vitalii Shpital Date: Wed, 9 Jun 2021 18:13:19 +0300 Subject: [PATCH] web/satellite: added loaders across all the UI. Removed most of the requests from initial load Added loader spinners across all of the UI to be visible while data is being fetched. Removed most of the requests from the initial load of the satellite dashboard. Removed useless requests after creating of new projects. This should make user's experience much more better since load time of the app is much lower than it was before. Change-Id: Ib0941ad4eee6b3caf781d132062b55cb17703fe7 --- .../components/accessGrants/AccessGrants.vue | 18 +- .../accessGrants/steps/PermissionsStep.vue | 12 +- .../account/billing/BillingArea.vue | 73 +++---- .../components/account/billing/InfoBar.vue | 174 +++++++++++++++++ .../DetailedHistory.vue | 44 ++++- .../EstimatedCostsAndCredits.vue | 48 +++-- .../billing/freeCredits/CreditsHistory.vue | 35 +++- .../billing/paymentMethods/AddCardForm.vue | 1 - .../billing/paymentMethods/PaymentMethods.vue | 25 ++- .../src/components/common/VInfoBar.vue | 130 ------------- .../src/components/common/VLoader.vue | 33 ++-- .../projectsDropdown/ProjectSelection.vue | 21 -- .../src/components/objects/BucketsView.vue | 4 +- .../src/components/project/CreateProject.vue | 47 +---- .../components/project/ProjectDashboard.vue | 57 +++++- .../components/project/buckets/BucketArea.vue | 23 +-- .../project/summary/ProjectSummary.vue | 32 +-- .../components/project/usage/ProjectUsage.vue | 6 + .../components/project/usage/UsageArea.vue | 29 +-- .../src/components/projectsList/InfoBar.vue | 131 +++++++++++++ .../components/projectsList/ProjectsList.vue | 25 ++- .../src/components/team/HeaderArea.vue | 3 + .../components/team/ProjectMembersArea.vue | 56 ++++-- web/satellite/src/store/modules/appState.ts | 13 -- web/satellite/src/store/modules/projects.ts | 17 +- web/satellite/src/store/mutationConstants.ts | 2 - .../src/utils/constants/actionNames.ts | 2 - web/satellite/src/views/DashboardArea.vue | 183 +----------------- .../DetailedHistory.spec.ts | 24 ++- .../EstimatedCostsAndCredits.spec.ts | 8 + .../freeCredits/CreditsHistory.spec.ts | 19 +- .../paymentMethods/PaymentMethods.spec.ts | 12 +- .../__snapshots__/PaymentMethods.spec.ts.snap | 6 + .../tests/unit/common/VInfoBar.spec.ts | 31 --- .../__snapshots__/VInfoBar.spec.ts.snap | 11 -- .../tests/unit/mock/api/accessGrants.ts | 2 +- web/satellite/tests/unit/mock/api/projects.ts | 2 +- .../unit/project/ProjectDashboard.spec.ts | 36 +++- .../project/summary/ProjectSummary.spec.ts | 3 + .../unit/project/usage/UsageArea.spec.ts | 2 + .../__snapshots__/ProjectUsage.spec.ts.snap | 4 +- .../projectMembers/ProjectMembersArea.spec.ts | 12 +- .../ProjectMembersArea.spec.ts.snap | 14 +- .../__snapshots__/DashboardArea.spec.ts.snap | 4 - 44 files changed, 763 insertions(+), 671 deletions(-) create mode 100644 web/satellite/src/components/account/billing/InfoBar.vue delete mode 100644 web/satellite/src/components/common/VInfoBar.vue create mode 100644 web/satellite/src/components/projectsList/InfoBar.vue delete mode 100644 web/satellite/tests/unit/common/VInfoBar.spec.ts delete mode 100644 web/satellite/tests/unit/common/__snapshots__/VInfoBar.spec.ts.snap diff --git a/web/satellite/src/components/accessGrants/AccessGrants.vue b/web/satellite/src/components/accessGrants/AccessGrants.vue index ed6f74488..91223dac6 100644 --- a/web/satellite/src/components/accessGrants/AccessGrants.vue +++ b/web/satellite/src/components/accessGrants/AccessGrants.vue @@ -20,10 +20,12 @@ width="203px" height="44px" :on-press="onCreateClick" + :is-disabled="areGrantsFetching" /> -
+ +
- + { try { - await this.$store.dispatch(FETCH, 1); + await this.$store.dispatch(FETCH, this.FIRST_PAGE); + + this.areGrantsFetching = false; } catch (error) { await this.$notify.error(`Unable to fetch Access Grants. ${error.message}`); } @@ -262,4 +270,8 @@ export default class AccessGrants extends Vue { } } } + + .grants-loader { + margin-top: 50px; + } diff --git a/web/satellite/src/components/accessGrants/steps/PermissionsStep.vue b/web/satellite/src/components/accessGrants/steps/PermissionsStep.vue index d37d95695..ecd7e338d 100644 --- a/web/satellite/src/components/accessGrants/steps/PermissionsStep.vue +++ b/web/satellite/src/components/accessGrants/steps/PermissionsStep.vue @@ -34,7 +34,8 @@

Buckets

- + +

Credit History

- - + +
@@ -30,12 +33,13 @@ diff --git a/web/satellite/src/components/account/billing/paymentMethods/AddCardForm.vue b/web/satellite/src/components/account/billing/paymentMethods/AddCardForm.vue index c16a10745..165d65aed 100644 --- a/web/satellite/src/components/account/billing/paymentMethods/AddCardForm.vue +++ b/web/satellite/src/components/account/billing/paymentMethods/AddCardForm.vue @@ -78,7 +78,6 @@ export default class AddCardForm extends Vue { setTimeout(() => { if (!this.userHasOwnProject) { this.$router.push(RouteConfig.CreateProject.path); - this.$store.dispatch(APP_STATE_ACTIONS.SHOW_CREATE_PROJECT_BUTTON); } }, 500); }, 2000); diff --git a/web/satellite/src/components/account/billing/paymentMethods/PaymentMethods.vue b/web/satellite/src/components/account/billing/paymentMethods/PaymentMethods.vue index 9857766a3..f51c6b303 100644 --- a/web/satellite/src/components/account/billing/paymentMethods/PaymentMethods.vue +++ b/web/satellite/src/components/account/billing/paymentMethods/PaymentMethods.vue @@ -71,7 +71,8 @@ Your card is secured by Stripe through TLS and AES-256 encryption. Your information is secure. -
+ +
; } @@ -116,6 +113,7 @@ interface AddCardConfirm { PaymentsBonus, LockImage, SuccessImage, + VLoader, }, }) export default class PaymentMethods extends Vue { @@ -125,15 +123,18 @@ export default class PaymentMethods extends Vue { public isLoaded: boolean = false; public isAddCardClicked: boolean = false; public isAddStorjClicked: boolean = false; + public areCardsFetching: boolean = true; /** * Lifecycle hook after initial render where credit cards are fetched. */ - public mounted() { + public async mounted(): Promise { try { - this.$store.dispatch(GET_CREDIT_CARDS); + await this.$store.dispatch(PAYMENTS_ACTIONS.GET_CREDIT_CARDS); + + this.areCardsFetching = false; } catch (error) { - this.$notify.error(error.message); + await this.$notify.error(error.message); } } @@ -307,7 +308,7 @@ export default class PaymentMethods extends Vue { } .button-moved { - top: 95px; + top: 83px; } .payment-methods-area { @@ -427,4 +428,8 @@ export default class PaymentMethods extends Vue { .reduced { height: 170px; } + + .pm-loader { + margin-top: 40px; + } diff --git a/web/satellite/src/components/common/VInfoBar.vue b/web/satellite/src/components/common/VInfoBar.vue deleted file mode 100644 index 33cf58584..000000000 --- a/web/satellite/src/components/common/VInfoBar.vue +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) 2019 Storj Labs, Inc. -// See LICENSE for copying information. - - - - - - diff --git a/web/satellite/src/components/common/VLoader.vue b/web/satellite/src/components/common/VLoader.vue index 73a59a899..2b24b63ec 100644 --- a/web/satellite/src/components/common/VLoader.vue +++ b/web/satellite/src/components/common/VLoader.vue @@ -2,18 +2,28 @@ // See LICENSE for copying information. diff --git a/web/satellite/src/components/objects/BucketsView.vue b/web/satellite/src/components/objects/BucketsView.vue index 6412e5113..4eae9882f 100644 --- a/web/satellite/src/components/objects/BucketsView.vue +++ b/web/satellite/src/components/objects/BucketsView.vue @@ -11,8 +11,8 @@
diff --git a/web/satellite/src/components/project/CreateProject.vue b/web/satellite/src/components/project/CreateProject.vue index e84c2143c..179310650 100644 --- a/web/satellite/src/components/project/CreateProject.vue +++ b/web/satellite/src/components/project/CreateProject.vue @@ -65,15 +65,8 @@ import HeaderedInput from '@/components/common/HeaderedInput.vue'; import VButton from '@/components/common/VButton.vue'; import { RouteConfig } from '@/router'; -import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants'; -import { BUCKET_ACTIONS } from '@/store/modules/buckets'; -import { PAYMENTS_ACTIONS } from '@/store/modules/payments'; import { PROJECTS_ACTIONS } from '@/store/modules/projects'; import { ProjectFields } from '@/types/projects'; -import { - APP_STATE_ACTIONS, - PM_ACTIONS, -} from '@/utils/constants/actionNames'; import { LocalData } from '@/utils/localData'; @Component({ @@ -152,18 +145,6 @@ export default class NewProjectPopup extends Vue { this.selectCreatedProject(); - try { - await this.fetchProjectMembers(); - await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP); - await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.createdProjectId); - } catch (error) { - await this.$notify.error(`Unable to create project. ${error.message}`); - } - - this.clearAccessGrants(); - - this.clearBucketUsage(); - await this.$notify.success('Project created successfully!'); this.isLoading = false; @@ -177,33 +158,6 @@ export default class NewProjectPopup extends Vue { private selectCreatedProject(): void { this.$store.dispatch(PROJECTS_ACTIONS.SELECT, this.createdProjectId); LocalData.setSelectedProjectId(this.createdProjectId); - - if (this.$store.getters.projectsCount >= this.$store.getters.user.projectLimit) { - this.$store.dispatch(APP_STATE_ACTIONS.HIDE_CREATE_PROJECT_BUTTON); - } - } - - /** - * Clears project members store and fetches new. - */ - private async fetchProjectMembers(): Promise { - await this.$store.dispatch(PM_ACTIONS.CLEAR); - const fistPage = 1; - await this.$store.dispatch(PM_ACTIONS.FETCH, fistPage); - } - - /** - * Clears access grants store. - */ - private clearAccessGrants(): void { - this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR); - } - - /** - * Clears bucket usage store. - */ - private clearBucketUsage(): void { - this.$store.dispatch(BUCKET_ACTIONS.CLEAR); } } @@ -211,6 +165,7 @@ export default class NewProjectPopup extends Vue { diff --git a/web/satellite/src/components/project/buckets/BucketArea.vue b/web/satellite/src/components/project/buckets/BucketArea.vue index ba57b5a0d..0d6735255 100644 --- a/web/satellite/src/components/project/buckets/BucketArea.vue +++ b/web/satellite/src/components/project/buckets/BucketArea.vue @@ -65,21 +65,6 @@ const { }, }) export default class BucketArea extends Vue { - /** - * Lifecycle hook after initial render where buckets list is fetched. - */ - public async mounted(): Promise { - if (!this.$store.getters.selectedProject.id) { - return; - } - - try { - await this.$store.dispatch(FETCH, 1); - } catch (error) { - await this.$notify.error(error.message); - } - } - /** * Lifecycle hook before component destruction where buckets search query is cleared. */ @@ -178,7 +163,7 @@ export default class BucketArea extends Vue { diff --git a/web/satellite/src/components/projectsList/ProjectsList.vue b/web/satellite/src/components/projectsList/ProjectsList.vue index 4512f0f5f..c282fd7fe 100644 --- a/web/satellite/src/components/projectsList/ProjectsList.vue +++ b/web/satellite/src/components/projectsList/ProjectsList.vue @@ -3,6 +3,7 @@ @@ -38,6 +42,7 @@ import { Component, Vue } from 'vue-property-decorator'; import VList from '@/components/common/VList.vue'; +import VLoader from '@/components/common/VLoader.vue'; import VPagination from '@/components/common/VPagination.vue'; import HeaderArea from '@/components/team/HeaderArea.vue'; import ProjectMemberListItem from '@/components/team/ProjectMemberListItem.vue'; @@ -70,11 +75,14 @@ declare interface ResetPagination { VPagination, SortingListHeader, EmptySearchResultIcon, + VLoader, }, }) export default class ProjectMembersArea extends Vue { private FIRST_PAGE = 1; + public areMembersFetching: boolean = true; + public $refs!: { pagination: HTMLElement & ResetPagination; }; @@ -84,7 +92,13 @@ export default class ProjectMembersArea extends Vue { * Fetches first page of team members list of current project. */ public async mounted(): Promise { - await this.$store.dispatch(FETCH, 1); + try { + await this.$store.dispatch(FETCH, this.FIRST_PAGE); + + this.areMembersFetching = false; + } catch (error) { + await this.$notify.error(error.message); + } } /** diff --git a/web/satellite/src/store/modules/appState.ts b/web/satellite/src/store/modules/appState.ts index 137d1585c..56daf4faa 100644 --- a/web/satellite/src/store/modules/appState.ts +++ b/web/satellite/src/store/modules/appState.ts @@ -28,7 +28,6 @@ export const appStateModule = { isEditProfilePopupShown: false, isChangePasswordPopupShown: false, isPaymentSelectionShown: false, - isCreateProjectButtonShown: false, }, satelliteName: '', partneredSatellites: new Array(), @@ -100,12 +99,6 @@ export const appStateModule = { [APP_STATE_MUTATIONS.SHOW_DELETE_PAYMENT_METHOD_POPUP](state: any, id: string): void { state.appState.deletePaymentMethodID = id; }, - [APP_STATE_MUTATIONS.SHOW_CREATE_PROJECT_BUTTON](state: any): void { - state.appState.isCreateProjectButtonShown = true; - }, - [APP_STATE_MUTATIONS.HIDE_CREATE_PROJECT_BUTTON](state: any): void { - state.appState.isCreateProjectButtonShown = false; - }, // Mutation that closes each popup/dropdown [APP_STATE_MUTATIONS.CLOSE_ALL](state: any): void { state.appState.isAccountDropdownShown = false; @@ -259,12 +252,6 @@ export const appStateModule = { commit(APP_STATE_MUTATIONS.SHOW_DELETE_PAYMENT_METHOD_POPUP, methodID); }, - [APP_STATE_ACTIONS.SHOW_CREATE_PROJECT_BUTTON]: function ({commit}: any): void { - commit(APP_STATE_MUTATIONS.SHOW_CREATE_PROJECT_BUTTON); - }, - [APP_STATE_ACTIONS.HIDE_CREATE_PROJECT_BUTTON]: function ({commit}: any): void { - commit(APP_STATE_MUTATIONS.HIDE_CREATE_PROJECT_BUTTON); - }, [APP_STATE_ACTIONS.CLOSE_POPUPS]: function ({commit}: any): void { commit(APP_STATE_MUTATIONS.CLOSE_ALL); }, diff --git a/web/satellite/src/store/modules/projects.ts b/web/satellite/src/store/modules/projects.ts index c6e8ea1eb..c0beb2926 100644 --- a/web/satellite/src/store/modules/projects.ts +++ b/web/satellite/src/store/modules/projects.ts @@ -2,9 +2,6 @@ // See LICENSE for copying information. import { StoreModule } from '@/store'; -import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants'; -import { BUCKET_ACTIONS } from '@/store/modules/buckets'; -import { PAYMENTS_ACTIONS } from '@/store/modules/payments'; import { Project, ProjectFields, @@ -13,7 +10,6 @@ import { ProjectsCursor, ProjectsPage, } from '@/types/projects'; -import { PM_ACTIONS } from '@/utils/constants/actionNames'; export const PROJECTS_ACTIONS = { FETCH: 'fetchProjects', @@ -170,7 +166,6 @@ export function makeProjectsModule(api: ProjectsApi): StoreModule return project; }, [CREATE_DEFAULT_PROJECT]: async function ({rootGetters, dispatch}: any): Promise { - const FIRST_PAGE = 1; const UNTITLED_PROJECT_NAME = 'My First Project'; const UNTITLED_PROJECT_DESCRIPTION = '___'; const project = new ProjectFields( @@ -178,17 +173,9 @@ export function makeProjectsModule(api: ProjectsApi): StoreModule UNTITLED_PROJECT_DESCRIPTION, rootGetters.user.id, ); - const createdProject = await dispatch(PROJECTS_ACTIONS.CREATE, project, {root: true}); + const createdProject = await dispatch(CREATE, project); - await dispatch(PROJECTS_ACTIONS.SELECT, createdProject.id, {root: true}); - await dispatch(PM_ACTIONS.CLEAR, null, {root: true}); - await dispatch(PM_ACTIONS.FETCH, FIRST_PAGE, {root: true}); - await dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY, null, {root: true}); - await dispatch(PAYMENTS_ACTIONS.GET_BALANCE, null, {root: true}); - await dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP, null, {root: true}); - await dispatch(PROJECTS_ACTIONS.GET_LIMITS, createdProject.id, {root: true}); - await dispatch(ACCESS_GRANTS_ACTIONS.CLEAR, null, {root: true}); - await dispatch(BUCKET_ACTIONS.CLEAR, null, {root: true}); + await dispatch(SELECT, createdProject.id); }, [SELECT]: function ({commit}: any, projectID: string): void { commit(SELECT_PROJECT, projectID); diff --git a/web/satellite/src/store/mutationConstants.ts b/web/satellite/src/store/mutationConstants.ts index eb99937e6..52a542e06 100644 --- a/web/satellite/src/store/mutationConstants.ts +++ b/web/satellite/src/store/mutationConstants.ts @@ -34,7 +34,5 @@ export const APP_STATE_MUTATIONS = { SET_SATELLITE_NAME: 'SET_SATELLITE_NAME', SET_PARTNERED_SATELLITES: 'SET_PARTNERED_SATELLITES', SET_SATELLITE_STATUS: 'SET_SATELLITE_STATUS', - SHOW_CREATE_PROJECT_BUTTON: 'SHOW_CREATE_PROJECT_BUTTON', - HIDE_CREATE_PROJECT_BUTTON: 'HIDE_CREATE_PROJECT_BUTTON', SET_COUPON_CODE_UI_STATUS: 'SET_COUPON_CODE_UI_STATUS', }; diff --git a/web/satellite/src/utils/constants/actionNames.ts b/web/satellite/src/utils/constants/actionNames.ts index a81f640ac..f38837d35 100644 --- a/web/satellite/src/utils/constants/actionNames.ts +++ b/web/satellite/src/utils/constants/actionNames.ts @@ -28,8 +28,6 @@ export const APP_STATE_ACTIONS = { SET_SATELLITE_NAME: 'SET_SATELLITE_NAME', SET_PARTNERED_SATELLITES: 'SET_PARTNERED_SATELLITES', SET_SATELLITE_STATUS: 'SET_SATELLITE_STATUS', - SHOW_CREATE_PROJECT_BUTTON: 'SHOW_CREATE_PROJECT_BUTTON', - HIDE_CREATE_PROJECT_BUTTON: 'HIDE_CREATE_PROJECT_BUTTON', SET_COUPON_CODE_UI_STATUS: 'SET_COUPON_CODE_UI_STATUS', }; diff --git a/web/satellite/src/views/DashboardArea.vue b/web/satellite/src/views/DashboardArea.vue index 22944f7aa..fabe60791 100644 --- a/web/satellite/src/views/DashboardArea.vue +++ b/web/satellite/src/views/DashboardArea.vue @@ -19,28 +19,6 @@
-
- - -
@@ -51,7 +29,6 @@