web/satellite: add folder sharing
This change allows users to generate links for sharing folders. Previously, users were only able to do this with files and buckets. Resolves #5644 Change-Id: I16dd8270337e3561b6bda895b46d3cc9be5f8041
This commit is contained in:
parent
5fc6eaab17
commit
074457fa4e
@ -81,6 +81,11 @@
|
||||
/>
|
||||
<dots-icon v-else />
|
||||
<div v-if="dropdownOpen" class="file-entry__functional__dropdown">
|
||||
<div class="file-entry__functional__dropdown__item" @click.stop="share">
|
||||
<share-icon />
|
||||
<p class="file-entry__functional__dropdown__item__label">Share</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!deleteConfirmation" class="file-entry__functional__dropdown__item"
|
||||
@click.stop="confirmDeletion"
|
||||
@ -125,6 +130,7 @@ import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { ObjectType } from '@/utils/objectIcon';
|
||||
import { ShareType } from '@/types/browser';
|
||||
|
||||
import TableItem from '@/components/common/TableItem.vue';
|
||||
|
||||
@ -390,7 +396,8 @@ function setShiftSelectedFiles(): void {
|
||||
function share(): void {
|
||||
obStore.closeDropdown();
|
||||
obStore.setObjectPathForModal(props.path + props.file.Key);
|
||||
appStore.updateActiveModal(MODALS.shareObject);
|
||||
appStore.setShareModalType(props.file.type === 'file' ? ShareType.File : ShareType.Folder);
|
||||
appStore.updateActiveModal(MODALS.share);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@
|
||||
<ButtonIcon
|
||||
class="gallery__header__functional__item"
|
||||
:icon="ShareIcon"
|
||||
:on-press="() => setActiveModal(ShareModal)"
|
||||
:on-press="showShareModal"
|
||||
info="Share"
|
||||
/>
|
||||
<ButtonIcon
|
||||
@ -48,7 +48,7 @@
|
||||
:on-distribution="() => setActiveModal(DistributionModal)"
|
||||
:on-view-details="() => setActiveModal(DetailsModal)"
|
||||
:on-download="download"
|
||||
:on-share="() => setActiveModal(ShareModal)"
|
||||
:on-share="showShareModal"
|
||||
:on-delete="() => setActiveModal(DeleteModal)"
|
||||
/>
|
||||
</div>
|
||||
@ -121,12 +121,14 @@ import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useLinksharing } from '@/composables/useLinksharing';
|
||||
import { RouteConfig } from '@/types/router';
|
||||
import { ShareType } from '@/types/browser';
|
||||
|
||||
import ButtonIcon from '@/components/browser/galleryView/ButtonIcon.vue';
|
||||
import OptionsDropdown from '@/components/browser/galleryView/OptionsDropdown.vue';
|
||||
import DeleteModal from '@/components/browser/galleryView/modals/Delete.vue';
|
||||
import ShareModal from '@/components/browser/galleryView/modals/Share.vue';
|
||||
import ShareModal from '@/components/modals/ShareModal.vue';
|
||||
import DetailsModal from '@/components/browser/galleryView/modals/Details.vue';
|
||||
import DistributionModal from '@/components/browser/galleryView/modals/Distribution.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
@ -148,6 +150,7 @@ const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
const notify = useNotify();
|
||||
const { generateObjectPreviewAndMapURL } = useLinksharing();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
@ -182,13 +185,6 @@ const fileIndex = computed((): number => {
|
||||
return obStore.sortedFiles.findIndex(f => f.Key === filePath.value.split('/').pop());
|
||||
});
|
||||
|
||||
/**
|
||||
* Format the file size to be displayed.
|
||||
*/
|
||||
const size = computed((): string => {
|
||||
return prettyBytes(obStore.sortedFiles.find(f => f.Key === file.value.Key)?.Size || 0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the filepath of the modal from the store.
|
||||
*/
|
||||
@ -271,7 +267,13 @@ const currentPath = computed((): string => {
|
||||
async function fetchPreviewAndMapUrl(): Promise<void> {
|
||||
isLoading.value = true;
|
||||
|
||||
const url: string = await obStore.state.fetchPreviewAndMapUrl(filePath.value);
|
||||
let url = '';
|
||||
try {
|
||||
url = await generateObjectPreviewAndMapURL(filePath.value);
|
||||
} catch (error) {
|
||||
notify.error(`Unable to get file preview and map URL. ${error.message}`, AnalyticsErrorEventSource.GALLERY_VIEW);
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
previewAndMapFailed.value = true;
|
||||
isLoading.value = false;
|
||||
@ -435,6 +437,14 @@ function findCachedURL(): string | undefined {
|
||||
return cache.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the Share modal.
|
||||
*/
|
||||
function showShareModal(): void {
|
||||
appStore.setShareModalType(ShareType.File);
|
||||
appStore.updateActiveModal(ShareModal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `fetchPreviewAndMapUrl` on before mount lifecycle method.
|
||||
*/
|
||||
|
@ -44,7 +44,7 @@ import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrow
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import ModalHeader from '@/components/browser/galleryView/modals/ModalHeader.vue';
|
||||
import ModalHeader from '@/components/modals/ModalHeader.vue';
|
||||
|
||||
import DeleteIcon from '@/../static/images/browser/galleryView/modals/delete.svg';
|
||||
|
||||
|
@ -48,7 +48,7 @@ import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrow
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import ModalHeader from '@/components/browser/galleryView/modals/ModalHeader.vue';
|
||||
import ModalHeader from '@/components/modals/ModalHeader.vue';
|
||||
|
||||
import DetailsIcon from '@/../static/images/browser/galleryView/modals/details.svg';
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
<script setup lang="ts">
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import ModalHeader from '@/components/browser/galleryView/modals/ModalHeader.vue';
|
||||
import ModalHeader from '@/components/modals/ModalHeader.vue';
|
||||
|
||||
import GlobeIcon from '@/../static/images/browser/galleryView/modals/globe.svg';
|
||||
|
||||
|
@ -117,10 +117,12 @@
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { BrowserObject, useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useLinksharing } from '@/composables/useLinksharing';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
@ -129,9 +131,12 @@ import VLoader from '@/components/common/VLoader.vue';
|
||||
import ErrorNoticeIcon from '@/../static/images/common/errorNotice.svg?url';
|
||||
import PlaceholderImage from '@/../static/images/browser/placeholder.svg';
|
||||
|
||||
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const notify = useNotify();
|
||||
const { generateFileOrFolderShareURL, generateObjectPreviewAndMapURL } = useLinksharing();
|
||||
|
||||
const isLoading = ref<boolean>(false);
|
||||
const previewAndMapFailed = ref<boolean>(false);
|
||||
@ -233,9 +238,12 @@ const placeHolderDisplayable = computed((): boolean => {
|
||||
async function fetchPreviewAndMapUrl(): Promise<void> {
|
||||
isLoading.value = true;
|
||||
|
||||
const url: string = await obStore.state.fetchPreviewAndMapUrl(
|
||||
filePath.value,
|
||||
);
|
||||
let url = '';
|
||||
try {
|
||||
url = await generateObjectPreviewAndMapURL(filePath.value);
|
||||
} catch (error) {
|
||||
notify.error(`Unable to get file preview and map URL. ${error.message}`, AnalyticsErrorEventSource.ACCESS_GRANTS_PAGE);
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
previewAndMapFailed.value = true;
|
||||
@ -294,9 +302,12 @@ async function copy(): Promise<void> {
|
||||
* Get the share link of the current opened file.
|
||||
*/
|
||||
async function getSharedLink(): Promise<void> {
|
||||
objectLink.value = await obStore.state.fetchSharedLink(
|
||||
filePath.value,
|
||||
);
|
||||
analytics.eventTriggered(AnalyticsEvent.LINK_SHARED);
|
||||
try {
|
||||
objectLink.value = await generateFileOrFolderShareURL(filePath.value);
|
||||
} catch (error) {
|
||||
notify.error(`Unable to get sharing URL. ${error.message}`, AnalyticsErrorEventSource.OBJECT_DETAILS_MODAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,281 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<VModal :on-close="closeModal">
|
||||
<template #content>
|
||||
<div class="modal">
|
||||
<h1 class="modal__title">Share Bucket</h1>
|
||||
<ShareContainer :link="link" />
|
||||
<p class="modal__label">
|
||||
Or copy link:
|
||||
</p>
|
||||
<VLoader v-if="isLoading" width="20px" height="20px" />
|
||||
<div v-if="!isLoading" class="modal__input-group">
|
||||
<input
|
||||
id="url"
|
||||
class="modal__input"
|
||||
type="url"
|
||||
:value="link"
|
||||
aria-describedby="btn-copy-link"
|
||||
readonly
|
||||
>
|
||||
<VButton
|
||||
:label="copyButtonState === ButtonStates.Copy ? 'Copy' : 'Copied'"
|
||||
width="114px"
|
||||
height="40px"
|
||||
:on-press="onCopy"
|
||||
:is-disabled="isLoading"
|
||||
:is-green="copyButtonState === ButtonStates.Copied"
|
||||
:icon="copyButtonState === ButtonStates.Copied ? 'none' : 'copy'"
|
||||
>
|
||||
<template v-if="copyButtonState === ButtonStates.Copied" #icon>
|
||||
<check-icon />
|
||||
</template>
|
||||
</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useAccessGrantsStore } from '@/store/modules/accessGrantsStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import ShareContainer from '@/components/common/share/ShareContainer.vue';
|
||||
|
||||
import CheckIcon from '@/../static/images/common/check.svg';
|
||||
|
||||
enum ButtonStates {
|
||||
Copy,
|
||||
Copied,
|
||||
}
|
||||
|
||||
const configStore = useConfigStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
const appStore = useAppStore();
|
||||
const agStore = useAccessGrantsStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const notify = useNotify();
|
||||
|
||||
const worker = ref<Worker | null>(null);
|
||||
const isLoading = ref<boolean>(true);
|
||||
const link = ref<string>('');
|
||||
const copyButtonState = ref<ButtonStates>(ButtonStates.Copy);
|
||||
|
||||
/**
|
||||
* Returns chosen bucket name from store.
|
||||
*/
|
||||
const bucketName = computed((): string => {
|
||||
return bucketsStore.state.fileComponentBucketName;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns passphrase from store.
|
||||
*/
|
||||
const passphrase = computed((): string => {
|
||||
return bucketsStore.state.passphrase;
|
||||
});
|
||||
|
||||
/**
|
||||
* Copies link to users clipboard.
|
||||
*/
|
||||
async function onCopy(): Promise<void> {
|
||||
await navigator.clipboard.writeText(link.value);
|
||||
copyButtonState.value = ButtonStates.Copied;
|
||||
|
||||
setTimeout(() => {
|
||||
copyButtonState.value = ButtonStates.Copy;
|
||||
}, 2000);
|
||||
|
||||
await notify.success('Link copied successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets share bucket link.
|
||||
*/
|
||||
async function setShareLink(): Promise<void> {
|
||||
if (!worker.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let path = `${bucketName.value}`;
|
||||
const now = new Date();
|
||||
const LINK_SHARING_AG_NAME = `${path}_shared-bucket_${now.toISOString()}`;
|
||||
const cleanAPIKey: AccessGrant = await agStore.createAccessGrant(LINK_SHARING_AG_NAME, projectsStore.state.selectedProject.id);
|
||||
|
||||
const satelliteNodeURL = configStore.state.config.satelliteNodeURL;
|
||||
const salt = await projectsStore.getProjectSalt(projectsStore.state.selectedProject.id);
|
||||
|
||||
worker.value.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': cleanAPIKey.secret,
|
||||
'passphrase': passphrase.value,
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const grantData = grantEvent.data;
|
||||
if (grantData.error) {
|
||||
await notify.error(grantData.error, AnalyticsErrorEventSource.SHARE_BUCKET_MODAL);
|
||||
return;
|
||||
}
|
||||
|
||||
worker.value.postMessage({
|
||||
'type': 'RestrictGrant',
|
||||
'isDownload': true,
|
||||
'isUpload': false,
|
||||
'isList': true,
|
||||
'isDelete': false,
|
||||
'paths': [path],
|
||||
'grant': grantData.value,
|
||||
});
|
||||
|
||||
const event: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const data = event.data;
|
||||
if (data.error) {
|
||||
await notify.error(data.error, AnalyticsErrorEventSource.SHARE_BUCKET_MODAL);
|
||||
return;
|
||||
}
|
||||
|
||||
const credentials: EdgeCredentials = await agStore.getEdgeCredentials(data.value, undefined, true);
|
||||
|
||||
path = encodeURIComponent(path.trim());
|
||||
|
||||
const publicLinksharingURL = configStore.state.config.publicLinksharingURL;
|
||||
|
||||
link.value = `${publicLinksharingURL}/${credentials.accessKeyId}/${path}`;
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.SHARE_BUCKET_MODAL);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local worker with worker instantiated in store.
|
||||
*/
|
||||
function setWorker(): void {
|
||||
worker.value = agStore.state.accessGrantsWebWorker;
|
||||
if (worker.value) {
|
||||
worker.value.onerror = (error: ErrorEvent) => {
|
||||
notify.error(error.message, AnalyticsErrorEventSource.SHARE_BUCKET_MODAL);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes open bucket modal.
|
||||
*/
|
||||
function closeModal(): void {
|
||||
if (isLoading.value) return;
|
||||
|
||||
appStore.removeActiveModal();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
setWorker();
|
||||
await setShareLink();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 50px;
|
||||
max-width: 470px;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 29px;
|
||||
color: #1b2533;
|
||||
margin: 10px 0 35px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
color: #354049;
|
||||
align-self: center;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
font-size: 16px;
|
||||
line-height: 21px;
|
||||
color: #384b65;
|
||||
align-self: flex-start;
|
||||
word-break: break-all;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
column-gap: 20px;
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
flex-direction: column-reverse;
|
||||
column-gap: unset;
|
||||
row-gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&__input-group {
|
||||
border: 1px solid var(--c-grey-4);
|
||||
background: var(--c-grey-1);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
color: var(--c-grey-6);
|
||||
outline: none;
|
||||
max-width: 340px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
max-width: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,12 +2,12 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<VModal :on-close="onClose">
|
||||
<VModal :on-close="closeModal">
|
||||
<template #content>
|
||||
<div class="modal">
|
||||
<ModalHeader
|
||||
:icon="ShareIcon"
|
||||
title="Share File"
|
||||
:title="'Share ' + shareType"
|
||||
/>
|
||||
<VLoader v-if="loading" width="40px" height="40px" />
|
||||
<template v-else>
|
||||
@ -29,7 +29,7 @@
|
||||
width="100%"
|
||||
border-radius="10px"
|
||||
font-size="14px"
|
||||
:on-press="onClose"
|
||||
:on-press="closeModal"
|
||||
is-white
|
||||
/>
|
||||
<VButton
|
||||
@ -50,13 +50,19 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { useLinksharing } from '@/composables/useLinksharing';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { ShareType } from '@/types/browser';
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import ShareContainer from '@/components/common/share/ShareContainer.vue';
|
||||
import ModalHeader from '@/components/browser/galleryView/modals/ModalHeader.vue';
|
||||
import ModalHeader from '@/components/modals/ModalHeader.vue';
|
||||
|
||||
import ShareIcon from '@/../static/images/browser/galleryView/modals/share.svg';
|
||||
|
||||
@ -65,16 +71,24 @@ enum ButtonStates {
|
||||
Copied,
|
||||
}
|
||||
|
||||
const obStore = useObjectBrowserStore();
|
||||
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
const props = defineProps<{
|
||||
onClose: () => void
|
||||
}>();
|
||||
const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const { generateFileOrFolderShareURL, generateBucketShareURL } = useLinksharing();
|
||||
const notify = useNotify();
|
||||
|
||||
const link = ref<string>('');
|
||||
const loading = ref<boolean>(true);
|
||||
const copyButtonState = ref<ButtonStates>(ButtonStates.Copy);
|
||||
|
||||
/**
|
||||
* Returns what type of entity is being shared.
|
||||
*/
|
||||
const shareType = computed((): ShareType => {
|
||||
return appStore.state.shareModalType;
|
||||
});
|
||||
|
||||
/**
|
||||
* Retrieve the path to the current file.
|
||||
*/
|
||||
@ -94,10 +108,26 @@ async function onCopy(): Promise<void> {
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the modal.
|
||||
*/
|
||||
function closeModal(): void {
|
||||
if (loading.value) return;
|
||||
|
||||
appStore.removeActiveModal();
|
||||
}
|
||||
|
||||
onMounted(async (): Promise<void> => {
|
||||
link.value = await obStore.state.fetchSharedLink(
|
||||
filePath.value,
|
||||
);
|
||||
analytics.eventTriggered(AnalyticsEvent.LINK_SHARED);
|
||||
try {
|
||||
if (shareType.value === ShareType.Bucket) {
|
||||
link.value = await generateBucketShareURL();
|
||||
} else {
|
||||
link.value = await generateFileOrFolderShareURL(filePath.value, shareType.value === ShareType.Folder);
|
||||
}
|
||||
} catch (error) {
|
||||
notify.error(`Unable to get sharing URL. ${error.message}`, AnalyticsErrorEventSource.SHARE_MODAL);
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
});
|
@ -1,189 +0,0 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<VModal :on-close="closeModal">
|
||||
<template #content>
|
||||
<div class="modal">
|
||||
<h1 class="modal__title">Share File</h1>
|
||||
<ShareContainer :link="link" />
|
||||
<p class="modal__label">
|
||||
Or copy link:
|
||||
</p>
|
||||
<VLoader v-if="isLoading" width="20px" height="20px" />
|
||||
<div v-if="!isLoading" class="modal__input-group">
|
||||
<input
|
||||
id="url"
|
||||
class="modal__input"
|
||||
type="url"
|
||||
:value="link"
|
||||
aria-describedby="btn-copy-link"
|
||||
readonly
|
||||
>
|
||||
<VButton
|
||||
:label="copyButtonState === ButtonStates.Copy ? 'Copy' : 'Copied'"
|
||||
width="114px"
|
||||
height="40px"
|
||||
:on-press="onCopy"
|
||||
:is-disabled="isLoading"
|
||||
:is-green="copyButtonState === ButtonStates.Copied"
|
||||
:icon="copyButtonState === ButtonStates.Copied ? 'none' : 'copy'"
|
||||
>
|
||||
<template v-if="copyButtonState === ButtonStates.Copied" #icon>
|
||||
<check-icon />
|
||||
</template>
|
||||
</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</VModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import ShareContainer from '@/components/common/share/ShareContainer.vue';
|
||||
|
||||
import CheckIcon from '@/../static/images/common/check.svg';
|
||||
|
||||
enum ButtonStates {
|
||||
Copy,
|
||||
Copied,
|
||||
}
|
||||
|
||||
const appStore = useAppStore();
|
||||
const obStore = useObjectBrowserStore();
|
||||
const notify = useNotify();
|
||||
|
||||
const isLoading = ref<boolean>(true);
|
||||
const link = ref<string>('');
|
||||
const copyButtonState = ref<ButtonStates>(ButtonStates.Copy);
|
||||
|
||||
/**
|
||||
* Retrieve the path to the current file that has the fileShareModal opened from the store.
|
||||
*/
|
||||
const filePath = computed((): string => {
|
||||
return obStore.state.objectPathForModal;
|
||||
});
|
||||
|
||||
/**
|
||||
* Copies link to users clipboard.
|
||||
*/
|
||||
async function onCopy(): Promise<void> {
|
||||
await navigator.clipboard.writeText(link.value);
|
||||
copyButtonState.value = ButtonStates.Copied;
|
||||
|
||||
setTimeout(() => {
|
||||
copyButtonState.value = ButtonStates.Copy;
|
||||
}, 2000);
|
||||
|
||||
await notify.success('Link copied successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes open bucket modal.
|
||||
*/
|
||||
function closeModal(): void {
|
||||
if (isLoading.value) return;
|
||||
|
||||
appStore.removeActiveModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook after initial render.
|
||||
* Sets share link.
|
||||
*/
|
||||
onMounted(async (): Promise<void> => {
|
||||
link.value = await obStore.state.fetchSharedLink(
|
||||
filePath.value,
|
||||
);
|
||||
|
||||
isLoading.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 50px;
|
||||
max-width: 470px;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 29px;
|
||||
color: #1b2533;
|
||||
margin: 10px 0 35px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
color: #354049;
|
||||
align-self: center;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
font-size: 16px;
|
||||
line-height: 21px;
|
||||
color: #384b65;
|
||||
align-self: flex-start;
|
||||
word-break: break-all;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
column-gap: 20px;
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
flex-direction: column-reverse;
|
||||
column-gap: unset;
|
||||
row-gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&__input-group {
|
||||
border: 1px solid var(--c-grey-4);
|
||||
background: var(--c-grey-1);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
color: var(--c-grey-6);
|
||||
outline: none;
|
||||
max-width: 340px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (width <= 430px) {
|
||||
max-width: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -34,6 +34,7 @@ import { RouteConfig } from '@/types/router';
|
||||
import { MODALS } from '@/utils/constants/appStatePopUps';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { ShareType } from '@/types/browser';
|
||||
|
||||
import ArrowDownIcon from '@/../static/images/common/dropIcon.svg';
|
||||
import DetailsIcon from '@/../static/images/objects/details.svg';
|
||||
@ -84,7 +85,8 @@ function onDetailsClick(): void {
|
||||
* Toggles share bucket modal.
|
||||
*/
|
||||
function onShareBucketClick(): void {
|
||||
appStore.updateActiveModal(MODALS.shareBucket);
|
||||
appStore.setShareModalType(ShareType.Bucket);
|
||||
appStore.updateActiveModal(MODALS.share);
|
||||
isDropdownOpen.value = false;
|
||||
}
|
||||
</script>
|
||||
|
@ -14,19 +14,16 @@
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { AnalyticsHttpApi } from '@/api/analytics';
|
||||
import { RouteConfig } from '@/types/router';
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { EdgeCredentials } from '@/types/accessGrants';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { MODALS } from '@/utils/constants/appStatePopUps';
|
||||
import { BucketPage } from '@/types/buckets';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useAccessGrantsStore } from '@/store/modules/accessGrantsStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { useObjectBrowserStore } from '@/store/modules/objectBrowserStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
|
||||
import FileBrowser from '@/components/browser/FileBrowser.vue';
|
||||
import UploadCancelPopup from '@/components/objects/UploadCancelPopup.vue';
|
||||
@ -34,16 +31,10 @@ import UploadCancelPopup from '@/components/objects/UploadCancelPopup.vue';
|
||||
const obStore = useObjectBrowserStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
const appStore = useAppStore();
|
||||
const configStore = useConfigStore();
|
||||
const agStore = useAccessGrantsStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const router = useRouter();
|
||||
const notify = useNotify();
|
||||
|
||||
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
|
||||
const worker = ref<Worker | null>(null);
|
||||
|
||||
/**
|
||||
* Indicates if upload cancel popup is visible.
|
||||
*/
|
||||
@ -58,13 +49,6 @@ const passphrase = computed((): string => {
|
||||
return bucketsStore.state.passphrase;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns apiKey from store.
|
||||
*/
|
||||
const apiKey = computed((): string => {
|
||||
return bucketsStore.state.apiKey;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns bucket name from store.
|
||||
*/
|
||||
@ -86,153 +70,16 @@ const edgeCredentials = computed((): EdgeCredentials => {
|
||||
return bucketsStore.state.edgeCredentials;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns linksharing URL from store.
|
||||
*/
|
||||
const linksharingURL = computed((): string => {
|
||||
return configStore.state.config.linksharingURL;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns public linksharing URL from store.
|
||||
*/
|
||||
const publicLinksharingURL = computed((): string => {
|
||||
return configStore.state.config.publicLinksharingURL;
|
||||
});
|
||||
|
||||
/**
|
||||
* Generates a URL for an object map.
|
||||
*/
|
||||
async function generateObjectPreviewAndMapUrl(path: string): Promise<string> {
|
||||
path = `${bucket.value}/${path}`;
|
||||
|
||||
try {
|
||||
const creds: EdgeCredentials = await generateCredentials(apiKey.value, path, false);
|
||||
|
||||
path = encodeURIComponent(path.trim());
|
||||
|
||||
return `${linksharingURL.value}/s/${creds.accessKeyId}/${path}`;
|
||||
} catch (error) {
|
||||
notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL for a link sharing service.
|
||||
*/
|
||||
async function generateShareLinkUrl(path: string): Promise<string> {
|
||||
path = `${bucket.value}/${path}`;
|
||||
const now = new Date();
|
||||
const LINK_SHARING_AG_NAME = `${path}_shared-object_${now.toISOString()}`;
|
||||
const cleanAPIKey: AccessGrant = await agStore.createAccessGrant(LINK_SHARING_AG_NAME, projectsStore.state.selectedProject.id);
|
||||
|
||||
try {
|
||||
const credentials: EdgeCredentials = await generateCredentials(cleanAPIKey.secret, path, true);
|
||||
|
||||
path = encodeURIComponent(path.trim());
|
||||
|
||||
await analytics.eventTriggered(AnalyticsEvent.LINK_SHARED);
|
||||
|
||||
return `${publicLinksharingURL.value}/${credentials.accessKeyId}/${path}`;
|
||||
} catch (error) {
|
||||
await notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local worker with worker instantiated in store.
|
||||
*/
|
||||
function setWorker(): void {
|
||||
worker.value = agStore.state.accessGrantsWebWorker;
|
||||
if (worker.value) {
|
||||
worker.value.onerror = (error: ErrorEvent) => {
|
||||
notify.error(error.message, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates share gateway credentials.
|
||||
*/
|
||||
async function generateCredentials(cleanApiKey: string, path: string, areEndless: boolean): Promise<EdgeCredentials> {
|
||||
if (!worker.value) {
|
||||
throw new Error('Worker is not defined');
|
||||
}
|
||||
|
||||
const satelliteNodeURL = configStore.state.config.satelliteNodeURL;
|
||||
const salt = await projectsStore.getProjectSalt(projectsStore.state.selectedProject.id);
|
||||
|
||||
worker.value.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': cleanApiKey,
|
||||
'passphrase': passphrase.value,
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const grantData = grantEvent.data;
|
||||
if (grantData.error) {
|
||||
await notify.error(grantData.error, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
|
||||
return new EdgeCredentials();
|
||||
}
|
||||
|
||||
let permissionsMsg = {
|
||||
'type': 'RestrictGrant',
|
||||
'isDownload': true,
|
||||
'isUpload': false,
|
||||
'isList': true,
|
||||
'isDelete': false,
|
||||
'paths': [path],
|
||||
'grant': grantData.value,
|
||||
};
|
||||
|
||||
if (!areEndless) {
|
||||
const now = new Date();
|
||||
const inOneDay = new Date(now.setDate(now.getDate() + 1));
|
||||
|
||||
permissionsMsg = Object.assign(permissionsMsg, { 'notAfter': inOneDay.toISOString() });
|
||||
}
|
||||
|
||||
worker.value.postMessage(permissionsMsg);
|
||||
|
||||
const event: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const data = event.data;
|
||||
if (data.error) {
|
||||
await notify.error(data.error, AnalyticsErrorEventSource.UPLOAD_FILE_VIEW);
|
||||
|
||||
return new EdgeCredentials();
|
||||
}
|
||||
|
||||
return await agStore.getEdgeCredentials(data.value, undefined, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates file browser.
|
||||
*/
|
||||
onBeforeMount(() => {
|
||||
setWorker();
|
||||
|
||||
obStore.init({
|
||||
endpoint: edgeCredentials.value.endpoint,
|
||||
accessKey: edgeCredentials.value.accessKeyId,
|
||||
secretKey: edgeCredentials.value.secretKey,
|
||||
bucket: bucket.value,
|
||||
browserRoot: RouteConfig.Buckets.with(RouteConfig.UploadFile).path,
|
||||
fetchPreviewAndMapUrl: generateObjectPreviewAndMapUrl,
|
||||
fetchSharedLink: generateShareLinkUrl,
|
||||
});
|
||||
});
|
||||
|
||||
|
111
web/satellite/src/composables/useLinksharing.ts
Normal file
111
web/satellite/src/composables/useLinksharing.ts
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { useAccessGrantsStore } from '@/store/modules/accessGrantsStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { useBucketsStore } from '@/store/modules/bucketsStore';
|
||||
import { AccessGrant, EdgeCredentials } from '@/types/accessGrants';
|
||||
|
||||
const WORKER_ERR_MSG = 'Worker is not defined';
|
||||
|
||||
export function useLinksharing() {
|
||||
const agStore = useAccessGrantsStore();
|
||||
const configStore = useConfigStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const bucketsStore = useBucketsStore();
|
||||
|
||||
const worker = computed((): Worker | null => agStore.state.accessGrantsWebWorker);
|
||||
|
||||
async function generateFileOrFolderShareURL(path: string, isFolder = false): Promise<string> {
|
||||
const fullPath = `${bucketsStore.state.fileComponentBucketName}/${path}`;
|
||||
const type = isFolder ? 'folder' : 'object';
|
||||
return generateShareURL(fullPath, type);
|
||||
}
|
||||
|
||||
async function generateBucketShareURL(): Promise<string> {
|
||||
return generateShareURL(bucketsStore.state.fileComponentBucketName, 'bucket');
|
||||
}
|
||||
|
||||
async function generateShareURL(path: string, type: string): Promise<string> {
|
||||
if (!worker.value) throw new Error(WORKER_ERR_MSG);
|
||||
|
||||
const LINK_SHARING_AG_NAME = `${path}_shared-${type}_${new Date().toISOString()}`;
|
||||
const grant: AccessGrant = await agStore.createAccessGrant(LINK_SHARING_AG_NAME, projectsStore.state.selectedProject.id);
|
||||
const credentials: EdgeCredentials = await generateCredentials(grant.secret, path, null);
|
||||
|
||||
return `${configStore.state.config.publicLinksharingURL}/${credentials.accessKeyId}/${encodeURIComponent(path.trim())}`;
|
||||
}
|
||||
|
||||
async function generateObjectPreviewAndMapURL(path: string): Promise<string> {
|
||||
if (!worker.value) throw new Error(WORKER_ERR_MSG);
|
||||
|
||||
path = bucketsStore.state.fileComponentBucketName + '/' + path;
|
||||
const now = new Date();
|
||||
const inOneDay = new Date(now.setDate(now.getDate() + 1));
|
||||
const creds: EdgeCredentials = await generateCredentials(bucketsStore.state.apiKey, path, inOneDay);
|
||||
|
||||
return `${configStore.state.config.linksharingURL}/s/${creds.accessKeyId}/${encodeURIComponent(path.trim())}`;
|
||||
}
|
||||
|
||||
async function generateCredentials(cleanAPIKey: string, path: string, expiration: Date | null): Promise<EdgeCredentials> {
|
||||
if (!worker.value) throw new Error(WORKER_ERR_MSG);
|
||||
|
||||
const satelliteNodeURL = configStore.state.config.satelliteNodeURL;
|
||||
const salt = await projectsStore.getProjectSalt(projectsStore.state.selectedProject.id);
|
||||
|
||||
worker.value.postMessage({
|
||||
'type': 'GenerateAccess',
|
||||
'apiKey': cleanAPIKey,
|
||||
'passphrase': bucketsStore.state.passphrase,
|
||||
'salt': salt,
|
||||
'satelliteNodeURL': satelliteNodeURL,
|
||||
});
|
||||
|
||||
const grantEvent: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const grantData = grantEvent.data;
|
||||
if (grantData.error) {
|
||||
throw new Error(grantData.error);
|
||||
}
|
||||
|
||||
let permissionsMsg = {
|
||||
'type': 'RestrictGrant',
|
||||
'isDownload': true,
|
||||
'isUpload': false,
|
||||
'isList': true,
|
||||
'isDelete': false,
|
||||
'paths': [path],
|
||||
'grant': grantData.value,
|
||||
};
|
||||
|
||||
if (expiration) {
|
||||
permissionsMsg = Object.assign(permissionsMsg, { 'notAfter': expiration.toISOString() });
|
||||
}
|
||||
|
||||
worker.value.postMessage(permissionsMsg);
|
||||
|
||||
const event: MessageEvent = await new Promise(resolve => {
|
||||
if (worker.value) {
|
||||
worker.value.onmessage = resolve;
|
||||
}
|
||||
});
|
||||
const data = event.data;
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
return agStore.getEdgeCredentials(data.value, undefined, true);
|
||||
}
|
||||
|
||||
return {
|
||||
generateBucketShareURL,
|
||||
generateFileOrFolderShareURL,
|
||||
generateObjectPreviewAndMapURL,
|
||||
};
|
||||
}
|
@ -9,6 +9,7 @@ import { FetchState } from '@/utils/constants/fetchStateEnum';
|
||||
import { ManageProjectPassphraseStep } from '@/types/managePassphrase';
|
||||
import { LocalData } from '@/utils/localData';
|
||||
import { LimitToChange } from '@/types/projects';
|
||||
import { ShareType } from '@/types/browser';
|
||||
|
||||
class AppState {
|
||||
public fetchState = FetchState.LOADING;
|
||||
@ -35,6 +36,7 @@ class AppState {
|
||||
public isLargeUploadWarningNotificationShown = false;
|
||||
public activeChangeLimit: LimitToChange = LimitToChange.Storage;
|
||||
public isProjectTableViewEnabled = LocalData.getProjectTableViewEnabled();
|
||||
public shareModalType: ShareType = ShareType.File;
|
||||
}
|
||||
|
||||
class ErrorPageState {
|
||||
@ -154,6 +156,10 @@ export const useAppStore = defineStore('app', () => {
|
||||
state.isGalleryView = value;
|
||||
}
|
||||
|
||||
function setShareModalType(type: ShareType): void {
|
||||
state.shareModalType = type;
|
||||
}
|
||||
|
||||
function closeDropdowns(): void {
|
||||
state.activeDropdown = '';
|
||||
}
|
||||
@ -185,6 +191,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
state.error.visible = false;
|
||||
state.isGalleryView = false;
|
||||
state.isProjectTableViewEnabled = false;
|
||||
state.shareModalType = ShareType.File;
|
||||
LocalData.removeProjectTableViewConfig();
|
||||
}
|
||||
|
||||
@ -211,6 +218,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
setUploadingModal,
|
||||
setLargeUploadWarningNotification,
|
||||
setLargeUploadNotification,
|
||||
setShareModalType,
|
||||
closeDropdowns,
|
||||
setErrorPage,
|
||||
removeErrorPage,
|
||||
|
@ -77,8 +77,6 @@ export class FilesState {
|
||||
selectedFiles: BrowserObject[] = [];
|
||||
shiftSelectedFiles: BrowserObject[] = [];
|
||||
filesToBeDeleted: BrowserObject[] = [];
|
||||
fetchSharedLink: (arg0: string) => Promisable<string> = () => 'javascript:null';
|
||||
fetchPreviewAndMapUrl: (arg0: string) => Promisable<string> = () => 'javascript:null';
|
||||
openedDropdown: null | string = null;
|
||||
headingSorted = 'name';
|
||||
orderBy: 'asc' | 'desc' = 'asc';
|
||||
@ -164,8 +162,6 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
endpoint,
|
||||
browserRoot,
|
||||
openModalOnFirstUpload = true,
|
||||
fetchSharedLink = () => 'javascript:null',
|
||||
fetchPreviewAndMapUrl = () => 'javascript:null',
|
||||
}: {
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
@ -173,8 +169,6 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
endpoint: string;
|
||||
browserRoot: string;
|
||||
openModalOnFirstUpload?: boolean;
|
||||
fetchSharedLink: (arg0: string) => Promisable<string>;
|
||||
fetchPreviewAndMapUrl: (arg0: string) => Promisable<string>;
|
||||
}): void {
|
||||
const s3Config: S3ClientConfig = {
|
||||
credentials: {
|
||||
@ -192,8 +186,6 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
state.bucket = bucket;
|
||||
state.browserRoot = browserRoot;
|
||||
state.openModalOnFirstUpload = openModalOnFirstUpload;
|
||||
state.fetchSharedLink = fetchSharedLink;
|
||||
state.fetchPreviewAndMapUrl = fetchPreviewAndMapUrl;
|
||||
state.path = '';
|
||||
state.files = [];
|
||||
}
|
||||
@ -810,8 +802,6 @@ export const useObjectBrowserStore = defineStore('objectBrowser', () => {
|
||||
state.selectedFiles = [];
|
||||
state.shiftSelectedFiles = [];
|
||||
state.filesToBeDeleted = [];
|
||||
state.fetchSharedLink = () => 'javascript:null';
|
||||
state.fetchPreviewAndMapUrl = () => 'javascript:null';
|
||||
state.openedDropdown = null;
|
||||
state.headingSorted = 'name';
|
||||
state.orderBy = 'asc';
|
||||
|
@ -22,3 +22,9 @@ export class ShareButtonConfig {
|
||||
public image: string = EmailIcon,
|
||||
) {}
|
||||
}
|
||||
|
||||
export enum ShareType {
|
||||
File = 'File',
|
||||
Folder = 'Folder',
|
||||
Bucket = 'Bucket',
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ export enum AnalyticsErrorEventSource {
|
||||
CREATE_FOLDER_MODAL = 'Create folder modal',
|
||||
OBJECT_DETAILS_MODAL = 'Object details modal',
|
||||
OPEN_BUCKET_MODAL = 'Open bucket modal',
|
||||
SHARE_BUCKET_MODAL = 'Share bucket modal',
|
||||
SHARE_MODAL = 'Share modal',
|
||||
OBJECTS_UPLOAD_MODAL = 'Objects upload modal',
|
||||
NAVIGATION_ACCOUNT_AREA = 'Navigation account area',
|
||||
NAVIGATION_PROJECT_SELECTION = 'Navigation project selection',
|
||||
|
@ -14,8 +14,7 @@ import MFARecoveryCodesModal from '@/components/modals/MFARecoveryCodesModal.vue
|
||||
import EnableMFAModal from '@/components/modals/EnableMFAModal.vue';
|
||||
import DisableMFAModal from '@/components/modals/DisableMFAModal.vue';
|
||||
import AddTokenFundsModal from '@/components/modals/AddTokenFundsModal.vue';
|
||||
import ShareBucketModal from '@/components/modals/ShareBucketModal.vue';
|
||||
import ShareObjectModal from '@/components/modals/ShareObjectModal.vue';
|
||||
import ShareModal from '@/components/modals/ShareModal.vue';
|
||||
import DeleteBucketModal from '@/components/modals/DeleteBucketModal.vue';
|
||||
import CreateBucketModal from '@/components/modals/CreateBucketModal.vue';
|
||||
import NewFolderModal from '@/components/modals/NewFolderModal.vue';
|
||||
@ -67,8 +66,7 @@ enum Modals {
|
||||
ENABLE_MFA = 'enableMFA',
|
||||
DISABLE_MFA = 'disableMFA',
|
||||
ADD_TOKEN_FUNDS = 'addTokenFunds',
|
||||
SHARE_BUCKET = 'shareBucket',
|
||||
SHARE_OBJECT = 'shareObject',
|
||||
SHARE = 'share',
|
||||
DELETE_BUCKET = 'deleteBucket',
|
||||
CREATE_BUCKET = 'createBucket',
|
||||
NEW_FOLDER = 'newFolder',
|
||||
@ -101,8 +99,7 @@ export const MODALS: Record<Modals, Component> = {
|
||||
[Modals.ENABLE_MFA]: EnableMFAModal,
|
||||
[Modals.DISABLE_MFA]: DisableMFAModal,
|
||||
[Modals.ADD_TOKEN_FUNDS]: AddTokenFundsModal,
|
||||
[Modals.SHARE_BUCKET]: ShareBucketModal,
|
||||
[Modals.SHARE_OBJECT]: ShareObjectModal,
|
||||
[Modals.SHARE]: ShareModal,
|
||||
[Modals.DELETE_BUCKET]: DeleteBucketModal,
|
||||
[Modals.CREATE_BUCKET]: CreateBucketModal,
|
||||
[Modals.NEW_FOLDER]: NewFolderModal,
|
||||
|
Loading…
Reference in New Issue
Block a user