Skip to content

Commit

Permalink
Merge pull request #33 from radek00/pause-upload
Browse files Browse the repository at this point in the history
Pause upload
  • Loading branch information
radek00 authored Aug 14, 2023
2 parents a290190 + a4def30 commit 3e45b3e
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ name: Publish Docker image
on:
push:
branches:
- 'release/docker-release'
- 'master'

jobs:
push_to_registry:
Expand Down
15 changes: 15 additions & 0 deletions SecureSend/ClientApp/src/assets/icons/PauseIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<svg
class="text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 10 16"
>
<path
fill-rule="evenodd"
d="M0 .8C0 .358.32 0 .714 0h1.429c.394 0 .714.358.714.8v14.4c0 .442-.32.8-.714.8H.714a.678.678 0 0 1-.505-.234A.851.851 0 0 1 0 15.2V.8Zm7.143 0c0-.442.32-.8.714-.8h1.429c.19 0 .37.084.505.234.134.15.209.354.209.566v14.4c0 .442-.32.8-.714.8H7.857c-.394 0-.714-.358-.714-.8V.8Z"
clip-rule="evenodd"
/>
</svg>
</template>
17 changes: 17 additions & 0 deletions SecureSend/ClientApp/src/assets/icons/PlayIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<svg
class="text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 16 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 1.984v14.032a1 1 0 0 0 1.506.845l12.006-7.016a.974.974 0 0 0 0-1.69L2.506 1.139A1 1 0 0 0 1 1.984Z"
/>
</svg>
</template>
49 changes: 37 additions & 12 deletions SecureSend/ClientApp/src/components/FileUploadForm/FileInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import PlusIcon from "@/assets/icons/PlusIcon.vue";
import { UploadStatus } from "@/models/enums/UploadStatus";
import { inject } from "vue";
import CloseIcon from "@/assets/icons/CloseIcon.vue";
import PauseIcon from "@/assets/icons/PauseIcon.vue";
import PlayIcon from "@/assets/icons/PlayIcon.vue";
const emit = defineEmits<{
onFielsChange: [files: File[] | null];
onFileRemove: [file: File];
onCancel: [file: string];
onCancel: [file: File];
onPause: [file: File];
onResume: [file: File];
}>();
defineProps<{
Expand Down Expand Up @@ -84,16 +88,37 @@ const { isOverDropZone } = useDropZone(fileDropZone, { onDrop });
<TrashIcon class="w-5 h-3"></TrashIcon>
<span class="sr-only">Remove file</span>
</button>
<button
v-if="isLoading"
@click="emit('onCancel', key.name)"
type="button"
:disabled="!isUploadSetup"
class="m-0 border hover:enabled:bg-red-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center mr-2 border-red-500 hover:enabled:text-white focus:ring-red-800 hover:bg-red-500 disabled:cursor-not-allowed disabled:bg-gray-600 disabled:border-gray-800"
>
<CloseIcon class="w-5 h-3"></CloseIcon>
<span class="sr-only">Cancel</span>
</button>
<div v-if="isLoading" class="flex gap-1 justify-between">
<button
@click="emit('onCancel', key)"
type="button"
:disabled="!isUploadSetup"
class="m-0 border hover:enabled:bg-red-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center mr-2 border-red-500 hover:enabled:text-white focus:ring-red-800 hover:bg-red-500 disabled:cursor-not-allowed disabled:bg-gray-600 disabled:border-gray-800"
>
<CloseIcon class="w-5 h-3"></CloseIcon>
<span class="sr-only">Cancel</span>
</button>
<button
v-if="value !== UploadStatus.paused"
@click="emit('onPause', key)"
type="button"
:disabled="!isUploadSetup"
class="m-0 border hover:enabled:bg-orange-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center mr-2 border-orange-500 hover:enabled:text-white focus:ring-orange-800 hover:bg-orange-500 disabled:cursor-not-allowed disabled:bg-gray-600 disabled:border-gray-800"
>
<PauseIcon class="w-5 h-3"></PauseIcon>
<span class="sr-only">Pause</span>
</button>
<button
v-if="value === UploadStatus.paused"
@click="emit('onResume', key)"
type="button"
:disabled="!isUploadSetup"
class="m-0 border hover:enabled:bg-green-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center mr-2 border-green-500 hover:enabled:text-white focus:ring-green-800 hover:bg-green-500 disabled:cursor-not-allowed disabled:bg-gray-600 disabled:border-gray-800"
>
<PlayIcon class="w-5 h-3"></PlayIcon>
<span class="sr-only">Resume</span>
</button>
</div>

<LoadingIndicator
v-if="value === 100"
Expand Down Expand Up @@ -128,7 +153,7 @@ const { isOverDropZone } = useDropZone(fileDropZone, { onDrop });
<label
for="add-more-files"
type="button"
class="w-[fit-content] text-blue-700 border border-blue-700 hover:bg-blue-700 hover:text-white focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center border-blue-500 text-blue-500 hover:text-white focus:ring-blue-800 hover:bg-blue-500"
class="w-[fit-content] text-blue-600 border border-blue-700 hover:bg-blue-700 hover:text-white focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center"
>
<PlusIcon class="w-4 h-4"></PlusIcon>
<span class="ml-2">Add more files</span>
Expand Down
1 change: 1 addition & 0 deletions SecureSend/ClientApp/src/models/enums/UploadStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export enum UploadStatus {
completed = "Upload completed",
cancelled = "Upload cancelled",
error = "Error with uploading file",
paused = "Upload paused",
}
1 change: 0 additions & 1 deletion SecureSend/ClientApp/src/utils/composables/useDropZone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export function useDropZone(
return (files.value = list.length === 0 ? null : list);
};
const registerListeners = () => {
console.log("registering");
target.value?.addEventListener("dragenter", (event) => {
event.preventDefault();
counter += 1;
Expand Down
51 changes: 45 additions & 6 deletions SecureSend/ClientApp/src/views/FileUploadView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
:is-upload-setup="isUploadSetup"
@on-fiels-change="(value) => onFilesChange(value)"
@on-cancel="(value) => onCancel(value)"
@on-pause="(value) => onPause(value)"
@on-resume="(value) => onResume(value)"
@on-file-remove="
(value) => {
files.delete(value);
Expand Down Expand Up @@ -126,6 +128,7 @@ let uuid = self.crypto.randomUUID();
const files = ref(new Map<File, number | string | boolean>());
const fileKeys = new Map<string, boolean>();
const pausedFiles = new Map<File, boolean | ((value?: string) => void)>();
const controllers = new Map<string, AbortController>();
let downloadUrl: string;
Expand Down Expand Up @@ -207,9 +210,13 @@ const formReset = async () => {
uuid = self.crypto.randomUUID();
files.value.clear();
fileKeys.clear();
[...controllers.values()].forEach((con) =>
con.signal.removeEventListener("pause", pauseEventListener)
);
controllers.clear();
isUploadSetup.value = false;
isLoading!.value = false;
pausedFiles.clear();
};
const copyToClipboard = () => {
Expand Down Expand Up @@ -237,6 +244,10 @@ const createDownloadUrl = () => {
return downloadUrl;
};
const pauseEventListener = (event: any) => {
pausedFiles.set(event.detail.file, true);
};
const encryptFile = async () => {
const requests: Promise<unknown>[] = [];
for (const [file] of files.value) {
Expand All @@ -247,8 +258,16 @@ const encryptFile = async () => {
try {
if (!controllers.has(file.name)) {
const controller = new AbortController();
controller.signal.addEventListener("pause", pauseEventListener);
controllers.set(file.name, controller);
}
if (pausedFiles.get(file)) {
files.value.set(file, UploadStatus.paused);
const promise = new Promise((res) => {
pausedFiles.set(file, res);
});
await promise;
}
await SecureSendService.uploadChunk(
uuid,
num,
Expand All @@ -265,8 +284,10 @@ const encryptFile = async () => {
: Math.ceil(((num + 1) / totalChunks) * 100)
);
} catch (error: any) {
if (error.code === DOMException.ABORT_ERR) {
if (error === UploadStatus.cancelled) {
files.value.set(file, UploadStatus.cancelled);
} else if (error === UploadStatus.paused) {
files.value.set(file, UploadStatus.paused);
} else {
files.value.set(file, UploadStatus.error);
}
Expand All @@ -282,16 +303,34 @@ const encryptFile = async () => {
results.find(
(promise) =>
promise.status === "rejected" &&
!(promise.reason instanceof DOMException)
promise.reason !== UploadStatus.cancelled
)
) {
throw new Error("Upload error");
}
};
const onCancel = async (name: string) => {
const controller = controllers.get(name);
controller?.abort();
await SecureSendService.cancelUpload({ id: uuid, fileName: name });
const onCancel = async (fileObj: File) => {
const controller = controllers.get(fileObj.name);
if (controller) {
controller.abort(UploadStatus.cancelled);
onResume(fileObj);
await SecureSendService.cancelUpload({ id: uuid, fileName: fileObj.name });
}
};
const onPause = (fileObj: File) => {
const controller = controllers.get(fileObj.name);
controller?.signal.dispatchEvent(
new CustomEvent("pause", { detail: { file: fileObj } })
);
};
const onResume = (fileObj: File) => {
const resolve = pausedFiles.get(fileObj);
if (resolve && typeof resolve == "function") {
resolve();
pausedFiles.set(fileObj, false);
}
};
</script>

0 comments on commit 3e45b3e

Please sign in to comment.