web/satellite: unmock list buckets in vuetify app
This change implements the table on the buckets view of the vuetify app. Searching and pagination are implemented, but sorting functionality needs to be added in a separate change - we need to extend the bucketsStore/backend functionality in order to support sorting. Resolves https://github.com/storj/storj/issues/6062 Change-Id: I4e92e6facbd7b21f4ec081e41f7e568ddb3cea29
This commit is contained in:
parent
16c5b3c340
commit
7487809476
@ -11,45 +11,161 @@
|
||||
hide-details
|
||||
/>
|
||||
|
||||
<v-data-table
|
||||
<v-data-table-server
|
||||
v-model="selected"
|
||||
:sort-by="sortBy"
|
||||
:headers="headers"
|
||||
:items="buckets"
|
||||
:items="page.buckets"
|
||||
:search="search"
|
||||
:loading="areBucketsFetching"
|
||||
:items-length="page.totalCount"
|
||||
:items-per-page-options="tableSizeOptions(page.totalCount)"
|
||||
item-value="name"
|
||||
class="elevation-1"
|
||||
show-select
|
||||
@update:itemsPerPage="onUpdateLimit"
|
||||
@update:page="onUpdatePage"
|
||||
>
|
||||
<template #item.name="{ item }">
|
||||
<div>
|
||||
<v-btn
|
||||
class="rounded-lg w-100 pl-1 pr-4 justify-start font-weight-bold"
|
||||
class="rounded-lg w-100 pl-1 pr-4 justify-start font-weight-bold text-lowercase"
|
||||
variant="text"
|
||||
height="40"
|
||||
color="default"
|
||||
to="/bucket"
|
||||
@click="openBucket(item.raw.name)"
|
||||
>
|
||||
<img src="../assets/icon-bucket-tonal.svg" alt="Bucket" class="mr-3">
|
||||
{{ item.raw.name }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
<template #item.storage="{ item }">
|
||||
<span>
|
||||
{{ item.raw.storage.toFixed(2) + 'GB' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #item.egress="{ item }">
|
||||
<span>
|
||||
{{ item.raw.egress.toFixed(2) + 'GB' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #item.objectCount="{ item }">
|
||||
<span>
|
||||
{{ item.raw.objectCount.toLocaleString() }}
|
||||
</span>
|
||||
</template>
|
||||
<template #item.segmentCount="{ item }">
|
||||
<span>
|
||||
{{ item.raw.segmentCount.toLocaleString() }}
|
||||
</span>
|
||||
</template>
|
||||
<template #item.createdAt="{ item }">
|
||||
<span>
|
||||
{{ item.raw.since.toLocaleString() }}
|
||||
</span>
|
||||
</template>
|
||||
</v-data-table-server>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ref, watch, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { VCard, VTextField, VBtn } from 'vuetify/components';
|
||||
import { VDataTable } from 'vuetify/labs/components';
|
||||
import { VDataTableServer } from 'vuetify/labs/components';
|
||||
|
||||
const props = defineProps<{
|
||||
headers: unknown[],
|
||||
buckets: unknown[],
|
||||
}>();
|
||||
import { BucketPage, BucketCursor } from '@/types/buckets';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { DEFAULT_PAGE_LIMIT } from '@/types/pagination';
|
||||
import { tableSizeOptions } from '@/types/common';
|
||||
|
||||
const bucketsStore = useBucketsStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const notify = useNotify();
|
||||
const router = useRouter();
|
||||
|
||||
const FIRST_PAGE = 1;
|
||||
const areBucketsFetching = ref<boolean>(true);
|
||||
const search = ref<string>('');
|
||||
const searchTimer = ref<NodeJS.Timeout>();
|
||||
const selected = ref([]);
|
||||
|
||||
const sortBy = [{ key: 'date', order: 'asc' }];
|
||||
const headers = [
|
||||
{
|
||||
title: 'Name',
|
||||
align: 'start',
|
||||
key: 'name',
|
||||
sortable: false,
|
||||
},
|
||||
{ title: 'Storage', key: 'storage', sortable: false },
|
||||
{ title: 'Egress', key: 'egress', sortable: false },
|
||||
{ title: 'Objects', key: 'objectCount', sortable: false },
|
||||
{ title: 'Segments', key: 'segmentCount', sortable: false },
|
||||
{ title: 'Date Created', key: 'createdAt', sortable: false },
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns buckets cursor from store.
|
||||
*/
|
||||
const cursor = computed((): BucketCursor => {
|
||||
return bucketsStore.state.cursor;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns buckets page from store.
|
||||
*/
|
||||
const page = computed((): BucketPage => {
|
||||
return bucketsStore.state.page;
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetches bucket using api.
|
||||
*/
|
||||
async function fetchBuckets(page = FIRST_PAGE, limit = DEFAULT_PAGE_LIMIT): Promise<void> {
|
||||
try {
|
||||
await bucketsStore.getBuckets(page, projectsStore.state.selectedProject.id, limit);
|
||||
if (areBucketsFetching.value) areBucketsFetching.value = false;
|
||||
} catch (error) {
|
||||
notify.error(`Unable to fetch buckets. ${error.message}`, AnalyticsErrorEventSource.BUCKET_TABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles update table rows limit event.
|
||||
*/
|
||||
function onUpdateLimit(limit: number): void {
|
||||
fetchBuckets(page.value.currentPage, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles update table page event.
|
||||
*/
|
||||
function onUpdatePage(page: number): void {
|
||||
fetchBuckets(page, cursor.value.limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles update table search.
|
||||
*/
|
||||
watch(() => search.value, () => {
|
||||
clearTimeout(searchTimer.value);
|
||||
|
||||
searchTimer.value = setTimeout(() => {
|
||||
bucketsStore.setBucketsSearch(search.value);
|
||||
fetchBuckets();
|
||||
}, 500); // 500ms delay for every new call.
|
||||
});
|
||||
|
||||
/**
|
||||
* Navigates to bucket page.
|
||||
*/
|
||||
function openBucket(bucketName: string): void {
|
||||
router.push(`/projects/${projectsStore.state.selectedProject.id}/buckets/${bucketName}`);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchBuckets();
|
||||
});
|
||||
</script>
|
||||
|
@ -58,9 +58,9 @@ const routes: RouteRecordRaw[] = [
|
||||
component: () => import(/* webpackChunkName: "Buckets" */ '@poc/views/Buckets.vue'),
|
||||
},
|
||||
{
|
||||
path: 'bucket',
|
||||
path: 'buckets/:bucketName',
|
||||
name: 'Bucket',
|
||||
component: () => import(/* webpackChunkName: "Buckets" */ '@poc/views/Bucket.vue'),
|
||||
component: () => import(/* webpackChunkName: "Bucket" */ '@poc/views/Bucket.vue'),
|
||||
},
|
||||
{
|
||||
path: 'access',
|
||||
|
@ -87,7 +87,7 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<BucketsDataTable :headers="headers" :buckets="buckets" />
|
||||
<BucketsDataTable />
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
@ -126,38 +126,4 @@ const bucketNameRules = [
|
||||
return true;
|
||||
},
|
||||
];
|
||||
const headers = [
|
||||
{
|
||||
title: 'Name',
|
||||
align: 'start',
|
||||
key: 'name',
|
||||
},
|
||||
{ title: 'Files', key: 'files' },
|
||||
{ title: 'Storage', key: 'storage' },
|
||||
{ title: 'Bandwidth', key: 'bandwidth' },
|
||||
{ title: 'Date Created', key: 'date' },
|
||||
];
|
||||
const buckets = [
|
||||
{
|
||||
name: 'Demo',
|
||||
date: '02 Mar 2023',
|
||||
files: '4,210',
|
||||
bandwidth: '481 MB',
|
||||
storage: '32 GB',
|
||||
},
|
||||
{
|
||||
name: 'Photos',
|
||||
date: '03 Mar 2023',
|
||||
files: '92,155',
|
||||
bandwidth: '2.0 GB',
|
||||
storage: '5.2 GB',
|
||||
},
|
||||
{
|
||||
name: 'Videos',
|
||||
date: '04 Mar 2023',
|
||||
files: '24',
|
||||
bandwidth: '102 MB',
|
||||
storage: '1.7 TB',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user