hazo_files 3.2.0 → 3.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/CHANGE_LOG.md +35 -0
- package/dist/background-upload/index.d.mts +1 -0
- package/dist/background-upload/index.d.ts +1 -0
- package/dist/background-upload/index.js +3 -0
- package/dist/background-upload/index.mjs +3 -0
- package/dist/background-upload/react/index.d.mts +1 -0
- package/dist/background-upload/react/index.d.ts +1 -0
- package/dist/background-upload/react/index.js +122 -5
- package/dist/background-upload/react/index.mjs +123 -6
- package/dist/ui/index.js +235 -109
- package/dist/ui/index.mjs +235 -109
- package/package.json +17 -13
package/CHANGE_LOG.md
CHANGED
|
@@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 3.4.0 — 2026-09-19
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Migrated onto the canonical `hazo_core/i18n` bridge (`createPackageT` /
|
|
13
|
+
`resolvePackageLocale`), replacing this package's local ~120-line copy at
|
|
14
|
+
`src/lib/create_package_t.ts` (now deleted). All 13 call sites across
|
|
15
|
+
`src/ui/components/**` and `src/background_upload/react/use-file-upload-toasts.ts`
|
|
16
|
+
now import directly from `hazo_core/i18n`. Behavior is unchanged — same
|
|
17
|
+
flat `src/locales/en.json` fallback catalog, same `{{var}}` mustache
|
|
18
|
+
interpolation, same optional/no-op `hazo_i18n` registration side effect.
|
|
19
|
+
`hazo_core` peer bumped to `^2.4.0` (first version shipping the `/i18n`
|
|
20
|
+
subpath) and `hazo_i18n` peer bumped to `^0.5.0`. Added an "i18n bridge"
|
|
21
|
+
autotest scenario group to the test-app covering catalog load, key
|
|
22
|
+
coverage, and interpolation.
|
|
23
|
+
|
|
24
|
+
## 3.3.0 — 2026-08-13
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
`HazoFileUploadProvider` handed the live tree a destroyed `UploadManager` after
|
|
29
|
+
a remount. The provider created the manager in a `useRef` and destroyed it in
|
|
30
|
+
its `useEffect` cleanup, but never rebuilt it. Under React StrictMode (dev
|
|
31
|
+
double-mount) or any real remount, the cleanup ran `manager.destroy()`, then the
|
|
32
|
+
re-run setup reused the same destroyed instance — so every `submit_batch` threw
|
|
33
|
+
`UploadManager is destroyed`. The effect now rebuilds the manager when it finds
|
|
34
|
+
a destroyed one and forces a re-render so the context value points at the fresh
|
|
35
|
+
instance.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- `UploadManager.is_destroyed` getter, so consumers (and the provider) can check
|
|
40
|
+
lifecycle state without touching internals.
|
|
41
|
+
|
|
42
|
+
|
|
8
43
|
## 3.2.0 — 2026-08-04
|
|
9
44
|
|
|
10
45
|
### Fixed
|
|
@@ -152,6 +152,7 @@ declare class UploadManager {
|
|
|
152
152
|
private destroyed;
|
|
153
153
|
private readonly config;
|
|
154
154
|
constructor(config?: UploadManagerConfig);
|
|
155
|
+
get is_destroyed(): boolean;
|
|
155
156
|
on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
|
|
156
157
|
submit_batch(options: CreateBatchOptions): string;
|
|
157
158
|
get_jobs_for_group(group_id: string): JobSnapshot[];
|
|
@@ -152,6 +152,7 @@ declare class UploadManager {
|
|
|
152
152
|
private destroyed;
|
|
153
153
|
private readonly config;
|
|
154
154
|
constructor(config?: UploadManagerConfig);
|
|
155
|
+
get is_destroyed(): boolean;
|
|
155
156
|
on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
|
|
156
157
|
submit_batch(options: CreateBatchOptions): string;
|
|
157
158
|
get_jobs_for_group(group_id: string): JobSnapshot[];
|
|
@@ -201,6 +201,9 @@ var UploadManager = class {
|
|
|
201
201
|
this.emitter.on("job:completed", ({ job }) => this.on_job_settled(job));
|
|
202
202
|
this.emitter.on("job:error", ({ job }) => this.on_job_settled(job));
|
|
203
203
|
}
|
|
204
|
+
get is_destroyed() {
|
|
205
|
+
return this.destroyed;
|
|
206
|
+
}
|
|
204
207
|
on(event, listener) {
|
|
205
208
|
return this.emitter.on(event, listener);
|
|
206
209
|
}
|
|
@@ -172,6 +172,9 @@ var UploadManager = class {
|
|
|
172
172
|
this.emitter.on("job:completed", ({ job }) => this.on_job_settled(job));
|
|
173
173
|
this.emitter.on("job:error", ({ job }) => this.on_job_settled(job));
|
|
174
174
|
}
|
|
175
|
+
get is_destroyed() {
|
|
176
|
+
return this.destroyed;
|
|
177
|
+
}
|
|
175
178
|
on(event, listener) {
|
|
176
179
|
return this.emitter.on(event, listener);
|
|
177
180
|
}
|
|
@@ -118,6 +118,7 @@ declare class UploadManager {
|
|
|
118
118
|
private destroyed;
|
|
119
119
|
private readonly config;
|
|
120
120
|
constructor(config?: UploadManagerConfig);
|
|
121
|
+
get is_destroyed(): boolean;
|
|
121
122
|
on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
|
|
122
123
|
submit_batch(options: CreateBatchOptions): string;
|
|
123
124
|
get_jobs_for_group(group_id: string): JobSnapshot[];
|
|
@@ -118,6 +118,7 @@ declare class UploadManager {
|
|
|
118
118
|
private destroyed;
|
|
119
119
|
private readonly config;
|
|
120
120
|
constructor(config?: UploadManagerConfig);
|
|
121
|
+
get is_destroyed(): boolean;
|
|
121
122
|
on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
|
|
122
123
|
submit_batch(options: CreateBatchOptions): string;
|
|
123
124
|
get_jobs_for_group(group_id: string): JobSnapshot[];
|
|
@@ -217,6 +217,9 @@ var UploadManager = class {
|
|
|
217
217
|
this.emitter.on("job:completed", ({ job }) => this.on_job_settled(job));
|
|
218
218
|
this.emitter.on("job:error", ({ job }) => this.on_job_settled(job));
|
|
219
219
|
}
|
|
220
|
+
get is_destroyed() {
|
|
221
|
+
return this.destroyed;
|
|
222
|
+
}
|
|
220
223
|
on(event, listener) {
|
|
221
224
|
return this.emitter.on(event, listener);
|
|
222
225
|
}
|
|
@@ -317,6 +320,108 @@ var FileUploadContext = (0, import_react.createContext)(null);
|
|
|
317
320
|
|
|
318
321
|
// src/background_upload/react/use-file-upload-toasts.ts
|
|
319
322
|
var import_react2 = require("react");
|
|
323
|
+
|
|
324
|
+
// src/locales/en.json
|
|
325
|
+
var en_default = {
|
|
326
|
+
"upload_dialog.title": "Upload Files",
|
|
327
|
+
"upload_dialog.uploading_to": "Uploading to:",
|
|
328
|
+
"upload_dialog.drop_text": "Drag and drop files here, or",
|
|
329
|
+
"upload_dialog.browse": "browse",
|
|
330
|
+
"upload_dialog.files_selected": "{{count}} file(s) selected",
|
|
331
|
+
"upload_dialog.total": "Total:",
|
|
332
|
+
"upload_dialog.cancel": "Cancel",
|
|
333
|
+
"upload_dialog.upload": "Upload",
|
|
334
|
+
"upload_dialog.select_files_error": "Please select files to upload",
|
|
335
|
+
"create_folder_dialog.title": "Create New Folder",
|
|
336
|
+
"create_folder_dialog.creating_in": "Creating folder in:",
|
|
337
|
+
"create_folder_dialog.name_label": "Folder Name",
|
|
338
|
+
"create_folder_dialog.name_placeholder": "Enter folder name",
|
|
339
|
+
"create_folder_dialog.cancel": "Cancel",
|
|
340
|
+
"create_folder_dialog.submit": "Create Folder",
|
|
341
|
+
"create_folder_dialog.name_required_error": "Please enter a folder name",
|
|
342
|
+
"create_folder_dialog.invalid_chars_error": "Folder name contains invalid characters",
|
|
343
|
+
"rename_dialog.title_folder": "Rename Folder",
|
|
344
|
+
"rename_dialog.title_file": "Rename File",
|
|
345
|
+
"rename_dialog.name_label": "New Name",
|
|
346
|
+
"rename_dialog.name_placeholder": "Enter new name",
|
|
347
|
+
"rename_dialog.cancel": "Cancel",
|
|
348
|
+
"rename_dialog.submit": "Rename",
|
|
349
|
+
"rename_dialog.name_required_error": "Please enter a name",
|
|
350
|
+
"rename_dialog.invalid_chars_error": "Name contains invalid characters",
|
|
351
|
+
"delete_confirm_dialog.title_folder": "Delete Folder",
|
|
352
|
+
"delete_confirm_dialog.title_file": "Delete File",
|
|
353
|
+
"delete_confirm_dialog.confirm_message": "Are you sure you want to delete",
|
|
354
|
+
"delete_confirm_dialog.folder_warning": "Warning: This folder and all its contents will be permanently deleted.",
|
|
355
|
+
"delete_confirm_dialog.cancel": "Cancel",
|
|
356
|
+
"delete_confirm_dialog.submit": "Delete",
|
|
357
|
+
"metadata_dialog.title": "File Metadata",
|
|
358
|
+
"metadata_dialog.close": "Close",
|
|
359
|
+
"file_actions.new_folder": "New Folder",
|
|
360
|
+
"file_actions.upload": "Upload",
|
|
361
|
+
"file_actions.download": "Download",
|
|
362
|
+
"file_actions.rename": "Rename",
|
|
363
|
+
"file_actions.delete": "Delete",
|
|
364
|
+
"file_actions.refresh": "Refresh",
|
|
365
|
+
"file_list.empty": "This folder is empty",
|
|
366
|
+
"file_list.header_name": "Name",
|
|
367
|
+
"file_list.header_size": "Size",
|
|
368
|
+
"file_list.header_modified": "Modified",
|
|
369
|
+
"folder_tree.root": "Root",
|
|
370
|
+
"file_preview.select_prompt": "Select a file to preview",
|
|
371
|
+
"file_preview.folder_label": "Folder",
|
|
372
|
+
"file_preview.created_label": "Created:",
|
|
373
|
+
"file_preview.modified_label": "Modified:",
|
|
374
|
+
"file_preview.error_loading": "Error loading preview",
|
|
375
|
+
"file_preview.video_unsupported": "Your browser does not support video playback.",
|
|
376
|
+
"file_preview.audio_unsupported": "Your browser does not support audio playback.",
|
|
377
|
+
"file_preview.no_preview": "No preview available",
|
|
378
|
+
"file_preview.size_label": "Size:",
|
|
379
|
+
"file_preview.type_label": "Type:",
|
|
380
|
+
"file_info_panel.no_item_selected": "No item selected",
|
|
381
|
+
"file_info_panel.no_custom_metadata": "No custom metadata",
|
|
382
|
+
"file_info_panel.name_label": "Name:",
|
|
383
|
+
"file_info_panel.path_label": "Path:",
|
|
384
|
+
"file_info_panel.type_label": "Type:",
|
|
385
|
+
"file_info_panel.size_label": "Size:",
|
|
386
|
+
"file_info_panel.created_label": "Created:",
|
|
387
|
+
"file_info_panel.modified_label": "Modified:",
|
|
388
|
+
"file_info_panel.storage_label": "Storage:",
|
|
389
|
+
"file_info_panel.custom_metadata_title": "Custom Metadata",
|
|
390
|
+
"file_info_panel.type_folder": "Folder",
|
|
391
|
+
"file_info_panel.type_unknown": "Unknown",
|
|
392
|
+
"file_browser.load_directory_error": "Failed to load directory",
|
|
393
|
+
"file_browser.move_item_error": "Failed to move item",
|
|
394
|
+
"file_browser.upload_file_error": "Failed to upload {{name}}",
|
|
395
|
+
"file_browser.download_file_error": "Failed to download file",
|
|
396
|
+
"file_browser.create_folder_error": "Failed to create folder",
|
|
397
|
+
"file_browser.delete_error": "Failed to delete",
|
|
398
|
+
"file_browser.rename_error": "Failed to rename",
|
|
399
|
+
"file_browser.context_menu_view_metadata": "View Metadata",
|
|
400
|
+
"file_browser.context_menu_rename": "Rename",
|
|
401
|
+
"file_browser.context_menu_download": "Download",
|
|
402
|
+
"file_browser.context_menu_delete": "Delete",
|
|
403
|
+
"use_file_upload_toasts.job_completed": "{{count}} {{file_word}} processed for {{label}}",
|
|
404
|
+
"use_file_upload_toasts.upload_failed": "Upload failed for {{label}}: {{error}}",
|
|
405
|
+
"use_file_upload_toasts.action_required": "Action required for {{label}}",
|
|
406
|
+
"use_file_upload_toasts.action_required_description": "Review and confirm data conflicts",
|
|
407
|
+
"use_file_upload_toasts.batch_complete": "Batch complete: {{completed}}/{{total}} succeeded",
|
|
408
|
+
"pattern_preview.title": "Preview",
|
|
409
|
+
"pattern_preview.no_pattern": "(no pattern defined)",
|
|
410
|
+
"pattern_preview.file_label": "File:",
|
|
411
|
+
"pattern_preview.folder_label": "Folder:",
|
|
412
|
+
"pattern_preview.full_path_label": "Full path:",
|
|
413
|
+
"pattern_preview.example_note": "Preview uses example values from your variables",
|
|
414
|
+
"separator_picker.add_label": "Add:",
|
|
415
|
+
"separator_picker.title_hyphen": "Hyphen",
|
|
416
|
+
"separator_picker.title_underscore": "Underscore",
|
|
417
|
+
"separator_picker.title_slash": "Slash (for folder paths)",
|
|
418
|
+
"separator_picker.title_space": "Space",
|
|
419
|
+
"separator_picker.title_period": "Period"
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// src/background_upload/react/use-file-upload-toasts.ts
|
|
423
|
+
var import_i18n = require("hazo_core/i18n");
|
|
424
|
+
var t_pkg = (0, import_i18n.createPackageT)("hazo_files", en_default);
|
|
320
425
|
var toast_promise = null;
|
|
321
426
|
function get_toast() {
|
|
322
427
|
if (!toast_promise) {
|
|
@@ -332,22 +437,26 @@ function useFileUploadToasts(manager) {
|
|
|
332
437
|
if (!t) return;
|
|
333
438
|
const label = job.group_label || job.group_id;
|
|
334
439
|
const n = job.files.length;
|
|
335
|
-
t.success(
|
|
440
|
+
t.success(t_pkg("use_file_upload_toasts.job_completed", {
|
|
441
|
+
count: String(n),
|
|
442
|
+
file_word: n > 1 ? "files" : "file",
|
|
443
|
+
label
|
|
444
|
+
}));
|
|
336
445
|
});
|
|
337
446
|
}));
|
|
338
447
|
unsubs.push(manager.on("job:error", ({ job, error }) => {
|
|
339
448
|
void get_toast().then((t) => {
|
|
340
449
|
if (!t) return;
|
|
341
450
|
const label = job.group_label || job.group_id;
|
|
342
|
-
t.error(
|
|
451
|
+
t.error(t_pkg("use_file_upload_toasts.upload_failed", { label, error: String(error) }));
|
|
343
452
|
});
|
|
344
453
|
}));
|
|
345
454
|
unsubs.push(manager.on("job:confirmation_needed", ({ job }) => {
|
|
346
455
|
void get_toast().then((t) => {
|
|
347
456
|
if (!t) return;
|
|
348
457
|
const label = job.group_label || job.group_id;
|
|
349
|
-
t.info(
|
|
350
|
-
description: "
|
|
458
|
+
t.info(t_pkg("use_file_upload_toasts.action_required", { label }), {
|
|
459
|
+
description: t_pkg("use_file_upload_toasts.action_required_description"),
|
|
351
460
|
duration: 1e4
|
|
352
461
|
});
|
|
353
462
|
});
|
|
@@ -356,7 +465,10 @@ function useFileUploadToasts(manager) {
|
|
|
356
465
|
void get_toast().then((t) => {
|
|
357
466
|
if (!t) return;
|
|
358
467
|
if (batch.failed > 0) {
|
|
359
|
-
t.warning(
|
|
468
|
+
t.warning(t_pkg("use_file_upload_toasts.batch_complete", {
|
|
469
|
+
completed: String(batch.completed),
|
|
470
|
+
total: String(batch.total)
|
|
471
|
+
}));
|
|
360
472
|
}
|
|
361
473
|
});
|
|
362
474
|
}));
|
|
@@ -381,7 +493,12 @@ function HazoFileUploadProvider({
|
|
|
381
493
|
if (!manager_ref.current) {
|
|
382
494
|
manager_ref.current = new UploadManager(config);
|
|
383
495
|
}
|
|
496
|
+
const [, force_render] = (0, import_react3.useReducer)((n) => n + 1, 0);
|
|
384
497
|
(0, import_react3.useEffect)(() => {
|
|
498
|
+
if (manager_ref.current.is_destroyed) {
|
|
499
|
+
manager_ref.current = new UploadManager(config);
|
|
500
|
+
force_render();
|
|
501
|
+
}
|
|
385
502
|
const m = manager_ref.current;
|
|
386
503
|
return () => {
|
|
387
504
|
m.destroy();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/background_upload/react/provider.tsx
|
|
2
|
-
import { useRef, useEffect as useEffect2 } from "react";
|
|
2
|
+
import { useRef, useReducer, useEffect as useEffect2 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/background_upload/core/upload-manager.ts
|
|
5
5
|
import { generateRequestId as generateRequestId2 } from "hazo_core";
|
|
@@ -177,6 +177,9 @@ var UploadManager = class {
|
|
|
177
177
|
this.emitter.on("job:completed", ({ job }) => this.on_job_settled(job));
|
|
178
178
|
this.emitter.on("job:error", ({ job }) => this.on_job_settled(job));
|
|
179
179
|
}
|
|
180
|
+
get is_destroyed() {
|
|
181
|
+
return this.destroyed;
|
|
182
|
+
}
|
|
180
183
|
on(event, listener) {
|
|
181
184
|
return this.emitter.on(event, listener);
|
|
182
185
|
}
|
|
@@ -277,6 +280,108 @@ var FileUploadContext = createContext(null);
|
|
|
277
280
|
|
|
278
281
|
// src/background_upload/react/use-file-upload-toasts.ts
|
|
279
282
|
import { useEffect } from "react";
|
|
283
|
+
|
|
284
|
+
// src/locales/en.json
|
|
285
|
+
var en_default = {
|
|
286
|
+
"upload_dialog.title": "Upload Files",
|
|
287
|
+
"upload_dialog.uploading_to": "Uploading to:",
|
|
288
|
+
"upload_dialog.drop_text": "Drag and drop files here, or",
|
|
289
|
+
"upload_dialog.browse": "browse",
|
|
290
|
+
"upload_dialog.files_selected": "{{count}} file(s) selected",
|
|
291
|
+
"upload_dialog.total": "Total:",
|
|
292
|
+
"upload_dialog.cancel": "Cancel",
|
|
293
|
+
"upload_dialog.upload": "Upload",
|
|
294
|
+
"upload_dialog.select_files_error": "Please select files to upload",
|
|
295
|
+
"create_folder_dialog.title": "Create New Folder",
|
|
296
|
+
"create_folder_dialog.creating_in": "Creating folder in:",
|
|
297
|
+
"create_folder_dialog.name_label": "Folder Name",
|
|
298
|
+
"create_folder_dialog.name_placeholder": "Enter folder name",
|
|
299
|
+
"create_folder_dialog.cancel": "Cancel",
|
|
300
|
+
"create_folder_dialog.submit": "Create Folder",
|
|
301
|
+
"create_folder_dialog.name_required_error": "Please enter a folder name",
|
|
302
|
+
"create_folder_dialog.invalid_chars_error": "Folder name contains invalid characters",
|
|
303
|
+
"rename_dialog.title_folder": "Rename Folder",
|
|
304
|
+
"rename_dialog.title_file": "Rename File",
|
|
305
|
+
"rename_dialog.name_label": "New Name",
|
|
306
|
+
"rename_dialog.name_placeholder": "Enter new name",
|
|
307
|
+
"rename_dialog.cancel": "Cancel",
|
|
308
|
+
"rename_dialog.submit": "Rename",
|
|
309
|
+
"rename_dialog.name_required_error": "Please enter a name",
|
|
310
|
+
"rename_dialog.invalid_chars_error": "Name contains invalid characters",
|
|
311
|
+
"delete_confirm_dialog.title_folder": "Delete Folder",
|
|
312
|
+
"delete_confirm_dialog.title_file": "Delete File",
|
|
313
|
+
"delete_confirm_dialog.confirm_message": "Are you sure you want to delete",
|
|
314
|
+
"delete_confirm_dialog.folder_warning": "Warning: This folder and all its contents will be permanently deleted.",
|
|
315
|
+
"delete_confirm_dialog.cancel": "Cancel",
|
|
316
|
+
"delete_confirm_dialog.submit": "Delete",
|
|
317
|
+
"metadata_dialog.title": "File Metadata",
|
|
318
|
+
"metadata_dialog.close": "Close",
|
|
319
|
+
"file_actions.new_folder": "New Folder",
|
|
320
|
+
"file_actions.upload": "Upload",
|
|
321
|
+
"file_actions.download": "Download",
|
|
322
|
+
"file_actions.rename": "Rename",
|
|
323
|
+
"file_actions.delete": "Delete",
|
|
324
|
+
"file_actions.refresh": "Refresh",
|
|
325
|
+
"file_list.empty": "This folder is empty",
|
|
326
|
+
"file_list.header_name": "Name",
|
|
327
|
+
"file_list.header_size": "Size",
|
|
328
|
+
"file_list.header_modified": "Modified",
|
|
329
|
+
"folder_tree.root": "Root",
|
|
330
|
+
"file_preview.select_prompt": "Select a file to preview",
|
|
331
|
+
"file_preview.folder_label": "Folder",
|
|
332
|
+
"file_preview.created_label": "Created:",
|
|
333
|
+
"file_preview.modified_label": "Modified:",
|
|
334
|
+
"file_preview.error_loading": "Error loading preview",
|
|
335
|
+
"file_preview.video_unsupported": "Your browser does not support video playback.",
|
|
336
|
+
"file_preview.audio_unsupported": "Your browser does not support audio playback.",
|
|
337
|
+
"file_preview.no_preview": "No preview available",
|
|
338
|
+
"file_preview.size_label": "Size:",
|
|
339
|
+
"file_preview.type_label": "Type:",
|
|
340
|
+
"file_info_panel.no_item_selected": "No item selected",
|
|
341
|
+
"file_info_panel.no_custom_metadata": "No custom metadata",
|
|
342
|
+
"file_info_panel.name_label": "Name:",
|
|
343
|
+
"file_info_panel.path_label": "Path:",
|
|
344
|
+
"file_info_panel.type_label": "Type:",
|
|
345
|
+
"file_info_panel.size_label": "Size:",
|
|
346
|
+
"file_info_panel.created_label": "Created:",
|
|
347
|
+
"file_info_panel.modified_label": "Modified:",
|
|
348
|
+
"file_info_panel.storage_label": "Storage:",
|
|
349
|
+
"file_info_panel.custom_metadata_title": "Custom Metadata",
|
|
350
|
+
"file_info_panel.type_folder": "Folder",
|
|
351
|
+
"file_info_panel.type_unknown": "Unknown",
|
|
352
|
+
"file_browser.load_directory_error": "Failed to load directory",
|
|
353
|
+
"file_browser.move_item_error": "Failed to move item",
|
|
354
|
+
"file_browser.upload_file_error": "Failed to upload {{name}}",
|
|
355
|
+
"file_browser.download_file_error": "Failed to download file",
|
|
356
|
+
"file_browser.create_folder_error": "Failed to create folder",
|
|
357
|
+
"file_browser.delete_error": "Failed to delete",
|
|
358
|
+
"file_browser.rename_error": "Failed to rename",
|
|
359
|
+
"file_browser.context_menu_view_metadata": "View Metadata",
|
|
360
|
+
"file_browser.context_menu_rename": "Rename",
|
|
361
|
+
"file_browser.context_menu_download": "Download",
|
|
362
|
+
"file_browser.context_menu_delete": "Delete",
|
|
363
|
+
"use_file_upload_toasts.job_completed": "{{count}} {{file_word}} processed for {{label}}",
|
|
364
|
+
"use_file_upload_toasts.upload_failed": "Upload failed for {{label}}: {{error}}",
|
|
365
|
+
"use_file_upload_toasts.action_required": "Action required for {{label}}",
|
|
366
|
+
"use_file_upload_toasts.action_required_description": "Review and confirm data conflicts",
|
|
367
|
+
"use_file_upload_toasts.batch_complete": "Batch complete: {{completed}}/{{total}} succeeded",
|
|
368
|
+
"pattern_preview.title": "Preview",
|
|
369
|
+
"pattern_preview.no_pattern": "(no pattern defined)",
|
|
370
|
+
"pattern_preview.file_label": "File:",
|
|
371
|
+
"pattern_preview.folder_label": "Folder:",
|
|
372
|
+
"pattern_preview.full_path_label": "Full path:",
|
|
373
|
+
"pattern_preview.example_note": "Preview uses example values from your variables",
|
|
374
|
+
"separator_picker.add_label": "Add:",
|
|
375
|
+
"separator_picker.title_hyphen": "Hyphen",
|
|
376
|
+
"separator_picker.title_underscore": "Underscore",
|
|
377
|
+
"separator_picker.title_slash": "Slash (for folder paths)",
|
|
378
|
+
"separator_picker.title_space": "Space",
|
|
379
|
+
"separator_picker.title_period": "Period"
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// src/background_upload/react/use-file-upload-toasts.ts
|
|
383
|
+
import { createPackageT } from "hazo_core/i18n";
|
|
384
|
+
var t_pkg = createPackageT("hazo_files", en_default);
|
|
280
385
|
var toast_promise = null;
|
|
281
386
|
function get_toast() {
|
|
282
387
|
if (!toast_promise) {
|
|
@@ -292,22 +397,26 @@ function useFileUploadToasts(manager) {
|
|
|
292
397
|
if (!t) return;
|
|
293
398
|
const label = job.group_label || job.group_id;
|
|
294
399
|
const n = job.files.length;
|
|
295
|
-
t.success(
|
|
400
|
+
t.success(t_pkg("use_file_upload_toasts.job_completed", {
|
|
401
|
+
count: String(n),
|
|
402
|
+
file_word: n > 1 ? "files" : "file",
|
|
403
|
+
label
|
|
404
|
+
}));
|
|
296
405
|
});
|
|
297
406
|
}));
|
|
298
407
|
unsubs.push(manager.on("job:error", ({ job, error }) => {
|
|
299
408
|
void get_toast().then((t) => {
|
|
300
409
|
if (!t) return;
|
|
301
410
|
const label = job.group_label || job.group_id;
|
|
302
|
-
t.error(
|
|
411
|
+
t.error(t_pkg("use_file_upload_toasts.upload_failed", { label, error: String(error) }));
|
|
303
412
|
});
|
|
304
413
|
}));
|
|
305
414
|
unsubs.push(manager.on("job:confirmation_needed", ({ job }) => {
|
|
306
415
|
void get_toast().then((t) => {
|
|
307
416
|
if (!t) return;
|
|
308
417
|
const label = job.group_label || job.group_id;
|
|
309
|
-
t.info(
|
|
310
|
-
description: "
|
|
418
|
+
t.info(t_pkg("use_file_upload_toasts.action_required", { label }), {
|
|
419
|
+
description: t_pkg("use_file_upload_toasts.action_required_description"),
|
|
311
420
|
duration: 1e4
|
|
312
421
|
});
|
|
313
422
|
});
|
|
@@ -316,7 +425,10 @@ function useFileUploadToasts(manager) {
|
|
|
316
425
|
void get_toast().then((t) => {
|
|
317
426
|
if (!t) return;
|
|
318
427
|
if (batch.failed > 0) {
|
|
319
|
-
t.warning(
|
|
428
|
+
t.warning(t_pkg("use_file_upload_toasts.batch_complete", {
|
|
429
|
+
completed: String(batch.completed),
|
|
430
|
+
total: String(batch.total)
|
|
431
|
+
}));
|
|
320
432
|
}
|
|
321
433
|
});
|
|
322
434
|
}));
|
|
@@ -341,7 +453,12 @@ function HazoFileUploadProvider({
|
|
|
341
453
|
if (!manager_ref.current) {
|
|
342
454
|
manager_ref.current = new UploadManager(config);
|
|
343
455
|
}
|
|
456
|
+
const [, force_render] = useReducer((n) => n + 1, 0);
|
|
344
457
|
useEffect2(() => {
|
|
458
|
+
if (manager_ref.current.is_destroyed) {
|
|
459
|
+
manager_ref.current = new UploadManager(config);
|
|
460
|
+
force_render();
|
|
461
|
+
}
|
|
345
462
|
const m = manager_ref.current;
|
|
346
463
|
return () => {
|
|
347
464
|
m.destroy();
|