@xuda.io/xuda-widget-plugin-xuda-drive 1.0.141 → 1.0.142

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 (3) hide show
  1. package/dist/runtime.mjs +1900 -1875
  2. package/package.json +1 -1
  3. package/src/runtime.mjs +49 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/xuda-widget-plugin-xuda-drive",
3
- "version": "1.0.141",
3
+ "version": "1.0.142",
4
4
  "description": "Xuda Drive widget plugin",
5
5
  "scripts": {
6
6
  "pub": "npm version patch --force && npm publish --access public",
package/src/runtime.mjs CHANGED
@@ -799,12 +799,19 @@ export async function viewer(fields, e) {
799
799
  <div v-if="uploadJobs.length || checkingFiles" class="fixed bottom-4 right-4 z-[100] w-96 bg-white rounded-lg shadow-2xl border border-neutral-200 overflow-hidden" style="font-family: system-ui, -apple-system, sans-serif;">
800
800
  <!-- Header -->
801
801
  <div class="flex items-center justify-between px-4 py-3 bg-neutral-900 text-white cursor-pointer" @click="jobWindowCollapsed = !jobWindowCollapsed">
802
- <div class="font-medium text-sm">
803
- <template v-if="checkingFiles">Checking {{ checkingFilesCount }} file{{ checkingFilesCount > 1 ? 's' : '' }}</template>
804
- <template v-else-if="uploadsInProgress > 0">Uploading {{ uploadsInProgress }} item{{ uploadsInProgress > 1 ? 's' : '' }}<template v-if="uploadsFailed">, {{ uploadsFailed }} failed</template></template>
805
- <template v-else>
806
- {{ uploadsDone }} uploaded<template v-if="uploadsFailed">, {{ uploadsFailed }} failed</template>
807
- </template>
802
+ <div class="flex items-center gap-2.5 font-medium text-sm">
803
+ <!-- Circular progress -->
804
+ <svg v-if="uploadJobs.length && !checkingFiles && uploadsInProgress > 0" class="w-5 h-5 -rotate-90 shrink-0" viewBox="0 0 20 20">
805
+ <circle cx="10" cy="10" r="8" fill="none" stroke="currentColor" stroke-width="2.5" opacity="0.2" />
806
+ <circle cx="10" cy="10" r="8" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" :stroke-dasharray="50.265" :stroke-dashoffset="50.265 - (50.265 * overallProgress / 100)" class="transition-all duration-300" />
807
+ </svg>
808
+ <div>
809
+ <template v-if="checkingFiles">Checking {{ checkingFilesCount }} file{{ checkingFilesCount > 1 ? 's' : '' }}</template>
810
+ <template v-else-if="uploadsInProgress > 0">Uploading {{ uploadsInProgress }} item{{ uploadsInProgress > 1 ? 's' : '' }}<template v-if="uploadsFailed">, {{ uploadsFailed }} failed</template></template>
811
+ <template v-else>
812
+ {{ uploadsDone }} uploaded<template v-if="uploadsFailed">, {{ uploadsFailed }} failed</template>
813
+ </template>
814
+ </div>
808
815
  </div>
809
816
  <div class="flex items-center gap-2">
810
817
  <button @click.stop="jobWindowCollapsed = !jobWindowCollapsed" class="text-white/70 hover:text-white">
@@ -849,8 +856,10 @@ export async function viewer(fields, e) {
849
856
  <!-- Upload jobs -->
850
857
  <div v-for="job in uploadJobs" :key="job.id" :ref="'job-' + job.id" class="flex items-center gap-3 px-4 py-2.5">
851
858
  <div class="shrink-0">
859
+ <!-- Pending (queued) -->
860
+ <svg v-if="job.status === 'pending'" class="w-5 h-5 text-neutral-300" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /></svg>
852
861
  <!-- Uploading spinner -->
853
- <svg v-if="job.status === 'uploading'" class="w-5 h-5 text-neutral-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /></svg>
862
+ <svg v-else-if="job.status === 'uploading'" class="w-5 h-5 text-neutral-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /></svg>
854
863
  <!-- Success icon -->
855
864
  <svg v-else-if="job.status === 'done'" class="w-5 h-5 text-green-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm13.36-1.814a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z" clip-rule="evenodd" /></svg>
856
865
  <!-- Error icon -->
@@ -1144,12 +1153,25 @@ export async function viewer(fields, e) {
1144
1153
  id: jobId,
1145
1154
  name: file.name,
1146
1155
  progress: 0,
1147
- status: 'uploading',
1156
+ status: 'pending',
1148
1157
  file: file,
1149
1158
  isUpdate: isUpdate,
1150
1159
  });
1151
- this.uploadSingleFile(file, jobId, isUpdate);
1152
1160
  });
1161
+
1162
+ this.processQueue();
1163
+ },
1164
+ processQueue() {
1165
+ const MAX_CONCURRENT = 10;
1166
+ const active = this.uploadJobs.filter(j => j.status === 'uploading').length;
1167
+ const pending = this.uploadJobs.filter(j => j.status === 'pending');
1168
+ const slotsAvailable = MAX_CONCURRENT - active;
1169
+
1170
+ for (let i = 0; i < Math.min(slotsAvailable, pending.length); i++) {
1171
+ const job = pending[i];
1172
+ job.status = 'uploading';
1173
+ this.uploadSingleFile(job.file, job.id, job.isUpdate);
1174
+ }
1153
1175
  },
1154
1176
  uploadSingleFile(file, jobId, isUpdate) {
1155
1177
  let formData = new FormData();
@@ -1200,6 +1222,14 @@ export async function viewer(fields, e) {
1200
1222
  }
1201
1223
  };
1202
1224
 
1225
+ const onComplete = () => {
1226
+ this.processQueue();
1227
+ const hasPending = this.uploadJobs.some(j => j.status === 'pending');
1228
+ if (this.uploadsInProgress === 0 && !hasPending) {
1229
+ this.refreshDirectory(false, true);
1230
+ }
1231
+ };
1232
+
1203
1233
  request.onload = () => {
1204
1234
  const job = this.uploadJobs.find((j) => j.id === jobId);
1205
1235
  try {
@@ -1212,19 +1242,13 @@ export async function viewer(fields, e) {
1212
1242
  } catch (_e) {
1213
1243
  if (job) job.status = 'error';
1214
1244
  }
1215
-
1216
- // If all jobs done, refresh directory
1217
- if (this.uploadsInProgress === 0) {
1218
- this.refreshDirectory(false, true);
1219
- }
1245
+ onComplete();
1220
1246
  };
1221
1247
 
1222
1248
  request.onerror = () => {
1223
1249
  const job = this.uploadJobs.find((j) => j.id === jobId);
1224
1250
  if (job) job.status = 'error';
1225
- if (this.uploadsInProgress === 0) {
1226
- this.refreshDirectory(false, true);
1227
- }
1251
+ onComplete();
1228
1252
  };
1229
1253
 
1230
1254
  request.send(formData);
@@ -1236,8 +1260,10 @@ export async function viewer(fields, e) {
1236
1260
  },
1237
1261
  retryAllFailed() {
1238
1262
  this.uploadJobs.filter(j => j.status === 'error').forEach(job => {
1239
- this.retryUpload(job);
1263
+ job.status = 'pending';
1264
+ job.progress = 0;
1240
1265
  });
1266
+ this.processQueue();
1241
1267
  },
1242
1268
  navigateFailed(direction) {
1243
1269
  const failedJobs = this.uploadJobs.filter(j => j.status === 'error');
@@ -1296,7 +1322,7 @@ export async function viewer(fields, e) {
1296
1322
  },
1297
1323
  computed: {
1298
1324
  uploadsInProgress() {
1299
- return this.uploadJobs.filter((j) => j.status === 'uploading').length;
1325
+ return this.uploadJobs.filter((j) => j.status === 'uploading' || j.status === 'pending').length;
1300
1326
  },
1301
1327
  uploadsDone() {
1302
1328
  return this.uploadJobs.filter(j => j.status === 'done').length;
@@ -1304,6 +1330,10 @@ export async function viewer(fields, e) {
1304
1330
  uploadsFailed() {
1305
1331
  return this.uploadJobs.filter(j => j.status === 'error').length;
1306
1332
  },
1333
+ overallProgress() {
1334
+ if (!this.uploadJobs.length) return 0;
1335
+ return this.uploadJobs.reduce((sum, j) => sum + j.progress, 0) / this.uploadJobs.length;
1336
+ },
1307
1337
  acceptTypes() {
1308
1338
  if (fields.file_upload_mime_type_preset) {
1309
1339
  switch (fields.file_upload_mime_type_preset) {