mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-02 17:55:52 +02:00
enhance(frontend): ファイルのアップロードを中止できるように (#16069)
* enhance(frontend): ファイルのアップロードを中止できるように * Update Changelog * fix: ダイアログを閉じたり、中断ボタンが押されたりしたときはその後のアップロードをすべて中止するように * fix
This commit is contained in:
@@ -130,7 +130,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 8px 16px;
|
||||
padding: 12px 16px;
|
||||
overflow: auto;
|
||||
background: var(--MI_THEME-bg);
|
||||
border-top: 1px solid var(--MI_THEME-divider);
|
||||
|
||||
@@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div :class="$style.root">
|
||||
<div :class="[$style.overallProgress, canRetry ? $style.overallProgressError : null]" :style="{ '--op': `${overallProgress}%` }"></div>
|
||||
|
||||
<div :class="$style.main" class="_gaps_s">
|
||||
<div :class="$style.items" class="_gaps_s">
|
||||
<div class="_gaps_s _spacer">
|
||||
<div class="_gaps_s">
|
||||
<div
|
||||
v-for="ctx in items"
|
||||
:key="ctx.id"
|
||||
@@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template #footer>
|
||||
<div class="_buttonsCenter">
|
||||
<MkButton v-if="isUploading" rounded @click="cancel()"><i class="ti ti-x"></i> {{ i18n.ts.cancel }}</MkButton>
|
||||
<MkButton v-if="isUploading" rounded @click="abortWithConfirm()"><i class="ti ti-x"></i> {{ i18n.ts.abort }}</MkButton>
|
||||
<MkButton v-else-if="!firstUploadAttempted" primary rounded @click="upload()"><i class="ti ti-upload"></i> {{ i18n.ts.upload }}</MkButton>
|
||||
|
||||
<MkButton v-if="canRetry" rounded @click="upload()"><i class="ti ti-reload"></i> {{ i18n.ts.retry }}</MkButton>
|
||||
@@ -96,10 +96,9 @@ import { i18n } from '@/i18n.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import bytes from '@/filters/bytes.js';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import { isWebpSupported } from '@/utility/isWebpSupported.js';
|
||||
import { uploadFile } from '@/utility/drive.js';
|
||||
import { uploadFile, UploadAbortedError } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
|
||||
@@ -138,7 +137,7 @@ const emit = defineEmits<{
|
||||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const items = ref([] as {
|
||||
const items = ref<{
|
||||
id: string;
|
||||
name: string;
|
||||
progress: { max: number; value: number } | null;
|
||||
@@ -147,10 +146,12 @@ const items = ref([] as {
|
||||
uploading: boolean;
|
||||
uploaded: Misskey.entities.DriveFile | null;
|
||||
uploadFailed: boolean;
|
||||
aborted: boolean;
|
||||
compressedSize?: number | null;
|
||||
compressedImage?: Blob | null;
|
||||
file: File;
|
||||
}[]);
|
||||
abort?: (() => void) | null;
|
||||
}[]>([]);
|
||||
|
||||
const dialog = useTemplateRef('dialog');
|
||||
|
||||
@@ -213,10 +214,23 @@ async function cancel() {
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
abortAll();
|
||||
emit('canceled');
|
||||
dialog.value?.close();
|
||||
}
|
||||
|
||||
async function abortWithConfirm() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.ts._uploader.abortConfirm,
|
||||
okText: i18n.ts.yes,
|
||||
cancelText: i18n.ts.no,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
abortAll();
|
||||
}
|
||||
|
||||
async function done() {
|
||||
if (items.value.some(item => item.uploaded == null)) {
|
||||
const { canceled } = await os.confirm({
|
||||
@@ -258,6 +272,17 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
|
||||
items.value.splice(items.value.indexOf(item), 1);
|
||||
},
|
||||
});
|
||||
} else if (item.uploading) {
|
||||
menu.push({
|
||||
icon: 'ti ti-cloud-pause',
|
||||
text: i18n.ts.abort,
|
||||
danger: true,
|
||||
action: () => {
|
||||
if (item.abort != null) {
|
||||
item.abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
||||
@@ -266,7 +291,20 @@ function showMenu(ev: MouseEvent, item: typeof items.value[0]) {
|
||||
async function upload() { // エラーハンドリングなどを考慮してシーケンシャルにやる
|
||||
firstUploadAttempted.value = true;
|
||||
|
||||
items.value = items.value.map(item => ({
|
||||
...item,
|
||||
aborted: false,
|
||||
uploadFailed: false,
|
||||
waiting: false,
|
||||
uploading: false,
|
||||
}));
|
||||
|
||||
for (const item of items.value.filter(item => item.uploaded == null)) {
|
||||
// アップロード処理途中で値が変わる場合(途中で全キャンセルされたりなど)もあるので、Array filterではなくここでチェック
|
||||
if (item.aborted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item.waiting = true;
|
||||
item.uploadFailed = false;
|
||||
|
||||
@@ -296,7 +334,7 @@ async function upload() { // エラーハンドリングなどを考慮してシ
|
||||
|
||||
item.uploading = true;
|
||||
|
||||
const driveFile = await uploadFile(item.compressedImage ?? item.file, {
|
||||
const { filePromise, abort } = uploadFile(item.compressedImage ?? item.file, {
|
||||
name: item.name,
|
||||
folderId: props.folderId,
|
||||
onProgress: (progress) => {
|
||||
@@ -308,16 +346,43 @@ async function upload() { // エラーハンドリングなどを考慮してシ
|
||||
item.progress.max = progress.total;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
item.abort = () => {
|
||||
item.abort = null;
|
||||
abort();
|
||||
item.uploading = false;
|
||||
item.waiting = false;
|
||||
item.uploadFailed = true;
|
||||
};
|
||||
|
||||
await filePromise.then((file) => {
|
||||
item.uploaded = file;
|
||||
item.abort = null;
|
||||
}).catch(err => {
|
||||
item.uploadFailed = true;
|
||||
item.progress = null;
|
||||
throw err;
|
||||
if (!(err instanceof UploadAbortedError)) {
|
||||
throw err;
|
||||
}
|
||||
}).finally(() => {
|
||||
item.uploading = false;
|
||||
item.waiting = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
item.uploaded = driveFile;
|
||||
function abortAll() {
|
||||
for (const item of items.value) {
|
||||
if (item.uploaded != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.abort != null) {
|
||||
item.abort();
|
||||
}
|
||||
item.aborted = true;
|
||||
item.uploadFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +405,7 @@ function initializeFile(file: File) {
|
||||
thumbnail: window.URL.createObjectURL(file),
|
||||
waiting: false,
|
||||
uploading: false,
|
||||
aborted: false,
|
||||
uploaded: null,
|
||||
uploadFailed: false,
|
||||
file: markRaw(file),
|
||||
@@ -373,13 +439,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.items {
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
|
||||
Reference in New Issue
Block a user