web/satellite: access grant list page
WHAT: access grants list page where all the created access grants will be visible/deletable WHY: initial page of new access grant flow Change-Id: I0b99f15e47295bd0d307dd3aebd9f6dea3ffbb25
This commit is contained in:
parent
fa95c6bbb9
commit
e16f02b70d
@ -1,38 +1,242 @@
|
|||||||
// Copyright (C) 2020 Storj Labs, Inc.
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||||||
// See LICENSE for copying information.
|
// See LICENSE for copying information.
|
||||||
<template>
|
<template>
|
||||||
<div class="access-grants">
|
<div class="access-grants">
|
||||||
<h2 class="access-grants__title">Access Grants</h2>
|
<div class="access-grants__title-area">
|
||||||
<EmptyState />
|
<h2 class="access-grants__title-area__title">Access Grants</h2>
|
||||||
</div>
|
<div class="access-grants__title-area__right">
|
||||||
|
<VButton
|
||||||
|
label="Create Access Grant +"
|
||||||
|
width="203px"
|
||||||
|
height="44px"
|
||||||
|
class="access-grants__title-area__right__cta"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="accessGrantsList.length" class="access-grants-items">
|
||||||
|
<SortAccessGrantsHeader :on-header-click-callback="onHeaderSectionClickCallback"/>
|
||||||
|
<div class="access-grants-items__content">
|
||||||
|
<VList
|
||||||
|
:data-set="accessGrantsList"
|
||||||
|
:item-component="itemComponent"
|
||||||
|
:on-item-click="toggleSelection"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<VPagination
|
||||||
|
v-if="totalPageCount > 1"
|
||||||
|
class="pagination-area"
|
||||||
|
ref="pagination"
|
||||||
|
:total-page-count="totalPageCount"
|
||||||
|
:on-page-click-callback="onPageClick"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<EmptyState v-else />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
import EmptyState from './EmptyState.vue';
|
import AccessGrantsItem from '@/components/accessGrants/AccessGrantsItem.vue';
|
||||||
|
import EmptyState from '@/components/accessGrants/EmptyState.vue';
|
||||||
|
import SortAccessGrantsHeader from '@/components/accessGrants/SortingHeader.vue';
|
||||||
|
import VButton from '@/components/common/VButton.vue';
|
||||||
|
import VList from '@/components/common/VList.vue';
|
||||||
|
import VPagination from '@/components/common/VPagination.vue';
|
||||||
|
|
||||||
|
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||||
|
import { AccessGrant, AccessGrantsOrderBy } from '@/types/accessGrants';
|
||||||
|
import { SortDirection } from '@/types/common';
|
||||||
|
|
||||||
|
const {
|
||||||
|
FETCH,
|
||||||
|
DELETE,
|
||||||
|
TOGGLE_SELECTION,
|
||||||
|
CLEAR,
|
||||||
|
CLEAR_SELECTION,
|
||||||
|
SET_SEARCH_QUERY,
|
||||||
|
SET_SORT_BY,
|
||||||
|
SET_SORT_DIRECTION,
|
||||||
|
} = ACCESS_GRANTS_ACTIONS;
|
||||||
|
|
||||||
|
declare interface ResetPagination {
|
||||||
|
resetPageIndex(): void;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
EmptyState,
|
EmptyState,
|
||||||
|
SortAccessGrantsHeader,
|
||||||
|
VList,
|
||||||
|
VPagination,
|
||||||
|
VButton,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default class AccessGrants extends Vue {
|
export default class AccessGrants extends Vue {
|
||||||
|
private FIRST_PAGE = 1;
|
||||||
|
/**
|
||||||
|
* Indicates if delete confirmation state should appear.
|
||||||
|
*/
|
||||||
|
private isDeleteClicked: boolean = false;
|
||||||
|
|
||||||
|
public $refs!: {
|
||||||
|
pagination: HTMLElement & ResetPagination;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook after initial render where list of existing access grants is fetched.
|
||||||
|
*/
|
||||||
|
public async mounted(): Promise<void> {
|
||||||
|
await this.$store.dispatch(FETCH, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook before component destruction.
|
||||||
|
* Clears existing access grants selection.
|
||||||
|
*/
|
||||||
|
public beforeDestroy(): void {
|
||||||
|
this.onClearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles access grant selection.
|
||||||
|
* @param accessGrant
|
||||||
|
*/
|
||||||
|
public async toggleSelection(accessGrant: AccessGrant): Promise<void> {
|
||||||
|
await this.$store.dispatch(TOGGLE_SELECTION, accessGrant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches access grants page by clicked index.
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public async onPageClick(index: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch(FETCH, index);
|
||||||
|
} catch (error) {
|
||||||
|
await this.$notify.error(`Unable to fetch Access Grants. ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for sorting.
|
||||||
|
* @param sortBy
|
||||||
|
* @param sortDirection
|
||||||
|
*/
|
||||||
|
public async onHeaderSectionClickCallback(sortBy: AccessGrantsOrderBy, sortDirection: SortDirection): Promise<void> {
|
||||||
|
await this.$store.dispatch(SET_SORT_BY, sortBy);
|
||||||
|
await this.$store.dispatch(SET_SORT_DIRECTION, sortDirection);
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch(FETCH, this.FIRST_PAGE);
|
||||||
|
} catch (error) {
|
||||||
|
await this.$notify.error(`Unable to fetch Access Grants. ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.totalPageCount > 1) {
|
||||||
|
this.$refs.pagination.resetPageIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes selected access grants, fetches updated list and changes area state to default.
|
||||||
|
*/
|
||||||
|
private async delete(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch(DELETE);
|
||||||
|
await this.$notify.success(`Access Grant deleted successfully`);
|
||||||
|
} catch (error) {
|
||||||
|
await this.$notify.error(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch(FETCH, this.FIRST_PAGE);
|
||||||
|
} catch (error) {
|
||||||
|
await this.$notify.error(`Unable to fetch Access Grants. ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isDeleteClicked = false;
|
||||||
|
|
||||||
|
if (this.totalPageCount > 1) {
|
||||||
|
this.$refs.pagination.resetPageIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds on button click login for deleting API key process.
|
||||||
|
*/
|
||||||
|
public onDeleteClick(): void {
|
||||||
|
if (!this.isDeleteClicked) {
|
||||||
|
this.isDeleteClicked = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears API Keys selection.
|
||||||
|
*/
|
||||||
|
public onClearSelection(): void {
|
||||||
|
this.$store.dispatch(CLEAR_SELECTION);
|
||||||
|
this.isDeleteClicked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns access grants pages count from store.
|
||||||
|
*/
|
||||||
|
public get totalPageCount(): number {
|
||||||
|
return this.$store.state.accessGrantsModule.page.pageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Access Grant item component.
|
||||||
|
*/
|
||||||
|
public get itemComponent() {
|
||||||
|
return AccessGrantsItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns access grants from store.
|
||||||
|
*/
|
||||||
|
public get accessGrantsList(): AccessGrant[] {
|
||||||
|
return this.$store.state.accessGrantsModule.page.accessGrants;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.access-grants {
|
.access-grants {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 40px 30px 55px 30px;
|
padding: 40px 30px 55px 30px;
|
||||||
font-family: 'font_regular', sans-serif;
|
font-family: 'font_regular', sans-serif;
|
||||||
|
|
||||||
&__title {
|
&__title-area {
|
||||||
font-family: 'font_bold', sans-serif;
|
display: flex;
|
||||||
font-size: 32px;
|
align-items: center;
|
||||||
line-height: 39px;
|
justify-content: space-between;
|
||||||
color: #263549;
|
|
||||||
margin: 0;
|
&__title {
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 27px;
|
||||||
|
color: #263549;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-grants-items {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
115
web/satellite/src/components/accessGrants/AccessGrantsItem.vue
Normal file
115
web/satellite/src/components/accessGrants/AccessGrantsItem.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="grants-item-container">
|
||||||
|
<div class="grants-item-container__common-info">
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<CheckboxIcon class="checkbox-container__image"/>
|
||||||
|
</div>
|
||||||
|
<div class="name-container" :title="itemData.name">
|
||||||
|
<p class="name">{{ itemData.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grants-item-container__common-info date-item-container">
|
||||||
|
<p class="date">{{ itemData.localDate() }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import CheckboxIcon from '@/../static/images/common/checkbox.svg';
|
||||||
|
|
||||||
|
import { AccessGrant } from '@/types/accessGrants';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
CheckboxIcon,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class AccessGrantsItem extends Vue {
|
||||||
|
@Prop({ default: new AccessGrant('', '', new Date(), '')})
|
||||||
|
private readonly itemData: AccessGrant;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.grants-item-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
height: 83px;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(242, 244, 247, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__common-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container {
|
||||||
|
margin-left: 28px;
|
||||||
|
max-height: 23px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-container {
|
||||||
|
max-width: calc(100% - 131px);
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 21px;
|
||||||
|
color: #354049;
|
||||||
|
margin-left: 17px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
font-family: 'font_regular', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 21px;
|
||||||
|
color: #354049;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grants-item-container.selected {
|
||||||
|
background-color: rgba(242, 244, 247, 0.6);
|
||||||
|
|
||||||
|
.grants-item-container__common-info {
|
||||||
|
|
||||||
|
.checkbox-container {
|
||||||
|
background-image: url('../../../static/images/accessGrants/vector.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 18px 12px;
|
||||||
|
background-position: center;
|
||||||
|
background-color: #0068dc;
|
||||||
|
|
||||||
|
&__image {
|
||||||
|
|
||||||
|
&__rect {
|
||||||
|
stroke: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-item-container {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,19 +2,19 @@
|
|||||||
// See LICENSE for copying information.
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-state__modal">
|
<div class="empty-state__modal">
|
||||||
<Key />
|
<Key />
|
||||||
<h4 class="empty-state__modal__heading">Create Your First Access Grant</h4>
|
<h4 class="empty-state__modal__heading">Create Your First Access Grant</h4>
|
||||||
<p class="empty-state__modal__subheading">Get started by creating an Access to interact with your Buckets</p>
|
<p class="empty-state__modal__subheading">Get started by creating an Access to interact with your Buckets</p>
|
||||||
<VButton
|
<VButton
|
||||||
label="Create Access Grant +"
|
label="Create Access Grant +"
|
||||||
width="199px"
|
width="199px"
|
||||||
height="44px"
|
height="44px"
|
||||||
class="empty-state__modal__cta"
|
class="empty-state__modal__cta"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -30,46 +30,44 @@ import Key from '@/../static/images/accessGrants/key.svg';
|
|||||||
VButton,
|
VButton,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
export default class EmptyState extends Vue {}
|
||||||
export default class EmptyState extends Vue {
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.empty-state {
|
.empty-state {
|
||||||
background-image: url('../../../static/images/accessGrants/access-grants-bg.png');
|
background-image: url('../../../static/images/accessGrants/access-grants-bg.png');
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
|
|
||||||
&__modal {
|
&__modal {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
width: 660px;
|
width: 660px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 100px 30px;
|
padding: 100px 30px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 110px;
|
top: 110px;
|
||||||
|
|
||||||
&__heading {
|
&__heading {
|
||||||
font-family: 'font_bold', sans-serif;
|
font-family: 'font_bold', sans-serif;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__subheading {
|
&__subheading {
|
||||||
font-family: 'font_regular', sans-serif;
|
font-family: 'font_regular', sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__cta {
|
&__cta {
|
||||||
margin: 25px auto 0;
|
margin: 25px auto 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
export default class ProgressBar extends Vue {
|
@Component
|
||||||
}
|
export default class ProgressBar extends Vue {}
|
||||||
</script>
|
</script>
|
||||||
|
116
web/satellite/src/components/accessGrants/SortingHeader.vue
Normal file
116
web/satellite/src/components/accessGrants/SortingHeader.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sort-header-container">
|
||||||
|
<div class="sort-header-container__name-item" @click="onHeaderItemClick(AccessGrantsOrderBy.NAME)">
|
||||||
|
<p class="sort-header-container__name-item__title">NAME</p>
|
||||||
|
<VerticalArrows
|
||||||
|
:is-active="areAccessGrantsSortedByName"
|
||||||
|
:direction="getSortDirection"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="sort-header-container__date-item" @click="onHeaderItemClick(AccessGrantsOrderBy.CREATED_AT)">
|
||||||
|
<p class="sort-header-container__date-item__title creation-date">DATE CREATED</p>
|
||||||
|
<VerticalArrows
|
||||||
|
:is-active="!areAccessGrantsSortedByName"
|
||||||
|
:direction="getSortDirection"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import VerticalArrows from '@/components/common/VerticalArrows.vue';
|
||||||
|
|
||||||
|
import { AccessGrantsOrderBy, OnHeaderClickCallback } from '@/types/accessGrants';
|
||||||
|
import { SortDirection } from '@/types/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
VerticalArrows,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class SortAccessGrantsHeader extends Vue {
|
||||||
|
@Prop({default: () => new Promise(() => false)})
|
||||||
|
private readonly onHeaderClickCallback: OnHeaderClickCallback;
|
||||||
|
|
||||||
|
public sortBy: AccessGrantsOrderBy = AccessGrantsOrderBy.NAME;
|
||||||
|
public sortDirection: SortDirection = SortDirection.ASCENDING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for arrow styling.
|
||||||
|
*/
|
||||||
|
public get getSortDirection(): SortDirection {
|
||||||
|
return this.sortDirection === SortDirection.DESCENDING ? SortDirection.ASCENDING : SortDirection.DESCENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get areAccessGrantsSortedByName(): boolean {
|
||||||
|
return this.sortBy === AccessGrantsOrderBy.NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets sorting kind if different from current.
|
||||||
|
* If same, changes sort direction.
|
||||||
|
* @param sortBy
|
||||||
|
*/
|
||||||
|
public async onHeaderItemClick(sortBy: AccessGrantsOrderBy): Promise<void> {
|
||||||
|
if (this.sortBy !== sortBy) {
|
||||||
|
this.sortBy = sortBy;
|
||||||
|
this.sortDirection = SortDirection.ASCENDING;
|
||||||
|
|
||||||
|
await this.onHeaderClickCallback(this.sortBy, this.sortDirection);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sortDirection = this.sortDirection === SortDirection.DESCENDING ?
|
||||||
|
SortDirection.ASCENDING
|
||||||
|
: SortDirection.DESCENDING;
|
||||||
|
|
||||||
|
await this.onHeaderClickCallback(this.sortBy, this.sortDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sort-header-container {
|
||||||
|
display: flex;
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
height: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
margin-top: 31px;
|
||||||
|
padding: 16px 16px 0 16px;
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
|
||||||
|
&__name-item,
|
||||||
|
&__date-item {
|
||||||
|
width: 60%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-family: 'font_medium', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 0 0 0 23px;
|
||||||
|
color: #2a2a32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.creation-date {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__date-item {
|
||||||
|
width: 40%;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -51,6 +51,7 @@ import NoPaywallInfoBar from '@/components/noPaywallInfoBar/NoPaywallInfoBar.vue
|
|||||||
|
|
||||||
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
||||||
import { RouteConfig } from '@/router';
|
import { RouteConfig } from '@/router';
|
||||||
|
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||||
@ -87,6 +88,8 @@ const {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class DashboardArea extends Vue {
|
export default class DashboardArea extends Vue {
|
||||||
|
private FIRST_PAGE: number = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds router link to project dashboard page.
|
* Holds router link to project dashboard page.
|
||||||
*/
|
*/
|
||||||
@ -176,7 +179,7 @@ export default class DashboardArea extends Vue {
|
|||||||
let apiKeysPage: ApiKeysPage = new ApiKeysPage();
|
let apiKeysPage: ApiKeysPage = new ApiKeysPage();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
apiKeysPage = await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, 1);
|
apiKeysPage = await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.$notify.error(`Unable to fetch api keys. ${error.message}`);
|
await this.$notify.error(`Unable to fetch api keys. ${error.message}`);
|
||||||
}
|
}
|
||||||
@ -193,9 +196,15 @@ export default class DashboardArea extends Vue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||||
|
} catch (error) {
|
||||||
|
await this.$notify.error(`Unable to fetch api keys. ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
|
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch(PM_ACTIONS.FETCH, 1);
|
await this.$store.dispatch(PM_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.$notify.error(`Unable to fetch project members. ${error.message}`);
|
await this.$notify.error(`Unable to fetch project members. ${error.message}`);
|
||||||
}
|
}
|
||||||
@ -207,7 +216,7 @@ export default class DashboardArea extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, 1);
|
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await this.$notify.error(`Unable to fetch buckets. ${error.message}`);
|
await this.$notify.error(`Unable to fetch buckets. ${error.message}`);
|
||||||
}
|
}
|
||||||
|
BIN
web/satellite/static/images/accessGrants/vector.png
Normal file
BIN
web/satellite/static/images/accessGrants/vector.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 179 B |
Loading…
Reference in New Issue
Block a user