From 99237d5c783292696c9a88eb28d80e4eb4780afa Mon Sep 17 00:00:00 2001 From: NickolaiYurchenko Date: Fri, 22 Apr 2022 21:30:56 +0300 Subject: [PATCH] web/satellite: new bucket creation flow old bucket creation flow removed new flow added name and passphrase splitted into separate views demo bucket will not be created automatically bucket creation progress bar added Change-Id: I2a1d7d77c3038caaafb3c06bdb0ac5dd1ad17599 --- satellite/console/consoleweb/server.go | 2 +- scripts/testdata/satellite-config.yaml.lock | 2 +- testsuite/ui/satellite/browser_test.go | 44 +- testsuite/ui/satellite/onboarding_test.go | 33 +- .../src/components/common/HeaderedInput.vue | 7 +- .../src/components/common/HeaderlessInput.vue | 5 +- .../src/components/objects/BucketCreation.vue | 203 +++++++++ .../BucketCreationGeneratePassphrase.vue | 399 ++++++++++++++++++ .../objects/BucketCreationNameStep.vue | 204 +++++++++ .../objects/BucketCreationProgress.vue | 134 ++++++ .../src/components/objects/BucketsView.vue | 137 +++--- .../src/components/objects/EncryptData.vue | 39 +- .../src/components/objects/ObjectsArea.vue | 4 +- web/satellite/src/router/index.ts | 7 + web/satellite/src/store/index.ts | 9 +- .../static/images/objects/bucketCreation.svg | 17 + web/satellite/static/images/objects/check.svg | 3 + .../static/images/objects/fingerprint.svg | 3 + web/satellite/static/images/objects/key.svg | 3 + 19 files changed, 1091 insertions(+), 164 deletions(-) create mode 100644 web/satellite/src/components/objects/BucketCreation.vue create mode 100644 web/satellite/src/components/objects/BucketCreationGeneratePassphrase.vue create mode 100644 web/satellite/src/components/objects/BucketCreationNameStep.vue create mode 100644 web/satellite/src/components/objects/BucketCreationProgress.vue create mode 100644 web/satellite/static/images/objects/bucketCreation.svg create mode 100644 web/satellite/static/images/objects/check.svg create mode 100644 web/satellite/static/images/objects/fingerprint.svg create mode 100644 web/satellite/static/images/objects/key.svg diff --git a/satellite/console/consoleweb/server.go b/satellite/console/consoleweb/server.go index 77e1fa944..e80ed10cc 100644 --- a/satellite/console/consoleweb/server.go +++ b/satellite/console/consoleweb/server.go @@ -94,7 +94,7 @@ type Config struct { PathwayOverviewEnabled bool `help:"indicates if the overview onboarding step should render with pathways" default:"true"` NewProjectDashboard bool `help:"indicates if new project dashboard should be used" default:"false"` NewNavigation bool `help:"indicates if new navigation structure should be rendered" default:"true"` - NewObjectsFlow bool `help:"indicates if new objects flow should be used" default:"true"` + NewObjectsFlow bool `help:"indicates if new objects flow should be used" default:"false"` NewAccessGrantFlow bool `help:"indicates if new access grant flow should be used" default:"false"` GeneratedAPIEnabled bool `help:"indicates if generated console api should be used" default:"false"` InactivityTimerEnabled bool `help:"indicates if session can be timed out due inactivity" default:"false"` diff --git a/scripts/testdata/satellite-config.yaml.lock b/scripts/testdata/satellite-config.yaml.lock index 1c999b9ce..0319f6d76 100755 --- a/scripts/testdata/satellite-config.yaml.lock +++ b/scripts/testdata/satellite-config.yaml.lock @@ -242,7 +242,7 @@ compensation.withheld-percents: 75,75,75,50,50,50,25,25,25,0,0,0,0,0,0 # console.new-navigation: true # indicates if new objects flow should be used -# console.new-objects-flow: true +# console.new-objects-flow: false # indicates if new project dashboard should be used # console.new-project-dashboard: false diff --git a/testsuite/ui/satellite/browser_test.go b/testsuite/ui/satellite/browser_test.go index 479f280fc..c7674aa2c 100644 --- a/testsuite/ui/satellite/browser_test.go +++ b/testsuite/ui/satellite/browser_test.go @@ -28,11 +28,15 @@ func TestBrowser_Features(t *testing.T) { // Navigate into browser with new onboarding. page.MustElementR("a", "Skip and go directly to dashboard").MustClick() page.MustElementR("p", "Buckets").MustClick() - wait := page.MustWaitRequestIdle() - page.MustElementR("p", "demo-bucket").MustClick() - wait() + page.MustElementR("[aria-roledescription=title]", "Create a bucket") + page.MustElementR("span", "Continue").MustClick() + waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Encrypt your bucket") + page.MustElementR("span", "Continue").MustClick() + waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Generate a passphrase") page.MustElementR("label", "I understand, and I have saved the passphrase.").MustClick() - page.MustElementR("span", "Next >").MustClick() + page.MustElementR("span", "Continue").MustClick() // Verify that browser component has loaded and that the dropzone is present. page.MustElementR("p", "Drop Files Here to Upload") @@ -64,6 +68,7 @@ func TestBrowser_Features(t *testing.T) { page.MustElementR("button", "Cancel").MustClick() // Add a file into folder and check that dropzone is still visible. + page.MustElementR("button", "Upload").MustClick() wait1 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img.png") wait1() @@ -74,7 +79,7 @@ func TestBrowser_Features(t *testing.T) { // Click on the file name. page.MustElementR("[aria-roledescription=file]", "img.png").MustClick() - require.Contains(t, page.MustElement("[aria-roledescription=image-preview]").MustProperty("src").Str(), "img.png", "The modal did not open on file click") + page.MustElement("[aria-roledescription=image-preview]") // Share a file. page.MustElementR("span", "Share").MustClick() @@ -90,7 +95,7 @@ func TestBrowser_Features(t *testing.T) { // Click on the hamburger and then details. page.MustElement("button[aria-roledescription=dropdown]").MustClick() page.MustElementR("button", "Details").MustClick() - require.Contains(t, page.MustElement("[aria-roledescription=image-preview]").MustProperty("src").Str(), "img.png", "The dropdown details functionality is not working") + page.MustElement("[aria-roledescription=image-preview]") page.MustElementR("span", "Share").MustClick() page.MustElement("#generateShareLink") page.MustElement("#close-modal").MustClick() @@ -106,6 +111,7 @@ func TestBrowser_Features(t *testing.T) { page.MustElementR("[aria-roledescription=folder]", "go-rod-test3") // Add two files. + page.MustElementR("button", "Upload").MustClick() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img2.png") page.MustElement("#close-modal").MustClick() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/img.png") @@ -225,6 +231,7 @@ func TestBrowser_Features(t *testing.T) { page.MustElementR("[aria-roledescription=folder]", "Свобода") // upload a video. + page.MustElementR("button", "Upload").MustClick() wait3 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/movie.mp4") wait3() @@ -234,7 +241,7 @@ func TestBrowser_Features(t *testing.T) { page.MustElementR("[aria-roledescription=file-size]", "1.48 kB") page.MustElement("[aria-roledescription=file-upload-date]") page.MustElementR("[aria-roledescription=file]", "movie.mp4").MustClick() - require.Contains(t, page.MustElement("[aria-roledescription=video-preview]").MustProperty("src").Str(), "movie.mp4", "The modal did not open on video file click") + page.MustElement("[aria-roledescription=video-preview]") page.MustElement("#close-modal").MustClick() // Upload an audio file. @@ -242,7 +249,7 @@ func TestBrowser_Features(t *testing.T) { page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/audio.mp3") wait4() page.MustElementR("[aria-roledescription=file]", "audio.mp3").MustClick() - require.Contains(t, page.MustElement("[aria-roledescription=audio-preview]").MustProperty("src").Str(), "audio.mp3", "The modal did not open on video file click") + page.MustElement("[aria-roledescription=audio-preview]") page.MustElement("#close-modal").MustClick() // Navigate out of nested folder and delete everything. @@ -266,11 +273,15 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { // Navigate into browser with new onboarding. page.MustElementR("a", "Skip and go directly to dashboard").MustClick() page.MustElementR("p", "Buckets").MustClick() - wait := page.MustWaitRequestIdle() - page.MustElementR("p", "demo-bucket").MustClick() - wait() + page.MustElementR("[aria-roledescription=title]", "Create a bucket") + page.MustElementR("span", "Continue").MustClick() + waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Encrypt your bucket") + page.MustElementR("span", "Continue").MustClick() + waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Generate a passphrase") page.MustElementR("label", "I understand, and I have saved the passphrase.").MustClick() - page.MustElementR("span", "Next >").MustClick() + page.MustElementR("span", "Continue").MustClick() // Verify that browser component has loaded and that the dropzone is present. page.MustElementR("p", "Drop Files Here to Upload") @@ -307,6 +318,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") page.MustElementR("button", "Cancel").MustClick() + page.MustElementR("button", "Upload").MustClick() wait1 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") wait1() @@ -315,6 +327,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the test0bytes.txt file") } else { + page.MustElementR("button", "Upload").MustClick() wait2 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=folder-upload]").MustSetFiles("./testdata") wait2() @@ -345,6 +358,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { require.Equal(t, " ", page.MustElement("[placeholder=\"Name of the folder\"]").MustText(), "Folder input does not contain the empty invalid name") page.MustElementR("button", "Cancel").MustClick() + page.MustElementR("button", "Upload").MustClick() wait3 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") wait3() @@ -353,11 +367,13 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The modal did not open upon clicking the test0bytes.txt file") } else { + page.MustElementR("button", "Upload").MustClick() wait4 := page.MustWaitRequestIdle() page.MustElement("input[aria-roledescription=folder-upload]").MustSetFiles("./testdata") wait4() page.MustElementR("table > tbody > tr:nth-child(1) > td", "..") page.MustElementR("[aria-roledescription=folder]", "testdata \\(1\\)").MustClick() + waitVueTick(page) page.MustElementR("[aria-roledescription=file]", "test0bytes.txt").MustClick() require.Contains(t, page.MustElement("[aria-roledescription=preview-placeholder]").String(), "svg", "The uploaded folder did not upload the files correctly") } @@ -366,6 +382,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { page.MustElement("#navigate-back").MustClick() // Upload a 0 byte file. + page.MustElementR("button", "Upload").MustClick() page.MustElement("input[aria-roledescription=file-upload]").MustSetFiles("./testdata/test0bytes.txt") page.MustElementR("span", "testing/test0bytes.txt") page.MustElement("#close-modal").MustClick() @@ -382,7 +399,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { if !testing.Short() { slowpage := page.Sleeper(uitest.MaxDuration(20 * time.Second)) - // Upload a 50 MB file. + // Upload a 5 MB file. testFile := generateEmptyFile(t, ctx, "testFile", 5*memory.MiB) wait5 := slowpage.MustWaitRequestIdle() slowpage.MustElement("input[aria-roledescription=file-upload]").MustSetFiles(testFile) @@ -403,6 +420,7 @@ func TestBrowser_FolderAndDifferentFileSizesUpload(t *testing.T) { slowpage.MustElement("#close-modal").MustClick() // Upload a 130MB file. + page.MustElementR("button", "Upload").MustClick() wait6 := slowpage.MustWaitRequestIdle() slowpage.MustElement("input[aria-roledescription=file-upload]").MustSetFiles(testFile2) require.Equal(t, " testing/testFile2", slowpage.MustElement("[aria-roledescription=file-uploading]").MustText(), "The testFile2 file has not started uploading") diff --git a/testsuite/ui/satellite/onboarding_test.go b/testsuite/ui/satellite/onboarding_test.go index 949d8d943..f41afce1c 100644 --- a/testsuite/ui/satellite/onboarding_test.go +++ b/testsuite/ui/satellite/onboarding_test.go @@ -29,25 +29,26 @@ func TestOnboarding_WizardBrowser(t *testing.T) { // Buckets Page bucketsTitle := page.MustElement("[aria-roledescription=title]").MustText() - require.Contains(t, bucketsTitle, "Buckets") - page.Race().ElementR("p", "demo-bucket").MustHandle(func(el *rod.Element) { - el.MustClick() - waitVueTick(page) - }).MustDo() - - // Passphrase screen - encryptionTitle := page.MustElement("[aria-roledescription=objects-title]").MustText() - require.Contains(t, encryptionTitle, "The object browser uses server side encryption.") - customPassphrase := page.MustElement("[aria-roledescription=enter-passphrase-label]") - customPassphraseLabel := customPassphrase.MustText() - require.Contains(t, customPassphraseLabel, "Enter your own passphrase") - customPassphrase.MustClick() + require.Contains(t, bucketsTitle, "Create a bucket") + page.MustElementR("[aria-roledescription=title]", "Create a bucket") + page.MustElementR("span", "Continue").MustClick() waitVueTick(page) - page.MustElement("[aria-roledescription=passphrase] input").MustInput("password123") - page.MustElement(".checkmark").MustClick() + page.MustElementR("[aria-roledescription=title]", "Encrypt your bucket") + page.MustElementR("span", "Continue").MustClick() waitVueTick(page) - page.MustElementX("(//span[text()=\"Next >\"])").MustClick() + page.MustElementR("[aria-roledescription=title]", "Generate a passphrase") + mnemonic := page.MustElement("[aria-roledescription=mnemonic]").MustText() + require.NotEmpty(t, mnemonic) + page.MustElementR("span", "Back").MustClick() waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Encrypt your bucket") + page.MustElement("[aria-roledescription=manual]").MustClick() + page.MustElementR("span", "Continue").MustClick() + waitVueTick(page) + page.MustElementR("[aria-roledescription=title]", "Enter a passphrase") + page.MustElement("[aria-roledescription=passphrase] input").MustInput("1") + page.MustElementR("label", "I understand, and I have saved the passphrase.").MustClick() + page.MustElementR("span", "Continue").MustClick() // Verify that browser component has loaded and that the dropzone is present page.MustElementR("p", "Drop Files Here to Upload") diff --git a/web/satellite/src/components/common/HeaderedInput.vue b/web/satellite/src/components/common/HeaderedInput.vue index 64fd73cce..c0353d8ac 100644 --- a/web/satellite/src/components/common/HeaderedInput.vue +++ b/web/satellite/src/components/common/HeaderedInput.vue @@ -58,9 +58,8 @@ import HeaderlessInput from './HeaderlessInput.vue'; ErrorIcon, }, }) +// TODO: merge these two components to have one single source of truth. export default class HeaderedInput extends HeaderlessInput { - @Prop({default: ''}) - private readonly initValue: string; @Prop({default: ''}) private readonly additionalLabel: string; @Prop({default: 0}) @@ -73,10 +72,6 @@ export default class HeaderedInput extends HeaderlessInput { private readonly isMultiline: boolean; @Prop({default: false}) private readonly isLoading: boolean; - - public created() { - this.setValue(this.initValue); - } } diff --git a/web/satellite/src/components/common/HeaderlessInput.vue b/web/satellite/src/components/common/HeaderlessInput.vue index 09e11f1e5..1236af7f8 100644 --- a/web/satellite/src/components/common/HeaderlessInput.vue +++ b/web/satellite/src/components/common/HeaderlessInput.vue @@ -78,8 +78,10 @@ export default class HeaderlessInput extends Vue { private type: string = this.textType; private isPasswordShown = false; + public value: string; + @Prop({default: ''}) - protected value: string; + protected readonly initValue: string; @Prop({default: ''}) protected readonly label: string; @@ -111,6 +113,7 @@ export default class HeaderlessInput extends Vue { public created() { this.type = this.isPassword ? this.passwordType : this.textType; + this.value = this.initValue; } /** diff --git a/web/satellite/src/components/objects/BucketCreation.vue b/web/satellite/src/components/objects/BucketCreation.vue new file mode 100644 index 000000000..c8a266e18 --- /dev/null +++ b/web/satellite/src/components/objects/BucketCreation.vue @@ -0,0 +1,203 @@ +// Copyright (C) 2022 Storj Labs, Inc. +// See LICENSE for copying information. + + + + + + diff --git a/web/satellite/src/components/objects/BucketCreationGeneratePassphrase.vue b/web/satellite/src/components/objects/BucketCreationGeneratePassphrase.vue new file mode 100644 index 000000000..442ad1aee --- /dev/null +++ b/web/satellite/src/components/objects/BucketCreationGeneratePassphrase.vue @@ -0,0 +1,399 @@ +// Copyright (C) 2022 Storj Labs, Inc. +// See LICENSE for copying information. + + + + + + diff --git a/web/satellite/src/components/objects/BucketCreationNameStep.vue b/web/satellite/src/components/objects/BucketCreationNameStep.vue new file mode 100644 index 000000000..c039571a0 --- /dev/null +++ b/web/satellite/src/components/objects/BucketCreationNameStep.vue @@ -0,0 +1,204 @@ +// Copyright (C) 2022 Storj Labs, Inc. +// See LICENSE for copying information. + + + + + + diff --git a/web/satellite/src/components/objects/BucketCreationProgress.vue b/web/satellite/src/components/objects/BucketCreationProgress.vue new file mode 100644 index 000000000..431d7c1ef --- /dev/null +++ b/web/satellite/src/components/objects/BucketCreationProgress.vue @@ -0,0 +1,134 @@ +// Copyright (C) 2022 Storj Labs, Inc. +// See LICENSE for copying information. + + + + + + diff --git a/web/satellite/src/components/objects/BucketsView.vue b/web/satellite/src/components/objects/BucketsView.vue index af98fd40c..189dbdbc5 100644 --- a/web/satellite/src/components/objects/BucketsView.vue +++ b/web/satellite/src/components/objects/BucketsView.vue @@ -5,7 +5,7 @@

Buckets

-
+

New Bucket

@@ -62,20 +62,20 @@ import { Bucket } from 'aws-sdk/clients/s3'; import { Component, Vue, Watch } from 'vue-property-decorator'; +import { RouteConfig } from '@/router'; +import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants'; +import { OBJECTS_ACTIONS } from '@/store/modules/objects'; +import { AccessGrant, EdgeCredentials } from '@/types/accessGrants'; +import { MetaUtils } from '@/utils/meta'; +import { Validator } from '@/utils/validation'; +import { LocalData } from "@/utils/localData"; + import VLoader from '@/components/common/VLoader.vue'; import BucketItem from '@/components/objects/BucketItem.vue'; import ObjectsPopup from '@/components/objects/ObjectsPopup.vue'; import BucketIcon from '@/../static/images/objects/bucket.svg'; -import { RouteConfig } from '@/router'; -import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants'; -import { DEMO_BUCKET_NAME, OBJECTS_ACTIONS } from '@/store/modules/objects'; -import { AccessGrant, EdgeCredentials } from '@/types/accessGrants'; -import { MetaUtils } from '@/utils/meta'; -import { Validator } from '@/utils/validation'; -import { LocalData } from "@/utils/localData"; - // @vue/component @Component({ components: { @@ -104,23 +104,15 @@ export default class BucketsView extends Vue { * Setup gateway credentials. */ public async mounted(): Promise { - if (!this.$store.state.objectsModule.passphrase && !this.isNewObjectsFlow) { - await this.$router.push(RouteConfig.Buckets.with(RouteConfig.EncryptData).path); - - return; - } - await this.setBucketsView(); } @Watch('selectedProjectID') public async handleProjectChange(): Promise { - if (this.isNewObjectsFlow) { - this.isLoading = true; + this.isLoading = true; - await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR); - await this.setBucketsView(); - } + await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR); + await this.setBucketsView(); } /** @@ -147,7 +139,14 @@ export default class BucketsView extends Vue { return; } - if (!wasDemoBucketCreated) await this.createDemoBucket(); + if (!this.bucketsList.length && !wasDemoBucketCreated) { + if (this.isNewObjectsFlow) { + await this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path); + return; + } + + await this.createDemoBucket(); + } } catch (error) { await this.$notify.error(`Failed to setup Buckets view. ${error.message}`); } finally { @@ -183,14 +182,10 @@ export default class BucketsView extends Vue { } const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl'); - let passphrase = ''; - if (!this.isNewObjectsFlow) { - passphrase = this.passphrase; - } this.worker.postMessage({ 'type': 'GenerateAccess', 'apiKey': this.grantWithPermissions, - 'passphrase': passphrase, + 'passphrase': '', 'projectID': this.$store.getters.selectedProject.id, 'satelliteNodeURL': satelliteNodeURL, }); @@ -224,6 +219,12 @@ export default class BucketsView extends Vue { }; } + public onNewBucketButtonClick(): void { + this.isNewObjectsFlow + ? this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path) + : this.showCreateBucketPopup(); + } + /** * Holds create bucket click logic. */ @@ -239,14 +240,9 @@ export default class BucketsView extends Vue { await this.setAccess(); } await this.$store.dispatch(OBJECTS_ACTIONS.CREATE_BUCKET, this.createBucketName); - if (this.isNewObjectsFlow) { - await this.$store.dispatch(OBJECTS_ACTIONS.FETCH_BUCKETS); - this.createBucketName = ''; - this.isRequestProcessing = false; - this.hideCreateBucketPopup(); - - return; - } + await this.$store.dispatch(OBJECTS_ACTIONS.FETCH_BUCKETS); + this.createBucketName = ''; + this.hideCreateBucketPopup(); } catch (error) { const BUCKET_ALREADY_EXISTS_ERROR = 'BucketAlreadyExists'; @@ -255,17 +251,9 @@ export default class BucketsView extends Vue { } else { await this.$notify.error(error.message); } - + } finally { this.isRequestProcessing = false; - - return; } - - const bucket = this.createBucketName; - this.createBucketName = ''; - this.isRequestProcessing = false; - - this.openBucket(bucket); } /** @@ -278,25 +266,14 @@ export default class BucketsView extends Vue { try { await this.$store.dispatch(OBJECTS_ACTIONS.CREATE_DEMO_BUCKET); - if (this.isNewObjectsFlow) { - await this.$store.dispatch(OBJECTS_ACTIONS.FETCH_BUCKETS); + await this.$store.dispatch(OBJECTS_ACTIONS.FETCH_BUCKETS); - LocalData.setDemoBucketCreatedStatus(); - this.isRequestProcessing = false; - - return; - } + LocalData.setDemoBucketCreatedStatus(); } catch (error) { await this.$notify.error(error.message); + } finally { this.isRequestProcessing = false; - - return; } - - LocalData.setDemoBucketCreatedStatus(); - this.isRequestProcessing = false; - - this.openBucket(DEMO_BUCKET_NAME); } /** @@ -317,17 +294,27 @@ export default class BucketsView extends Vue { await this.$store.dispatch(OBJECTS_ACTIONS.FETCH_BUCKETS); } catch (error) { await this.$notify.error(error.message); - - this.isRequestProcessing = false; - return; + } finally { + this.isRequestProcessing = false; } - this.isRequestProcessing = false; this.deleteBucketName = ''; this.hideDeleteBucketPopup(); } + /** + * Removes temporary created access grant. + */ + public async removeTemporaryAccessGrant(): Promise { + try { + await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.DELETE_BY_NAME_AND_PROJECT_ID, this.FILE_BROWSER_AG_NAME); + await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR); + } catch (error) { + await this.$notify.error(error.message); + } + } + /** * Opens utils dropdown. */ @@ -389,31 +376,12 @@ export default class BucketsView extends Vue { this.createBucketName = name; } - /** - * Removes temporary created access grant. - */ - public async removeTemporaryAccessGrant(): Promise { - try { - await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.DELETE_BY_NAME_AND_PROJECT_ID, this.FILE_BROWSER_AG_NAME); - await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR); - } catch (error) { - await this.$notify.error(error.message); - } - } - /** * Holds on bucket click. Proceeds to file browser. */ public openBucket(bucketName: string): void { this.$store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, bucketName); - - if (this.isNewObjectsFlow) { - this.$router.push(RouteConfig.Buckets.with(RouteConfig.EncryptData).path); - - return; - } - - this.$router.push(RouteConfig.Buckets.with(RouteConfig.UploadFile).path); + this.$router.push(RouteConfig.Buckets.with(RouteConfig.EncryptData).path); } /** @@ -423,13 +391,6 @@ export default class BucketsView extends Vue { return this.$store.state.objectsModule.bucketsList; } - /** - * Returns passphrase from store. - */ - private get passphrase(): string { - return this.$store.state.objectsModule.passphrase; - } - /** * Returns objects flow status from store. */ diff --git a/web/satellite/src/components/objects/EncryptData.vue b/web/satellite/src/components/objects/EncryptData.vue index e764f560d..c5980710f 100644 --- a/web/satellite/src/components/objects/EncryptData.vue +++ b/web/satellite/src/components/objects/EncryptData.vue @@ -98,13 +98,11 @@ export default class EncryptData extends Vue { * Sets local worker if new flow is used. */ public mounted(): void { - if (this.isNewObjectsFlow) { - if (!this.apiKey) { - this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path) - } - - this.setWorker(); + if (!this.apiKey) { + this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path) } + + this.setWorker(); } /** @@ -142,27 +140,19 @@ export default class EncryptData extends Vue { return; } - const keyToBeStored = await result.toString('hex'); + const keyToBeStored = result.toString('hex'); await LocalData.setUserIDPassSalt(this.$store.getters.user.id, keyToBeStored, SALT); await this.$store.dispatch(OBJECTS_ACTIONS.SET_PASSPHRASE, this.passphrase); - if (this.isNewObjectsFlow) { - try { - await this.setAccess(); - await this.$router.push(RouteConfig.UploadFile.path); - } catch (e) { - await this.$notify.error(e.message); - } - + try { + await this.setAccess(); + await this.$router.push(RouteConfig.UploadFile.path); + } catch (e) { + await this.$notify.error(e.message); + } finally { this.isLoading = false; - - return; } - - this.isLoading = false; - - await this.$router.push(RouteConfig.BucketsManagement.path); } /** @@ -242,13 +232,6 @@ export default class EncryptData extends Vue { private get bucket(): string { return this.$store.state.objectsModule.fileComponentBucketName; } - - /** - * Returns objects flow status from store. - */ - private get isNewObjectsFlow(): string { - return this.$store.state.appStateModule.isNewObjectsFlow; - } } diff --git a/web/satellite/src/components/objects/ObjectsArea.vue b/web/satellite/src/components/objects/ObjectsArea.vue index 6e1b2deb2..c6e20e4ea 100644 --- a/web/satellite/src/components/objects/ObjectsArea.vue +++ b/web/satellite/src/components/objects/ObjectsArea.vue @@ -22,8 +22,8 @@ export default class ObjectsArea extends Vue { * Redirects if flow is disabled. */ public async mounted(): Promise { - const value = MetaUtils.getMetaContent('file-browser-flow-disabled'); - if (value === "true") { + const isFileBrowserFlowDisabled = MetaUtils.getMetaContent('file-browser-flow-disabled'); + if (isFileBrowserFlowDisabled === "true") { await this.$router.push(RouteConfig.ProjectDashboard.path); } } diff --git a/web/satellite/src/router/index.ts b/web/satellite/src/router/index.ts index ce9407b8d..79a225bc4 100644 --- a/web/satellite/src/router/index.ts +++ b/web/satellite/src/router/index.ts @@ -45,6 +45,7 @@ import RegistrationSuccess from "@/components/common/RegistrationSuccess.vue"; import SuccessScreen from "@/components/onboardingTour/steps/cliFlow/SuccessScreen.vue"; import AGName from "@/components/onboardingTour/steps/cliFlow/AGName.vue"; import AGPermissions from "@/components/onboardingTour/steps/cliFlow/AGPermissions.vue"; +import BucketCreation from "@/components/objects/BucketCreation.vue"; import { NavigationLink } from '@/types/navigation'; import { MetaUtils } from "@/utils/meta"; @@ -121,6 +122,7 @@ export abstract class RouteConfig { public static BucketsManagement = new NavigationLink('management', 'Buckets Management'); public static UploadFile = new NavigationLink('upload/', 'Objects Upload'); public static UploadFileChildren = new NavigationLink('*', 'Objects Upload Children'); + public static BucketCreation = new NavigationLink('creation', 'Bucket Creation') } const isNewProjectDashboard = MetaUtils.getMetaContent('new-project-dashboard') === 'true'; @@ -419,6 +421,11 @@ export const router = new Router({ }, ], }, + { + path: RouteConfig.BucketCreation.path, + name: RouteConfig.BucketCreation.name, + component: BucketCreation, + }, ], }, ], diff --git a/web/satellite/src/store/index.ts b/web/satellite/src/store/index.ts index b503042cd..aa278ee1b 100644 --- a/web/satellite/src/store/index.ts +++ b/web/satellite/src/store/index.ts @@ -95,7 +95,6 @@ export default store; store and the router. Many of the tests require router, however, this implementation relies on store state for the routing behavior. */ - router.beforeEach(async (to, _, next) => { if (!to.path.includes(RouteConfig.UploadFile.path) && !store.state.appStateModule.appState.isUploadCancelPopupVisible) { const areUploadsInProgress: boolean = await store.dispatch(OBJECTS_ACTIONS.CHECK_ONGOING_UPLOADS, to.path); @@ -127,13 +126,7 @@ router.beforeEach(async (to, _, next) => { } if (navigateToDefaultSubTab(to.matched, RouteConfig.Buckets)) { - if (store.state.appStateModule.isNewObjectsFlow) { - next(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path); - - return; - } - - next(RouteConfig.Buckets.with(RouteConfig.EncryptData).path); + next(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path); return; } diff --git a/web/satellite/static/images/objects/bucketCreation.svg b/web/satellite/static/images/objects/bucketCreation.svg new file mode 100644 index 000000000..e89ba5114 --- /dev/null +++ b/web/satellite/static/images/objects/bucketCreation.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/web/satellite/static/images/objects/check.svg b/web/satellite/static/images/objects/check.svg new file mode 100644 index 000000000..97d15a100 --- /dev/null +++ b/web/satellite/static/images/objects/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/satellite/static/images/objects/fingerprint.svg b/web/satellite/static/images/objects/fingerprint.svg new file mode 100644 index 000000000..cef81bdf6 --- /dev/null +++ b/web/satellite/static/images/objects/fingerprint.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/satellite/static/images/objects/key.svg b/web/satellite/static/images/objects/key.svg new file mode 100644 index 000000000..d4a31f912 --- /dev/null +++ b/web/satellite/static/images/objects/key.svg @@ -0,0 +1,3 @@ + + +