PluginProbe
The Innovative Form Builder – IvyForms / 1.1
The Innovative Form Builder – IvyForms v1.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / _components / dialog / IvyImportDialog.vue

IvyImportDialog.vue in The Innovative Form Builder – IvyForms 1.1, at frontend/src/views/_components/dialog/IvyImportDialog.vue

198 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <IvyDialog
3 v-model="isVisible"
4 :title="getLabel('import_forms')"
5 show-close
6 align-center
7 width="500px"
8 :z-index="10001"
9 append-to-body
10 >
11 <div
12 class="ivyforms-import-dialog ivyforms-flex ivyforms-flex-direction-column ivyforms-gap-24 ivyforms-pb-16"
13 >
14 <p class="ivyforms-import-dialog__description regular-16">
15 {{ getLabel('import_forms_instructions') }}
16 </p>
17
18 <div class="ivyforms-import-dialog__field ivyforms-flex ivyforms-flex-direction-column">
19 <label class="ivyforms-import-dialog__label medium-18">
20 {{ getLabel('choose_ivyforms_file') }}
21 </label>
22 <p class="ivyforms-import-dialog__hint regular-16">
23 {{ getLabel('maximum_file_size') }}
24 </p>
25
26 <div
27 class="ivyforms-import-dialog__file-selector ivyforms-flex ivyforms-align-items-center ivyforms-gap-12 ivyforms-mt-4"
28 >
29 <input
30 ref="fileInputRef"
31 type="file"
32 accept=".json"
33 class="ivyforms-import-dialog__file-input"
34 @change="handleFileSelect"
35 />
36
37 <IvyButtonAction priority="tertiary" type="fill" size="d" @click="triggerFileInput">
38 {{ getLabel('choose_file') }}
39 </IvyButtonAction>
40
41 <span class="ivyforms-import-dialog__file-name ivyforms-flex-1 regular-14">
42 {{ selectedFileName || getLabel('no_file_chosen') }}
43 </span>
44 </div>
45 </div>
46 </div>
47
48 <template #footer>
49 <IvyButtonAction
50 priority="success"
51 size="d"
52 type="fill"
53 :disabled="!selectedFile || isImporting"
54 @click="handleImport"
55 >
56 {{ isImporting ? getLabel('importing') : getLabel('import') }}
57 </IvyButtonAction>
58 </template>
59 </IvyDialog>
60 </template>
61
62 <script setup lang="ts">
63 import { ref, computed, watch } from 'vue'
64 import IvyDialog from '@/views/_components/dialog/IvyDialog.vue'
65 import IvyButtonAction from '@/views/_components/button/IvyButtonAction.vue'
66 import { useLabels } from '@/composables/useLabels'
67 import IvyMessage from '@/views/_components/message/ivyMessage.ts'
68
69 interface Props {
70 modelValue: boolean
71 isImporting?: boolean
72 }
73
74 const props = withDefaults(defineProps<Props>(), {
75 modelValue: false,
76 isImporting: false,
77 })
78
79 const emit = defineEmits<{
80 (e: 'update:modelValue', value: boolean): void
81 (e: 'import', file: File): void
82 (e: 'cancel'): void
83 }>()
84
85 const { getLabel } = useLabels()
86
87 // Maximum file size: 5 MB
88 const MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024
89
90 const fileInputRef = ref<HTMLInputElement | null>(null)
91 const selectedFile = ref<File | null>(null)
92 const selectedFileName = ref<string>('')
93
94 const isVisible = computed({
95 get: () => props.modelValue,
96 set: (value: boolean) => {
97 emit('update:modelValue', value)
98 if (!value) {
99 resetDialog()
100 }
101 },
102 })
103
104 const triggerFileInput = () => {
105 fileInputRef.value?.click()
106 }
107
108 const handleFileSelect = (event: Event) => {
109 const target = event.target as HTMLInputElement
110 const file = target.files?.[0]
111 if (file) {
112 // Validate file size
113 if (file.size > MAX_FILE_SIZE_BYTES) {
114 const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2)
115 const maxSizeMB = MAX_FILE_SIZE_BYTES / (1024 * 1024)
116 const errorMessage = getLabel('file_size_exceeds_limit')
117 .replace('{fileSize}', fileSizeMB)
118 .replace('{maxSize}', maxSizeMB.toString())
119 IvyMessage({
120 message: errorMessage,
121 type: 'error',
122 })
123 // Clear the file input
124 if (fileInputRef.value) {
125 fileInputRef.value.value = ''
126 }
127 return
128 }
129 selectedFile.value = file
130 selectedFileName.value = file.name
131 }
132 }
133
134 const handleImport = () => {
135 if (selectedFile.value) {
136 emit('import', selectedFile.value)
137 }
138 }
139
140 const clearFile = () => {
141 selectedFile.value = null
142 selectedFileName.value = ''
143 if (fileInputRef.value) {
144 fileInputRef.value.value = ''
145 }
146 }
147
148 const resetDialog = () => {
149 clearFile()
150 }
151
152 // Watch for external reset (e.g., after successful import)
153 watch(
154 () => props.modelValue,
155 (newValue) => {
156 if (!newValue) {
157 resetDialog()
158 }
159 },
160 )
161 </script>
162
163 <style lang="scss" scoped>
164 .ivyforms-import-dialog {
165 &__description {
166 color: var(--map-base-text--1);
167 }
168
169 &__label {
170 color: var(--map-base-text-0);
171 }
172
173 &__hint {
174 color: var(--map-base-text--1);
175 }
176
177 &__file-input {
178 display: none;
179 }
180
181 &__file-name {
182 color: var(--map-base-dusk-symbol-0);
183 overflow: hidden;
184 text-overflow: ellipsis;
185 white-space: nowrap;
186 }
187 }
188
189 // Ensure dialog is above template selection modal
190 :deep(.el-overlay) {
191 z-index: 10001 !important;
192 }
193
194 :deep(.ivyforms-dialog-wrapper) {
195 z-index: 10001 !important;
196 }
197 </style>
198