-
-
-
-
๐ Model Deployment
-
-
- This module allows users to deploy a machine learning model for inference.
- First, you'll have to choose a model. Then, you can select between two input methods:
-
-
-
- โ Manual Sample Entry: Fill in the required feature values manually to test a single sample.
-
-
-
- โ Test File Input: Upload a dataset file (CSV format) to run batch predictions on multiple samples.
-
-
-
+
- ๐ Learn more about this tool in our{' '}
- shell.openExternal("https://medomicslab.gitbook.io/medomics-docs/tutorials/deployment/application-module")}
- style={{ color: "#4991dfff", textDecoration: "none", cursor: "pointer" }}
- >
- documentation. ๐
-
+ Select a model and provide input data. You can either enter a single sample manually
+ or upload a CSV dataset for batch predictions.
-
-
+
+ Single sample: Fill in required feature values to test one prediction.
+
+ Dataset file: Upload a CSV to run batch predictions on multiple samples.
+
+
+ }
+ >
+
-
-
-
-
+
>
)
diff --git a/renderer/components/mainPages/evaluationLandingPage.jsx b/renderer/components/mainPages/evaluationLandingPage.jsx
index 5f19e917..19100cd0 100644
--- a/renderer/components/mainPages/evaluationLandingPage.jsx
+++ b/renderer/components/mainPages/evaluationLandingPage.jsx
@@ -1,17 +1,18 @@
import { randomUUID } from "crypto"
import Image from "next/image"
import { InputText } from "primereact/inputtext"
+import { Message } from "primereact/message"
import { useContext, useEffect, useState } from "react"
import { Button, Card, Stack } from "react-bootstrap"
import { FaAlignJustify } from "react-icons/fa"
import { MdDashboard } from "react-icons/md"
import { TbZoom } from "react-icons/tb"
import med3paLogo from "../../../resources/MED3paLogo.png"
-import myimage from "../../../resources/medomics_transparent_bg.png"
import { LayoutModelContext } from "../layout/layoutContext"
import { insertMEDDataObjectIfNotExists } from "../mongoDB/mongoDBUtils"
import { DataContext } from "../workspace/dataContext"
import { MEDDataObject } from "../workspace/NewMedDataObject"
+import ModuleLandingShell, { ModuleGuideText } from "./moduleBasics/ModuleLandingShell"
// Variable used to store some modularity information about the module
@@ -142,30 +143,33 @@ export default function EvaluationLandingPage() {
const isStartDisabled = loading || trimmedName === "" || !isValidName || hasConflict
return (
-
-
- Evaluation Module
-
-
-
-
-
-
- {/* Description of the Evaluation Module */}
-
-
- The Evaluation Module is as a quality-check workspace that tests completed AI models on fresh data,
- uses interactive dashboards to explain how they make decisions, and flags unreliable predictions to
- ensure no patient group is left behind.
-
-
-
-
- {/* Main Title and Subtitle */}
-
-
+
+
+ The Evaluation Module is a quality-check workspace that tests completed AI models on fresh data,
+ uses interactive dashboards to explain how they make decisions, and flags unreliable predictions to
+ ensure no patient group is left behind.
+
+
+ }
+ documentation={{
+ url: "https://medomicslab.gitbook.io/medomics-docs/tutorials/development/evaluation-module",
+ label: "Evaluation Module documentation",
+ }}
+ >
+
{/* Explainer Dashboard Card */}
-
+
Explainer Dashboard
@@ -193,7 +197,10 @@ export default function EvaluationLandingPage() {
{/* MED3pa Card */}
-
+
MED3pa
@@ -201,16 +208,17 @@ export default function EvaluationLandingPage() {
- Evaluate models stability and performance and flag unreliable predictions to ensure no patient group is left behind.
+
+
+ Evaluate models stability and performance and flag unreliable predictions to ensure no patient group is left behind.
+
-
-
-
-
+
)
}
diff --git a/renderer/components/mainPages/exploratory.jsx b/renderer/components/mainPages/exploratory.jsx
index 7b7a0d01..b23dffd7 100644
--- a/renderer/components/mainPages/exploratory.jsx
+++ b/renderer/components/mainPages/exploratory.jsx
@@ -1,12 +1,10 @@
-import { shell } from 'electron'
-import Image from "next/image"
import { useContext } from "react"
-import myimage from "../../../resources/medomics_transparent_bg.png"
import DTale from "../exploratory/dtale"
import SweetViz from "../exploratory/sweetViz"
import YDataProfiling from "../exploratory/yDataProfiling"
import { ErrorRequestContext } from "../generalPurpose/errorRequestContext"
import { WorkspaceContext } from "../workspace/workspaceContext"
+import ModuleLandingShell, { ModuleGuideText } from "./moduleBasics/ModuleLandingShell"
import ModulePage from "./moduleBasics/modulePage"
@@ -19,43 +17,30 @@ const ExploratoryPage = () => {
const { setError } = useContext(ErrorRequestContext)
return (
- <>
-
-
- Exploratory Module
-
-
-
-
-
๐ Exploratory Data Analysis (EDA)
-
- Before training a machine learning model, it is essential to explore and understand the dataset.
- This page provides three powerful tools, each with a unique role in data exploration:
-
-
-
โก SweetViz : Generates automated reports with dataset characteristics,
- feature distributions, correlations, and comparisons. Helps quickly detect outliers, missing values, and potential biases.
-
-
โก Y-Data Profiling : Performs a deep statistical audit to analyze feature types,
- missing values, and relationships, helping detect preprocessing issues before model training.
-
-
โก D-Tale : Provides a spreadsheet-like interactive interface for filtering,
- sorting, visualizing, and modifying data in real time.
-
-
- ๐ Learn how to use these tools in our
- shell.openExternal("https://medomicslab.gitbook.io/medomics-docs/tutorials/design/exploratory-module")}
- style={{ color: "#4991dfff", textDecoration: "none", cursor: "pointer" }}
- > documentation. ๐
-
-
-
-
-
-
-
- >
+
+
+ The Exploratory Module helps you understand your data, detect potential issues,
+ and make informed decisions for preprocessing and model selection.
+
+ SweetViz: Automated reports with distributions, correlations, and comparisons.
+ Y-Data Profiling: Deep statistical audit of feature types, missing values, and relationships.
+ D-Tale: Spreadsheet-like interface for filtering, sorting, and visualizing data in real time.
+
+ }
+ >
+
+
+
+
)
}
diff --git a/renderer/components/mainPages/extractionLandingPage.jsx b/renderer/components/mainPages/extractionLandingPage.jsx
index 0619b629..0236c939 100644
--- a/renderer/components/mainPages/extractionLandingPage.jsx
+++ b/renderer/components/mainPages/extractionLandingPage.jsx
@@ -6,8 +6,8 @@ import { FaAlignJustify, FaChartLine } from "react-icons/fa"
import { FaImage } from "react-icons/fa6"
import { LuBrain } from "react-icons/lu"
import medimlLogo from "../../../resources/MEDimlLogo.png"
-import myimage from "../../../resources/medomics_transparent_bg.png"
import { LayoutModelContext } from "../layout/layoutContext"
+import ModuleLandingShell, { ModuleGuideText } from "./moduleBasics/ModuleLandingShell"
export default function ExtractionLandingPage() {
@@ -20,114 +20,108 @@ export default function ExtractionLandingPage() {
}
return (
-
-
- Extraction Module
-
-
-
-
+
+
+ This module offers ready-made tools to pull insights from images, notes, and health tracking data,
+ while relying on the specialized MEDiml tool to extract deeper features from medical scans.
+
+
+ }
+ documentation={{
+ url: "https://medomicslab.gitbook.io/medomics-docs/tutorials/design/extraction-modules",
+ label: "Extraction Module documentation",
+ }}
+ >
+
+
- {/* Description of the Extraction Module */}
-
-
- This input module offers ready-made tools to pull insights from images, notes, and health tracking data,
- while relying on the specialized MEDiml tool to extract deeper features from medical scans.
-
-
+
+
+
+
+ MEDiml
+
+
+
+
+ Extract radiomic features from medical images and analyze your radiomics data using machine learning models.
+
+ choosePage(e, "ExtractionMEDimage")}>
+ Start Extraction
+
+
+
-
-
-
- {/* Disabled warning message */}
-
-
- {/* Main Title and Subtitle */}
-
-
- {/* MEDiml Card */}
-
-
-
- MEDiml
-
-
-
-
- Extract radiomic features from medical images and analyze your radiomics data using machine learning models.
-
- choosePage(e, "ExtractionMEDimage")}>
- Start Extraction
-
-
-
-
- {/* Text Card */}
-
-
-
- Text
-
-
-
-
- Extract Embeddings from Text Notes using a variety of models.
-
- choosePage(e, "ExtractionText")}>
- Start Extraction
-
-
-
-
-
+
+
+
+ Text
+
+
+
+
+ Extract Embeddings from Text Notes using a variety of models.
+
+ choosePage(e, "ExtractionText")}>
+ Start Extraction
+
+
+
-
-
-
-
-
- {/* Time Series Card */}
-
-
-
- Time Series
-
-
-
-
- Extract time series characteristics from physiological signals using TSFRESH and other models.
-
- choosePage(e, "ExtractionTS")}>
- Start Extraction
-
-
-
+
+
+
+
+ Time Series
+
+
+
+
+ Extract time series characteristics from physiological signals using TSFRESH and other models.
+
+ choosePage(e, "ExtractionTS")}>
+ Start Extraction
+
+
+
- {/* Image Card */}
-
-
-
- Image
-
-
-
-
- Extract Embeddings from JPG images using a variety of models from TorchXRayVision python library.
-
- choosePage(e, "ExtractionImage")}>
- Start Extraction
-
-
-
-
-
+
+
+
+ Image
+
+
+
+
+ Extract Embeddings from JPG images using a variety of models from TorchXRayVision python library.
+
+ choosePage(e, "ExtractionImage")}>
+ Start Extraction
+
+
+
-
-
+
+
)
}
diff --git a/renderer/components/mainPages/learningLandingPage.jsx b/renderer/components/mainPages/learningLandingPage.jsx
new file mode 100644
index 00000000..0e452073
--- /dev/null
+++ b/renderer/components/mainPages/learningLandingPage.jsx
@@ -0,0 +1,499 @@
+import { randomUUID } from "crypto";
+import { Button } from "primereact/button";
+import { InputText } from "primereact/inputtext";
+import { useContext, useEffect, useState } from "react";
+import { Card, Stack } from "react-bootstrap";
+import { AiOutlineExperiment } from "react-icons/ai";
+import { LuBrainCircuit } from "react-icons/lu";
+import { toast } from "react-toastify";
+import { sceneDescription as learningSceneDescription } from "../../public/setupVariables/learningNodesParams";
+import { LayoutModelContext } from "../layout/layoutContext";
+import { getCollectionData } from "../dbComponents/utils";
+import { insertMEDDataObjectIfNotExists } from "../mongoDB/mongoDBUtils";
+import { DataContext } from "../workspace/dataContext";
+import { MEDDataObject } from "../workspace/NewMedDataObject";
+import { FaPlay } from "react-icons/fa";
+import ModuleLandingShell, { ModuleGuideSteps, ModuleGuideText } from "./moduleBasics/ModuleLandingShell";
+
+
+const buildOpenItem = (id, medObject) => ({
+ index: id,
+ canMove: true,
+ isFolder: false,
+ children: medObject.childrenIDs || [],
+ data: medObject.name,
+ canRename: true,
+ type: medObject.type || "medml",
+ inWorkspace: medObject.inWorkspace ?? false,
+ path: medObject.path ?? null,
+ isLocked: medObject.isLocked ?? null,
+ usedIn: medObject.usedIn ?? null,
+});
+
+const BRAND_NAVY = "rgb(88, 131, 196)";
+const BRAND_BLUE = "rgb(171, 223, 147)";
+
+const JOURNEY_STEPS = [
+ { id: 1, label: "Readiness check", detail: "Ensure your data is ready for training using other modules" },
+ { id: 2, label: "Name your experiment", detail: "Pick a clear, unique scene name" },
+ { id: 3, label: "Build visually", detail: "Drag, drop, and connect nodes, no coding required" },
+];
+
+export default function LearningLandingPage() {
+ const [nameExt, setNameExp] = useState("");
+ const [nameML, setNameML] = useState("");
+ const [nameExpError, setNameExpError] = useState("");
+ const [nameMlError, setNameMLError] = useState("");
+ const [isExtDisabled, setIsExtDisabled] = useState(true);
+ const [isMLDisabled, setIsMLDisabled] = useState(true);
+ const [experimentList, setExperimentList] = useState([]);
+ const [loadingExt, setLoadingExp] = useState(false);
+ const [loadingML, setLoadingML] = useState(false);
+ const [pendingOpenId, setPendingOpenId] = useState(null);
+ const [scenesExpanded, setScenesExpanded] = useState(false);
+ const { dispatchLayout, setLayoutRequestQueue } = useContext(LayoutModelContext);
+ const { globalData } = useContext(DataContext);
+
+ useEffect(() => {
+ let cancelled = false;
+
+ const loadExperiments = async () => {
+ const scenes = [];
+
+ for (const id of Object.keys(globalData)) {
+ const medObject = globalData[id];
+ if (medObject.type !== "medml") continue;
+
+ let isExperiment = false;
+ const metadataId = MEDDataObject.getChildIDWithName(globalData, id, "metadata.json");
+ if (metadataId) {
+ try {
+ const jsonContent = await getCollectionData(metadataId);
+ if (jsonContent?.[0]?.isExperiment !== undefined) {
+ isExperiment = !!jsonContent[0].isExperiment;
+ }
+ } catch {
+ // Default to main scene when metadata cannot be read.
+ }
+ }
+
+ scenes.push({
+ id,
+ name: medObject.name.replace(/\.medml$/i, ""),
+ displayName: medObject.name,
+ isExperiment,
+ openItem: buildOpenItem(id, medObject),
+ });
+ }
+
+ scenes.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
+
+ if (!cancelled) {
+ setExperimentList(scenes);
+ }
+ };
+
+ loadExperiments();
+ return () => {
+ cancelled = true;
+ };
+ }, [globalData]);
+
+ useEffect(() => {
+ if (!pendingOpenId || !globalData[pendingOpenId]) return;
+
+ setLoadingExp(false);
+ setLoadingML(false);
+
+ const medObject = globalData[pendingOpenId];
+ const openItem = buildOpenItem(pendingOpenId, medObject);
+ const type = openItem.type === "medml" ? "openInLearningModule" : null;
+ if (type === null) {
+ toast.error("We couldn't open this file type. Please contact support if this persists.");
+ return;
+ }
+ dispatchLayout({ type: type, payload: openItem });
+ if (setLayoutRequestQueue) {
+ setLayoutRequestQueue((prev) => [...prev, { type: "DELETE_TAB", payload: { id: "learningLandingPage" } }]);
+ } else {
+ dispatchLayout({ type: "remove", payload: { name: "Learning Module" } });
+ }
+
+ setPendingOpenId(null);
+ }, [dispatchLayout, globalData, pendingOpenId, setLayoutRequestQueue]);
+
+ const createSceneContent = async (sceneName, isExperiment) => {
+ const setLoading = isExperiment ? setLoadingExp : setLoadingML;
+ setLoading(true);
+ const trimmedSceneName = sceneName.trim();
+
+ const sceneId = randomUUID();
+
+ let sceneFolder = new MEDDataObject({
+ id: randomUUID(),
+ name: trimmedSceneName,
+ type: "directory",
+ parentID: "EXPERIMENTS",
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ let sceneFolderId = await insertMEDDataObjectIfNotExists(sceneFolder)
+
+ if (!isExperiment) {
+ for (const folder of learningSceneDescription.externalFolders) {
+ let medObject = new MEDDataObject({
+ id: randomUUID(),
+ name: folder,
+ type: "directory",
+ parentID: sceneFolderId,
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ await insertMEDDataObjectIfNotExists(medObject)
+ }
+ }
+
+ let sceneObject = new MEDDataObject({
+ id: randomUUID(),
+ name: trimmedSceneName + ".medml",
+ type: "medml",
+ parentID: sceneFolderId,
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ let sceneObjectId = await insertMEDDataObjectIfNotExists(sceneObject)
+
+ const emptyScene = [
+ {
+ nodes: [],
+ edges: [],
+ viewport: {
+ x: 235.01823373389306,
+ y: 186.91830088750686,
+ zoom: 1.0,
+ },
+ MLType: "classification",
+ intersections: [],
+ isExperiment: isExperiment,
+ },
+ ];
+ let metadataObject = new MEDDataObject({
+ id: randomUUID(),
+ name: "metadata.json",
+ type: "json",
+ parentID: sceneObjectId,
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ await insertMEDDataObjectIfNotExists(metadataObject, null, emptyScene)
+
+ let backendMetadataObject = new MEDDataObject({
+ id: randomUUID(),
+ name: "backend_metadata.json",
+ type: "json",
+ parentID: sceneObjectId,
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ await insertMEDDataObjectIfNotExists(backendMetadataObject, null, emptyScene)
+
+ for (const folder of learningSceneDescription.internalFolders) {
+ let medObject = new MEDDataObject({
+ id: randomUUID(),
+ name: folder,
+ type: "directory",
+ parentID: sceneObjectId,
+ childrenIDs: [],
+ inWorkspace: false
+ })
+ await insertMEDDataObjectIfNotExists(medObject)
+ }
+
+ MEDDataObject.updateWorkspaceDataObject();
+ setPendingOpenId(sceneObjectId || sceneId);
+ };
+
+ const validateName = (value, existingList, extension) => {
+ const trimmedName = value.trim();
+ const isValidName = /^[A-Za-z0-9_-]+$/.test(trimmedName);
+ const existingNames = new Set(existingList);
+ const hasConflict =
+ trimmedName !== "" && (existingNames.has(trimmedName) || existingNames.has(`${trimmedName}.${extension}`));
+
+ if (trimmedName === "") return { error: "", disabled: true };
+ if (!isValidName) {
+ return { error: "Use only letters, numbers, hyphens, or underscores.", disabled: true };
+ }
+ if (hasConflict) {
+ return { error: "An experiment with this name already exists. Try a different name.", disabled: true };
+ }
+ return { error: "", disabled: false };
+ };
+
+ const experimentNames = experimentList.map((scene) => scene.displayName);
+
+ const handleOpenScene = (item) => {
+ dispatchLayout({ type: "openInLearningModule", payload: item });
+ if (setLayoutRequestQueue) {
+ setLayoutRequestQueue((prev) => [...prev, { type: "DELETE_TAB", payload: { id: "learningLandingPage" } }]);
+ } else {
+ dispatchLayout({ type: "remove", payload: { name: "Learning Module" } });
+ }
+ };
+
+ const onNameExpChange = (e) => {
+ setNameExp(e);
+ const { error, disabled } = validateName(e, experimentNames, "medml");
+ setNameExpError(error);
+ setIsExtDisabled(loadingExt || disabled);
+ };
+
+ const onNameMLChange = (e) => {
+ setNameML(e);
+ const { error, disabled } = validateName(e, experimentNames, "medml");
+ setNameMLError(error);
+ setIsMLDisabled(loadingML || disabled);
+ };
+
+ const totalExperiments = experimentList.length;
+ const isCreating = loadingExt || loadingML;
+
+ const workspaceFooter = totalExperiments === 0 ? (
+
+
No experiments yet
+
+ Name your first scene above and click Create & open to launch the visual builder.
+
+
+ ) : (
+
+ setScenesExpanded((prev) => !prev)}
+ aria-expanded={scenesExpanded}
+ aria-controls="workspace-scenes-grid"
+ >
+
+ {totalExperiments} scene{totalExperiments !== 1 ? "s" : ""} in workspace
+
+
+
+
+ {scenesExpanded && (
+
+ {experimentList.map((scene) => {
+ const accentColor = scene.isExperiment ? "#8db8ec" : "#54ebeb";
+
+ return (
+
handleOpenScene(scene.openItem)}
+ title={`${scene.name} (${scene.isExperiment ? "Experimental" : "Main"})`}
+ aria-label={`Open ${scene.name} ${scene.isExperiment ? "experimental" : "main"} scene`}
+ onMouseEnter={(e) => {
+ e.currentTarget.style.borderColor = accentColor;
+ }}
+ onMouseLeave={(e) => {
+ e.currentTarget.style.borderColor = "";
+ }}
+ >
+ {scene.isExperiment ? (
+
+ ) : (
+
+ )}
+ {scene.name}
+
+ );
+ })}
+
+ )}
+
+ );
+
+ return (
+
+
+
+
+
+
+ Start with an Experimental Scene to compare models quickly. When you're ready,
+ open a Main Scene for your full training pipeline.
+
+
+
+ >
+ }
+ footer={workspaceFooter}
+ >
+
+ {/* Experimental Scene */}
+
+
+
+
+
+ Experimental Scene
+
+
+
+
+
+ STEP 1 ยท MODEL EXPLORATION
+
+
+ Compare algorithms side-by-side on your dataset before running a full experiment.
+
+
+
+
+
+
+ onNameExpChange(e.target.value)}
+ aria-invalid={!!nameExpError}
+ aria-describedby={nameExpError ? "experimental-scene-error" : "experimental-scene-hint"}
+ disabled={isCreating}
+ />
+ .medml
+
+ {!nameExpError && (
+
+ Letters, numbers, hyphens, and underscores only.
+
+ )}
+ {nameExpError && (
+
+ {nameExpError}
+
+ )}
+
+
+ createSceneContent(nameExt, "medext")}
+ disabled={isExtDisabled || loadingML}
+ label={loadingExt ? "Creating scene..." : "Create & open scene"}
+ aria-label="Create and open experimental scene"
+ />
+
+
+
+
+ {/* Main Scene */}
+
+
+
+
+
+ Main Scene
+
+
+
+
+
+ STEP 2 ยท TRAIN & FINALIZE
+
+
+ Set up your definitive ML workflow, then train, test, tune hyperparameters, and visualize results in one
+ visual canvas.
+
+
+
+
+
+
+
+
+ onNameMLChange(e.target.value)}
+ aria-invalid={!!nameMlError}
+ aria-describedby={nameMlError ? "main-scene-error" : "main-scene-hint"}
+ disabled={isCreating}
+ />
+ .medml
+
+ {!nameMlError && (
+
+ Letters, numbers, hyphens, and underscores only.
+
+ )}
+ {nameMlError && (
+
+ {nameMlError}
+
+ )}
+
+
+ createSceneContent(nameML, "medml")}
+ disabled={isMLDisabled || loadingExt}
+ label={loadingML ? "Creating scene..." : "Create & open scene"}
+ aria-label="Create and open main learning scene"
+ />
+
+
+
+
+
+ );
+}
diff --git a/renderer/components/mainPages/medfl.jsx b/renderer/components/mainPages/medfl.jsx
index daf2b13a..d4cfebd5 100644
--- a/renderer/components/mainPages/medfl.jsx
+++ b/renderer/components/mainPages/medfl.jsx
@@ -1,13 +1,11 @@
-import React from "react"
+import MedflowWelcomePage from "./medflWelcomePage"
import ModulePage from "./moduleBasics/modulePage"
-import MEDflHelloWorldPanel from "../medfl/medflHelloWorldPanel"
const MEDflPage = ({ pageId }) => {
return (
<>
- MEDfl Module
-
+
>
)
diff --git a/renderer/components/mainPages/medflWelcomePage.jsx b/renderer/components/mainPages/medflWelcomePage.jsx
new file mode 100644
index 00000000..217dc1da
--- /dev/null
+++ b/renderer/components/mainPages/medflWelcomePage.jsx
@@ -0,0 +1,75 @@
+import Image from "next/image"
+import { Message } from "primereact/message"
+import { useContext } from "react"
+import { Button, Card, Stack } from "react-bootstrap"
+import { FaCogs, FaGlobe } from "react-icons/fa"
+import myimage from "../../../resources/medomics_transparent_bg.png"
+import { LayoutModelContext } from "../layout/layoutContext"
+import ModuleLandingShell, { ModuleGuideText } from "./moduleBasics/ModuleLandingShell"
+
+export default function MedflWelcomePage() {
+ const { dispatchLayout } = useContext(LayoutModelContext)
+
+ function choosePage(event, name) {
+ event.stopPropagation()
+ console.log(`Double clicked ${name}`, event, `open${name}Module`)
+ dispatchLayout({ type: `open${name}Module`, payload: { pageId: name } })
+ }
+
+ return (
+
+
+ MEDfl is a collaborative framework for federated learning in medicine.
+
+
+ A comprehensive package for simulating the federated learning process in the medical field,
+ featuring an intuitive user interface for seamless interaction.
+
+
+ }
+ documentation={{
+ url: "https://medfl.app",
+ label: "MEDfl's Official Website",
+ }}
+ >
+
+
+
+
+
+ Simulation FL
+
+
+
+
+ Run a full federated learning simulation locally. Perfect for testing pipelines, debugging strategies, and visualizing metrics in a controlled environment.
+
+ choosePage(e, "MEDfl")}>
+ Start Simulation
+
+
+
+
+
+
+
+ Real-World FL
+
+
+
+
+ Connect to real devices or remote servers to orchestrate a production-grade federated learning workflow with secure communication and live data.
+
+ choosePage(e, "flRwWorkflow")}>
+ Go Live
+
+
+
+
+
+ )
+}
diff --git a/renderer/pages/_app.js b/renderer/pages/_app.js
index 77aac8c0..956d5784 100644
--- a/renderer/pages/_app.js
+++ b/renderer/pages/_app.js
@@ -49,6 +49,7 @@ import "../styles/extraction/extractionTabular.css"
import "../styles/flow/reactFlow.css"
import "../styles/flow/results.css"
import "../styles/globals.css"
+import "../styles/moduleLanding.css"
import "../styles/iconSidebar.css"
import "../styles/imageContainer.css"
import "../styles/input/MEDprofiles.css"
diff --git a/renderer/styles/exploratory/exploratory.css b/renderer/styles/exploratory/exploratory.css
index c87d8640..fb1d5a84 100644
--- a/renderer/styles/exploratory/exploratory.css
+++ b/renderer/styles/exploratory/exploratory.css
@@ -1,23 +1,21 @@
-.exploratory {
+.exploratory.module-landing-shell .module-landing-content {
display: flex;
flex-direction: column;
gap: 1rem;
- width: 100%;
- padding: 1rem;
}
-.exploratory > .p-card {
+.exploratory.module-landing-shell .module-landing-content > .p-card {
box-shadow:
2px 2px 3px -1px rgb(0 0 0 / 20%),
0 1px 1px 0 rgb(0 0 0 / 14%),
0px 0px 3px 2px rgb(0 0 0 / 12%);
}
-.exploratory > .p-card .p-card-content {
+.exploratory.module-landing-shell .module-landing-content > .p-card .p-card-content {
padding: 0;
}
-.exploratory > .p-card .p-card-body {
+.exploratory.module-landing-shell .module-landing-content > .p-card .p-card-body {
padding: 1rem;
padding-top: 0.25rem;
}
diff --git a/renderer/styles/globals.css b/renderer/styles/globals.css
index 4bf9d3e1..4a54e4b9 100644
--- a/renderer/styles/globals.css
+++ b/renderer/styles/globals.css
@@ -189,6 +189,10 @@ a {
text-align: right;
}
+.text-italic {
+ font-style: italic;
+}
+
hr.solid {
border-top: 3px solid #bbb;
margin: 0 0 0.25rem 0;