@gradio/upload 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +3 -3
- package/src/Upload.svelte +43 -31
- package/src/UploadProgress.svelte +174 -0
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# @gradio/upload
|
2
2
|
|
3
|
+
## 0.4.0
|
4
|
+
|
5
|
+
### Features
|
6
|
+
|
7
|
+
- [#6356](https://github.com/gradio-app/gradio/pull/6356) [`854b482f5`](https://github.com/gradio-app/gradio/commit/854b482f598e0dc47673846631643c079576da9c) - Redesign file upload. Thanks [@hannahblair](https://github.com/hannahblair)!
|
8
|
+
- [#6307](https://github.com/gradio-app/gradio/pull/6307) [`f1409f95e`](https://github.com/gradio-app/gradio/commit/f1409f95ed39c5565bed6a601e41f94e30196a57) - Provide status updates on file uploads. Thanks [@freddyaboulton](https://github.com/freddyaboulton)!
|
9
|
+
|
3
10
|
## 0.3.3
|
4
11
|
|
5
12
|
### Fixes
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@gradio/upload",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"description": "Gradio UI packages",
|
5
5
|
"type": "module",
|
6
6
|
"main": "src/index.ts",
|
@@ -9,8 +9,8 @@
|
|
9
9
|
"dependencies": {
|
10
10
|
"@gradio/atoms": "^0.2.1",
|
11
11
|
"@gradio/icons": "^0.2.0",
|
12
|
-
"@gradio/client": "^0.
|
13
|
-
"@gradio/upload": "^0.
|
12
|
+
"@gradio/client": "^0.8.0",
|
13
|
+
"@gradio/upload": "^0.4.0",
|
14
14
|
"@gradio/utils": "^0.2.0"
|
15
15
|
},
|
16
16
|
"main_changeset": true,
|
package/src/Upload.svelte
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
import type { FileData } from "@gradio/client";
|
4
4
|
import { upload_files, upload, prepare_files } from "@gradio/client";
|
5
5
|
import { _ } from "svelte-i18n";
|
6
|
+
import UploadProgress from "./UploadProgress.svelte";
|
6
7
|
|
7
8
|
export let filetype: string | null = null;
|
8
9
|
export let dragging = false;
|
@@ -15,6 +16,10 @@
|
|
15
16
|
export let hidden = false;
|
16
17
|
export let include_sources = false;
|
17
18
|
|
19
|
+
let uploading = false;
|
20
|
+
let upload_id: string;
|
21
|
+
let file_data: FileData[];
|
22
|
+
|
18
23
|
// Needed for wasm support
|
19
24
|
const upload_fn = getContext<typeof upload_files>("upload_files");
|
20
25
|
|
@@ -36,8 +41,11 @@
|
|
36
41
|
file_data: FileData[]
|
37
42
|
): Promise<(FileData | null)[]> {
|
38
43
|
await tick();
|
39
|
-
|
44
|
+
upload_id = Math.random().toString(36).substring(2, 15);
|
45
|
+
uploading = true;
|
46
|
+
const _file_data = await upload(file_data, root, upload_id, upload_fn);
|
40
47
|
dispatch("load", file_count === "single" ? _file_data?.[0] : _file_data);
|
48
|
+
uploading = false;
|
41
49
|
return _file_data || [];
|
42
50
|
}
|
43
51
|
|
@@ -48,7 +56,7 @@
|
|
48
56
|
return;
|
49
57
|
}
|
50
58
|
let _files: File[] = files.map((f) => new File([f], f.name));
|
51
|
-
|
59
|
+
file_data = await prepare_files(_files);
|
52
60
|
return await handle_upload(file_data);
|
53
61
|
}
|
54
62
|
|
@@ -90,35 +98,39 @@
|
|
90
98
|
}
|
91
99
|
</script>
|
92
100
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
101
|
+
{#if uploading}
|
102
|
+
<UploadProgress {root} {upload_id} files={file_data} />
|
103
|
+
{:else}
|
104
|
+
<button
|
105
|
+
class:hidden
|
106
|
+
class:center
|
107
|
+
class:boundedheight
|
108
|
+
class:flex
|
109
|
+
style:height={include_sources ? "calc(100% - 40px" : "100%"}
|
110
|
+
on:drag|preventDefault|stopPropagation
|
111
|
+
on:dragstart|preventDefault|stopPropagation
|
112
|
+
on:dragend|preventDefault|stopPropagation
|
113
|
+
on:dragover|preventDefault|stopPropagation
|
114
|
+
on:dragenter|preventDefault|stopPropagation
|
115
|
+
on:dragleave|preventDefault|stopPropagation
|
116
|
+
on:drop|preventDefault|stopPropagation
|
117
|
+
on:click={open_file_upload}
|
118
|
+
on:drop={loadFilesFromDrop}
|
119
|
+
on:dragenter={updateDragging}
|
120
|
+
on:dragleave={updateDragging}
|
121
|
+
>
|
122
|
+
<slot />
|
123
|
+
<input
|
124
|
+
type="file"
|
125
|
+
bind:this={hidden_upload}
|
126
|
+
on:change={load_files_from_upload}
|
127
|
+
accept={filetype}
|
128
|
+
multiple={file_count === "multiple" || undefined}
|
129
|
+
webkitdirectory={file_count === "directory" || undefined}
|
130
|
+
mozdirectory={file_count === "directory" || undefined}
|
131
|
+
/>
|
132
|
+
</button>
|
133
|
+
{/if}
|
122
134
|
|
123
135
|
<style>
|
124
136
|
button {
|
@@ -0,0 +1,174 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import { FileData } from "@gradio/client";
|
3
|
+
import { onMount, createEventDispatcher } from "svelte";
|
4
|
+
|
5
|
+
type FileDataWithProgress = FileData & { progress: number };
|
6
|
+
|
7
|
+
export let upload_id: string;
|
8
|
+
export let root: string;
|
9
|
+
export let files: FileData[];
|
10
|
+
|
11
|
+
let event_source: EventSource;
|
12
|
+
let progress = false;
|
13
|
+
let current_file_upload: FileDataWithProgress;
|
14
|
+
|
15
|
+
let files_with_progress: FileDataWithProgress[] = files.map((file) => {
|
16
|
+
return {
|
17
|
+
...file,
|
18
|
+
progress: 0
|
19
|
+
};
|
20
|
+
});
|
21
|
+
|
22
|
+
const dispatch = createEventDispatcher();
|
23
|
+
|
24
|
+
function handleProgress(filename: string, chunk_size: number): void {
|
25
|
+
// Find the corresponding file in the array and update its progress
|
26
|
+
files_with_progress = files_with_progress.map((file) => {
|
27
|
+
if (file.orig_name === filename) {
|
28
|
+
file.progress += chunk_size;
|
29
|
+
}
|
30
|
+
return file;
|
31
|
+
});
|
32
|
+
}
|
33
|
+
|
34
|
+
function getProgress(file: FileDataWithProgress): number {
|
35
|
+
return (file.progress * 100) / (file.size || 0) || 0;
|
36
|
+
}
|
37
|
+
|
38
|
+
onMount(() => {
|
39
|
+
event_source = new EventSource(
|
40
|
+
`${root}/upload_progress?upload_id=${upload_id}`
|
41
|
+
);
|
42
|
+
// Event listener for progress updates
|
43
|
+
event_source.onmessage = async function (event) {
|
44
|
+
const _data = JSON.parse(event.data);
|
45
|
+
if (!progress) progress = true;
|
46
|
+
if (_data.msg === "done") {
|
47
|
+
event_source.close();
|
48
|
+
dispatch("done");
|
49
|
+
} else {
|
50
|
+
current_file_upload = _data;
|
51
|
+
handleProgress(_data.orig_name, _data.chunk_size);
|
52
|
+
}
|
53
|
+
};
|
54
|
+
});
|
55
|
+
|
56
|
+
function calculateTotalProgress(files: FileData[]): number {
|
57
|
+
let totalProgress = 0;
|
58
|
+
files.forEach((file) => {
|
59
|
+
totalProgress += getProgress(file as FileDataWithProgress);
|
60
|
+
});
|
61
|
+
|
62
|
+
document.documentElement.style.setProperty(
|
63
|
+
"--upload-progress-width",
|
64
|
+
(totalProgress / files.length).toFixed(2) + "%"
|
65
|
+
);
|
66
|
+
|
67
|
+
return totalProgress / files.length;
|
68
|
+
}
|
69
|
+
|
70
|
+
$: calculateTotalProgress(files_with_progress);
|
71
|
+
</script>
|
72
|
+
|
73
|
+
<div class="wrap" class:progress>
|
74
|
+
<span class="uploading"
|
75
|
+
>Uploading {files_with_progress.length}
|
76
|
+
{files_with_progress.length > 1 ? "files" : "file"}...</span
|
77
|
+
>
|
78
|
+
|
79
|
+
{#if current_file_upload}
|
80
|
+
<div class="file">
|
81
|
+
<span>
|
82
|
+
<div class="progress-bar">
|
83
|
+
<progress
|
84
|
+
style="visibility:hidden;height:0;width:0;"
|
85
|
+
value={getProgress(current_file_upload)}
|
86
|
+
max="100">{getProgress(current_file_upload)}</progress
|
87
|
+
>
|
88
|
+
</div>
|
89
|
+
</span>
|
90
|
+
<span class="file-name">
|
91
|
+
{current_file_upload.orig_name}
|
92
|
+
</span>
|
93
|
+
</div>
|
94
|
+
{/if}
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<style>
|
98
|
+
.wrap {
|
99
|
+
overflow-y: auto;
|
100
|
+
transition: opacity 0.5s ease-in-out;
|
101
|
+
background: var(--block-background-fill);
|
102
|
+
position: relative;
|
103
|
+
display: flex;
|
104
|
+
flex-direction: column;
|
105
|
+
align-items: center;
|
106
|
+
justify-content: center;
|
107
|
+
min-height: var(--size-40);
|
108
|
+
}
|
109
|
+
|
110
|
+
.wrap::after {
|
111
|
+
content: "";
|
112
|
+
position: absolute;
|
113
|
+
top: 0;
|
114
|
+
left: 0;
|
115
|
+
width: var(--upload-progress-width);
|
116
|
+
height: 100%;
|
117
|
+
transition: all 0.5s ease-in-out;
|
118
|
+
z-index: 1;
|
119
|
+
}
|
120
|
+
|
121
|
+
.uploading {
|
122
|
+
font-size: var(--text-lg);
|
123
|
+
font-family: var(--font);
|
124
|
+
z-index: 2;
|
125
|
+
}
|
126
|
+
|
127
|
+
.file-name {
|
128
|
+
margin: var(--spacing-md);
|
129
|
+
font-size: var(--text-lg);
|
130
|
+
color: var(--body-text-color-subdued);
|
131
|
+
}
|
132
|
+
|
133
|
+
.file {
|
134
|
+
font-size: var(--text-md);
|
135
|
+
z-index: 2;
|
136
|
+
display: flex;
|
137
|
+
align-items: center;
|
138
|
+
}
|
139
|
+
|
140
|
+
.file progress {
|
141
|
+
display: inline;
|
142
|
+
height: var(--size-1);
|
143
|
+
width: 100%;
|
144
|
+
transition: all 0.5s ease-in-out;
|
145
|
+
color: var(--color-accent);
|
146
|
+
border: none;
|
147
|
+
}
|
148
|
+
|
149
|
+
.file progress[value]::-webkit-progress-value {
|
150
|
+
background-color: var(--color-accent);
|
151
|
+
border-radius: 20px;
|
152
|
+
}
|
153
|
+
|
154
|
+
.file progress[value]::-webkit-progress-bar {
|
155
|
+
background-color: var(--border-color-accent);
|
156
|
+
border-radius: 20px;
|
157
|
+
}
|
158
|
+
|
159
|
+
.progress-bar {
|
160
|
+
width: 14px;
|
161
|
+
height: 14px;
|
162
|
+
border-radius: 50%;
|
163
|
+
background: radial-gradient(
|
164
|
+
closest-side,
|
165
|
+
var(--block-background-fill) 64%,
|
166
|
+
transparent 53% 100%
|
167
|
+
),
|
168
|
+
conic-gradient(
|
169
|
+
var(--color-accent) var(--upload-progress-width),
|
170
|
+
var(--border-color-accent) 0
|
171
|
+
);
|
172
|
+
transition: all 0.5s ease-in-out;
|
173
|
+
}
|
174
|
+
</style>
|