web/satellite/vuetify-poc: enable object browser pagination
Enabled object browser pagination for vuetify app. Also fixed some small bug when returning to first page. Issue: https://github.com/storj/storj/issues/5595 Change-Id: I8b5e90a4cd7d7a79a8beeb292b7374db3f93d700
This commit is contained in:
parent
2bf4113821
commit
9254dd2208
@ -458,7 +458,7 @@ function changePageAndLimit(page: number, limit: number): void {
|
|||||||
|
|
||||||
const tokenToBeFetched = obStore.state.continuationTokens.get(tokenKey);
|
const tokenToBeFetched = obStore.state.continuationTokens.get(tokenKey);
|
||||||
if (!tokenToBeFetched) {
|
if (!tokenToBeFetched) {
|
||||||
obStore.listByToken(routePath.value, 1, tokenToBeFetched);
|
obStore.initList(routePath.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +292,8 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
|||||||
const { Contents, CommonPrefixes } = response;
|
const { Contents, CommonPrefixes } = response;
|
||||||
|
|
||||||
processFetchedObjects(path, Contents, CommonPrefixes);
|
processFetchedObjects(path, Contents, CommonPrefixes);
|
||||||
|
|
||||||
|
state.activeObjectsRange = { start: 1, end: MAX_KEY_COUNT };
|
||||||
}
|
}
|
||||||
|
|
||||||
keyCount += response.KeyCount ?? 0;
|
keyCount += response.KeyCount ?? 0;
|
||||||
@ -305,7 +307,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
|||||||
state.totalObjectCount = keyCount;
|
state.totalObjectCount = keyCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listByToken(path: string, key: number, continuationToken?: string): Promise<void> {
|
async function listByToken(path: string, key: number, continuationToken: string): Promise<void> {
|
||||||
assertIsInitialized(state);
|
assertIsInitialized(state);
|
||||||
|
|
||||||
const input: ListObjectsV2CommandInput = {
|
const input: ListObjectsV2CommandInput = {
|
||||||
@ -321,10 +323,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
|||||||
|
|
||||||
processFetchedObjects(path, Contents, CommonPrefixes);
|
processFetchedObjects(path, Contents, CommonPrefixes);
|
||||||
|
|
||||||
state.activeObjectsRange = {
|
state.activeObjectsRange = { start: key - MAX_KEY_COUNT, end: key };
|
||||||
start: key === 1 ? key : key - MAX_KEY_COUNT,
|
|
||||||
end: key === 1 ? MAX_KEY_COUNT : key,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function processFetchedObjects(path: string, Contents: _Object[] | undefined, CommonPrefixes: CommonPrefix[] | undefined): void {
|
function processFetchedObjects(path: string, Contents: _Object[] | undefined, CommonPrefixes: CommonPrefix[] | undefined): void {
|
||||||
|
@ -43,14 +43,14 @@ export type UUID = string
|
|||||||
export type MemorySize = string
|
export type MemorySize = string
|
||||||
export type Time = string
|
export type Time = string
|
||||||
|
|
||||||
export function tableSizeOptions(itemCount: number): {title: string, value: number}[] {
|
export function tableSizeOptions(itemCount: number, isObjectBrowser = false): {title: string, value: number}[] {
|
||||||
const opts = [
|
const opts = [
|
||||||
{ title: '10', value: 10 },
|
{ title: '10', value: 10 },
|
||||||
{ title: '25', value: 25 },
|
{ title: '25', value: 25 },
|
||||||
{ title: '50', value: 50 },
|
{ title: '50', value: 50 },
|
||||||
{ title: '100', value: 100 },
|
{ title: '100', value: 100 },
|
||||||
];
|
];
|
||||||
if (itemCount < 1000) {
|
if (itemCount < 1000 && !isObjectBrowser) {
|
||||||
return [{ title: 'All', value: itemCount }, ...opts];
|
return [{ title: 'All', value: itemCount }, ...opts];
|
||||||
}
|
}
|
||||||
return opts;
|
return opts;
|
||||||
|
@ -30,7 +30,10 @@
|
|||||||
hover
|
hover
|
||||||
must-sort
|
must-sort
|
||||||
:loading="isFetching || loading"
|
:loading="isFetching || loading"
|
||||||
:items-length="allFiles.length"
|
:items-length="isPaginationEnabled ? totalObjectCount : allFiles.length"
|
||||||
|
:items-per-page-options="isPaginationEnabled ? tableSizeOptions(totalObjectCount, true) : undefined"
|
||||||
|
@update:page="onPageChange"
|
||||||
|
@update:itemsPerPage="onLimitChange"
|
||||||
>
|
>
|
||||||
<template #item.name="{ item }: ItemSlotProps">
|
<template #item.name="{ item }: ItemSlotProps">
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -77,13 +80,20 @@ import {
|
|||||||
} from 'vuetify/components';
|
} from 'vuetify/components';
|
||||||
import { VDataTableServer } from 'vuetify/labs/components';
|
import { VDataTableServer } from 'vuetify/labs/components';
|
||||||
|
|
||||||
import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
import {
|
||||||
|
BrowserObject,
|
||||||
|
MAX_KEY_COUNT,
|
||||||
|
ObjectBrowserCursor,
|
||||||
|
useObjectBrowserStore,
|
||||||
|
} from '@/store/modules/objectBrowserStore';
|
||||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||||
import { useNotify } from '@/utils/hooks';
|
import { useNotify } from '@/utils/hooks';
|
||||||
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
||||||
import { Size } from '@/utils/bytesSize';
|
import { Size } from '@/utils/bytesSize';
|
||||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||||
|
import { useConfigStore } from '@/store/modules/configStore';
|
||||||
|
import { tableSizeOptions } from '@/types/common';
|
||||||
|
|
||||||
import BrowserRowActions from '@poc/components/BrowserRowActions.vue';
|
import BrowserRowActions from '@poc/components/BrowserRowActions.vue';
|
||||||
import FilePreviewDialog from '@poc/components/dialogs/FilePreviewDialog.vue';
|
import FilePreviewDialog from '@poc/components/dialogs/FilePreviewDialog.vue';
|
||||||
@ -131,6 +141,7 @@ const props = defineProps<{
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const config = useConfigStore();
|
||||||
const obStore = useObjectBrowserStore();
|
const obStore = useObjectBrowserStore();
|
||||||
const projectsStore = useProjectsStore();
|
const projectsStore = useProjectsStore();
|
||||||
const bucketsStore = useBucketsStore();
|
const bucketsStore = useBucketsStore();
|
||||||
@ -180,12 +191,29 @@ const bucketName = computed<string>(() => bucketsStore.state.fileComponentBucket
|
|||||||
*/
|
*/
|
||||||
const filePath = computed<string>(() => bucketsStore.state.fileComponentPath);
|
const filePath = computed<string>(() => bucketsStore.state.fileComponentPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns total object count from store.
|
||||||
|
*/
|
||||||
|
const isPaginationEnabled = computed<boolean>(() => config.state.config.objectBrowserPaginationEnabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns total object count from store.
|
||||||
|
*/
|
||||||
|
const totalObjectCount = computed<number>(() => obStore.state.totalObjectCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns table cursor from store.
|
||||||
|
*/
|
||||||
|
const cursor = computed<ObjectBrowserCursor>(() => obStore.state.cursor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns every file under the current path.
|
* Returns every file under the current path.
|
||||||
*/
|
*/
|
||||||
const allFiles = computed<BrowserObjectWrapper[]>(() => {
|
const allFiles = computed<BrowserObjectWrapper[]>(() => {
|
||||||
if (props.forceEmpty) return [];
|
if (props.forceEmpty) return [];
|
||||||
return obStore.state.files.map<BrowserObjectWrapper>(file => {
|
|
||||||
|
const objects = isPaginationEnabled.value ? obStore.displayedObjects : obStore.state.files;
|
||||||
|
return objects.map<BrowserObjectWrapper>(file => {
|
||||||
const lowerName = file.Key.toLowerCase();
|
const lowerName = file.Key.toLowerCase();
|
||||||
const dotIdx = lowerName.indexOf('.');
|
const dotIdx = lowerName.indexOf('.');
|
||||||
const ext = dotIdx === -1 ? '' : file.Key.slice(dotIdx + 1);
|
const ext = dotIdx === -1 ? '' : file.Key.slice(dotIdx + 1);
|
||||||
@ -243,11 +271,43 @@ const tableFiles = computed<BrowserObjectWrapper[]>(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.itemsPerPage === -1) return files;
|
if (opts.itemsPerPage === -1 || isPaginationEnabled.value) return files;
|
||||||
|
|
||||||
return files.slice((opts.page - 1) * opts.itemsPerPage, opts.page * opts.itemsPerPage);
|
return files.slice((opts.page - 1) * opts.itemsPerPage, opts.page * opts.itemsPerPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles page change event.
|
||||||
|
*/
|
||||||
|
function onPageChange(page: number): void {
|
||||||
|
obStore.setCursor({ page, limit: options.value?.itemsPerPage ?? 10 });
|
||||||
|
|
||||||
|
const lastObjectOnPage = page * cursor.value.limit;
|
||||||
|
const activeRange = obStore.state.activeObjectsRange;
|
||||||
|
|
||||||
|
if (lastObjectOnPage > activeRange.start && lastObjectOnPage <= activeRange.end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = filePath.value ? filePath.value + '/' : '';
|
||||||
|
const tokenKey = Math.ceil(lastObjectOnPage / MAX_KEY_COUNT) * MAX_KEY_COUNT;
|
||||||
|
|
||||||
|
const tokenToBeFetched = obStore.state.continuationTokens.get(tokenKey);
|
||||||
|
if (!tokenToBeFetched) {
|
||||||
|
obStore.initList(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obStore.listByToken(path, tokenKey, tokenToBeFetched);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles items per page change event.
|
||||||
|
*/
|
||||||
|
function onLimitChange(newLimit: number): void {
|
||||||
|
obStore.setCursor({ page: options.value?.page ?? 1, limit: newLimit });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string form of the file's last modified date.
|
* Returns the string form of the file's last modified date.
|
||||||
*/
|
*/
|
||||||
@ -308,7 +368,14 @@ async function fetchFiles(): Promise<void> {
|
|||||||
isFetching.value = true;
|
isFetching.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await obStore.list(filePath.value ? filePath.value + '/' : '');
|
const path = filePath.value ? filePath.value + '/' : '';
|
||||||
|
|
||||||
|
if (isPaginationEnabled.value) {
|
||||||
|
await obStore.initList(path);
|
||||||
|
} else {
|
||||||
|
await obStore.list(path);
|
||||||
|
}
|
||||||
|
|
||||||
selected.value = [];
|
selected.value = [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.message = `Error fetching files. ${err.message}`;
|
err.message = `Error fetching files. ${err.message}`;
|
||||||
|
Loading…
Reference in New Issue
Block a user