Skip to content

Commit

Permalink
web/satellite/v2: require confirmation for multi file delete
Browse files Browse the repository at this point in the history
This change modifies the existing file delete dialog to support deletes
of multiple selected files from the file browser.

Issue: #6715

Change-Id: I52b12633b1c7866edfd107f0d71d71d087a85d8a
  • Loading branch information
wilfred-asomanii authored and Storj Robot committed Jan 26, 2024
1 parent ffbcf9d commit 9d967ad
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<span>{{ statusLabel }}</span>
<template v-if="isClosable" #actions>
<v-row class="ma-0 align-center">
<v-icon v-if="isExpanded" :icon="mdiChevronUp" class="mr-2" />
<v-icon v-if="!isExpanded" :icon="mdiChevronUp" class="mr-2" />
<v-icon v-else :icon="mdiChevronDown" class="mr-2" />
<v-btn variant="outlined" color="default" size="x-small" :icon="mdiClose" title="Close" @click="closeDialog" />
</v-row>
Expand Down
32 changes: 15 additions & 17 deletions web/satellite/vuetify-poc/src/components/BrowserTableComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
color="default"
density="comfortable"
variant="outlined"
@click="deleteSelectedFiles"
@click="isDeleteFileDialogShown = true"
>
<template #prepend>
<icon-trash bold />
Expand All @@ -128,10 +128,9 @@
</v-snackbar>

<delete-file-dialog
v-if="fileToDelete"
v-model="isDeleteFileDialogShown"
:file="fileToDelete"
@content-removed="fileToDelete = null"
:files="filesToDelete"
@files-deleted="clearDeleteFiles"
/>
<share-dialog
v-model="isShareDialogShown"
Expand Down Expand Up @@ -213,7 +212,6 @@ const router = useRouter();
const isFetching = ref<boolean>(false);
const search = ref<string>('');
const selected = ref([]);
const previewDialog = ref<boolean>(false);
const options = ref<TableOptions>();
const fileToDelete = ref<BrowserObject | null>(null);
Expand Down Expand Up @@ -350,24 +348,24 @@ const selectedFiles: WritableComputedRef<string[]> = computed({
},
});
/**
* Returns the selected files to the delete dialog.
*/
const filesToDelete = computed<BrowserObject[]>(() => {
if (fileToDelete.value) return [fileToDelete.value];
return obStore.state.selectedFiles;
});
/**
* Returns the first browser object in the table that is a file.
*/
const firstFile = computed<BrowserObject | null>(() => {
return tableFiles.value.find(f => f.browserObject.type === 'file')?.browserObject || null;
});
/**
* Delete selected files.
*/
async function deleteSelectedFiles() {
if (!selectedFiles.value.length) return;
try {
await obStore.deleteSelected();
obStore.updateSelectedFiles([]);
} catch (e) {
notify.notifyError(e, AnalyticsErrorEventSource.FILE_BROWSER_ENTRY);
}
function clearDeleteFiles(): void {
fileToDelete.value = null;
obStore.updateSelectedFiles([]);
}
/**
Expand Down Expand Up @@ -476,7 +474,7 @@ async function fetchFiles(): Promise<void> {
await obStore.list(path);
}
selected.value = [];
selectedFiles.value = [];
if (isPaginationEnabled.value) {
const cachedPage = routePageCache.get(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<icon-trash />
</v-sheet>
</template>
<v-card-title class="font-weight-bold text-capitalize">Delete {{ fileType }}</v-card-title>
<v-card-title class="font-weight-bold text-capitalize">Delete {{ fileTypes }}</v-card-title>
<template #append>
<v-btn
icon="$close"
Expand All @@ -36,9 +36,9 @@
<v-divider />

<div class="pa-7">
The following {{ fileType }} <template v-if="isFolder">and all of its data</template> will be deleted. This action cannot be undone.
The following {{ fileTypes }}<template v-if="isFolder">, and all contained data</template> will be deleted. This action cannot be undone.
<br><br>
<span class="font-weight-bold">{{ file.path + file.Key }}</span>
<p v-for="file of files" :key="file.path + file.Key" class="font-weight-bold">{{ file.path + file.Key }}</p>
</div>

<v-divider />
Expand Down Expand Up @@ -86,13 +86,13 @@ import IconTrash from '@poc/components/icons/IconTrash.vue';
const props = defineProps<{
modelValue: boolean,
file: BrowserObject,
files: BrowserObject[],
}>();
const emit = defineEmits<{
'update:modelValue': [value: boolean],
'contentRemoved': [],
'fileDeleted': [],
'filesDeleted': [],
}>();
const model = computed<boolean>({
Expand All @@ -110,33 +110,55 @@ const innerContent = ref<Component | null>(null);
const filePath = computed<string>(() => bucketsStore.state.fileComponentPath);
const fileType = computed<string>(() => {
return props.file.type ?? 'file';
const fileCount = computed<number>(() => props.files.filter(file => file.type === 'file').length);
const folderCount = computed<number>(() => props.files.filter(file => file.type === 'folder').length);
/**
* types of objects to be deleted.
*/
const fileTypes = computed<string>(() => {
if (fileCount.value > 0 && folderCount.value > 0) {
return `file${fileCount.value > 1 ? 's' : ''} and folder${folderCount.value > 1 ? 's' : ''}`;
} else if (folderCount.value > 0) {
return `folder${folderCount.value > 1 ? 's' : ''}`;
} else {
return `file${fileCount.value > 1 ? 's' : ''}`;
}
});
const isFolder = computed<boolean>(() => {
return fileType.value === 'folder';
return folderCount.value > 0;
});
async function onDeleteClick(): Promise<void> {
await withLoading(async () => {
try {
if (isFolder.value) {
await obStore.deleteFolder(props.file, filePath.value ? filePath.value + '/' : '');
} else {
await obStore.deleteObject(filePath.value ? filePath.value + '/' : '', props.file);
}
if (props.files.length === 1) {
await deleteSingleFile(props.files[0]);
} else if (props.files.length > 1) {
// multiple files selected in the file browser.
await obStore.deleteSelected();
} else return;
} catch (error) {
error.message = `Error deleting ${fileType.value}. ${error.message}`;
notify.notifyError(error, AnalyticsErrorEventSource.FILE_BROWSER_ENTRY);
error.message = `Error deleting ${fileTypes.value}. ${error.message}`;
notify.notifyError(error, AnalyticsErrorEventSource.FILE_BROWSER);
return;
}
emit('fileDeleted');
notify.success(`${fileType.value.charAt(0).toUpperCase() + fileType.value.slice(1)} deleted.`);
emit('filesDeleted');
notify.success(`${fileCount.value + folderCount.value} ${fileTypes.value} deleted`);
model.value = false;
});
}
async function deleteSingleFile(file: BrowserObject): Promise<void> {
if (isFolder.value) {
await obStore.deleteFolder(file, filePath.value ? filePath.value + '/' : '');
} else {
await obStore.deleteObject(filePath.value ? filePath.value + '/' : '', file);
}
}
watch(innerContent, comp => !comp && emit('contentRemoved'));
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@
<delete-file-dialog
v-if="fileToDelete"
v-model="isDeleteFileDialogShown"
:file="fileToDelete"
@file-deleted="onDeleteComplete"
:files="[fileToDelete]"
@files-deleted="onDeleteComplete"
/>
</template>

Expand Down

0 comments on commit 9d967ad

Please sign in to comment.