nuxt-media-library 0.0.65 → 0.0.67
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/dist/module.json +1 -1
- package/dist/runtime/components/MLMedia/Field.d.vue.ts +1 -1
- package/dist/runtime/components/MLMedia/Field.vue.d.ts +1 -1
- package/dist/runtime/components/MLMedia/Gallery.d.vue.ts +1 -1
- package/dist/runtime/components/MLMedia/Gallery.vue.d.ts +1 -1
- package/dist/runtime/components/MLMedia/GallerySection.d.vue.ts +1 -1
- package/dist/runtime/components/MLMedia/GallerySection.vue +21 -6
- package/dist/runtime/components/MLMedia/GallerySection.vue.d.ts +1 -1
- package/dist/runtime/components/MLMedia/MediaTile.d.vue.ts +6 -0
- package/dist/runtime/components/MLMedia/MediaTile.vue +5 -2
- package/dist/runtime/components/MLMedia/MediaTile.vue.d.ts +6 -0
- package/dist/runtime/components/MLMedia/PickerRow.d.vue.ts +1 -1
- package/dist/runtime/components/MLMedia/PickerRow.vue.d.ts +1 -1
- package/dist/runtime/components/MLMedia/ProgressVeil.d.vue.ts +2 -1
- package/dist/runtime/components/MLMedia/ProgressVeil.vue +10 -7
- package/dist/runtime/components/MLMedia/ProgressVeil.vue.d.ts +2 -1
- package/dist/runtime/components/MLProcessing/StepLayout.d.vue.ts +1 -1
- package/dist/runtime/components/MLProcessing/StepLayout.vue.d.ts +1 -1
- package/dist/runtime/components/MLProcessing/StepperItem.d.vue.ts +2 -2
- package/dist/runtime/components/MLProcessing/StepperItem.vue.d.ts +2 -2
- package/dist/runtime/composables/useMLAssetStall.d.ts +23 -0
- package/dist/runtime/composables/useMLAssetStall.js +59 -0
- package/dist/runtime/composables/useMLMediaGallery.d.ts +2 -0
- package/dist/runtime/composables/useMLMediaGallery.js +2 -0
- package/dist/runtime/composables/useMLUploadQueue.js +1 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -86,10 +86,10 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
86
86
|
pickFrom: readonly string[] | null;
|
|
87
87
|
required: boolean;
|
|
88
88
|
removeLabel: string;
|
|
89
|
-
onPick: () => void;
|
|
90
89
|
hint: string;
|
|
91
90
|
missingAlt: boolean;
|
|
92
91
|
picker: boolean;
|
|
92
|
+
onPick: () => void;
|
|
93
93
|
editor: boolean;
|
|
94
94
|
onOpen: (assetId: string) => void;
|
|
95
95
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -86,10 +86,10 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
86
86
|
pickFrom: readonly string[] | null;
|
|
87
87
|
required: boolean;
|
|
88
88
|
removeLabel: string;
|
|
89
|
-
onPick: () => void;
|
|
90
89
|
hint: string;
|
|
91
90
|
missingAlt: boolean;
|
|
92
91
|
picker: boolean;
|
|
92
|
+
onPick: () => void;
|
|
93
93
|
editor: boolean;
|
|
94
94
|
onOpen: (assetId: string) => void;
|
|
95
95
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -108,9 +108,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
108
108
|
max: number | null;
|
|
109
109
|
maxSize: number | null;
|
|
110
110
|
pickFrom: readonly string[] | null;
|
|
111
|
-
onPick: () => void;
|
|
112
111
|
hint: string;
|
|
113
112
|
picker: boolean;
|
|
113
|
+
onPick: () => void;
|
|
114
114
|
editor: boolean;
|
|
115
115
|
onOpen: (assetId: string) => void;
|
|
116
116
|
featured: boolean;
|
|
@@ -108,9 +108,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
108
108
|
max: number | null;
|
|
109
109
|
maxSize: number | null;
|
|
110
110
|
pickFrom: readonly string[] | null;
|
|
111
|
-
onPick: () => void;
|
|
112
111
|
hint: string;
|
|
113
112
|
picker: boolean;
|
|
113
|
+
onPick: () => void;
|
|
114
114
|
editor: boolean;
|
|
115
115
|
onOpen: (assetId: string) => void;
|
|
116
116
|
featured: boolean;
|
|
@@ -104,9 +104,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
104
104
|
pickFrom: readonly string[] | null;
|
|
105
105
|
removeLabel: string;
|
|
106
106
|
onAdd: (assetId: string, tag: string | undefined) => void;
|
|
107
|
-
onPick: () => void;
|
|
108
107
|
hint: string;
|
|
109
108
|
picker: boolean;
|
|
109
|
+
onPick: () => void;
|
|
110
110
|
editor: boolean;
|
|
111
111
|
onOpen: (assetId: string) => void;
|
|
112
112
|
featured: boolean;
|
|
@@ -4,6 +4,7 @@ import { useMLMediaGallery } from "../../composables/useMLMediaGallery";
|
|
|
4
4
|
import { useMLFilePicker } from "../../composables/useMLFilePicker";
|
|
5
5
|
import { useMLMediaEditor } from "../../composables/useMLMediaEditor";
|
|
6
6
|
import { useMLMediaMeta } from "../../composables/useMLMediaMeta";
|
|
7
|
+
import { useMLAssetStall } from "../../composables/useMLAssetStall";
|
|
7
8
|
import { assetName } from "../../utils/assetFormat";
|
|
8
9
|
import { assetThumbnailUrl } from "../../utils/assetThumbnail";
|
|
9
10
|
import { acceptForKinds, partitionFiles } from "../../utils/fileAccept";
|
|
@@ -90,12 +91,24 @@ function removeSelected() {
|
|
|
90
91
|
gallery.remove([...selected.value]);
|
|
91
92
|
selected.value = /* @__PURE__ */ new Set();
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
+
const uploadRunning = (item) => {
|
|
94
95
|
const p = item.upload?.phase;
|
|
95
|
-
|
|
96
|
+
return p === "uploading" || p === "processing" || p === "failed";
|
|
97
|
+
};
|
|
98
|
+
const stalls = useMLAssetStall(
|
|
99
|
+
() => items.value.filter((i) => i.id && !uploadRunning(i)).map((i) => i.id),
|
|
100
|
+
(id) => gallery.asset(id),
|
|
101
|
+
(ids) => gallery.refresh(ids)
|
|
102
|
+
);
|
|
103
|
+
const STUCK_HINT = "Remove it, or upload the file again.";
|
|
104
|
+
function tileState(item) {
|
|
105
|
+
if (uploadRunning(item)) return { phase: item.upload.phase, detail: !item.id ? item.upload.file.name : void 0 };
|
|
96
106
|
const s = item.asset?.status?.toLowerCase();
|
|
97
|
-
if (s === "
|
|
98
|
-
|
|
107
|
+
if (s === "failed") return { phase: "failed", label: "Processing failed", detail: STUCK_HINT };
|
|
108
|
+
const stall = stalls.stall(item.id);
|
|
109
|
+
if (stall === "not_started") return { phase: "stalled", label: "Processing didn't start", detail: STUCK_HINT };
|
|
110
|
+
if (stall === "stalled") return { phase: "stalled", label: "Processing stalled", detail: STUCK_HINT };
|
|
111
|
+
if (s === "processing" || s === "uploaded" || s === "pending") return { phase: "processing" };
|
|
99
112
|
return null;
|
|
100
113
|
}
|
|
101
114
|
function tileSrc(item) {
|
|
@@ -375,9 +388,11 @@ async function onTileKey(e, index) {
|
|
|
375
388
|
:selectable="!!item.id && !disabled"
|
|
376
389
|
:selected="!!item.id && selected.has(item.id)"
|
|
377
390
|
:selecting="selected.size > 0"
|
|
378
|
-
:phase="
|
|
391
|
+
:phase="tileState(item)?.phase ?? null"
|
|
392
|
+
:phase-label="tileState(item)?.label"
|
|
393
|
+
:controls="uploadRunning(item)"
|
|
379
394
|
:progress="item.upload?.progress ?? null"
|
|
380
|
-
:phase-detail="item
|
|
395
|
+
:phase-detail="tileState(item)?.detail"
|
|
381
396
|
:on-open="openFor(item)"
|
|
382
397
|
@update:selected="(v) => item.id && setSelected(item.id, v)"
|
|
383
398
|
@cancel="onCancel(item)"
|
|
@@ -104,9 +104,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
104
104
|
pickFrom: readonly string[] | null;
|
|
105
105
|
removeLabel: string;
|
|
106
106
|
onAdd: (assetId: string, tag: string | undefined) => void;
|
|
107
|
-
onPick: () => void;
|
|
108
107
|
hint: string;
|
|
109
108
|
picker: boolean;
|
|
109
|
+
onPick: () => void;
|
|
110
110
|
editor: boolean;
|
|
111
111
|
onOpen: (assetId: string) => void;
|
|
112
112
|
featured: boolean;
|
|
@@ -17,7 +17,11 @@ type __VLS_Props = {
|
|
|
17
17
|
/** Overlay for uploads and processing. Omit when the file is ready. */
|
|
18
18
|
phase?: ProgressVeilPhase | null;
|
|
19
19
|
progress?: number | null;
|
|
20
|
+
/** Replaces the phase's label, e.g. "Processing didn't start". */
|
|
21
|
+
phaseLabel?: string;
|
|
20
22
|
phaseDetail?: string;
|
|
23
|
+
/** Show the veil's Cancel / Retry. Off for files with no upload running here. */
|
|
24
|
+
controls?: boolean;
|
|
21
25
|
disabled?: boolean;
|
|
22
26
|
/** Fixed shape for grid cells. */
|
|
23
27
|
aspect?: 'square' | 'landscape' | 'portrait' | 'video';
|
|
@@ -46,10 +50,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
46
50
|
disabled: boolean;
|
|
47
51
|
phase: ProgressVeilPhase | null;
|
|
48
52
|
selected: boolean;
|
|
53
|
+
controls: boolean;
|
|
49
54
|
selectable: boolean;
|
|
50
55
|
missingAlt: boolean;
|
|
51
56
|
onOpen: () => void;
|
|
52
57
|
selecting: boolean;
|
|
58
|
+
phaseLabel: string;
|
|
53
59
|
phaseDetail: string;
|
|
54
60
|
aspect: "square" | "landscape" | "portrait" | "video";
|
|
55
61
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -13,7 +13,9 @@ const props = defineProps({
|
|
|
13
13
|
selecting: { type: Boolean, required: false, default: false },
|
|
14
14
|
phase: { type: [String, null], required: false, default: null },
|
|
15
15
|
progress: { type: [Number, null], required: false, default: null },
|
|
16
|
+
phaseLabel: { type: String, required: false, default: void 0 },
|
|
16
17
|
phaseDetail: { type: String, required: false, default: void 0 },
|
|
18
|
+
controls: { type: Boolean, required: false, default: true },
|
|
17
19
|
disabled: { type: Boolean, required: false, default: false },
|
|
18
20
|
aspect: { type: String, required: false, default: "square" },
|
|
19
21
|
onOpen: { type: Function, required: false, default: void 0 }
|
|
@@ -85,9 +87,10 @@ function onKey(e) {
|
|
|
85
87
|
v-if="phase"
|
|
86
88
|
:phase="phase"
|
|
87
89
|
:progress="progress"
|
|
90
|
+
:label="phaseLabel"
|
|
88
91
|
:detail="phaseDetail"
|
|
89
|
-
:on-cancel="phase !== 'failed' ? () => emit('cancel') : void 0"
|
|
90
|
-
:on-retry="phase === 'failed' ? () => emit('retry') : void 0"
|
|
92
|
+
:on-cancel="controls && phase !== 'failed' ? () => emit('cancel') : void 0"
|
|
93
|
+
:on-retry="controls && phase === 'failed' ? () => emit('retry') : void 0"
|
|
91
94
|
/>
|
|
92
95
|
</MLMediaThumbnail>
|
|
93
96
|
|
|
@@ -17,7 +17,11 @@ type __VLS_Props = {
|
|
|
17
17
|
/** Overlay for uploads and processing. Omit when the file is ready. */
|
|
18
18
|
phase?: ProgressVeilPhase | null;
|
|
19
19
|
progress?: number | null;
|
|
20
|
+
/** Replaces the phase's label, e.g. "Processing didn't start". */
|
|
21
|
+
phaseLabel?: string;
|
|
20
22
|
phaseDetail?: string;
|
|
23
|
+
/** Show the veil's Cancel / Retry. Off for files with no upload running here. */
|
|
24
|
+
controls?: boolean;
|
|
21
25
|
disabled?: boolean;
|
|
22
26
|
/** Fixed shape for grid cells. */
|
|
23
27
|
aspect?: 'square' | 'landscape' | 'portrait' | 'video';
|
|
@@ -46,10 +50,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
46
50
|
disabled: boolean;
|
|
47
51
|
phase: ProgressVeilPhase | null;
|
|
48
52
|
selected: boolean;
|
|
53
|
+
controls: boolean;
|
|
49
54
|
selectable: boolean;
|
|
50
55
|
missingAlt: boolean;
|
|
51
56
|
onOpen: () => void;
|
|
52
57
|
selecting: boolean;
|
|
58
|
+
phaseLabel: string;
|
|
53
59
|
phaseDetail: string;
|
|
54
60
|
aspect: "square" | "landscape" | "portrait" | "video";
|
|
55
61
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -32,8 +32,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
32
32
|
name: string;
|
|
33
33
|
disabled: boolean;
|
|
34
34
|
selected: boolean;
|
|
35
|
-
date: string;
|
|
36
35
|
selectable: boolean;
|
|
36
|
+
date: string;
|
|
37
37
|
disabledReason: string;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
39
39
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -32,8 +32,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
32
32
|
name: string;
|
|
33
33
|
disabled: boolean;
|
|
34
34
|
selected: boolean;
|
|
35
|
-
date: string;
|
|
36
35
|
selectable: boolean;
|
|
36
|
+
date: string;
|
|
37
37
|
disabledReason: string;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
39
39
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** 'stalled': processing didn't start or stopped moving (no spinner, no bar). */
|
|
2
|
+
export type ProgressVeilPhase = 'uploading' | 'processing' | 'failed' | 'stalled';
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
phase: ProgressVeilPhase;
|
|
4
5
|
/** 0–100. Null or omitted shows an indeterminate bar (e.g. a step with no progress events). */
|
|
@@ -12,13 +12,14 @@ const props = defineProps({
|
|
|
12
12
|
const PHASES = {
|
|
13
13
|
uploading: { label: "Uploading", color: "primary", icon: "i-lucide-upload" },
|
|
14
14
|
processing: { label: "Processing", color: "warning", icon: "i-lucide-loader-circle" },
|
|
15
|
-
failed: { label: "Failed", color: "error", icon: "i-lucide-circle-alert" }
|
|
15
|
+
failed: { label: "Failed", color: "error", icon: "i-lucide-circle-alert" },
|
|
16
|
+
stalled: { label: "Stuck", color: "warning", icon: "i-lucide-clock-alert" }
|
|
16
17
|
};
|
|
17
18
|
const meta = computed(() => PHASES[props.phase]);
|
|
18
19
|
const value = computed(() => props.progress == null ? null : Math.round(Math.min(100, Math.max(0, props.progress))));
|
|
19
20
|
const heading = computed(() => {
|
|
20
21
|
const text = props.label ?? meta.value.label;
|
|
21
|
-
return value.value != null && props.phase !== "failed" ? `${text} ${value.value}%` : text;
|
|
22
|
+
return value.value != null && props.phase !== "failed" && props.phase !== "stalled" ? `${text} ${value.value}%` : text;
|
|
22
23
|
});
|
|
23
24
|
</script>
|
|
24
25
|
|
|
@@ -35,7 +36,7 @@ const heading = computed(() => {
|
|
|
35
36
|
class="w-full self-end"
|
|
36
37
|
>
|
|
37
38
|
<UProgress
|
|
38
|
-
v-if="phase !== 'failed'"
|
|
39
|
+
v-if="phase !== 'failed' && phase !== 'stalled'"
|
|
39
40
|
:model-value="value"
|
|
40
41
|
:color="meta.color"
|
|
41
42
|
size="2xs"
|
|
@@ -43,7 +44,8 @@ const heading = computed(() => {
|
|
|
43
44
|
<UIcon
|
|
44
45
|
v-else
|
|
45
46
|
:name="meta.icon"
|
|
46
|
-
class="mx-auto block size-4
|
|
47
|
+
class="mx-auto block size-4"
|
|
48
|
+
:class="phase === 'stalled' ? 'text-warning' : 'text-error'"
|
|
47
49
|
/>
|
|
48
50
|
</div>
|
|
49
51
|
|
|
@@ -56,7 +58,8 @@ const heading = computed(() => {
|
|
|
56
58
|
class="size-4"
|
|
57
59
|
:class="{
|
|
58
60
|
'animate-spin motion-reduce:animate-none': phase === 'processing',
|
|
59
|
-
'text-error': phase === 'failed'
|
|
61
|
+
'text-error': phase === 'failed',
|
|
62
|
+
'text-warning': phase === 'stalled'
|
|
60
63
|
}"
|
|
61
64
|
/>
|
|
62
65
|
<span class="text-xs font-semibold tabular-nums">{{ heading }}</span>
|
|
@@ -65,7 +68,7 @@ const heading = computed(() => {
|
|
|
65
68
|
class="w-full truncate text-xs text-muted"
|
|
66
69
|
>{{ detail }}</span>
|
|
67
70
|
<UProgress
|
|
68
|
-
v-if="phase !== 'failed'"
|
|
71
|
+
v-if="phase !== 'failed' && phase !== 'stalled'"
|
|
69
72
|
:model-value="value"
|
|
70
73
|
:color="meta.color"
|
|
71
74
|
size="xs"
|
|
@@ -85,7 +88,7 @@ const heading = computed(() => {
|
|
|
85
88
|
@click.stop="onRetry"
|
|
86
89
|
/>
|
|
87
90
|
<UButton
|
|
88
|
-
v-if="onCancel && phase !== 'failed'"
|
|
91
|
+
v-if="onCancel && phase !== 'failed' && phase !== 'stalled'"
|
|
89
92
|
size="xs"
|
|
90
93
|
variant="ghost"
|
|
91
94
|
color="neutral"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** 'stalled': processing didn't start or stopped moving (no spinner, no bar). */
|
|
2
|
+
export type ProgressVeilPhase = 'uploading' | 'processing' | 'failed' | 'stalled';
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
phase: ProgressVeilPhase;
|
|
4
5
|
/** 0–100. Null or omitted shows an indeterminate bar (e.g. a step with no progress events). */
|
|
@@ -16,8 +16,8 @@ type __VLS_Slots = {} & {
|
|
|
16
16
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
17
17
|
description: string;
|
|
18
18
|
icon: string;
|
|
19
|
-
titleClass: string;
|
|
20
19
|
iconClass: string;
|
|
20
|
+
titleClass: string;
|
|
21
21
|
spinning: boolean;
|
|
22
22
|
showBody: boolean;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -16,8 +16,8 @@ type __VLS_Slots = {} & {
|
|
|
16
16
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
17
17
|
description: string;
|
|
18
18
|
icon: string;
|
|
19
|
-
titleClass: string;
|
|
20
19
|
iconClass: string;
|
|
20
|
+
titleClass: string;
|
|
21
21
|
spinning: boolean;
|
|
22
22
|
showBody: boolean;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -5,12 +5,12 @@ type __VLS_Props = {
|
|
|
5
5
|
};
|
|
6
6
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
7
|
retry: () => any;
|
|
8
|
-
"update:options": (value: Record<string, any>) => any;
|
|
9
8
|
run: () => any;
|
|
9
|
+
"update:options": (value: Record<string, any>) => any;
|
|
10
10
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
11
|
onRetry?: (() => any) | undefined;
|
|
12
|
-
"onUpdate:options"?: ((value: Record<string, any>) => any) | undefined;
|
|
13
12
|
onRun?: (() => any) | undefined;
|
|
13
|
+
"onUpdate:options"?: ((value: Record<string, any>) => any) | undefined;
|
|
14
14
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
15
|
declare const _default: typeof __VLS_export;
|
|
16
16
|
export default _default;
|
|
@@ -5,12 +5,12 @@ type __VLS_Props = {
|
|
|
5
5
|
};
|
|
6
6
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
7
|
retry: () => any;
|
|
8
|
-
"update:options": (value: Record<string, any>) => any;
|
|
9
8
|
run: () => any;
|
|
9
|
+
"update:options": (value: Record<string, any>) => any;
|
|
10
10
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
11
|
onRetry?: (() => any) | undefined;
|
|
12
|
-
"onUpdate:options"?: ((value: Record<string, any>) => any) | undefined;
|
|
13
12
|
onRun?: (() => any) | undefined;
|
|
13
|
+
"onUpdate:options"?: ((value: Record<string, any>) => any) | undefined;
|
|
14
14
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
15
|
declare const _default: typeof __VLS_export;
|
|
16
16
|
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { AssetDetail, DeliveryAsset } from '../types/asset.js';
|
|
3
|
+
/** 'not_started': still uploaded / pending after a re-check. 'stalled': processing with no change for a long time. */
|
|
4
|
+
export type AssetStall = 'not_started' | 'stalled';
|
|
5
|
+
export interface UseMLAssetStallOptions {
|
|
6
|
+
/** Re-check interval, ms. */
|
|
7
|
+
pollMs?: number;
|
|
8
|
+
/** Processing with no change for this long is stalled, ms. */
|
|
9
|
+
stallMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Watches files that came from the record still waiting for or in
|
|
13
|
+
* processing (not ones uploading here: their upload follows processing).
|
|
14
|
+
* The resolve answer has no timestamps, so this re-checks them every
|
|
15
|
+
* `pollMs` and judges by what it sees: still uploaded / pending after one
|
|
16
|
+
* re-check means processing didn't start; processing with nothing changed
|
|
17
|
+
* for `stallMs` means it stalled. Stuck files keep being re-checked, so
|
|
18
|
+
* they recover when the library catches up.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useMLAssetStall(ids: MaybeRefOrGetter<readonly string[]>, asset: (id: string) => AssetDetail | DeliveryAsset | null, refresh: (ids: string[]) => Promise<void>, options?: UseMLAssetStallOptions): {
|
|
21
|
+
/** Why this file looks stuck, or null. */
|
|
22
|
+
stall: (id: string | null | undefined) => AssetStall | null;
|
|
23
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getCurrentScope, onScopeDispose, ref, toValue, watch } from "vue";
|
|
2
|
+
const WAITING = /* @__PURE__ */ new Set(["pending", "uploaded"]);
|
|
3
|
+
const BUSY = /* @__PURE__ */ new Set([...WAITING, "processing"]);
|
|
4
|
+
function signature(asset) {
|
|
5
|
+
return [asset.status, ...(asset.renditions ?? []).map((r) => `${r.id}:${r.status}`)].join("|").toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
export function useMLAssetStall(ids, asset, refresh, options = {}) {
|
|
8
|
+
const pollMs = options.pollMs ?? 2e4;
|
|
9
|
+
const stallMs = options.stallMs ?? 15 * 6e4;
|
|
10
|
+
const seen = /* @__PURE__ */ new Map();
|
|
11
|
+
const stalls = ref({});
|
|
12
|
+
let timer;
|
|
13
|
+
const watched = () => toValue(ids).filter((id) => {
|
|
14
|
+
const a = asset(id);
|
|
15
|
+
return !!a && BUSY.has(a.status?.toLowerCase());
|
|
16
|
+
});
|
|
17
|
+
function evaluate(rechecked) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const next = {};
|
|
20
|
+
const live = new Set(watched());
|
|
21
|
+
for (const id of [...seen.keys()]) if (!live.has(id)) seen.delete(id);
|
|
22
|
+
for (const id of live) {
|
|
23
|
+
const a = asset(id);
|
|
24
|
+
const sig = signature(a);
|
|
25
|
+
const prev = seen.get(id);
|
|
26
|
+
const entry = prev && prev.sig === sig ? { ...prev, checks: prev.checks + (rechecked ? 1 : 0) } : { sig, since: now, checks: 0 };
|
|
27
|
+
seen.set(id, entry);
|
|
28
|
+
if (WAITING.has(a.status.toLowerCase())) {
|
|
29
|
+
if (entry.checks >= 1) next[id] = "not_started";
|
|
30
|
+
} else if (now - entry.since >= stallMs) {
|
|
31
|
+
next[id] = "stalled";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (JSON.stringify(next) !== JSON.stringify(stalls.value)) stalls.value = next;
|
|
35
|
+
}
|
|
36
|
+
async function tick() {
|
|
37
|
+
const list = watched();
|
|
38
|
+
if (!list.length) return stop();
|
|
39
|
+
try {
|
|
40
|
+
await refresh(list);
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
evaluate(true);
|
|
44
|
+
}
|
|
45
|
+
function stop() {
|
|
46
|
+
clearInterval(timer);
|
|
47
|
+
timer = void 0;
|
|
48
|
+
}
|
|
49
|
+
watch(() => watched().map((id) => `${id}:${signature(asset(id))}`).join(","), () => {
|
|
50
|
+
evaluate(false);
|
|
51
|
+
if (watched().length && !timer && import.meta.client !== false) timer = setInterval(() => void tick(), pollMs);
|
|
52
|
+
if (!watched().length) stop();
|
|
53
|
+
}, { immediate: true });
|
|
54
|
+
if (getCurrentScope()) onScopeDispose(stop);
|
|
55
|
+
return {
|
|
56
|
+
/** Why this file looks stuck, or null. */
|
|
57
|
+
stall: (id) => id ? stalls.value[id] ?? null : null
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -43,6 +43,8 @@ export declare function useMLMediaGallery(model: Ref<string[]>, options?: UseMLM
|
|
|
43
43
|
items: import("vue").ComputedRef<GalleryItem[]>;
|
|
44
44
|
/** The loaded asset for an ID in the list, if any. */
|
|
45
45
|
asset: (id: string) => AssetDetail | null;
|
|
46
|
+
/** Reload some files' details from the library, e.g. to re-check their processing. */
|
|
47
|
+
refresh: (only: string[]) => Promise<void>;
|
|
46
48
|
message: Ref<string | null, string | null>;
|
|
47
49
|
remaining: import("vue").ComputedRef<number>;
|
|
48
50
|
full: import("vue").ComputedRef<boolean>;
|
|
@@ -118,6 +118,8 @@ export function useMLMediaGallery(model, options = {}) {
|
|
|
118
118
|
items,
|
|
119
119
|
/** The loaded asset for an ID in the list, if any. */
|
|
120
120
|
asset: (id) => library.get(id),
|
|
121
|
+
/** Reload some files' details from the library, e.g. to re-check their processing. */
|
|
122
|
+
refresh: (only) => library.refresh(only),
|
|
121
123
|
message,
|
|
122
124
|
remaining,
|
|
123
125
|
full,
|
|
@@ -112,7 +112,7 @@ function createQueue() {
|
|
|
112
112
|
upload.failedTaskId = null;
|
|
113
113
|
upload.processingSince ??= Date.now();
|
|
114
114
|
persist();
|
|
115
|
-
if (processing) {
|
|
115
|
+
if (processing && !upload.backend) {
|
|
116
116
|
const s = processing.track(assetId);
|
|
117
117
|
stream = s;
|
|
118
118
|
stopWatch = watch(
|