|
50 | 50 | </script> |
51 | 51 |
|
52 | 52 | <script lang="ts"> |
53 | | - import { onDestroy } from "svelte"; |
54 | | -
|
55 | 53 | import Loader from "./Loader.svelte"; |
56 | 54 | import type { LoadingStatus } from "./types"; |
57 | 55 | import type { I18nFormatter } from "@gradio/utils"; |
58 | | - import { createEventDispatcher } from "svelte"; |
59 | 56 |
|
60 | 57 | import { IconButton } from "@gradio/atoms"; |
61 | 58 | import { Clear } from "@gradio/icons"; |
62 | 59 |
|
63 | | - const dispatch = createEventDispatcher(); |
64 | | -
|
65 | | - export let i18n: I18nFormatter; |
66 | | - export let eta: number | null = null; |
67 | | - export let queue_position: number | null; |
68 | | - export let queue_size: number | null; |
69 | | - export let status: |
70 | | - | "complete" |
71 | | - | "pending" |
72 | | - | "error" |
73 | | - | "generating" |
74 | | - | "streaming" |
75 | | - | null; |
76 | | - export let scroll_to_output = false; |
77 | | - export let timer = true; |
78 | | - export let show_progress: "full" | "minimal" | "hidden" = "full"; |
79 | | - export let message: string | null = null; |
80 | | - export let progress: LoadingStatus["progress"] | null | undefined = null; |
81 | | - export let variant: "default" | "center" = "default"; |
82 | | - export let loading_text = "Loading..."; |
83 | | - export let absolute = true; |
84 | | - export let translucent = false; |
85 | | - export let border = false; |
86 | | - export let autoscroll: boolean; |
87 | | - export let validation_error: string | null = null; |
88 | | - export let show_validation_error = true; |
89 | | - export let type: "input" | "outputs" | null = null; |
90 | | -
|
91 | | - $: should_hide = |
92 | | - type === "input" || |
93 | | - !status || |
94 | | - status === "complete" || |
95 | | - show_progress === "hidden" || |
96 | | - status == "streaming" || |
97 | | - (show_validation_error && validation_error); |
| 60 | + interface Props { |
| 61 | + i18n: I18nFormatter; |
| 62 | + eta?: number | null; |
| 63 | + queue_position: number | null; |
| 64 | + queue_size: number | null; |
| 65 | + status: |
| 66 | + | "complete" |
| 67 | + | "pending" |
| 68 | + | "error" |
| 69 | + | "generating" |
| 70 | + | "streaming" |
| 71 | + | null; |
| 72 | + scroll_to_output?: boolean; |
| 73 | + timer?: boolean; |
| 74 | + show_progress?: "full" | "minimal" | "hidden"; |
| 75 | + message?: string | null; |
| 76 | + progress?: LoadingStatus["progress"] | null | undefined; |
| 77 | + variant?: "default" | "center"; |
| 78 | + loading_text?: string; |
| 79 | + absolute?: boolean; |
| 80 | + translucent?: boolean; |
| 81 | + border?: boolean; |
| 82 | + autoscroll: boolean; |
| 83 | + validation_error?: string | null; |
| 84 | + show_validation_error?: boolean; |
| 85 | + type?: "input" | "output" | null; |
| 86 | + on_clear_status?: () => void; |
| 87 | + } |
| 88 | +
|
| 89 | + let { |
| 90 | + i18n, |
| 91 | + eta = null, |
| 92 | + queue_position, |
| 93 | + queue_size, |
| 94 | + status, |
| 95 | + scroll_to_output = false, |
| 96 | + timer = true, |
| 97 | + show_progress = "full", |
| 98 | + message = null, |
| 99 | + progress = null, |
| 100 | + variant = "default", |
| 101 | + loading_text = "Loading...", |
| 102 | + absolute = true, |
| 103 | + translucent = false, |
| 104 | + border = false, |
| 105 | + autoscroll, |
| 106 | + validation_error = null, |
| 107 | + show_validation_error = true, |
| 108 | + type = null, |
| 109 | + on_clear_status |
| 110 | + }: Props = $props(); |
98 | 111 |
|
99 | 112 | let el: HTMLDivElement; |
100 | 113 |
|
101 | | - let _timer = false; |
102 | | - let timer_start = 0; |
103 | | - let timer_diff = 0; |
104 | | - let old_eta: number | null = null; |
105 | | - let eta_from_start: number | null = null; |
106 | | - let message_visible = false; |
107 | | - let eta_level: number | null = 0; |
108 | | - let progress_level: (number | undefined)[] | null = null; |
109 | | - let last_progress_level: number | undefined = undefined; |
110 | | - let progress_bar: HTMLElement | null = null; |
111 | | - let show_eta_bar = true; |
112 | | -
|
113 | | - $: eta_level = |
| 114 | + let _timer = $state(false); |
| 115 | + let timer_start = $state(0); |
| 116 | + let timer_diff = $state(0); |
| 117 | + let old_eta = $state<number | null>(null); |
| 118 | + let eta_from_start = $state<number | null>(null); |
| 119 | + let message_visible = $state(false); |
| 120 | + let progress_level = $state<(number | undefined)[] | null>(null); |
| 121 | + let last_progress_level = $state<number | undefined>(undefined); |
| 122 | + let progress_bar = $state<HTMLElement | null>(null); |
| 123 | + let show_eta_bar = $state(true); |
| 124 | + let formatted_eta = $state<string | null>(null); |
| 125 | + let show_message_timeout = $state<NodeJS.Timeout | null>(null); |
| 126 | +
|
| 127 | + const should_hide = $derived( |
| 128 | + type === "input" || |
| 129 | + !status || |
| 130 | + status === "complete" || |
| 131 | + show_progress === "hidden" || |
| 132 | + status == "streaming" || |
| 133 | + !!(show_validation_error && validation_error) |
| 134 | + ); |
| 135 | +
|
| 136 | + const eta_level = $derived( |
114 | 137 | eta_from_start === null || eta_from_start <= 0 || !timer_diff |
115 | 138 | ? null |
116 | | - : Math.min(timer_diff / eta_from_start, 1); |
117 | | - $: if (progress != null) { |
118 | | - show_eta_bar = false; |
119 | | - } |
| 139 | + : Math.min(timer_diff / eta_from_start, 1) |
| 140 | + ); |
| 141 | +
|
| 142 | + const formatted_timer = $derived(timer_diff.toFixed(1)); |
| 143 | +
|
| 144 | + $effect(() => { |
| 145 | + if (progress != null) { |
| 146 | + show_eta_bar = false; |
| 147 | + } else { |
| 148 | + show_eta_bar = true; |
| 149 | + } |
| 150 | + }); |
120 | 151 |
|
121 | | - $: { |
| 152 | + $effect(() => { |
122 | 153 | if (progress != null) { |
123 | 154 | progress_level = progress.map((p) => { |
124 | 155 | if (p.index != null && p.length != null) { |
|
144 | 175 | } else { |
145 | 176 | last_progress_level = undefined; |
146 | 177 | } |
147 | | - } |
148 | | -
|
149 | | - const start_timer = (): void => { |
150 | | - eta = old_eta = formatted_eta = null; |
151 | | - timer_start = performance.now(); |
152 | | - timer_diff = 0; |
153 | | - _timer = true; |
154 | | - run(); |
155 | | - }; |
| 178 | + }); |
156 | 179 |
|
157 | 180 | function run(): void { |
158 | 181 | raf(() => { |
|
161 | 184 | }); |
162 | 185 | } |
163 | 186 |
|
164 | | - function stop_timer(): void { |
| 187 | + function start_timer(): void { |
| 188 | + old_eta = formatted_eta = null; |
| 189 | + timer_start = performance.now(); |
165 | 190 | timer_diff = 0; |
166 | | - eta = old_eta = formatted_eta = null; |
| 191 | + _timer = true; |
| 192 | + run(); |
| 193 | + } |
167 | 194 |
|
| 195 | + function stop_timer(): void { |
| 196 | + timer_diff = 0; |
| 197 | + old_eta = formatted_eta = null; |
168 | 198 | if (!_timer) return; |
169 | 199 | _timer = false; |
170 | 200 | } |
171 | 201 |
|
172 | | - onDestroy(() => { |
173 | | - if (_timer) stop_timer(); |
174 | | - }); |
175 | | -
|
176 | | - $: { |
| 202 | + $effect(() => { |
177 | 203 | if (status === "pending") { |
178 | 204 | start_timer(); |
179 | 205 | } else { |
180 | 206 | stop_timer(); |
181 | 207 | } |
182 | | - } |
183 | 208 |
|
184 | | - $: el && |
185 | | - scroll_to_output && |
186 | | - (status === "pending" || status === "complete") && |
187 | | - scroll_into_view(el, autoscroll); |
| 209 | + return () => { |
| 210 | + if (_timer) stop_timer(); |
| 211 | + }; |
| 212 | + }); |
188 | 213 |
|
189 | | - let formatted_eta: string | null = null; |
190 | | - $: { |
| 214 | + $effect(() => { |
| 215 | + if ( |
| 216 | + el && |
| 217 | + scroll_to_output && |
| 218 | + (status === "pending" || status === "complete") |
| 219 | + ) { |
| 220 | + scroll_into_view(el, autoscroll); |
| 221 | + } |
| 222 | + }); |
| 223 | +
|
| 224 | + $effect(() => { |
191 | 225 | if (eta === null) { |
192 | 226 | eta = old_eta; |
193 | 227 | } |
|
196 | 230 | formatted_eta = eta_from_start.toFixed(1); |
197 | 231 | old_eta = eta; |
198 | 232 | } |
199 | | - } |
200 | | - let show_message_timeout: NodeJS.Timeout | null = null; |
| 233 | + }); |
| 234 | +
|
201 | 235 | function close_message(): void { |
202 | 236 | message_visible = false; |
203 | 237 | if (show_message_timeout !== null) { |
204 | 238 | clearTimeout(show_message_timeout); |
205 | 239 | } |
206 | 240 | } |
207 | | - $: { |
| 241 | +
|
| 242 | + $effect(() => { |
208 | 243 | close_message(); |
209 | 244 | if (status === "error" && message) { |
210 | 245 | message_visible = true; |
211 | 246 | } |
212 | | - } |
213 | | - $: formatted_timer = timer_diff.toFixed(1); |
| 247 | + }); |
214 | 248 | </script> |
215 | 249 |
|
216 | 250 | <div |
|
240 | 274 | background="var(--background-fill-primary)" |
241 | 275 | color="var(--error-background-text)" |
242 | 276 | border="var(--border-color-primary)" |
243 | | - on:click={() => (validation_error = null)} |
| 277 | + onclick={() => (validation_error = null)} |
244 | 278 | /></button |
245 | 279 | > |
246 | 280 | </div> |
|
324 | 358 | Icon={Clear} |
325 | 359 | label={i18n("common.clear")} |
326 | 360 | disabled={false} |
327 | | - on:click={() => { |
328 | | - dispatch("clear_status"); |
| 361 | + onclick={() => { |
| 362 | + on_clear_status?.(); |
329 | 363 | }} |
330 | 364 | /> |
331 | 365 | </div> |
|
0 commit comments