UBER-924: Fix file upload progress (#3757)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2023-09-28 17:50:37 +07:00 committed by GitHub
parent 3e8cbb18af
commit e1cdd7636a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 26 deletions

View File

@ -14,10 +14,22 @@
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'
import Spinner from './Spinner.svelte'
export let shrink: boolean = false
export let label: string = ''
const dispatch = createEventDispatcher()
let timer: any
onMount(() => {
timer = setTimeout(() => {
dispatch('progress')
}, 50)
return () => {
clearTimeout(timer)
}
})
</script>
<div class="spinner-container" class:fullSize={!shrink}>

View File

@ -17,7 +17,7 @@
import type { Doc } from '@hcengineering/core'
import { Attachment } from '@hcengineering/attachment'
import { createQuery, getClient } from '@hcengineering/presentation'
import { ActionIcon, IconAdd, Label } from '@hcengineering/ui'
import { ActionIcon, IconAdd, Label, Loading } from '@hcengineering/ui'
import { AttachmentPresenter } from '..'
import attachment from '../plugin'
import { uploadFile } from '../utils'
@ -31,6 +31,8 @@
let docs: Attachment[] = []
let progress = false
const query = createQuery()
$: query.query(
attachment.class.Attachment,
@ -59,14 +61,19 @@
})
}
function fileSelected () {
async function fileSelected (): Promise<void> {
progress = true
const list = inputFile.files
if (list === null || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
if (file !== null) {
await createAttachment(file)
}
}
inputFile.value = ''
progress = false
}
let inputFile: HTMLInputElement
@ -94,7 +101,11 @@
</div>
{#if canAdd}
<div>
{#if progress}
<Loading />
{:else}
<ActionIcon size={'medium'} icon={IconAdd} action={add} />
{/if}
</div>
{/if}
</div>

View File

@ -16,7 +16,7 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { Attachment } from '@hcengineering/attachment'
import { showPopup, closeTooltip, Label, getIconSize2x } from '@hcengineering/ui'
import { showPopup, closeTooltip, Label, getIconSize2x, Loading } from '@hcengineering/ui'
import presentation, { PDFViewer, getFileUrl } from '@hcengineering/presentation'
import filesize from 'filesize'
@ -24,6 +24,8 @@
export let removable: boolean = false
export let showPreview = false
export let progress: boolean = false
const dispatch = createEventDispatcher()
const maxLenght: number = 30
@ -100,7 +102,11 @@
class:image={isImage(value.type)}
style={imgStyle}
>
{#if !isImage(value.type)}{iconLabel(value.name)}{/if}
{#if progress}
<div class="flex p-3">
<Loading />
</div>
{:else if !isImage(value.type)}{iconLabel(value.name)}{/if}
</div>
{:else}
<div class="flex-center icon">

View File

@ -19,9 +19,9 @@
import { deleteFile, uploadFile } from '../utils'
import attachment from '../plugin'
import { IntlString, setPlatformStatus, unknownError, Asset } from '@hcengineering/platform'
import { createEventDispatcher, onDestroy } from 'svelte'
import { createEventDispatcher, onDestroy, tick } from 'svelte'
import { Account, Class, Doc, generateId, IdMap, Ref, Space, toIdMap } from '@hcengineering/core'
import type { AnySvelteComponent } from '@hcengineering/ui'
import { Loading, type AnySvelteComponent } from '@hcengineering/ui'
import { Attachment } from '@hcengineering/attachment'
import AttachmentPresenter from './AttachmentPresenter.svelte'
@ -59,6 +59,8 @@
const newAttachments: Set<Ref<Attachment>> = new Set<Ref<Attachment>>()
const removedAttachments: Set<Attachment> = new Set<Attachment>()
let progress = false
let refContainer: HTMLElement
$: objectId && updateAttachments(objectId)
@ -128,24 +130,33 @@
await client.addCollection(attachment.class.Attachment, space, objectId, _class, 'attachments', doc, doc._id)
}
function fileSelected () {
async function fileSelected (): Promise<void> {
progress = true
await tick()
const list = inputFile.files
if (list === null || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
if (file !== null) {
await createAttachment(file)
}
}
inputFile.value = ''
progress = false
}
function fileDrop (e: DragEvent) {
async function fileDrop (e: DragEvent): Promise<void> {
progress = true
const list = e.dataTransfer?.files
if (list === undefined || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
if (file !== null) {
await createAttachment(file)
}
}
progress = false
}
async function removeAttachment (attachment: Attachment): Promise<void> {
removedAttachments.add(attachment)
@ -221,7 +232,7 @@
dispatch('update', { message: event.detail, attachments: attachments.size })
}
function pasteAction (evt: ClipboardEvent): void {
async function pasteAction (evt: ClipboardEvent): Promise<void> {
let t: HTMLElement | null = evt.target as HTMLElement
let allowed = false
while (t != null) {
@ -235,15 +246,17 @@
}
const items = evt.clipboardData?.items ?? []
progress = true
for (const index in items) {
const item = items[index]
if (item.kind === 'file') {
const blob = item.getAsFile()
if (blob !== null) {
createAttachment(blob)
await createAttachment(blob)
}
}
}
progress = false
}
</script>
@ -263,8 +276,13 @@
on:dragleave={() => {}}
on:drop|preventDefault|stopPropagation={fileDrop}
>
{#if attachments.size}
{#if attachments.size || progress}
<div class="flex-row-center list scroll-divider-color">
{#if progress}
<div class="flex p-3">
<Loading />
</div>
{/if}
{#each Array.from(attachments.values()) as attachment}
<div class="item flex">
<AttachmentPresenter

View File

@ -117,8 +117,7 @@
_class={object._class}
space={object.space}
alwaysEdit
on:attached={(e) => descriptionBox.saveNewAttachment(e.detail)}
on:detached={(e) => descriptionBox.removeAttachmentById(e.detail)}
useDirectAttachDelete
showButtons
on:blur={() => save(object, description)}
on:changeContent={triggerSave}

View File

@ -25,6 +25,7 @@
import AttachmentPresenter from './AttachmentPresenter.svelte'
import AttachmentPreview from './AttachmentPreview.svelte'
import { ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
import Loading from '@hcengineering/ui/src/components/Loading.svelte'
export let objectId: Ref<Doc> | undefined = undefined
export let space: Ref<Space> | undefined = undefined
@ -46,6 +47,10 @@
export let enableBackReferences: boolean = false
export let isScrollable = true
export let useDirectAttachDelete = false
let progress = false
let draftKey = objectId ? `${objectId}_attachments` : undefined
$: draftKey = objectId ? `${objectId}_attachments` : undefined
@ -164,6 +169,10 @@
saveDraft()
dispatch('attach', { action: 'saved', value: attachments.size })
dispatch('attached', _id)
if (useDirectAttachDelete) {
saveNewAttachment(_id)
}
return { file: uuid, type: file.type }
} catch (err: any) {
setPlatformStatus(unknownError(err))
@ -176,33 +185,48 @@
await client.addCollection(attachment.class.Attachment, space, objectId, _class, 'attachments', doc, doc._id)
}
function fileSelected () {
async function fileSelected (): Promise<void> {
progress = true
const list = inputFile.files
if (list === null || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
if (file !== null) {
await createAttachment(file)
}
}
inputFile.value = ''
progress = false
}
export function fileDrop (e: DragEvent) {
export async function fileDrop (e: DragEvent): Promise<void> {
progress = true
const list = e.dataTransfer?.files
if (list !== undefined && list.length !== 0) {
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
if (file !== null) {
await createAttachment(file)
}
}
}
progress = false
}
async function removeAttachment (attachment: Attachment): Promise<void> {
if (useDirectAttachDelete) {
progressItems.push(attachment._id)
progressItems = progressItems
await deleteAttachment(attachment)
}
removedAttachments.add(attachment)
attachments.delete(attachment._id)
attachments = attachments
refInput.removeAttachment(attachment.file)
saveDraft()
dispatch('detached', attachment._id)
progressItems = progressItems.filter((it) => it !== attachment._id)
}
async function deleteAttachment (attachment: Attachment): Promise<void> {
@ -299,7 +323,7 @@
return false
}
export function pasteAction (evt: ClipboardEvent): void {
export async function pasteAction (evt: ClipboardEvent): Promise<void> {
if (!isAllowedPaste(evt)) {
return
}
@ -310,7 +334,7 @@
if (item.kind === 'file') {
const blob = item.getAsFile()
if (blob !== null) {
createAttachment(blob)
await createAttachment(blob)
}
}
}
@ -323,6 +347,9 @@
size: attachments.size,
values: attachments.size === 0 ? true : attachments
})
let element: HTMLElement
let progressItems: Ref<Doc>[] = []
</script>
<input
@ -373,7 +400,7 @@
}}
/>
</div>
{#if attachments.size && enableAttachments}
{#if (attachments.size && enableAttachments) || progress}
<div class="flex-row-center list scroll-divider-color">
{#each Array.from(attachments.values()) as attachment, index}
<div class="item flex-center flex-no-shrink clear-mins">
@ -384,13 +411,25 @@
value={attachment}
removable
showPreview
progress={progressItems.includes(attachment._id)}
on:remove={(result) => {
if (result !== undefined) removeAttachment(attachment)
if (result !== undefined) {
removeAttachment(attachment)
}
}}
/>
{/if}
</div>
{/each}
{#if progress}
<div class="flex p-3" bind:this={element}>
<Loading
on:progress={() => {
element.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' })
}}
/>
</div>
{/if}
</div>
{/if}
</div>

View File

@ -36,6 +36,8 @@
const notificationClient = NotificationClientImpl.getClient()
let objectId = generateId()
let progress = false
let copy: string = ''
const obj: Data<NewMessage> = {
@ -82,6 +84,7 @@
let inputFile: HTMLInputElement
function fileSelected () {
progress = true
const list = inputFile.files
if (list === null || list.length === 0) return
for (let index = 0; index < list.length; index++) {
@ -89,17 +92,20 @@
if (file !== null) createAttachment(file)
}
inputFile.value = ''
progress = false
}
function fileDrop (e: DragEvent) {
e.preventDefault()
e.stopPropagation()
progress = true
const list = e.dataTransfer?.files
if (list === undefined || list.length === 0) return
for (let index = 0; index < list.length; index++) {
const file = list.item(index)
if (file !== null) createAttachment(file)
}
progress = false
}
async function createAttachment (file: File) {
@ -187,11 +193,12 @@
<Button
icon={IconAttachment}
kind={'ghost'}
loading={progress}
on:click={() => {
inputFile.click()
}}
/>
<Button label={plugin.string.Send} kind={'accented'} on:click={sendMsg} />
<Button label={plugin.string.Send} kind={'accented'} disabled={progress} on:click={sendMsg} />
</div>
</div>
{#if attachments.length}