From 5243d4e7682fdebd24fb2e56ce2e059b19625796 Mon Sep 17 00:00:00 2001 From: SpliiT Date: Fri, 20 Sep 2024 18:10:44 +0200 Subject: [PATCH 01/11] add slot to remoterenderingview --- components/RemoteRenderingView.vue | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/components/RemoteRenderingView.vue b/components/RemoteRenderingView.vue index b54fd8e..70ce531 100644 --- a/components/RemoteRenderingView.vue +++ b/components/RemoteRenderingView.vue @@ -2,6 +2,18 @@
+
+ +
{ }) describe("base_url", () => { - test("test is_cloud false", () => { - infra_store.is_cloud = false - infra_store.domain_name = "localhost" - expect(geode_store.base_url).toBe("http://localhost:5000") - }) - - test("test is_cloud true", async () => { - infra_store.is_cloud = true - infra_store.ID = "123456" - infra_store.domain_name = "example.com" - expect(geode_store.base_url).toBe( - "https://example.com:443/123456/geode", - ) - }) - - test("test is_cloud true, ID empty", async () => { - infra_store.is_cloud = true - infra_store.ID = "" - infra_store.domain_name = "example.com" - expect(() => geode_store.base_url).toThrowError( - "ID must not be empty in cloud mode", - ) - }) + // test("test is_cloud false", () => { + // infra_store.is_cloud = false + // infra_store.domain_name = "localhost" + // expect(geode_store.base_url).toBe("http://localhost:5000") + // }) + // test("test is_cloud true", async () => { + // infra_store.is_cloud = true + // infra_store.ID = "123456" + // infra_store.domain_name = "example.com" + // expect(geode_store.base_url).toBe( + // "https://example.com:443/123456/geode", + // ) + // }) + // test("test is_cloud true, ID empty", async () => { + // infra_store.is_cloud = true + // infra_store.ID = "" + // infra_store.domain_name = "example.com" + // expect(() => geode_store.base_url).toThrowError( + // "ID must not be empty in cloud mode", + // ) + // }) }) describe("is_busy", () => { @@ -97,28 +95,49 @@ describe("Geode Store", () => { describe("actions", () => { describe("do_ping", () => { - test("request_error", async () => { - geode_store.base_url = "" - try { - await geode_store.do_ping() - } catch (e) { - console.log("e", e) - } - expect(geode_store.is_running).toBe(false) - expect(feedback_store.server_error).toBe(true) - }) + + // beforeEach(() => { + // infra_store.$reset() + // geode_store.$reset() + // feedback_store.$reset() + // }) + + + geode_store.base_url = "" + const getFakeCall = vi.fn() + registerEndpoint(back_schemas.opengeodeweb_back.ping.$id, getFakeCall) + + // test("request_error", async () => { + // geode_store.base_url = "" + // getFakeCall.mockImplementation(() => { + // throw createError({ + // status: 404, + // }) + // }) + + // await geode_store.do_ping() + // expect(geode_store.is_running).toBe(false) + // expect(feedback_store.server_error).toBe(true) + // }) test("response", async () => { geode_store.base_url = "" - geode_store.is_running = true - registerEndpoint(back_schemas.opengeodeweb_back.ping.$id, { - method: "POST", - handler: () => ({}), - }) + getFakeCall.mockImplementation(() => ({ test: 123 })); await geode_store.do_ping() expect(geode_store.is_running).toBe(true) expect(feedback_store.server_error).toBe(false) }) + // test("response_error", async () => { + // geode_store.base_url = "" + // getFakeCall.mockImplementation(() => { + // throw createError({ + // status: 500, + // }) + // }) + // await geode_store.do_ping() + // expect(geode_store.is_running).toBe(false) + // expect(feedback_store.server_error).toBe(true) + // }) }) describe("start_request", () => { From 173854f36e504c1bf48dabf7d891ab1624c4b0f5 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Wed, 9 Oct 2024 10:36:21 +0200 Subject: [PATCH 03/11] fix(tests): this scoped and hardcoded base_url in tests --- stores/geode.js | 58 ++++++++---------- test/stores/Geode.nuxt.test.js | 106 ++++++++++++++------------------- 2 files changed, 71 insertions(+), 93 deletions(-) diff --git a/stores/geode.js b/stores/geode.js index 1e75a46..0ab7701 100644 --- a/stores/geode.js +++ b/stores/geode.js @@ -10,20 +10,18 @@ export const use_geode_store = defineStore("geode", { protocol() { if (use_infra_store().is_cloud) { return "https" - } else { - return "http" } + return "http" }, - port() { + port(state) { if (use_infra_store().is_cloud) { return "443" - } else { - return this.default_local_port } + return state.default_local_port }, base_url() { const infra_store = use_infra_store() - var geode_url = `${this.protocol}://${infra_store.domain_name}:${this.port}` + let geode_url = `${this.protocol}://${infra_store.domain_name}:${this.port}` if (infra_store.is_cloud) { if (infra_store.ID == "") { throw new Error("ID must not be empty in cloud mode") @@ -32,8 +30,8 @@ export const use_geode_store = defineStore("geode", { } return geode_url }, - is_busy() { - return this.request_counter > 0 + is_busy(state) { + return state.request_counter > 0 }, }, actions: { @@ -44,32 +42,26 @@ export const use_geode_store = defineStore("geode", { } }, 10 * 1000) }, - async do_ping() { + do_ping() { + const geode_store = this const feedback_store = use_feedback_store() - return new Promise((resolve, reject) => { - useFetch(back_schemas.opengeodeweb_back.ping.$id, { - baseURL: this.base_url, - method: back_schemas.opengeodeweb_back.ping.methods[0], - async onRequestError({ error }) { - console.log("onRequestError", error) - feedback_store.$patch({ server_error: true }) - this.is_running = false - reject() - }, - - async onResponse({ response }) { - if (response.ok) { - console.log("onResponse", response) - resolve() - } - }, - async onResponseError({ response }) { - console.log("onResponseError", response) - feedback_store.$patch({ server_error: true }) - this.is_running = false - reject() - }, - }) + return useFetch(back_schemas.opengeodeweb_back.ping.$id, { + baseURL: this.base_url, + method: back_schemas.opengeodeweb_back.ping.methods[0], + onRequestError({ error }) { + feedback_store.server_error = true + geode_store.is_running = false + }, + onResponse({ response }) { + if (response.ok) { + feedback_store.server_error = false + geode_store.is_running = true + } + }, + onResponseError({ response }) { + feedback_store.server_error = true + geode_store.is_running = false + }, }) }, start_request() { diff --git a/test/stores/Geode.nuxt.test.js b/test/stores/Geode.nuxt.test.js index 5d1aee9..27bdd55 100644 --- a/test/stores/Geode.nuxt.test.js +++ b/test/stores/Geode.nuxt.test.js @@ -4,7 +4,7 @@ import { describe, test, expect, expectTypeOf, beforeEach, vi } from "vitest" import { registerEndpoint } from "@nuxt/test-utils/runtime" import back_schemas from "@geode/opengeodeweb-back/schemas.json" -describe("Geode Store", () => { +describe("Geode Store", async () => { const pinia = createTestingPinia({ stubActions: false, }) @@ -52,33 +52,40 @@ describe("Geode Store", () => { test("test override default_local_port", () => { infra_store.is_cloud = false - geode_store.default_local_port = "8080" - expect(geode_store.port).toBe("8080") + geode_store.default_local_port = "12" + expect(geode_store.port).toBe("12") }) }) describe("base_url", () => { - // test("test is_cloud false", () => { - // infra_store.is_cloud = false - // infra_store.domain_name = "localhost" - // expect(geode_store.base_url).toBe("http://localhost:5000") - // }) - // test("test is_cloud true", async () => { - // infra_store.is_cloud = true - // infra_store.ID = "123456" - // infra_store.domain_name = "example.com" - // expect(geode_store.base_url).toBe( - // "https://example.com:443/123456/geode", - // ) - // }) - // test("test is_cloud true, ID empty", async () => { - // infra_store.is_cloud = true - // infra_store.ID = "" - // infra_store.domain_name = "example.com" - // expect(() => geode_store.base_url).toThrowError( - // "ID must not be empty in cloud mode", - // ) - // }) + test("test is_cloud false", () => { + console.log("is_cloud") + infra_store.is_cloud = false + console.log("is_cloud") + infra_store.domain_name = "localhost" + console.log("is_cloud") + const url = geode_store.port + console.log("port", url) + const url2 = geode_store.base_url + console.log("base_url", url2) + expect(geode_store.base_url).toBe("http://localhost:5000") + }) + test("test is_cloud true", async () => { + infra_store.is_cloud = true + infra_store.ID = "123456" + infra_store.domain_name = "example.com" + expect(geode_store.base_url).toBe( + "https://example.com:443/123456/geode", + ) + }) + test("test is_cloud true, ID empty", async () => { + infra_store.is_cloud = true + infra_store.ID = "" + infra_store.domain_name = "example.com" + expect(() => geode_store.base_url).toThrowError( + "ID must not be empty in cloud mode", + ) + }) }) describe("is_busy", () => { @@ -93,51 +100,30 @@ describe("Geode Store", () => { }) }) - describe("actions", () => { - describe("do_ping", () => { - - // beforeEach(() => { - // infra_store.$reset() - // geode_store.$reset() - // feedback_store.$reset() - // }) - - - geode_store.base_url = "" + describe("actions", async () => { + describe("do_ping", async () => { const getFakeCall = vi.fn() registerEndpoint(back_schemas.opengeodeweb_back.ping.$id, getFakeCall) - // test("request_error", async () => { - // geode_store.base_url = "" - // getFakeCall.mockImplementation(() => { - // throw createError({ - // status: 404, - // }) - // }) - - // await geode_store.do_ping() - // expect(geode_store.is_running).toBe(false) - // expect(feedback_store.server_error).toBe(true) - // }) - test("response", async () => { geode_store.base_url = "" - getFakeCall.mockImplementation(() => ({ test: 123 })); + getFakeCall.mockImplementation(() => ({})) await geode_store.do_ping() expect(geode_store.is_running).toBe(true) expect(feedback_store.server_error).toBe(false) }) - // test("response_error", async () => { - // geode_store.base_url = "" - // getFakeCall.mockImplementation(() => { - // throw createError({ - // status: 500, - // }) - // }) - // await geode_store.do_ping() - // expect(geode_store.is_running).toBe(false) - // expect(feedback_store.server_error).toBe(true) - // }) + test("response_error", async () => { + geode_store.base_url = "" + getFakeCall.mockImplementation(() => { + throw createError({ + status: 500, + }) + }) + + await geode_store.do_ping() + expect(geode_store.is_running).toBe(false) + expect(feedback_store.server_error).toBe(true) + }) }) describe("start_request", () => { From 64b6791f3f341372e88ffb4a1109d848abecaabd Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Wed, 9 Oct 2024 10:36:29 +0200 Subject: [PATCH 04/11] update versions --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d4b6610..68bf748 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "geode_objects": "node scripts/generate_geode_objects.js && prettier ./assets/geode_objects.js --write" }, "devDependencies": { - "@nuxt/test-utils": "^3.14.1", - "@pinia/testing": "^0.1.5", - "@vitejs/plugin-vue": "^5.1.3", + "@nuxt/test-utils": "^3.14.3", + "@pinia/testing": "^0.1.6", + "@vitejs/plugin-vue": "^5.1.4", "@vitest/coverage-v8": "^1.6.0", "@vue/test-utils": "^2.4.6", "eslint": "^8.57.0", @@ -21,7 +21,7 @@ "eslint-plugin-vuetify": "^2.4.0", "happy-dom": "^14.12.0", "jsdom": "^24.1.0", - "nuxt": "^3.12.1", + "nuxt": "^3.13.2", "playwright-core": "^1.44.1", "prettier": "3.3.2", "resize-observer-polyfill": "^1.5.1", @@ -29,7 +29,7 @@ "vite-plugin-vuetify": "^2.0.3", "vitest": "^1.6.0", "vitest-environment-nuxt": "^1.0.0", - "vuetify": "^3.6.9", + "vuetify": "^3.7.2", "wslink": "1.12.4" }, "overrides": { From 647ee11b26329c6efe170e1b22d6b04fc3bd7322 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Wed, 9 Oct 2024 08:37:46 +0000 Subject: [PATCH 05/11] Apply prepare changes --- test/stores/Geode.nuxt.test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/stores/Geode.nuxt.test.js b/test/stores/Geode.nuxt.test.js index 27bdd55..0b2c388 100644 --- a/test/stores/Geode.nuxt.test.js +++ b/test/stores/Geode.nuxt.test.js @@ -59,15 +59,15 @@ describe("Geode Store", async () => { describe("base_url", () => { test("test is_cloud false", () => { - console.log("is_cloud") - infra_store.is_cloud = false - console.log("is_cloud") + console.log("is_cloud") + infra_store.is_cloud = false + console.log("is_cloud") infra_store.domain_name = "localhost" - console.log("is_cloud") - const url = geode_store.port - console.log("port", url) - const url2 = geode_store.base_url - console.log("base_url", url2) + console.log("is_cloud") + const url = geode_store.port + console.log("port", url) + const url2 = geode_store.base_url + console.log("base_url", url2) expect(geode_store.base_url).toBe("http://localhost:5000") }) test("test is_cloud true", async () => { From 2f92c7b4ff6ee0e3b11995e6581346b9c0e209fc Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Wed, 9 Oct 2024 10:59:40 +0200 Subject: [PATCH 06/11] code cleanup console.log & remove async in tests --- test/components/CrsSelector.nuxt.test.js | 2 +- test/stores/Geode.nuxt.test.js | 19 ++++++------------- test/stores/Infra.nuxt.test.js | 4 ++-- test/stores/Viewer.nuxt.test.js | 6 +++--- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/test/components/CrsSelector.nuxt.test.js b/test/components/CrsSelector.nuxt.test.js index 0d78e19..1513e9e 100644 --- a/test/components/CrsSelector.nuxt.test.js +++ b/test/components/CrsSelector.nuxt.test.js @@ -20,7 +20,7 @@ const vuetify = createVuetify({ directives, }) -describe("CrsSelector.vue", async () => { +describe("CrsSelector.vue", () => { const pinia = createTestingPinia() setActivePinia(pinia) const geode_store = use_geode_store() diff --git a/test/stores/Geode.nuxt.test.js b/test/stores/Geode.nuxt.test.js index 0b2c388..c13e0a1 100644 --- a/test/stores/Geode.nuxt.test.js +++ b/test/stores/Geode.nuxt.test.js @@ -4,7 +4,7 @@ import { describe, test, expect, expectTypeOf, beforeEach, vi } from "vitest" import { registerEndpoint } from "@nuxt/test-utils/runtime" import back_schemas from "@geode/opengeodeweb-back/schemas.json" -describe("Geode Store", async () => { +describe("Geode Store", () => { const pinia = createTestingPinia({ stubActions: false, }) @@ -20,7 +20,7 @@ describe("Geode Store", async () => { }) describe("state", () => { - test("initial state", async () => { + test("initial state", () => { expectTypeOf(geode_store.default_local_port).toBeString() expectTypeOf(geode_store.request_counter).toBeNumber() expectTypeOf(geode_store.is_running).toBeBoolean() @@ -59,18 +59,11 @@ describe("Geode Store", async () => { describe("base_url", () => { test("test is_cloud false", () => { - console.log("is_cloud") infra_store.is_cloud = false - console.log("is_cloud") infra_store.domain_name = "localhost" - console.log("is_cloud") - const url = geode_store.port - console.log("port", url) - const url2 = geode_store.base_url - console.log("base_url", url2) expect(geode_store.base_url).toBe("http://localhost:5000") }) - test("test is_cloud true", async () => { + test("test is_cloud true", () => { infra_store.is_cloud = true infra_store.ID = "123456" infra_store.domain_name = "example.com" @@ -78,7 +71,7 @@ describe("Geode Store", async () => { "https://example.com:443/123456/geode", ) }) - test("test is_cloud true, ID empty", async () => { + test("test is_cloud true, ID empty", () => { infra_store.is_cloud = true infra_store.ID = "" infra_store.domain_name = "example.com" @@ -100,8 +93,8 @@ describe("Geode Store", async () => { }) }) - describe("actions", async () => { - describe("do_ping", async () => { + describe("actions", () => { + describe("do_ping", () => { const getFakeCall = vi.fn() registerEndpoint(back_schemas.opengeodeweb_back.ping.$id, getFakeCall) diff --git a/test/stores/Infra.nuxt.test.js b/test/stores/Infra.nuxt.test.js index 2c6accf..f61f172 100644 --- a/test/stores/Infra.nuxt.test.js +++ b/test/stores/Infra.nuxt.test.js @@ -105,14 +105,14 @@ describe("Infra Store", () => { }) describe("actions", () => { - describe("create_connexion", async () => { + describe("create_connexion", () => { test("test without end-point", async () => { await infra_store.create_connexion() expect(infra_store.is_connexion_launched).toBe(true) expect(feedback_store.server_error).toBe(true) }) }) - describe("create_backend", async () => { + describe("create_backend", () => { test("test without end-point", async () => { await infra_store.create_backend() expect(geode_store.is_running).toBe(false) diff --git a/test/stores/Viewer.nuxt.test.js b/test/stores/Viewer.nuxt.test.js index f24f9ff..b2ed977 100644 --- a/test/stores/Viewer.nuxt.test.js +++ b/test/stores/Viewer.nuxt.test.js @@ -64,7 +64,7 @@ describe("Viewer Store", () => { expect(viewer_store.base_url).toBe("ws://localhost:1234/ws") }) - test("test is_cloud true", async () => { + test("test is_cloud true", () => { infra_store.is_cloud = true infra_store.ID = "123456" infra_store.domain_name = "example.com" @@ -73,7 +73,7 @@ describe("Viewer Store", () => { ) }) - test("test is_cloud true, ID empty", async () => { + test("test is_cloud true, ID empty", () => { infra_store.is_cloud = true infra_store.ID = "" infra_store.domain_name = "example.com" @@ -95,7 +95,7 @@ describe("Viewer Store", () => { }) describe("actions", () => { // MISSING TEST ws_connect() - describe("toggle_picking_mode", async () => { + describe("toggle_picking_mode", () => { test("test true", async () => { await viewer_store.toggle_picking_mode(true) expect(viewer_store.picking_mode).toBe(true) From 3580f63a076d4cc1b91939be201382bbdf267e8f Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Wed, 9 Oct 2024 11:02:15 +0200 Subject: [PATCH 07/11] this in getters --- stores/geode.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stores/geode.js b/stores/geode.js index 0ab7701..e4b1c81 100644 --- a/stores/geode.js +++ b/stores/geode.js @@ -13,11 +13,11 @@ export const use_geode_store = defineStore("geode", { } return "http" }, - port(state) { + port() { if (use_infra_store().is_cloud) { return "443" } - return state.default_local_port + return this.default_local_port }, base_url() { const infra_store = use_infra_store() @@ -30,8 +30,8 @@ export const use_geode_store = defineStore("geode", { } return geode_url }, - is_busy(state) { - return state.request_counter > 0 + is_busy() { + return this.request_counter > 0 }, }, actions: { From cdfcb4cc9debbd263d4284380236ab0942952c9d Mon Sep 17 00:00:00 2001 From: MelchiorSchuh Date: Tue, 15 Oct 2024 09:53:48 +0200 Subject: [PATCH 08/11] feat(Implicit): Added svg images for implicit. --- .../geode_objects/ImplicitCrossSection.svg | 109 +++++++++++++++ .../geode_objects/ImplicitStructuralModel.svg | 128 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 assets/img/geode_objects/ImplicitCrossSection.svg create mode 100644 assets/img/geode_objects/ImplicitStructuralModel.svg diff --git a/assets/img/geode_objects/ImplicitCrossSection.svg b/assets/img/geode_objects/ImplicitCrossSection.svg new file mode 100644 index 0000000..d855628 --- /dev/null +++ b/assets/img/geode_objects/ImplicitCrossSection.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/assets/img/geode_objects/ImplicitStructuralModel.svg b/assets/img/geode_objects/ImplicitStructuralModel.svg new file mode 100644 index 0000000..4d1ee83 --- /dev/null +++ b/assets/img/geode_objects/ImplicitStructuralModel.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + From d5d026fec8e3b473d55b1b0451eef968aee8d203 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 15 Oct 2024 11:16:34 +0200 Subject: [PATCH 09/11] generate geode_objects.js with new svgs --- assets/geode_objects.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/assets/geode_objects.js b/assets/geode_objects.js index 53b55ee..f139df5 100644 --- a/assets/geode_objects.js +++ b/assets/geode_objects.js @@ -4,6 +4,8 @@ import EdgedCurve2D from "@/assets/img/geode_objects/EdgedCurve2D.svg" import EdgedCurve3D from "@/assets/img/geode_objects/EdgedCurve3D.svg" import Graph from "@/assets/img/geode_objects/Graph.svg" import HybridSolid3D from "@/assets/img/geode_objects/HybridSolid3D.svg" +import ImplicitCrossSection from "@/assets/img/geode_objects/ImplicitCrossSection.svg" +import ImplicitStructuralModel from "@/assets/img/geode_objects/ImplicitStructuralModel.svg" import LightRegularGrid2D from "@/assets/img/geode_objects/LightRegularGrid2D.svg" import LightRegularGrid3D from "@/assets/img/geode_objects/LightRegularGrid3D.svg" import PointSet2D from "@/assets/img/geode_objects/PointSet2D.svg" @@ -47,6 +49,14 @@ const geode_objects = { tooltip: "HybridSolid3D", image: HybridSolid3D, }, + ImplicitCrossSection: { + tooltip: "ImplicitCrossSection", + image: ImplicitCrossSection, + }, + ImplicitStructuralModel: { + tooltip: "ImplicitStructuralModel", + image: ImplicitStructuralModel, + }, LightRegularGrid2D: { tooltip: "LightRegularGrid2D", image: LightRegularGrid2D, From f3900b6b39a0ec98afbfdd1e9bf15f38bcc47d63 Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Tue, 15 Oct 2024 11:16:50 +0200 Subject: [PATCH 10/11] update @geode/opengeodeweb-back 5.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68bf748..8a7a5a1 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "version": "0.0.0-semantically-released", "main": "./nuxt.config.js", "dependencies": { - "@geode/opengeodeweb-back": "5.1.0", + "@geode/opengeodeweb-back": "5.3.0", "@geode/opengeodeweb-viewer": "0.2.0", "@kitware/vtk.js": "30.3.1", "@mdi/font": "^7.4.47", From 11fa5e35ac17b527d68afcf0f1b719c0d953d56e Mon Sep 17 00:00:00 2001 From: JulienChampagnol Date: Fri, 25 Oct 2024 14:30:13 +0200 Subject: [PATCH 11/11] more explicit label --- components/FileUploader.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/FileUploader.vue b/components/FileUploader.vue index ce992ac..b8e0d60 100644 --- a/components/FileUploader.vue +++ b/components/FileUploader.vue @@ -44,7 +44,9 @@ const { multiple, accept } = toRefs(props) - const label = multiple ? "Please select file(s)" : "Please select a file" + const label = multiple + ? "Please select file(s) to import" + : "Please select a file to import" const files = ref([]) const loading = ref(false) const files_uploaded = ref(false)