web/satellite/vuetify-poc: allow file browser downloads

This change allows files to be downloaded from within the file browser
of the Vuetify project.

Resolves #6107

Change-Id: I0ac0384711baccb99c0a6d382fe96f318290789b
This commit is contained in:
Jeremy Wharton 2023-08-30 15:47:25 -05:00 committed by Storj Robot
parent b671641a28
commit 28d498f91d
4 changed files with 142 additions and 85 deletions

View File

@ -666,7 +666,7 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
clearAllSelectedFiles();
}
async function download(file): Promise<void> {
async function download(file: BrowserObject): Promise<void> {
assertIsInitialized(state);
const url = await getSignedUrl(state.s3, new GetObjectCommand({

View File

@ -1,55 +0,0 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<v-menu activator="parent">
<v-list class="pa-2">
<v-list-item density="comfortable" link rounded="lg">
<template #prepend>
<icon-preview />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Preview
</v-list-item-title>
</v-list-item>
<v-list-item density="comfortable" link rounded="lg">
<template #prepend>
<icon-download />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Download
</v-list-item-title>
</v-list-item>
<v-list-item density="comfortable" link rounded="lg">
<template #prepend>
<icon-share bold />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Share
</v-list-item-title>
</v-list-item>
<v-divider class="my-2" />
<v-list-item density="comfortable" link rounded="lg" base-color="error">
<template #prepend>
<icon-trash bold />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Delete
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
<script setup lang="ts">
import { VMenu, VList, VListItem, VListItemTitle, VDivider } from 'vuetify/components';
import IconDownload from '@poc/components/icons/IconDownload.vue';
import IconShare from '@poc/components/icons/IconShare.vue';
import IconPreview from '@poc/components/icons/IconPreview.vue';
import IconTrash from '@poc/components/icons/IconTrash.vue';
</script>

View File

@ -0,0 +1,138 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="text-no-wrap text-right">
<v-btn
v-if="file.type !== 'folder'"
variant="outlined"
color="default"
size="small"
class="mr-1 text-caption"
density="comfortable"
icon
:loading="isDownloading"
@click="onDownloadClick"
>
<icon-download />
<v-tooltip activator="parent" location="start">Download</v-tooltip>
</v-btn>
<v-btn
variant="outlined"
color="default"
size="small"
class="mr-1 text-caption"
density="comfortable"
icon
>
<v-icon icon="mdi-dots-horizontal" />
<v-menu activator="parent">
<v-list class="pa-2">
<template v-if="file.type !== 'folder'">
<v-list-item density="comfortable" link rounded="lg">
<template #prepend>
<icon-preview />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Preview
</v-list-item-title>
</v-list-item>
<v-list-item
density="comfortable"
:link="!isDownloading"
rounded="lg"
@click="onDownloadClick"
>
<template #prepend>
<icon-download />
</template>
<v-fade-transition>
<v-list-item-title v-show="!isDownloading" class="pl-2 text-body-2 font-weight-medium">
Download
</v-list-item-title>
</v-fade-transition>
<div v-if="isDownloading" class="browser_actions_menu__loader">
<v-progress-circular indeterminate size="23" width="2" />
</div>
</v-list-item>
</template>
<v-list-item density="comfortable" link rounded="lg">
<template #prepend>
<icon-share bold />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Share
</v-list-item-title>
</v-list-item>
<v-divider class="my-2" />
<v-list-item density="comfortable" link rounded="lg" base-color="error">
<template #prepend>
<icon-trash bold />
</template>
<v-list-item-title class="pl-2 text-body-2 font-weight-medium">
Delete
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-btn>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import {
VMenu,
VList,
VListItem,
VListItemTitle,
VDivider,
VProgressCircular,
VFadeTransition,
VIcon,
VBtn,
VTooltip,
} from 'vuetify/components';
import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
import { useNotify } from '@/utils/hooks';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import IconDownload from '@poc/components/icons/IconDownload.vue';
import IconShare from '@poc/components/icons/IconShare.vue';
import IconPreview from '@poc/components/icons/IconPreview.vue';
import IconTrash from '@poc/components/icons/IconTrash.vue';
const obStore = useObjectBrowserStore();
const notify = useNotify();
const props = defineProps<{
file: BrowserObject;
}>();
const isDownloading = ref<boolean>(false);
async function onDownloadClick(): Promise<void> {
isDownloading.value = true;
await obStore.download(props.file).catch((err: Error) => {
err.message = `Error downloading file. ${err.message}`;
notify.notifyError(err, AnalyticsErrorEventSource.FILE_BROWSER_ENTRY);
});
isDownloading.value = false;
}
</script>
<style scoped lang="scss">
.browser_actions_menu__loader {
inset: 0;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -58,32 +58,8 @@
{{ getFormattedDate(item.raw.browserObject) }}
</template>
<template #item.actions>
<div class="text-no-wrap">
<v-btn
variant="outlined"
color="default"
size="small"
class="mr-1 text-caption"
density="comfortable"
icon
>
<icon-download />
<v-tooltip activator="parent" location="start">Download</v-tooltip>
</v-btn>
<v-btn
variant="outlined"
color="default"
size="small"
class="mr-1 text-caption"
density="comfortable"
icon
>
<browser-actions-menu />
<v-icon icon="mdi-dots-horizontal" />
</v-btn>
</div>
<template #item.actions="{ item }: ItemSlotProps">
<browser-row-actions :file="item.raw.browserObject" />
</template>
</v-data-table-server>
@ -209,7 +185,6 @@ import {
VToolbarTitle,
VTooltip,
VCarouselItem,
VIcon,
} from 'vuetify/components';
import { VDataTableServer } from 'vuetify/labs/components';
@ -222,8 +197,7 @@ import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames
import { useBucketsStore } from '@/store/modules/bucketsStore';
import IconShare from '@poc/components/icons/IconShare.vue';
import IconDownload from '@poc/components/icons/IconDownload.vue';
import BrowserActionsMenu from '@poc/components/BrowserActionsMenu.vue';
import BrowserRowActions from '@poc/components/BrowserRowActions.vue';
import folderIcon from '@poc/assets/icon-folder-tonal.svg';
import pdfIcon from '@poc/assets/icon-pdf-tonal.svg';