web/satellite: updated file browser prep flow

WHAT:
added additional screen when entering objects screen that tells user that server side encryption is used
replaced create passpgrase flow with enter passphrase flow

WHY:
bakeoff

Change-Id: I00271785bd7872fadbcd6317c53f57707b3a1271
This commit is contained in:
Vitalii Shpital 2021-04-14 18:38:58 +03:00
parent 240d571380
commit 2f39fc0f84
4 changed files with 246 additions and 58 deletions

View File

@ -4,18 +4,8 @@
<template> <template>
<div class="generate-container"> <div class="generate-container">
<h1 class="generate-container__title">Encryption Passphrase</h1> <h1 class="generate-container__title">Encryption Passphrase</h1>
<div class="generate-container__warning">
<div class="generate-container__warning__header">
<WarningIcon/>
<p class="generate-container__warning__header__label">Save Your Encryption Passphrase</p>
</div>
<p class="generate-container__warning__message">
Youll need this passphrase to access data in the future. This is the only time it will be displayed.
Be sure to write it down.
</p>
</div>
<div class="generate-container__choosing"> <div class="generate-container__choosing">
<p class="generate-container__choosing__label">Choose Passphrase Type</p> <p class="generate-container__choosing__label">Passphrase</p>
<div class="generate-container__choosing__right"> <div class="generate-container__choosing__right">
<p <p
class="generate-container__choosing__right__option left-option" class="generate-container__choosing__right__option left-option"
@ -26,13 +16,22 @@
</p> </p>
<p <p
class="generate-container__choosing__right__option" class="generate-container__choosing__right__option"
:class="{ active: isCreateState }" :class="{ active: isEnterState }"
@click="onChooseCreate" @click="onChooseCreate"
> >
Create Phrase Enter Phrase
</p> </p>
</div> </div>
</div> </div>
<div class="generate-container__enter-passphrase-box" v-if="isEnterState">
<div class="generate-container__enter-passphrase-box__header">
<GreenWarningIcon/>
<h2 class="generate-container__enter-passphrase-box__header__label">Enter an Existing Passphrase</h2>
</div>
<p class="generate-container__enter-passphrase-box__message">
if you already have an encryption passphrase, enter your encryption passphrase here.
</p>
</div>
<div class="generate-container__value-area"> <div class="generate-container__value-area">
<div class="generate-container__value-area__mnemonic" v-if="isGenerateState"> <div class="generate-container__value-area__mnemonic" v-if="isGenerateState">
<p class="generate-container__value-area__mnemonic__value">{{ passphrase }}</p> <p class="generate-container__value-area__mnemonic__value">{{ passphrase }}</p>
@ -47,30 +46,36 @@
<div class="generate-container__value-area__password" v-else> <div class="generate-container__value-area__password" v-else>
<HeaderedInput <HeaderedInput
class="generate-container__value-area__password__input" class="generate-container__value-area__password__input"
placeholder="Strong passphrases contain 12 characters or more" placeholder="Enter encryption passphrase here"
@setData="onChangePassphrase" @setData="onChangePassphrase"
:error="errorMessage" :error="errorMessage"
label="Create Your Passphrase"
/> />
</div> </div>
</div> </div>
<label class="generate-container__check-area" :class="{ error: isError }" for="pass-checkbox"> <div class="generate-container__warning" v-if="isGenerateState">
<input <h2 class="generate-container__warning__title">Save Your Encryption Passphrase</h2>
class="generate-container__check-area__checkbox" <p class="generate-container__warning__message">
id="pass-checkbox" Youll need this passphrase to access data in the future. This is the only time it will be displayed.
type="checkbox" Be sure to write it down.
v-model="isChecked" </p>
@change="isError = false" <label class="generate-container__warning__check-area" :class="{ error: isError }" for="pass-checkbox">
> <input
Yes, I wrote this down or saved it somewhere. class="generate-container__warning__check-area__checkbox"
</label> id="pass-checkbox"
type="checkbox"
v-model="isChecked"
@change="isError = false"
>
Yes, I wrote this down or saved it somewhere.
</label>
</div>
<VButton <VButton
class="generate-container__next-button" class="generate-container__next-button"
label="Next" label="Next"
width="100%" width="100%"
height="48px" height="48px"
:on-press="onProceed" :on-press="onProceed"
:is-disabled="isLoading" :is-disabled="isButtonDisabled"
/> />
</div> </div>
</template> </template>
@ -83,14 +88,14 @@ import HeaderedInput from '@/components/common/HeaderedInput.vue';
import VButton from '@/components/common/VButton.vue'; import VButton from '@/components/common/VButton.vue';
import BackIcon from '@/../static/images/accessGrants/back.svg'; import BackIcon from '@/../static/images/accessGrants/back.svg';
import WarningIcon from '@/../static/images/accessGrants/warning.svg'; import GreenWarningIcon from '@/../static/images/accessGrants/greenWarning.svg';
import { AnalyticsHttpApi } from '@/api/analytics'; import { AnalyticsHttpApi } from '@/api/analytics';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames'; import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
@Component({ @Component({
components: { components: {
WarningIcon, GreenWarningIcon,
BackIcon, BackIcon,
VButton, VButton,
HeaderedInput, HeaderedInput,
@ -103,10 +108,11 @@ export default class GeneratePassphrase extends Vue {
public readonly setParentPassphrase: (passphrase: string) => void; public readonly setParentPassphrase: (passphrase: string) => void;
@Prop({ default: false }) @Prop({ default: false })
public readonly isLoading: boolean; public readonly isLoading: boolean;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi(); private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public isGenerateState: boolean = true; public isGenerateState: boolean = true;
public isCreateState: boolean = false; public isEnterState: boolean = false;
public isChecked: boolean = false; public isChecked: boolean = false;
public isError: boolean = false; public isError: boolean = false;
public passphrase: string = ''; public passphrase: string = '';
@ -123,12 +129,12 @@ export default class GeneratePassphrase extends Vue {
public onProceed(): void { public onProceed(): void {
if (!this.passphrase) { if (!this.passphrase) {
this.errorMessage = 'Passphrase can`t be empty'; this.errorMessage = 'Passphrase can\'t be empty';
return; return;
} }
if (!this.isChecked) { if (!this.isChecked && this.isGenerateState) {
this.isError = true; this.isError = true;
return; return;
@ -148,7 +154,7 @@ export default class GeneratePassphrase extends Vue {
this.passphrase = bip39.generateMnemonic(); this.passphrase = bip39.generateMnemonic();
this.setParentPassphrase(this.passphrase); this.setParentPassphrase(this.passphrase);
this.isCreateState = false; this.isEnterState = false;
this.isGenerateState = true; this.isGenerateState = true;
} }
@ -156,13 +162,13 @@ export default class GeneratePassphrase extends Vue {
* Changes state to create passphrase. * Changes state to create passphrase.
*/ */
public onChooseCreate(): void { public onChooseCreate(): void {
if (this.passphrase && this.isCreateState) return; if (this.passphrase && this.isEnterState) return;
this.errorMessage = ''; this.errorMessage = '';
this.passphrase = ''; this.passphrase = '';
this.setParentPassphrase(this.passphrase); this.setParentPassphrase(this.passphrase);
this.isCreateState = true; this.isEnterState = true;
this.isGenerateState = false; this.isGenerateState = false;
} }
@ -184,6 +190,13 @@ export default class GeneratePassphrase extends Vue {
this.setParentPassphrase(this.passphrase); this.setParentPassphrase(this.passphrase);
this.errorMessage = ''; this.errorMessage = '';
} }
/**
* Indicates if button is disabled.
*/
public get isButtonDisabled(): boolean {
return this.isLoading || !this.passphrase || (!this.isChecked && this.isGenerateState);
}
} }
</script> </script>
@ -209,35 +222,74 @@ export default class GeneratePassphrase extends Vue {
margin: 0 0 30px 0; margin: 0 0 30px 0;
} }
&__warning { &__enter-passphrase-box {
display: flex;
flex-direction: column;
padding: 20px; padding: 20px;
width: calc(100% - 40px); background: #f9fffc;
background: #fff9f7; border: 1px solid #1a9666;
border: 1px solid #f84b00; border-radius: 9px;
margin-bottom: 35px;
border-radius: 8px;
&__header { &__header {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 10px;
&__label { &__label {
font-style: normal;
font-family: 'font_bold', sans-serif; font-family: 'font_bold', sans-serif;
font-size: 16px; font-size: 16px;
line-height: 19px; line-height: 19px;
color: #1b2533; color: #1b2533;
margin: 0 0 0 15px; margin: 0 0 0 10px;
} }
} }
&__message {
font-size: 16px;
line-height: 19px;
color: #1b2533;
margin: 0;
}
}
&__warning {
display: flex;
flex-direction: column;
padding: 20px;
width: calc(100% - 40px);
margin: 35px 0;
background: #fff;
border: 1px solid #e6e9ef;
border-radius: 9px;
&__title {
width: 100%;
text-align: center;
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
color: #1b2533;
margin: 0 0 0 15px;
}
&__message { &__message {
font-size: 16px; font-size: 16px;
line-height: 19px; line-height: 19px;
color: #1b2533; color: #1b2533;
margin: 10px 0 0 0; margin: 10px 0 0 0;
text-align: center;
}
&__check-area {
margin-top: 27px;
font-size: 14px;
line-height: 19px;
color: #1b2533;
display: flex;
justify-content: center;
align-items: center;
&__checkbox {
margin: 0 10px 0 0;
}
} }
} }
@ -246,6 +298,7 @@ export default class GeneratePassphrase extends Vue {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
margin-bottom: 25px;
&__label { &__label {
font-family: 'font_bold', sans-serif; font-family: 'font_bold', sans-serif;
@ -271,7 +324,6 @@ export default class GeneratePassphrase extends Vue {
} }
&__value-area { &__value-area {
margin: 32px 0;
width: 100%; width: 100%;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@ -302,23 +354,13 @@ export default class GeneratePassphrase extends Vue {
&__password { &__password {
width: 100%; width: 100%;
margin: 10px 0 20px 0;
&__input { &__input {
width: calc(100% - 8px); width: 100%;
} }
} }
} }
&__check-area {
margin-bottom: 32px;
font-size: 14px;
line-height: 19px;
color: #1b2533;
&__checkbox {
margin: 0 10px 0 0;
}
}
} }
.left-option { .left-option {
@ -355,4 +397,8 @@ export default class GeneratePassphrase extends Vue {
} }
} }
} }
/deep/ .headered-input {
padding-right: 0 !important;
}
</style> </style>

View File

@ -0,0 +1,131 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="warning-view">
<div class="warning-view__container">
<h1 class="warning-view__container__title">Object Browser</h1>
<div class="warning-view__container__message-container">
<h2 class="warning-view__container__message-container__sub-title">The object browser uses server side encryption.</h2>
<p class="warning-view__container__message-container__message">
If you want to use our product with only end-to-end encryption, you may want to skip this feature.
</p>
</div>
<div class="warning-view__container__buttons-area">
<VButton
class="warning-view__container__buttons-area__left-button"
label="Return to dashboard"
width="50%"
height="48px"
:on-press="goToDashboard"
:is-blue-white="true"
/>
<VButton
label="Continue"
width="50%"
height="48px"
:on-press="proceed"
/>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import VButton from '@/components/common/VButton.vue';
import { RouteConfig } from '@/router';
@Component({
components: {
VButton,
},
})
export default class WarningView extends Vue {
/**
* Redirects to project dashboard page.
*/
public goToDashboard(): void {
this.$router.push(RouteConfig.ProjectDashboard.path);
}
/**
* Proceeds further into file browser flow.
*/
public proceed(): void {
this.$router.push(RouteConfig.CreatePassphrase.path);
}
}
</script>
<style scoped lang="scss">
.warning-view {
font-family: 'font_regular', sans-serif;
font-style: normal;
display: flex;
align-items: center;
justify-content: center;
padding: 200px 0 20px 0;
&__container {
background: #fff;
border-radius: 6px;
padding: 35px 50px;
max-width: 515px;
&__title {
width: 100%;
text-align: center;
font-family: 'font_Bold', sans-serif;
font-size: 22px;
line-height: 27px;
color: #000;
margin: 0 0 35px 0;
}
&__message-container {
padding: 40px 30px;
width: calc(100% - 60px);
background: #fff;
border: 1px solid #e6e9ef;
border-radius: 9px;
display: flex;
flex-direction: column;
align-items: center;
&__sub-title {
font-family: 'font_bold', sans-serif;
font-size: 16px;
line-height: 19px;
text-align: center;
color: #ce3030;
margin: 0 0 10px 0;
}
&__message {
font-weight: normal;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #1b2533;
word-break: break-word;
margin: 0;
}
}
&__buttons-area {
margin-top: 35px;
display: flex;
align-items: center;
justify-content: space-between;
&__left-button {
margin-right: 40px;
}
}
}
}
</style>

View File

@ -25,6 +25,7 @@ import CreatePassphrase from '@/components/objects/CreatePassphrase.vue';
import EnterPassphrase from '@/components/objects/EnterPassphrase.vue'; import EnterPassphrase from '@/components/objects/EnterPassphrase.vue';
import ObjectsArea from '@/components/objects/ObjectsArea.vue'; import ObjectsArea from '@/components/objects/ObjectsArea.vue';
import UploadFile from '@/components/objects/UploadFile.vue'; import UploadFile from '@/components/objects/UploadFile.vue';
import WarningView from '@/components/objects/WarningView.vue';
import OnboardingTourArea from '@/components/onboardingTour/OnboardingTourArea.vue'; import OnboardingTourArea from '@/components/onboardingTour/OnboardingTourArea.vue';
import AddPaymentStep from '@/components/onboardingTour/steps/AddPaymentStep.vue'; import AddPaymentStep from '@/components/onboardingTour/steps/AddPaymentStep.vue';
import CreateAccessGrantStep from '@/components/onboardingTour/steps/CreateAccessGrantStep.vue'; import CreateAccessGrantStep from '@/components/onboardingTour/steps/CreateAccessGrantStep.vue';
@ -94,6 +95,7 @@ export abstract class RouteConfig {
public static AccessGrantGateway = new NavigationLink('gateway', 'Onboarding Access Grant Gateway'); public static AccessGrantGateway = new NavigationLink('gateway', 'Onboarding Access Grant Gateway');
// objects child paths. // objects child paths.
public static Warning = new NavigationLink('warning', 'Objects Warning');
public static CreatePassphrase = new NavigationLink('create-passphrase', 'Objects Create Passphrase'); public static CreatePassphrase = new NavigationLink('create-passphrase', 'Objects Create Passphrase');
public static EnterPassphrase = new NavigationLink('enter-passphrase', 'Objects Enter Passphrase'); public static EnterPassphrase = new NavigationLink('enter-passphrase', 'Objects Enter Passphrase');
public static BucketsManagement = new NavigationLink('buckets', 'Buckets Management'); public static BucketsManagement = new NavigationLink('buckets', 'Buckets Management');
@ -324,6 +326,11 @@ export const router = new Router({
name: RouteConfig.Objects.name, name: RouteConfig.Objects.name,
component: ObjectsArea, component: ObjectsArea,
children: [ children: [
{
path: RouteConfig.Warning.path,
name: RouteConfig.Warning.name,
component: WarningView,
},
{ {
path: RouteConfig.CreatePassphrase.path, path: RouteConfig.CreatePassphrase.path,
name: RouteConfig.CreatePassphrase.name, name: RouteConfig.CreatePassphrase.name,
@ -389,7 +396,7 @@ router.beforeEach((to, from, next) => {
} }
if (navigateToDefaultSubTab(to.matched, RouteConfig.Objects)) { if (navigateToDefaultSubTab(to.matched, RouteConfig.Objects)) {
next(RouteConfig.Objects.with(RouteConfig.CreatePassphrase).path); next(RouteConfig.Objects.with(RouteConfig.Warning).path);
return; return;
} }

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="18" y="18" width="18" height="18" rx="9" transform="rotate(-180 18 18)" fill="#1A9666"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.99707 4.66675C8.44478 4.66675 7.99707 5.11446 7.99707 5.66675L7.99707 9.00008C7.99707 9.55237 8.44478 10.0001 8.99707 10.0001C9.54935 10.0001 9.99707 9.55237 9.99707 9.00008L9.99707 5.66675C9.99707 5.11446 9.54935 4.66675 8.99707 4.66675ZM9.00098 11C8.31062 11 7.75098 11.5596 7.75098 12.25C7.75098 12.9404 8.31062 13.5 9.00098 13.5C9.69133 13.5 10.251 12.9404 10.251 12.25C10.251 11.5596 9.69133 11 9.00098 11Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 689 B