@5minds/node-red-dashboard-2-processcube-dynamic-form 2.6.1 → 2.7.0-develop-86aad3-mh4xebm6

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.
@@ -80,20 +80,28 @@
80
80
  </p>
81
81
  </div>
82
82
  <div v-else-if="createComponent(field).isFileField" class="ui-dynamic-form-file-wrapper">
83
- <div v-if="getFilePreviewsForField(field.id).length > 0" class="ui-dynamic-form-image-previews">
83
+ <div v-if="getFilePreviewsForField(field.id).length > 0" class="ui-dynamic-form-file-previews">
84
84
  <h4>Current files:</h4>
85
85
  <div class="ui-dynamic-form-preview-grid">
86
86
  <div
87
87
  v-for="preview in getFilePreviewsForField(field.id)"
88
88
  :key="preview.name"
89
89
  class="ui-dynamic-form-preview-item"
90
+ @click="openFileModal(preview)"
90
91
  >
92
+ <!-- Image preview -->
91
93
  <img
94
+ v-if="preview.isImage"
92
95
  :src="preview.url"
93
96
  :alt="preview.name"
94
97
  class="ui-dynamic-form-preview-image"
95
- @click="openImageModal(preview)"
96
98
  />
99
+ <!-- File icon for non-images -->
100
+ <div v-else class="ui-dynamic-form-file-icon">
101
+ <v-icon size="48" :color="getFileIconColor(preview.type)">
102
+ {{ getFileIcon(preview.type) }}
103
+ </v-icon>
104
+ </div>
97
105
  <div class="ui-dynamic-form-preview-info">
98
106
  <span class="ui-dynamic-form-preview-name">{{ preview.name }}</span>
99
107
  <span class="ui-dynamic-form-preview-size">{{ formatFileSize(preview.size) }}</span>
@@ -169,26 +177,37 @@
169
177
  <UIDynamicFormFooterAction :actions="actions" :actionCallback="actionFn" />
170
178
  </div>
171
179
 
172
- <v-dialog v-model="imageModalOpen" max-width="800px">
173
- <v-card v-if="modalImage">
174
- <v-card-title class="headline">{{ modalImage.name }}</v-card-title>
180
+ <v-dialog v-model="fileModalOpen" max-width="800px">
181
+ <v-card v-if="modalFile">
182
+ <v-card-title class="headline">{{ modalFile.name }}</v-card-title>
175
183
  <v-card-text>
176
- <img
177
- :src="modalImage.url"
178
- :alt="modalImage.name"
179
- style="width: 100%; max-height: 70vh; object-fit: contain"
180
- />
184
+ <!-- Image preview -->
185
+ <div v-if="modalFile.isImage">
186
+ <img
187
+ :src="modalFile.url"
188
+ :alt="modalFile.name"
189
+ style="width: 100%; max-height: 70vh; object-fit: contain"
190
+ />
191
+ </div>
192
+ <!-- File icon for non-images -->
193
+ <div v-else class="ui-dynamic-form-modal-file-icon">
194
+ <v-icon size="120" :color="getFileIconColor(modalFile.type)">
195
+ {{ getFileIcon(modalFile.type) }}
196
+ </v-icon>
197
+ <p class="text-h6 mt-4">{{ getFileTypeDescription(modalFile.type) }}</p>
198
+ </div>
199
+
181
200
  <div style="margin-top: 16px">
182
- <strong>Size:</strong> {{ formatFileSize(modalImage.size) }}<br />
183
- <strong>Type:</strong> {{ modalImage.type }}
201
+ <strong>Size:</strong> {{ formatFileSize(modalFile.size) }}<br />
202
+ <strong>Type:</strong> {{ modalFile.type }}
184
203
  </div>
185
204
  </v-card-text>
186
205
  <v-card-actions>
187
- <a href="modalImage.url" :download="modalImage.name">
206
+ <a :href="modalFile.url" :download="modalFile.name">
188
207
  <v-btn variant="tonal" rounded="lg">Herunterladen</v-btn>
189
208
  </a>
190
209
  <v-spacer></v-spacer>
191
- <v-btn variant="flat" rounded="lg" @click="closeImageModal">Schließen</v-btn>
210
+ <v-btn variant="flat" rounded="lg" @click="closeFileModal">Schließen</v-btn>
192
211
  </v-card-actions>
193
212
  </v-card>
194
213
  </v-dialog>
@@ -350,8 +369,8 @@ export default {
350
369
  msg: null,
351
370
  collapsed: false,
352
371
  firstFormFieldRef: null,
353
- imageModalOpen: false,
354
- modalImage: null,
372
+ fileModalOpen: false,
373
+ modalFile: null,
355
374
  objectUrlsByField: {},
356
375
  previewCache: {},
357
376
  };
@@ -1450,6 +1469,11 @@ export default {
1450
1469
 
1451
1470
  return `data:${fileData.type};base64,${fileData.data}`;
1452
1471
  },
1472
+ generateFileDownloadUrl(fileData) {
1473
+ if (!fileData || !fileData.data || !fileData.type) return null;
1474
+
1475
+ return `data:${fileData.type};base64,${fileData.data}`;
1476
+ },
1453
1477
  getFilePreviewsForField(fieldId) {
1454
1478
  const currentData = this.formData[fieldId] || null;
1455
1479
  const cachedOriginalData = this.originalFileData[fieldId] || null;
@@ -1480,12 +1504,13 @@ export default {
1480
1504
  } else if (originalFileData) {
1481
1505
  const fileArray = Array.isArray(originalFileData) ? originalFileData : [originalFileData];
1482
1506
  previews = fileArray
1483
- .filter((file) => this.isImageFile(file))
1507
+ .filter((file) => file && file.name) // Accept all files, not just images
1484
1508
  .map((file) => ({
1485
1509
  name: file.name,
1486
- url: this.generateImagePreviewUrl(file),
1510
+ url: this.isImageFile(file) ? this.generateImagePreviewUrl(file) : this.generateFileDownloadUrl(file),
1487
1511
  size: file.size,
1488
1512
  type: file.type,
1513
+ isImage: this.isImageFile(file),
1489
1514
  }));
1490
1515
  }
1491
1516
 
@@ -1513,7 +1538,7 @@ export default {
1513
1538
  actualFile = fileItem[0];
1514
1539
  }
1515
1540
 
1516
- return actualFile && actualFile.type && actualFile.type.startsWith('image/');
1541
+ return actualFile; // Accept all files, not just images
1517
1542
  })
1518
1543
  .map((fileItem) => {
1519
1544
  let actualFile = null;
@@ -1540,6 +1565,7 @@ export default {
1540
1565
  url: url,
1541
1566
  size: actualFile.size,
1542
1567
  type: actualFile.type,
1568
+ isImage: actualFile.type && actualFile.type.startsWith('image/'),
1543
1569
  isObjectUrl: true,
1544
1570
  };
1545
1571
  })
@@ -1589,6 +1615,79 @@ export default {
1589
1615
  this.previewCache = {};
1590
1616
  }
1591
1617
  },
1618
+ getFileIcon(mimeType) {
1619
+ if (!mimeType) return 'mdi-file';
1620
+
1621
+ if (mimeType.startsWith('image/')) return 'mdi-image';
1622
+ if (mimeType === 'application/pdf') return 'mdi-file-pdf-box';
1623
+ if (mimeType.includes('word') || mimeType.includes('msword') ||
1624
+ mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
1625
+ return 'mdi-file-word';
1626
+ }
1627
+ if (mimeType.includes('excel') || mimeType.includes('spreadsheet') ||
1628
+ mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
1629
+ return 'mdi-file-excel';
1630
+ }
1631
+ if (mimeType.includes('powerpoint') || mimeType.includes('presentation') ||
1632
+ mimeType === 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
1633
+ return 'mdi-file-powerpoint';
1634
+ }
1635
+ if (mimeType === 'text/plain') return 'mdi-file-document';
1636
+ if (mimeType.includes('zip') || mimeType.includes('rar') || mimeType.includes('7z')) {
1637
+ return 'mdi-folder-zip';
1638
+ }
1639
+
1640
+ return 'mdi-file';
1641
+ },
1642
+ getFileIconColor(mimeType) {
1643
+ if (!mimeType) return 'grey';
1644
+
1645
+ if (mimeType.startsWith('image/')) return 'green';
1646
+ if (mimeType === 'application/pdf') return 'red';
1647
+ if (mimeType.includes('word') || mimeType.includes('msword') ||
1648
+ mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
1649
+ return 'blue';
1650
+ }
1651
+ if (mimeType.includes('excel') || mimeType.includes('spreadsheet') ||
1652
+ mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
1653
+ return 'green';
1654
+ }
1655
+ if (mimeType.includes('powerpoint') || mimeType.includes('presentation') ||
1656
+ mimeType === 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
1657
+ return 'orange';
1658
+ }
1659
+
1660
+ return 'grey';
1661
+ },
1662
+ getFileTypeDescription(mimeType) {
1663
+ if (!mimeType) return 'Unbekannter Dateityp';
1664
+
1665
+ if (mimeType === 'application/pdf') return 'PDF-Dokument';
1666
+ if (mimeType.includes('word') || mimeType.includes('msword') ||
1667
+ mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
1668
+ return 'Word-Dokument';
1669
+ }
1670
+ if (mimeType.includes('excel') || mimeType.includes('spreadsheet') ||
1671
+ mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
1672
+ return 'Excel-Arbeitsmappe';
1673
+ }
1674
+ if (mimeType.includes('powerpoint') || mimeType.includes('presentation') ||
1675
+ mimeType === 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
1676
+ return 'PowerPoint-Präsentation';
1677
+ }
1678
+ if (mimeType === 'text/plain') return 'Textdatei';
1679
+ if (mimeType.startsWith('image/')) return 'Bilddatei';
1680
+
1681
+ return 'Datei';
1682
+ },
1683
+ openFileModal(file) {
1684
+ this.modalFile = file;
1685
+ this.fileModalOpen = true;
1686
+ },
1687
+ closeFileModal() {
1688
+ this.fileModalOpen = false;
1689
+ this.modalFile = null;
1690
+ },
1592
1691
  },
1593
1692
  };
1594
1693
 
@@ -701,3 +701,56 @@ code {
701
701
  .ui-dynamic-form-dark .ui-dynamic-form-preview-size {
702
702
  color: #ccc;
703
703
  }
704
+
705
+ /* File icon styles for non-image files */
706
+ .ui-dynamic-form-file-icon {
707
+ display: flex;
708
+ align-items: center;
709
+ justify-content: center;
710
+ width: 100px;
711
+ height: 100px;
712
+ background-color: #f8f9fa;
713
+ border: 2px dashed #dee2e6;
714
+ border-radius: 8px;
715
+ margin-bottom: 8px;
716
+ }
717
+
718
+ .ui-dynamic-form-dark .ui-dynamic-form-file-icon {
719
+ background-color: #2d2d2d;
720
+ border-color: #555;
721
+ }
722
+
723
+ /* Modal file icon styles */
724
+ .ui-dynamic-form-modal-file-icon {
725
+ display: flex;
726
+ flex-direction: column;
727
+ align-items: center;
728
+ justify-content: center;
729
+ padding: 40px;
730
+ }
731
+
732
+ /* Update class name for general file previews */
733
+ .ui-dynamic-form-file-previews {
734
+ margin-bottom: 16px;
735
+ padding: 16px;
736
+ background-color: #f8f9fa;
737
+ border-radius: 8px;
738
+ border: 1px solid #dee2e6;
739
+ }
740
+
741
+ .ui-dynamic-form-file-previews h4 {
742
+ margin: 0 0 12px 0;
743
+ color: #495057;
744
+ font-size: 14px;
745
+ font-weight: 600;
746
+ }
747
+
748
+ /* Dark theme adjustments for file previews */
749
+ .ui-dynamic-form-dark .ui-dynamic-form-file-previews {
750
+ background-color: #2d2d2d;
751
+ border-color: #555;
752
+ }
753
+
754
+ .ui-dynamic-form-dark .ui-dynamic-form-file-previews h4 {
755
+ color: #fff;
756
+ }