{satellite}/web,console,testsuite: remove old navigation structure

Removed old satellite UI navigation structure.
Removed old feature flag.

Change-Id: Ic998886cf2e30ebd44e67a20fc53888103fe4b8d
This commit is contained in:
Vitalii 2022-05-31 13:30:40 +03:00
parent 18ef3d3881
commit ba58530089
48 changed files with 525 additions and 2954 deletions

View File

@ -93,7 +93,6 @@ type Config struct {
LinksharingURL string `help:"url link for linksharing requests" default:"https://link.storjshare.io" devDefault:""`
PathwayOverviewEnabled bool `help:"indicates if the overview onboarding step should render with pathways" default:"true"`
NewProjectDashboard bool `help:"indicates if new project dashboard should be used" default:"false"`
NewNavigation bool `help:"indicates if new navigation structure should be rendered" default:"true"`
NewObjectsFlow bool `help:"indicates if new objects flow should be used" default:"true"`
NewAccessGrantFlow bool `help:"indicates if new access grant flow should be used" default:"false"`
NewBillingScreen bool `help:"indicates if new billing screens should be used" default:"false"`
@ -416,7 +415,6 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
NewProjectDashboard bool
DefaultPaidStorageLimit memory.Size
DefaultPaidBandwidthLimit memory.Size
NewNavigation bool
NewObjectsFlow bool
NewAccessGrantFlow bool
NewBillingScreen bool
@ -454,7 +452,6 @@ func (server *Server) appHandler(w http.ResponseWriter, r *http.Request) {
data.HcaptchaEnabled = server.config.Hcaptcha.Enabled
data.HcaptchaSiteKey = server.config.Hcaptcha.SiteKey
data.NewProjectDashboard = server.config.NewProjectDashboard
data.NewNavigation = server.config.NewNavigation
data.NewObjectsFlow = server.config.NewObjectsFlow
data.NewAccessGrantFlow = server.config.NewAccessGrantFlow
data.NewBillingScreen = server.config.NewBillingScreen

View File

@ -184,9 +184,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: false
# indicates if new navigation structure should be rendered
# console.new-navigation: true
# indicates if new objects flow should be used
# console.new-objects-flow: true

View File

@ -34,7 +34,6 @@ func configureSatellite(log *zap.Logger, index int, config *satellite.Config) {
if dir := os.Getenv("STORJ_TEST_SATELLITE_WEB"); dir != "" {
config.Console.StaticDir = dir
}
config.Console.NewNavigation = true
config.Console.NewObjectsFlow = true
config.Console.NewProjectDashboard = true
config.Console.CouponCodeBillingUIEnabled = true

View File

@ -30,7 +30,6 @@
<meta name="new-project-dashboard" content="{{ .NewProjectDashboard }}">
<meta name="default-paid-storage-limit" content="{{ .DefaultPaidStorageLimit }}">
<meta name="default-paid-bandwidth-limit" content="{{ .DefaultPaidBandwidthLimit }}">
<meta name="new-navigation-structure" content="{{ .NewNavigation }}">
<meta name="new-objects-flow" content="{{ .NewObjectsFlow }}">
<meta name="new-access-grant-flow" content="{{ .NewAccessGrantFlow }}">
<meta name="new-billing-screen" content="{{ .NewBillingScreen }}">

View File

@ -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 isNewNavStructure = MetaUtils.getMetaContent('new-navigation-structure');
const isNewObjectsFlow = MetaUtils.getMetaContent('new-objects-flow');
if (satelliteName) {
@ -76,10 +75,6 @@ export default class App extends Vue {
this.$store.dispatch(APP_STATE_ACTIONS.SET_PROJECT_DASHBOARD_STATUS, isNewProjectDashboard === 'true');
}
if (isNewNavStructure) {
this.$store.dispatch(APP_STATE_ACTIONS.SET_NAV_STRUCTURE_STATUS, isNewNavStructure === 'true');
}
if (isNewObjectsFlow) {
this.$store.dispatch(APP_STATE_ACTIONS.SET_OBJECTS_FLOW_STATUS, isNewObjectsFlow === 'true');
}

View File

@ -1,333 +0,0 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="header-container">
<div class="header-container__left-area">
<div class="header-container__left-area__logo-area">
<NavigationMenuIcon
v-if="!isNavigationVisible && !isOnboardingTour"
id="navigation-menu-icon"
class="header-container__left-area__logo-area__menu-button"
@click.stop="toggleNavigationVisibility"
/>
<div v-if="isNavigationVisible" class="header-container__left-area__logo-area__close-button" @click.stop="toggleNavigationVisibility">
<NavigationCloseIcon />
<p class="header-container__left-area__logo-area__close-button__title">Close</p>
</div>
<LogoIcon
class="logo"
@click.stop="onLogoClick"
/>
</div>
<div class="header-container__left-area__selection-wrapper">
<ProjectSelection class="project-selection" />
<ResourcesSelection class="resources-selection" />
<SettingsSelection class="settings-selection" />
</div>
</div>
<div class="header-container__right-area">
<VInfo
v-if="!isOnboardingTour"
class="header-container__right-area__info"
title="Need some help?"
button-label="Start tour"
:on-button-click="onStartTourButtonClick"
>
<template #icon>
<InfoIcon class="header-container__right-area__info__icon" aria-roledescription="restart-onb-icon" />
</template>
<template #message>
<p class="header-container__right-area__info__message">
You can always start the onboarding tour and go through all the steps to get you started again.
</p>
</template>
</VInfo>
<div class="header-container__right-area__satellite-area">
<div class="header-container__right-area__satellite-area__checkmark">
<CheckmarkIcon />
</div>
<p class="header-container__right-area__satellite-area__name">{{ satelliteName }}</p>
</div>
<AccountButton class="header-container__right-area__account-button" />
</div>
<NavigationArea
v-if="isNavigationVisible"
class="adapted-navigation"
/>
<div v-if="isNavigationVisible" class="navigation-blur" @click.self.stop="toggleNavigationVisibility" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ProjectSelection from '@/components/header/projectsDropdown/ProjectSelection.vue';
import ResourcesSelection from '@/components/header/resourcesDropdown/ResourcesSelection.vue';
import SettingsSelection from '@/components/header/settingsDropdown/SettingsSelection.vue';
import NavigationArea from '@/components/navigation/NavigationArea.vue';
import VInfo from '@/components/common/VInfo.vue';
import LogoIcon from '@/../static/images/logo.svg';
import InfoIcon from '@/../static/images/header/info.svg';
import CheckmarkIcon from '@/../static/images/header/checkmark.svg';
import NavigationCloseIcon from '@/../static/images/header/navigationClose.svg';
import NavigationMenuIcon from '@/../static/images/header/navigationMenu.svg';
import { RouteConfig } from '@/router';
import AccountButton from './accountDropdown/AccountButton.vue';
// @vue/component
@Component({
components: {
AccountButton,
NavigationArea,
VInfo,
NavigationMenuIcon,
NavigationCloseIcon,
LogoIcon,
InfoIcon,
CheckmarkIcon,
ProjectSelection,
ResourcesSelection,
SettingsSelection,
},
})
export default class HeaderArea extends Vue {
/**
* Indicates if navigation toggling button is visible depending on screen width.
*/
public isNavigationVisible = false;
/**
* Toggle navigation visibility.
*/
public toggleNavigationVisibility(): void {
this.isNavigationVisible = !this.isNavigationVisible;
}
/**
* Reloads page.
*/
public onLogoClick(): void {
location.reload();
}
/**
* Redirects to onboarding tour.
*/
public async onStartTourButtonClick(): Promise<void> {
await this.$router.push(RouteConfig.OnboardingTour.path).catch(() => {return; })
}
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
/**
* Returns satellite name from config.
*/
public get satelliteName(): string {
return this.$store.state.appStateModule.satelliteName;
}
}
</script>
<style scoped lang="scss">
.header-container {
font-family: 'font_regular', sans-serif;
min-height: 62px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30px 0 10px;
position: relative;
&__left-area {
display: flex;
align-items: center;
&__logo-area {
width: 220px;
margin-right: 20px;
&__menu-button {
display: none;
}
&__close-button {
display: flex;
align-items: center;
cursor: pointer;
&__title {
margin-left: 13px;
font-size: 16px;
line-height: 23px;
color: #a9b5c1;
}
}
}
&__selection-wrapper {
display: flex;
}
}
&__right-area {
display: flex;
align-items: center;
&__info {
max-height: 24px;
margin-right: 17px;
&__icon {
cursor: pointer;
}
&__message {
color: #586c86;
font-family: 'font_regular', sans-serif;
font-size: 12px;
line-height: 21px;
}
}
&__satellite-area {
height: 36px;
background: #f6f6fa;
border-radius: 58px;
display: flex;
align-items: center;
padding: 0 10px 0 5px;
margin-right: 20px;
&__checkmark {
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
background: #fff;
border-radius: 11px;
}
&__name {
font-weight: 500;
font-size: 14px;
line-height: 18px;
color: #000;
}
}
}
}
.logo {
cursor: pointer;
}
.adapted-navigation {
position: absolute;
top: 62px;
left: 0;
z-index: 100;
height: 100vh;
background: #e6e9ef;
}
.navigation-blur {
height: 100vh;
width: 100%;
position: absolute;
top: 62px;
left: 220px;
z-index: 99;
background: rgb(134 134 148 / 40%);
}
.project-selection,
.resources-selection {
margin-right: 35px;
}
::v-deep .info__box {
top: 100%;
&__message {
min-width: 335px;
}
}
@media screen and (min-width: 1281px) {
.adapted-navigation,
.navigation-blur,
.header-container__left-area__logo-area__close-button {
display: none;
}
}
@media screen and (max-width: 1280px) {
.header-container {
padding: 0 40px;
&__left-area {
&__logo-area {
&__menu-button {
display: block;
cursor: pointer;
}
}
}
}
.logo {
display: none;
}
::v-deep .edit-project {
margin-left: 0;
}
}
@media screen and (max-width: 1024px) {
.header-container {
&__left-area {
&__logo-area {
width: 100px;
}
}
}
.project-selection,
.resources-selection {
margin-right: 15px;
}
}
@media screen and (max-width: 768px) {
.header-container {
&__left-area {
&__selection-wrapper {
display: none;
}
}
}
}
</style>

View File

@ -1,100 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="account-button">
<div
class="account-button__container"
@click.stop="toggleDropdown"
>
<div class="account-button__container__avatar">
<h1 class="account-button__container__avatar__letter">
{{ avatarLetter }}
</h1>
</div>
</div>
<AccountDropdown
v-if="isDropdownShown"
v-click-outside="closeDropdown"
/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import AccountDropdown from './AccountDropdown.vue';
// @vue/component
@Component({
components: {
AccountDropdown,
},
})
export default class AccountButton extends Vue {
/**
* Returns first letter of user`s name.
*/
public get avatarLetter(): string {
return this.$store.getters.userName.slice(0, 1).toUpperCase();
}
/**
* Indicates if account dropdown is shown.
*/
public get isDropdownShown(): string {
return this.$store.state.appStateModule.appState.isAccountDropdownShown;
}
/**
* Toggles account dropdown's visibility.
*/
public toggleDropdown(): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_ACCOUNT);
}
/**
* Closes account dropdown.
*/
public closeDropdown(): void {
if (!this.isDropdownShown) return;
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
}
</script>
<style scoped lang="scss">
.account-button {
background-color: #fff;
position: relative;
&__container {
display: flex;
align-items: center;
justify-content: flex-start;
width: max-content;
height: 50px;
&__avatar {
width: 40px;
height: 40px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
background: #2582ff;
cursor: pointer;
&__letter {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #fff;
}
}
}
}
</style>

View File

@ -1,128 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="account-dropdown">
<div class="account-dropdown__wrap">
<div class="account-dropdown__wrap__name-container">
<p class="account-dropdown__wrap__name-container__name">{{ userName }}</p>
</div>
<div class="account-dropdown__wrap__item-container" @click.stop="onLogoutClick">
<p class="account-dropdown__wrap__item-container__title">Sign Out</p>
<p class="account-dropdown__wrap__item-container__arrow">-></p>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { AuthHttpApi } from '@/api/auth';
import { RouteConfig } from '@/router';
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { USER_ACTIONS } from '@/store/modules/users';
import {
APP_STATE_ACTIONS,
NOTIFICATION_ACTIONS,
PM_ACTIONS,
} from '@/utils/constants/actionNames';
import { LocalData } from '@/utils/localData';
// @vue/component
@Component
export default class AccountDropdown extends Vue {
private readonly auth: AuthHttpApi = new AuthHttpApi();
/**
* Returns user's full name.
*/
public get userName(): string {
return this.$store.getters.userName;
}
/**
* Performs logout on backend than clears all user information from store and local storage.
*/
public async onLogoutClick(): Promise<void> {
await this.$router.push(RouteConfig.Login.path);
try {
await this.auth.logout();
} catch (error) {
await this.$notify.error(error.message);
return;
}
await this.$store.dispatch(PM_ACTIONS.CLEAR);
await this.$store.dispatch(PROJECTS_ACTIONS.CLEAR);
await this.$store.dispatch(USER_ACTIONS.CLEAR);
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.STOP_ACCESS_GRANTS_WEB_WORKER);
await this.$store.dispatch(NOTIFICATION_ACTIONS.CLEAR);
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR);
await this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
LocalData.removeUserId();
}
}
</script>
<style scoped lang="scss">
.account-dropdown {
position: absolute;
top: 65px;
right: 0;
padding: 6px 0;
background-color: #f5f6fa;
z-index: 1120;
box-shadow: 0 20px 34px 0 rgb(10 27 44 / 28%);
border-radius: 6px;
&__wrap {
font-family: 'font_regular', sans-serif;
min-width: 250px;
max-width: 250px;
background-color: #f5f6fa;
border-radius: 6px;
&__name-container {
width: calc(100% - 45px);
margin-left: 30px;
padding: 0 15px 15px 0;
&__name {
font-size: 14px;
line-height: 19px;
color: #1b2533;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 15px 0 0;
}
}
&__item-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 20px 20px 30px;
cursor: pointer;
&__title,
&__arrow {
font-size: 14px;
line-height: 19px;
color: #0068dc;
font-weight: 500;
margin: 0;
}
}
}
}
</style>

View File

@ -1,241 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="project-dropdown">
<div v-if="isLoading" class="project-dropdown__loader-container">
<VLoader
width="30px"
height="30px"
/>
</div>
<div v-else class="project-dropdown__wrap">
<div class="project-dropdown__wrap__choice" @click.prevent.stop="closeDropdown">
<div class="project-dropdown__wrap__choice__mark-container">
<SelectionIcon
class="project-dropdown__wrap__choice__mark-container__image"
/>
</div>
<p class="project-dropdown__wrap__choice__selected">
{{ selectedProject.name }}
</p>
</div>
<div
v-for="project in projects"
:key="project.id"
class="project-dropdown__wrap__choice"
@click.prevent.stop="onProjectSelected(project.id)"
>
<p class="project-dropdown__wrap__choice__unselected">{{ project.name }}</p>
</div>
</div>
<div class="project-dropdown__create-project" @click.stop="onProjectsLinkClick">
<div class="project-dropdown__create-project__border" />
<div class="project-dropdown__create-project__button-area">
<p class="project-dropdown__create-project__button-area__text">Manage Projects</p>
<p class="project-dropdown__create-project__button-area__arrow">-></p>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import VLoader from '@/components/common/VLoader.vue';
import SelectionIcon from '@/../static/images/header/selection.svg';
import { RouteConfig } from '@/router';
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
import { OBJECTS_ACTIONS } from '@/store/modules/objects';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { Project } from '@/types/projects';
import { PM_ACTIONS } from '@/utils/constants/actionNames';
import { LocalData } from '@/utils/localData';
// @vue/component
@Component({
components: {
SelectionIcon,
VLoader,
},
})
export default class ProjectDropdown extends Vue {
@Prop({ default: false })
public readonly isLoading: boolean;
private FIRST_PAGE = 1;
/**
* Fetches all project related information.
* @param projectID
*/
public async onProjectSelected(projectID: string): Promise<void> {
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, projectID);
LocalData.setSelectedProjectId(projectID);
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
this.closeDropdown();
if (this.isBucketsView) {
await this.$store.dispatch(OBJECTS_ACTIONS.CLEAR);
await this.$router.push({name: RouteConfig.Buckets.name}).catch(() => {return; });
}
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PM_ACTIONS.FETCH, this.FIRST_PAGE);
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, this.FIRST_PAGE);
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, this.FIRST_PAGE);
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
} catch (error) {
await this.$notify.error(`Unable to select project. ${error.message}`);
}
}
/**
* Returns projects list from store.
*/
public get projects(): Project[] {
return this.$store.getters.projectsWithoutSelected;
}
/**
* Returns selected project from store.
*/
public get selectedProject(): Project {
return this.$store.getters.selectedProject;
}
/**
* Closes dropdown.
*/
public closeDropdown(): void {
this.$emit('close');
}
/**
* Route to projects list page.
*/
public onProjectsLinkClick(): void {
if (this.$route.name !== RouteConfig.ProjectsList.name) {
this.$router.push(RouteConfig.ProjectsList.path);
}
this.$emit('close');
}
/**
* Indicates if current route is objects view.
*/
private get isBucketsView(): boolean {
return this.$route.path.includes(RouteConfig.Buckets.path);
}
}
</script>
<style scoped lang="scss">
::-webkit-scrollbar,
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
margin: 0;
width: 0;
}
.project-dropdown {
position: absolute;
z-index: 1120;
left: 0;
top: 50px;
box-shadow: 0 20px 34px rgb(10 27 44 / 28%);
border-radius: 6px;
background-color: #fff;
padding-top: 6px;
min-width: 300px;
&__loader-container {
margin: 10px 0;
display: flex;
align-items: center;
justify-content: center;
}
&__wrap {
overflow-y: scroll;
height: auto;
min-width: 300px;
max-height: 250px;
background-color: #fff;
border-radius: 6px;
font-family: 'font_regular', sans-serif;
&__choice {
width: auto;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 25px;
&__selected,
&__unselected {
margin: 12px 0;
font-size: 14px;
line-height: 20px;
color: #1b2533;
word-break: break-all;
}
&__selected {
font-family: 'font_bold', sans-serif;
}
&__unselected {
padding-left: 22px;
}
&:hover {
background-color: #f5f6fa;
.project-dropdown__wrap__choice__unselected {
font-family: 'font_bold', sans-serif;
color: #354049;
}
}
&__mark-container {
width: 10px;
margin-right: 12px;
&__image {
object-fit: cover;
}
}
}
}
&__create-project {
&__border {
border-top: 1px solid #c7cdd2;
width: 90%;
float: right;
}
&__button-area {
display: flex;
justify-content: space-between;
align-items: center;
width: calc(100% - 50px);
padding: 15px 25px;
&__text,
&__arrow {
color: #0068dc;
font-size: 14px;
}
}
}
}
</style>

View File

@ -1,203 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="project-selection" :class="{ disabled: isOnboardingTour, active: isDropdownShown, navigation: inNavigation }">
<div
class="project-selection__toggle-container"
@click.stop="toggleSelection"
>
<p class="project-selection__toggle-container__name" :class="{ 'white': isDropdownShown, 'name-navigation': inNavigation }">Projects</p>
<ExpandIcon
class="project-selection__toggle-container__expand-icon"
:class="{ expanded: isDropdownShown }"
alt="Arrow down (expand)"
/>
<ProjectDropdown
v-show="isDropdownShown"
v-click-outside="closeDropdown"
:is-loading="isLoading"
in-navigation="true"
@close="closeDropdown"
/>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import ExpandIcon from '@/../static/images/common/BlackArrowExpand.svg';
import { RouteConfig } from '@/router';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import ProjectDropdown from './ProjectDropdown.vue';
// @vue/component
@Component({
components: {
ProjectDropdown,
ExpandIcon,
},
})
export default class ProjectSelection extends Vue {
@Prop({default: false})
protected readonly inNavigation: boolean;
private isLoading = false;
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
/**
* Indicates select project dropdown shown.
*/
public get isDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isSelectProjectDropdownShown;
}
/**
* Fetches projects related information and than toggles selection popup.
*/
public async toggleSelection(): Promise<void> {
if (this.isOnboardingTour) return;
this.toggleDropdown();
if (this.isLoading || !this.isDropdownShown) return;
this.isLoading = true;
try {
await this.$store.dispatch(PROJECTS_ACTIONS.FETCH);
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
} catch (error) {
await this.$notify.error(error.message);
}
this.isLoading = false;
}
/**
* Toggles project dropdown visibility.
*/
public toggleDropdown(): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SELECT_PROJECT_DROPDOWN);
}
/**
* Closes select project dropdown.
*/
public closeDropdown(): void {
if (!this.isDropdownShown) return;
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
}
</script>
<style scoped lang="scss">
.expanded {
.black-arrow-expand-path {
fill: #fff !important;
}
}
.project-selection {
background-color: #fff;
cursor: pointer;
margin-right: 20px;
min-width: 130px;
border-radius: 6px;
&__toggle-container {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
width: calc(100% - 32px);
height: 36px;
&__name {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #354049;
transition: opacity 0.2s ease-in-out;
word-break: unset;
margin: 0;
}
&__name.name-navigation {
color: #1b2533;
white-space: nowrap;
}
&__expand-icon {
margin-left: 15px;
}
}
&:hover {
background-color: #f5f6fa;
.project-selection__toggle-container__name {
font-family: 'font_bold', sans-serif;
color: #0068dc;
}
.black-arrow-expand-path {
fill: #0068dc;
}
}
}
.disabled {
opacity: 0.5;
pointer-events: none;
cursor: default;
}
.active {
background: #2582ff !important;
}
.white {
font-family: 'font_bold', sans-serif;
color: #fff !important;
}
.navigation {
background: none;
flex: 0 0 auto;
padding: 10px;
width: calc(100% - 20px);
margin-bottom: 15px;
text-decoration: none;
&:hover {
background-color: #0068dc;
.project-selection__toggle-container__name {
color: #fff;
}
.black-arrow-expand-path {
fill: #fff;
}
}
}
.navigation.active {
background: #0068dc !important;
}
</style>

View File

@ -1,121 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="resources-dropdown">
<a
class="resources-dropdown__item-container"
href="https://docs.storj.io/"
target="_blank"
rel="noopener noreferrer"
>
<DocsIcon class="resources-dropdown__item-container__image" />
<p class="resources-dropdown__item-container__title">Docs</p>
</a>
<a
class="resources-dropdown__item-container"
href="https://forum.storj.io/"
target="_blank"
rel="noopener noreferrer"
>
<CommunityIcon class="resources-dropdown__item-container__image" />
<p class="resources-dropdown__item-container__title">Community</p>
</a>
<a
class="resources-dropdown__item-container"
href="https://supportdcs.storj.io/hc/en-us"
target="_blank"
rel="noopener noreferrer"
>
<SupportIcon class="resources-dropdown__item-container__image" />
<p class="resources-dropdown__item-container__title">Support</p>
</a>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import CommunityIcon from '@/../static/images/header/community.svg';
import DocsIcon from '@/../static/images/header/docs.svg';
import SupportIcon from '@/../static/images/header/support.svg';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
// @vue/component
@Component({
components: {
DocsIcon,
CommunityIcon,
SupportIcon,
},
})
export default class ResourcesDropdown extends Vue {
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
public onDocsIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, 'https://docs.storj.io/node');
}
public onCommunityIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, 'https://storj.io/community/');
}
public onSupportIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, 'mailto:support@storj.io');
}
}
</script>
<style scoped lang="scss">
.resources-dropdown {
position: absolute;
top: 50px;
left: 0;
padding: 6px 0;
background-color: #f5f6fa;
z-index: 1120;
font-family: 'font_regular', sans-serif;
min-width: 255px;
box-shadow: 0 20px 34px rgb(10 27 44 / 28%);
border-radius: 6px;
&__item-container {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 20px;
&__image {
min-width: 20px;
object-fit: cover;
}
&__title {
margin: 8px 0 14px 13px;
font-size: 14px;
line-height: 20px;
color: #1b2533;
}
&:hover {
font-family: 'font_bold', sans-serif;
.docs-svg-path,
.community-svg-path,
.support-svg-path {
fill: #2d75d2 !important;
}
}
}
}
</style>

View File

@ -1,182 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="resources-selection" :class="{ disabled: isOnboardingTour, active: isDropdownShown, navigation: inNavigation }">
<div
class="resources-selection__toggle-container"
@click.stop="toggleDropdown"
>
<p class="resources-selection__toggle-container__name" :class="{ 'white': isDropdownShown, 'name-navigation': inNavigation }">Resources</p>
<ExpandIcon
class="resources-selection__toggle-container__expand-icon"
:class="{ expanded: isDropdownShown }"
alt="Arrow down (expand)"
/>
<ResourcesDropdown
v-show="isDropdownShown"
v-click-outside="closeDropdown"
in-navigation="true"
@close="closeDropdown"
/>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import ExpandIcon from '@/../static/images/common/BlackArrowExpand.svg';
import { RouteConfig } from '@/router';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import ResourcesDropdown from './ResourcesDropdown.vue';
// @vue/component
@Component({
components: {
ResourcesDropdown,
ExpandIcon,
},
})
export default class ResourcesSelection extends Vue {
@Prop({default: false})
protected readonly inNavigation: boolean;
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
/**
* Indicates if resources dropdown shown.
*/
public get isDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isResourcesDropdownShown;
}
/**
* Toggles resources dropdown visibility.
*/
public toggleDropdown(): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_RESOURCES_DROPDOWN);
}
/**
* Closes resources dropdown.
*/
public closeDropdown(): void {
if (!this.isDropdownShown) return;
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
}
</script>
<style scoped lang="scss">
.expanded {
.black-arrow-expand-path {
fill: #fff !important;
}
}
.resources-selection {
background-color: #fff;
cursor: pointer;
margin-right: 20px;
border-radius: 6px;
min-width: 140px;
&__toggle-container {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 0 16px;
width: calc(100% - 32px);
height: 36px;
&__name {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #354049;
transition: opacity 0.2s ease-in-out;
word-break: unset;
margin: 0;
}
&__name.name-navigation {
color: #1b2533;
white-space: nowrap;
}
&__expand-icon {
margin-left: 15px;
}
}
&:hover {
background-color: #f5f6fa;
.resources-selection__toggle-container__name {
font-family: 'font_bold', sans-serif;
color: #0068dc;
}
.black-arrow-expand-path {
fill: #0068dc;
}
}
}
.disabled {
opacity: 0.5;
pointer-events: none;
cursor: default;
}
.active {
background: #2582ff !important;
}
.white {
font-family: 'font_bold', sans-serif;
color: #fff !important;
}
.navigation {
background: none;
flex: 0 0 auto;
padding: 10px;
width: calc(100% - 20px);
margin-bottom: 15px;
text-decoration: none;
&:hover {
background-color: #0068dc;
.resources-selection__toggle-container__name {
color: #fff;
}
.black-arrow-expand-path {
fill: #fff;
}
}
.active {
background: #0068dc !important;
}
}
.navigation.active {
background: #0068dc !important;
}
</style>

View File

@ -1,151 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="settings-dropdown">
<div class="settings-dropdown__choice" @click.prevent.stop="onAccountSettingsClick">
<div class="settings-dropdown__choice__mark-container">
<SettingsIcon
class="settings-dropdown__choice__mark-container__image"
:class="{ 'image-active': isAccountSettingsPage }"
/>
</div>
<p class="settings-dropdown__choice__label" :class="{ active: isAccountSettingsPage }">
Account Settings
</p>
</div>
<div class="settings-dropdown__choice" @click.prevent.stop="onBillingClick">
<div class="settings-dropdown__choice__mark-container">
<BillingIcon
class="settings-dropdown__choice__mark-container__image"
:class="{ 'image-active': isBillingPage }"
/>
</div>
<p class="settings-dropdown__choice__label" :class="{ active: isBillingPage }">
Billing
</p>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import BillingIcon from '@/../static/images/header/billing.svg';
import SettingsIcon from '@/../static/images/header/settings.svg';
import { RouteConfig } from '@/router';
// @vue/component
@Component({
components: {
BillingIcon,
SettingsIcon,
},
})
export default class SettingsDropdown extends Vue {
/**
* Indicates if current route is account settings page.
*/
public get isAccountSettingsPage(): boolean {
return this.$route.name === RouteConfig.Settings.name;
}
/**
* Indicates if current route is billing page.
*/
public get isBillingPage(): boolean {
return this.$route.name === RouteConfig.Billing.name;
}
/**
* Redirects to account settings page.
*/
public onAccountSettingsClick(): void {
if (this.$route.name !== RouteConfig.Settings.name) {
this.$router.push(RouteConfig.Account.with(RouteConfig.Settings).path);
}
this.closeDropdown();
}
/**
* Redirects to billing page.
*/
public onBillingClick(): void {
if (this.$route.name !== RouteConfig.Billing.name) {
this.$router.push(RouteConfig.Account.with(RouteConfig.Billing).path);
}
this.closeDropdown();
}
/**
* Closes dropdown.
*/
private closeDropdown(): void {
this.$emit('close');
}
}
</script>
<style scoped lang="scss">
.image-active {
.settings-svg-path,
.billing-svg-path {
fill: #0068dc;
}
}
.settings-dropdown {
position: absolute;
left: 0;
top: 50px;
z-index: 1120;
box-shadow: 0 20px 34px rgb(10 27 44 / 28%);
border-radius: 6px;
background-color: #f5f6fa;
padding: 6px 0;
&__choice {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 25px;
min-width: 205px;
background-color: #f5f6fa;
border-radius: 6px;
font-family: 'font_regular', sans-serif;
&__label {
margin: 8px 0 14px 10px;
font-size: 14px;
line-height: 20px;
color: #1b2533;
}
&:hover {
font-family: 'font_bold', sans-serif;
.settings-svg-path,
.billing-svg-path {
fill: #0068dc;
}
}
&__mark-container {
width: 10px;
margin-right: 12px;
&__image {
object-fit: cover;
}
}
}
}
.active {
font-family: 'font_bold', sans-serif;
}
</style>

View File

@ -1,180 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="settings-selection" :class="{ disabled: isOnboardingTour, active: isDropdownShown, navigation: inNavigation }">
<div
class="settings-selection__toggle-container"
@click.stop="toggleDropdown"
>
<p class="settings-selection__toggle-container__name" :class="{ 'white': isDropdownShown, 'name-navigation': inNavigation }">Settings</p>
<ExpandIcon
class="settings-selection__toggle-container__expand-icon"
:class="{ expanded: isDropdownShown }"
alt="Arrow down (expand)"
/>
<SettingsDropdown
v-show="isDropdownShown"
v-click-outside="closeDropdown"
in-navigation="true"
@close="closeDropdown"
/>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import ExpandIcon from '@/../static/images/common/BlackArrowExpand.svg';
import { RouteConfig } from '@/router';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import SettingsDropdown from './SettingsDropdown.vue';
// @vue/component
@Component({
components: {
SettingsDropdown,
ExpandIcon,
},
})
export default class SettingsSelection extends Vue {
@Prop({default: false})
protected readonly inNavigation: boolean;
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
/**
* Indicates if settings dropdown shown.
*/
public get isDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isSettingsDropdownShown;
}
/**
* Toggles project dropdown visibility.
*/
public toggleDropdown(): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SETTINGS_DROPDOWN);
}
/**
* Closes project dropdown.
*/
public closeDropdown(): void {
if (!this.isDropdownShown) return;
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
}
</script>
<style scoped lang="scss">
.expanded {
.black-arrow-expand-path {
fill: #fff !important;
}
}
.settings-selection {
background-color: #fff;
cursor: pointer;
margin-right: 20px;
min-width: 130px;
border-radius: 6px;
&__toggle-container {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
width: calc(100% - 32px);
height: 36px;
&__name {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #354049;
transition: opacity 0.2s ease-in-out;
word-break: unset;
margin: 0;
}
&__name.name-navigation {
color: #1b2533;
white-space: nowrap;
}
&__expand-icon {
margin-left: 15px;
}
}
&:hover {
background-color: #f5f6fa;
.settings-selection__toggle-container__name {
font-family: 'font_bold', sans-serif;
color: #0068dc;
}
.black-arrow-expand-path {
fill: #0068dc;
}
}
}
.disabled {
opacity: 0.5;
pointer-events: none;
cursor: default;
}
.active {
background: #2582ff !important;
}
.white {
font-family: 'font_bold', sans-serif;
color: #fff !important;
}
.navigation {
background: none;
flex: 0 0 auto;
padding: 10px;
width: calc(100% - 20px);
text-decoration: none;
&:hover {
background-color: #0068dc;
.settings-selection__toggle-container__name {
color: #fff;
}
.black-arrow-expand-path {
fill: #fff;
}
}
.active {
background: #0068dc !important;
}
}
.navigation.active {
background: #0068dc !important;
}
</style>

View File

@ -1,169 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="edit-project">
<div class="edit-project__selection-area" :class="{ active: isDropdownShown, 'on-edit': isEditPage }" @click.stop.prevent="toggleDropdown">
<p class="edit-project__selection-area__name" :title="projectName">{{ projectName }}</p>
<DotsImage class="edit-project__selection-area__image" />
</div>
<div v-if="isDropdownShown" v-click-outside="closeDropdown" class="edit-project__dropdown">
<div class="edit-project__dropdown__choice" @click.stop.prevent="onEditProjectClick">
<EditImage />
<p class="edit-project__dropdown__choice__label">Edit Details</p>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import DotsImage from '@/../static/images/navigation/dots.svg';
import EditImage from '@/../static/images/navigation/edit.svg';
import { RouteConfig } from '@/router';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
// @vue/component
@Component({
components: {
DotsImage,
EditImage,
},
})
export default class EditProjectDropdown extends Vue {
/**
* Returns selected project's name.
*/
public get projectName(): string {
return this.$store.getters.selectedProject.name;
}
/**
* Indicates if dropdown is shown.
*/
public get isDropdownShown(): string {
return this.$store.state.appStateModule.appState.isEditProjectDropdownShown;
}
/**
* Indicates if current route name equals "edit project details" route name.
*/
public get isEditPage(): boolean {
return this.$route.name === RouteConfig.EditProjectDetails.name;
}
/**
* Redirects to edit project details page.
*/
public onEditProjectClick(): void {
this.closeDropdown();
this.$router.push(RouteConfig.EditProjectDetails.path);
}
/**
* Toggles dropdown visibility.
*/
public toggleDropdown(): void {
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_EDIT_PROJECT_DROPDOWN);
}
/**
* Closes dropdown.
*/
public closeDropdown(): void {
if (!this.isDropdownShown) return;
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
}
</script>
<style scoped lang="scss">
.edit-project {
font-family: 'font_regular', sans-serif;
position: relative;
width: 185px;
margin: 0 0 30px 15px;
&__selection-area {
width: calc(100% - 15px);
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
border-radius: 6px;
cursor: pointer;
&__name {
font-family: 'font_medium', sans-serif;
font-size: 18px;
line-height: 22px;
color: #000;
margin: 0 5px 0 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__image {
min-width: 3px;
}
}
&__dropdown {
position: absolute;
top: calc(100% + 5px);
left: 0;
background-color: #fff;
box-shadow: 0 8px 34px rgb(161 173 185 / 41%);
border-radius: 6px;
padding: 5px 0;
width: calc(100% + 5px);
z-index: 1;
&__choice {
background-color: #fff;
width: calc(100% - 32px);
padding: 10px 16px;
cursor: pointer;
display: flex;
align-items: center;
&__label {
margin: 0 0 0 10px;
font-weight: 500;
font-size: 14px;
line-height: 19px;
color: #354049;
}
&:hover {
background-color: #f5f5f7;
.edit-project__dropdown__choice__label {
font-weight: unset;
font-family: 'font_bold', sans-serif;
}
}
}
}
}
.active {
background-color: #fff;
}
.on-edit {
background-color: #0068dc;
.edit-project__selection-area__name {
color: #fff;
}
.edit-dots-svg-path {
fill: #fff;
}
}
</style>

View File

@ -1,26 +1,144 @@
// Copyright (C) 2019 Storj Labs, Inc.
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div v-if="!isNavigationHidden" class="navigation-area">
<EditProjectDropdown />
<router-link
v-for="navItem in navigation"
:key="navItem.name"
:aria-label="navItem.name"
class="navigation-area__item-container"
:to="navItem.path"
@click.native="trackClickEvent(navItem.name)"
>
<div class="navigation-area__item-container__link">
<component :is="navItem.icon" class="navigation-area__item-container__link__icon" />
<p class="navigation-area__item-container__link__title">{{ navItem.name }}</p>
<div class="navigation-area">
<div ref="navigationContainer" class="navigation-area__container">
<div class="navigation-area__container__wrap">
<LogoIcon class="navigation-area__container__wrap__logo" @click.stop="onLogoClick" />
<SmallLogoIcon class="navigation-area__container__wrap__small-logo" @click.stop="onLogoClick" />
<div class="navigation-area__container__wrap__edit">
<ProjectSelection />
</div>
<div class="navigation-area__container__wrap__border" />
<router-link
v-for="navItem in navigation"
:key="navItem.name"
:aria-label="navItem.name"
class="navigation-area__container__wrap__item-container"
:to="navItem.path"
@click.native="trackClickEvent(navItem.name)"
>
<div class="navigation-area__container__wrap__item-container__left">
<component :is="navItem.icon" class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">{{ navItem.name }}</p>
</div>
</router-link>
<div class="navigation-area__container__wrap__border" />
<div ref="resourcesContainer" class="container-wrapper">
<div
class="navigation-area__container__wrap__item-container"
:class="{ active: isResourcesDropdownShown }"
@click.stop="toggleResourcesDropdown"
>
<div class="navigation-area__container__wrap__item-container__left">
<ResourcesIcon class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">Resources</p>
</div>
<ArrowIcon class="navigation-area__container__wrap__item-container__arrow" />
</div>
<GuidesDropdown
v-if="isResourcesDropdownShown"
:close="closeDropdowns"
:y-position="resourcesDropdownYPos"
:x-position="resourcesDropdownXPos"
>
<a
class="dropdown-item"
href="https://docs.storj.io/"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewDocsEvent('https://docs.storj.io/')"
>
<DocsIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Docs</h2>
<p class="dropdown-item__text__label">Documentation for Storj</p>
</div>
</a>
<div class="dropdown-border" />
<a
class="dropdown-item"
href="https://forum.storj.io/"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewForumEvent('https://forum.storj.io/')"
>
<ForumIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Forum</h2>
<p class="dropdown-item__text__label">Join our global community</p>
</div>
</a>
<div class="dropdown-border" />
<a
class="dropdown-item"
href="https://supportdcs.storj.io/hc/en-us"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewSupportEvent('https://supportdcs.storj.io/hc/en-us')"
>
<SupportIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Support</h2>
<p class="dropdown-item__text__label">Get technical support</p>
</div>
</a>
</GuidesDropdown>
</div>
<div ref="quickStartContainer" class="container-wrapper">
<div
class="navigation-area__container__wrap__item-container"
:class="{ active: isQuickStartDropdownShown }"
@click.stop="toggleQuickStartDropdown"
>
<div class="navigation-area__container__wrap__item-container__left">
<QuickStartIcon class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">Quick Start</p>
</div>
<ArrowIcon class="navigation-area__container__wrap__item-container__arrow" />
</div>
<GuidesDropdown
v-if="isQuickStartDropdownShown"
:close="closeDropdowns"
:y-position="quickStartDropdownYPos"
:x-position="quickStartDropdownXPos"
>
<div class="dropdown-item" aria-roledescription="create-project-route" @click.stop="navigateToNewProject">
<NewProjectIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">New Project</h2>
<p class="dropdown-item__text__label">Create a new project.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="create-ag-route" @click.stop="navigateToCreateAG">
<CreateAGIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Create an Access Grant</h2>
<p class="dropdown-item__text__label">Start the wizard to create a new access grant.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="objects-route" @click.stop="navigateToBuckets">
<UploadInWebIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Upload in Web</h2>
<p class="dropdown-item__text__label">Start uploading files in the web browser.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="cli-flow-route" @click.stop="navigateToCLIFlow">
<UploadInCLIIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Upload using CLI</h2>
<p class="dropdown-item__text__label">Start guide for using the Uplink CLI.</p>
</div>
</div>
</GuidesDropdown>
</div>
</div>
</router-link>
<div class="navigation-area__selection-wrapper">
<ProjectSelection in-navigation="true" class="project-selection" />
<ResourcesSelection in-navigation="true" class="resources-selection" />
<SettingsSelection in-navigation="true" class="settings-selection" />
<AccountArea />
</div>
</div>
</template>
@ -28,70 +146,239 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import EditProjectDropdown from '@/components/navigation/EditProjectDropdown.vue';
import AccessGrantsIcon from '@/../static/images/navigation/apiKeys.svg';
import DashboardIcon from '@/../static/images/navigation/dashboard.svg';
import BucketsIcon from '@/../static/images/navigation/objects.svg';
import ProjectSelection from '@/components/header/projectsDropdown/ProjectSelection.vue';
import ResourcesSelection from '@/components/header/resourcesDropdown/ResourcesSelection.vue';
import SettingsSelection from '@/components/header/settingsDropdown/SettingsSelection.vue';
import TeamIcon from '@/../static/images/navigation/team.svg';
import ProjectSelection from '@/components/navigation/ProjectSelection.vue';
import GuidesDropdown from '@/components/navigation/GuidesDropdown.vue';
import AccountArea from '@/components/navigation/AccountArea.vue';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { NavigationLink } from '@/types/navigation';
import { MetaUtils } from '@/utils/meta';
import { APP_STATE_ACTIONS } from "@/utils/constants/actionNames";
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import LogoIcon from '@/../static/images/logo.svg';
import SmallLogoIcon from '@/../static/images/smallLogo.svg';
import AccessGrantsIcon from '@/../static/images/navigation/accessGrants.svg';
import DashboardIcon from '@/../static/images/navigation/projectDashboard.svg';
import BucketsIcon from '@/../static/images/navigation/buckets.svg';
import UsersIcon from '@/../static/images/navigation/users.svg';
import BillingIcon from '@/../static/images/navigation/billing.svg';
import ResourcesIcon from '@/../static/images/navigation/resources.svg';
import QuickStartIcon from '@/../static/images/navigation/quickStart.svg';
import ArrowIcon from '@/../static/images/navigation/arrowExpandRight.svg';
import DocsIcon from '@/../static/images/navigation/docs.svg';
import ForumIcon from '@/../static/images/navigation/forum.svg';
import SupportIcon from '@/../static/images/navigation/support.svg';
import NewProjectIcon from '@/../static/images/navigation/newProject.svg';
import CreateAGIcon from '@/../static/images/navigation/createAccessGrant.svg';
import UploadInCLIIcon from '@/../static/images/navigation/uploadInCLI.svg';
import UploadInWebIcon from '@/../static/images/navigation/uploadInWeb.svg';
// @vue/component
@Component({
components: {
ProjectSelection,
GuidesDropdown,
AccountArea,
LogoIcon,
SmallLogoIcon,
DashboardIcon,
AccessGrantsIcon,
TeamIcon,
EditProjectDropdown,
UsersIcon,
BillingIcon,
BucketsIcon,
ProjectSelection,
ResourcesSelection,
SettingsSelection
ResourcesIcon,
QuickStartIcon,
ArrowIcon,
DocsIcon,
ForumIcon,
SupportIcon,
NewProjectIcon,
CreateAGIcon,
UploadInCLIIcon,
UploadInWebIcon,
},
})
export default class NavigationArea extends Vue {
public navigation: NavigationLink[] = [];
private readonly TWENTY_PIXELS = 20;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public resourcesDropdownYPos = 0;
public resourcesDropdownXPos = 0;
public quickStartDropdownYPos = 0;
public quickStartDropdownXPos = 0;
public navigation: NavigationLink[] = [
RouteConfig.ProjectDashboard.withIcon(DashboardIcon),
RouteConfig.Buckets.withIcon(BucketsIcon),
RouteConfig.AccessGrants.withIcon(AccessGrantsIcon),
RouteConfig.Users.withIcon(UsersIcon),
RouteConfig.Account.with(RouteConfig.Billing).withIcon(BillingIcon),
];
public $refs!: {
resourcesContainer: HTMLDivElement;
quickStartContainer: HTMLDivElement;
navigationContainer: HTMLDivElement;
};
/**
* Lifecycle hook before initial render.
* Sets navigation side bar list.
* Mounted hook after initial render.
* Adds scroll event listener to close dropdowns.
*/
public beforeMount(): void {
const value = MetaUtils.getMetaContent('file-browser-flow-disabled');
if (value === "true") {
this.navigation = [
RouteConfig.ProjectDashboard.withIcon(DashboardIcon),
RouteConfig.AccessGrants.withIcon(AccessGrantsIcon),
RouteConfig.Users.withIcon(TeamIcon),
];
return;
}
this.navigation = [
RouteConfig.ProjectDashboard.withIcon(DashboardIcon),
RouteConfig.Buckets.withIcon(BucketsIcon),
RouteConfig.AccessGrants.withIcon(AccessGrantsIcon),
RouteConfig.Users.withIcon(TeamIcon),
];
public mounted(): void {
this.$refs.navigationContainer.addEventListener('scroll', this.closeDropdowns)
window.addEventListener('resize', this.closeDropdowns)
}
/**
* Indicates if navigation side bar is hidden.
* Mounted hook before component destroy.
* Removes scroll event listener.
*/
public get isNavigationHidden(): boolean {
return this.isOnboardingTour || this.isCreateProjectPage;
public beforeDestroy(): void {
this.$refs.navigationContainer.removeEventListener('scroll', this.closeDropdowns)
window.removeEventListener('resize', this.closeDropdowns)
}
/**
* Redirects to create project screen.
*/
public navigateToCreateAG(): void {
this.analytics.eventTriggered(AnalyticsEvent.CREATE_AN_ACCESS_GRANT_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant).path).catch(() => {return;});
}
/**
* Redirects to objects screen.
*/
public navigateToBuckets(): void {
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_IN_WEB_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.Buckets.path).catch(() => {return;});
}
/**
* Redirects to onboarding CLI flow screen.
*/
public navigateToCLIFlow(): void {
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_USING_CLI_CLICKED);
this.closeDropdowns();
this.$store.commit(APP_STATE_MUTATIONS.SET_ONB_AG_NAME_STEP_BACK_ROUTE, this.$route.path);
this.$router.push({name: RouteConfig.AGName.name});
}
/**
* Redirects to create access grant screen.
*/
public navigateToNewProject(): void {
this.analytics.eventTriggered(AnalyticsEvent.NEW_PROJECT_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.CreateProject.path);
}
/**
* Reloads page.
*/
public onLogoClick(): void {
location.reload();
}
/**
* Sets resources dropdown Y position depending on container's current position.
* It is used to handle small screens.
*/
public setResourcesDropdownYPos(): void {
const container = this.$refs.resourcesContainer.getBoundingClientRect();
this.resourcesDropdownYPos = container.top + container.height / 2;
}
/**
* Sets resources dropdown X position depending on container's current position.
* It is used to handle small screens.
*/
public setResourcesDropdownXPos(): void {
this.resourcesDropdownXPos = this.$refs.resourcesContainer.getBoundingClientRect().width - this.TWENTY_PIXELS;
}
/**
* Sets quick start dropdown Y position depending on container's current position.
* It is used to handle small screens.
*/
public setQuickStartDropdownYPos(): void {
const container = this.$refs.quickStartContainer.getBoundingClientRect();
this.quickStartDropdownYPos = container.top + container.height / 2;
}
/**
* Sets quick start dropdown X position depending on container's current position.
* It is used to handle small screens.
*/
public setQuickStartDropdownXPos(): void {
this.quickStartDropdownXPos = this.$refs.quickStartContainer.getBoundingClientRect().width - this.TWENTY_PIXELS;
}
/**
* Toggles resources dropdown visibility.
*/
public toggleResourcesDropdown(): void {
this.setResourcesDropdownYPos()
this.setResourcesDropdownXPos()
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_RESOURCES_DROPDOWN);
}
/**
* Toggles quick start dropdown visibility.
*/
public toggleQuickStartDropdown(): void {
this.setQuickStartDropdownYPos()
this.setQuickStartDropdownXPos()
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_QUICK_START_DROPDOWN);
}
/**
* Closes dropdowns.
*/
public closeDropdowns(): void {
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
/**
* Indicates if resources dropdown shown.
*/
public get isResourcesDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isResourcesDropdownShown;
}
/**
* Indicates if quick start dropdown shown.
*/
public get isQuickStartDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isQuickStartDropdownShown;
}
/**
* Sends "View Docs" event to segment and opens link.
*/
public trackViewDocsEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_DOCS_CLICKED);
window.open(link)
}
/**
* Sends "View Forum" event to segment and opens link.
*/
public trackViewForumEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_FORUM_CLICKED);
window.open(link)
}
/**
* Sends "View Support" event to segment and opens link.
*/
public trackViewSupportEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_SUPPORT_CLICKED);
window.open(link)
}
/**
@ -100,21 +387,6 @@ export default class NavigationArea extends Vue {
public trackClickEvent(name: string): void {
this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, name);
}
/**
* Indicates if current route is create project page.
*/
private get isCreateProjectPage(): boolean {
return this.$route.name === RouteConfig.CreateProject.name;
}
/**
* Indicates if current route is onboarding tour.
* Overviewstep needs navigation.
*/
private get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
}
</script>
@ -123,87 +395,173 @@ export default class NavigationArea extends Vue {
fill: rgb(53 64 73);
}
.container-wrapper {
width: 100%;
}
.navigation-area {
padding: 25px;
min-width: 170px;
max-width: 170px;
background: #e6e9ef;
display: flex;
flex-direction: column;
align-items: center;
min-width: 280px;
max-width: 280px;
background-color: #fff;
font-family: 'font_regular', sans-serif;
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
&__item-container {
flex: 0 0 auto;
padding: 10px;
width: calc(100% - 20px);
&__container {
display: flex;
justify-content: flex-start;
flex-direction: column;
align-items: center;
margin-bottom: 40px;
text-decoration: none;
justify-content: space-between;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
&__link {
&__wrap {
display: flex;
justify-content: flex-start;
flex-direction: column;
align-items: center;
width: 100%;
padding-top: 40px;
&__icon {
min-width: 24px;
&__logo {
cursor: pointer;
min-height: 37px;
}
&__title {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #1b2533;
margin: 0 0 0 18px;
white-space: nowrap;
}
}
&.router-link-active,
&:hover {
font-family: 'font_bold', sans-serif;
background: #0068dc;
border-radius: 6px;
.navigation-area__item-container__link__title {
color: #fff;
&__small-logo {
display: none;
}
.svg .navigation-svg-path:not(.white) {
fill: #fff !important;
opacity: 1;
&__edit {
margin-top: 40px;
width: 100%;
}
}
}
&__selection-wrapper {
display: none;
&__item-container {
padding: 22px 32px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
border-left: 4px solid #fff;
color: #56606d;
font-weight: 500;
position: static;
cursor: pointer;
box-sizing: border-box;
.project-selection {
&__left {
display: flex;
align-items: center;
&__toggle-container {
background: none;
&__name {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 23px;
color: #1b2533;
margin: 0 0 0 18px;
white-space: nowrap;
&__label {
font-size: 14px;
line-height: 20px;
margin-left: 24px;
}
}
}
&__border {
margin: 8px 24px;
height: 1px;
width: calc(100% - 48px);
background: #ebeef1;
}
}
}
}
@media screen and (max-width: 768px) {
.active {
font-weight: 600;
border-color: #0149ff;
background-color: #f7f8fb;
color: #0149ff;
.navigation-area {
.navigation-area__container__wrap__item-container {
&__selection-wrapper {
&__left__image path,
&__arrow path {
fill: #0149ff;
}
}
}
.router-link-active,
.navigation-area__container__wrap__item-container:hover {
font-weight: 600;
border-color: #0149ff;
background-color: #f7f8fb;
color: #0149ff;
.navigation-area__container__wrap__item-container__left__image path {
fill: #0149ff;
}
}
.dropdown-item {
display: flex;
align-items: center;
font-family: 'font_regular', sans-serif;
padding: 10px 24px;
cursor: pointer;
&__icon {
margin-left: 15px;
max-width: 37px;
min-width: 37px;
}
&__text {
margin-left: 24px;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 14px;
line-height: 22px;
color: #091c45;
}
&__label {
font-size: 12px;
line-height: 21px;
color: #091c45;
}
}
}
.dropdown-border {
height: 1px;
width: calc(100% - 48px);
margin: 0 24px;
background-color: #091c45;
opacity: 0.1;
}
@media screen and (max-width: 1280px) {
.navigation-area {
min-width: unset;
max-width: unset;
&__container__wrap {
&__logo {
display: none;
}
&__item-container {
justify-content: center;
&__left__label,
&__arrow {
display: none;
}
}
&__small-logo {
cursor: pointer;
min-height: 40px;
display: block;
}
}

View File

@ -85,7 +85,7 @@ import CreateProjectIcon from '@/../static/images/navigation/createProject.svg';
VLoader,
},
})
export default class NewProjectSelection extends Vue {
export default class ProjectSelection extends Vue {
private FIRST_PAGE = 1;
private dropdownYPos = 0;
private dropdownXPos = 0;

View File

@ -1,570 +0,0 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="navigation-area">
<div ref="navigationContainer" class="navigation-area__container">
<div class="navigation-area__container__wrap">
<LogoIcon class="navigation-area__container__wrap__logo" @click.stop="onLogoClick" />
<SmallLogoIcon class="navigation-area__container__wrap__small-logo" @click.stop="onLogoClick" />
<div class="navigation-area__container__wrap__edit">
<NewProjectSelection />
</div>
<div class="navigation-area__container__wrap__border" />
<router-link
v-for="navItem in navigation"
:key="navItem.name"
:aria-label="navItem.name"
class="navigation-area__container__wrap__item-container"
:to="navItem.path"
@click.native="trackClickEvent(navItem.name)"
>
<div class="navigation-area__container__wrap__item-container__left">
<component :is="navItem.icon" class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">{{ navItem.name }}</p>
</div>
</router-link>
<div class="navigation-area__container__wrap__border" />
<div ref="resourcesContainer" class="container-wrapper">
<div
class="navigation-area__container__wrap__item-container"
:class="{ active: isResourcesDropdownShown }"
@click.stop="toggleResourcesDropdown"
>
<div class="navigation-area__container__wrap__item-container__left">
<ResourcesIcon class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">Resources</p>
</div>
<ArrowIcon class="navigation-area__container__wrap__item-container__arrow" />
</div>
<GuidesDropdown
v-if="isResourcesDropdownShown"
:close="closeDropdowns"
:y-position="resourcesDropdownYPos"
:x-position="resourcesDropdownXPos"
>
<a
class="dropdown-item"
href="https://docs.storj.io/"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewDocsEvent('https://docs.storj.io/')"
>
<DocsIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Docs</h2>
<p class="dropdown-item__text__label">Documentation for Storj</p>
</div>
</a>
<div class="dropdown-border" />
<a
class="dropdown-item"
href="https://forum.storj.io/"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewForumEvent('https://forum.storj.io/')"
>
<ForumIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Forum</h2>
<p class="dropdown-item__text__label">Join our global community</p>
</div>
</a>
<div class="dropdown-border" />
<a
class="dropdown-item"
href="https://supportdcs.storj.io/hc/en-us"
target="_blank"
rel="noopener noreferrer"
@click.prevent="trackViewSupportEvent('https://supportdcs.storj.io/hc/en-us')"
>
<SupportIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Support</h2>
<p class="dropdown-item__text__label">Get technical support</p>
</div>
</a>
</GuidesDropdown>
</div>
<div ref="quickStartContainer" class="container-wrapper">
<div
class="navigation-area__container__wrap__item-container"
:class="{ active: isQuickStartDropdownShown }"
@click.stop="toggleQuickStartDropdown"
>
<div class="navigation-area__container__wrap__item-container__left">
<QuickStartIcon class="navigation-area__container__wrap__item-container__left__image" />
<p class="navigation-area__container__wrap__item-container__left__label">Quick Start</p>
</div>
<ArrowIcon class="navigation-area__container__wrap__item-container__arrow" />
</div>
<GuidesDropdown
v-if="isQuickStartDropdownShown"
:close="closeDropdowns"
:y-position="quickStartDropdownYPos"
:x-position="quickStartDropdownXPos"
>
<div class="dropdown-item" aria-roledescription="create-project-route" @click.stop="navigateToNewProject">
<NewProjectIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">New Project</h2>
<p class="dropdown-item__text__label">Create a new project.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="create-ag-route" @click.stop="navigateToCreateAG">
<CreateAGIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Create an Access Grant</h2>
<p class="dropdown-item__text__label">Start the wizard to create a new access grant.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="objects-route" @click.stop="navigateToBuckets">
<UploadInWebIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Upload in Web</h2>
<p class="dropdown-item__text__label">Start uploading files in the web browser.</p>
</div>
</div>
<div class="dropdown-border" />
<div class="dropdown-item" aria-roledescription="cli-flow-route" @click.stop="navigateToCLIFlow">
<UploadInCLIIcon class="dropdown-item__icon" />
<div class="dropdown-item__text">
<h2 class="dropdown-item__text__title">Upload using CLI</h2>
<p class="dropdown-item__text__label">Start guide for using the Uplink CLI.</p>
</div>
</div>
</GuidesDropdown>
</div>
</div>
<AccountArea />
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import NewProjectSelection from '@/components/navigation/newNavigationStructure/NewProjectSelection.vue';
import GuidesDropdown from '@/components/navigation/newNavigationStructure/GuidesDropdown.vue';
import AccountArea from '@/components/navigation/newNavigationStructure/AccountArea.vue';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { NavigationLink } from '@/types/navigation';
import { APP_STATE_ACTIONS } from "@/utils/constants/actionNames";
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import LogoIcon from '@/../static/images/logo.svg';
import SmallLogoIcon from '@/../static/images/smallLogo.svg';
import AccessGrantsIcon from '@/../static/images/navigation/accessGrants.svg';
import DashboardIcon from '@/../static/images/navigation/projectDashboard.svg';
import BucketsIcon from '@/../static/images/navigation/buckets.svg';
import UsersIcon from '@/../static/images/navigation/users.svg';
import BillingIcon from '@/../static/images/navigation/billing.svg';
import ResourcesIcon from '@/../static/images/navigation/resources.svg';
import QuickStartIcon from '@/../static/images/navigation/quickStart.svg';
import ArrowIcon from '@/../static/images/navigation/arrowExpandRight.svg';
import DocsIcon from '@/../static/images/navigation/docs.svg';
import ForumIcon from '@/../static/images/navigation/forum.svg';
import SupportIcon from '@/../static/images/navigation/support.svg';
import NewProjectIcon from '@/../static/images/navigation/newProject.svg';
import CreateAGIcon from '@/../static/images/navigation/createAccessGrant.svg';
import UploadInCLIIcon from '@/../static/images/navigation/uploadInCLI.svg';
import UploadInWebIcon from '@/../static/images/navigation/uploadInWeb.svg';
// @vue/component
@Component({
components: {
NewProjectSelection,
GuidesDropdown,
AccountArea,
LogoIcon,
SmallLogoIcon,
DashboardIcon,
AccessGrantsIcon,
UsersIcon,
BillingIcon,
BucketsIcon,
ResourcesIcon,
QuickStartIcon,
ArrowIcon,
DocsIcon,
ForumIcon,
SupportIcon,
NewProjectIcon,
CreateAGIcon,
UploadInCLIIcon,
UploadInWebIcon,
},
})
export default class NewNavigationArea extends Vue {
private readonly TWENTY_PIXELS = 20;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public resourcesDropdownYPos = 0;
public resourcesDropdownXPos = 0;
public quickStartDropdownYPos = 0;
public quickStartDropdownXPos = 0;
public navigation: NavigationLink[] = [
RouteConfig.ProjectDashboard.withIcon(DashboardIcon),
RouteConfig.Buckets.withIcon(BucketsIcon),
RouteConfig.AccessGrants.withIcon(AccessGrantsIcon),
RouteConfig.Users.withIcon(UsersIcon),
RouteConfig.Account.with(RouteConfig.Billing).withIcon(BillingIcon),
];
public $refs!: {
resourcesContainer: HTMLDivElement;
quickStartContainer: HTMLDivElement;
navigationContainer: HTMLDivElement;
};
/**
* Mounted hook after initial render.
* Adds scroll event listener to close dropdowns.
*/
public mounted(): void {
this.$refs.navigationContainer.addEventListener('scroll', this.closeDropdowns)
window.addEventListener('resize', this.closeDropdowns)
}
/**
* Mounted hook before component destroy.
* Removes scroll event listener.
*/
public beforeDestroy(): void {
this.$refs.navigationContainer.removeEventListener('scroll', this.closeDropdowns)
window.removeEventListener('resize', this.closeDropdowns)
}
/**
* Redirects to create project screen.
*/
public navigateToCreateAG(): void {
this.analytics.eventTriggered(AnalyticsEvent.CREATE_AN_ACCESS_GRANT_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant).path).catch(() => {return;});
}
/**
* Redirects to objects screen.
*/
public navigateToBuckets(): void {
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_IN_WEB_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.Buckets.path).catch(() => {return;});
}
/**
* Redirects to onboarding CLI flow screen.
*/
public navigateToCLIFlow(): void {
this.analytics.eventTriggered(AnalyticsEvent.UPLOAD_USING_CLI_CLICKED);
this.closeDropdowns();
this.$store.commit(APP_STATE_MUTATIONS.SET_ONB_AG_NAME_STEP_BACK_ROUTE, this.$route.path);
this.$router.push({name: RouteConfig.AGName.name});
}
/**
* Redirects to create access grant screen.
*/
public navigateToNewProject(): void {
this.analytics.eventTriggered(AnalyticsEvent.NEW_PROJECT_CLICKED);
this.closeDropdowns();
this.$router.push(RouteConfig.CreateProject.path);
}
/**
* Reloads page.
*/
public onLogoClick(): void {
location.reload();
}
/**
* Sets resources dropdown Y position depending on container's current position.
* It is used to handle small screens.
*/
public setResourcesDropdownYPos(): void {
const container = this.$refs.resourcesContainer.getBoundingClientRect();
this.resourcesDropdownYPos = container.top + container.height / 2;
}
/**
* Sets resources dropdown X position depending on container's current position.
* It is used to handle small screens.
*/
public setResourcesDropdownXPos(): void {
this.resourcesDropdownXPos = this.$refs.resourcesContainer.getBoundingClientRect().width - this.TWENTY_PIXELS;
}
/**
* Sets quick start dropdown Y position depending on container's current position.
* It is used to handle small screens.
*/
public setQuickStartDropdownYPos(): void {
const container = this.$refs.quickStartContainer.getBoundingClientRect();
this.quickStartDropdownYPos = container.top + container.height / 2;
}
/**
* Sets quick start dropdown X position depending on container's current position.
* It is used to handle small screens.
*/
public setQuickStartDropdownXPos(): void {
this.quickStartDropdownXPos = this.$refs.quickStartContainer.getBoundingClientRect().width - this.TWENTY_PIXELS;
}
/**
* Toggles resources dropdown visibility.
*/
public toggleResourcesDropdown(): void {
this.setResourcesDropdownYPos()
this.setResourcesDropdownXPos()
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_RESOURCES_DROPDOWN);
}
/**
* Toggles quick start dropdown visibility.
*/
public toggleQuickStartDropdown(): void {
this.setQuickStartDropdownYPos()
this.setQuickStartDropdownXPos()
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_QUICK_START_DROPDOWN);
}
/**
* Closes dropdowns.
*/
public closeDropdowns(): void {
this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
}
/**
* Indicates if resources dropdown shown.
*/
public get isResourcesDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isResourcesDropdownShown;
}
/**
* Indicates if quick start dropdown shown.
*/
public get isQuickStartDropdownShown(): boolean {
return this.$store.state.appStateModule.appState.isQuickStartDropdownShown;
}
/**
* Sends "View Docs" event to segment and opens link.
*/
public trackViewDocsEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_DOCS_CLICKED);
window.open(link)
}
/**
* Sends "View Forum" event to segment and opens link.
*/
public trackViewForumEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_FORUM_CLICKED);
window.open(link)
}
/**
* Sends "View Support" event to segment and opens link.
*/
public trackViewSupportEvent(link: string): void {
this.analytics.eventTriggered(AnalyticsEvent.VIEW_SUPPORT_CLICKED);
window.open(link)
}
/**
* Sends new path click event to segment.
*/
public trackClickEvent(name: string): void {
this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, name);
}
}
</script>
<style scoped lang="scss">
.navigation-svg-path {
fill: rgb(53 64 73);
}
.container-wrapper {
width: 100%;
}
.navigation-area {
min-width: 280px;
max-width: 280px;
background-color: #fff;
font-family: 'font_regular', sans-serif;
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
&__container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
&__wrap {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding-top: 40px;
&__logo {
cursor: pointer;
min-height: 37px;
}
&__small-logo {
display: none;
}
&__edit {
margin-top: 40px;
width: 100%;
}
&__item-container {
padding: 22px 32px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
border-left: 4px solid #fff;
color: #56606d;
font-weight: 500;
position: static;
cursor: pointer;
box-sizing: border-box;
&__left {
display: flex;
align-items: center;
&__label {
font-size: 14px;
line-height: 20px;
margin-left: 24px;
}
}
}
&__border {
margin: 8px 24px;
height: 1px;
width: calc(100% - 48px);
background: #ebeef1;
}
}
}
}
.active {
font-weight: 600;
border-color: #0149ff;
background-color: #f7f8fb;
color: #0149ff;
.navigation-area__container__wrap__item-container {
&__left__image path,
&__arrow path {
fill: #0149ff;
}
}
}
.router-link-active,
.navigation-area__container__wrap__item-container:hover {
font-weight: 600;
border-color: #0149ff;
background-color: #f7f8fb;
color: #0149ff;
.navigation-area__container__wrap__item-container__left__image path {
fill: #0149ff;
}
}
.dropdown-item {
display: flex;
align-items: center;
font-family: 'font_regular', sans-serif;
padding: 10px 24px;
cursor: pointer;
&__icon {
margin-left: 15px;
max-width: 37px;
min-width: 37px;
}
&__text {
margin-left: 24px;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 14px;
line-height: 22px;
color: #091c45;
}
&__label {
font-size: 12px;
line-height: 21px;
color: #091c45;
}
}
}
.dropdown-border {
height: 1px;
width: calc(100% - 48px);
margin: 0 24px;
background-color: #091c45;
opacity: 0.1;
}
@media screen and (max-width: 1280px) {
.navigation-area {
min-width: unset;
max-width: unset;
&__container__wrap {
&__logo {
display: none;
}
&__item-container {
justify-content: center;
&__left__label,
&__arrow {
display: none;
}
}
&__small-logo {
cursor: pointer;
min-height: 40px;
display: block;
}
}
}
}
</style>

View File

@ -69,6 +69,7 @@ const {
export default class Projects extends Vue {
private currentPageNumber = 1;
private FIRST_PAGE = 1;
private isLoading = false;
public areProjectsFetching = true;
@ -110,6 +111,10 @@ export default class Projects extends Vue {
* @param project
*/
public async onProjectSelected(project: Project): Promise<void> {
if (this.isLoading) return;
this.isLoading = true;
const projectID = project.id;
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, projectID);
LocalData.setSelectedProjectId(projectID);
@ -122,16 +127,12 @@ export default class Projects extends Vue {
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, this.FIRST_PAGE);
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
if (this.isNewNavStructure) {
await this.$router.push(RouteConfig.EditProjectDetails.path);
return;
}
await this.$router.push(RouteConfig.ProjectDashboard.path);
await this.$router.push(RouteConfig.EditProjectDetails.path);
} catch (error) {
await this.$notify.error(`Unable to select project. ${error.message}`);
}
this.isLoading = false;
}
/**
@ -147,13 +148,6 @@ export default class Projects extends Vue {
public get projectsPage(): ProjectsPage {
return this.$store.state.projectsModule.page;
}
/**
* Indicates if new navigation structure is used.
*/
public get isNewNavStructure(): boolean {
return this.$store.state.appStateModule.isNewNavStructure;
}
}
</script>

View File

@ -51,7 +51,6 @@ class State {
public couponCodeBillingUIEnabled = false,
public couponCodeSignupUIEnabled = false,
public isNewProjectDashboard = false,
public isNewNavStructure = false,
public isNewObjectsFlow = false,
){}
}
@ -176,9 +175,6 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.SET_ONB_CLEAN_API_KEY](state: State, apiKey: string): void {
state.appState.onbCleanApiKey = apiKey;
},
[APP_STATE_MUTATIONS.SET_NAV_STRUCTURE_STATUS](state: State, isNewNavStructure: boolean): void {
state.isNewNavStructure = isNewNavStructure;
},
[APP_STATE_MUTATIONS.SET_OBJECTS_FLOW_STATUS](state: State, isNewObjectsFlow: boolean): void {
state.isNewObjectsFlow = isNewObjectsFlow;
},
@ -346,9 +342,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_NAV_STRUCTURE_STATUS]: function ({commit}: AppContext, isNewNavStructure: boolean): void {
commit(APP_STATE_MUTATIONS.SET_NAV_STRUCTURE_STATUS, isNewNavStructure);
},
[APP_STATE_ACTIONS.SET_OBJECTS_FLOW_STATUS]: function ({commit}: AppContext, isNewObjectsFlow: boolean): void {
commit(APP_STATE_MUTATIONS.SET_OBJECTS_FLOW_STATUS, isNewObjectsFlow);
},

View File

@ -46,7 +46,6 @@ export const APP_STATE_MUTATIONS = {
SET_ONB_API_KEY_STEP_BACK_ROUTE: 'SET_ONB_API_KEY_STEP_BACK_ROUTE',
SET_ONB_API_KEY: 'SET_ONB_API_KEY',
SET_ONB_CLEAN_API_KEY: 'SET_ONB_CLEAN_API_KEY',
SET_NAV_STRUCTURE_STATUS: 'SET_NAV_STRUCTURE_STATUS',
SET_OBJECTS_FLOW_STATUS: 'SET_OBJECTS_FLOW_STATUS',
SET_ONB_OS: 'SET_ONB_OS',
};

View File

@ -34,7 +34,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_NAV_STRUCTURE_STATUS: 'SET_NAV_STRUCTURE_STATUS',
SET_OBJECTS_FLOW_STATUS: 'SET_OBJECTS_FLOW_STATUS',
};

View File

@ -6,49 +6,26 @@
<div v-if="isLoading" class="loading-overlay active">
<LoaderImage class="loading-icon" />
</div>
<div v-if="!isLoading" class="dashboard__wrap">
<template v-if="!isNewNavStructure">
<BetaSatBar v-if="isBetaSatellite" />
<PaidTierBar v-if="!creditCards.length && !isOnboardingTour" :open-add-p-m-modal="togglePMModal" />
<ProjectInfoBar v-if="isProjectListPage" />
<MFARecoveryCodeBar v-if="showMFARecoveryCodeBar" :open-generate-modal="generateNewMFARecoveryCodes" />
</template>
<template v-if="isNewNavStructure">
<div class="dashboard__wrap__new-main-area">
<NewNavigationArea v-if="!isNavigationHidden" />
<div
class="dashboard__wrap__new-main-area__content-wrap"
:class="{
'with-one-bar': amountOfInfoBars === 1,
'with-two-bars': amountOfInfoBars === 2,
'with-three-bars': amountOfInfoBars === 3,
'with-four-bars': amountOfInfoBars === 4,
'no-nav': isNavigationHidden,
}"
>
<BetaSatBar v-if="isBetaSatellite" />
<PaidTierBar v-if="!creditCards.length && !isOnboardingTour" :open-add-p-m-modal="togglePMModal" />
<ProjectInfoBar v-if="isProjectListPage" />
<MFARecoveryCodeBar v-if="showMFARecoveryCodeBar" :open-generate-modal="generateNewMFARecoveryCodes" />
<router-view class="dashboard__wrap__new-main-area__content-wrap__content" />
</div>
</div>
</template>
<template v-else>
<DashboardHeader />
<div v-else class="dashboard__wrap">
<div class="dashboard__wrap__main-area">
<NavigationArea v-if="!isNavigationHidden" />
<div
class="dashboard__wrap__main-area"
class="dashboard__wrap__main-area__content-wrap"
:class="{
'with-one-bar-old': amountOfInfoBars === 1,
'with-two-bars-old': amountOfInfoBars === 2,
'with-three-bars-old': amountOfInfoBars === 3,
'with-four-bars-old': amountOfInfoBars === 4,
'with-one-bar': amountOfInfoBars === 1,
'with-two-bars': amountOfInfoBars === 2,
'with-three-bars': amountOfInfoBars === 3,
'with-four-bars': amountOfInfoBars === 4,
'no-nav': isNavigationHidden,
}"
>
<NavigationArea class="regular-navigation" />
<router-view class="dashboard__wrap__main-area__content" />
<BetaSatBar v-if="isBetaSatellite" />
<PaidTierBar v-if="!creditCards.length && !isOnboardingTour" :open-add-p-m-modal="togglePMModal" />
<ProjectInfoBar v-if="isProjectListPage" />
<MFARecoveryCodeBar v-if="showMFARecoveryCodeBar" :open-generate-modal="generateNewMFARecoveryCodes" />
<router-view class="dashboard__wrap__main-area__content-wrap__content" />
</div>
</template>
</div>
</div>
<MFARecoveryCodesPopup v-if="isMFACodesPopup" :toggle-modal="toggleMFACodesPopup" />
<AllModals />
@ -63,9 +40,7 @@ import PaidTierBar from '@/components/infoBars/PaidTierBar.vue';
import MFARecoveryCodeBar from '@/components/infoBars/MFARecoveryCodeBar.vue';
import BetaSatBar from '@/components/infoBars/BetaSatBar.vue';
import MFARecoveryCodesPopup from '@/components/account/mfa/MFARecoveryCodesPopup.vue';
import DashboardHeader from '@/components/header/HeaderArea.vue';
import NavigationArea from '@/components/navigation/NavigationArea.vue';
import NewNavigationArea from '@/components/navigation/newNavigationStructure/NewNavigationArea.vue';
import ProjectInfoBar from "@/components/infoBars/ProjectInfoBar.vue";
import LoaderImage from '@/../static/images/common/loader.svg';
@ -97,8 +72,6 @@ const {
components: {
AllModals,
NavigationArea,
NewNavigationArea,
DashboardHeader,
LoaderImage,
PaidTierBar,
MFARecoveryCodeBar,
@ -296,19 +269,12 @@ export default class DashboardArea extends Vue {
* Indicates whether the MFA recovery code warning bar should be shown.
*/
public get showMFARecoveryCodeBar(): boolean {
const user : User = this.$store.getters.user;
const user: User = this.$store.getters.user;
return user.isMFAEnabled && user.mfaRecoveryCodeCount < this.recoveryCodeWarningThreshold;
}
/**
* Indicates if new navigation structure is used.
*/
public get isNewNavStructure(): boolean {
return this.$store.state.appStateModule.isNewNavStructure;
}
/**
* Indicates if navigation side bar is hidden.
* Indicates if navigation sidebar is hidden.
*/
public get isNavigationHidden(): boolean {
return this.isOnboardingTour || this.isCreateProjectPage;
@ -409,17 +375,6 @@ export default class DashboardArea extends Vue {
height: 100%;
&__main-area {
display: flex;
height: calc(100% - 62px);
&__content {
overflow-y: auto;
width: 100%;
position: relative;
}
}
&__new-main-area {
display: flex;
width: 100%;
height: 100%;
@ -451,22 +406,6 @@ export default class DashboardArea extends Vue {
height: calc(100% - 104px);
}
.with-one-bar-old {
height: calc(100% - 62px - 26px);
}
.with-two-bars-old {
height: calc(100% - 62px - 52px);
}
.with-three-bars-old {
height: calc(100% - 62px - 78px);
}
.with-four-bars-old {
height: calc(100% - 62px - 104px);
}
.no-nav {
width: 100%;
}
@ -477,7 +416,7 @@ export default class DashboardArea extends Vue {
display: none;
}
.dashboard__wrap__new-main-area__content-wrap {
.dashboard__wrap__main-area__content-wrap {
width: calc(100% - 86px);
}

View File

@ -1,4 +0,0 @@
<svg width="20" height="15" viewBox="0 0 20 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="billing-svg-path" d="M3 0C1.34314 0 0 1.34314 0 3H20C20 1.34314 18.6569 0 17 0H3Z" fill="#768394"/>
<path class="billing-svg-path" d="M20 6H0V12C0 13.6569 1.34314 15 3 15H17C18.6569 15 20 13.6569 20 12V6Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 347 B

View File

@ -1,4 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.17423 8.83244C0.634669 8.29287 0.634669 7.41807 1.17423 6.8785C1.7138 6.33894 2.5886 6.33894 3.12817 6.8785L6.38473 10.1351C6.92429 10.6746 6.92429 11.5494 6.38473 12.089C5.84516 12.6286 4.97036 12.6286 4.43079 12.089L1.17423 8.83244Z" fill="#2683FF"/>
<path d="M6.38473 12.089C5.84516 12.6286 4.97036 12.6286 4.43079 12.089C3.89123 11.5494 3.89123 10.6746 4.43079 10.1351L10.2926 4.27325C10.8322 3.73369 11.707 3.73369 12.2465 4.27325C12.7861 4.81282 12.7861 5.68762 12.2465 6.22719L6.38473 12.089Z" fill="#2683FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 641 B

View File

@ -1,5 +0,0 @@
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="community-svg-path" d="M13.6765 3.63971C13.6765 1.62955 12.0469 0 10.0368 0C10.0245 0 10.0122 6.05864e-05 10 0.000181759C9.98776 6.05864e-05 9.9755 0 9.96324 0C7.95308 0 6.32353 1.62955 6.32353 3.63971C6.32353 4.98758 7.0562 6.16432 8.145 6.79341C6.72107 7.46304 5.73529 8.91052 5.73529 10.5882V12.1324H14.2647V10.5882C14.2647 8.91052 13.2789 7.46305 11.855 6.79342C12.9438 6.16433 13.6765 4.98758 13.6765 3.63971Z" fill="#5B5C5E"/>
<path class="community-svg-path" d="M6.17664 0.51958C5.62898 0.189734 4.98738 0 4.30147 0C2.29132 0 0.661765 1.62955 0.661765 3.63971C0.661765 4.97413 1.37988 6.14082 2.45092 6.77431C1.00483 7.43522 0 8.89438 0 10.5882V12.1324H4.41177V10.5882C4.41177 9.072 5.02955 7.66786 6.06128 6.65394L6.07985 6.63596L6.0486 6.5949C5.44573 5.78186 5.094 4.78793 5.0744 3.73295L5.07353 3.63971C5.07353 2.45764 5.48676 1.37208 6.17664 0.51958Z" fill="#5B5C5E"/>
<path class="community-svg-path" d="M13.8234 0.51958C14.371 0.189734 15.0126 0 15.6985 0C17.7087 0 19.3382 1.62955 19.3382 3.63971C19.3382 4.97413 18.6201 6.14082 17.5491 6.77431C18.9952 7.43522 20 8.89438 20 10.5882V12.1324H15.5882V10.5882C15.5882 9.072 14.9705 7.66786 13.9387 6.65394L13.9201 6.63596L13.9514 6.5949C14.5543 5.78186 14.906 4.78793 14.9256 3.73295L14.9265 3.63971C14.9265 2.45764 14.5132 1.37208 13.8234 0.51958Z" fill="#5B5C5E"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,3 +0,0 @@
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="docs-svg-path" fill-rule="evenodd" clip-rule="evenodd" d="M0 1C0 0.447715 0.447715 0 1 0H9.41177V13H1C0.447715 13 0 12.5523 0 12V1ZM8.23534 2.36358H1.17651V3.54539H8.23534V2.36358ZM4.70593 4.72734H1.17651V5.90915H4.70593V4.72734ZM1.17651 7.09091H4.70593V8.27273H1.17651V7.09091ZM8.23534 10.6364V9.45462H1.17651V10.6364H8.23534ZM10.5882 0H19C19.5523 0 20 0.447715 20 1V12C20 12.5523 19.5523 13 19 13H10.5882V0ZM18.8236 2.36358H11.7647V3.54539H18.8236V2.36358ZM18.8236 4.72734H11.7647V5.90915H18.8236V4.72734ZM11.7647 7.09091H18.8236V8.27273H11.7647V7.09091ZM15.2941 9.45462H11.7647V10.6364H15.2941V9.45462Z" fill="#5B5C5E"/>
</svg>

Before

Width:  |  Height:  |  Size: 744 B

View File

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 16V12" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 8H12.01" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 524 B

View File

@ -1,5 +0,0 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="20" fill="#F5F6FA"/>
<path d="M14.4015 13.2402C14.8097 13.6484 15.2211 14.0598 15.6292 14.468L18.5784 17.4171C19.7631 18.6018 20.9477 19.7864 22.1363 20.975L25.2198 24.0585C25.7199 24.5586 26.2302 25.0458 26.7175 25.5562C26.7239 25.5626 26.7303 25.5691 26.7374 25.5761C27.0434 25.8821 27.0633 26.4381 26.7374 26.7409C26.4083 27.0436 25.8979 27.0668 25.5727 26.7409C25.1645 26.3327 24.7531 25.9213 24.3449 25.5131L21.3957 22.564C20.2111 21.3793 19.0265 20.1947 17.8379 19.0061L14.7544 15.9226C14.2543 15.4225 13.7439 14.9353 13.2567 14.4249C13.2503 14.4185 13.2438 14.412 13.2368 14.405C12.9308 14.099 12.9108 13.543 13.2368 13.2402C13.5659 12.9375 14.0756 12.9143 14.4015 13.2402Z" fill="#2B3543"/>
<path d="M26.7362 14.4018C26.328 14.8099 25.9166 15.2213 25.5085 15.6295L22.5593 18.5787C21.3746 19.7634 20.19 20.948 19.0014 22.1366L15.918 25.22C15.4179 25.7201 14.9306 26.2305 14.4202 26.7177C14.4138 26.7242 14.4074 26.7306 14.4003 26.7377C14.0943 27.0437 13.5383 27.0636 13.2356 26.7377C12.9328 26.4086 12.9097 25.8982 13.2356 25.5729C13.6437 25.1647 14.0551 24.7534 14.4633 24.3452L17.4125 21.396C18.5972 20.2113 19.7818 19.0267 20.9704 17.8381L24.0538 14.7547C24.5539 14.2546 25.0412 13.7442 25.5515 13.2569C25.558 13.2505 25.5644 13.2441 25.5715 13.237C25.8774 12.931 26.4335 12.9111 26.7362 13.237C27.039 13.5661 27.0621 14.0759 26.7362 14.4018Z" fill="#2B3543"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,5 +0,0 @@
<svg width="21" height="15" viewBox="0 0 21 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="21" height="2.37931" rx="1.18966" fill="#2683FF"/>
<rect y="6.31055" width="21" height="2.37931" rx="1.18966" fill="#2683FF"/>
<rect y="12.6206" width="21" height="2.37931" rx="1.18966" fill="#2683FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 331 B

View File

@ -1,3 +0,0 @@
<svg width="15" height="13" viewBox="0 0 15 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.0928 3.02746C14.6603 2.4239 14.631 1.4746 14.0275 0.907152C13.4239 0.339699 12.4746 0.368972 11.9072 0.972536L14.0928 3.02746ZM4.53846 11L3.44613 12.028C3.72968 12.3293 4.12509 12.5001 4.53884 12.5C4.95258 12.4999 5.34791 12.3289 5.63131 12.0275L4.53846 11ZM3.09234 7.27469C2.52458 6.67141 1.57527 6.64261 0.971991 7.21036C0.36871 7.77812 0.339911 8.72743 0.907664 9.33071L3.09234 7.27469ZM11.9072 0.972536L3.44561 9.97254L5.63131 12.0275L14.0928 3.02746L11.9072 0.972536ZM5.6308 9.97199L3.09234 7.27469L0.907664 9.33071L3.44613 12.028L5.6308 9.97199Z" fill="#2683FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 690 B

View File

@ -1,3 +0,0 @@
<svg width="19" height="20" viewBox="0 0 19 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="settings-svg-path" d="M18.4987 12.5738L17.7603 12.0675C17.0852 11.6034 16.7266 10.8228 16.7266 10.0211C16.7266 10.0211 16.7266 10.0211 16.7266 10C16.7266 9.9789 16.7266 10 16.7266 9.9789C16.7266 9.15612 17.0852 8.39662 17.7603 7.93249L18.4987 7.42616C18.9418 7.1308 19.0684 6.54008 18.7941 6.09705L17.5072 3.88186C17.254 3.41772 16.6844 3.24894 16.1992 3.48101L15.3975 3.86076C14.6802 4.19831 13.8574 4.17722 13.1823 3.77637C13.1401 3.75527 13.0768 3.71308 13.0346 3.69198C12.3384 3.31224 11.8954 2.59494 11.8321 1.81435L11.7688 0.92827C11.7266 0.400844 11.2836 0 10.7772 0H8.18229C7.65486 0 7.21182 0.400844 7.19073 0.92827L7.12744 1.81435C7.06415 2.59494 6.62111 3.31224 5.92491 3.69198C5.88271 3.71308 5.81942 3.75527 5.77723 3.77637C5.10212 4.17722 4.25824 4.19831 3.56204 3.86076L2.73925 3.45992C2.27512 3.22785 1.7055 3.41772 1.43123 3.86076L0.144315 6.09705C-0.108849 6.56118 0.0177328 7.1308 0.439674 7.42616L1.17807 7.93249C1.85318 8.39662 2.21183 9.17722 2.21183 9.9789C2.21183 9.9789 2.21183 9.9789 2.21183 10C2.21183 10 2.21183 10 2.21183 10.0211C2.21183 10.8439 1.85318 11.6034 1.17807 12.0675L0.439674 12.5738C-0.00336422 12.8692 -0.129946 13.4599 0.144315 13.903L1.43123 16.1181C1.6844 16.5823 2.25402 16.7511 2.73925 16.519L3.54094 16.1392C4.25824 15.8017 5.08102 15.8228 5.75613 16.2236C5.79832 16.2447 5.86161 16.2869 5.90381 16.308C6.60001 16.6878 7.04305 17.4051 7.10634 18.1857L7.16963 19.0717C7.21182 19.5992 7.65486 20 8.16119 20H10.735C11.2625 20 11.7055 19.5992 11.7266 19.0717L11.7899 18.1857C11.8532 17.4051 12.2962 16.6878 12.9924 16.308C13.0346 16.2869 13.0979 16.2447 13.1401 16.2236C13.8152 15.8228 14.6591 15.8017 15.3553 16.1392L16.157 16.519C16.6211 16.7511 17.1907 16.5612 17.465 16.1181L18.7519 13.8819C19.0473 13.4388 18.9207 12.8692 18.4987 12.5738ZM9.46921 13.7553C7.4017 13.7553 5.71394 12.0675 5.71394 10C5.71394 7.93249 7.4017 6.24473 9.46921 6.24473C11.5367 6.24473 13.2245 7.93249 13.2245 10C13.2245 12.0675 11.5367 13.7553 9.46921 13.7553Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,6 +0,0 @@
<svg width="16" height="15" viewBox="0 0 16 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="support-svg-path" d="M0 4C0 1.79086 1.79086 0 4 0H12C14.2091 0 16 1.79086 16 4V15L12.1428 13H4C1.79086 13 0 11.2091 0 9V4Z" fill="#5B5C5E"/>
<circle cx="4" cy="6" r="1" fill="white"/>
<circle cx="8" cy="6" r="1" fill="white"/>
<circle cx="12" cy="6" r="1" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 403 B

View File

@ -1,3 +0,0 @@
<svg class="svg" width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="navigation-svg-path" opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M19 0L18.8777 3.30167L17.3804 3.33154L17.3114 4.86798L15.548 5.164L15.5552 6.62419L14.0737 6.63827L13.8958 8.28354L12.3349 9.84422L13.2397 13.2214C13.3996 13.8182 13.229 14.4549 12.7921 14.8918L9.19044 18.4934C8.75356 18.9303 8.1168 19.1009 7.52001 18.941L2.60009 17.6227C2.00331 17.4628 1.53716 16.9967 1.37725 16.3999L0.0589658 11.48C-0.100943 10.8832 0.0696777 10.2464 0.506556 9.80956L4.10819 6.20793C4.54507 5.77105 5.18183 5.60043 5.77862 5.76034L9.15552 6.66484L15.6983 0.122284L19 0ZM6.52703 12.473C5.78414 11.7301 4.57967 11.7301 3.83678 12.473C3.09389 13.2159 3.09389 14.4203 3.83678 15.1632C4.57967 15.9061 5.78414 15.9061 6.52703 15.1632C7.26992 14.4203 7.26992 13.2159 6.52703 12.473Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 925 B

View File

@ -1,3 +0,0 @@
<svg class="svg" width="19" height="17" viewBox="0 0 19 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="navigation-svg-path" fill-rule="evenodd" clip-rule="evenodd" d="M15.6691 16.8889H9.5H3.3309C1.29229 15.1294 0 12.5137 0 9.59331C0 4.29507 4.2533 0 9.5 0C14.7467 0 19 4.29507 19 9.59331C19 12.5137 17.7077 15.1294 15.6691 16.8889ZM12.9227 5.32961L14.4156 6.83704L9.93721 11.3594L8.44444 9.85192L12.9227 5.32961Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 459 B

View File

@ -1,5 +0,0 @@
<svg width="3" height="15" viewBox="0 0 3 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="edit-dots-svg-path" d="M2.72723 1.36362C2.72723 2.11672 2.11672 2.72723 1.36362 2.72723C0.610511 2.72723 0 2.11672 0 1.36362C0 0.610511 0.610511 0 1.36362 0C2.11672 0 2.72723 0.610511 2.72723 1.36362Z" fill="#1B2533"/>
<path class="edit-dots-svg-path" d="M2.72723 7.49922C2.72723 8.25232 2.11672 8.86283 1.36362 8.86283C0.610511 8.86283 0 8.25232 0 7.49922C0 6.74611 0.610511 6.1356 1.36362 6.1356C2.11672 6.1356 2.72723 6.74611 2.72723 7.49922Z" fill="#1B2533"/>
<path class="edit-dots-svg-path" d="M1.36362 15C2.11672 15 2.72723 14.3895 2.72723 13.6364C2.72723 12.8833 2.11672 12.2728 1.36362 12.2728C0.610511 12.2728 0 12.8833 0 13.6364C0 14.3895 0.610511 15 1.36362 15Z" fill="#1B2533"/>
</svg>

Before

Width:  |  Height:  |  Size: 818 B

View File

@ -1,3 +0,0 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.43444 0L12.13 2.69556L3.50422 11.3213L0 12.13L0.808667 8.62578L9.43444 0Z" fill="#2582FF"/>
</svg>

Before

Width:  |  Height:  |  Size: 211 B

View File

@ -1,3 +0,0 @@
<svg class="svg" width="24" height="21" viewBox="0 0 24 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="navigation-svg-path" d="M0 3C0 1.34315 1.34315 0 3 0H10.5C11.3284 0 12 0.671573 12 1.5C12 2.32843 12.6716 3 13.5 3H21C22.6569 3 24 4.34315 24 6V18C24 19.6569 22.6569 21 21 21H3C1.34315 21 0 19.6569 0 18V3Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 356 B

View File

@ -1,3 +0,0 @@
<svg class="svg" width="21" height="18" viewBox="0 0 21 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="navigation-svg-path" opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M14.8165 0C17.7839 0 20.1895 2.40557 20.1895 5.373C20.1895 7.40389 19.0627 9.17161 17.4002 10.0851C19.4392 11.0968 20.8407 13.2 20.8407 15.6305V17.91H8.46655V15.6305C8.46655 13.13 9.94989 10.976 12.0846 10.0004C10.5035 9.06519 9.44345 7.34289 9.44345 5.373C9.44345 2.40557 11.849 0 14.8165 0ZM6.34991 0C7.36246 0 8.3096 0.280088 9.11806 0.767013C8.09966 2.02549 7.48964 3.62801 7.48964 5.373L7.49091 5.51065C7.51986 7.06803 8.03908 8.53529 8.92906 9.73552L8.97519 9.79612L8.94777 9.82267C7.42471 11.3194 6.51273 13.3922 6.51273 15.6305V17.91H0V15.6305C0 13.13 1.48335 10.976 3.61809 10.0004C2.037 9.06519 0.976909 7.34289 0.976909 5.373C0.976909 2.40557 3.38248 0 6.34991 0Z" fill="#768394"/>
</svg>

Before

Width:  |  Height:  |  Size: 902 B

View File

@ -1,76 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import Vuex from 'vuex';
import AccountDropdown from '@/components/header/accountDropdown/AccountDropdown.vue';
import { router } from '@/router';
import { createLocalVue, mount } from '@vue/test-utils';
import { appStateModule } from '@/store/modules/appState';
import {makeProjectsModule} from "@/store/modules/projects";
import {makeUsersModule} from "@/store/modules/users";
import {makeAccessGrantsModule} from "@/store/modules/accessGrants";
import {makeBucketsModule} from "@/store/modules/buckets";
import {makeObjectsModule,} from "@/store/modules/objects";
import {makeNotificationsModule} from "@/store/modules/notifications";
import {makeProjectMembersModule} from "@/store/modules/projectMembers";
import {makePaymentsModule} from "@/store/modules/payments";
import {makeFilesModule} from "@/store/modules/files";
import {PaymentsMock} from "../../mock/api/payments";
import {UsersApiMock} from "../../mock/api/users";
import {ProjectsApiMock} from "../../mock/api/projects";
import {AccessGrantsMock} from "../../mock/api/accessGrants";
import {ProjectMembersApiMock} from "../../mock/api/projectMembers";
import {BucketsMock} from "../../mock/api/buckets";
const localVue = createLocalVue();
localVue.use(Vuex);
const paymentsApi = new PaymentsMock();
const usersApi = new UsersApiMock();
const projectsApi = new ProjectsApiMock();
const accessGrantsApi = new AccessGrantsMock();
const projectMembersApi = new ProjectMembersApiMock();
const bucketsApi = new BucketsMock();
const store = new Vuex.Store({ modules: {
appStateModule,
notificationsModule: makeNotificationsModule(),
accessGrantsModule: makeAccessGrantsModule(accessGrantsApi),
projectMembersModule: makeProjectMembersModule(projectMembersApi),
paymentsModule: makePaymentsModule(paymentsApi),
usersModule: makeUsersModule(usersApi),
projectsModule: makeProjectsModule(projectsApi),
bucketUsageModule: makeBucketsModule(bucketsApi),
objectsModule: makeObjectsModule(),
files: makeFilesModule(),
}});
describe('AccountDropdown', () => {
it('renders correctly', (): void => {
const wrapper = mount(AccountDropdown, {
store,
localVue,
router,
});
expect(wrapper).toMatchSnapshot();
});
it('router works correctly', async (): Promise<void> => {
const routerSpy = jest.spyOn(router, "push");
const wrapper = mount(AccountDropdown, {
store,
localVue,
router,
});
await wrapper.find('.account-dropdown__wrap__item-container').trigger('click');
expect(routerSpy).toHaveBeenCalled();
});
});

View File

@ -1,15 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AccountDropdown renders correctly 1`] = `
<div class="account-dropdown">
<div class="account-dropdown__wrap">
<div class="account-dropdown__wrap__name-container">
<p class="account-dropdown__wrap__name-container__name"></p>
</div>
<div class="account-dropdown__wrap__item-container">
<p class="account-dropdown__wrap__item-container__title">Sign Out</p>
<p class="account-dropdown__wrap__item-container__arrow">-&gt;</p>
</div>
</div>
</div>
`;

View File

@ -1,79 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import { VNode } from 'vue';
import { DirectiveBinding } from 'vue/types/options';
import Vuex from 'vuex';
import EditProjectDropdown from '@/components/navigation/EditProjectDropdown.vue';
import { router } from '@/router';
import { appStateModule } from '@/store/modules/appState';
import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects';
import { Project } from '@/types/projects';
import { createLocalVue, mount } from '@vue/test-utils';
import { ProjectsApiMock } from '../mock/api/projects';
import { makeNotificationsModule } from "@/store/modules/notifications";
import { NotificatorPlugin } from "@/utils/plugins/notificator";
const localVue = createLocalVue();
localVue.use(Vuex);
const projectsApi = new ProjectsApiMock();
const projectsModule = makeProjectsModule(projectsApi);
const notificationsModule = makeNotificationsModule();
const store = new Vuex.Store({ modules: { projectsModule, appStateModule, notificationsModule }});
const project = new Project('id', 'test', 'test', 'test', 'ownedId', false);
localVue.use(new NotificatorPlugin(store));
let clickOutsideEvent: EventListener;
localVue.directive('cli' +
'ck-outside', {
bind: function (el: HTMLElement, binding: DirectiveBinding, vnode: VNode) {
clickOutsideEvent = function(event: Event): void {
if (el === event.target) {
return;
}
if (vnode.context && binding.expression) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', clickOutsideEvent);
},
unbind: function(): void {
document.body.removeEventListener('click', clickOutsideEvent);
},
});
store.commit(PROJECTS_MUTATIONS.ADD, project);
store.commit(PROJECTS_MUTATIONS.SELECT_PROJECT, project.id);
describe('EditProjectDropdown', () => {
it('renders correctly', (): void => {
const wrapper = mount(EditProjectDropdown, {
store,
localVue,
router,
});
expect(wrapper).toMatchSnapshot();
});
it('dropdown opens correctly', async (): Promise<void> => {
const wrapper = mount(EditProjectDropdown, {
store,
localVue,
router,
});
await wrapper.find('.edit-project__selection-area').trigger('click');
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -1,23 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EditProjectDropdown dropdown opens correctly 1`] = `
<div class="edit-project">
<div class="edit-project__selection-area active">
<p title="test" class="edit-project__selection-area__name">test</p> <svg class="edit-project__selection-area__image"></svg>
</div>
<div class="edit-project__dropdown">
<div class="edit-project__dropdown__choice"><svg></svg>
<p class="edit-project__dropdown__choice__label">Edit Details</p>
</div>
</div>
</div>
`;
exports[`EditProjectDropdown renders correctly 1`] = `
<div class="edit-project">
<div class="edit-project__selection-area">
<p title="test" class="edit-project__selection-area__name">test</p> <svg class="edit-project__selection-area__image"></svg>
</div>
<!---->
</div>
`;

View File

@ -1,37 +0,0 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
import Vuex from 'vuex';
import ProjectDropdown from '@/components/header/projectsDropdown/ProjectDropdown.vue';
import { appStateModule } from '@/store/modules/appState';
import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects';
import { Project } from '@/types/projects';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { ProjectsApiMock } from '../mock/api/projects';
const localVue = createLocalVue();
localVue.use(Vuex);
const projectsApi = new ProjectsApiMock();
const projectsModule = makeProjectsModule(projectsApi);
const project1 = new Project('testId1', 'testName1', '');
const project2 = new Project('testId2', 'testName2', '');
const store = new Vuex.Store({ modules: { projectsModule, appStateModule }});
describe('ProjectDropdown', () => {
it('renders correctly', () => {
store.commit(PROJECTS_MUTATIONS.SET_PROJECTS, [project1, project2]);
store.commit(PROJECTS_MUTATIONS.SELECT_PROJECT, project1.id);
const wrapper = shallowMount(ProjectDropdown, {
store,
localVue,
});
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -1,26 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ProjectDropdown renders correctly 1`] = `
<div class="project-dropdown">
<div class="project-dropdown__wrap">
<div class="project-dropdown__wrap__choice">
<div class="project-dropdown__wrap__choice__mark-container">
<selectionicon-stub class="project-dropdown__wrap__choice__mark-container__image"></selectionicon-stub>
</div>
<p class="project-dropdown__wrap__choice__selected">
testName1
</p>
</div>
<div class="project-dropdown__wrap__choice">
<p class="project-dropdown__wrap__choice__unselected">testName2</p>
</div>
</div>
<div class="project-dropdown__create-project">
<div class="project-dropdown__create-project__border"></div>
<div class="project-dropdown__create-project__button-area">
<p class="project-dropdown__create-project__button-area__text">Manage Projects</p>
<p class="project-dropdown__create-project__button-area__arrow">-&gt;</p>
</div>
</div>
</div>
`;

View File

@ -2,16 +2,16 @@
exports[`Dashboard renders correctly when data is loaded 1`] = `
<div class="dashboard">
<!---->
<div class="dashboard__wrap">
<!---->
<paidtierbar-stub openaddpmmodal="[Function]"></paidtierbar-stub>
<!---->
<!---->
<dashboardheader-stub></dashboardheader-stub>
<div class="dashboard__wrap__main-area with-one-bar-old">
<navigationarea-stub class="regular-navigation"></navigationarea-stub>
<router-view-stub name="default" class="dashboard__wrap__main-area__content"></router-view-stub>
<div class="dashboard__wrap__main-area">
<navigationarea-stub></navigationarea-stub>
<div class="dashboard__wrap__main-area__content-wrap with-one-bar">
<!---->
<paidtierbar-stub openaddpmmodal="[Function]"></paidtierbar-stub>
<!---->
<!---->
<router-view-stub name="default" class="dashboard__wrap__main-area__content-wrap__content"></router-view-stub>
</div>
</div>
</div>
<!---->
@ -25,7 +25,6 @@ exports[`Dashboard renders correctly when data is loading 1`] = `
<loaderimage-stub class="loading-icon"></loaderimage-stub>
</div>
<!---->
<!---->
<allmodals-stub></allmodals-stub>
</div>
`;