satellite/{web, console}: removed old project level passphrase flow
Removed old behavior and bucket creation flow. Issue: https://github.com/storj/storj/issues/5521 Change-Id: I1a443911215cd1f611069fd9e6202598066b80b2
This commit is contained in:
parent
382af95499
commit
5377b9c314
@ -68,35 +68,34 @@ type Config struct {
|
||||
AuthToken string `help:"auth token needed for access to registration token creation endpoint" default:"" testDefault:"very-secret-token"`
|
||||
AuthTokenSecret string `help:"secret used to sign auth tokens" releaseDefault:"" devDefault:"my-suppa-secret-key"`
|
||||
|
||||
ContactInfoURL string `help:"url link to contacts page" default:"https://forum.storj.io"`
|
||||
FrameAncestors string `help:"allow domains to embed the satellite in a frame, space separated" default:"tardigrade.io storj.io"`
|
||||
LetUsKnowURL string `help:"url link to let us know page" default:"https://storjlabs.atlassian.net/servicedesk/customer/portals"`
|
||||
SEO string `help:"used to communicate with web crawlers and other web robots" default:"User-agent: *\nDisallow: \nDisallow: /cgi-bin/"`
|
||||
SatelliteName string `help:"used to display at web satellite console" default:"Storj"`
|
||||
SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" `
|
||||
TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://www.storj.io/terms-of-service/"`
|
||||
AccountActivationRedirectURL string `help:"url link for account activation redirect" default:""`
|
||||
PartneredSatellites console.Satellites `help:"names and addresses of partnered satellites in JSON list format" default:"[{\"name\":\"US1\",\"address\":\"https://us1.storj.io\"},{\"name\":\"EU1\",\"address\":\"https://eu1.storj.io\"},{\"name\":\"AP1\",\"address\":\"https://ap1.storj.io\"}]"`
|
||||
GeneralRequestURL string `help:"url link to general request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000379291"`
|
||||
ProjectLimitsIncreaseRequestURL string `help:"url link to project limit increase request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"`
|
||||
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:"http://localhost:8000"`
|
||||
IsBetaSatellite bool `help:"indicates if satellite is in beta" default:"false"`
|
||||
BetaSatelliteFeedbackURL string `help:"url link for for beta satellite feedback" default:""`
|
||||
BetaSatelliteSupportURL string `help:"url link for for beta satellite support" default:""`
|
||||
DocumentationURL string `help:"url link to documentation" default:"https://docs.storj.io/"`
|
||||
CouponCodeBillingUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from billing" default:"false"`
|
||||
CouponCodeSignupUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from signup" default:"false"`
|
||||
FileBrowserFlowDisabled bool `help:"indicates if file browser flow is disabled" default:"false"`
|
||||
CSPEnabled bool `help:"indicates if Content Security Policy is enabled" devDefault:"false" releaseDefault:"true"`
|
||||
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:"http://localhost:8001"`
|
||||
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:"true"`
|
||||
NewBillingScreen bool `help:"indicates if new billing screens should be used" default:"true"`
|
||||
GeneratedAPIEnabled bool `help:"indicates if generated console api should be used" default:"false"`
|
||||
OptionalSignupSuccessURL string `help:"optional url to external registration success page" default:""`
|
||||
HomepageURL string `help:"url link to storj.io homepage" default:"https://www.storj.io"`
|
||||
NativeTokenPaymentsEnabled bool `help:"indicates if storj native token payments system is enabled" default:"false"`
|
||||
NewEncryptionPassphraseFlowEnabled bool `help:"indicates if new encryption passphrase flow is enabled" default:"true"`
|
||||
ContactInfoURL string `help:"url link to contacts page" default:"https://forum.storj.io"`
|
||||
FrameAncestors string `help:"allow domains to embed the satellite in a frame, space separated" default:"tardigrade.io storj.io"`
|
||||
LetUsKnowURL string `help:"url link to let us know page" default:"https://storjlabs.atlassian.net/servicedesk/customer/portals"`
|
||||
SEO string `help:"used to communicate with web crawlers and other web robots" default:"User-agent: *\nDisallow: \nDisallow: /cgi-bin/"`
|
||||
SatelliteName string `help:"used to display at web satellite console" default:"Storj"`
|
||||
SatelliteOperator string `help:"name of organization which set up satellite" default:"Storj Labs" `
|
||||
TermsAndConditionsURL string `help:"url link to terms and conditions page" default:"https://www.storj.io/terms-of-service/"`
|
||||
AccountActivationRedirectURL string `help:"url link for account activation redirect" default:""`
|
||||
PartneredSatellites console.Satellites `help:"names and addresses of partnered satellites in JSON list format" default:"[{\"name\":\"US1\",\"address\":\"https://us1.storj.io\"},{\"name\":\"EU1\",\"address\":\"https://eu1.storj.io\"},{\"name\":\"AP1\",\"address\":\"https://ap1.storj.io\"}]"`
|
||||
GeneralRequestURL string `help:"url link to general request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000379291"`
|
||||
ProjectLimitsIncreaseRequestURL string `help:"url link to project limit increase request page" default:"https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"`
|
||||
GatewayCredentialsRequestURL string `help:"url link for gateway credentials requests" default:"https://auth.storjshare.io" devDefault:"http://localhost:8000"`
|
||||
IsBetaSatellite bool `help:"indicates if satellite is in beta" default:"false"`
|
||||
BetaSatelliteFeedbackURL string `help:"url link for for beta satellite feedback" default:""`
|
||||
BetaSatelliteSupportURL string `help:"url link for for beta satellite support" default:""`
|
||||
DocumentationURL string `help:"url link to documentation" default:"https://docs.storj.io/"`
|
||||
CouponCodeBillingUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from billing" default:"false"`
|
||||
CouponCodeSignupUIEnabled bool `help:"indicates if user is allowed to add coupon codes to account from signup" default:"false"`
|
||||
FileBrowserFlowDisabled bool `help:"indicates if file browser flow is disabled" default:"false"`
|
||||
CSPEnabled bool `help:"indicates if Content Security Policy is enabled" devDefault:"false" releaseDefault:"true"`
|
||||
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:"http://localhost:8001"`
|
||||
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:"true"`
|
||||
NewBillingScreen bool `help:"indicates if new billing screens should be used" default:"true"`
|
||||
GeneratedAPIEnabled bool `help:"indicates if generated console api should be used" default:"false"`
|
||||
OptionalSignupSuccessURL string `help:"optional url to external registration success page" default:""`
|
||||
HomepageURL string `help:"url link to storj.io homepage" default:"https://www.storj.io"`
|
||||
NativeTokenPaymentsEnabled bool `help:"indicates if storj native token payments system is enabled" default:"false"`
|
||||
|
||||
OauthCodeExpiry time.Duration `help:"how long oauth authorization codes are issued for" default:"10m"`
|
||||
OauthAccessTokenExpiry time.Duration `help:"how long oauth access tokens are issued for" default:"24h"`
|
||||
@ -428,46 +427,45 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
|
||||
header.Set("Referrer-Policy", "same-origin") // Only expose the referring url when navigating around the satellite itself.
|
||||
|
||||
var data struct {
|
||||
ExternalAddress string
|
||||
SatelliteName string
|
||||
SatelliteNodeURL string
|
||||
StripePublicKey string
|
||||
PartneredSatellites string
|
||||
DefaultProjectLimit int
|
||||
GeneralRequestURL string
|
||||
ProjectLimitsIncreaseRequestURL string
|
||||
GatewayCredentialsRequestURL string
|
||||
IsBetaSatellite bool
|
||||
BetaSatelliteFeedbackURL string
|
||||
BetaSatelliteSupportURL string
|
||||
DocumentationURL string
|
||||
CouponCodeBillingUIEnabled bool
|
||||
CouponCodeSignupUIEnabled bool
|
||||
FileBrowserFlowDisabled bool
|
||||
LinksharingURL string
|
||||
PathwayOverviewEnabled bool
|
||||
RegistrationRecaptchaEnabled bool
|
||||
RegistrationRecaptchaSiteKey string
|
||||
RegistrationHcaptchaEnabled bool
|
||||
RegistrationHcaptchaSiteKey string
|
||||
LoginRecaptchaEnabled bool
|
||||
LoginRecaptchaSiteKey string
|
||||
LoginHcaptchaEnabled bool
|
||||
LoginHcaptchaSiteKey string
|
||||
NewProjectDashboard bool
|
||||
DefaultPaidStorageLimit memory.Size
|
||||
DefaultPaidBandwidthLimit memory.Size
|
||||
NewBillingScreen bool
|
||||
InactivityTimerEnabled bool
|
||||
InactivityTimerDuration int
|
||||
InactivityTimerViewerEnabled bool
|
||||
OptionalSignupSuccessURL string
|
||||
HomepageURL string
|
||||
NativeTokenPaymentsEnabled bool
|
||||
NewEncryptionPassphraseFlowEnabled bool
|
||||
PasswordMinimumLength int
|
||||
PasswordMaximumLength int
|
||||
ABTestingEnabled bool
|
||||
ExternalAddress string
|
||||
SatelliteName string
|
||||
SatelliteNodeURL string
|
||||
StripePublicKey string
|
||||
PartneredSatellites string
|
||||
DefaultProjectLimit int
|
||||
GeneralRequestURL string
|
||||
ProjectLimitsIncreaseRequestURL string
|
||||
GatewayCredentialsRequestURL string
|
||||
IsBetaSatellite bool
|
||||
BetaSatelliteFeedbackURL string
|
||||
BetaSatelliteSupportURL string
|
||||
DocumentationURL string
|
||||
CouponCodeBillingUIEnabled bool
|
||||
CouponCodeSignupUIEnabled bool
|
||||
FileBrowserFlowDisabled bool
|
||||
LinksharingURL string
|
||||
PathwayOverviewEnabled bool
|
||||
RegistrationRecaptchaEnabled bool
|
||||
RegistrationRecaptchaSiteKey string
|
||||
RegistrationHcaptchaEnabled bool
|
||||
RegistrationHcaptchaSiteKey string
|
||||
LoginRecaptchaEnabled bool
|
||||
LoginRecaptchaSiteKey string
|
||||
LoginHcaptchaEnabled bool
|
||||
LoginHcaptchaSiteKey string
|
||||
NewProjectDashboard bool
|
||||
DefaultPaidStorageLimit memory.Size
|
||||
DefaultPaidBandwidthLimit memory.Size
|
||||
NewBillingScreen bool
|
||||
InactivityTimerEnabled bool
|
||||
InactivityTimerDuration int
|
||||
InactivityTimerViewerEnabled bool
|
||||
OptionalSignupSuccessURL string
|
||||
HomepageURL string
|
||||
NativeTokenPaymentsEnabled bool
|
||||
PasswordMinimumLength int
|
||||
PasswordMaximumLength int
|
||||
ABTestingEnabled bool
|
||||
}
|
||||
|
||||
data.ExternalAddress = server.config.ExternalAddress
|
||||
@ -506,7 +504,6 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data.OptionalSignupSuccessURL = server.config.OptionalSignupSuccessURL
|
||||
data.HomepageURL = server.config.HomepageURL
|
||||
data.NativeTokenPaymentsEnabled = server.config.NativeTokenPaymentsEnabled
|
||||
data.NewEncryptionPassphraseFlowEnabled = server.config.NewEncryptionPassphraseFlowEnabled
|
||||
data.PasswordMinimumLength = console.PasswordMinimumLength
|
||||
data.PasswordMaximumLength = console.PasswordMaximumLength
|
||||
data.ABTestingEnabled = server.config.ABTesting.Enabled
|
||||
|
3
scripts/testdata/satellite-config.yaml.lock
vendored
3
scripts/testdata/satellite-config.yaml.lock
vendored
@ -244,9 +244,6 @@ compensation.withheld-percents: 75,75,75,50,50,50,25,25,25,0,0,0,0,0,0
|
||||
# indicates if new billing screens should be used
|
||||
# console.new-billing-screen: true
|
||||
|
||||
# indicates if new encryption passphrase flow is enabled
|
||||
# console.new-encryption-passphrase-flow-enabled: true
|
||||
|
||||
# indicates if new project dashboard should be used
|
||||
# console.new-project-dashboard: true
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
<meta name="optional-signup-success-url" content="{{ .OptionalSignupSuccessURL }}">
|
||||
<meta name="homepage-url" content="{{ .HomepageURL }}">
|
||||
<meta name="native-token-payments-enabled" content="{{ .NativeTokenPaymentsEnabled }}">
|
||||
<meta name="new-encryption-passphrase-flow-enabled" content="{{ .NewEncryptionPassphraseFlowEnabled }}">
|
||||
<meta name="password-minimum-length" content="{{ .PasswordMinimumLength }}">
|
||||
<meta name="password-maximum-length" content="{{ .PasswordMaximumLength }}">
|
||||
<meta name="ab-testing-enabled" content="{{ .ABTestingEnabled }}">
|
||||
|
@ -40,7 +40,6 @@ export default class App extends Vue {
|
||||
const couponCodeBillingUIEnabled = MetaUtils.getMetaContent('coupon-code-billing-ui-enabled');
|
||||
const couponCodeSignupUIEnabled = MetaUtils.getMetaContent('coupon-code-signup-ui-enabled');
|
||||
const isNewProjectDashboard = MetaUtils.getMetaContent('new-project-dashboard');
|
||||
const isNewEncryptionPassphraseFlowEnabled = MetaUtils.getMetaContent('new-encryption-passphrase-flow-enabled');
|
||||
|
||||
if (satelliteName) {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.SET_SATELLITE_NAME, satelliteName);
|
||||
@ -73,10 +72,6 @@ export default class App extends Vue {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.SET_PROJECT_DASHBOARD_STATUS, isNewProjectDashboard === 'true');
|
||||
}
|
||||
|
||||
if (isNewEncryptionPassphraseFlowEnabled) {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS, isNewEncryptionPassphraseFlowEnabled === 'true');
|
||||
}
|
||||
|
||||
this.fixViewportHeight();
|
||||
}
|
||||
|
||||
|
@ -5,28 +5,11 @@
|
||||
<VModal :on-close="closeModal">
|
||||
<template #content>
|
||||
<div class="modal">
|
||||
<template v-if="isNewEncryptionPassphraseFlowEnabled">
|
||||
<OpenBucketIcon />
|
||||
<h1 class="modal__title">Enter your encryption passphrase</h1>
|
||||
<p class="modal__info">
|
||||
To open a bucket and view your encrypted files, <br>please enter your encryption passphrase.
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Icon />
|
||||
<h1 class="modal__title">Open a Bucket</h1>
|
||||
<p class="modal__info">
|
||||
To open a bucket and view your files, please enter the encryption passphrase you saved upon
|
||||
creating this bucket.
|
||||
</p>
|
||||
<VInput
|
||||
class="modal__input"
|
||||
label="Bucket Name"
|
||||
:init-value="bucketName"
|
||||
role-description="bucket"
|
||||
:disabled="true"
|
||||
/>
|
||||
</template>
|
||||
<OpenBucketIcon />
|
||||
<h1 class="modal__title">Enter your encryption passphrase</h1>
|
||||
<p class="modal__info">
|
||||
To open a bucket and view your encrypted files, <br>please enter your encryption passphrase.
|
||||
</p>
|
||||
<VInput
|
||||
label="Encryption Passphrase"
|
||||
placeholder="Enter a passphrase here"
|
||||
@ -73,7 +56,6 @@ import VModal from '@/components/common/VModal.vue';
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import Icon from '@/../static/images/objects/openBucket.svg';
|
||||
import OpenBucketIcon from '@/../static/images/buckets/openBucket.svg';
|
||||
|
||||
// @vue/component
|
||||
@ -82,7 +64,6 @@ import OpenBucketIcon from '@/../static/images/buckets/openBucket.svg';
|
||||
VInput,
|
||||
VModal,
|
||||
VButton,
|
||||
Icon,
|
||||
OpenBucketIcon,
|
||||
},
|
||||
})
|
||||
@ -144,11 +125,6 @@ export default class OpenBucketModal extends Vue {
|
||||
const now = new Date();
|
||||
const inThreeDays = new Date(now.setDate(now.getDate() + 3));
|
||||
|
||||
let bucketsCaveat: string[] = [];
|
||||
if (!this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
bucketsCaveat = this.bucketName ? [this.bucketName] : [];
|
||||
}
|
||||
|
||||
await this.worker.postMessage({
|
||||
'type': 'SetPermission',
|
||||
'isDownload': true,
|
||||
@ -156,7 +132,7 @@ export default class OpenBucketModal extends Vue {
|
||||
'isList': true,
|
||||
'isDelete': true,
|
||||
'notAfter': inThreeDays.toISOString(),
|
||||
'buckets': bucketsCaveat,
|
||||
'buckets': [],
|
||||
'apiKey': this.apiKey,
|
||||
});
|
||||
|
||||
@ -185,11 +161,8 @@ export default class OpenBucketModal extends Vue {
|
||||
|
||||
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant });
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
|
||||
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
|
||||
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
|
||||
}
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
|
||||
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,13 +207,6 @@ export default class OpenBucketModal extends Vue {
|
||||
private get apiKey(): string {
|
||||
return this.$store.state.objectsModule.apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -273,10 +239,6 @@ export default class OpenBucketModal extends Vue {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
margin-bottom: 21px;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
column-gap: 20px;
|
||||
|
@ -47,7 +47,7 @@
|
||||
<p class="project-selection__dropdown__items__choice__unselected">{{ project.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isNewEncryptionPassphraseFlowEnabled" tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
|
||||
<div tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
|
||||
<PassphraseIcon />
|
||||
<p class="project-selection__dropdown__link-container__label">Manage Passphrase</p>
|
||||
</div>
|
||||
@ -346,20 +346,9 @@ export default class MobileNavigation extends Vue {
|
||||
* Toggles manage passphrase modal shown.
|
||||
*/
|
||||
public onManagePassphraseClick(): void {
|
||||
if (!this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_MANAGE_PROJECT_PASSPHRASE_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is objects view.
|
||||
*/
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p class="project-selection__dropdown__items__choice__unselected">{{ project.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isNewEncryptionPassphraseFlowEnabled" tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
|
||||
<div tabindex="0" class="project-selection__dropdown__link-container" @click.stop="onManagePassphraseClick" @keyup.enter="onManagePassphraseClick">
|
||||
<PassphraseIcon />
|
||||
<p class="project-selection__dropdown__link-container__label">Manage Passphrase</p>
|
||||
</div>
|
||||
@ -152,11 +152,8 @@ export default class ProjectSelection extends Vue {
|
||||
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
|
||||
this.closeDropdown();
|
||||
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled || this.isBucketsView) {
|
||||
this.$store.commit(OBJECTS_MUTATIONS.CLEAR);
|
||||
}
|
||||
|
||||
if (this.isBucketsView) {
|
||||
this.$store.commit(OBJECTS_MUTATIONS.CLEAR);
|
||||
await this.$router.push(RouteConfig.Buckets.path).catch(() => {return; });
|
||||
|
||||
return;
|
||||
@ -266,10 +263,6 @@ export default class ProjectSelection extends Vue {
|
||||
* Toggles manage passphrase modal shown.
|
||||
*/
|
||||
public onManagePassphraseClick(): void {
|
||||
if (!this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_MANAGE_PROJECT_PASSPHRASE_MODAL_SHOWN);
|
||||
|
||||
this.closeDropdown();
|
||||
@ -296,13 +289,6 @@ export default class ProjectSelection extends Vue {
|
||||
this.closeDropdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is objects view.
|
||||
*/
|
||||
|
@ -1,286 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="bucket-creation">
|
||||
<bucket-creation-progress class="bucket-creation__progress" :creation-step="creationStep" />
|
||||
<bucket-creation-name-step
|
||||
v-if="creationStep === BucketCreationSteps.Name"
|
||||
:is-parent-loading="isLoading"
|
||||
@setName="setName"
|
||||
/>
|
||||
<bucket-creation-generate-passphrase
|
||||
v-if="creationStep === BucketCreationSteps.Passphrase"
|
||||
:on-next-click="onPassphraseGenerationNextClick"
|
||||
:on-back-click="onGenerationBackClick"
|
||||
:set-parent-passphrase="setPassphrase"
|
||||
:is-loading="isLoading"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { OBJECTS_ACTIONS, OBJECTS_MUTATIONS } from '@/store/modules/objects';
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { MetaUtils } from '@/utils/meta';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
|
||||
import BucketCreationGeneratePassphrase from '@/components/objects/BucketCreationGeneratePassphrase.vue';
|
||||
import BucketCreationNameStep from '@/components/objects/BucketCreationNameStep.vue';
|
||||
import BucketCreationProgress from '@/components/objects/BucketCreationProgress.vue';
|
||||
|
||||
export enum BucketCreationSteps {
|
||||
Name = 0,
|
||||
Passphrase,
|
||||
Upload
|
||||
}
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
BucketCreationProgress,
|
||||
BucketCreationNameStep,
|
||||
BucketCreationGeneratePassphrase,
|
||||
},
|
||||
})
|
||||
export default class BucketCreation extends Vue {
|
||||
private worker: Worker;
|
||||
|
||||
private readonly FILE_BROWSER_AG_NAME: string = 'Web file browser API key';
|
||||
public readonly BucketCreationSteps = BucketCreationSteps;
|
||||
public creationStep: BucketCreationSteps = BucketCreationSteps.Name;
|
||||
public isLoading = false;
|
||||
public bucketName = '';
|
||||
public passphrase = '';
|
||||
|
||||
public readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
/**
|
||||
* Sets bucket name from child component.
|
||||
*/
|
||||
public async setName(name: string): Promise<void> {
|
||||
this.bucketName = name;
|
||||
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled && !this.promptForPassphrase) {
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
await this.createBucketAndNavigate();
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.creationStep = BucketCreationSteps.Passphrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets passphrase from child component.
|
||||
*/
|
||||
public setPassphrase(passphrase: string): void {
|
||||
this.passphrase = passphrase;
|
||||
this.$store.dispatch(OBJECTS_ACTIONS.SET_PASSPHRASE, this.passphrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local worker with worker instantiated in store.
|
||||
*/
|
||||
public setWorker(): void {
|
||||
this.worker = this.$store.state.accessGrantsModule.accessGrantsWebWorker;
|
||||
this.worker.onerror = (error: ErrorEvent) => {
|
||||
this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on next button click logic on passphrase generation step.
|
||||
*/
|
||||
public async onPassphraseGenerationNextClick(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
this.setWorker();
|
||||
await this.setAccess();
|
||||
await this.createBucketAndNavigate();
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on back button click logic on passphrase generation step.
|
||||
*/
|
||||
public onGenerationBackClick(): void {
|
||||
this.creationStep = BucketCreationSteps.Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes temporary created access grant.
|
||||
*/
|
||||
public async removeTemporaryAccessGrant(): Promise<void> {
|
||||
try {
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.DELETE_BY_NAME_AND_PROJECT_ID, this.FILE_BROWSER_AG_NAME);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches bucket using api.
|
||||
*/
|
||||
public async fetchBuckets(page = 1): Promise<void> {
|
||||
try {
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, page);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to fetch buckets. ${error.message}`, AnalyticsErrorEventSource.BUCKET_CREATION_FLOW);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets access to S3 client.
|
||||
*/
|
||||
public async setAccess(): Promise<void> {
|
||||
if (!this.apiKey) {
|
||||
await this.removeTemporaryAccessGrant();
|
||||
const cleanAPIKey: AccessGrant = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CREATE, this.FILE_BROWSER_AG_NAME);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_API_KEY, cleanAPIKey.secret);
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const inThreeDays = new Date(now.setDate(now.getDate() + 3));
|
||||
|
||||
const bucketsCaveat: string[] = [];
|
||||
if (!this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
bucketsCaveat.push(this.bucketName);
|
||||
}
|
||||
|
||||
await this.worker.postMessage({
|
||||
'type': 'SetPermission',
|
||||
'isDownload': true,
|
||||
'isUpload': true,
|
||||
'isList': true,
|
||||
'isDelete': true,
|
||||
'notAfter': inThreeDays.toISOString(),
|
||||
'buckets': bucketsCaveat,
|
||||
'apiKey': this.apiKey,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
if (grantEvent.data.error) {
|
||||
throw new Error(grantEvent.data.error);
|
||||
}
|
||||
|
||||
const satelliteNodeURL: string = MetaUtils.getMetaContent('satellite-nodeurl');
|
||||
const salt = await this.$store.dispatch(PROJECTS_ACTIONS.GET_SALT, this.$store.getters.selectedProject.id);
|
||||
|
||||
this.worker.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': grantEvent.data.value,
|
||||
'passphrase': this.passphrase,
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const accessGrantEvent: MessageEvent = await new Promise(resolve => this.worker.onmessage = resolve);
|
||||
if (accessGrantEvent.data.error) {
|
||||
throw new Error(accessGrantEvent.data.error);
|
||||
}
|
||||
|
||||
const accessGrant = accessGrantEvent.data.value;
|
||||
|
||||
const gatewayCredentials: EdgeCredentials = await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.GET_GATEWAY_CREDENTIALS, { accessGrant });
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_GATEWAY_CREDENTIALS, gatewayCredentials);
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_S3_CLIENT);
|
||||
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
await this.$store.commit(OBJECTS_MUTATIONS.SET_PROMPT_FOR_PASSPHRASE, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates bucket and navigates to file browser.
|
||||
*/
|
||||
private async createBucketAndNavigate(): Promise<void> {
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.CREATE_BUCKET, this.bucketName);
|
||||
await this.fetchBuckets();
|
||||
await this.$store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, this.bucketName);
|
||||
this.analytics.eventTriggered(AnalyticsEvent.BUCKET_CREATED);
|
||||
this.analytics.pageVisit(RouteConfig.UploadFile.path);
|
||||
await this.$router.push(RouteConfig.UploadFile.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns apiKey from store.
|
||||
*/
|
||||
private get apiKey(): string {
|
||||
return this.$store.state.objectsModule.apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns condition if user has to be prompt for passphrase from store.
|
||||
*/
|
||||
private get promptForPassphrase(): boolean {
|
||||
return this.$store.state.objectsModule.promptForPassphrase;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bucket-creation {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding-bottom: 30px;
|
||||
|
||||
&__progress {
|
||||
margin-bottom: 44px;
|
||||
width: 460px;
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
width: 85%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.bucket-icon) {
|
||||
width: 267px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
|
||||
:deep(.label-container__main__label) {
|
||||
font-size: 0.875rem !important;
|
||||
line-height: 1.285rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
||||
:deep(.bucket-icon) {
|
||||
width: 190px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,455 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="encrypt-container">
|
||||
<bucket-icon class="bucket-icon" />
|
||||
<div v-if="generationStep === GenerationSteps.TypeSelection" class="encrypt-container__functional">
|
||||
<div class="encrypt-container__functional__header">
|
||||
<p class="encrypt-container__functional__header__title" aria-roledescription="title">
|
||||
Encrypt your bucket
|
||||
</p>
|
||||
<p class="encrypt-container__functional__header__info">
|
||||
We encourage you to generate the encryption passphrase.
|
||||
You can also enter your own passphrase for this bucket.
|
||||
</p>
|
||||
</div>
|
||||
<div class="encrypt-container__functional__variant" aria-roledescription="generate" @click="selectedType = GenerationSteps.Generation">
|
||||
<input
|
||||
class="encrypt-container__functional__variant__radio"
|
||||
type="radio"
|
||||
name="radio"
|
||||
:checked="selectedType === GenerationSteps.Generation"
|
||||
>
|
||||
<div class="encrypt-container__functional__variant__icon">
|
||||
<key-icon />
|
||||
</div>
|
||||
<div class="encrypt-container__functional__variant__text-container">
|
||||
<h4 class="encrypt-container__functional__variant__text-container__title">Generate passphrase</h4>
|
||||
<p class="encrypt-container__functional__variant__text-container__info">Automatically generate 12-word passphrase.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="encrypt-container__functional__variant__divider" />
|
||||
<div class="encrypt-container__functional__variant" aria-roledescription="manual" @click="selectedType = GenerationSteps.Manual">
|
||||
<input
|
||||
class="encrypt-container__functional__variant__radio"
|
||||
type="radio"
|
||||
name="radio"
|
||||
:checked="selectedType === GenerationSteps.Manual"
|
||||
>
|
||||
<div class="encrypt-container__functional__variant__icon">
|
||||
<fingerprint-icon />
|
||||
</div>
|
||||
<div class="encrypt-container__functional__variant__text-container">
|
||||
<h4 class="encrypt-container__functional__variant__text-container__title">Enter passphrase</h4>
|
||||
<p class="encrypt-container__functional__variant__text-container__info">You can also enter your own passphrase.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="encrypt-container__functional">
|
||||
<div class="encrypt-container__functional__header">
|
||||
<p class="encrypt-container__functional__header__title" aria-roledescription="title">
|
||||
{{ generationStep === GenerationSteps.Generation ? 'Generate a passphrase' : 'Enter a passphrase' }}
|
||||
</p>
|
||||
<p class="encrypt-container__functional__header__info">
|
||||
Please note that Storj does not know or store your encryption passphrase.
|
||||
If you lose it, you will not be able to recover your files.
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="generationStep === GenerationSteps.Generation" class="encrypt-container__functional__generate">
|
||||
<p class="encrypt-container__functional__generate__value" aria-roledescription="mnemonic">{{ passphrase }}</p>
|
||||
<v-button
|
||||
class="encrypt-container__functional__generate__button"
|
||||
label="Download"
|
||||
width="143px"
|
||||
height="48px"
|
||||
:on-press="onDownloadClick"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="encrypt-container__functional__enter">
|
||||
<v-input
|
||||
label="Your Passphrase"
|
||||
placeholder="Enter a passphrase here..."
|
||||
:error="enterError"
|
||||
role-description="passphrase"
|
||||
is-password
|
||||
:disabled="isLoading"
|
||||
@setData="setPassphrase"
|
||||
/>
|
||||
</div>
|
||||
<v-checkbox
|
||||
class="encrypt-container__functional__checkbox"
|
||||
label="I understand, and I have saved the passphrase."
|
||||
:is-checkbox-error="isCheckboxError"
|
||||
@setData="setSavingConfirmation"
|
||||
/>
|
||||
</div>
|
||||
<div class="encrypt-container__buttons">
|
||||
<v-button
|
||||
class="encrypt-container__buttons__back button"
|
||||
label="Back"
|
||||
height="48px"
|
||||
width="45%"
|
||||
:is-white="true"
|
||||
:on-press="generationStep === GenerationSteps.TypeSelection ? onBackClick : navigateToTypeSelection"
|
||||
:is-disabled="isLoading"
|
||||
/>
|
||||
<v-button
|
||||
v-if="generationStep === GenerationSteps.TypeSelection"
|
||||
class="button"
|
||||
height="48px"
|
||||
width="45%"
|
||||
label="Continue"
|
||||
:on-press="selectPassphraseVariant"
|
||||
/>
|
||||
<v-button
|
||||
v-else
|
||||
class="button"
|
||||
label="Continue"
|
||||
height="48px"
|
||||
width="45%"
|
||||
:on-press="onNextButtonClick"
|
||||
:is-disabled="isLoading || !isSavingConfirmed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { generateMnemonic } from 'bip39';
|
||||
|
||||
import { Download } from '@/utils/download';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
import VCheckbox from '@/components/common/VCheckbox.vue';
|
||||
|
||||
import BucketIcon from '@/../static/images/objects/bucketCreation.svg';
|
||||
import KeyIcon from '@/../static/images/objects/key.svg';
|
||||
import FingerprintIcon from '@/../static/images/objects/fingerprint.svg';
|
||||
|
||||
enum GenerationSteps {
|
||||
TypeSelection,
|
||||
Generation,
|
||||
Manual,
|
||||
}
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
BucketIcon,
|
||||
KeyIcon,
|
||||
FingerprintIcon,
|
||||
VButton,
|
||||
VInput,
|
||||
VCheckbox,
|
||||
},
|
||||
})
|
||||
export default class GeneratePassphrase extends Vue {
|
||||
@Prop({ default: () => null })
|
||||
public readonly onNextClick: () => unknown;
|
||||
@Prop({ default: () => null })
|
||||
public readonly onBackClick: () => unknown;
|
||||
@Prop({ default: () => null })
|
||||
public readonly setParentPassphrase: (passphrase: string) => void;
|
||||
@Prop({ default: false })
|
||||
public readonly isLoading: boolean;
|
||||
|
||||
public readonly GenerationSteps = GenerationSteps;
|
||||
|
||||
public selectedType: GenerationSteps = GenerationSteps.Generation;
|
||||
public generationStep: GenerationSteps = GenerationSteps.TypeSelection;
|
||||
public enterError = '';
|
||||
public passphrase = '';
|
||||
public isSavingConfirmed = false;
|
||||
public isCheckboxError = false;
|
||||
|
||||
private readonly analytics = new AnalyticsHttpApi();
|
||||
|
||||
public setSavingConfirmation(value: boolean): void {
|
||||
this.isSavingConfirmed = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects passphrase setup variant.
|
||||
* If not manual, generates passphrase.
|
||||
*/
|
||||
public selectPassphraseVariant(): void {
|
||||
if (this.selectedType === GenerationSteps.Generation) {
|
||||
this.passphrase = generateMnemonic();
|
||||
this.setParentPassphrase(this.passphrase);
|
||||
}
|
||||
|
||||
this.generationStep = this.selectedType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on download button click logic.
|
||||
* Downloads encryption passphrase as a txt file.
|
||||
*/
|
||||
public onDownloadClick(): void {
|
||||
if (!this.passphrase) {
|
||||
this.enterError = 'Can\'t be empty!';
|
||||
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = 'StorjEncryptionPassphrase.txt';
|
||||
|
||||
Download.file(this.passphrase, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates back to passphrase option selection.
|
||||
*/
|
||||
public navigateToTypeSelection(): void {
|
||||
this.enterError = '';
|
||||
this.passphrase = '';
|
||||
this.isSavingConfirmed = false;
|
||||
this.generationStep = GenerationSteps.TypeSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets passphrase from child component.
|
||||
*/
|
||||
public setPassphrase(passphrase: string): void {
|
||||
if (this.enterError) this.enterError = '';
|
||||
|
||||
this.passphrase = passphrase;
|
||||
this.setParentPassphrase(this.passphrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on next button click logic.
|
||||
*/
|
||||
public async onNextButtonClick(): Promise<void> {
|
||||
if (!this.passphrase) {
|
||||
this.enterError = 'Can\'t be empty!';
|
||||
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isSavingConfirmed) {
|
||||
this.isCheckboxError = true;
|
||||
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_PASSPHRASE_STEP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.onNextClick();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.encrypt-container {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding: 60px 60px 50px;
|
||||
max-width: 500px;
|
||||
background: #fcfcfc;
|
||||
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
|
||||
border-radius: 20px;
|
||||
margin: 30px auto 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__functional {
|
||||
margin-top: 20px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 26px;
|
||||
line-height: 31px;
|
||||
color: #131621;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 21px;
|
||||
color: #354049;
|
||||
}
|
||||
}
|
||||
|
||||
&__variant {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 20px 0;
|
||||
cursor: pointer;
|
||||
|
||||
&__radio {
|
||||
color: var(--c-blue-3);
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: var(--c-blue-1);
|
||||
margin: 0 8px;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&__text-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background: var(--c-grey-4);
|
||||
}
|
||||
}
|
||||
|
||||
&__generate {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px 22px;
|
||||
background: #eff0f7;
|
||||
border-radius: 10px;
|
||||
margin-top: 25px;
|
||||
|
||||
&__value {
|
||||
font-size: 14px;
|
||||
line-height: 25px;
|
||||
color: #384b65;
|
||||
}
|
||||
|
||||
&__button {
|
||||
margin-left: 12px;
|
||||
min-width: 130px;
|
||||
}
|
||||
}
|
||||
|
||||
&__download {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #0068dc;
|
||||
cursor: pointer;
|
||||
margin: 20px 25px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&__warning-title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #1b2533;
|
||||
margin: 25px 25px 10px;
|
||||
}
|
||||
|
||||
&__warning-msg {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #1b2533;
|
||||
margin: 0 25px;
|
||||
}
|
||||
|
||||
&__checkbox {
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 30px;
|
||||
|
||||
&__back {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
|
||||
.encrypt-container {
|
||||
padding: 40px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
||||
.encrypt-container {
|
||||
|
||||
&__functional__header {
|
||||
|
||||
&__title {
|
||||
font-size: 1.715rem;
|
||||
line-height: 2.215rem;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.285rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
flex-direction: column-reverse;
|
||||
margin-top: 25px;
|
||||
|
||||
.button {
|
||||
width: 100% !important;
|
||||
|
||||
&:first-of-type {
|
||||
margin: 25px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 385px) {
|
||||
|
||||
.encrypt-container {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,264 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="bucket-name-creation">
|
||||
<v-loader v-if="isLoading" width="100px" height="100px" />
|
||||
<template v-else>
|
||||
<bucket-icon class="bucket-icon" />
|
||||
<div class="bucket-name-creation__functional">
|
||||
<div class="bucket-name-creation__functional__header">
|
||||
<p class="bucket-name-creation__functional__header__title" aria-roledescription="title">
|
||||
Create a bucket
|
||||
</p>
|
||||
<p class="bucket-name-creation__functional__header__info">
|
||||
Buckets are used to store your files. It’s recommended that every bucket should have it’s own encryption passphrase.
|
||||
</p>
|
||||
</div>
|
||||
<v-input
|
||||
label="Bucket Name"
|
||||
placeholder="Enter a name here..."
|
||||
:error="nameError"
|
||||
role-description="name"
|
||||
:init-value="name"
|
||||
additional-label="Lowercase alphanumeric characters only (no spaces)"
|
||||
:disabled="isLoading || isParentLoading"
|
||||
@setData="onChangeName"
|
||||
/>
|
||||
</div>
|
||||
<div class="bucket-name-creation__buttons">
|
||||
<v-button
|
||||
class="button"
|
||||
label="Cancel"
|
||||
height="48px"
|
||||
width="47%"
|
||||
:on-press="onCancelClick"
|
||||
:is-white="true"
|
||||
/>
|
||||
<v-button
|
||||
class="button"
|
||||
label="Continue"
|
||||
height="48px"
|
||||
width="47%"
|
||||
:on-press="onNextButtonClick"
|
||||
:is-disabled="!name || nameError !== '' || isParentLoading"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { Validator } from '@/utils/validation';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
import VInput from '@/components/common/VInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
import BucketIcon from '@/../static/images/objects/bucketCreation.svg';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
VInput,
|
||||
VButton,
|
||||
BucketIcon,
|
||||
VLoader,
|
||||
},
|
||||
})
|
||||
export default class BucketCreationNameStep extends Vue {
|
||||
@Prop({ default: false })
|
||||
public readonly isParentLoading: boolean;
|
||||
|
||||
public name = '';
|
||||
public nameError = '';
|
||||
public isLoading = true;
|
||||
|
||||
public readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
public async mounted(): Promise<void> {
|
||||
try {
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH_ALL_BUCKET_NAMES);
|
||||
this.name = this.allBucketNames.length > 0 ? '' : 'demo-bucket';
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message, AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bucket name from input.
|
||||
*/
|
||||
public onChangeName(value: string): void {
|
||||
if (this.nameError) this.nameError = '';
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bucket name from input.
|
||||
*/
|
||||
public onNextButtonClick(): void {
|
||||
if (!this.isBucketNameValid(this.name)) {
|
||||
this.analytics.errorEventTriggered(AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.allBucketNames.includes(this.name)) {
|
||||
this.$notify.error('Bucket with this name already exists', AnalyticsErrorEventSource.BUCKET_CREATION_NAME_STEP);
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('setName', this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to buckets list view.
|
||||
*/
|
||||
public onCancelClick(): void {
|
||||
LocalData.setDemoBucketCreatedStatus();
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
|
||||
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation status of a bucket name.
|
||||
*/
|
||||
private isBucketNameValid(name: string): boolean {
|
||||
switch (true) {
|
||||
case name.length < 3 || name.length > 63:
|
||||
this.nameError = 'Name must be not less than 3 and not more than 63 characters length';
|
||||
|
||||
return false;
|
||||
case !Validator.bucketName(name):
|
||||
this.nameError = 'Name must contain only lowercase latin characters, numbers, a hyphen or a period';
|
||||
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private get allBucketNames(): string[] {
|
||||
return this.$store.state.bucketUsageModule.allBucketNames;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bucket-name-creation {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding: 60px 65px 50px;
|
||||
max-width: 500px;
|
||||
background: #fcfcfc;
|
||||
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
|
||||
border-radius: 20px;
|
||||
margin: 30px auto 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__functional {
|
||||
margin-top: 20px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 26px;
|
||||
line-height: 31px;
|
||||
color: #131621;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 21px;
|
||||
color: #354049;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 30px;
|
||||
|
||||
&__back {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.label-container__main__label) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.label-container__main) {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
|
||||
.bucket-name-creation {
|
||||
padding: 40px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
||||
.bucket-name-creation {
|
||||
|
||||
&__functional__header {
|
||||
|
||||
&__title {
|
||||
font-size: 1.715rem;
|
||||
line-height: 2.215rem;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.285rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
flex-direction: column-reverse;
|
||||
margin-top: 25px;
|
||||
|
||||
.button {
|
||||
width: 100% !important;
|
||||
|
||||
&:first-of-type {
|
||||
margin: 25px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 385px) {
|
||||
|
||||
.bucket-name-creation {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,138 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="bucket-creation-progress">
|
||||
<div class="bucket-creation-progress__item active">
|
||||
<div class="bucket-creation-progress__item__outer-circle">
|
||||
<div class="bucket-creation-progress__item__inner-circle">
|
||||
<span v-if="creationStep === BucketCreationSteps.Name">1</span>
|
||||
<check-icon v-else />
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="bucket-creation-progress__item__label" :class="{ passed: creationStep >= BucketCreationSteps.Passphrase }">Bucket</h4>
|
||||
<div class="bucket-creation-progress__item__divider" />
|
||||
</div>
|
||||
<div class="bucket-creation-progress__item" :class="{ active: creationStep >= BucketCreationSteps.Passphrase }">
|
||||
<div class="bucket-creation-progress__item__outer-circle">
|
||||
<div class="bucket-creation-progress__item__inner-circle">
|
||||
<check-icon v-if="creationStep === BucketCreationSteps.Upload" />
|
||||
<span v-else>2</span>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="bucket-creation-progress__item__label" :class="{ passed: creationStep >= BucketCreationSteps.Passphrase }">Encryption</h4>
|
||||
<div class="bucket-creation-progress__item__divider" />
|
||||
</div>
|
||||
<div class="bucket-creation-progress__item" :class="{ active: creationStep > BucketCreationSteps.Passphrase }">
|
||||
<div class="bucket-creation-progress__item__outer-circle">
|
||||
<div class="bucket-creation-progress__item__inner-circle">
|
||||
<span>3</span>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="bucket-creation-progress__item__label">Upload</h4>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { BucketCreationSteps } from '@/components/objects/BucketCreation.vue';
|
||||
|
||||
import CheckIcon from '@/../static/images/objects/check.svg';
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {
|
||||
CheckIcon,
|
||||
},
|
||||
})
|
||||
export default class BucketCreationProgress extends Vue {
|
||||
@Prop({ default: 0 })
|
||||
public readonly creationStep: BucketCreationSteps;
|
||||
|
||||
public readonly BucketCreationSteps = BucketCreationSteps;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bucket-creation-progress {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&__outer-circle,
|
||||
&__inner-circle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__outer-circle {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background: rgb(20 20 42 / 20%);
|
||||
}
|
||||
|
||||
&__inner-circle {
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
background: #b1b1b1;
|
||||
|
||||
span {
|
||||
font-family: 'font_semiBold', sans-serif;
|
||||
font-size: 10px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: rgb(20 20 42 / 20%);
|
||||
margin-top: 13px;
|
||||
}
|
||||
|
||||
&__divider {
|
||||
position: absolute;
|
||||
width: 130px;
|
||||
height: 1px;
|
||||
top: 16px;
|
||||
left: 100%;
|
||||
background: var(--c-grey-2);
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
.bucket-creation-progress__item__outer-circle {
|
||||
background: var(--c-blue-2);
|
||||
}
|
||||
|
||||
.bucket-creation-progress__item__inner-circle {
|
||||
background: var(--c-blue-3);
|
||||
}
|
||||
|
||||
.bucket-creation-progress__item__label {
|
||||
color: var(--c-blue-3);
|
||||
|
||||
&.passed {
|
||||
color: #14142a !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -86,10 +86,7 @@ export default class BucketDetails extends Vue {
|
||||
public openBucket(): void {
|
||||
this.$store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, this.bucket?.name);
|
||||
|
||||
if (
|
||||
this.$route.params.backRoute === RouteConfig.UploadFileChildren.name ||
|
||||
(this.isNewEncryptionPassphraseFlowEnabled && !this.promptForPassphrase)
|
||||
) {
|
||||
if (this.$route.params.backRoute === RouteConfig.UploadFileChildren.name || !this.promptForPassphrase) {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
|
||||
this.$router.push(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
|
||||
|
||||
@ -105,13 +102,6 @@ export default class BucketDetails extends Vue {
|
||||
private get promptForPassphrase(): boolean {
|
||||
return this.$store.state.objectsModule.promptForPassphrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
private get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -19,28 +19,19 @@
|
||||
<EmptyBucketIcon class="buckets-table__no-buckets-area__image" />
|
||||
<CreateBucketIcon class="buckets-table__no-buckets-area__small-image" />
|
||||
<h4 class="buckets-table__no-buckets-area__title">There are no buckets in this project</h4>
|
||||
<template v-if="isNewEncryptionPassphraseFlowEnabled">
|
||||
<template v-if="promptForPassphrase">
|
||||
<p class="buckets-table__no-buckets-area__body">Set an encryption passphrase to start uploading files.</p>
|
||||
<VButton
|
||||
label="Set Encryption Passphrase ->"
|
||||
width="234px"
|
||||
height="40px"
|
||||
font-size="14px"
|
||||
:on-press="onSetClick"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="buckets-table__no-buckets-area__body">Create a new bucket to upload files</p>
|
||||
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
|
||||
<WhitePlusIcon class="new-bucket-button__icon" />
|
||||
<p class="new-bucket-button__label">New Bucket</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="promptForPassphrase">
|
||||
<p class="buckets-table__no-buckets-area__body">Set an encryption passphrase to start uploading files.</p>
|
||||
<VButton
|
||||
label="Set Encryption Passphrase ->"
|
||||
width="234px"
|
||||
height="40px"
|
||||
font-size="14px"
|
||||
:on-press="onSetClick"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="buckets-table__no-buckets-area__body">Create a new bucket to upload files</p>
|
||||
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onNewBucketButtonClick">
|
||||
<div class="new-bucket-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
|
||||
<WhitePlusIcon class="new-bucket-button__icon" />
|
||||
<p class="new-bucket-button__label">New Bucket</p>
|
||||
</div>
|
||||
@ -164,13 +155,6 @@ const promptForPassphrase = computed((): boolean => {
|
||||
return store.state.objectsModule.promptForPassphrase;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
const isNewEncryptionPassphraseFlowEnabled = computed((): boolean => {
|
||||
return store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
});
|
||||
|
||||
/**
|
||||
* Toggles set passphrase modal visibility.
|
||||
*/
|
||||
@ -185,14 +169,6 @@ function onCreateBucketClick(): void {
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts bucket creation flow.
|
||||
*/
|
||||
function onNewBucketButtonClick(): void {
|
||||
analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches bucket using api.
|
||||
*/
|
||||
@ -240,7 +216,7 @@ function openDropdown(key: number): void {
|
||||
*/
|
||||
function openBucket(bucketName: string): void {
|
||||
store.dispatch(OBJECTS_ACTIONS.SET_FILE_COMPONENT_BUCKET_NAME, bucketName);
|
||||
if (isNewEncryptionPassphraseFlowEnabled.value && !promptForPassphrase.value) {
|
||||
if (!promptForPassphrase.value) {
|
||||
analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
|
||||
router.push(RouteConfig.Buckets.with(RouteConfig.UploadFile).path);
|
||||
|
||||
|
@ -5,26 +5,18 @@
|
||||
<div class="buckets-view">
|
||||
<div class="buckets-view__title-area">
|
||||
<h1 class="buckets-view__title-area__title" aria-roledescription="title">Buckets</h1>
|
||||
<template v-if="isNewEncryptionPassphraseFlowEnabled">
|
||||
<VButton
|
||||
v-if="promptForPassphrase"
|
||||
label="Set Encryption Passphrase ->"
|
||||
width="234px"
|
||||
height="40px"
|
||||
font-size="14px"
|
||||
:on-press="onSetClick"
|
||||
/>
|
||||
<div v-else class="buckets-view-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
|
||||
<WhitePlusIcon class="buckets-view-button__icon" />
|
||||
<p class="buckets-view-button__label">New Bucket</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="buckets-view-button" :class="{ disabled: isLoading }" @click="onNewBucketButtonClick">
|
||||
<WhitePlusIcon class="buckets-view-button__icon" />
|
||||
<p class="buckets-view-button__label">New Bucket</p>
|
||||
</div>
|
||||
</template>
|
||||
<VButton
|
||||
v-if="promptForPassphrase"
|
||||
label="Set Encryption Passphrase ->"
|
||||
width="234px"
|
||||
height="40px"
|
||||
font-size="14px"
|
||||
:on-press="onSetClick"
|
||||
/>
|
||||
<div v-else class="buckets-view-button" :class="{ disabled: isLoading }" @click="onCreateBucketClick">
|
||||
<WhitePlusIcon class="buckets-view-button__icon" />
|
||||
<p class="buckets-view-button__label">New Bucket</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buckets-view__divider" />
|
||||
@ -99,15 +91,8 @@ export default class BucketsView extends Vue {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.bucketsPage.buckets.length && !wasDemoBucketCreated) {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
if (!this.promptForPassphrase) {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
|
||||
}
|
||||
} else {
|
||||
await this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
}
|
||||
if (!this.bucketsPage.buckets.length && !wasDemoBucketCreated && !this.promptForPassphrase) {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Failed to setup Buckets view. ${error.message}`, AnalyticsErrorEventSource.BUCKET_PAGE);
|
||||
@ -141,14 +126,6 @@ export default class BucketsView extends Vue {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_BUCKET_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts bucket creation flow.
|
||||
*/
|
||||
public onNewBucketButtonClick(): void {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketCreation).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides server-side encryption banner.
|
||||
*/
|
||||
@ -164,13 +141,6 @@ export default class BucketsView extends Vue {
|
||||
return this.$store.state.bucketUsageModule.page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user should be prompt for passphrase.
|
||||
*/
|
||||
|
@ -32,17 +32,6 @@ export default class ObjectsArea extends Vue {
|
||||
await this.$router.push(RouteConfig.ProjectDashboard.path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook before component destroying.
|
||||
* Clears objects VUEX state.
|
||||
*/
|
||||
public beforeDestroy(): void {
|
||||
// new encryption passphrase flow should not clear passphrase/api key when exiting object browser.
|
||||
if (!this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled) {
|
||||
this.$store.dispatch(OBJECTS_ACTIONS.CLEAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -11,8 +11,7 @@
|
||||
<p class="medium">Do you know a bucket can have multiple passphrases?</p>
|
||||
<p>
|
||||
If you don’t see the objects you’re looking for,
|
||||
<span v-if="isNewEncryptionPassphraseFlowEnabled" class="link" @click="toggleManagePassphrase">try opening the bucket again</span>
|
||||
<router-link v-else class="link" :to="bucketsManagementPath">try opening the bucket again</router-link>
|
||||
<span class="link" @click="toggleManagePassphrase">try opening the bucket again</span>
|
||||
with a different passphrase.
|
||||
</p>
|
||||
</template>
|
||||
@ -51,8 +50,6 @@ export default class UploadFile extends Vue {
|
||||
private worker: Worker;
|
||||
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
public readonly bucketsManagementPath: string = RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path;
|
||||
|
||||
/**
|
||||
* Lifecycle hook after vue instance was created.
|
||||
* Initiates file browser.
|
||||
@ -75,10 +72,6 @@ export default class UploadFile extends Vue {
|
||||
|
||||
@Watch('edgeCredentials.secretKey')
|
||||
public async reinit(): Promise<void> {
|
||||
if (!this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.edgeCredentials.secretKey) {
|
||||
await this.$router.push(RouteConfig.Buckets.with(RouteConfig.BucketsManagement).path).catch(() => {return;});
|
||||
return;
|
||||
@ -257,13 +250,6 @@ export default class UploadFile extends Vue {
|
||||
private get edgeCredentials(): EdgeCredentials {
|
||||
return this.$store.state.objectsModule.gatewayCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -95,14 +95,7 @@ export default class OverviewStep extends Vue {
|
||||
* Redirects to buckets page.
|
||||
*/
|
||||
public onUploadInBrowserClick(): void {
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled) {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PASSPHRASE_MODAL_SHOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push(RouteConfig.Buckets.path).catch(() => {return; });
|
||||
this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, 'Continue in Browser');
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.path);
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PASSPHRASE_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,13 +104,6 @@ export default class OverviewStep extends Vue {
|
||||
private get satelliteName(): string {
|
||||
return this.$store.state.appStateModule.satelliteName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
private get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -7,40 +7,7 @@
|
||||
<p class="project-dashboard__message">
|
||||
Expect a delay of a few hours between network activity and the latest dashboard stats.
|
||||
</p>
|
||||
<DashboardFunctionalHeader
|
||||
v-if="isNewEncryptionPassphraseFlowEnabled"
|
||||
:loading="isDataFetching || areBucketsFetching"
|
||||
/>
|
||||
<template v-else>
|
||||
<VLoader v-if="isDataFetching" class="project-dashboard__loader" width="100px" height="100px" />
|
||||
<p v-if="!isDataFetching && limits.objectCount" class="project-dashboard__subtitle" aria-roledescription="with-usage-title">
|
||||
Your
|
||||
<span class="project-dashboard__subtitle__value">{{ limits.objectCount }} objects</span>
|
||||
are stored in
|
||||
<span class="project-dashboard__subtitle__value">{{ limits.segmentCount }} segments</span>
|
||||
around the world
|
||||
</p>
|
||||
<template v-if="!isDataFetching && !limits.objectCount">
|
||||
<p class="project-dashboard__subtitle" aria-roledescription="empty-title">
|
||||
Welcome to Storj :) <br> You’re ready to experience the future of cloud storage
|
||||
</p>
|
||||
</template>
|
||||
<p class="project-dashboard__limits">
|
||||
<span class="project-dashboard__limits--bold">Storage Limit</span>
|
||||
per month: {{ limits.storageLimit | bytesToBase10String }} |
|
||||
<span class="project-dashboard__limits--bold">Bandwidth Limit</span>
|
||||
per month: {{ limits.bandwidthLimit | bytesToBase10String }}
|
||||
</p>
|
||||
<template v-if="!isDataFetching && !limits.objectCount">
|
||||
<VButton
|
||||
class="project-dashboard__upload-button"
|
||||
label="Upload"
|
||||
width="100px"
|
||||
height="40px"
|
||||
:on-press="onUploadClick"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
<DashboardFunctionalHeader :loading="isDataFetching || areBucketsFetching" />
|
||||
<div class="project-dashboard__stats-header">
|
||||
<h2 class="project-dashboard__stats-header__title">Project Stats</h2>
|
||||
<div class="project-dashboard__stats-header__buttons">
|
||||
@ -265,7 +232,7 @@ export default class NewProjectDashboard extends Vue {
|
||||
past.setDate(past.getDate() - 30);
|
||||
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
|
||||
if (this.isNewEncryptionPassphraseFlowEnabled && this.hasJustLoggedIn) {
|
||||
if (this.hasJustLoggedIn) {
|
||||
if (this.limits.objectCount > 0) {
|
||||
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_ENTER_PASSPHRASE_MODAL_SHOWN);
|
||||
} else {
|
||||
@ -332,14 +299,6 @@ export default class NewProjectDashboard extends Vue {
|
||||
this.$router.push(RouteConfig.CreateProject.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds on upload button click logic.
|
||||
*/
|
||||
public onUploadClick(): void {
|
||||
this.analytics.pageVisit(RouteConfig.Buckets.path);
|
||||
this.$router.push(RouteConfig.Buckets.path).catch(() => {return;});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatted amount.
|
||||
*/
|
||||
@ -441,13 +400,6 @@ export default class NewProjectDashboard extends Vue {
|
||||
return this.$store.state.projectsModule.chartDataBefore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new encryption passphrase flow is enabled.
|
||||
*/
|
||||
public get isNewEncryptionPassphraseFlowEnabled(): boolean {
|
||||
return this.$store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has just logged in.
|
||||
*/
|
||||
@ -479,19 +431,6 @@ export default class NewProjectDashboard extends Vue {
|
||||
background-repeat: no-repeat;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
|
||||
&__limits {
|
||||
font-size: 14px;
|
||||
margin-top: 11px;
|
||||
|
||||
&--bold {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
&__loader {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 16px;
|
||||
@ -506,25 +445,6 @@ export default class NewProjectDashboard extends Vue {
|
||||
margin: 10px 0 64px;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
letter-spacing: -0.02em;
|
||||
color: #000;
|
||||
max-width: 365px;
|
||||
|
||||
&__value {
|
||||
text-decoration: underline;
|
||||
text-underline-position: under;
|
||||
text-decoration-color: var(--c-green-3);
|
||||
}
|
||||
}
|
||||
|
||||
&__upload-button {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&__stats-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -43,7 +43,6 @@ 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 BucketDetails from '@/components/objects/BucketDetails.vue';
|
||||
|
||||
const ActivateAccount = () => import('@/views/ActivateAccount.vue');
|
||||
@ -114,7 +113,6 @@ export abstract class RouteConfig {
|
||||
public static BucketsDetails = new NavigationLink('details', 'Bucket Details');
|
||||
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';
|
||||
@ -390,11 +388,6 @@ export const router = new Router({
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: RouteConfig.BucketCreation.path,
|
||||
name: RouteConfig.BucketCreation.name,
|
||||
component: BucketCreation,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -102,9 +102,7 @@ export default store;
|
||||
*/
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (to.name === RouteConfig.NewProjectDashboard.name && from.name === RouteConfig.Login.name) {
|
||||
if (store.state.appStateModule.isNewEncryptionPassphraseFlowEnabled) {
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_HAS_JUST_LOGGED_IN);
|
||||
}
|
||||
store.commit(APP_STATE_MUTATIONS.TOGGLE_HAS_JUST_LOGGED_IN);
|
||||
}
|
||||
|
||||
if (!to.path.includes(RouteConfig.UploadFile.path) && !store.state.appStateModule.appState.isUploadCancelPopupVisible) {
|
||||
|
@ -70,7 +70,6 @@ class State {
|
||||
public couponCodeBillingUIEnabled = false,
|
||||
public couponCodeSignupUIEnabled = false,
|
||||
public isNewProjectDashboard = false,
|
||||
public isNewEncryptionPassphraseFlowEnabled = false,
|
||||
){}
|
||||
}
|
||||
|
||||
@ -272,9 +271,6 @@ export const appStateModule = {
|
||||
[APP_STATE_MUTATIONS.SET_PROJECT_DASHBOARD_STATUS](state: State, isNewProjectDashboard: boolean): void {
|
||||
state.isNewProjectDashboard = isNewProjectDashboard;
|
||||
},
|
||||
[APP_STATE_MUTATIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS](state: State, isNewEncryptionPassphraseFlowEnabled: boolean): void {
|
||||
state.isNewEncryptionPassphraseFlowEnabled = isNewEncryptionPassphraseFlowEnabled;
|
||||
},
|
||||
[APP_STATE_MUTATIONS.SET_ONB_AG_NAME_STEP_BACK_ROUTE](state: State, backRoute: string): void {
|
||||
state.appState.onbAGStepBackRoute = backRoute;
|
||||
},
|
||||
@ -442,9 +438,6 @@ export const appStateModule = {
|
||||
[APP_STATE_ACTIONS.SET_PROJECT_DASHBOARD_STATUS]: function ({ commit }: AppContext, isNewProjectDashboard: boolean): void {
|
||||
commit(APP_STATE_MUTATIONS.SET_PROJECT_DASHBOARD_STATUS, isNewProjectDashboard);
|
||||
},
|
||||
[APP_STATE_ACTIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS]: function ({ commit }: AppContext, isNewEncryptionPassphraseFlowEnabled: boolean): void {
|
||||
commit(APP_STATE_MUTATIONS.SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS, isNewEncryptionPassphraseFlowEnabled);
|
||||
},
|
||||
[APP_STATE_ACTIONS.SET_COUPON_CODE_BILLING_UI_STATUS]: function ({ commit }: AppContext, couponCodeBillingUIEnabled: boolean): void {
|
||||
commit(APP_STATE_MUTATIONS.SET_COUPON_CODE_BILLING_UI_STATUS, couponCodeBillingUIEnabled);
|
||||
},
|
||||
|
@ -62,7 +62,6 @@ export const APP_STATE_MUTATIONS = {
|
||||
SET_COUPON_CODE_BILLING_UI_STATUS: 'SET_COUPON_CODE_BILLING_UI_STATUS',
|
||||
SET_COUPON_CODE_SIGNUP_UI_STATUS: 'SET_COUPON_CODE_SIGNUP_UI_STATUS',
|
||||
SET_PROJECT_DASHBOARD_STATUS: 'SET_PROJECT_DASHBOARD_STATUS',
|
||||
SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS: 'SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS',
|
||||
SET_ONB_AG_NAME_STEP_BACK_ROUTE: 'SET_ONB_AG_NAME_STEP_BACK_ROUTE',
|
||||
SET_ONB_API_KEY_STEP_BACK_ROUTE: 'SET_ONB_API_KEY_STEP_BACK_ROUTE',
|
||||
SET_ONB_API_KEY: 'SET_ONB_API_KEY',
|
||||
|
@ -32,7 +32,6 @@ export const APP_STATE_ACTIONS = {
|
||||
SET_COUPON_CODE_BILLING_UI_STATUS: 'SET_COUPON_CODE_BILLING_UI_STATUS',
|
||||
SET_COUPON_CODE_SIGNUP_UI_STATUS: 'SET_COUPON_CODE_SIGNUP_UI_STATUS',
|
||||
SET_PROJECT_DASHBOARD_STATUS: 'SET_PROJECT_DASHBOARD_STATUS',
|
||||
SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS: 'SET_ENCRYPTION_PASSPHRASE_FLOW_STATUS',
|
||||
};
|
||||
|
||||
export const NOTIFICATION_ACTIONS = {
|
||||
|
Loading…
Reference in New Issue
Block a user