@xuda.io/xuda-widget-plugin-xuda-drive 1.0.134 → 1.0.136
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/runtime.mjs +2071 -2062
- package/package.json +1 -1
- package/src/runtime.mjs +219 -202
- package/tests/index.html +52 -56
package/package.json
CHANGED
package/src/runtime.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import 'filepond/dist/filepond.min.css';
|
|
|
3
3
|
|
|
4
4
|
window.FilePond = FilePond;
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
|
|
8
7
|
|
|
9
8
|
import * as pintura from './vendors/pintura/pintura/pintura.js';
|
|
@@ -163,7 +162,7 @@ export async function upload(fields, e) {
|
|
|
163
162
|
allowProcess: true,
|
|
164
163
|
allowRemove: true,
|
|
165
164
|
allowRevert: true,
|
|
166
|
-
maxParallelUploads:
|
|
165
|
+
maxParallelUploads: 50,
|
|
167
166
|
|
|
168
167
|
imageCropAspectRatio: 1,
|
|
169
168
|
imageResizeTargetWidth: 200,
|
|
@@ -634,7 +633,7 @@ export async function viewer(fields, e) {
|
|
|
634
633
|
|
|
635
634
|
<div>
|
|
636
635
|
<button
|
|
637
|
-
@click="
|
|
636
|
+
@click="$refs.fileInput.click()"
|
|
638
637
|
type="button"
|
|
639
638
|
class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"
|
|
640
639
|
>
|
|
@@ -752,129 +751,91 @@ export async function viewer(fields, e) {
|
|
|
752
751
|
</div>
|
|
753
752
|
</div>
|
|
754
753
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
<div v-show="uploadModal" @click="uploadModal=false" class="absolute inset-0 w-full h-full bg-white backdrop-blur-sm bg-opacity-70"></div>
|
|
754
|
+
<!-- Hidden native file input -->
|
|
755
|
+
<input type="file" ref="fileInput" :multiple="options.file_upload_allow_multiple_files" :accept="acceptTypes" class="hidden" @change="onFilesSelected" />
|
|
758
756
|
|
|
757
|
+
<!-- Consent override modal -->
|
|
758
|
+
<teleport to="body">
|
|
759
|
+
<div @keydown.escape.window="showExistModal = false" v-show="showExistModal" class="fixed top-0 left-0 z-[99] w-screen h-screen" x-cloak>
|
|
760
|
+
<div v-show="showExistModal" @click="showExistModal=false" class="absolute inset-0 w-full h-full bg-white backdrop-blur-sm bg-opacity-70"></div>
|
|
759
761
|
<transition key="wrapper" enter-from-class="opacity-0" enter-active-class="ease-out duration-300" enter-to-class="opacity-100" leave-from-class="opacity-100" leave-active-class="ease-in duration-300" leave-to-class="opacity-0">
|
|
760
|
-
<div class="flex items-center justify-center size-full" v-show="
|
|
761
|
-
<transition
|
|
762
|
-
|
|
763
|
-
enter-active-class="ease-out duration-300"
|
|
764
|
-
enter-from-class="opacity-0 -translate-y-2 sm:scale-95"
|
|
765
|
-
enter-to-class="opacity-100 translate-y-0 sm:scale-100"
|
|
766
|
-
leave-active-class="ease-in duration-200"
|
|
767
|
-
leave-from-class="opacity-100 translate-y-0 sm:scale-100"
|
|
768
|
-
leave-to-class="opacity-0 -translate-y-2 sm:scale-95"
|
|
769
|
-
>
|
|
770
|
-
<div v-show="uploadModal" class="relative w-full py-6 bg-white border shadow-lg px-7 border-neutral-200 sm:max-w-lg sm:rounded-lg overflow-hidden">
|
|
762
|
+
<div class="flex items-center justify-center size-full" v-show="showExistModal">
|
|
763
|
+
<transition key="inner" enter-active-class="ease-out duration-300" enter-from-class="opacity-0 -translate-y-2 sm:scale-95" enter-to-class="opacity-100 translate-y-0 sm:scale-100" leave-active-class="ease-in duration-200" leave-from-class="opacity-100 translate-y-0 sm:scale-100" leave-to-class="opacity-0 -translate-y-2 sm:scale-95">
|
|
764
|
+
<div v-show="showExistModal" class="relative w-full py-6 bg-white border shadow-lg px-7 border-neutral-200 sm:max-w-lg sm:rounded-lg overflow-hidden">
|
|
771
765
|
<div class="flex items-center justify-between pb-3">
|
|
772
|
-
<h3 class="text-lg font-semibold"
|
|
773
|
-
<button @click="
|
|
766
|
+
<h3 class="text-lg font-semibold">Upload options</h3>
|
|
767
|
+
<button @click="showExistModal=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
|
|
774
768
|
<svg class="w-5 h-5" 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="M6 18L18 6M6 6l12 12" /></svg>
|
|
775
769
|
</button>
|
|
776
770
|
</div>
|
|
777
|
-
<div
|
|
778
|
-
|
|
779
|
-
<
|
|
771
|
+
<div class="flex-1">
|
|
772
|
+
<p class="text-gray-800">One or more items already exists in this location. Do you want to replace the existing items with a new version or keep both items? Replacing the items won't change sharing settings.</p>
|
|
773
|
+
<fieldset>
|
|
774
|
+
<div class="mt-6 space-y-5 pl-2">
|
|
775
|
+
<div v-for="option in replaceOptions" :key="option.value">
|
|
776
|
+
<label :for="option.value" class="flex items-center cursor-pointer">
|
|
777
|
+
<input :id="option.value" name="notification-method" type="radio" :value="option.value" v-model="overrideAction" :checked="option.value === overrideAction" class="option-radio peer" />
|
|
778
|
+
<div class="ml-3 block font-medium peer-checked:text-black text-light-700 cursor-pointer">{{ option.label }}</div>
|
|
779
|
+
</label>
|
|
780
|
+
</div>
|
|
781
|
+
</div>
|
|
782
|
+
</fieldset>
|
|
783
|
+
</div>
|
|
784
|
+
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-6">
|
|
785
|
+
<button @click="showExistModal=false" type="button" class="inline-flex gap-2 items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors border rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-100 focus:ring-offset-2">
|
|
780
786
|
<div>Dismiss</div>
|
|
781
787
|
</button>
|
|
782
|
-
<button
|
|
783
|
-
|
|
784
|
-
:disabled="uploaderLoading || checkingFiles"
|
|
785
|
-
type="button"
|
|
786
|
-
class="inline-flex items-center gap-2 justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
787
|
-
>
|
|
788
|
-
<template v-if="checkingFiles">
|
|
789
|
-
<sepcial-loader class="size-5" />
|
|
790
|
-
Checking files...
|
|
791
|
-
</template>
|
|
792
|
-
|
|
793
|
-
<template v-else-if="uploaderLoading">
|
|
794
|
-
<sepcial-loader class="size-5" />
|
|
795
|
-
Uploading
|
|
796
|
-
</template>
|
|
797
|
-
|
|
798
|
-
<template v-else>Upload</template>
|
|
788
|
+
<button @click="startUpload(true)" type="button" class="inline-flex items-center gap-2 justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900">
|
|
789
|
+
Upload
|
|
799
790
|
</button>
|
|
800
791
|
</div>
|
|
801
|
-
|
|
802
|
-
<div v-show="showExistModal" class="absolute inset-0 bg-white py-6 px-7 flex flex-col">
|
|
803
|
-
<div class="flex items-center justify-between pb-3">
|
|
804
|
-
<h3 class="text-lg font-semibold">Upload options</h3>
|
|
805
|
-
<button @click="showExistModal=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
|
|
806
|
-
<svg class="w-5 h-5" 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="M6 18L18 6M6 6l12 12" /></svg>
|
|
807
|
-
</button>
|
|
808
|
-
</div>
|
|
809
|
-
|
|
810
|
-
<div class="flex-1">
|
|
811
|
-
<p class="text-gray-800">One or more items already exists in this location. Do you want to replace the existing items with a new version or keep both items? Replacing the items won't change sharing settings.</p>
|
|
812
|
-
|
|
813
|
-
<fieldset>
|
|
814
|
-
<div class="mt-6 space-y-5 pl-2">
|
|
815
|
-
<div v-for="option in replaceOptions" :key="option.value">
|
|
816
|
-
<label :for="option.value" class="flex items-center cursor-pointer">
|
|
817
|
-
<input :id="option.value" name="notification-method" type="radio" :value="option.value" v-model="overrideAction" :checked="option.value === overrideAction" class="option-radio peer" />
|
|
818
|
-
<div class="ml-3 block font-medium peer-checked:text-black text-light-700 cursor-pointer">{{ option.label }}</div>
|
|
819
|
-
</label>
|
|
820
|
-
</div>
|
|
821
|
-
</div>
|
|
822
|
-
</fieldset>
|
|
823
|
-
</div>
|
|
824
|
-
|
|
825
|
-
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
|
826
|
-
<button @click="showExistModal=false" type="button" class="inline-flex gap-2 items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors border rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-100 focus:ring-offset-2">
|
|
827
|
-
<div>Dismiss</div>
|
|
828
|
-
</button>
|
|
829
|
-
<button
|
|
830
|
-
@click="uploadFiles(true)"
|
|
831
|
-
:disabled="uploaderLoading"
|
|
832
|
-
type="button"
|
|
833
|
-
class="inline-flex items-center gap-2 justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
834
|
-
>
|
|
835
|
-
Upload
|
|
836
|
-
</button>
|
|
837
|
-
</div>
|
|
838
|
-
</div>
|
|
839
|
-
|
|
840
|
-
<div v-show="checkerFailedModal" class="absolute inset-0 bg-white py-6 px-7 flex flex-col">
|
|
841
|
-
<div class="flex items-center justify-between pb-3">
|
|
842
|
-
<h3 class="text-lg font-semibold">Checker failed</h3>
|
|
843
|
-
<button @click="checkerFailedModal=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
|
|
844
|
-
<svg class="w-5 h-5" 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="M6 18L18 6M6 6l12 12" /></svg>
|
|
845
|
-
</button>
|
|
846
|
-
</div>
|
|
847
|
-
|
|
848
|
-
<div class="flex-1">
|
|
849
|
-
<p class="text-gray-800">We couldn't complete your file upload due to a network error. This might be due to a temporary connection issue.
|
|
850
|
-
|
|
851
|
-
</p>
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
</div>
|
|
855
|
-
|
|
856
|
-
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
|
857
|
-
<button @click="checkerFailedModal=false" type="button" class="inline-flex gap-2 items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors border rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-100 focus:ring-offset-2">
|
|
858
|
-
<div>Dismiss</div>
|
|
859
|
-
</button>
|
|
860
|
-
<button
|
|
861
|
-
@click="uploadFiles(false), (checkerFailedModal = false)"
|
|
862
|
-
:disabled="uploaderLoading"
|
|
863
|
-
type="button"
|
|
864
|
-
class="inline-flex items-center gap-2 justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
865
|
-
>
|
|
866
|
-
Retry
|
|
867
|
-
</button>
|
|
868
|
-
</div>
|
|
869
|
-
</div>
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
792
|
</div>
|
|
874
793
|
</transition>
|
|
875
794
|
</div>
|
|
876
795
|
</transition>
|
|
877
796
|
</div>
|
|
797
|
+
|
|
798
|
+
<!-- Upload job window (Google Drive style) -->
|
|
799
|
+
<div v-if="uploadJobs.length" 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
|
+
<!-- Header -->
|
|
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="uploadsInProgress > 0">Uploading {{ uploadsInProgress }} item{{ uploadsInProgress > 1 ? 's' : '' }}</template>
|
|
804
|
+
<template v-else>{{ uploadJobs.length }} upload{{ uploadJobs.length > 1 ? 's' : '' }} complete</template>
|
|
805
|
+
</div>
|
|
806
|
+
<div class="flex items-center gap-2">
|
|
807
|
+
<button @click.stop="jobWindowCollapsed = !jobWindowCollapsed" class="text-white/70 hover:text-white">
|
|
808
|
+
<svg :class="{ 'rotate-180': jobWindowCollapsed }" class="w-5 h-5 transition-transform" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" /></svg>
|
|
809
|
+
</button>
|
|
810
|
+
<button v-if="uploadsInProgress === 0" @click.stop="uploadJobs = []" class="text-white/70 hover:text-white">
|
|
811
|
+
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
|
|
812
|
+
</button>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
<!-- File list -->
|
|
816
|
+
<div v-show="!jobWindowCollapsed" class="max-h-64 overflow-y-auto divide-y divide-neutral-100">
|
|
817
|
+
<div v-for="job in uploadJobs" :key="job.id" class="flex items-center gap-3 px-4 py-2.5">
|
|
818
|
+
<div class="shrink-0">
|
|
819
|
+
<!-- Upload icon -->
|
|
820
|
+
<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>
|
|
821
|
+
<!-- Success icon -->
|
|
822
|
+
<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>
|
|
823
|
+
<!-- Error icon -->
|
|
824
|
+
<svg v-else-if="job.status === 'error'" class="w-5 h-5 text-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-1.72 6.97a.75.75 0 10-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 101.06 1.06L12 13.06l1.72 1.72a.75.75 0 101.06-1.06L13.06 12l1.72-1.72a.75.75 0 10-1.06-1.06L12 10.94l-1.72-1.72z" clip-rule="evenodd" /></svg>
|
|
825
|
+
</div>
|
|
826
|
+
<div class="flex-1 min-w-0">
|
|
827
|
+
<div class="text-sm truncate" v-text="job.name"></div>
|
|
828
|
+
<!-- Progress bar -->
|
|
829
|
+
<div v-if="job.status === 'uploading'" class="mt-1 h-1 bg-neutral-100 rounded-full overflow-hidden">
|
|
830
|
+
<div class="h-full bg-blue-500 rounded-full transition-all duration-300" :style="{ width: job.progress + '%' }"></div>
|
|
831
|
+
</div>
|
|
832
|
+
</div>
|
|
833
|
+
<div class="shrink-0 text-xs text-neutral-400">
|
|
834
|
+
<span v-if="job.status === 'uploading'">{{ Math.round(job.progress) }}%</span>
|
|
835
|
+
</div>
|
|
836
|
+
</div>
|
|
837
|
+
</div>
|
|
838
|
+
</div>
|
|
878
839
|
</teleport>
|
|
879
840
|
</div>
|
|
880
841
|
|
|
@@ -993,18 +954,18 @@ export async function viewer(fields, e) {
|
|
|
993
954
|
folders: [],
|
|
994
955
|
files: [],
|
|
995
956
|
view: fields.default_view_type || 'gallery',
|
|
996
|
-
uploadModal: false,
|
|
997
|
-
uploaderLoading: false,
|
|
998
|
-
checkingFiles: false,
|
|
999
957
|
loadingSearch: false,
|
|
1000
958
|
fetcher,
|
|
1001
959
|
formatBytes,
|
|
1002
|
-
initUploader: upload,
|
|
1003
960
|
swiper: null,
|
|
1004
961
|
existingTags: '',
|
|
1005
962
|
showSearchPopper: false,
|
|
1006
963
|
isOverDropZone: false,
|
|
1007
964
|
removeChipCount: 0,
|
|
965
|
+
// Upload job window state
|
|
966
|
+
uploadJobs: [],
|
|
967
|
+
jobWindowCollapsed: false,
|
|
968
|
+
pendingFiles: [],
|
|
1008
969
|
searchOptions: [
|
|
1009
970
|
{
|
|
1010
971
|
label: 'Filename',
|
|
@@ -1036,10 +997,7 @@ export async function viewer(fields, e) {
|
|
|
1036
997
|
existingFiles: {},
|
|
1037
998
|
allLoading: false,
|
|
1038
999
|
showExistModal: false,
|
|
1039
|
-
checkerFailedModal: false,
|
|
1040
1000
|
overrideAction: 'replace',
|
|
1041
|
-
pond: null,
|
|
1042
|
-
processFiles: null,
|
|
1043
1001
|
};
|
|
1044
1002
|
},
|
|
1045
1003
|
methods: {
|
|
@@ -1086,67 +1044,139 @@ export async function viewer(fields, e) {
|
|
|
1086
1044
|
refreshFsLightbox();
|
|
1087
1045
|
});
|
|
1088
1046
|
},
|
|
1089
|
-
|
|
1090
|
-
|
|
1047
|
+
onFilesSelected(event) {
|
|
1048
|
+
const files = Array.from(event.target.files);
|
|
1049
|
+
if (!files.length) return;
|
|
1050
|
+
this.pendingFiles = files;
|
|
1051
|
+
// Reset the input so re-selecting the same files works
|
|
1052
|
+
event.target.value = '';
|
|
1053
|
+
this.checkAndUpload();
|
|
1054
|
+
},
|
|
1055
|
+
checkAndUpload() {
|
|
1056
|
+
this.existingFiles = {};
|
|
1057
|
+
var file_paths = this.pendingFiles.map((f) => '/' + f.name);
|
|
1058
|
+
|
|
1059
|
+
this.fetcher('check_drive_files_workspace', {
|
|
1060
|
+
file_paths,
|
|
1061
|
+
type: 'file',
|
|
1062
|
+
})
|
|
1063
|
+
.then(() => {
|
|
1064
|
+
// No conflicts — upload all
|
|
1065
|
+
this.startUpload(false);
|
|
1066
|
+
})
|
|
1067
|
+
.catch((err) => {
|
|
1068
|
+
if (err.code === -764) {
|
|
1069
|
+
(err.files || []).forEach((file, index) => {
|
|
1070
|
+
if (file.code === -764) {
|
|
1071
|
+
this.existingFiles[this.pendingFiles[index].name] = file.duplicates;
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
if (Object.keys(this.existingFiles).length) {
|
|
1076
|
+
this.showExistModal = true;
|
|
1077
|
+
} else {
|
|
1078
|
+
this.startUpload(false);
|
|
1079
|
+
}
|
|
1080
|
+
} else {
|
|
1081
|
+
// Network error — upload anyway, server will handle it
|
|
1082
|
+
this.startUpload(false);
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
},
|
|
1086
|
+
startUpload(isAfterConsent) {
|
|
1087
|
+
if (isAfterConsent) {
|
|
1091
1088
|
this.showExistModal = false;
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
const filesToUpload = this.pendingFiles;
|
|
1092
|
+
this.pendingFiles = [];
|
|
1093
|
+
this.jobWindowCollapsed = false;
|
|
1094
|
+
|
|
1095
|
+
filesToUpload.forEach((file) => {
|
|
1096
|
+
const jobId = crypto.randomUUID();
|
|
1097
|
+
this.uploadJobs.push({
|
|
1098
|
+
id: jobId,
|
|
1099
|
+
name: file.name,
|
|
1100
|
+
progress: 0,
|
|
1101
|
+
status: 'uploading',
|
|
1097
1102
|
});
|
|
1103
|
+
this.uploadSingleFile(file, jobId);
|
|
1104
|
+
});
|
|
1105
|
+
},
|
|
1106
|
+
uploadSingleFile(file, jobId) {
|
|
1107
|
+
let formData = new FormData();
|
|
1108
|
+
formData.append('file', file, file.name);
|
|
1109
|
+
|
|
1110
|
+
const { app_id: appId, gtp_token, app_token, api_key } = e._session;
|
|
1111
|
+
formData.append('app_id_reference', APP_OBJ?.[appId]?.app_id_reference);
|
|
1112
|
+
formData.append('app_id', appId);
|
|
1113
|
+
formData.append('gtp_token', gtp_token);
|
|
1114
|
+
formData.append('app_token', app_token);
|
|
1115
|
+
formData.append('drive_type', 'workspace');
|
|
1116
|
+
if (api_key) formData.append('api_key', api_key);
|
|
1117
|
+
|
|
1118
|
+
if (fields.file_upload_folder) formData.append('folder', fields.file_upload_folder);
|
|
1119
|
+
if (fields.public_file) formData.append('make_public', fields.public_file);
|
|
1120
|
+
|
|
1121
|
+
let tags = fields.assign_file_tags || [];
|
|
1122
|
+
let file_tags = [];
|
|
1123
|
+
if (fields.auto_tag_generator) {
|
|
1124
|
+
let identifier = fields.auto_tag_identifier || ' ';
|
|
1125
|
+
const filename = file.name.split('.').slice(0, -1).join('.');
|
|
1126
|
+
file_tags = filename.split(identifier);
|
|
1127
|
+
}
|
|
1128
|
+
formData.append('tags', [...tags, ...file_tags]);
|
|
1129
|
+
|
|
1130
|
+
const request = new XMLHttpRequest();
|
|
1098
1131
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1132
|
+
let _domain = e._session.domain;
|
|
1133
|
+
if (e._session.is_deployment) {
|
|
1134
|
+
_domain = e._session.opt.regional_server === 'dev.xuda.ai' ? 'dev.xuda.ai' : 'xuda.ai';
|
|
1135
|
+
}
|
|
1103
1136
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1137
|
+
if (this.overrideAction === 'replace' && file.name in this.existingFiles) {
|
|
1138
|
+
formData.append('file_path', '/' + file.name);
|
|
1139
|
+
formData.append('file_name', file.name);
|
|
1140
|
+
request.open('POST', 'https://' + _domain + '/cpi/update_drive_file_workspace');
|
|
1106
1141
|
} else {
|
|
1107
|
-
|
|
1108
|
-
|
|
1142
|
+
request.open('POST', 'https://' + _domain + '/cpi/upload_drive_file_workspace');
|
|
1143
|
+
}
|
|
1109
1144
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1145
|
+
request.setRequestHeader('xu-gtp-token', gtp_token);
|
|
1146
|
+
request.setRequestHeader('xu-app-token', app_token);
|
|
1112
1147
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
this.uploaderLoading = true;
|
|
1148
|
+
request.upload.onprogress = (ev) => {
|
|
1149
|
+
if (ev.lengthComputable) {
|
|
1150
|
+
const job = this.uploadJobs.find((j) => j.id === jobId);
|
|
1151
|
+
if (job) job.progress = (ev.loaded / ev.total) * 100;
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1120
1154
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
this.checkerFailedModal = true;
|
|
1147
|
-
}
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1155
|
+
request.onload = () => {
|
|
1156
|
+
const job = this.uploadJobs.find((j) => j.id === jobId);
|
|
1157
|
+
try {
|
|
1158
|
+
const res = JSON.parse(request.responseText);
|
|
1159
|
+
if (request.status >= 200 && request.status < 300 && res.code > 0) {
|
|
1160
|
+
if (job) { job.status = 'done'; job.progress = 100; }
|
|
1161
|
+
} else {
|
|
1162
|
+
if (job) job.status = 'error';
|
|
1163
|
+
}
|
|
1164
|
+
} catch (_e) {
|
|
1165
|
+
if (job) job.status = 'error';
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// If all jobs done, refresh directory
|
|
1169
|
+
if (this.uploadsInProgress === 0) {
|
|
1170
|
+
this.refreshDirectory(false, true);
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
request.onerror = () => {
|
|
1175
|
+
const job = this.uploadJobs.find((j) => j.id === jobId);
|
|
1176
|
+
if (job) job.status = 'error';
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
request.send(formData);
|
|
1150
1180
|
},
|
|
1151
1181
|
|
|
1152
1182
|
removeLastSearch($event) {
|
|
@@ -1178,10 +1208,10 @@ export async function viewer(fields, e) {
|
|
|
1178
1208
|
moment,
|
|
1179
1209
|
},
|
|
1180
1210
|
mounted() {
|
|
1181
|
-
var onDrop = (
|
|
1211
|
+
var onDrop = (droppedFiles) => {
|
|
1182
1212
|
if (this.view === 'slider') return;
|
|
1183
|
-
this.
|
|
1184
|
-
this.
|
|
1213
|
+
this.pendingFiles = Array.from(droppedFiles);
|
|
1214
|
+
this.checkAndUpload();
|
|
1185
1215
|
};
|
|
1186
1216
|
|
|
1187
1217
|
const { isOverDropZone } = useDropZone(this.$refs.dropZoneRef, {
|
|
@@ -1191,6 +1221,21 @@ export async function viewer(fields, e) {
|
|
|
1191
1221
|
this.isOverDropZone = isOverDropZone;
|
|
1192
1222
|
},
|
|
1193
1223
|
computed: {
|
|
1224
|
+
uploadsInProgress() {
|
|
1225
|
+
return this.uploadJobs.filter((j) => j.status === 'uploading').length;
|
|
1226
|
+
},
|
|
1227
|
+
acceptTypes() {
|
|
1228
|
+
if (fields.file_upload_mime_type_preset) {
|
|
1229
|
+
switch (fields.file_upload_mime_type_preset) {
|
|
1230
|
+
case 'image': return 'image/*';
|
|
1231
|
+
case 'video': return 'video/*';
|
|
1232
|
+
case 'audio': return 'audio/*';
|
|
1233
|
+
default: return 'image/*';
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
if (fields.file_upload_custom_mime_types) return fields.file_upload_custom_mime_types;
|
|
1237
|
+
return null;
|
|
1238
|
+
},
|
|
1194
1239
|
searchTags() {
|
|
1195
1240
|
return this.opts.search_string.split(' ').filter((e) => e.includes(':'));
|
|
1196
1241
|
},
|
|
@@ -1269,34 +1314,6 @@ export async function viewer(fields, e) {
|
|
|
1269
1314
|
async created() {
|
|
1270
1315
|
this.refreshDirectory();
|
|
1271
1316
|
|
|
1272
|
-
this.$nextTick(async () => {
|
|
1273
|
-
// debugger;
|
|
1274
|
-
var { pond, processFiles } = await this.initUploader({ ...fields, instant_file_upload: 'N' }, { ...e, $containerP: $('#imageUploaderComponent') });
|
|
1275
|
-
|
|
1276
|
-
this.pond = pond;
|
|
1277
|
-
this.processFiles = processFiles;
|
|
1278
|
-
|
|
1279
|
-
// Avoid per-file DOM removal — let processfiles handle cleanup in bulk
|
|
1280
|
-
this.pond.on('processfile', (e, { id }) => {
|
|
1281
|
-
// if (!e?.type !== 'error') {
|
|
1282
|
-
// this.pond.removeFiles(id);
|
|
1283
|
-
// }
|
|
1284
|
-
|
|
1285
|
-
// if (!this.pond.getFiles().length) {
|
|
1286
|
-
// this.uploaderLoading = false;
|
|
1287
|
-
// this.uploadModal = false;
|
|
1288
|
-
// this.pond.removeFiles();
|
|
1289
|
-
// }
|
|
1290
|
-
});
|
|
1291
|
-
|
|
1292
|
-
this.pond.on('processfiles', () => {
|
|
1293
|
-
this.uploaderLoading = false;
|
|
1294
|
-
this.uploadModal = false;
|
|
1295
|
-
this.pond.removeFiles();
|
|
1296
|
-
this.refreshDirectory(false, true);
|
|
1297
|
-
});
|
|
1298
|
-
});
|
|
1299
|
-
|
|
1300
1317
|
this.$watch('opts', (value) => {
|
|
1301
1318
|
this.refreshDirectory();
|
|
1302
1319
|
});
|
package/tests/index.html
CHANGED
|
@@ -1,57 +1,53 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
</script>
|
|
55
|
-
</body>
|
|
56
|
-
|
|
57
|
-
</html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>AG Grid Plugin Tester</title>
|
|
7
|
+
|
|
8
|
+
<script src="https://master.xuda.ai/dist/runtime/js/xuda-runtime-slim.js"></script>
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
html,
|
|
12
|
+
body {
|
|
13
|
+
height: 100%;
|
|
14
|
+
width: 100%;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
|
|
18
|
+
<link rel="stylesheet" href="./style.css" />
|
|
19
|
+
</head>
|
|
20
|
+
|
|
21
|
+
<body>
|
|
22
|
+
<div id="tester"></div>
|
|
23
|
+
|
|
24
|
+
<script type="module">
|
|
25
|
+
import * as plugin from '../src/runtime.mjs';
|
|
26
|
+
|
|
27
|
+
var xu = new xuda($('#tester')[0], { domain: 'master.xuda.io' });
|
|
28
|
+
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
const SESSION_ID = Object.keys(SESSION_OBJ)[0];
|
|
31
|
+
var _session = {
|
|
32
|
+
...SESSION_OBJ[SESSION_ID],
|
|
33
|
+
prog_id: '5b1_cmp_189d0a5c99e2',
|
|
34
|
+
api_key: 'pk_e3c62dd6084d61dde054eb9ddb21bd21',
|
|
35
|
+
DS_GLB: {
|
|
36
|
+
1: { prog_id: '5b1_cmp_189d0a5c99e2', rows_found: 0, data_feed: { rows: [] } },
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const e = {
|
|
41
|
+
SESSION_ID,
|
|
42
|
+
$containerP: $('#embed_' + SESSION_ID),
|
|
43
|
+
dsP: 1,
|
|
44
|
+
plugin_name: '@xuda.io/xuda-widget-plugin-xuda-drive',
|
|
45
|
+
_session,
|
|
46
|
+
SESSION_OBJ,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
plugin.viewer({}, e);
|
|
50
|
+
}, 2000);
|
|
51
|
+
</script>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|