@geode/opengeodeweb-front 10.32.2-rc.1 → 10.32.2-rc.2
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/app/components/DragAndDrop.vue +48 -2
- package/app/components/DragAndDropInternal/DragAndDropInline.vue +2 -2
- package/app/components/DragAndDropInternal/DragAndDropOverlay.vue +2 -2
- package/app/components/FileUploader.vue +1 -1
- package/package.json +1 -1
- package/tests/unit/components/DragAndDrop.nuxt.test.js +89 -0
|
@@ -6,7 +6,7 @@ import DragAndDropOverlay from "./DragAndDropInternal/DragAndDropOverlay.vue";
|
|
|
6
6
|
const { multiple, accept, loading, showExtensions, fullscreen, inline, showOverlay, texts } =
|
|
7
7
|
defineProps({
|
|
8
8
|
multiple: { type: Boolean, default: false },
|
|
9
|
-
accept: { type: String, default: "" },
|
|
9
|
+
accept: { type: [String, Array], default: "" },
|
|
10
10
|
loading: { type: Boolean, default: false },
|
|
11
11
|
showExtensions: { type: Boolean, default: true },
|
|
12
12
|
fullscreen: { type: Boolean, default: false },
|
|
@@ -29,6 +29,52 @@ const isInternalDrag = ref(false);
|
|
|
29
29
|
const dragCounter = ref(0);
|
|
30
30
|
const fileInput = ref(undefined);
|
|
31
31
|
|
|
32
|
+
const WILDCARD_SUFFIX_LENGTH = 2;
|
|
33
|
+
|
|
34
|
+
function isFileAccepted(file, acceptValue) {
|
|
35
|
+
const fileName = (file.name || "").toLowerCase();
|
|
36
|
+
const fileType = (file.type || "").toLowerCase();
|
|
37
|
+
const isVext = fileName.endsWith(".vext");
|
|
38
|
+
|
|
39
|
+
if (!acceptValue) {
|
|
40
|
+
return !isVext;
|
|
41
|
+
}
|
|
42
|
+
let rules = [];
|
|
43
|
+
if (Array.isArray(acceptValue)) {
|
|
44
|
+
rules = acceptValue;
|
|
45
|
+
} else if (typeof acceptValue === "string") {
|
|
46
|
+
rules = acceptValue.split(",");
|
|
47
|
+
}
|
|
48
|
+
rules = rules.map((rule) => String(rule).trim()).filter(Boolean);
|
|
49
|
+
if (rules.length === 0) {
|
|
50
|
+
return !isVext;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return rules.some((rule) => {
|
|
54
|
+
let cleanRule = rule.toLowerCase();
|
|
55
|
+
if (!cleanRule) {
|
|
56
|
+
return !isVext;
|
|
57
|
+
}
|
|
58
|
+
if (cleanRule === "*" || cleanRule === "*.*") {
|
|
59
|
+
return !isVext;
|
|
60
|
+
}
|
|
61
|
+
if (cleanRule.startsWith("*.")) {
|
|
62
|
+
cleanRule = cleanRule.slice(1);
|
|
63
|
+
}
|
|
64
|
+
if (cleanRule.startsWith(".")) {
|
|
65
|
+
return fileName.endsWith(cleanRule);
|
|
66
|
+
}
|
|
67
|
+
if (cleanRule.includes("/")) {
|
|
68
|
+
if (cleanRule.endsWith("/*")) {
|
|
69
|
+
const typeGroup = cleanRule.slice(0, -WILDCARD_SUFFIX_LENGTH);
|
|
70
|
+
return fileType.startsWith(typeGroup);
|
|
71
|
+
}
|
|
72
|
+
return fileType === cleanRule;
|
|
73
|
+
}
|
|
74
|
+
return fileName.endsWith(`.${cleanRule}`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
32
78
|
function triggerFileDialog() {
|
|
33
79
|
fileInput.value?.click();
|
|
34
80
|
}
|
|
@@ -58,7 +104,7 @@ function onDrop(event) {
|
|
|
58
104
|
event.preventDefault();
|
|
59
105
|
dragCounter.value = 0;
|
|
60
106
|
isDragging.value = false;
|
|
61
|
-
const files = [...event.dataTransfer.files];
|
|
107
|
+
const files = [...event.dataTransfer.files].filter((file) => isFileAccepted(file, accept));
|
|
62
108
|
if (files.length > 0) {
|
|
63
109
|
emit("files-selected", files);
|
|
64
110
|
}
|
|
@@ -12,7 +12,7 @@ const { isDragging, loading, texts, accept, showExtensions } = defineProps({
|
|
|
12
12
|
loading: "Loading...",
|
|
13
13
|
}),
|
|
14
14
|
},
|
|
15
|
-
accept: { type: String, default: "" },
|
|
15
|
+
accept: { type: [String, Array], default: "" },
|
|
16
16
|
showExtensions: { type: Boolean, required: true },
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -51,7 +51,7 @@ const emit = defineEmits(["click"]);
|
|
|
51
51
|
v-if="accept && showExtensions"
|
|
52
52
|
class="text-body-2 text-white opacity-60 bg-transparent"
|
|
53
53
|
>
|
|
54
|
-
{{ accept }}
|
|
54
|
+
{{ Array.isArray(accept) ? accept.join(", ") : accept }}
|
|
55
55
|
</v-sheet>
|
|
56
56
|
</v-card-text>
|
|
57
57
|
</GlassCard>
|
|
@@ -14,7 +14,7 @@ const { isDragging, showOverlay, fullscreen, loading, texts, multiple, accept, s
|
|
|
14
14
|
}),
|
|
15
15
|
},
|
|
16
16
|
multiple: { type: Boolean, required: true },
|
|
17
|
-
accept: { type: String, default: "" },
|
|
17
|
+
accept: { type: [String, Array], default: "" },
|
|
18
18
|
showExtensions: { type: Boolean, required: true },
|
|
19
19
|
});
|
|
20
20
|
</script>
|
|
@@ -76,7 +76,7 @@ const { isDragging, showOverlay, fullscreen, loading, texts, multiple, accept, s
|
|
|
76
76
|
:size="fullscreen ? 'x-large' : 'large'"
|
|
77
77
|
class="px-8 glow-chip"
|
|
78
78
|
>
|
|
79
|
-
Accepted formats: {{ accept }}
|
|
79
|
+
Accepted formats: {{ Array.isArray(accept) ? accept.join(", ") : accept }}
|
|
80
80
|
</v-chip>
|
|
81
81
|
|
|
82
82
|
<v-sheet
|
|
@@ -8,7 +8,7 @@ const emit = defineEmits(["files_uploaded", "decrement_step", "reset_values"]);
|
|
|
8
8
|
|
|
9
9
|
const { multiple, accept, files, autoUpload, showOverlay, mini } = defineProps({
|
|
10
10
|
multiple: { type: Boolean, default: false },
|
|
11
|
-
accept: { type: String, default: "" },
|
|
11
|
+
accept: { type: [String, Array], default: "" },
|
|
12
12
|
files: { type: Array, default: () => [] },
|
|
13
13
|
autoUpload: { type: Boolean, default: true },
|
|
14
14
|
showOverlay: { type: Boolean, default: false },
|
package/package.json
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Third party imports
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
import { flushPromises } from "@vue/test-utils";
|
|
4
|
+
import { mountSuspended } from "@nuxt/test-utils/runtime";
|
|
5
|
+
|
|
6
|
+
// Local imports
|
|
7
|
+
import { setupActivePinia, vuetify } from "@ogw_tests/utils";
|
|
8
|
+
import DragAndDrop from "@ogw_front/components/DragAndDrop";
|
|
9
|
+
|
|
10
|
+
describe("drag and drop", () => {
|
|
11
|
+
const pinia = setupActivePinia();
|
|
12
|
+
|
|
13
|
+
test("ignores dropped files that do not match accept prop", async () => {
|
|
14
|
+
const wrapper = await mountSuspended(DragAndDrop, {
|
|
15
|
+
global: {
|
|
16
|
+
plugins: [vuetify, pinia],
|
|
17
|
+
},
|
|
18
|
+
props: {
|
|
19
|
+
accept: ".vtp,.vts",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const dropEvent = new Event("drop", { bubbles: true, cancelable: true });
|
|
24
|
+
Object.defineProperty(dropEvent, "dataTransfer", {
|
|
25
|
+
value: {
|
|
26
|
+
files: [new File(["extension_data"], "plugin.vext")],
|
|
27
|
+
types: ["Files"],
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
globalThis.dispatchEvent(dropEvent);
|
|
32
|
+
await flushPromises();
|
|
33
|
+
|
|
34
|
+
expect(wrapper.emitted("files-selected")).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("emits files-selected when dropped file matches accept prop", async () => {
|
|
38
|
+
const wrapper = await mountSuspended(DragAndDrop, {
|
|
39
|
+
global: {
|
|
40
|
+
plugins: [vuetify, pinia],
|
|
41
|
+
},
|
|
42
|
+
props: {
|
|
43
|
+
accept: ".vtp,.vts",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const validFile = new File(["mesh_data"], "model.vtp");
|
|
48
|
+
const dropEvent = new Event("drop", { bubbles: true, cancelable: true });
|
|
49
|
+
Object.defineProperty(dropEvent, "dataTransfer", {
|
|
50
|
+
value: {
|
|
51
|
+
files: [validFile],
|
|
52
|
+
types: ["Files"],
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
globalThis.dispatchEvent(dropEvent);
|
|
57
|
+
await flushPromises();
|
|
58
|
+
|
|
59
|
+
expect(wrapper.emitted("files-selected")).toBeDefined();
|
|
60
|
+
expect(wrapper.emitted("files-selected")[0][0]).toStrictEqual([validFile]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("accepts general files but excludes .vext when accept prop is empty", async () => {
|
|
64
|
+
const wrapper = await mountSuspended(DragAndDrop, {
|
|
65
|
+
global: {
|
|
66
|
+
plugins: [vuetify, pinia],
|
|
67
|
+
},
|
|
68
|
+
props: {
|
|
69
|
+
accept: "",
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const dataFile = new File(["any_data"], "data_file.txt");
|
|
74
|
+
const extensionFile = new File(["extension_data"], "plugin.vext");
|
|
75
|
+
const dropEvent = new Event("drop", { bubbles: true, cancelable: true });
|
|
76
|
+
Object.defineProperty(dropEvent, "dataTransfer", {
|
|
77
|
+
value: {
|
|
78
|
+
files: [dataFile, extensionFile],
|
|
79
|
+
types: ["Files"],
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
globalThis.dispatchEvent(dropEvent);
|
|
84
|
+
await flushPromises();
|
|
85
|
+
|
|
86
|
+
expect(wrapper.emitted("files-selected")).toBeDefined();
|
|
87
|
+
expect(wrapper.emitted("files-selected")[0][0]).toStrictEqual([dataFile]);
|
|
88
|
+
});
|
|
89
|
+
});
|