nuxt-media-library 0.0.44

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.
Files changed (164) hide show
  1. package/README.md +243 -0
  2. package/dist/module.d.mts +31 -0
  3. package/dist/module.d.ts +31 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +118 -0
  6. package/dist/runtime/components/MLAssetManager/AssetActivity.d.vue.ts +6 -0
  7. package/dist/runtime/components/MLAssetManager/AssetActivity.vue +13 -0
  8. package/dist/runtime/components/MLAssetManager/AssetActivity.vue.d.ts +6 -0
  9. package/dist/runtime/components/MLAssetManager/AssetCard.d.vue.ts +14 -0
  10. package/dist/runtime/components/MLAssetManager/AssetCard.vue +100 -0
  11. package/dist/runtime/components/MLAssetManager/AssetCard.vue.d.ts +14 -0
  12. package/dist/runtime/components/MLAssetManager/AssetDetail.d.vue.ts +14 -0
  13. package/dist/runtime/components/MLAssetManager/AssetDetail.vue +156 -0
  14. package/dist/runtime/components/MLAssetManager/AssetDetail.vue.d.ts +14 -0
  15. package/dist/runtime/components/MLAssetManager/AssetList.d.vue.ts +15 -0
  16. package/dist/runtime/components/MLAssetManager/AssetList.vue +41 -0
  17. package/dist/runtime/components/MLAssetManager/AssetList.vue.d.ts +15 -0
  18. package/dist/runtime/components/MLAssetManager/AssetOverview.d.vue.ts +8 -0
  19. package/dist/runtime/components/MLAssetManager/AssetOverview.vue +321 -0
  20. package/dist/runtime/components/MLAssetManager/AssetOverview.vue.d.ts +8 -0
  21. package/dist/runtime/components/MLAssetManager/AssetPreview.d.vue.ts +10 -0
  22. package/dist/runtime/components/MLAssetManager/AssetPreview.vue +18 -0
  23. package/dist/runtime/components/MLAssetManager/AssetPreview.vue.d.ts +10 -0
  24. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.d.vue.ts +9 -0
  25. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.vue +21 -0
  26. package/dist/runtime/components/MLAssetManager/AssetPreviewAudio.vue.d.ts +9 -0
  27. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.d.vue.ts +9 -0
  28. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.vue +39 -0
  29. package/dist/runtime/components/MLAssetManager/AssetPreviewDocument.vue.d.ts +9 -0
  30. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.d.vue.ts +7 -0
  31. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.vue +41 -0
  32. package/dist/runtime/components/MLAssetManager/AssetPreviewFallback.vue.d.ts +7 -0
  33. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.d.vue.ts +9 -0
  34. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.vue +30 -0
  35. package/dist/runtime/components/MLAssetManager/AssetPreviewImage.vue.d.ts +9 -0
  36. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.d.vue.ts +15 -0
  37. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.vue +69 -0
  38. package/dist/runtime/components/MLAssetManager/AssetPreviewSidebar.vue.d.ts +15 -0
  39. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.d.vue.ts +9 -0
  40. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.vue +148 -0
  41. package/dist/runtime/components/MLAssetManager/AssetPreviewVideo.vue.d.ts +9 -0
  42. package/dist/runtime/components/MLAssetManager/AssetRenditions.d.vue.ts +8 -0
  43. package/dist/runtime/components/MLAssetManager/AssetRenditions.vue +148 -0
  44. package/dist/runtime/components/MLAssetManager/AssetRenditions.vue.d.ts +8 -0
  45. package/dist/runtime/components/MLAssetManager/Processing.d.vue.ts +8 -0
  46. package/dist/runtime/components/MLAssetManager/Processing.vue +84 -0
  47. package/dist/runtime/components/MLAssetManager/Processing.vue.d.ts +8 -0
  48. package/dist/runtime/components/MLAssetManager/SlotCard.d.vue.ts +17 -0
  49. package/dist/runtime/components/MLAssetManager/SlotCard.vue +94 -0
  50. package/dist/runtime/components/MLAssetManager/SlotCard.vue.d.ts +17 -0
  51. package/dist/runtime/components/MLAssetManager/Widget.d.vue.ts +14 -0
  52. package/dist/runtime/components/MLAssetManager/Widget.vue +328 -0
  53. package/dist/runtime/components/MLAssetManager/Widget.vue.d.ts +14 -0
  54. package/dist/runtime/components/MLPreviewProvider.d.vue.ts +31 -0
  55. package/dist/runtime/components/MLPreviewProvider.vue +51 -0
  56. package/dist/runtime/components/MLPreviewProvider.vue.d.ts +31 -0
  57. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.d.vue.ts +13 -0
  58. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.vue +47 -0
  59. package/dist/runtime/components/MLProcessing/Forms/ConfigureStepModal.vue.d.ts +13 -0
  60. package/dist/runtime/components/MLProcessing/Forms/FramePicker.d.vue.ts +11 -0
  61. package/dist/runtime/components/MLProcessing/Forms/FramePicker.vue +162 -0
  62. package/dist/runtime/components/MLProcessing/Forms/FramePicker.vue.d.ts +11 -0
  63. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.d.vue.ts +14 -0
  64. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.vue +113 -0
  65. package/dist/runtime/components/MLProcessing/Forms/StepOptionsForm.vue.d.ts +14 -0
  66. package/dist/runtime/components/MLProcessing/Pipeline.d.vue.ts +15 -0
  67. package/dist/runtime/components/MLProcessing/Pipeline.vue +178 -0
  68. package/dist/runtime/components/MLProcessing/Pipeline.vue.d.ts +15 -0
  69. package/dist/runtime/components/MLProcessing/PipelineStepItem.d.vue.ts +20 -0
  70. package/dist/runtime/components/MLProcessing/PipelineStepItem.vue +309 -0
  71. package/dist/runtime/components/MLProcessing/PipelineStepItem.vue.d.ts +20 -0
  72. package/dist/runtime/components/MLProcessing/ProgressBar.d.vue.ts +9 -0
  73. package/dist/runtime/components/MLProcessing/ProgressBar.vue +27 -0
  74. package/dist/runtime/components/MLProcessing/ProgressBar.vue.d.ts +9 -0
  75. package/dist/runtime/components/MLProcessing/StepLayout.d.vue.ts +31 -0
  76. package/dist/runtime/components/MLProcessing/StepLayout.vue +36 -0
  77. package/dist/runtime/components/MLProcessing/StepLayout.vue.d.ts +31 -0
  78. package/dist/runtime/components/MLProcessing/Stepper.d.vue.ts +16 -0
  79. package/dist/runtime/components/MLProcessing/Stepper.vue +87 -0
  80. package/dist/runtime/components/MLProcessing/Stepper.vue.d.ts +16 -0
  81. package/dist/runtime/components/MLProcessing/StepperItem.d.vue.ts +16 -0
  82. package/dist/runtime/components/MLProcessing/StepperItem.vue +150 -0
  83. package/dist/runtime/components/MLProcessing/StepperItem.vue.d.ts +16 -0
  84. package/dist/runtime/components/MLProcessing/TopBar.d.vue.ts +21 -0
  85. package/dist/runtime/components/MLProcessing/TopBar.vue +46 -0
  86. package/dist/runtime/components/MLProcessing/TopBar.vue.d.ts +21 -0
  87. package/dist/runtime/components/MLUploader/ButtonUploader.d.vue.ts +55 -0
  88. package/dist/runtime/components/MLUploader/ButtonUploader.vue +211 -0
  89. package/dist/runtime/components/MLUploader/ButtonUploader.vue.d.ts +55 -0
  90. package/dist/runtime/components/MLUploader/Item.d.vue.ts +34 -0
  91. package/dist/runtime/components/MLUploader/Item.vue +242 -0
  92. package/dist/runtime/components/MLUploader/Item.vue.d.ts +34 -0
  93. package/dist/runtime/components/MLUploader/PolicyPopover.d.vue.ts +7 -0
  94. package/dist/runtime/components/MLUploader/PolicyPopover.vue +160 -0
  95. package/dist/runtime/components/MLUploader/PolicyPopover.vue.d.ts +7 -0
  96. package/dist/runtime/components/MLUploader/Widget.d.vue.ts +44 -0
  97. package/dist/runtime/components/MLUploader/Widget.vue +251 -0
  98. package/dist/runtime/components/MLUploader/Widget.vue.d.ts +44 -0
  99. package/dist/runtime/composables/resourcePolicy/mimeUtils.d.ts +4 -0
  100. package/dist/runtime/composables/resourcePolicy/mimeUtils.js +71 -0
  101. package/dist/runtime/composables/resourcePolicy/useMLResourcePolicy.d.ts +17 -0
  102. package/dist/runtime/composables/resourcePolicy/useMLResourcePolicy.js +150 -0
  103. package/dist/runtime/composables/useElapsedTimer.d.ts +13 -0
  104. package/dist/runtime/composables/useElapsedTimer.js +46 -0
  105. package/dist/runtime/composables/useMLAssetLibrary.d.ts +31 -0
  106. package/dist/runtime/composables/useMLAssetLibrary.js +53 -0
  107. package/dist/runtime/composables/useMLAssetManager.d.ts +30 -0
  108. package/dist/runtime/composables/useMLAssetManager.js +229 -0
  109. package/dist/runtime/composables/useMLAssetManagerPreview.d.ts +28 -0
  110. package/dist/runtime/composables/useMLAssetManagerPreview.js +232 -0
  111. package/dist/runtime/composables/useMLAssetPreview.d.ts +23 -0
  112. package/dist/runtime/composables/useMLAssetPreview.js +153 -0
  113. package/dist/runtime/composables/useMLChunkUploader.d.ts +9 -0
  114. package/dist/runtime/composables/useMLChunkUploader.js +22 -0
  115. package/dist/runtime/composables/useMLProcessingPipeline.d.ts +38 -0
  116. package/dist/runtime/composables/useMLProcessingPipeline.js +258 -0
  117. package/dist/runtime/composables/useMLProcessingStatus.d.ts +34 -0
  118. package/dist/runtime/composables/useMLProcessingStatus.js +100 -0
  119. package/dist/runtime/composables/useMLProcessingStepper.d.ts +32 -0
  120. package/dist/runtime/composables/useMLProcessingStepper.js +280 -0
  121. package/dist/runtime/composables/useMLProcessingStrategies.d.ts +7 -0
  122. package/dist/runtime/composables/useMLProcessingStrategies.js +47 -0
  123. package/dist/runtime/composables/useMLRepeater.d.ts +5 -0
  124. package/dist/runtime/composables/useMLRepeater.js +11 -0
  125. package/dist/runtime/css/index.css +1 -0
  126. package/dist/runtime/index.d.ts +13 -0
  127. package/dist/runtime/index.js +13 -0
  128. package/dist/runtime/plugins/asset-direcetive-client.d.ts +2 -0
  129. package/dist/runtime/plugins/asset-direcetive-client.js +64 -0
  130. package/dist/runtime/plugins/config.d.ts +13 -0
  131. package/dist/runtime/plugins/config.js +23 -0
  132. package/dist/runtime/schemas/resource-policy.schema.d.ts +607 -0
  133. package/dist/runtime/schemas/resource-policy.schema.js +117 -0
  134. package/dist/runtime/server/assets-proxy.d.ts +2 -0
  135. package/dist/runtime/server/assets-proxy.js +81 -0
  136. package/dist/runtime/server/create-ml-proxy.d.ts +47 -0
  137. package/dist/runtime/server/create-ml-proxy.js +232 -0
  138. package/dist/runtime/server/delivery-proxy.d.ts +2 -0
  139. package/dist/runtime/server/delivery-proxy.js +74 -0
  140. package/dist/runtime/server/index.d.ts +2 -0
  141. package/dist/runtime/server/index.js +1 -0
  142. package/dist/runtime/server/processing-proxy.d.ts +2 -0
  143. package/dist/runtime/server/processing-proxy.js +55 -0
  144. package/dist/runtime/server/resource-policy-proxy.d.ts +2 -0
  145. package/dist/runtime/server/resource-policy-proxy.js +80 -0
  146. package/dist/runtime/server/tsconfig.json +0 -0
  147. package/dist/runtime/server/uploads-proxy.d.ts +2 -0
  148. package/dist/runtime/server/uploads-proxy.js +99 -0
  149. package/dist/runtime/types/asset.d.ts +174 -0
  150. package/dist/runtime/types/asset.js +7 -0
  151. package/dist/runtime/types/preview.d.ts +20 -0
  152. package/dist/runtime/types/preview.js +0 -0
  153. package/dist/runtime/types/resourcePolicy.d.ts +77 -0
  154. package/dist/runtime/types/resourcePolicy.js +25 -0
  155. package/dist/runtime/types/uploader.d.ts +71 -0
  156. package/dist/runtime/types/uploader.js +0 -0
  157. package/dist/runtime/utils/uploader/checksum.d.ts +21 -0
  158. package/dist/runtime/utils/uploader/checksum.js +23 -0
  159. package/dist/runtime/utils/uploader/chunking.d.ts +8 -0
  160. package/dist/runtime/utils/uploader/chunking.js +21 -0
  161. package/dist/runtime/utils/uploader/uploader.d.ts +20 -0
  162. package/dist/runtime/utils/uploader/uploader.js +206 -0
  163. package/dist/types.d.mts +11 -0
  164. package/package.json +81 -0
@@ -0,0 +1,309 @@
1
+ <script setup>
2
+ import { computed, toRef } from "vue";
3
+ import { useElapsedTimer } from "../../composables/useElapsedTimer";
4
+ const props = defineProps({
5
+ task: { type: Object, required: true },
6
+ expanded: { type: Boolean, required: true },
7
+ sseEvent: { type: [Object, null], required: false },
8
+ blocker: { type: [Object, null], required: false }
9
+ });
10
+ const emit = defineEmits(["toggle", "configure", "retry"]);
11
+ const effectiveStatus = computed(() => {
12
+ const sse = props.sseEvent?.status?.toLowerCase();
13
+ if (sse && sse !== "reaped") return sse;
14
+ return (props.task.status ?? "").toLowerCase();
15
+ });
16
+ const isDone = computed(() => effectiveStatus.value === "succeeded");
17
+ const isRunning = computed(() => effectiveStatus.value === "running");
18
+ const isFailed = computed(() => effectiveStatus.value === "failed");
19
+ const isPendingInput = computed(() => effectiveStatus.value === "pending_input");
20
+ const isWaiting = computed(() => effectiveStatus.value === "waiting");
21
+ const isCanceled = computed(() => effectiveStatus.value === "canceled");
22
+ const isRetry = computed(() => effectiveStatus.value === "retry");
23
+ const isSkipped = computed(
24
+ () => props.task.metadata_payload?.skipped === true
25
+ );
26
+ function parseUtc(iso) {
27
+ if (!iso.endsWith("Z") && !iso.includes("+") && !/\d{2}:\d{2}$/.test(iso.slice(-6))) {
28
+ return (/* @__PURE__ */ new Date(iso + "Z")).getTime();
29
+ }
30
+ return new Date(iso).getTime();
31
+ }
32
+ const startedAtRef = toRef(() => props.task.started_at);
33
+ const { elapsed, formatDuration } = useElapsedTimer(startedAtRef, isRunning);
34
+ const durationText = computed(() => {
35
+ if (isRunning.value) return elapsed.value;
36
+ if (props.task.started_at && props.task.finished_at) {
37
+ const ms = parseUtc(props.task.finished_at) - parseUtc(props.task.started_at);
38
+ return formatDuration(ms);
39
+ }
40
+ return "";
41
+ });
42
+ function humanize(name) {
43
+ return name.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
44
+ }
45
+ const displayName = computed(() => humanize(props.task.task_type));
46
+ const statusLabel = computed(() => {
47
+ if (isSkipped.value) return "SKIPPED";
48
+ if (isDone.value) return "DONE";
49
+ if (isRunning.value) return "RUNNING";
50
+ if (isFailed.value) return "FAILED";
51
+ if (isPendingInput.value) return "NEEDS INPUT";
52
+ if (isWaiting.value) return "WAITING";
53
+ if (isRetry.value) return "RETRY";
54
+ if (isCanceled.value) return "CANCELED";
55
+ return "QUEUED";
56
+ });
57
+ const statusIcon = computed(() => {
58
+ if (isSkipped.value) return "i-lucide-skip-forward";
59
+ if (isDone.value) return "i-lucide-circle-check";
60
+ if (isRunning.value) return "i-lucide-loader";
61
+ if (isFailed.value) return "i-lucide-circle-x";
62
+ if (isPendingInput.value) return "i-lucide-pencil-line";
63
+ if (isWaiting.value) return "i-lucide-clock";
64
+ if (isCanceled.value) return "i-lucide-ban";
65
+ if (isRetry.value) return "i-lucide-refresh-cw";
66
+ return "i-lucide-circle-dot";
67
+ });
68
+ const titleClasses = computed(() => {
69
+ if (isRunning.value) return "font-bold text-primary";
70
+ if (isDone.value) return "font-semibold text-default";
71
+ if (isFailed.value) return "font-semibold text-error";
72
+ if (isPendingInput.value) return "font-semibold text-amber-600";
73
+ if (isCanceled.value || isSkipped.value) return "text-muted line-through";
74
+ return "text-muted";
75
+ });
76
+ const iconClasses = computed(() => {
77
+ if (isDone.value) return "text-green-500";
78
+ if (isRunning.value) return "text-primary";
79
+ if (isFailed.value) return "text-red-500";
80
+ if (isPendingInput.value) return "text-amber-500";
81
+ if (isRetry.value) return "text-amber-500";
82
+ if (isCanceled.value || isSkipped.value) return "text-muted";
83
+ return "text-muted";
84
+ });
85
+ const badgeColor = computed(() => {
86
+ if (isFailed.value) return "error";
87
+ if (isRunning.value) return "warning";
88
+ if (isDone.value || isSkipped.value) return "success";
89
+ if (isPendingInput.value) return "warning";
90
+ if (isRetry.value) return "warning";
91
+ return "neutral";
92
+ });
93
+ const badgeVariant = computed(() => isRunning.value ? "solid" : "subtle");
94
+ const rowDescription = computed(() => {
95
+ if (reapedHint.value?.terminal) return "Worker timed out \u2014 retries exhausted";
96
+ if (reapedHint.value?.requeued) return "Worker timed out \u2014 re-queued";
97
+ if (isSkipped.value && props.task.metadata_payload?.reason) {
98
+ return props.task.metadata_payload.reason;
99
+ }
100
+ if (isWaiting.value && props.blocker) {
101
+ const blockerStatus = (props.blocker.status ?? "").toLowerCase();
102
+ const blockerName = humanize(props.blocker.task_type);
103
+ if (blockerStatus === "pending_input") return `Waiting on ${blockerName} (needs configuration)`;
104
+ if (blockerStatus === "running") return `Waiting on ${blockerName}`;
105
+ if (blockerStatus === "failed") return `Blocked by failure in ${blockerName}`;
106
+ return `Waiting on ${blockerName}`;
107
+ }
108
+ return "";
109
+ });
110
+ const maxRetries = computed(() => props.task.max_retries ?? props.task.maxRetries ?? null);
111
+ const attemptsBadge = computed(() => {
112
+ const attempts = props.task.attempts ?? 0;
113
+ const max = maxRetries.value;
114
+ if (!attempts) return "";
115
+ if (typeof max === "number" && max > 0) return `${attempts}/${max}`;
116
+ return `${attempts}`;
117
+ });
118
+ const showAttemptsBadge = computed(
119
+ () => !!attemptsBadge.value && (isFailed.value || isRetry.value || isRunning.value && (props.task.attempts ?? 0) > 1)
120
+ );
121
+ const failureKind = computed(() => props.task.failure_kind ?? props.task.failureKind ?? null);
122
+ const failurePill = computed(() => {
123
+ if (!isFailed.value || !failureKind.value) return null;
124
+ switch (failureKind.value) {
125
+ case "validation":
126
+ return { label: "Invalid config", color: "error", icon: "i-lucide-alert-triangle" };
127
+ case "timeout":
128
+ return { label: "Timed out", color: "warning", icon: "i-lucide-timer-off" };
129
+ case "crash":
130
+ return { label: "Crashed", color: "error", icon: "i-lucide-circle-x" };
131
+ case "worker_lost":
132
+ return { label: "Worker died", color: "neutral", icon: "i-lucide-plug-zap" };
133
+ default:
134
+ return null;
135
+ }
136
+ });
137
+ const isValidationFailure = computed(
138
+ () => isFailed.value && failureKind.value === "validation"
139
+ );
140
+ const isRetryable = computed(
141
+ () => isFailed.value && failureKind.value !== "validation" && failureKind.value !== "worker_lost"
142
+ );
143
+ const reapedHint = computed(() => {
144
+ if (props.sseEvent?.status?.toLowerCase() !== "reaped") return null;
145
+ const meta = props.sseEvent.metadata ?? {};
146
+ return { requeued: meta.requeued === true, terminal: meta.terminal === true };
147
+ });
148
+ const blobChain = computed(() => {
149
+ const inId = props.task.input_blob_id ?? props.task.inputBlobId ?? null;
150
+ const outId = props.task.output_blob_id ?? props.task.outputBlobId ?? null;
151
+ if (!inId && !outId) return null;
152
+ const short = (id) => id ? id.slice(0, 8) : "\u2014";
153
+ return { in: short(inId), out: short(outId), inFull: inId, outFull: outId };
154
+ });
155
+ const hasExpandableContent = computed(
156
+ () => !!(props.task.last_error || props.task.metadata_payload && Object.keys(props.task.metadata_payload).length || blobChain.value)
157
+ );
158
+ const metadataEntries = computed(() => {
159
+ if (!props.task.metadata_payload) return [];
160
+ return Object.entries(props.task.metadata_payload).filter(
161
+ ([key]) => key !== "skipped" && key !== "reason"
162
+ );
163
+ });
164
+ const formatTime = (iso) => {
165
+ const ms = parseUtc(iso);
166
+ const date = new Date(ms);
167
+ return date.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit", second: "2-digit" });
168
+ };
169
+ const formatMetaKey = (key) => key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
170
+ </script>
171
+
172
+ <template>
173
+ <MLProcessingStepLayout
174
+ :title="displayName"
175
+ :description="rowDescription"
176
+ :title-class="titleClasses"
177
+ :icon="statusIcon"
178
+ :icon-class="iconClasses"
179
+ :spinning="isRunning"
180
+ class="group"
181
+ :class="{ 'cursor-pointer': hasExpandableContent }"
182
+ @click="hasExpandableContent && emit('toggle')"
183
+ >
184
+ <template #header-actions>
185
+ <span v-if="durationText" class="text-xs text-muted font-mono">{{ durationText }}</span>
186
+ <UBadge
187
+ v-if="failurePill"
188
+ :color="failurePill.color"
189
+ variant="subtle"
190
+ size="xs"
191
+ :icon="failurePill.icon"
192
+ :label="failurePill.label"
193
+ />
194
+ <UBadge
195
+ v-if="showAttemptsBadge"
196
+ color="warning"
197
+ variant="subtle"
198
+ size="xs"
199
+ icon="i-lucide-refresh-cw"
200
+ :label="attemptsBadge"
201
+ :title="`Attempt ${task.attempts}${maxRetries ? ' of ' + maxRetries : ''}`"
202
+ />
203
+ <UBadge
204
+ v-if="!isDone && !failurePill"
205
+ :color="badgeColor"
206
+ :variant="badgeVariant"
207
+ :label="statusLabel"
208
+ size="xs"
209
+ />
210
+ <UButton
211
+ v-if="isPendingInput || isValidationFailure"
212
+ size="xs"
213
+ variant="soft"
214
+ color="warning"
215
+ icon="i-lucide-settings"
216
+ label="Configure"
217
+ @click.stop="emit('configure', task.id)"
218
+ />
219
+ <UButton
220
+ v-if="isRetryable"
221
+ size="xs"
222
+ variant="ghost"
223
+ color="warning"
224
+ icon="i-lucide-refresh-cw"
225
+ :title="`Retry this step${maxRetries ? ` (${task.attempts ?? 0}/${maxRetries} attempts used)` : ''}`"
226
+ @click.stop="emit('retry', task.id)"
227
+ />
228
+ <UIcon
229
+ v-if="hasExpandableContent"
230
+ name="i-lucide-chevron-down"
231
+ class="size-4 text-muted transition-transform duration-200"
232
+ :class="{ 'rotate-180': expanded }"
233
+ />
234
+ </template>
235
+
236
+ <!-- Expanded Content -->
237
+ <Transition
238
+ enter-active-class="transition-all duration-200 ease-out"
239
+ leave-active-class="transition-all duration-150 ease-in"
240
+ enter-from-class="opacity-0 max-h-0"
241
+ enter-to-class="opacity-100 max-h-96"
242
+ leave-from-class="opacity-100 max-h-96"
243
+ leave-to-class="opacity-0 max-h-0"
244
+ >
245
+ <div v-if="expanded" class="overflow-hidden">
246
+ <div class="mt-3 space-y-2 text-xs">
247
+ <!-- Error -->
248
+ <div
249
+ v-if="task.last_error"
250
+ class="bg-error/5 border border-error/20 rounded-md p-3 text-error"
251
+ >
252
+ <div class="font-medium mb-1">Error</div>
253
+ <pre class="whitespace-pre-wrap font-mono text-[11px] leading-relaxed">{{ task.last_error }}</pre>
254
+ <div v-if="task.attempts > 1" class="text-muted mt-1.5">
255
+ Attempt {{ task.attempts }}
256
+ </div>
257
+ </div>
258
+
259
+ <!-- Metadata -->
260
+ <div
261
+ v-if="metadataEntries.length"
262
+ class="bg-muted/30 border border-default rounded-md p-3"
263
+ >
264
+ <div
265
+ v-for="([key, value]) in metadataEntries"
266
+ :key="key"
267
+ class="flex items-start gap-2 py-0.5"
268
+ >
269
+ <span class="text-muted shrink-0">{{ formatMetaKey(key) }}:</span>
270
+ <span
271
+ v-if="typeof value === 'boolean'"
272
+ class="font-medium"
273
+ :class="value ? 'text-green-500' : 'text-red-500'"
274
+ >
275
+ {{ value ? "Yes" : "No" }}
276
+ </span>
277
+ <span v-else-if="typeof value === 'number'" class="font-mono">{{ value }}</span>
278
+ <span v-else-if="Array.isArray(value)">{{ value.join(", ") }}</span>
279
+ <pre
280
+ v-else-if="typeof value === 'object' && value !== null"
281
+ class="text-[11px] font-mono whitespace-pre-wrap"
282
+ >{{ JSON.stringify(value, null, 2) }}</pre>
283
+ <span v-else>{{ value }}</span>
284
+ </div>
285
+ </div>
286
+
287
+ <!-- Blob chain (debug) -->
288
+ <div
289
+ v-if="blobChain"
290
+ class="flex items-center gap-2 text-muted font-mono text-[11px]"
291
+ >
292
+ <span class="text-muted/70">in:</span>
293
+ <span :title="blobChain.inFull ?? ''">{{ blobChain.in }}</span>
294
+ <UIcon name="i-lucide-arrow-right" class="size-3" />
295
+ <span class="text-muted/70">out:</span>
296
+ <span :title="blobChain.outFull ?? ''">{{ blobChain.out }}</span>
297
+ </div>
298
+
299
+ <!-- Timing -->
300
+ <div class="flex flex-wrap gap-4 text-muted">
301
+ <span v-if="task.queued_at">Queued: {{ formatTime(task.queued_at) }}</span>
302
+ <span v-if="task.started_at">Started: {{ formatTime(task.started_at) }}</span>
303
+ <span v-if="task.finished_at">Finished: {{ formatTime(task.finished_at) }}</span>
304
+ </div>
305
+ </div>
306
+ </div>
307
+ </Transition>
308
+ </MLProcessingStepLayout>
309
+ </template>
@@ -0,0 +1,20 @@
1
+ import type { ProcessingTask } from "../../types/asset.js";
2
+ import type { ProcessingEvent } from "../../composables/useMLProcessingStatus.js";
3
+ type __VLS_Props = {
4
+ task: ProcessingTask;
5
+ expanded: boolean;
6
+ sseEvent?: ProcessingEvent | null;
7
+ /** Upstream task currently blocking this row (only meaningful for `waiting` rows). */
8
+ blocker?: ProcessingTask | null;
9
+ };
10
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ toggle: () => any;
12
+ retry: (taskId: string) => any;
13
+ configure: (taskId: string) => any;
14
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
15
+ onToggle?: (() => any) | undefined;
16
+ onRetry?: ((taskId: string) => any) | undefined;
17
+ onConfigure?: ((taskId: string) => any) | undefined;
18
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
+ declare const _default: typeof __VLS_export;
20
+ export default _default;
@@ -0,0 +1,9 @@
1
+ type __VLS_Props = {
2
+ percent: number;
3
+ color?: 'primary' | 'success' | 'error';
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
6
+ color: "primary" | "success" | "error";
7
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,27 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ const props = defineProps({
4
+ percent: { type: Number, required: true },
5
+ color: { type: String, required: false, default: "primary" }
6
+ });
7
+ const barClass = computed(() => {
8
+ switch (props.color) {
9
+ case "success":
10
+ return "bg-green-500";
11
+ case "error":
12
+ return "bg-red-500";
13
+ default:
14
+ return "bg-primary";
15
+ }
16
+ });
17
+ </script>
18
+
19
+ <template>
20
+ <div class="h-0.5 border-x border-default overflow-hidden">
21
+ <div
22
+ class="h-full transition-all duration-500 ease-out"
23
+ :class="barClass"
24
+ :style="{ width: `${percent}%` }"
25
+ />
26
+ </div>
27
+ </template>
@@ -0,0 +1,9 @@
1
+ type __VLS_Props = {
2
+ percent: number;
3
+ color?: 'primary' | 'success' | 'error';
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
6
+ color: "primary" | "success" | "error";
7
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,31 @@
1
+ type __VLS_Props = {
2
+ title: string;
3
+ description?: string;
4
+ titleClass?: string;
5
+ icon?: string;
6
+ iconClass?: string;
7
+ spinning?: boolean;
8
+ showBody?: boolean;
9
+ };
10
+ declare var __VLS_6: {}, __VLS_8: {};
11
+ type __VLS_Slots = {} & {
12
+ 'header-actions'?: (props: typeof __VLS_6) => any;
13
+ } & {
14
+ default?: (props: typeof __VLS_8) => any;
15
+ };
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
+ description: string;
18
+ icon: string;
19
+ titleClass: string;
20
+ iconClass: string;
21
+ spinning: boolean;
22
+ showBody: boolean;
23
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,36 @@
1
+ <script setup>
2
+ defineProps({
3
+ title: { type: String, required: true },
4
+ description: { type: String, required: false, default: "" },
5
+ titleClass: { type: String, required: false, default: "" },
6
+ icon: { type: String, required: false, default: "i-lucide-circle-dot" },
7
+ iconClass: { type: String, required: false, default: "text-muted" },
8
+ spinning: { type: Boolean, required: false, default: false },
9
+ showBody: { type: Boolean, required: false, default: true }
10
+ });
11
+ </script>
12
+
13
+ <template>
14
+ <div class="">
15
+ <!-- Header -->
16
+ <div class="flex items-center justify-between bg-default p-2 border border-default ">
17
+ <div class="flex items-center gap-2 min-w-0">
18
+ <UIcon
19
+ :name="icon"
20
+ class="size-4 shrink-0"
21
+ :class="[iconClass, { 'animate-spin': spinning }]"
22
+ />
23
+ <div class="">
24
+ <span class="text-sm truncate" :class="titleClass">{{ title }}</span>
25
+ <span class="text-sm truncate" v-if="description" :class="description">{{ description }}</span>
26
+ </div>
27
+ </div>
28
+ <div class="flex items-center gap-2 shrink-0">
29
+ <slot name="header-actions"/>
30
+ </div>
31
+ </div>
32
+
33
+ <!-- Body -->
34
+ <slot v-if="showBody && $slots.default"/>
35
+ </div>
36
+ </template>
@@ -0,0 +1,31 @@
1
+ type __VLS_Props = {
2
+ title: string;
3
+ description?: string;
4
+ titleClass?: string;
5
+ icon?: string;
6
+ iconClass?: string;
7
+ spinning?: boolean;
8
+ showBody?: boolean;
9
+ };
10
+ declare var __VLS_6: {}, __VLS_8: {};
11
+ type __VLS_Slots = {} & {
12
+ 'header-actions'?: (props: typeof __VLS_6) => any;
13
+ } & {
14
+ default?: (props: typeof __VLS_8) => any;
15
+ };
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
+ description: string;
18
+ icon: string;
19
+ titleClass: string;
20
+ iconClass: string;
21
+ spinning: boolean;
22
+ showBody: boolean;
23
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ assetId: string;
3
+ assetKind?: string;
4
+ downloadUrl?: string | null;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
+ failed: () => any;
8
+ complete: () => any;
9
+ stepComplete: (stepName: string) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onFailed?: (() => any) | undefined;
12
+ onComplete?: (() => any) | undefined;
13
+ onStepComplete?: ((stepName: string) => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,87 @@
1
+ <script setup>
2
+ import { watch } from "vue";
3
+ import { useMLProcessingStepper } from "../../composables/useMLProcessingStepper";
4
+ const props = defineProps({
5
+ assetId: { type: String, required: true },
6
+ assetKind: { type: String, required: false },
7
+ downloadUrl: { type: [String, null], required: false }
8
+ });
9
+ const emit = defineEmits(["complete", "failed", "stepComplete"]);
10
+ const {
11
+ steps,
12
+ loading,
13
+ currentStepIndex,
14
+ allComplete,
15
+ hasAnyFailed,
16
+ progressPercent,
17
+ updateStepOptions,
18
+ runStep,
19
+ retryStep,
20
+ runRemaining
21
+ } = useMLProcessingStepper(() => props.assetId);
22
+ watch(allComplete, (done) => {
23
+ if (done) emit("complete");
24
+ });
25
+ watch(hasAnyFailed, (failed) => {
26
+ if (failed) emit("failed");
27
+ });
28
+ const hasPendingSteps = () => steps.value.some((s) => s.status !== "succeeded" && s.status !== "skipped");
29
+ </script>
30
+
31
+ <template>
32
+ <div class="space-y-0">
33
+ <MLProcessingTopBar title="Manual Processing">
34
+ <template #subtitle>
35
+ Step {{ Math.min(currentStepIndex + 1, steps.length) }} of {{ steps.length }}
36
+ <template v-if="allComplete"> · All steps complete</template>
37
+ </template>
38
+ <template #actions>
39
+ <UButton
40
+ v-if="hasPendingSteps() && !allComplete"
41
+ variant="outline"
42
+ color="neutral"
43
+ size="xs"
44
+ icon="i-lucide-fast-forward"
45
+ label="Run Remaining"
46
+ @click="runRemaining"
47
+ />
48
+ </template>
49
+ </MLProcessingTopBar>
50
+
51
+ <MLProcessingProgressBar
52
+ :percent="progressPercent"
53
+ :color="hasAnyFailed ? 'error' : allComplete ? 'success' : 'primary'"
54
+ />
55
+
56
+ <!-- Steps -->
57
+ <div class="border border-t-0 border-default rounded-b-lg">
58
+ <!-- Loading -->
59
+ <div v-if="loading && !steps.length" class="space-y-3 p-4">
60
+ <USkeleton v-for="i in 4" :key="i" class="h-12 w-full" />
61
+ </div>
62
+
63
+ <!-- Step List -->
64
+ <template v-else-if="steps.length">
65
+ <MLProcessingStepperItem
66
+ v-for="step in steps"
67
+ :key="step.name"
68
+ :step="step"
69
+ :download-url="step.name === 'video_thumbnail' ? downloadUrl : void 0"
70
+ @update:options="updateStepOptions(step.name, $event)"
71
+ @run="runStep(step.name)"
72
+ @retry="retryStep(step.name)"
73
+ />
74
+ </template>
75
+
76
+ <!-- Empty -->
77
+ <UEmpty
78
+ v-else
79
+ icon="i-lucide-list-checks"
80
+ title="No pipeline available"
81
+ description="No processing steps found for this asset type."
82
+ size="sm"
83
+ class="py-8"
84
+ />
85
+ </div>
86
+ </div>
87
+ </template>
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ assetId: string;
3
+ assetKind?: string;
4
+ downloadUrl?: string | null;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
+ failed: () => any;
8
+ complete: () => any;
9
+ stepComplete: (stepName: string) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onFailed?: (() => any) | undefined;
12
+ onComplete?: (() => any) | undefined;
13
+ onStepComplete?: ((stepName: string) => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import type { StepState } from "../../composables/useMLProcessingStepper.js";
2
+ type __VLS_Props = {
3
+ step: StepState;
4
+ downloadUrl?: string | null;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
+ retry: () => any;
8
+ "update:options": (value: Record<string, any>) => any;
9
+ run: () => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onRetry?: (() => any) | undefined;
12
+ "onUpdate:options"?: ((value: Record<string, any>) => any) | undefined;
13
+ onRun?: (() => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;