web/satellite/vuetify-poc: show file previews
This change enables files to be previewed. Issue: https://github.com/storj/storj/issues/6108 Change-Id: I3045950281822620de96b86e0180eb0d24e2d629
This commit is contained in:
parent
e2006d821c
commit
2d18f43b6a
@ -63,112 +63,7 @@
|
||||
</template>
|
||||
</v-data-table-server>
|
||||
|
||||
<v-dialog v-model="previewDialog" transition="fade-transition" class="preview-dialog" fullscreen theme="dark">
|
||||
<v-card class="preview-card">
|
||||
<v-carousel hide-delimiters show-arrows="hover" height="100vh">
|
||||
<template #prev="{ props: slotProps }">
|
||||
<v-btn
|
||||
color="default"
|
||||
class="rounded-circle"
|
||||
icon
|
||||
@click="slotProps.onClick"
|
||||
>
|
||||
<svg width="10" height="17" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_24843_332342)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.30725 8.23141C0.276805 7.67914 0.528501 7.04398 1.03164 6.54085L6.84563 0.726856C7.64837 -0.0758889 8.78719 -0.238577 9.38925 0.363481C9.99131 0.96554 9.82862 2.10436 9.02587 2.9071L3.71149 8.22148L9.02681 13.5368C9.82955 14.3395 9.99224 15.4784 9.39018 16.0804C8.78812 16.6825 7.6493 16.5198 6.84656 15.717L1.03257 9.90305C0.535173 9.40565 0.283513 8.77923 0.30725 8.23141Z" fill="white" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_24843_332342">
|
||||
<rect width="17.0002" height="10" fill="white" transform="translate(10) rotate(90)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</v-btn>
|
||||
</template>
|
||||
<template #next="{ props: slotProps }">
|
||||
<v-btn
|
||||
color="default"
|
||||
class="rounded-circle"
|
||||
icon
|
||||
@click="slotProps.onClick"
|
||||
>
|
||||
<svg width="10" height="17" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_24843_332338)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.69263 8.23141C9.72307 7.67914 9.47138 7.04398 8.96824 6.54085L3.15425 0.726856C2.35151 -0.0758889 1.21269 -0.238577 0.61063 0.363481C0.00857207 0.96554 0.17126 2.10436 0.974005 2.9071L6.28838 8.22148L0.973072 13.5368C0.170328 14.3395 0.00763934 15.4784 0.609698 16.0804C1.21176 16.6825 2.35057 16.5198 3.15332 15.717L8.96731 9.90305C9.46471 9.40565 9.71637 8.77923 9.69263 8.23141Z" fill="white" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_24843_332338">
|
||||
<rect width="17.0002" height="10" fill="white" transform="matrix(4.37114e-08 1 1 -4.37114e-08 0 0)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-toolbar
|
||||
color="rgba(0, 0, 0, 0.3)"
|
||||
theme="dark"
|
||||
>
|
||||
<!-- <v-img src="../assets/logo-white.svg" height="30" width="160" class="ml-3" alt="Storj Logo"/> -->
|
||||
<v-toolbar-title>
|
||||
Image.jpg
|
||||
</v-toolbar-title>
|
||||
<template #append>
|
||||
<v-btn icon size="small" color="white">
|
||||
<img src="@poc/assets/icon-download.svg" width="22" alt="Download">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Download
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<icon-share size="22" />
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Share
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<img src="@poc/assets/icon-geo-distribution.svg" width="22" alt="Geographic Distribution">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Geographic Distribution
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<img src="@poc/assets/icon-more.svg" width="22" alt="More">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
More
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white" @click="previewDialog = false">
|
||||
<img src="@poc/assets/icon-close.svg" width="18" alt="Close">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Close
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<!-- <v-btn icon="$close" color="white" size="small" @click="previewDialog = false"></v-btn> -->
|
||||
</template>
|
||||
</v-toolbar>
|
||||
<v-carousel-item
|
||||
v-for="(item,i) in items"
|
||||
:key="i"
|
||||
:src="item.src"
|
||||
/>
|
||||
</v-carousel>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<file-preview-dialog v-model="previewDialog" />
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
@ -178,13 +73,7 @@ import { useRouter } from 'vue-router';
|
||||
import {
|
||||
VCard,
|
||||
VTextField,
|
||||
VDialog,
|
||||
VCarousel,
|
||||
VBtn,
|
||||
VToolbar,
|
||||
VToolbarTitle,
|
||||
VTooltip,
|
||||
VCarouselItem,
|
||||
} from 'vuetify/components';
|
||||
import { VDataTableServer } from 'vuetify/labs/components';
|
||||
|
||||
@ -196,8 +85,8 @@ import { Size } from '@/utils/bytesSize';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
|
||||
import IconShare from '@poc/components/icons/IconShare.vue';
|
||||
import BrowserRowActions from '@poc/components/BrowserRowActions.vue';
|
||||
import FilePreviewDialog from '@poc/components/dialogs/FilePreviewDialog.vue';
|
||||
|
||||
import folderIcon from '@poc/assets/icon-folder-tonal.svg';
|
||||
import pdfIcon from '@poc/assets/icon-pdf-tonal.svg';
|
||||
@ -255,12 +144,6 @@ const selected = ref([]);
|
||||
const previewDialog = ref<boolean>(false);
|
||||
const options = ref<TableOptions>();
|
||||
|
||||
const items = [
|
||||
{ src: 'https://cdn.vuetifyjs.com/images/carousel/squirrel.jpg' },
|
||||
{ src: 'https://cdn.vuetifyjs.com/images/carousel/sky.jpg' },
|
||||
{ src: 'https://cdn.vuetifyjs.com/images/carousel/bird.jpg' },
|
||||
{ src: 'https://cdn.vuetifyjs.com/images/carousel/planet.jpg' },
|
||||
];
|
||||
const sortBy = [{ key: 'name', order: 'asc' }];
|
||||
const headers = [
|
||||
{
|
||||
@ -413,8 +296,7 @@ function onFileClick(file: BrowserObject): void {
|
||||
return;
|
||||
}
|
||||
|
||||
// Implement logic to fetch the file content for preview or generate a URL for preview
|
||||
// Then, open the preview dialog
|
||||
obStore.setObjectPathForModal(obStore.state.path + file.Key);
|
||||
previewDialog.value = true;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,256 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<v-dialog v-model="model" transition="fade-transition" class="preview-dialog" fullscreen theme="dark">
|
||||
<v-card class="preview-card">
|
||||
<v-carousel v-model="constCarouselIndex" hide-delimiters show-arrows="hover" height="100vh">
|
||||
<template #prev>
|
||||
<v-btn
|
||||
color="default"
|
||||
class="rounded-circle"
|
||||
icon
|
||||
@click="onPrevious"
|
||||
>
|
||||
<v-icon icon="mdi-chevron-left" size="x-large" />
|
||||
</v-btn>
|
||||
</template>
|
||||
<template #next>
|
||||
<v-btn
|
||||
color="default"
|
||||
class="rounded-circle"
|
||||
icon
|
||||
@click="onNext"
|
||||
>
|
||||
<v-icon icon="mdi-chevron-right" size="x-large" />
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-toolbar
|
||||
color="rgba(0, 0, 0, 0.3)"
|
||||
theme="dark"
|
||||
>
|
||||
<v-toolbar-title>
|
||||
{{ fileName }}
|
||||
</v-toolbar-title>
|
||||
<template #append>
|
||||
<v-btn :loading="isDownloading" icon size="small" color="white" @click="download">
|
||||
<img src="@poc/assets/icon-download.svg" width="22" alt="Download">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Download
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<icon-share size="22" />
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Share
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<img src="@poc/assets/icon-geo-distribution.svg" width="22" alt="Geographic Distribution">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Geographic Distribution
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white">
|
||||
<img src="@poc/assets/icon-more.svg" width="22" alt="More">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
More
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn icon size="small" color="white" @click="model = false">
|
||||
<img src="@poc/assets/icon-close.svg" width="18" alt="Close">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
Close
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-toolbar>
|
||||
|
||||
<v-carousel-item v-for="(file, i) in files" :key="file.Key">
|
||||
<!-- v-carousel will mount all items at the same time -->
|
||||
<!-- so :active will tell file-preview-item if it is the current. -->
|
||||
<!-- If it is, it'll load the preview. -->
|
||||
<file-preview-item :active="i === fileIndex" :file="file" @download="download" />
|
||||
</v-carousel-item>
|
||||
</v-carousel>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import {
|
||||
VBtn,
|
||||
VCard,
|
||||
VCarousel,
|
||||
VCarouselItem,
|
||||
VDialog,
|
||||
VIcon,
|
||||
VToolbar,
|
||||
VToolbarTitle,
|
||||
VTooltip,
|
||||
} from 'vuetify/components';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
import IconShare from '@poc/components/icons/IconShare.vue';
|
||||
import FilePreviewItem from '@poc/components/dialogs/filePreviewComponents/FilePreviewItem.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
const notify = useNotify();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const isDownloading = ref<boolean>(false);
|
||||
|
||||
const folderType = 'folder';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean,
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: boolean): void,
|
||||
}>();
|
||||
|
||||
const model = computed<boolean>({
|
||||
get: () => props.modelValue,
|
||||
set: value => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
const constCarouselIndex = computed(() => carouselIndex.value);
|
||||
const carouselIndex = ref(0);
|
||||
|
||||
/**
|
||||
* Retrieve the file object that the modal is set to from the store.
|
||||
*/
|
||||
const currentFile = computed((): BrowserObject => {
|
||||
return obStore.sortedFiles[fileIndex.value];
|
||||
});
|
||||
|
||||
const files = computed((): BrowserObject[] => {
|
||||
return obStore.sortedFiles;
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the file index that the modal is set to from the store.
|
||||
*/
|
||||
const fileIndex = computed((): number => {
|
||||
return files.value.findIndex(f => f.Key === filePath.value.split('/').pop());
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the name of the current file.
|
||||
*/
|
||||
const fileName = computed((): string | undefined => {
|
||||
return filePath.value.split('/').pop();
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the current filepath.
|
||||
*/
|
||||
const filePath = computed((): string => {
|
||||
return obStore.state.objectPathForModal;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns current path without object key.
|
||||
*/
|
||||
const currentPath = computed((): string => {
|
||||
return obStore.state.path;
|
||||
});
|
||||
|
||||
/**
|
||||
* Download the current opened file.
|
||||
*/
|
||||
async function download(): Promise<void> {
|
||||
if (isDownloading.value) {
|
||||
return;
|
||||
}
|
||||
isDownloading.value = true;
|
||||
try {
|
||||
await obStore.download(currentFile.value);
|
||||
notify.success('Keep this download link private. If you want to share, use the Share option.');
|
||||
} catch (error) {
|
||||
notify.error('Can not download your file', AnalyticsErrorEventSource.OBJECT_DETAILS_MODAL);
|
||||
}
|
||||
isDownloading.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles on previous click logic.
|
||||
*/
|
||||
function onPrevious(): void {
|
||||
const currentIndex = fileIndex.value;
|
||||
const sortedFilesLength = obStore.sortedFiles.length;
|
||||
|
||||
let newFile: BrowserObject;
|
||||
if (currentIndex <= 0) {
|
||||
newFile = obStore.sortedFiles[sortedFilesLength - 1];
|
||||
} else {
|
||||
newFile = obStore.sortedFiles[currentIndex - 1];
|
||||
if (newFile.type === folderType) {
|
||||
newFile = obStore.sortedFiles[sortedFilesLength - 1];
|
||||
}
|
||||
}
|
||||
setNewObjectPath(newFile.Key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles on next click logic.
|
||||
*/
|
||||
function onNext(): void {
|
||||
let newFile: BrowserObject | undefined = obStore.sortedFiles[fileIndex.value + 1];
|
||||
if (!newFile || newFile.type === folderType) {
|
||||
newFile = obStore.sortedFiles.find(f => f.type !== folderType);
|
||||
|
||||
if (!newFile) return;
|
||||
}
|
||||
setNewObjectPath(newFile.Key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new object path.
|
||||
*/
|
||||
function setNewObjectPath(objectKey: string): void {
|
||||
obStore.setObjectPathForModal(`${currentPath.value}${objectKey}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch for changes on the filepath and changes the current carousel item accordingly.
|
||||
*/
|
||||
watch(filePath, () => {
|
||||
if (!filePath.value) return;
|
||||
|
||||
carouselIndex.value = fileIndex.value;
|
||||
});
|
||||
|
||||
watch(() => props.modelValue, shown => {
|
||||
if (!shown) {
|
||||
return;
|
||||
}
|
||||
carouselIndex.value = fileIndex.value;
|
||||
}, { immediate: true });
|
||||
</script>
|
@ -0,0 +1,227 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<v-container v-if="isLoading" class="fill-height flex-column justify-center align-center">
|
||||
<v-progress-circular indeterminate />
|
||||
</v-container>
|
||||
<v-container v-else-if="previewIsVideo" class="fill-height flex-column justify-center align-center">
|
||||
<video
|
||||
controls
|
||||
:src="objectPreviewUrl"
|
||||
style="max-width: 100%; max-height: 90%;"
|
||||
aria-roledescription="video-preview"
|
||||
/>
|
||||
</v-container>
|
||||
<v-container v-else-if="previewIsAudio" class="fill-height flex-column justify-center align-center">
|
||||
<audio
|
||||
controls
|
||||
:src="objectPreviewUrl"
|
||||
aria-roledescription="audio-preview"
|
||||
/>
|
||||
</v-container>
|
||||
<v-container v-else-if="previewIsImage" class="fill-height flex-column justify-center align-center">
|
||||
<img
|
||||
v-if="objectPreviewUrl"
|
||||
:src="objectPreviewUrl"
|
||||
class="v-img__img v-img__img--contain"
|
||||
aria-roledescription="image-preview"
|
||||
alt="preview"
|
||||
>
|
||||
</v-container>
|
||||
<v-container v-else-if="placeHolderDisplayable || previewAndMapFailed" class="fill-height flex-column justify-center align-center">
|
||||
<p class="mb-5">{{ file?.Key || '' }}</p>
|
||||
<p class="text-h5 mb-5 font-weight-bold">No preview available</p>
|
||||
<v-btn
|
||||
@click="() => emits('download')"
|
||||
>
|
||||
<template #prepend>
|
||||
<img src="@poc/assets/icon-download.svg" width="22" alt="Download">
|
||||
</template>
|
||||
{{ `Download (${prettyBytes(file?.Size || 0)})` }}
|
||||
</v-btn>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { VBtn, VContainer, VProgressCircular } from 'vuetify/components';
|
||||
import { useRoute } from 'vue-router';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { BrowserObject, PreviewCache, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useLinksharing } from '@/composables/useLinksharing';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
const notify = useNotify();
|
||||
const { generateObjectPreviewAndMapURL } = useLinksharing();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const isLoading = ref<boolean>(false);
|
||||
const previewAndMapFailed = ref<boolean>(false);
|
||||
|
||||
const imgExts = ['bmp', 'svg', 'jpg', 'jpeg', 'png', 'ico', 'gif'];
|
||||
const videoExts = ['m4v', 'mp4', 'webm', 'mov', 'mkv'];
|
||||
const audioExts = ['m4a', 'mp3', 'wav', 'ogg'];
|
||||
|
||||
const props = defineProps<{
|
||||
file: BrowserObject,
|
||||
active: boolean, // whether this item is visible
|
||||
}>();
|
||||
|
||||
const emits = defineEmits(['download']);
|
||||
|
||||
/**
|
||||
* Returns object preview URLs cache from store.
|
||||
*/
|
||||
const cachedObjectPreviewURLs = computed((): Map<string, PreviewCache> => {
|
||||
return obStore.state.cachedObjectPreviewURLs;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns object preview URL from cache.
|
||||
*/
|
||||
const objectPreviewUrl = computed((): string => {
|
||||
const cache = cachedObjectPreviewURLs.value.get(encodedFilePath.value);
|
||||
const url = cache?.url || '';
|
||||
return `${url}?view=1`;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns bucket name from store.
|
||||
*/
|
||||
const bucket = computed((): string => {
|
||||
return bucketsStore.state.fileComponentBucketName;
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the current filepath.
|
||||
*/
|
||||
const filePath = computed((): string => {
|
||||
return obStore.state.objectPathForModal;
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the encoded filepath.
|
||||
*/
|
||||
const encodedFilePath = computed((): string => {
|
||||
return encodeURIComponent(`${bucket.value}/${filePath.value.trim()}`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the extension of the current file.
|
||||
*/
|
||||
const extension = computed((): string | undefined => {
|
||||
return filePath.value.split('.').pop();
|
||||
});
|
||||
|
||||
/**
|
||||
* Check to see if the current file is an image file.
|
||||
*/
|
||||
const previewIsImage = computed((): boolean => {
|
||||
if (!extension.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return imgExts.includes(extension.value.toLowerCase());
|
||||
});
|
||||
|
||||
/**
|
||||
* Check to see if the current file is a video file.
|
||||
*/
|
||||
const previewIsVideo = computed((): boolean => {
|
||||
if (!extension.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return videoExts.includes(extension.value.toLowerCase());
|
||||
});
|
||||
|
||||
/**
|
||||
* Check to see if the current file is an audio file.
|
||||
*/
|
||||
const previewIsAudio = computed((): boolean => {
|
||||
if (!extension.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return audioExts.includes(extension.value.toLowerCase());
|
||||
});
|
||||
|
||||
/**
|
||||
* Check to see if the current file is neither an image file, video file, or audio file.
|
||||
*/
|
||||
const placeHolderDisplayable = computed((): boolean => {
|
||||
return [
|
||||
previewIsImage.value,
|
||||
previewIsVideo.value,
|
||||
previewIsAudio.value,
|
||||
].every((value) => !value);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the object map url for the file being displayed.
|
||||
*/
|
||||
async function fetchPreviewAndMapUrl(): Promise<void> {
|
||||
isLoading.value = true;
|
||||
previewAndMapFailed.value = false;
|
||||
|
||||
let url = '';
|
||||
try {
|
||||
url = await generateObjectPreviewAndMapURL(
|
||||
bucketsStore.state.fileComponentBucketName, filePath.value);
|
||||
} catch (error) {
|
||||
error.message = `Unable to get file preview and map URL. ${error.message}`;
|
||||
notify.notifyError(error, AnalyticsErrorEventSource.GALLERY_VIEW);
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
previewAndMapFailed.value = true;
|
||||
isLoading.value = false;
|
||||
return;
|
||||
}
|
||||
obStore.cacheObjectPreviewURL(encodedFilePath.value, { url, lastModified: props.file.LastModified.getTime() });
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads object URL from cache or generates new URL.
|
||||
*/
|
||||
function processFilePath(): void {
|
||||
const url = findCachedURL();
|
||||
if (!url) {
|
||||
fetchPreviewAndMapUrl();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find current object path in cache.
|
||||
*/
|
||||
function findCachedURL(): string | undefined {
|
||||
const cache = cachedObjectPreviewURLs.value.get(encodedFilePath.value);
|
||||
|
||||
if (!cache) return undefined;
|
||||
|
||||
if (cache.lastModified !== props.file.LastModified.getTime()) {
|
||||
obStore.removeFromObjectPreviewCache(encodedFilePath.value);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return cache.url;
|
||||
}
|
||||
|
||||
watch(() => props.active, active => {
|
||||
if (active) {
|
||||
processFilePath();
|
||||
}
|
||||
}, { immediate: true });
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user