From 6af3d75fc2b8ac6bd1b0580dd9c70b3fcb61f399 Mon Sep 17 00:00:00 2001 From: Julien Vignoud Date: Thu, 20 Feb 2025 11:47:13 +0100 Subject: [PATCH 1/5] webapp: create a tutorial store and install Driver.js --- package-lock.json | 7 +++++++ webapp/package.json | 1 + webapp/src/store/index.ts | 1 + webapp/src/store/tutorial.ts | 11 +++++++++++ 4 files changed, 20 insertions(+) create mode 100644 webapp/src/store/tutorial.ts diff --git a/package-lock.json b/package-lock.json index cc363e25f..11d3b0d26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6228,6 +6228,12 @@ "webidl-conversions": "^4.0.2" } }, + "node_modules/driver.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/driver.js/-/driver.js-1.3.5.tgz", + "integrity": "sha512-exkp49hXuujvTOZ3zYgySWRlEAa8/3nA8glYjtuZjmkTdsQITXivBsW1ytyhKQx3WkeYaovlnvVcLbtTaN86kA==", + "license": "MIT" + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -13848,6 +13854,7 @@ "apexcharts": "4", "cypress": "13", "d3": "7", + "driver.js": "^1.3.5", "pinia": "<2.2.3", "pinia-plugin-persistedstate-2": "2", "vee-validate": "4", diff --git a/webapp/package.json b/webapp/package.json index 8554f7b93..380cf65e1 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -17,6 +17,7 @@ "apexcharts": "4", "cypress": "13", "d3": "7", + "driver.js": "1", "pinia": "<2.2.3", "pinia-plugin-persistedstate-2": "2", "vee-validate": "4", diff --git a/webapp/src/store/index.ts b/webapp/src/store/index.ts index 6ae53d5cd..2c9123c82 100644 --- a/webapp/src/store/index.ts +++ b/webapp/src/store/index.ts @@ -4,3 +4,4 @@ export { useModelsStore } from "./models"; export { useTasksStore } from "./tasks"; export { useTrainingStore } from "./training"; export { useValidationStore } from "./validation"; +export { useTutorialStore } from "./tutorial"; diff --git a/webapp/src/store/tutorial.ts b/webapp/src/store/tutorial.ts new file mode 100644 index 000000000..604ad39aa --- /dev/null +++ b/webapp/src/store/tutorial.ts @@ -0,0 +1,11 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; + +export const useTutorialStore = defineStore("guide", () => { + const showGuide = ref(false); + + function toggleGuide() { + showGuide.value = !showGuide.value; + } + return { showGuide, toggleGuide }; +}); From aadb2b813182a9cd69ec26335e012adf3f8e2f49 Mon Sep 17 00:00:00 2001 From: Julien Vignoud Date: Thu, 20 Feb 2025 11:39:43 +0100 Subject: [PATCH 2/5] webapp: home page tutorial on sidebar --- webapp/src/assets/svg/QuestionMarkIcon.vue | 13 ++++ webapp/src/components/home/Home.vue | 84 ++++++++++++++++++++++ webapp/src/components/sidebar/SideBar.vue | 28 +++++--- 3 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 webapp/src/assets/svg/QuestionMarkIcon.vue diff --git a/webapp/src/assets/svg/QuestionMarkIcon.vue b/webapp/src/assets/svg/QuestionMarkIcon.vue new file mode 100644 index 000000000..bcf806841 --- /dev/null +++ b/webapp/src/assets/svg/QuestionMarkIcon.vue @@ -0,0 +1,13 @@ + diff --git a/webapp/src/components/home/Home.vue b/webapp/src/components/home/Home.vue index 69874db72..33021cb2a 100644 --- a/webapp/src/components/home/Home.vue +++ b/webapp/src/components/home/Home.vue @@ -41,5 +41,89 @@ import GetStarted from "@/components/home/GetStarted.vue"; import FeedbackIcon from "@/assets/svg/FeedbackIcon.vue"; import InfoIcon from "@/assets/svg/InfoIcon.vue"; +import { nextTick, watch } from "vue"; +import { useRouter } from "vue-router"; + +import { driver, type DriveStep } from "driver.js"; +import "driver.js/dist/driver.css"; + +import { useTutorialStore } from "@/store"; + const started = ref(false); +const router = useRouter(); +const tutorialStore = useTutorialStore(); + +// Create a driver object +const driverObj = driver({ + showProgress: false, +}); + +const steps: DriveStep[] = [ + { + element: "#task-icon", + popover: { + title: "Collaborate on ML Tasks", + description: + "DISCOllaboratives let users collaboratively train ML models while keeping their datasets private.", + side: "left", + align: "start", + }, + }, + { + element: "#create-icon", + popover: { + title: "Create a Collaborative ML Task", + description: + "Create a DISCOllaborative by defining an ML model and task, allowing others to join and contribute while keeping their data private.", + side: "left", + align: "start", + }, + }, + { + element: "#evaluate-icon", + popover: { + title: "Evaluate ML Models", + description: + "Test locally stored models or download models from the DISCO server to evaluate their performance.", + side: "left", + align: "start", + }, + }, + { + element: ".theme-button", + popover: { + title: "Switch Theme", + description: + "Toggle between light and dark themes for a personalized visual experience.", + side: "left", + align: "start", + }, + }, + { + element: "#help-icon", + popover: { + title: "Show help", + description: "You can access a hint at any time if something is unclear.", + side: "left", + align: "start", + }, + }, +]; + +driverObj.setSteps(steps); +driverObj.drive(); + +watch( + () => tutorialStore.showGuide, + async (_) => { + if (driverObj.isActive()) { + await driverObj.destroy(); + } + if (router.currentRoute.value.path === "/") { + driverObj.setSteps(steps); + await nextTick(); + driverObj.drive(); + } + }, +); diff --git a/webapp/src/components/sidebar/SideBar.vue b/webapp/src/components/sidebar/SideBar.vue index fe0806650..844884a7d 100644 --- a/webapp/src/components/sidebar/SideBar.vue +++ b/webapp/src/components/sidebar/SideBar.vue @@ -14,18 +14,20 @@
- + + + - + - + - + @@ -37,8 +39,12 @@ :text="currentTheme === 'light' ? 'Switch to Dark Mode' : 'Switch to Light Mode'" @click="toggleDarkMode" > - - + + + + + +
@@ -58,8 +64,12 @@ import DISCO from "@/components/simple/DISCO.vue"; import SidebarButton from "./SidebarButton.vue"; import MoonIcon from "@/assets/svg/MoonIcon.vue"; import SunIcon from "@/assets/svg/SunIcon.vue"; +import QuestionMarkIcon from "@/assets/svg/QuestionMarkIcon.vue"; -const currentTheme = ref(localStorage.getItem('theme') || 'light'); +import { useTutorialStore } from "@/store"; + +const currentTheme = ref(localStorage.getItem("theme") || "light"); +const tutorialStore = useTutorialStore(); // Apply the initial theme on mount onMounted(() => { @@ -75,5 +85,7 @@ const toggleDarkMode = () => { currentTheme.value = newTheme; }; - +const showGuide = () => { + tutorialStore.toggleGuide(); +}; From cf4c82329b5e4dab4a2f7d692b44e7157097b99c Mon Sep 17 00:00:00 2001 From: Julien Vignoud Date: Thu, 20 Feb 2025 11:40:21 +0100 Subject: [PATCH 3/5] webapp: data input and training tutorial --- .../dataset_input/DataDescription.vue | 37 ++-- .../dataset_input/FileSelection.vue | 5 +- .../LabeledImageDatasetInput/index.vue | 2 + webapp/src/components/training/Finished.vue | 30 +-- .../src/components/training/TrainingSteps.vue | 172 +++++++++++++++++- 5 files changed, 218 insertions(+), 28 deletions(-) diff --git a/webapp/src/components/dataset_input/DataDescription.vue b/webapp/src/components/dataset_input/DataDescription.vue index 45f0bc111..32b584fa1 100644 --- a/webapp/src/components/dataset_input/DataDescription.vue +++ b/webapp/src/components/dataset_input/DataDescription.vue @@ -4,18 +4,30 @@ -
- Don't have any data? You can download an example dataset here. -

+
+ Don't have any data? You can download an example dataset + here.

-

+
+
-
-
+
+
- {{ column.columnName }}: {{ column.columnData }} + {{ column.columnName }}: + {{ column.columnData }}
-
+
Error! Image not found + />
@@ -45,10 +58,10 @@ diff --git a/webapp/src/components/dataset_input/FileSelection.vue b/webapp/src/components/dataset_input/FileSelection.vue index fb521ef15..380e715fb 100644 --- a/webapp/src/components/dataset_input/FileSelection.vue +++ b/webapp/src/components/dataset_input/FileSelection.vue @@ -18,11 +18,14 @@ @dragleave="onDragLeave" @drop="async (e: DragEvent) => await dragFiles(e)" > -

+

Drag and drop the {{ fileType }} or