From c83d5186c8185f8f3d2ce21cfc0f6162f888201b Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 23 Jan 2026 19:02:17 -0300 Subject: [PATCH 01/42] Refactor DatasetsContent to utilize useDatasets hook for improved dataset management --- DashAI/front/src/hooks/useDatasets.js | 130 ++++++++++++++++++ .../src/pages/datasets/DatasetsContent.jsx | 130 ++++-------------- 2 files changed, 156 insertions(+), 104 deletions(-) create mode 100644 DashAI/front/src/hooks/useDatasets.js diff --git a/DashAI/front/src/hooks/useDatasets.js b/DashAI/front/src/hooks/useDatasets.js new file mode 100644 index 000000000..d0f8384bd --- /dev/null +++ b/DashAI/front/src/hooks/useDatasets.js @@ -0,0 +1,130 @@ +import { useState, useCallback } from "react"; +import { + getDatasets, + deleteDataset, + getDatasetInfo, + updateDataset, +} from "../api/datasets"; +import { startJobPolling } from "../utils/jobPoller"; + +export function useDatasets({ enqueueSnackbar, t }) { + const [datasets, setDatasets] = useState([]); + const [selectedDatasetId, setSelectedDatasetId] = useState(null); + + // ---------------- helpers ---------------- + + const enrichDatasetsWithInfo = useCallback( + async (newDatasets, existingDatasets = []) => { + return Promise.all( + newDatasets.map(async (dataset) => { + const existing = existingDatasets.find((d) => d.id === dataset.id); + + if (existing) { + return { + ...dataset, + total_rows: existing.total_rows, + total_columns: existing.total_columns, + }; + } + + try { + const info = await getDatasetInfo(dataset.id); + return { + ...dataset, + total_rows: info.total_rows, + total_columns: info.total_columns, + }; + } catch (error) { + console.warn( + `Failed to fetch info for dataset ${dataset.id}`, + error, + ); + return dataset; + } + }), + ); + }, + [], + ); + + // ---------------- actions ---------------- + + const fetchDatasets = useCallback(async () => { + const data = await getDatasets(); + const enriched = await enrichDatasetsWithInfo(data, datasets); + setDatasets(enriched); + }, [datasets, enrichDatasetsWithInfo]); + + const selectDataset = (id) => { + setSelectedDatasetId(id); + }; + + const clearSelectedDataset = () => { + setSelectedDatasetId(null); + }; + + const deleteDatasetLocal = (id) => { + setDatasets((prev) => prev.filter((d) => d.id !== id)); + if (id === selectedDatasetId) { + setSelectedDatasetId(null); + } + }; + + const deleteDatasetRemote = async (id) => { + await deleteDataset(id); + }; + + const editDataset = async (id, newName) => { + const updated = await updateDataset(id, { name: newName }); + setDatasets((prev) => + prev.map((d) => (d.id === id ? { ...d, name: updated.name } : d)), + ); + + enqueueSnackbar(t("datasets:message.datasetUpdateSuccess"), { + variant: "success", + }); + }; + + const addDatasetOptimistically = (dataset) => { + setDatasets((prev) => [...prev, dataset]); + setSelectedDatasetId(dataset.id); + }; + + const startDatasetPolling = (newDataset, datasetJob) => { + startJobPolling( + datasetJob.id, + async () => { + enqueueSnackbar( + t("datasets:message.datasetCreationSuccess", { + datasetName: newDataset.name, + }), + { variant: "success" }, + ); + await fetchDatasets(); + setSelectedDatasetId(newDataset.id); + }, + async () => { + enqueueSnackbar(t("datasets:error.failedToCreateDataset"), { + variant: "error", + }); + deleteDatasetLocal(newDataset.id); + }, + ); + }; + + return { + datasets, + selectedDatasetId, + + fetchDatasets, + selectDataset, + clearSelectedDataset, + + deleteDatasetLocal, + deleteDatasetRemote, + + editDataset, + addDatasetOptimistically, + startDatasetPolling, + }; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 6b531ed85..e5a86eee1 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -30,13 +30,12 @@ import { import { enqueueDatasetJob } from "../../api/job"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; +import { useDatasets } from "../../hooks/useDatasets"; export default function DatasetsContent() { const [step, setStep] = useState(0); const [selectedOption, setSelectedOption] = useState(null); - const [selectedDatasetId, setSelectedDatasetId] = useState(null); const [selectedNotebookId, setSelectedNotebookId] = useState(0); - const [datasets, setDatasets] = useState([]); const [notebooks, setNotebooks] = useState([]); const [leftBarVisible, setLeftBarVisible] = useState(true); const [rightBarVisible, setRightBarVisible] = useState(true); @@ -51,6 +50,19 @@ export default function DatasetsContent() { const { enqueueSnackbar } = useSnackbar(); const { t } = useTranslation(["datasets", "common"]); + const { + datasets, + selectedDatasetId, + fetchDatasets, + selectDataset, + clearSelectedDataset, + deleteDatasetLocal, + deleteDatasetRemote, + editDataset, + addDatasetOptimistically, + startDatasetPolling, + } = useDatasets({ enqueueSnackbar, t }); + const goToNextStep = (option) => { if (option === "dataset" && tourContext?.run) { setStep((prevStep) => prevStep + 1); @@ -68,56 +80,6 @@ export default function DatasetsContent() { } }; - const enrichDatasetsWithInfo = async (newDatasets, existingDatasets = []) => { - const enrichedDatasets = await Promise.all( - newDatasets.map(async (dataset) => { - const existingDataset = existingDatasets.find( - (d) => d.id === dataset.id, - ); - if (existingDataset) { - return { - ...dataset, - total_rows: existingDataset.total_rows, - total_columns: existingDataset.total_columns, - }; - } - - try { - const info = await getDatasetInfo(dataset.id); - return { - ...dataset, - total_rows: info.total_rows, - total_columns: info.total_columns, - }; - } catch (error) { - console.warn( - `Failed to fetch info for dataset ${dataset.id}:`, - error, - ); - return { - ...dataset, - total_rows: dataset.total_rows, - columns: dataset.total_columns, - }; - } - }), - ); - return enrichedDatasets; - }; - - const fetchDatasets = async () => { - try { - const data = await getDatasets(); - const enrichedDatasets = await enrichDatasetsWithInfo(data, datasets); - setDatasets(enrichedDatasets); - } catch (error) { - enqueueSnackbar(t("datasets:error.failedToFetchDatasets"), { - variant: "error", - }); - console.error("Failed to fetch datasets:", error); - } - }; - const fetchNotebooks = async () => { try { const data = await getNotebooks(); @@ -143,7 +105,7 @@ export default function DatasetsContent() { }; const handleDatasetClick = (datasetId) => { - setSelectedDatasetId(datasetId); + selectDataset(datasetId); setSelectedNotebookId(null); setSelectedOption("dataset"); setRightBarContent(null); @@ -155,27 +117,22 @@ export default function DatasetsContent() { setSelectedOption("notebook"); }; - const handleDatasetDelete = (id) => { + const handleDatasetDelete = async (id) => { if (id === selectedDatasetId) { - setSelectedDatasetId(null); + clearSelectedDataset(); setStep(0); setSelectedOption(null); } - setDatasets((prevDatasets) => - prevDatasets.filter((dataset) => dataset.id !== id), - ); + deleteDatasetLocal(id); setNotebooks((prevNotebooks) => { - const filteredNotebooks = prevNotebooks.filter( - (notebook) => notebook.dataset_id !== id, - ); + const filtered = prevNotebooks.filter((n) => n.dataset_id !== id); if ( selectedNotebookId && prevNotebooks.find( - (notebook) => - notebook.id === selectedNotebookId && notebook.dataset_id === id, + (n) => n.id === selectedNotebookId && n.dataset_id === id, ) ) { setSelectedNotebookId(null); @@ -183,10 +140,10 @@ export default function DatasetsContent() { setSelectedOption(null); } - return filteredNotebooks; + return filtered; }); - deleteDataset(id); + await deleteDatasetRemote(id); }; const handleNotebookDelete = (id) => { @@ -249,21 +206,16 @@ export default function DatasetsContent() { setStep(1); }; - const handleDatasetCreated = async (newDataset, datasetJob) => { - setDatasets((prevDatasets) => [...prevDatasets, newDataset]); - setSelectedDatasetId(newDataset.id); + const handleDatasetCreated = (newDataset, datasetJob) => { + addDatasetOptimistically(newDataset); setStep(0); setSelectedOption("dataset"); setSelectedNotebookId(null); - // clear right bar content injected during dataset creation (e.g. dataloader config) setRightBarContent(null); - pollForDataset( - { datasetId: newDataset.id, datasetName: newDataset.name }, - { jobId: datasetJob.id }, - ); + startDatasetPolling(newDataset, datasetJob); }; const pollForDataset = async ( @@ -338,37 +290,7 @@ export default function DatasetsContent() { } }; - const handleEditDataset = async (id, newName) => { - try { - const updatedDataset = await updateDataset(id, { name: newName }); - setDatasets((prevDatasets) => - prevDatasets.map((dataset) => - dataset.id === id - ? { ...dataset, name: updatedDataset.name } - : dataset, - ), - ); - enqueueSnackbar(t("datasets:message.datasetUpdateSuccess"), { - variant: "success", - }); - } catch (error) { - console.error("Failed to update dataset:", error); - if (error.response?.status === 409) { - enqueueSnackbar(t("datasets:error.datasetNameExists"), { - variant: "error", - }); - } else if (error.response?.status === 422) { - enqueueSnackbar(t("datasets:error.datasetNameEmpty"), { - variant: "error", - }); - } else { - enqueueSnackbar(t("datasets:error.failedToUpdateDataset"), { - variant: "error", - }); - } - throw error; - } - }; + const handleEditDataset = (id, newName) => editDataset(id, newName); const handleEditNotebook = async (id, newName) => { try { From 251de242f3de7daacb8f9c5355c0f3c4ced9d2a8 Mon Sep 17 00:00:00 2001 From: Creylay Date: Mon, 26 Jan 2026 13:07:17 -0300 Subject: [PATCH 02/42] Refactor DatasetsContent to integrate useNotebooks hook and enhance dataset management --- DashAI/front/src/hooks/useDatasets.js | 56 +++- DashAI/front/src/hooks/useNotebooks.js | 87 +++++ .../src/pages/datasets/DatasetsContent.jsx | 300 +++++++----------- 3 files changed, 247 insertions(+), 196 deletions(-) create mode 100644 DashAI/front/src/hooks/useNotebooks.js diff --git a/DashAI/front/src/hooks/useDatasets.js b/DashAI/front/src/hooks/useDatasets.js index d0f8384bd..df406ab63 100644 --- a/DashAI/front/src/hooks/useDatasets.js +++ b/DashAI/front/src/hooks/useDatasets.js @@ -4,8 +4,10 @@ import { deleteDataset, getDatasetInfo, updateDataset, + createDataset, } from "../api/datasets"; import { startJobPolling } from "../utils/jobPoller"; +import { replace } from "formik"; export function useDatasets({ enqueueSnackbar, t }) { const [datasets, setDatasets] = useState([]); @@ -55,6 +57,10 @@ export function useDatasets({ enqueueSnackbar, t }) { setDatasets(enriched); }, [datasets, enrichDatasetsWithInfo]); + const fetchFreshDatasets = async () => { + return await getDatasets(); + }; + const selectDataset = (id) => { setSelectedDatasetId(id); }; @@ -75,14 +81,30 @@ export function useDatasets({ enqueueSnackbar, t }) { }; const editDataset = async (id, newName) => { - const updated = await updateDataset(id, { name: newName }); - setDatasets((prev) => - prev.map((d) => (d.id === id ? { ...d, name: updated.name } : d)), - ); - - enqueueSnackbar(t("datasets:message.datasetUpdateSuccess"), { - variant: "success", - }); + try { + const updated = await updateDataset(id, { name: newName }); + setDatasets((prev) => + prev.map((d) => (d.id === id ? { ...d, name: updated.name } : d)), + ); + enqueueSnackbar(t("datasets:message.datasetUpdateSuccess"), { + variant: "success", + }); + } catch (error) { + if (error.response?.status === 409) { + enqueueSnackbar(t("datasets:error.datasetNameExists"), { + variant: "error", + }); + } else if (error.response?.status === 422) { + enqueueSnackbar(t("datasets:error.datasetNameEmpty"), { + variant: "error", + }); + } else { + enqueueSnackbar(t("datasets:error.failedToUpdateDataset"), { + variant: "error", + }); + } + throw error; + } }; const addDatasetOptimistically = (dataset) => { @@ -112,11 +134,26 @@ export function useDatasets({ enqueueSnackbar, t }) { ); }; + const removeDatasetById = (id) => { + setDatasets((prev) => prev.filter((d) => d.id !== id)); + + if (id === selectedDatasetId) { + setSelectedDatasetId(null); + } + }; + + const replaceDatasets = (datasets) => { + setDatasets(datasets); + }; + return { datasets, selectedDatasetId, + createDataset, + fetchDatasets, + fetchFreshDatasets, selectDataset, clearSelectedDataset, @@ -126,5 +163,8 @@ export function useDatasets({ enqueueSnackbar, t }) { editDataset, addDatasetOptimistically, startDatasetPolling, + + removeDatasetById, + replaceDatasets, }; } diff --git a/DashAI/front/src/hooks/useNotebooks.js b/DashAI/front/src/hooks/useNotebooks.js new file mode 100644 index 000000000..f93ba4f63 --- /dev/null +++ b/DashAI/front/src/hooks/useNotebooks.js @@ -0,0 +1,87 @@ +import { useState, useCallback } from "react"; +import { getNotebooks, deleteNotebook, updateNotebook } from "../api/notebook"; + +export function useNotebooks({ enqueueSnackbar, t }) { + const [notebooks, setNotebooks] = useState([]); + const [selectedNotebookId, setSelectedNotebookId] = useState(null); + + // -------- actions -------- + + const fetchNotebooks = useCallback(async () => { + try { + const data = await getNotebooks(); + setNotebooks(data); + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToFetchNotebooks"), { + variant: "error", + }); + console.error("Failed to fetch notebooks:", error); + } + }, [enqueueSnackbar, t]); + + const selectNotebook = (id) => { + setSelectedNotebookId(id); + }; + + const clearSelectedNotebook = () => { + setSelectedNotebookId(null); + }; + + const deleteNotebookById = async (id) => { + setNotebooks((prev) => prev.filter((n) => n.id !== id)); + await deleteNotebook(id); + }; + + const editNotebook = async (id, newName) => { + try { + const updated = await updateNotebook(id, { name: newName }); + setNotebooks((prev) => + prev.map((n) => (n.id === id ? { ...n, name: updated.name } : n)), + ); + enqueueSnackbar(t("datasets:message.notebookUpdateSuccess"), { + variant: "success", + }); + } catch (error) { + if (error.response?.status === 422) { + enqueueSnackbar(t("datasets:error.notebookNameEmpty"), { + variant: "error", + }); + } else if (error.response?.status === 304) { + enqueueSnackbar(t("datasets:message.noChangesMade"), { + variant: "info", + }); + } else { + enqueueSnackbar(t("datasets:error.failedToUpdateNotebook"), { + variant: "error", + }); + } + throw error; + } + }; + + const removeNotebooksByDatasetId = (datasetId) => { + setNotebooks((prev) => prev.filter((n) => n.dataset_id !== datasetId)); + + if ( + selectedNotebookId && + notebooks.find( + (n) => n.id === selectedNotebookId && n.dataset_id === datasetId, + ) + ) { + setSelectedNotebookId(null); + } + }; + + return { + notebooks, + selectedNotebookId, + + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + deleteNotebookById, + editNotebook, + + removeNotebooksByDatasetId, + }; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index e5a86eee1..5c6d21194 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -11,32 +11,19 @@ import UploadDatasetSteps from "../../components/notebooks/datasetCreation/Uploa import UploadNotebookSteps from "../../components/notebooks/notebookCreation/UploadNotebookSteps"; import DatasetVisualization from "../../components/DatasetVisualization"; import NotebookVisualization from "../../components/notebooks/notebook/NotebookVisualization"; -import { - getDatasets, - deleteDataset, - getDatasetInfo, - updateDataset, - createDataset, -} from "../../api/datasets"; import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import { startJobPolling } from "../../utils/jobPoller"; -import { - getNotebooks, - deleteNotebook, - updateNotebook, -} from "../../api/notebook"; import { enqueueDatasetJob } from "../../api/job"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; import { useDatasets } from "../../hooks/useDatasets"; +import { useNotebooks } from "../../hooks/useNotebooks"; export default function DatasetsContent() { const [step, setStep] = useState(0); const [selectedOption, setSelectedOption] = useState(null); - const [selectedNotebookId, setSelectedNotebookId] = useState(0); - const [notebooks, setNotebooks] = useState([]); const [leftBarVisible, setLeftBarVisible] = useState(true); const [rightBarVisible, setRightBarVisible] = useState(true); const [leftBarWidth, setLeftBarWidth] = useState(20); @@ -53,7 +40,9 @@ export default function DatasetsContent() { const { datasets, selectedDatasetId, + createDataset, fetchDatasets, + fetchFreshDatasets, selectDataset, clearSelectedDataset, deleteDatasetLocal, @@ -61,34 +50,35 @@ export default function DatasetsContent() { editDataset, addDatasetOptimistically, startDatasetPolling, + removeDatasetById, + replaceDatasets, } = useDatasets({ enqueueSnackbar, t }); + const { + notebooks, + selectedNotebookId, + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + deleteNotebookById, + editNotebook, + removeNotebooksByDatasetId, + } = useNotebooks({ enqueueSnackbar, t }); + const goToNextStep = (option) => { if (option === "dataset" && tourContext?.run) { setStep((prevStep) => prevStep + 1); setSelectedOption(option); - setSelectedNotebookId(null); - setSelectedDatasetId(null); + clearSelectedNotebook(); + clearSelectedDataset(); setTimeout(() => { tourContext.nextStep(); }, 600); } else { setStep((prevStep) => prevStep + 1); setSelectedOption(option); - setSelectedNotebookId(null); - setSelectedDatasetId(null); - } - }; - - const fetchNotebooks = async () => { - try { - const data = await getNotebooks(); - setNotebooks(data); - } catch (error) { - enqueueSnackbar(t("datasets:error.failedToFetchNotebooks"), { - variant: "error", - }); - console.error("Failed to fetch notebooks:", error); + clearSelectedNotebook(); + clearSelectedDataset(); } }; @@ -98,22 +88,22 @@ export default function DatasetsContent() { }, []); const handleNewSessionButton = () => { - setSelectedDatasetId(null); - setSelectedNotebookId(null); + clearSelectedDataset(); + clearSelectedNotebook(); setStep(0); setSelectedOption(null); }; const handleDatasetClick = (datasetId) => { selectDataset(datasetId); - setSelectedNotebookId(null); + clearSelectedNotebook(); setSelectedOption("dataset"); setRightBarContent(null); }; const handleNotebookClick = (notebookId) => { - setSelectedNotebookId(notebookId); - setSelectedDatasetId(null); + selectNotebook(notebookId); + clearSelectedDataset(); setSelectedOption("notebook"); }; @@ -125,70 +115,53 @@ export default function DatasetsContent() { } deleteDatasetLocal(id); - - setNotebooks((prevNotebooks) => { - const filtered = prevNotebooks.filter((n) => n.dataset_id !== id); - - if ( - selectedNotebookId && - prevNotebooks.find( - (n) => n.id === selectedNotebookId && n.dataset_id === id, - ) - ) { - setSelectedNotebookId(null); - setStep(0); - setSelectedOption(null); - } - - return filtered; - }); + removeNotebooksByDatasetId(id); await deleteDatasetRemote(id); }; const handleNotebookDelete = (id) => { + deleteNotebookById(id); + if (id === selectedNotebookId) { - setSelectedNotebookId(null); + clearSelectedNotebook(); setStep(0); setSelectedOption(null); } - - setNotebooks((prevNotebooks) => - prevNotebooks.filter((notebook) => notebook.id !== id), - ); - - deleteNotebook(id); }; const handleAddDatasetFromNotebook = async (name) => { - if (selectedNotebook) { - try { - const data = await createDataset(name); - enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { - variant: "success", - }); - setDatasets((prev) => [...prev, data]); - setSelectedDatasetId(data.id); - setSelectedOption("dataset"); - setSelectedNotebookId(null); - - const job = await enqueueDatasetJob( - data.id, - null, - "", - {}, - selectedNotebook.id, - ); - pollForDataset( - { datasetId: data.id, datasetName: name }, - { jobId: job.id }, - ); - } catch (error) { - enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { - variant: "error", - }); - console.error("Failed to create dataset from notebook:", error); - } + if (!selectedNotebook) return; + + try { + const data = await createDataset(name); + + enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { + variant: "success", + }); + + addDatasetOptimistically(data); + + setSelectedOption("dataset"); + clearSelectedNotebook(); + + const job = await enqueueDatasetJob( + data.id, + null, + "", + {}, + selectedNotebook.id, + ); + + pollForDataset( + { datasetId: data.id, datasetName: name }, + { jobId: job.id }, + ); + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { + variant: "error", + }); + console.error("Failed to create dataset from notebook:", error); } }; @@ -196,8 +169,8 @@ export default function DatasetsContent() { await fetchNotebooks(); setStep(0); setSelectedOption("notebook"); - setSelectedNotebookId(createdNotebook.id); - setSelectedDatasetId(null); + selectNotebook(createdNotebook.id); + clearSelectedDataset(); }; const handleNewNotebookFromDataset = () => { @@ -211,118 +184,69 @@ export default function DatasetsContent() { setStep(0); setSelectedOption("dataset"); - setSelectedNotebookId(null); + clearSelectedNotebook(); // clear right bar content injected during dataset creation (e.g. dataloader config) setRightBarContent(null); startDatasetPolling(newDataset, datasetJob); }; - const pollForDataset = async ( - { datasetId, datasetName }, - { jobId }, - attempt = 1, - maxAttempts = 10, - ) => { - if (jobId && attempt === 1) { - startJobPolling( - jobId, - async (result) => { - enqueueSnackbar( - t("datasets:message.datasetCreationSuccess", { datasetName }), - { - variant: "success", - }, - ); - - try { - const freshDatasets = await getDatasets(); - const dataset = freshDatasets.find((d) => d.id === datasetId); - - if (dataset) { - const enrichedDatasets = await enrichDatasetsWithInfo( - freshDatasets, - datasets, - ); - setDatasets(enrichedDatasets); - setSelectedDatasetId(datasetId); - } else { - await fetchDatasets(); - setSelectedDatasetId(datasetId); - } - } catch (error) { - console.error( - "Error fetching datasets after job completion:", - error, + const pollForDataset = async ({ datasetId, datasetName }, { jobId }) => { + if (!jobId) return; + + startJobPolling( + jobId, + async () => { + enqueueSnackbar( + t("datasets:message.datasetCreationSuccess", { datasetName }), + { variant: "success" }, + ); + + try { + const freshDatasets = await fetchFreshDatasets(); + const dataset = freshDatasets.find((d) => d.id === datasetId); + + if (dataset) { + const enriched = await enrichDatasetsWithInfo( + freshDatasets, + datasets, ); + + replaceDatasets(enriched); + selectDataset(datasetId); + } else { await fetchDatasets(); - setSelectedDatasetId(datasetId); + selectDataset(datasetId); } - }, - (result) => { - console.error(`Dataset job failed:`, result); - enqueueSnackbar( - t("datasets:error.failedToCreateDataset", { - error: result.error || t("common:unknownError"), - }), - { variant: "error" }, - ); - - setDatasets((prevDatasets) => { - const datasetExists = prevDatasets.some((d) => d.id === datasetId); - - if (datasetExists) { - deleteDataset(datasetId).catch((error) => { - console.error("Error deleting failed dataset:", error); - }); - - return prevDatasets.filter((d) => d.id !== datasetId); - } - - return prevDatasets; - }); - - setSelectedDatasetId(null); - setStep(0); - setSelectedOption(null); - }, - ); - } + } catch (error) { + console.error("Error fetching datasets after job completion:", error); + await fetchDatasets(); + selectDataset(datasetId); + } + }, + + async (result) => { + console.error("Dataset job failed:", result); + + enqueueSnackbar( + t("datasets:error.failedToCreateDataset", { + error: result?.error || t("common:unknownError"), + }), + { variant: "error" }, + ); + + removeDatasetById(datasetId); + clearSelectedDataset(); + + setStep(0); + setSelectedOption(null); + }, + ); }; const handleEditDataset = (id, newName) => editDataset(id, newName); - const handleEditNotebook = async (id, newName) => { - try { - const updatedNotebook = await updateNotebook(id, { name: newName }); - setNotebooks((prevNotebooks) => - prevNotebooks.map((notebook) => - notebook.id === id - ? { ...notebook, name: updatedNotebook.name } - : notebook, - ), - ); - enqueueSnackbar(t("datasets:message.notebookUpdateSuccess"), { - variant: "success", - }); - } catch (error) { - console.error("Failed to update notebook:", error); - if (error.response?.status === 422) { - enqueueSnackbar(t("datasets:error.notebookNameEmpty"), { - variant: "error", - }); - } else if (error.response?.status === 304) { - enqueueSnackbar(t("datasets:message.noChangesMade"), { - variant: "info", - }); - } else { - enqueueSnackbar(t("datasets:error.failedToUpdateNotebook"), { - variant: "error", - }); - } - throw error; - } - }; + const handleEditNotebook = (id, newName) => editNotebook(id, newName); const handleMouseMove = useCallback((e) => { if (isResizingLeft.current) { From 102f51c88f7ec6a5ac255019010cc431b1e180ff Mon Sep 17 00:00:00 2001 From: Creylay Date: Mon, 26 Jan 2026 16:43:14 -0300 Subject: [PATCH 03/42] Refactor DatasetsContent to utilize useDatasetUIState for improved UI state management --- DashAI/front/src/hooks/useDatasetUIState.js | 56 +++++++++++++++ .../src/pages/datasets/DatasetsContent.jsx | 71 +++++++++---------- 2 files changed, 89 insertions(+), 38 deletions(-) create mode 100644 DashAI/front/src/hooks/useDatasetUIState.js diff --git a/DashAI/front/src/hooks/useDatasetUIState.js b/DashAI/front/src/hooks/useDatasetUIState.js new file mode 100644 index 000000000..263e7cfdf --- /dev/null +++ b/DashAI/front/src/hooks/useDatasetUIState.js @@ -0,0 +1,56 @@ +import { useState, useCallback } from "react"; + +/** + * Manages the UI state for dataset module: + * - step + * - selectedOption + * - navigation resets + */ +export function useDatasetUIState() { + const [step, setStep] = useState(0); + const [selectedOption, setSelectedOption] = useState(null); + + // ---------------- navigation helpers ---------------- + + const resetUI = useCallback(() => { + setStep(0); + setSelectedOption(null); + }, []); + + const goToDatasetFlow = useCallback(() => { + setStep(1); + setSelectedOption("dataset"); + }, []); + + const goToNotebookFlow = useCallback(() => { + setStep(1); + setSelectedOption("notebook"); + }, []); + + const selectDatasetView = useCallback(() => { + setStep(0); + setSelectedOption("dataset"); + }, []); + + const selectNotebookView = useCallback(() => { + setStep(0); + setSelectedOption("notebook"); + }, []); + + const goToNotebookCreation = () => { + setSelectedOption("notebook"); + setStep(1); + }; + + return { + step, + selectedOption, + + resetUI, + goToDatasetFlow, + goToNotebookFlow, + goToNotebookCreation, + selectDatasetView, + selectNotebookView, + }; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 5c6d21194..7dbb88b94 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -20,10 +20,9 @@ import { ExplorersAndConvertersProvider } from "../../components/notebooks/conte import { useTranslation } from "react-i18next"; import { useDatasets } from "../../hooks/useDatasets"; import { useNotebooks } from "../../hooks/useNotebooks"; +import { useDatasetUIState } from "../../hooks/useDatasetUIState"; export default function DatasetsContent() { - const [step, setStep] = useState(0); - const [selectedOption, setSelectedOption] = useState(null); const [leftBarVisible, setLeftBarVisible] = useState(true); const [rightBarVisible, setRightBarVisible] = useState(true); const [leftBarWidth, setLeftBarWidth] = useState(20); @@ -65,20 +64,31 @@ export default function DatasetsContent() { removeNotebooksByDatasetId, } = useNotebooks({ enqueueSnackbar, t }); + const { + step, + selectedOption, + resetUI, + goToDatasetFlow, + goToNotebookFlow, + goToNotebookCreation, + selectDatasetView, + selectNotebookView, + } = useDatasetUIState(); + const goToNextStep = (option) => { + if (option === "dataset") { + goToDatasetFlow(); + } else { + goToNotebookFlow(); + } + + clearSelectedNotebook(); + clearSelectedDataset(); + if (option === "dataset" && tourContext?.run) { - setStep((prevStep) => prevStep + 1); - setSelectedOption(option); - clearSelectedNotebook(); - clearSelectedDataset(); setTimeout(() => { tourContext.nextStep(); }, 600); - } else { - setStep((prevStep) => prevStep + 1); - setSelectedOption(option); - clearSelectedNotebook(); - clearSelectedDataset(); } }; @@ -90,28 +100,26 @@ export default function DatasetsContent() { const handleNewSessionButton = () => { clearSelectedDataset(); clearSelectedNotebook(); - setStep(0); - setSelectedOption(null); + resetUI(); }; const handleDatasetClick = (datasetId) => { selectDataset(datasetId); clearSelectedNotebook(); - setSelectedOption("dataset"); + selectDatasetView(); setRightBarContent(null); }; const handleNotebookClick = (notebookId) => { selectNotebook(notebookId); clearSelectedDataset(); - setSelectedOption("notebook"); + selectNotebookView(); }; const handleDatasetDelete = async (id) => { if (id === selectedDatasetId) { clearSelectedDataset(); - setStep(0); - setSelectedOption(null); + resetUI(); } deleteDatasetLocal(id); @@ -125,8 +133,7 @@ export default function DatasetsContent() { if (id === selectedNotebookId) { clearSelectedNotebook(); - setStep(0); - setSelectedOption(null); + resetUI(); } }; @@ -139,10 +146,8 @@ export default function DatasetsContent() { enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { variant: "success", }); - addDatasetOptimistically(data); - - setSelectedOption("dataset"); + selectDatasetView(); clearSelectedNotebook(); const job = await enqueueDatasetJob( @@ -167,27 +172,21 @@ export default function DatasetsContent() { const handleNotebookCreated = async (createdNotebook) => { await fetchNotebooks(); - setStep(0); - setSelectedOption("notebook"); + selectNotebookView(); selectNotebook(createdNotebook.id); clearSelectedDataset(); }; const handleNewNotebookFromDataset = () => { - // Keep selectedDatasetId but go to notebook creation - setSelectedOption("notebook"); - setStep(1); + goToNotebookCreation(); }; const handleDatasetCreated = (newDataset, datasetJob) => { addDatasetOptimistically(newDataset); - - setStep(0); - setSelectedOption("dataset"); + selectDatasetView(); clearSelectedNotebook(); // clear right bar content injected during dataset creation (e.g. dataloader config) setRightBarContent(null); - startDatasetPolling(newDataset, datasetJob); }; @@ -237,9 +236,7 @@ export default function DatasetsContent() { removeDatasetById(datasetId); clearSelectedDataset(); - - setStep(0); - setSelectedOption(null); + resetUI(); }, ); }; @@ -500,8 +497,7 @@ export default function DatasetsContent() { {step === 1 && selectedOption === "dataset" ? ( { - setStep(0); - setSelectedOption(null); + resetUI(); fetchDatasets(); // clear right bar when exiting setRightBarContent(null); @@ -513,8 +509,7 @@ export default function DatasetsContent() { ) : step === 1 && selectedOption === "notebook" ? ( { - setStep(0); - setSelectedOption(null); + resetUI(); fetchNotebooks(); }} datasets={datasets} From 37f1ce21e9c3db2c43132e12f488d46d15737420 Mon Sep 17 00:00:00 2001 From: Creylay Date: Mon, 26 Jan 2026 18:36:53 -0300 Subject: [PATCH 04/42] Refactor DatasetsContent to implement useDatasetFlow for enhanced dataset management and job polling --- DashAI/front/src/hooks/useDatasetFlow.js | 124 ++++++++++++++++++ DashAI/front/src/hooks/useDatasets.js | 1 + .../src/pages/datasets/DatasetsContent.jsx | 108 +++------------ 3 files changed, 145 insertions(+), 88 deletions(-) create mode 100644 DashAI/front/src/hooks/useDatasetFlow.js diff --git a/DashAI/front/src/hooks/useDatasetFlow.js b/DashAI/front/src/hooks/useDatasetFlow.js new file mode 100644 index 000000000..38bc4cd3e --- /dev/null +++ b/DashAI/front/src/hooks/useDatasetFlow.js @@ -0,0 +1,124 @@ +import { startJobPolling } from "../utils/jobPoller"; +import { enqueueDatasetJob } from "../api/job"; +import { createDataset, deleteDataset } from "../api/datasets"; + +export function useDatasetFlow({ + datasets, + enrichDatasetsWithInfo, + fetchDatasets, + replaceDatasets, + addDatasetOptimistically, + removeDatasetById, + selectDataset, + clearSelectedDataset, + removeNotebooksByDatasetId, + enqueueSnackbar, + t, + resetUIAfterFailure, +}) { + const pollForDataset = ({ datasetId, datasetName }, { jobId }) => { + if (!jobId) return; + + startJobPolling( + jobId, + + //Susccess + async () => { + enqueueSnackbar( + t("datasets:message.datasetCreationSuccess", { datasetName }), + { variant: "success" }, + ); + + try { + const freshDatasets = await fetchDatasets(true); + const dataset = freshDatasets.find((d) => d.id === datasetId); + + if (dataset) { + const enriched = await enrichDatasetsWithInfo( + freshDatasets, + datasets, + ); + replaceDatasets(enriched); + selectDataset(datasetId); + } else { + await fetchDatasets(); + selectDataset(datasetId); + } + } catch (error) { + console.error("Error after dataset job completion:", error); + await fetchDatasets(); + selectDataset(datasetId); + } + }, + + //Failure + async (result) => { + console.error("Dataset job failed:", result); + + enqueueSnackbar( + t("datasets:error.failedToCreateDataset", { + error: result?.error || t("common:unknownError"), + }), + { variant: "error" }, + ); + + deleteDatasetRemote(datasetId).catch(console.error); + clearSelectedDataset(); + resetUIAfterFailure(); + }, + ); + }; + + const createDatasetFromNotebook = async (name, notebookId) => { + try { + const dataset = await createDataset(name); + + enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { + variant: "success", + }); + + // optimistic + replaceDatasets((prev) => [...prev, dataset]); + selectDataset(dataset.id); + + const job = await enqueueDatasetJob(dataset.id, null, "", {}, notebookId); + + pollForDataset( + { datasetId: dataset.id, datasetName: name }, + { jobId: job.id }, + ); + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { + variant: "error", + }); + console.error("Failed to create dataset from notebook:", error); + } + }; + + const deleteDatasetById = async (datasetId) => { + removeDatasetById(datasetId); + removeNotebooksByDatasetId(datasetId); + + try { + await deleteDataset(datasetId); + } catch (error) { + console.error("Failed to delete dataset:", error); + } + }; + + const createDatasetFromUpload = (dataset, job) => { + addDatasetOptimistically(dataset); + selectDataset(dataset.id); + pollForDataset( + { datasetId: dataset.id, datasetName: dataset.name }, + { jobId: job.id }, + ); + }; + + return { + createDatasetFromNotebook, + createDatasetFromUpload, + deleteDatasetById, + pollForDataset, + }; +} diff --git a/DashAI/front/src/hooks/useDatasets.js b/DashAI/front/src/hooks/useDatasets.js index df406ab63..c0ff2b4fb 100644 --- a/DashAI/front/src/hooks/useDatasets.js +++ b/DashAI/front/src/hooks/useDatasets.js @@ -149,6 +149,7 @@ export function useDatasets({ enqueueSnackbar, t }) { return { datasets, selectedDatasetId, + enrichDatasetsWithInfo, createDataset, diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 7dbb88b94..64e370da8 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -14,13 +14,12 @@ import NotebookVisualization from "../../components/notebooks/notebook/NotebookV import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; -import { startJobPolling } from "../../utils/jobPoller"; -import { enqueueDatasetJob } from "../../api/job"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; import { useDatasets } from "../../hooks/useDatasets"; import { useNotebooks } from "../../hooks/useNotebooks"; import { useDatasetUIState } from "../../hooks/useDatasetUIState"; +import { useDatasetFlow } from "../../hooks/useDatasetFlow"; export default function DatasetsContent() { const [leftBarVisible, setLeftBarVisible] = useState(true); @@ -39,9 +38,9 @@ export default function DatasetsContent() { const { datasets, selectedDatasetId, + enrichDatasetsWithInfo, createDataset, fetchDatasets, - fetchFreshDatasets, selectDataset, clearSelectedDataset, deleteDatasetLocal, @@ -75,6 +74,19 @@ export default function DatasetsContent() { selectNotebookView, } = useDatasetUIState(); + const { createDatasetFromNotebook, deleteDatasetById } = useDatasetFlow({ + datasets, + enrichDatasetsWithInfo, + fetchDatasets, + replaceDatasets, + selectDataset, + clearSelectedDataset, + deleteDatasetRemote, + enqueueSnackbar, + t, + resetUI, + }); + const goToNextStep = (option) => { if (option === "dataset") { goToDatasetFlow(); @@ -116,16 +128,13 @@ export default function DatasetsContent() { selectNotebookView(); }; - const handleDatasetDelete = async (id) => { + const handleDatasetDelete = (id) => { if (id === selectedDatasetId) { clearSelectedDataset(); resetUI(); } - deleteDatasetLocal(id); - removeNotebooksByDatasetId(id); - - await deleteDatasetRemote(id); + deleteDatasetById(id); }; const handleNotebookDelete = (id) => { @@ -139,35 +148,9 @@ export default function DatasetsContent() { const handleAddDatasetFromNotebook = async (name) => { if (!selectedNotebook) return; - - try { - const data = await createDataset(name); - - enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { - variant: "success", - }); - addDatasetOptimistically(data); - selectDatasetView(); - clearSelectedNotebook(); - - const job = await enqueueDatasetJob( - data.id, - null, - "", - {}, - selectedNotebook.id, - ); - - pollForDataset( - { datasetId: data.id, datasetName: name }, - { jobId: job.id }, - ); - } catch (error) { - enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { - variant: "error", - }); - console.error("Failed to create dataset from notebook:", error); - } + clearSelectedNotebook(); + selectDatasetView(); + createDatasetFromNotebook(name, selectedNotebook.id); }; const handleNotebookCreated = async (createdNotebook) => { @@ -190,57 +173,6 @@ export default function DatasetsContent() { startDatasetPolling(newDataset, datasetJob); }; - const pollForDataset = async ({ datasetId, datasetName }, { jobId }) => { - if (!jobId) return; - - startJobPolling( - jobId, - async () => { - enqueueSnackbar( - t("datasets:message.datasetCreationSuccess", { datasetName }), - { variant: "success" }, - ); - - try { - const freshDatasets = await fetchFreshDatasets(); - const dataset = freshDatasets.find((d) => d.id === datasetId); - - if (dataset) { - const enriched = await enrichDatasetsWithInfo( - freshDatasets, - datasets, - ); - - replaceDatasets(enriched); - selectDataset(datasetId); - } else { - await fetchDatasets(); - selectDataset(datasetId); - } - } catch (error) { - console.error("Error fetching datasets after job completion:", error); - await fetchDatasets(); - selectDataset(datasetId); - } - }, - - async (result) => { - console.error("Dataset job failed:", result); - - enqueueSnackbar( - t("datasets:error.failedToCreateDataset", { - error: result?.error || t("common:unknownError"), - }), - { variant: "error" }, - ); - - removeDatasetById(datasetId); - clearSelectedDataset(); - resetUI(); - }, - ); - }; - const handleEditDataset = (id, newName) => editDataset(id, newName); const handleEditNotebook = (id, newName) => editNotebook(id, newName); From 45d30497334b2609c64707b62a1cee7242143f7e Mon Sep 17 00:00:00 2001 From: Creylay Date: Mon, 26 Jan 2026 19:31:02 -0300 Subject: [PATCH 05/42] Refactor DatasetsContent to implement useDatasetActions for improved dataset and notebook management --- DashAI/front/src/hooks/useDatasetActions.js | 62 +++++++++++++++++ DashAI/front/src/hooks/useDatasetFlow.js | 14 ---- .../src/pages/datasets/DatasetsContent.jsx | 67 +++++++++---------- 3 files changed, 93 insertions(+), 50 deletions(-) create mode 100644 DashAI/front/src/hooks/useDatasetActions.js diff --git a/DashAI/front/src/hooks/useDatasetActions.js b/DashAI/front/src/hooks/useDatasetActions.js new file mode 100644 index 000000000..1e1891897 --- /dev/null +++ b/DashAI/front/src/hooks/useDatasetActions.js @@ -0,0 +1,62 @@ +export function useDatasetActions({ + selectedDatasetId, + selectedNotebookId, + + selectDataset, + selectNotebook, + clearSelectedDataset, + clearSelectedNotebook, + + deleteDatasetLocal, + deleteDatasetRemote, + removeNotebooksByDatasetId, + deleteNotebookById, + + editDataset, + editNotebook, + + resetUI, + selectDatasetView, + selectNotebookView, +}) { + const handleDatasetClick = (id) => { + selectDataset(id); + clearSelectedNotebook(); + selectDatasetView(); + }; + + const handleNotebookClick = (id) => { + selectNotebook(id); + clearSelectedDataset(); + selectNotebookView(); + }; + + const handleDatasetDelete = async (id) => { + if (id === selectedDatasetId) { + clearSelectedDataset(); + resetUI(); + } + + deleteDatasetLocal(id); + removeNotebooksByDatasetId(id); + await deleteDatasetRemote(id); + }; + + const handleNotebookDelete = (id) => { + deleteNotebookById(id); + + if (id === selectedNotebookId) { + clearSelectedNotebook(); + resetUI(); + } + }; + + return { + handleDatasetClick, + handleNotebookClick, + handleDatasetDelete, + handleNotebookDelete, + handleEditDataset: editDataset, + handleEditNotebook: editNotebook, + }; +} diff --git a/DashAI/front/src/hooks/useDatasetFlow.js b/DashAI/front/src/hooks/useDatasetFlow.js index 38bc4cd3e..76b7a38c2 100644 --- a/DashAI/front/src/hooks/useDatasetFlow.js +++ b/DashAI/front/src/hooks/useDatasetFlow.js @@ -8,10 +8,8 @@ export function useDatasetFlow({ fetchDatasets, replaceDatasets, addDatasetOptimistically, - removeDatasetById, selectDataset, clearSelectedDataset, - removeNotebooksByDatasetId, enqueueSnackbar, t, resetUIAfterFailure, @@ -95,17 +93,6 @@ export function useDatasetFlow({ } }; - const deleteDatasetById = async (datasetId) => { - removeDatasetById(datasetId); - removeNotebooksByDatasetId(datasetId); - - try { - await deleteDataset(datasetId); - } catch (error) { - console.error("Failed to delete dataset:", error); - } - }; - const createDatasetFromUpload = (dataset, job) => { addDatasetOptimistically(dataset); selectDataset(dataset.id); @@ -118,7 +105,6 @@ export function useDatasetFlow({ return { createDatasetFromNotebook, createDatasetFromUpload, - deleteDatasetById, pollForDataset, }; } diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 64e370da8..979240b29 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -20,6 +20,7 @@ import { useDatasets } from "../../hooks/useDatasets"; import { useNotebooks } from "../../hooks/useNotebooks"; import { useDatasetUIState } from "../../hooks/useDatasetUIState"; import { useDatasetFlow } from "../../hooks/useDatasetFlow"; +import { useDatasetActions } from "../../hooks/useDatasetActions"; export default function DatasetsContent() { const [leftBarVisible, setLeftBarVisible] = useState(true); @@ -74,7 +75,7 @@ export default function DatasetsContent() { selectNotebookView, } = useDatasetUIState(); - const { createDatasetFromNotebook, deleteDatasetById } = useDatasetFlow({ + const { createDatasetFromNotebook } = useDatasetFlow({ datasets, enrichDatasetsWithInfo, fetchDatasets, @@ -87,6 +88,35 @@ export default function DatasetsContent() { resetUI, }); + const { + handleDatasetClick, + handleNotebookClick, + handleDatasetDelete, + handleNotebookDelete, + handleEditDataset, + handleEditNotebook, + } = useDatasetActions({ + selectedDatasetId, + selectedNotebookId, + + selectDataset, + selectNotebook, + clearSelectedDataset, + clearSelectedNotebook, + + deleteDatasetLocal, + deleteDatasetRemote, + removeNotebooksByDatasetId, + deleteNotebookById, + + editDataset, + editNotebook, + + resetUI, + selectDatasetView, + selectNotebookView, + }); + const goToNextStep = (option) => { if (option === "dataset") { goToDatasetFlow(); @@ -115,37 +145,6 @@ export default function DatasetsContent() { resetUI(); }; - const handleDatasetClick = (datasetId) => { - selectDataset(datasetId); - clearSelectedNotebook(); - selectDatasetView(); - setRightBarContent(null); - }; - - const handleNotebookClick = (notebookId) => { - selectNotebook(notebookId); - clearSelectedDataset(); - selectNotebookView(); - }; - - const handleDatasetDelete = (id) => { - if (id === selectedDatasetId) { - clearSelectedDataset(); - resetUI(); - } - - deleteDatasetById(id); - }; - - const handleNotebookDelete = (id) => { - deleteNotebookById(id); - - if (id === selectedNotebookId) { - clearSelectedNotebook(); - resetUI(); - } - }; - const handleAddDatasetFromNotebook = async (name) => { if (!selectedNotebook) return; clearSelectedNotebook(); @@ -173,10 +172,6 @@ export default function DatasetsContent() { startDatasetPolling(newDataset, datasetJob); }; - const handleEditDataset = (id, newName) => editDataset(id, newName); - - const handleEditNotebook = (id, newName) => editNotebook(id, newName); - const handleMouseMove = useCallback((e) => { if (isResizingLeft.current) { const container = document.querySelector('[data-container="datasets"]'); From 38936c342f8bec650f3b746fee58f82e4cc19b5f Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 27 Jan 2026 11:11:10 -0300 Subject: [PATCH 06/42] Add useThreePanelLayout hook for managing three-panel layout with resizable bars --- .../front/src/hooks/useThreePanelsLayout.js | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 DashAI/front/src/hooks/useThreePanelsLayout.js diff --git a/DashAI/front/src/hooks/useThreePanelsLayout.js b/DashAI/front/src/hooks/useThreePanelsLayout.js new file mode 100644 index 000000000..cc1041bc3 --- /dev/null +++ b/DashAI/front/src/hooks/useThreePanelsLayout.js @@ -0,0 +1,104 @@ +import { useState, useRef, useEffect, useCallback } from "react"; + +export function useThreePanelLayout() { + const [leftBarVisible, setLeftBarVisible] = useState(true); + const [rightBarVisible, setRightBarVisible] = useState(true); + const [leftBarWidth, setLeftBarWidth] = useState(20); + const [rightBarWidth, setRightBarWidth] = useState(20); + + const [isTogglingLeft, setIsTogglingLeft] = useState(false); + const [isTogglingRight, setIsTogglingRight] = useState(false); + + const isResizingLeft = useRef(false); + const isResizingRight = useRef(false); + + const handleMouseMove = useCallback((e) => { + const container = document.querySelector('[data-container="datasets"]'); + if (!container) return; + + const rect = container.getBoundingClientRect(); + + if (isResizingLeft.current) { + const w = ((e.clientX - rect.left) / rect.width) * 100; + if (w >= 15 && w <= 40) setLeftBarWidth(w); + } + + if (isResizingRight.current) { + const w = ((rect.right - e.clientX) / rect.width) * 100; + if (w >= 15 && w <= 40) setRightBarWidth(w); + } + }, []); + + const handleMouseUp = useCallback(() => { + isResizingLeft.current = false; + isResizingRight.current = false; + document.body.style.cursor = "default"; + document.body.style.userSelect = "auto"; + }, []); + + useEffect(() => { + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + return () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + }; + }, [handleMouseMove, handleMouseUp]); + + const handleToggleLeft = useCallback(() => { + setIsTogglingLeft(true); + setLeftBarVisible((v) => !v); + + setTimeout(() => { + setIsTogglingLeft(false); + }, 300); + }, []); + + const handleToggleRight = useCallback(() => { + setIsTogglingRight(true); + setRightBarVisible((v) => !v); + + setTimeout(() => { + setIsTogglingRight(false); + }, 300); + }, []); + + const centerWidth = + leftBarVisible && rightBarVisible + ? 100 - leftBarWidth - rightBarWidth + : leftBarVisible + ? 100 - leftBarWidth + : rightBarVisible + ? 100 - rightBarWidth + : 100; + + return { + leftBarVisible, + rightBarVisible, + leftBarWidth, + rightBarWidth, + centerWidth, + + handleToggleLeft, + handleToggleRight, + + isTogglingLeft, + isTogglingRight, + + bindLeftResize: { + onMouseDown: () => { + isResizingLeft.current = true; + document.body.style.cursor = "col-resize"; + document.body.style.userSelect = "none"; + }, + }, + + bindRightResize: { + onMouseDown: () => { + isResizingRight.current = true; + document.body.style.cursor = "col-resize"; + document.body.style.userSelect = "none"; + }, + }, + }; +} From 0f0df8e99e6fb86cedc9a74176c9d86e6471e5f3 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 27 Jan 2026 11:13:54 -0300 Subject: [PATCH 07/42] Refactor DatasetsContent to integrate useNotebookActions for improved notebook management --- DashAI/front/src/hooks/useNotebooksActions.js | 36 +++++ .../src/pages/datasets/DatasetsContent.jsx | 143 +++++------------- 2 files changed, 75 insertions(+), 104 deletions(-) create mode 100644 DashAI/front/src/hooks/useNotebooksActions.js diff --git a/DashAI/front/src/hooks/useNotebooksActions.js b/DashAI/front/src/hooks/useNotebooksActions.js new file mode 100644 index 000000000..1d78fe718 --- /dev/null +++ b/DashAI/front/src/hooks/useNotebooksActions.js @@ -0,0 +1,36 @@ +export function useNotebookActions({ + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + clearSelectedDataset, + selectNotebookView, + selectDatasetView, + goToNotebookCreation, + createDatasetFromNotebook, +}) { + const handleAddDatasetFromNotebook = async (name, selectedNotebook) => { + if (!selectedNotebook) return; + + clearSelectedNotebook(); + selectDatasetView(); + + createDatasetFromNotebook(name, selectedNotebook.id); + }; + + const handleNotebookCreated = async (createdNotebook) => { + await fetchNotebooks(); + selectNotebookView(); + selectNotebook(createdNotebook.id); + clearSelectedDataset(); + }; + + const handleNewNotebookFromDataset = () => { + goToNotebookCreation(); + }; + + return { + handleAddDatasetFromNotebook, + handleNotebookCreated, + handleNewNotebookFromDataset, + }; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 979240b29..c7a8d3683 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -21,17 +21,11 @@ import { useNotebooks } from "../../hooks/useNotebooks"; import { useDatasetUIState } from "../../hooks/useDatasetUIState"; import { useDatasetFlow } from "../../hooks/useDatasetFlow"; import { useDatasetActions } from "../../hooks/useDatasetActions"; +import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; +import { useNotebookActions } from "../../hooks/useNotebooksActions"; export default function DatasetsContent() { - const [leftBarVisible, setLeftBarVisible] = useState(true); - const [rightBarVisible, setRightBarVisible] = useState(true); - const [leftBarWidth, setLeftBarWidth] = useState(20); - const [rightBarWidth, setRightBarWidth] = useState(20); const [rightBarContent, setRightBarContent] = useState(null); - const isResizingLeft = useRef(false); - const isResizingRight = useRef(false); - const [isTogglingLeft, setIsTogglingLeft] = useState(false); - const [isTogglingRight, setIsTogglingRight] = useState(false); const tourContext = useTourContext(); const { enqueueSnackbar } = useSnackbar(); const { t } = useTranslation(["datasets", "common"]); @@ -40,7 +34,6 @@ export default function DatasetsContent() { datasets, selectedDatasetId, enrichDatasetsWithInfo, - createDataset, fetchDatasets, selectDataset, clearSelectedDataset, @@ -49,7 +42,6 @@ export default function DatasetsContent() { editDataset, addDatasetOptimistically, startDatasetPolling, - removeDatasetById, replaceDatasets, } = useDatasets({ enqueueSnackbar, t }); @@ -117,6 +109,38 @@ export default function DatasetsContent() { selectNotebookView, }); + const { + leftBarVisible, + rightBarVisible, + leftBarWidth, + rightBarWidth, + centerWidth, + + handleToggleLeft, + handleToggleRight, + + isTogglingLeft, + isTogglingRight, + + bindLeftResize, + bindRightResize, + } = useThreePanelLayout(); + + const { + handleAddDatasetFromNotebook, + handleNotebookCreated, + handleNewNotebookFromDataset, + } = useNotebookActions({ + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + clearSelectedDataset, + selectNotebookView, + selectDatasetView, + goToNotebookCreation, + createDatasetFromNotebook, + }); + const goToNextStep = (option) => { if (option === "dataset") { goToDatasetFlow(); @@ -145,24 +169,6 @@ export default function DatasetsContent() { resetUI(); }; - const handleAddDatasetFromNotebook = async (name) => { - if (!selectedNotebook) return; - clearSelectedNotebook(); - selectDatasetView(); - createDatasetFromNotebook(name, selectedNotebook.id); - }; - - const handleNotebookCreated = async (createdNotebook) => { - await fetchNotebooks(); - selectNotebookView(); - selectNotebook(createdNotebook.id); - clearSelectedDataset(); - }; - - const handleNewNotebookFromDataset = () => { - goToNotebookCreation(); - }; - const handleDatasetCreated = (newDataset, datasetJob) => { addDatasetOptimistically(newDataset); selectDatasetView(); @@ -172,65 +178,6 @@ export default function DatasetsContent() { startDatasetPolling(newDataset, datasetJob); }; - const handleMouseMove = useCallback((e) => { - if (isResizingLeft.current) { - const container = document.querySelector('[data-container="datasets"]'); - const containerRect = container.getBoundingClientRect(); - const newWidth = - ((e.clientX - containerRect.left) / containerRect.width) * 100; - if (newWidth >= 15 && newWidth <= 40) { - setLeftBarWidth(newWidth); - } - } - - if (isResizingRight.current) { - const container = document.querySelector('[data-container="datasets"]'); - const containerRect = container.getBoundingClientRect(); - const newWidth = - ((containerRect.right - e.clientX) / containerRect.width) * 100; - if (newWidth >= 15 && newWidth <= 40) { - setRightBarWidth(newWidth); - } - } - }, []); - - const handleMouseUp = useCallback(() => { - isResizingLeft.current = false; - isResizingRight.current = false; - document.body.style.cursor = "default"; - document.body.style.userSelect = "auto"; - }, []); - - const handleToggleLeft = () => { - setIsTogglingLeft(true); - setLeftBarVisible(!leftBarVisible); - setTimeout(() => setIsTogglingLeft(false), 300); - }; - - const handleToggleRight = () => { - setIsTogglingRight(true); - setRightBarVisible(!rightBarVisible); - setTimeout(() => setIsTogglingRight(false), 300); - }; - - useEffect(() => { - window.addEventListener("mousemove", handleMouseMove); - window.addEventListener("mouseup", handleMouseUp); - return () => { - window.removeEventListener("mousemove", handleMouseMove); - window.removeEventListener("mouseup", handleMouseUp); - }; - }, [handleMouseMove, handleMouseUp]); - - const centerWidth = - leftBarVisible && rightBarVisible - ? 100 - leftBarWidth - rightBarWidth - : leftBarVisible - ? 100 - leftBarWidth - : rightBarVisible - ? 100 - rightBarWidth - : 100; - const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); @@ -272,11 +219,7 @@ export default function DatasetsContent() { onToggle={handleToggleLeft} /> { - isResizingLeft.current = true; - document.body.style.cursor = "col-resize"; - document.body.style.userSelect = "none"; - }} + {...bindLeftResize} sx={{ position: "absolute", right: -2, @@ -334,8 +277,8 @@ export default function DatasetsContent() { + handleAddDatasetFromNotebook(name, selectedNotebook) } existingDatasets={datasets} /> @@ -378,11 +321,7 @@ export default function DatasetsContent() { {rightBarVisible && ( <> { - isResizingRight.current = true; - document.body.style.cursor = "col-resize"; - document.body.style.userSelect = "none"; - }} + {...bindRightResize} sx={{ position: "absolute", left: -2, @@ -518,11 +457,7 @@ export default function DatasetsContent() { {rightBarVisible && ( <> { - isResizingRight.current = true; - document.body.style.cursor = "col-resize"; - document.body.style.userSelect = "none"; - }} + {...bindLeftResize} sx={{ position: "absolute", left: -2, From e9865d780616fe0071512c3e45ae8b2f3137b5e7 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 27 Jan 2026 16:46:45 -0300 Subject: [PATCH 08/42] Refactor DatasetsContent to utilize useLayoutActions for improved flow management --- DashAI/front/src/hooks/useLayoutActions.js | 53 +++++++++++++++++++ .../src/pages/datasets/DatasetsContent.jsx | 45 ++++++---------- 2 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 DashAI/front/src/hooks/useLayoutActions.js diff --git a/DashAI/front/src/hooks/useLayoutActions.js b/DashAI/front/src/hooks/useLayoutActions.js new file mode 100644 index 000000000..bb67257a5 --- /dev/null +++ b/DashAI/front/src/hooks/useLayoutActions.js @@ -0,0 +1,53 @@ +export function useLayoutActions({ + goToDatasetFlow, + goToNotebookFlow, + resetUI, + + clearSelectedDataset, + clearSelectedNotebook, + + selectDatasetView, + + addDatasetOptimistically, + startDatasetPolling, + + setRightBarContent, + tourContext, +}) { + const goToNextStep = (option) => { + if (option === "dataset") { + goToDatasetFlow(); + } else { + goToNotebookFlow(); + } + + clearSelectedDataset(); + clearSelectedNotebook(); + + if (option === "dataset" && tourContext?.run) { + setTimeout(() => { + tourContext.nextStep(); + }, 600); + } + }; + + const handleNewSessionButton = () => { + clearSelectedDataset(); + clearSelectedNotebook(); + resetUI(); + }; + + const handleDatasetCreated = (newDataset, datasetJob) => { + addDatasetOptimistically(newDataset); + selectDatasetView(); + clearSelectedNotebook(); + setRightBarContent(null); + startDatasetPolling(newDataset, datasetJob); + }; + + return { + goToNextStep, + handleNewSessionButton, + handleDatasetCreated, + }; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index c7a8d3683..8613d5f1c 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -23,6 +23,7 @@ import { useDatasetFlow } from "../../hooks/useDatasetFlow"; import { useDatasetActions } from "../../hooks/useDatasetActions"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { useNotebookActions } from "../../hooks/useNotebooksActions"; +import { useLayoutActions } from "../../hooks/useLayoutActions"; export default function DatasetsContent() { const [rightBarContent, setRightBarContent] = useState(null); @@ -141,43 +142,29 @@ export default function DatasetsContent() { createDatasetFromNotebook, }); - const goToNextStep = (option) => { - if (option === "dataset") { - goToDatasetFlow(); - } else { - goToNotebookFlow(); - } + const { goToNextStep, handleNewSessionButton, handleDatasetCreated } = + useLayoutActions({ + goToDatasetFlow, + goToNotebookFlow, + resetUI, - clearSelectedNotebook(); - clearSelectedDataset(); + clearSelectedDataset, + clearSelectedNotebook, - if (option === "dataset" && tourContext?.run) { - setTimeout(() => { - tourContext.nextStep(); - }, 600); - } - }; + selectDatasetView, + + addDatasetOptimistically, + startDatasetPolling, + + setRightBarContent, + tourContext, + }); useEffect(() => { fetchDatasets(); fetchNotebooks(); }, []); - const handleNewSessionButton = () => { - clearSelectedDataset(); - clearSelectedNotebook(); - resetUI(); - }; - - const handleDatasetCreated = (newDataset, datasetJob) => { - addDatasetOptimistically(newDataset); - selectDatasetView(); - clearSelectedNotebook(); - // clear right bar content injected during dataset creation (e.g. dataloader config) - setRightBarContent(null); - startDatasetPolling(newDataset, datasetJob); - }; - const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); From 88e5f47ba6c51f2308bcc353a7cde1aadef86c3d Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 27 Jan 2026 17:05:27 -0300 Subject: [PATCH 09/42] Refactor DatasetsContent to reorganize hooks into a dedicated datasets directory and remove unused hooks for improved code structure and maintainability --- .../src/hooks/{ => datasets}/useDatasetActions.js | 0 .../src/hooks/{ => datasets}/useDatasetFlow.js | 6 +++--- .../src/hooks/{ => datasets}/useDatasetUIState.js | 0 .../front/src/hooks/{ => datasets}/useDatasets.js | 4 ++-- .../src/hooks/{ => datasets}/useLayoutActions.js | 0 .../front/src/hooks/{ => datasets}/useNotebooks.js | 6 +++++- .../hooks/{ => datasets}/useNotebooksActions.js | 0 .../front/src/pages/datasets/DatasetsContent.jsx | 14 +++++++------- 8 files changed, 17 insertions(+), 13 deletions(-) rename DashAI/front/src/hooks/{ => datasets}/useDatasetActions.js (100%) rename DashAI/front/src/hooks/{ => datasets}/useDatasetFlow.js (94%) rename DashAI/front/src/hooks/{ => datasets}/useDatasetUIState.js (100%) rename DashAI/front/src/hooks/{ => datasets}/useDatasets.js (98%) rename DashAI/front/src/hooks/{ => datasets}/useLayoutActions.js (100%) rename DashAI/front/src/hooks/{ => datasets}/useNotebooks.js (96%) rename DashAI/front/src/hooks/{ => datasets}/useNotebooksActions.js (100%) diff --git a/DashAI/front/src/hooks/useDatasetActions.js b/DashAI/front/src/hooks/datasets/useDatasetActions.js similarity index 100% rename from DashAI/front/src/hooks/useDatasetActions.js rename to DashAI/front/src/hooks/datasets/useDatasetActions.js diff --git a/DashAI/front/src/hooks/useDatasetFlow.js b/DashAI/front/src/hooks/datasets/useDatasetFlow.js similarity index 94% rename from DashAI/front/src/hooks/useDatasetFlow.js rename to DashAI/front/src/hooks/datasets/useDatasetFlow.js index 76b7a38c2..56f85d12c 100644 --- a/DashAI/front/src/hooks/useDatasetFlow.js +++ b/DashAI/front/src/hooks/datasets/useDatasetFlow.js @@ -1,6 +1,6 @@ -import { startJobPolling } from "../utils/jobPoller"; -import { enqueueDatasetJob } from "../api/job"; -import { createDataset, deleteDataset } from "../api/datasets"; +import { startJobPolling } from "../../utils/jobPoller"; +import { enqueueDatasetJob } from "../../api/job"; +import { createDataset, deleteDataset } from "../../api/datasets"; export function useDatasetFlow({ datasets, diff --git a/DashAI/front/src/hooks/useDatasetUIState.js b/DashAI/front/src/hooks/datasets/useDatasetUIState.js similarity index 100% rename from DashAI/front/src/hooks/useDatasetUIState.js rename to DashAI/front/src/hooks/datasets/useDatasetUIState.js diff --git a/DashAI/front/src/hooks/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js similarity index 98% rename from DashAI/front/src/hooks/useDatasets.js rename to DashAI/front/src/hooks/datasets/useDatasets.js index c0ff2b4fb..a8ea6525e 100644 --- a/DashAI/front/src/hooks/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -5,8 +5,8 @@ import { getDatasetInfo, updateDataset, createDataset, -} from "../api/datasets"; -import { startJobPolling } from "../utils/jobPoller"; +} from "../../api/datasets"; +import { startJobPolling } from "../../utils/jobPoller"; import { replace } from "formik"; export function useDatasets({ enqueueSnackbar, t }) { diff --git a/DashAI/front/src/hooks/useLayoutActions.js b/DashAI/front/src/hooks/datasets/useLayoutActions.js similarity index 100% rename from DashAI/front/src/hooks/useLayoutActions.js rename to DashAI/front/src/hooks/datasets/useLayoutActions.js diff --git a/DashAI/front/src/hooks/useNotebooks.js b/DashAI/front/src/hooks/datasets/useNotebooks.js similarity index 96% rename from DashAI/front/src/hooks/useNotebooks.js rename to DashAI/front/src/hooks/datasets/useNotebooks.js index f93ba4f63..322b78fbd 100644 --- a/DashAI/front/src/hooks/useNotebooks.js +++ b/DashAI/front/src/hooks/datasets/useNotebooks.js @@ -1,5 +1,9 @@ import { useState, useCallback } from "react"; -import { getNotebooks, deleteNotebook, updateNotebook } from "../api/notebook"; +import { + getNotebooks, + deleteNotebook, + updateNotebook, +} from "../../api/notebook"; export function useNotebooks({ enqueueSnackbar, t }) { const [notebooks, setNotebooks] = useState([]); diff --git a/DashAI/front/src/hooks/useNotebooksActions.js b/DashAI/front/src/hooks/datasets/useNotebooksActions.js similarity index 100% rename from DashAI/front/src/hooks/useNotebooksActions.js rename to DashAI/front/src/hooks/datasets/useNotebooksActions.js diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 8613d5f1c..2d92e128a 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -16,14 +16,14 @@ import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; -import { useDatasets } from "../../hooks/useDatasets"; -import { useNotebooks } from "../../hooks/useNotebooks"; -import { useDatasetUIState } from "../../hooks/useDatasetUIState"; -import { useDatasetFlow } from "../../hooks/useDatasetFlow"; -import { useDatasetActions } from "../../hooks/useDatasetActions"; +import { useDatasets } from "../../hooks/datasets/useDatasets"; +import { useNotebooks } from "../../hooks/datasets/useNotebooks"; +import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; +import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; +import { useDatasetActions } from "../../hooks/datasets/useDatasetActions"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; -import { useNotebookActions } from "../../hooks/useNotebooksActions"; -import { useLayoutActions } from "../../hooks/useLayoutActions"; +import { useNotebookActions } from "../../hooks/datasets/useNotebooksActions"; +import { useLayoutActions } from "../../hooks/datasets/useLayoutActions"; export default function DatasetsContent() { const [rightBarContent, setRightBarContent] = useState(null); From 48a0f89b134db32c8139dfe5042e72fb4f052b39 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 27 Jan 2026 17:05:57 -0300 Subject: [PATCH 10/42] Refactor DatasetsContent to remove unused imports for cleaner code --- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 2d92e128a..a5507ea84 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useRef, useCallback } from "react"; +import { useState, useEffect } from "react"; import { Box, IconButton } from "@mui/material"; import { ChevronLeft, ChevronRight } from "@mui/icons-material"; import { useSnackbar } from "notistack"; From 683185a136b458ffe001a3a7ce621547889c0aa9 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 28 Jan 2026 10:16:19 -0300 Subject: [PATCH 11/42] Refactor DatasetsContent to implement three-panel layout with dedicated LeftPanel, CenterPanel, and RightPanel components for improved UI structure and maintainability --- .../src/components/layout/ModuleContainer.jsx | 15 + .../front/src/pages/datasets/CenterPanel.jsx | 21 + .../src/pages/datasets/DatasetsContent.jsx | 386 ++++++------------ DashAI/front/src/pages/datasets/LeftPanel.jsx | 72 ++++ .../front/src/pages/datasets/RightPanel.jsx | 71 ++++ .../pages/datasets/ThreePanelLayoutContext.js | 12 + 6 files changed, 319 insertions(+), 258 deletions(-) create mode 100644 DashAI/front/src/components/layout/ModuleContainer.jsx create mode 100644 DashAI/front/src/pages/datasets/CenterPanel.jsx create mode 100644 DashAI/front/src/pages/datasets/LeftPanel.jsx create mode 100644 DashAI/front/src/pages/datasets/RightPanel.jsx create mode 100644 DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js diff --git a/DashAI/front/src/components/layout/ModuleContainer.jsx b/DashAI/front/src/components/layout/ModuleContainer.jsx new file mode 100644 index 000000000..09f693d7b --- /dev/null +++ b/DashAI/front/src/components/layout/ModuleContainer.jsx @@ -0,0 +1,15 @@ +import { Box } from "@mui/material"; + +export default function ModuleContainer({ children, ...props }) { + return ( + + {children} + + ); +} diff --git a/DashAI/front/src/pages/datasets/CenterPanel.jsx b/DashAI/front/src/pages/datasets/CenterPanel.jsx new file mode 100644 index 000000000..075100b6f --- /dev/null +++ b/DashAI/front/src/pages/datasets/CenterPanel.jsx @@ -0,0 +1,21 @@ +import { Box } from "@mui/material"; +import CenterBox from "../../components/threeSectionLayout/CenterBox"; +import { useThreePanelLayoutContext } from "./ThreePanelLayoutContext"; + +export default function CenterPanel({ children }) { + const { centerWidth, isTogglingLeft, isTogglingRight } = + useThreePanelLayoutContext(); + return ( + + {children} + + ); +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index a5507ea84..4f99c79de 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -1,16 +1,17 @@ import { useState, useEffect } from "react"; -import { Box, IconButton } from "@mui/material"; -import { ChevronLeft, ChevronRight } from "@mui/icons-material"; import { useSnackbar } from "notistack"; import { useTourContext } from "../../components/tour/TourProvider"; +import ModuleContainer from "../../components/layout/ModuleContainer"; +import LeftPanel from "./LeftPanel"; import LeftBar from "../../components/notebooks/LeftBar"; -import CenterBox from "../../components/threeSectionLayout/CenterBox"; +import CenterPanel from "./CenterPanel"; import RightBar from "../../components/notebooks/RightBar"; import SelectOptionMenu from "../../components/threeSectionLayout/SelectOptionMenu"; import UploadDatasetSteps from "../../components/notebooks/datasetCreation/UploadDatasetSteps"; import UploadNotebookSteps from "../../components/notebooks/notebookCreation/UploadNotebookSteps"; import DatasetVisualization from "../../components/DatasetVisualization"; import NotebookVisualization from "../../components/notebooks/notebook/NotebookVisualization"; +import RightPanel from "./RightPanel"; import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; @@ -22,6 +23,7 @@ import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; import { useDatasetActions } from "../../hooks/datasets/useDatasetActions"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; +import { ThreePanelLayoutContext } from "./ThreePanelLayoutContext"; import { useNotebookActions } from "../../hooks/datasets/useNotebooksActions"; import { useLayoutActions } from "../../hooks/datasets/useLayoutActions"; @@ -110,22 +112,7 @@ export default function DatasetsContent() { selectNotebookView, }); - const { - leftBarVisible, - rightBarVisible, - leftBarWidth, - rightBarWidth, - centerWidth, - - handleToggleLeft, - handleToggleRight, - - isTogglingLeft, - isTogglingRight, - - bindLeftResize, - bindRightResize, - } = useThreePanelLayout(); + const threePanelLayout = useThreePanelLayout(); const { handleAddDatasetFromNotebook, @@ -170,189 +157,122 @@ export default function DatasetsContent() { return ( <> - - {/* Left Panel */} - - {leftBarVisible && ( - <> - - - - )} - - - {!leftBarVisible && ( - - - - )} - - - {selectedNotebookId ? ( - - <> - {/* Center Panel - Notebook */} - - - - handleAddDatasetFromNotebook(name, selectedNotebook) - } - existingDatasets={datasets} - /> - - + + + + + - {!rightBarVisible && ( - - - - )} - - {/* Right Panel - Notebook */} - - {rightBarVisible && ( - <> - + {selectedNotebookId ? ( + + <> + + {selectedNotebookId ? ( + {}} + existingDatasets={datasets} + /> + ) : step === 1 && selectedOption === "dataset" ? ( + { + resetUI(); + fetchDatasets(); + setRightBarContent(null); + }} + handleDatasetCreated={handleDatasetCreated} + existingDatasets={datasets} + renderRightBar={setRightBarContent} + /> + ) : step === 1 && selectedOption === "notebook" ? ( + { + resetUI(); + fetchNotebooks(); }} + datasets={datasets} + handleNotebookCreated={handleNotebookCreated} + existingNotebooks={notebooks} + preselectedDatasetId={selectedDatasetId} /> + ) : selectedDatasetId ? ( + + ) : step === 0 ? ( + + ) : null} + + + {rightBarContent ? ( + rightBarContent + ) : ( - - )} - - - - - - ) : ( - <> - - - {step === 1 && selectedOption === "dataset" ? ( + )} + + + + + ) : ( + <> + + {selectedNotebookId ? ( + {}} + existingDatasets={datasets} + /> + ) : step === 1 && selectedOption === "dataset" ? ( { resetUI(); fetchDatasets(); - // clear right bar when exiting setRightBarContent(null); }} handleDatasetCreated={handleDatasetCreated} @@ -406,73 +326,23 @@ export default function DatasetsContent() { goToNextStep={goToNextStep} /> ) : null} - - - - {!rightBarVisible && ( - - - - )} - - - {rightBarVisible && ( - <> - + + {rightBarContent ? ( + rightBarContent + ) : ( + - {rightBarContent ? ( - rightBarContent - ) : ( - - )} - - )} - - - )} - - - {!selectedNotebookId && } + )} + + + )} + + + {!selectedNotebookId && } + ); } diff --git a/DashAI/front/src/pages/datasets/LeftPanel.jsx b/DashAI/front/src/pages/datasets/LeftPanel.jsx new file mode 100644 index 000000000..a9b455e6f --- /dev/null +++ b/DashAI/front/src/pages/datasets/LeftPanel.jsx @@ -0,0 +1,72 @@ +import { Box, IconButton } from "@mui/material"; +import { ChevronRight } from "@mui/icons-material"; +import { useThreePanelLayoutContext } from "./ThreePanelLayoutContext"; + +export default function LeftPanel({ children }) { + const { + leftBarVisible, + leftBarWidth, + isTogglingLeft, + bindLeftResize, + handleToggleLeft, + } = useThreePanelLayoutContext(); + return ( + <> + {!leftBarVisible && ( + + + + )} + + {leftBarVisible && ( + <> + {children} + + + )} + + + ); +} diff --git a/DashAI/front/src/pages/datasets/RightPanel.jsx b/DashAI/front/src/pages/datasets/RightPanel.jsx new file mode 100644 index 000000000..8d482e098 --- /dev/null +++ b/DashAI/front/src/pages/datasets/RightPanel.jsx @@ -0,0 +1,71 @@ +import { Box, IconButton } from "@mui/material"; +import { ChevronLeft } from "@mui/icons-material"; +import { useThreePanelLayoutContext } from "./ThreePanelLayoutContext"; + +export default function RightPanel({ isNotebook, children }) { + const { + rightBarVisible, + rightBarWidth, + isTogglingRight, + bindRightResize, + handleToggleRight, + } = useThreePanelLayoutContext(); + return ( + <> + {!rightBarVisible && ( + + + + )} + + {rightBarVisible && ( + <> + + {children} + + )} + + + ); +} diff --git a/DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js b/DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js new file mode 100644 index 000000000..30213b3b6 --- /dev/null +++ b/DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js @@ -0,0 +1,12 @@ +import { createContext, useContext } from "react"; + +export const ThreePanelLayoutContext = createContext(null); + +export function useThreePanelLayoutContext() { + const ctx = useContext(ThreePanelLayoutContext); + if (!ctx) + throw new Error( + "useThreePanelLayoutContext must be used within a ThreePanelLayoutProvider", + ); + return ctx; +} From 9432eb55599d9660275f8b2590e66e8236d12f82 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 28 Jan 2026 11:19:44 -0300 Subject: [PATCH 12/42] Refactor DatasetsContent and related components to reorganize panel structure, moving SideBar and CenterBox to panelContainers, and implement DatasetsCenterContent for improved layout management and maintainability --- .../src/components/generative/ParamsBar.jsx | 2 +- .../src/components/generative/SessionBar.jsx | 2 +- .../front/src/components/models/LeftBar.jsx | 2 +- .../front/src/components/models/RightBar.jsx | 2 +- .../src/components/notebooks/LeftBar.jsx | 2 +- .../src/components/notebooks/RightBar.jsx | 2 +- .../{ => panelContainers}/CenterBox.jsx | 0 .../{ => panelContainers}/SideBar.jsx | 0 .../panels}/CenterPanel.jsx | 2 +- .../threeSectionLayout/panels}/LeftPanel.jsx | 0 .../threeSectionLayout/panels}/RightPanel.jsx | 0 .../panels}/ThreePanelLayoutContext.js | 0 .../pages/datasets/DatasetsCenterContent.jsx | 101 +++++++++ .../src/pages/datasets/DatasetsContent.jsx | 207 +++++------------- .../front/src/pages/generative/Generative.jsx | 2 +- .../front/src/pages/models/ModelsContent.jsx | 2 +- 16 files changed, 166 insertions(+), 160 deletions(-) rename DashAI/front/src/components/threeSectionLayout/{ => panelContainers}/CenterBox.jsx (100%) rename DashAI/front/src/components/threeSectionLayout/{ => panelContainers}/SideBar.jsx (100%) rename DashAI/front/src/{pages/datasets => components/threeSectionLayout/panels}/CenterPanel.jsx (89%) rename DashAI/front/src/{pages/datasets => components/threeSectionLayout/panels}/LeftPanel.jsx (100%) rename DashAI/front/src/{pages/datasets => components/threeSectionLayout/panels}/RightPanel.jsx (100%) rename DashAI/front/src/{pages/datasets => components/threeSectionLayout/panels}/ThreePanelLayoutContext.js (100%) create mode 100644 DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx diff --git a/DashAI/front/src/components/generative/ParamsBar.jsx b/DashAI/front/src/components/generative/ParamsBar.jsx index c94639463..cd997fda8 100644 --- a/DashAI/front/src/components/generative/ParamsBar.jsx +++ b/DashAI/front/src/components/generative/ParamsBar.jsx @@ -12,7 +12,7 @@ import { updateGenerativeSessionParams, } from "../../api/generativeTask"; import { preprocessSchema, buildYupSchema } from "./utils"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import { useTranslation } from "react-i18next"; export default function ParamsBar({ diff --git a/DashAI/front/src/components/generative/SessionBar.jsx b/DashAI/front/src/components/generative/SessionBar.jsx index 506690a0c..c2be7628c 100644 --- a/DashAI/front/src/components/generative/SessionBar.jsx +++ b/DashAI/front/src/components/generative/SessionBar.jsx @@ -7,7 +7,7 @@ import InfoSessionModal from "./InfoSessionModal"; import Footer from "./Footer"; import SessionList from "./SessionList"; import NewItemButton from "../threeSectionLayout/NewItemButton"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import BarHeader from "../threeSectionLayout/BarHeader"; import { useTranslation } from "react-i18next"; diff --git a/DashAI/front/src/components/models/LeftBar.jsx b/DashAI/front/src/components/models/LeftBar.jsx index 1109e2ee5..dab468f2c 100644 --- a/DashAI/front/src/components/models/LeftBar.jsx +++ b/DashAI/front/src/components/models/LeftBar.jsx @@ -6,7 +6,7 @@ import StorageIcon from "@mui/icons-material/Storage"; import Biotech from "@mui/icons-material/Biotech"; import Footer from "../threeSectionLayout/Footer"; import BarHeader from "../threeSectionLayout/BarHeader"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import CollapsibleList from "../threeSectionLayout/CollapsibleList"; import GroupedCollapsibleList from "../threeSectionLayout/GroupedCollapsibleList"; import SearchBar from "../threeSectionLayout/SearchBar"; diff --git a/DashAI/front/src/components/models/RightBar.jsx b/DashAI/front/src/components/models/RightBar.jsx index 855abd3d4..a63d2a1fa 100644 --- a/DashAI/front/src/components/models/RightBar.jsx +++ b/DashAI/front/src/components/models/RightBar.jsx @@ -10,7 +10,7 @@ import { import { useTheme } from "@mui/material/styles"; import { ChevronRight, Search as SearchIcon } from "@mui/icons-material"; import { useSnackbar } from "notistack"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import { getComponents } from "../../api/component"; import ModelListItem from "./model/ModelListItem"; import { useTranslation } from "react-i18next"; diff --git a/DashAI/front/src/components/notebooks/LeftBar.jsx b/DashAI/front/src/components/notebooks/LeftBar.jsx index 8c299c879..98c03dc87 100644 --- a/DashAI/front/src/components/notebooks/LeftBar.jsx +++ b/DashAI/front/src/components/notebooks/LeftBar.jsx @@ -7,7 +7,7 @@ import BarHeader from "../threeSectionLayout/BarHeader"; import CollapsibleList from "../threeSectionLayout/CollapsibleList"; import SearchBar from "../threeSectionLayout/SearchBar"; import NewItemButton from "../threeSectionLayout/NewItemButton"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import InfoNotebookModal from "./notebook/InfoNotebookModal"; import { ChevronLeft } from "@mui/icons-material"; import { useTranslation } from "react-i18next"; diff --git a/DashAI/front/src/components/notebooks/RightBar.jsx b/DashAI/front/src/components/notebooks/RightBar.jsx index 159dfe5cd..304c7b272 100644 --- a/DashAI/front/src/components/notebooks/RightBar.jsx +++ b/DashAI/front/src/components/notebooks/RightBar.jsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import SideBar from "../threeSectionLayout/SideBar"; +import SideBar from "../threeSectionLayout/panelContainers/SideBar"; import { Box, Typography, diff --git a/DashAI/front/src/components/threeSectionLayout/CenterBox.jsx b/DashAI/front/src/components/threeSectionLayout/panelContainers/CenterBox.jsx similarity index 100% rename from DashAI/front/src/components/threeSectionLayout/CenterBox.jsx rename to DashAI/front/src/components/threeSectionLayout/panelContainers/CenterBox.jsx diff --git a/DashAI/front/src/components/threeSectionLayout/SideBar.jsx b/DashAI/front/src/components/threeSectionLayout/panelContainers/SideBar.jsx similarity index 100% rename from DashAI/front/src/components/threeSectionLayout/SideBar.jsx rename to DashAI/front/src/components/threeSectionLayout/panelContainers/SideBar.jsx diff --git a/DashAI/front/src/pages/datasets/CenterPanel.jsx b/DashAI/front/src/components/threeSectionLayout/panels/CenterPanel.jsx similarity index 89% rename from DashAI/front/src/pages/datasets/CenterPanel.jsx rename to DashAI/front/src/components/threeSectionLayout/panels/CenterPanel.jsx index 075100b6f..c245b96db 100644 --- a/DashAI/front/src/pages/datasets/CenterPanel.jsx +++ b/DashAI/front/src/components/threeSectionLayout/panels/CenterPanel.jsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import CenterBox from "../../components/threeSectionLayout/CenterBox"; +import CenterBox from "../panelContainers/CenterBox"; import { useThreePanelLayoutContext } from "./ThreePanelLayoutContext"; export default function CenterPanel({ children }) { diff --git a/DashAI/front/src/pages/datasets/LeftPanel.jsx b/DashAI/front/src/components/threeSectionLayout/panels/LeftPanel.jsx similarity index 100% rename from DashAI/front/src/pages/datasets/LeftPanel.jsx rename to DashAI/front/src/components/threeSectionLayout/panels/LeftPanel.jsx diff --git a/DashAI/front/src/pages/datasets/RightPanel.jsx b/DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx similarity index 100% rename from DashAI/front/src/pages/datasets/RightPanel.jsx rename to DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx diff --git a/DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js b/DashAI/front/src/components/threeSectionLayout/panels/ThreePanelLayoutContext.js similarity index 100% rename from DashAI/front/src/pages/datasets/ThreePanelLayoutContext.js rename to DashAI/front/src/components/threeSectionLayout/panels/ThreePanelLayoutContext.js diff --git a/DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx b/DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx new file mode 100644 index 000000000..569b9911c --- /dev/null +++ b/DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx @@ -0,0 +1,101 @@ +import NotebookVisualization from "../../components/notebooks/notebook/NotebookVisualization"; +import UploadDatasetSteps from "../../components/notebooks/datasetCreation/UploadDatasetSteps"; +import UploadNotebookSteps from "../../components/notebooks/notebookCreation/UploadNotebookSteps"; +import DatasetVisualization from "../../components/DatasetVisualization"; +import SelectOptionMenu from "../../components/threeSectionLayout/SelectOptionMenu"; + +export default function DatasetsCenterContent({ + selectedNotebookId, + selectedNotebook, + step, + selectedOption, + selectedDatasetId, + selectedDataset, + datasets, + notebooks, + t, + goToNextStep, + resetUI, + fetchDatasets, + fetchNotebooks, + setRightBarContent, + handleDatasetCreated, + handleNotebookCreated, + handleNewNotebookFromDataset, +}) { + if (selectedNotebookId) { + return ( + {}} + existingDatasets={datasets} + /> + ); + } + if (step === 1 && selectedOption === "dataset") { + return ( + { + resetUI(); + fetchDatasets(); + setRightBarContent(null); + }} + handleDatasetCreated={handleDatasetCreated} + existingDatasets={datasets} + renderRightBar={setRightBarContent} + /> + ); + } + if (step === 1 && selectedOption === "notebook") { + return ( + { + resetUI(); + fetchNotebooks(); + }} + datasets={datasets} + handleNotebookCreated={handleNotebookCreated} + existingNotebooks={notebooks} + preselectedDatasetId={selectedDatasetId} + /> + ); + } + if (selectedDatasetId) { + return ( + + ); + } + if (step === 0) { + return ( + + ); + } + return null; +} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 4f99c79de..958300805 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -2,16 +2,12 @@ import { useState, useEffect } from "react"; import { useSnackbar } from "notistack"; import { useTourContext } from "../../components/tour/TourProvider"; import ModuleContainer from "../../components/layout/ModuleContainer"; -import LeftPanel from "./LeftPanel"; +import LeftPanel from "../../components/threeSectionLayout/panels/LeftPanel"; import LeftBar from "../../components/notebooks/LeftBar"; -import CenterPanel from "./CenterPanel"; +import CenterPanel from "../../components/threeSectionLayout/panels/CenterPanel"; import RightBar from "../../components/notebooks/RightBar"; -import SelectOptionMenu from "../../components/threeSectionLayout/SelectOptionMenu"; -import UploadDatasetSteps from "../../components/notebooks/datasetCreation/UploadDatasetSteps"; -import UploadNotebookSteps from "../../components/notebooks/notebookCreation/UploadNotebookSteps"; -import DatasetVisualization from "../../components/DatasetVisualization"; -import NotebookVisualization from "../../components/notebooks/notebook/NotebookVisualization"; -import RightPanel from "./RightPanel"; +import RightPanel from "../../components/threeSectionLayout/panels/RightPanel"; +import DatasetsCenterContent from "./DatasetsCenterContent"; import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; @@ -23,7 +19,7 @@ import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; import { useDatasetActions } from "../../hooks/datasets/useDatasetActions"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; -import { ThreePanelLayoutContext } from "./ThreePanelLayoutContext"; +import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; import { useNotebookActions } from "../../hooks/datasets/useNotebooksActions"; import { useLayoutActions } from "../../hooks/datasets/useLayoutActions"; @@ -114,20 +110,17 @@ export default function DatasetsContent() { const threePanelLayout = useThreePanelLayout(); - const { - handleAddDatasetFromNotebook, - handleNotebookCreated, - handleNewNotebookFromDataset, - } = useNotebookActions({ - fetchNotebooks, - selectNotebook, - clearSelectedNotebook, - clearSelectedDataset, - selectNotebookView, - selectDatasetView, - goToNotebookCreation, - createDatasetFromNotebook, - }); + const { handleNotebookCreated, handleNewNotebookFromDataset } = + useNotebookActions({ + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + clearSelectedDataset, + selectNotebookView, + selectDatasetView, + goToNotebookCreation, + createDatasetFromNotebook, + }); const { goToNextStep, handleNewSessionButton, handleDatasetCreated } = useLayoutActions({ @@ -181,70 +174,27 @@ export default function DatasetsContent() { <> - {selectedNotebookId ? ( - {}} - existingDatasets={datasets} - /> - ) : step === 1 && selectedOption === "dataset" ? ( - { - resetUI(); - fetchDatasets(); - setRightBarContent(null); - }} - handleDatasetCreated={handleDatasetCreated} - existingDatasets={datasets} - renderRightBar={setRightBarContent} - /> - ) : step === 1 && selectedOption === "notebook" ? ( - { - resetUI(); - fetchNotebooks(); - }} - datasets={datasets} - handleNotebookCreated={handleNotebookCreated} - existingNotebooks={notebooks} - preselectedDatasetId={selectedDatasetId} - /> - ) : selectedDatasetId ? ( - - ) : step === 0 ? ( - - ) : null} + {rightBarContent ? ( @@ -262,70 +212,25 @@ export default function DatasetsContent() { ) : ( <> - {selectedNotebookId ? ( - {}} - existingDatasets={datasets} - /> - ) : step === 1 && selectedOption === "dataset" ? ( - { - resetUI(); - fetchDatasets(); - setRightBarContent(null); - }} - handleDatasetCreated={handleDatasetCreated} - existingDatasets={datasets} - renderRightBar={setRightBarContent} - /> - ) : step === 1 && selectedOption === "notebook" ? ( - { - resetUI(); - fetchNotebooks(); - }} - datasets={datasets} - handleNotebookCreated={handleNotebookCreated} - existingNotebooks={notebooks} - preselectedDatasetId={selectedDatasetId} - /> - ) : selectedDatasetId ? ( - - ) : step === 0 ? ( - - ) : null} + {rightBarContent ? ( diff --git a/DashAI/front/src/pages/generative/Generative.jsx b/DashAI/front/src/pages/generative/Generative.jsx index d7dafe56c..427f9877d 100644 --- a/DashAI/front/src/pages/generative/Generative.jsx +++ b/DashAI/front/src/pages/generative/Generative.jsx @@ -7,7 +7,7 @@ import SelectModelMenu from "../../components/generative/SelectModelMenu"; import ParamsBar from "../../components/generative/ParamsBar"; import { getSessions, removeSession } from "../../api/session"; import JobQueueWidget from "../../components/jobs/JobQueueWidget"; -import CenterBox from "../../components/threeSectionLayout/CenterBox"; +import CenterBox from "../../components/threeSectionLayout/panelContainers/CenterBox"; export default function Generative() { const [stepIndex, setStepIndex] = useState(0); diff --git a/DashAI/front/src/pages/models/ModelsContent.jsx b/DashAI/front/src/pages/models/ModelsContent.jsx index e6498b601..722124627 100644 --- a/DashAI/front/src/pages/models/ModelsContent.jsx +++ b/DashAI/front/src/pages/models/ModelsContent.jsx @@ -8,7 +8,7 @@ import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import LeftBar from "../../components/models/LeftBar"; -import CenterBox from "../../components/threeSectionLayout/CenterBox"; +import CenterBox from "../../components/threeSectionLayout/panelContainers/CenterBox"; import RightBar from "../../components/models/RightBar"; import SelectOptionMenu from "../../components/threeSectionLayout/SelectOptionMenu"; import CreateSessionSteps from "../../components/models/CreateSessionSteps"; From 5e4cfdee290d63dda9c2b51cb0a595fe405d657f Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 28 Jan 2026 11:22:33 -0300 Subject: [PATCH 13/42] Refactor DatasetsContent to import DatasetsCenterContent from the correct path for improved module organization --- .../notebooks/dataset}/DatasetsCenterContent.jsx | 10 +++++----- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename DashAI/front/src/{pages/datasets => components/notebooks/dataset}/DatasetsCenterContent.jsx (84%) diff --git a/DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx similarity index 84% rename from DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx rename to DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 569b9911c..1c62d2657 100644 --- a/DashAI/front/src/pages/datasets/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -1,8 +1,8 @@ -import NotebookVisualization from "../../components/notebooks/notebook/NotebookVisualization"; -import UploadDatasetSteps from "../../components/notebooks/datasetCreation/UploadDatasetSteps"; -import UploadNotebookSteps from "../../components/notebooks/notebookCreation/UploadNotebookSteps"; -import DatasetVisualization from "../../components/DatasetVisualization"; -import SelectOptionMenu from "../../components/threeSectionLayout/SelectOptionMenu"; +import NotebookVisualization from "../notebook/NotebookVisualization"; +import UploadDatasetSteps from "../datasetCreation/UploadDatasetSteps"; +import UploadNotebookSteps from "../notebookCreation/UploadNotebookSteps"; +import DatasetVisualization from "../../DatasetVisualization"; +import SelectOptionMenu from "../../threeSectionLayout/SelectOptionMenu"; export default function DatasetsCenterContent({ selectedNotebookId, diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 958300805..613740964 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -7,7 +7,7 @@ import LeftBar from "../../components/notebooks/LeftBar"; import CenterPanel from "../../components/threeSectionLayout/panels/CenterPanel"; import RightBar from "../../components/notebooks/RightBar"; import RightPanel from "../../components/threeSectionLayout/panels/RightPanel"; -import DatasetsCenterContent from "./DatasetsCenterContent"; +import DatasetsCenterContent from "../../components/notebooks/dataset/DatasetsCenterContent"; import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; From cb9707e40928ffffc2c8a62ed73e44639660bf25 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 28 Jan 2026 11:52:24 -0300 Subject: [PATCH 14/42] Refactor RightPanel to accept toggleButtonTop prop for dynamic positioning in DatasetsContent --- .../src/components/threeSectionLayout/panels/RightPanel.jsx | 5 ++--- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx b/DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx index 8d482e098..c8ee71230 100644 --- a/DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx +++ b/DashAI/front/src/components/threeSectionLayout/panels/RightPanel.jsx @@ -1,8 +1,7 @@ import { Box, IconButton } from "@mui/material"; import { ChevronLeft } from "@mui/icons-material"; import { useThreePanelLayoutContext } from "./ThreePanelLayoutContext"; - -export default function RightPanel({ isNotebook, children }) { +export default function RightPanel({ toggleButtonTop = "50%", children }) { const { rightBarVisible, rightBarWidth, @@ -18,7 +17,7 @@ export default function RightPanel({ isNotebook, children }) { sx={{ position: "absolute", right: 8, - top: isNotebook ? "calc(50% + 60px)" : "50%", + top: toggleButtonTop, transform: "translateY(-50%)", bgcolor: "background.paper", zIndex: 10, diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 613740964..61d87f92b 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -196,7 +196,7 @@ export default function DatasetsContent() { } /> - + {rightBarContent ? ( rightBarContent ) : ( @@ -232,7 +232,7 @@ export default function DatasetsContent() { handleNewNotebookFromDataset={handleNewNotebookFromDataset} /> - + {rightBarContent ? ( rightBarContent ) : ( From c6d32eaed295e951a8229b37ba38d1aaba88e3f2 Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 30 Jan 2026 18:10:08 -0300 Subject: [PATCH 15/42] Refactor DatasetVisualization component to streamline imports and improve code readability --- DashAI/front/src/components/DatasetVisualization.jsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/DashAI/front/src/components/DatasetVisualization.jsx b/DashAI/front/src/components/DatasetVisualization.jsx index ee84890c9..45c0051a9 100644 --- a/DashAI/front/src/components/DatasetVisualization.jsx +++ b/DashAI/front/src/components/DatasetVisualization.jsx @@ -2,32 +2,23 @@ import { useCallback, useState, useEffect } from "react"; import { Button, Grid, - Paper, Typography, CircularProgress, Box, - Chip, Alert, Divider, Tabs, Tab, } from "@mui/material"; import { useTheme } from "@mui/material/styles"; -import { - AddCircleOutline as AddIcon, - CheckCircle as CheckIcon, -} from "@mui/icons-material"; +import { AddCircleOutline as AddIcon } from "@mui/icons-material"; import { getDatasetFile, getDatasetInfo, getDatasetFileFiltered, } from "../api/datasets"; -import DatasetTable from "./notebooks/dataset/DatasetTable"; -import { getComponents } from "../api/component"; import { useTourContext } from "./tour/TourProvider"; -import { useSnackbar } from "notistack"; import JobQueueWidget from "./jobs/JobQueueWidget"; -import { getDatasetStatus } from "../utils/datasetStatus"; import { formatDate } from "../pages/results/constants/formatDate"; import Header from "./notebooks/dataset/header/Header"; import Tooltip from "@mui/material/Tooltip"; From f0d261a36c557be9f91b20175ee332f80bb31bdd Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 30 Jan 2026 18:10:14 -0300 Subject: [PATCH 16/42] Add tourContextType prop to DatasetVisualization for enhanced tour functionality --- .../src/components/notebooks/dataset/DatasetsCenterContent.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 1c62d2657..2ffb59873 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -68,6 +68,7 @@ export default function DatasetsCenterContent({ onNewItem={handleNewNotebookFromDataset} existingItems={notebooks} newItemButtonText={t("datasets:button.newNotebook")} + tourContextType="datasets" /> ); } From 36e307d6318b1110585a49657248dc4c2f126995 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 00:20:14 -0300 Subject: [PATCH 17/42] Refactor dataset handling in DatasetsContent and related components for improved functionality and code clarity --- .../dataset/DatasetsCenterContent.jsx | 3 +- .../notebook/DatasetPreviewNotebook.jsx | 7 +- .../src/hooks/datasets/useDatasetActions.js | 62 -------- .../src/hooks/datasets/useDatasetFlow.js | 15 +- .../front/src/hooks/datasets/useDatasets.js | 6 +- .../src/hooks/datasets/useLayoutActions.js | 53 ------- .../front/src/hooks/datasets/useNotebooks.js | 4 +- .../src/hooks/datasets/useNotebooksActions.js | 36 ----- .../src/pages/datasets/DatasetsContent.jsx | 137 ++++++++++-------- 9 files changed, 101 insertions(+), 222 deletions(-) delete mode 100644 DashAI/front/src/hooks/datasets/useDatasetActions.js delete mode 100644 DashAI/front/src/hooks/datasets/useLayoutActions.js delete mode 100644 DashAI/front/src/hooks/datasets/useNotebooksActions.js diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 2ffb59873..f02628f1b 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -22,12 +22,13 @@ export default function DatasetsCenterContent({ handleDatasetCreated, handleNotebookCreated, handleNewNotebookFromDataset, + handleAddDatasetFromNotebook, }) { if (selectedNotebookId) { return ( {}} + handleAddDatasetFromNotebook={handleAddDatasetFromNotebook} existingDatasets={datasets} /> ); diff --git a/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx b/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx index 701c2f811..8fb678257 100644 --- a/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx +++ b/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx @@ -21,6 +21,7 @@ import { NotebookHistoryModal } from "./NotebookHistoryModal"; import { useExplorersAndConverters } from "../context/ExplorersAndConvertersContext"; import { useTourContext } from "../../tour/TourProvider"; import { useTranslation } from "react-i18next"; +import { useDatasets } from "../../../hooks/datasets/useDatasets"; export default function DatasetPreviewNotebook({ notebook, @@ -102,6 +103,8 @@ export default function DatasetPreviewNotebook({ }; }, [notebook, explorersAndConverters]); + const { createDatasetFromNotebook } = useDatasets({ t }); + return ( setShowSaveDatasetModal(false)} - onSaveDataset={handleAddDatasetFromNotebook} + onSaveDataset={(name) => + handleAddDatasetFromNotebook(name, notebook.id) + } appliedConverters={converters.filter( (converter) => converter.status === 3, )} diff --git a/DashAI/front/src/hooks/datasets/useDatasetActions.js b/DashAI/front/src/hooks/datasets/useDatasetActions.js deleted file mode 100644 index 1e1891897..000000000 --- a/DashAI/front/src/hooks/datasets/useDatasetActions.js +++ /dev/null @@ -1,62 +0,0 @@ -export function useDatasetActions({ - selectedDatasetId, - selectedNotebookId, - - selectDataset, - selectNotebook, - clearSelectedDataset, - clearSelectedNotebook, - - deleteDatasetLocal, - deleteDatasetRemote, - removeNotebooksByDatasetId, - deleteNotebookById, - - editDataset, - editNotebook, - - resetUI, - selectDatasetView, - selectNotebookView, -}) { - const handleDatasetClick = (id) => { - selectDataset(id); - clearSelectedNotebook(); - selectDatasetView(); - }; - - const handleNotebookClick = (id) => { - selectNotebook(id); - clearSelectedDataset(); - selectNotebookView(); - }; - - const handleDatasetDelete = async (id) => { - if (id === selectedDatasetId) { - clearSelectedDataset(); - resetUI(); - } - - deleteDatasetLocal(id); - removeNotebooksByDatasetId(id); - await deleteDatasetRemote(id); - }; - - const handleNotebookDelete = (id) => { - deleteNotebookById(id); - - if (id === selectedNotebookId) { - clearSelectedNotebook(); - resetUI(); - } - }; - - return { - handleDatasetClick, - handleNotebookClick, - handleDatasetDelete, - handleNotebookDelete, - handleEditDataset: editDataset, - handleEditNotebook: editNotebook, - }; -} diff --git a/DashAI/front/src/hooks/datasets/useDatasetFlow.js b/DashAI/front/src/hooks/datasets/useDatasetFlow.js index 56f85d12c..ba884cf56 100644 --- a/DashAI/front/src/hooks/datasets/useDatasetFlow.js +++ b/DashAI/front/src/hooks/datasets/useDatasetFlow.js @@ -1,6 +1,7 @@ import { startJobPolling } from "../../utils/jobPoller"; import { enqueueDatasetJob } from "../../api/job"; import { createDataset, deleteDataset } from "../../api/datasets"; +import { useSnackbar } from "notistack"; export function useDatasetFlow({ datasets, @@ -10,10 +11,12 @@ export function useDatasetFlow({ addDatasetOptimistically, selectDataset, clearSelectedDataset, - enqueueSnackbar, t, - resetUIAfterFailure, + resetUI, + deleteDatasetRemote, }) { + const { enqueueSnackbar } = useSnackbar(); + const pollForDataset = ({ datasetId, datasetName }, { jobId }) => { if (!jobId) return; @@ -62,13 +65,19 @@ export function useDatasetFlow({ deleteDatasetRemote(datasetId).catch(console.error); clearSelectedDataset(); - resetUIAfterFailure(); + resetUI(); }, ); }; const createDatasetFromNotebook = async (name, notebookId) => { try { + console.log( + "Creating dataset from notebook:", + notebookId, + "with name:", + name, + ); const dataset = await createDataset(name); enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index a8ea6525e..f46985dc3 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -1,4 +1,6 @@ import { useState, useCallback } from "react"; +import { useSnackbar } from "notistack"; +import { enqueueDatasetJob } from "../../api/job"; import { getDatasets, deleteDataset, @@ -7,9 +9,9 @@ import { createDataset, } from "../../api/datasets"; import { startJobPolling } from "../../utils/jobPoller"; -import { replace } from "formik"; -export function useDatasets({ enqueueSnackbar, t }) { +export function useDatasets({ t }) { + const { enqueueSnackbar } = useSnackbar(); const [datasets, setDatasets] = useState([]); const [selectedDatasetId, setSelectedDatasetId] = useState(null); diff --git a/DashAI/front/src/hooks/datasets/useLayoutActions.js b/DashAI/front/src/hooks/datasets/useLayoutActions.js deleted file mode 100644 index bb67257a5..000000000 --- a/DashAI/front/src/hooks/datasets/useLayoutActions.js +++ /dev/null @@ -1,53 +0,0 @@ -export function useLayoutActions({ - goToDatasetFlow, - goToNotebookFlow, - resetUI, - - clearSelectedDataset, - clearSelectedNotebook, - - selectDatasetView, - - addDatasetOptimistically, - startDatasetPolling, - - setRightBarContent, - tourContext, -}) { - const goToNextStep = (option) => { - if (option === "dataset") { - goToDatasetFlow(); - } else { - goToNotebookFlow(); - } - - clearSelectedDataset(); - clearSelectedNotebook(); - - if (option === "dataset" && tourContext?.run) { - setTimeout(() => { - tourContext.nextStep(); - }, 600); - } - }; - - const handleNewSessionButton = () => { - clearSelectedDataset(); - clearSelectedNotebook(); - resetUI(); - }; - - const handleDatasetCreated = (newDataset, datasetJob) => { - addDatasetOptimistically(newDataset); - selectDatasetView(); - clearSelectedNotebook(); - setRightBarContent(null); - startDatasetPolling(newDataset, datasetJob); - }; - - return { - goToNextStep, - handleNewSessionButton, - handleDatasetCreated, - }; -} diff --git a/DashAI/front/src/hooks/datasets/useNotebooks.js b/DashAI/front/src/hooks/datasets/useNotebooks.js index 322b78fbd..531d0e437 100644 --- a/DashAI/front/src/hooks/datasets/useNotebooks.js +++ b/DashAI/front/src/hooks/datasets/useNotebooks.js @@ -1,11 +1,13 @@ import { useState, useCallback } from "react"; +import { useSnackbar } from "notistack"; import { getNotebooks, deleteNotebook, updateNotebook, } from "../../api/notebook"; -export function useNotebooks({ enqueueSnackbar, t }) { +export function useNotebooks({ t }) { + const { enqueueSnackbar } = useSnackbar(); const [notebooks, setNotebooks] = useState([]); const [selectedNotebookId, setSelectedNotebookId] = useState(null); diff --git a/DashAI/front/src/hooks/datasets/useNotebooksActions.js b/DashAI/front/src/hooks/datasets/useNotebooksActions.js deleted file mode 100644 index 1d78fe718..000000000 --- a/DashAI/front/src/hooks/datasets/useNotebooksActions.js +++ /dev/null @@ -1,36 +0,0 @@ -export function useNotebookActions({ - fetchNotebooks, - selectNotebook, - clearSelectedNotebook, - clearSelectedDataset, - selectNotebookView, - selectDatasetView, - goToNotebookCreation, - createDatasetFromNotebook, -}) { - const handleAddDatasetFromNotebook = async (name, selectedNotebook) => { - if (!selectedNotebook) return; - - clearSelectedNotebook(); - selectDatasetView(); - - createDatasetFromNotebook(name, selectedNotebook.id); - }; - - const handleNotebookCreated = async (createdNotebook) => { - await fetchNotebooks(); - selectNotebookView(); - selectNotebook(createdNotebook.id); - clearSelectedDataset(); - }; - - const handleNewNotebookFromDataset = () => { - goToNotebookCreation(); - }; - - return { - handleAddDatasetFromNotebook, - handleNotebookCreated, - handleNewNotebookFromDataset, - }; -} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 61d87f92b..d545ab517 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -1,5 +1,4 @@ import { useState, useEffect } from "react"; -import { useSnackbar } from "notistack"; import { useTourContext } from "../../components/tour/TourProvider"; import ModuleContainer from "../../components/layout/ModuleContainer"; import LeftPanel from "../../components/threeSectionLayout/panels/LeftPanel"; @@ -16,23 +15,19 @@ import { useTranslation } from "react-i18next"; import { useDatasets } from "../../hooks/datasets/useDatasets"; import { useNotebooks } from "../../hooks/datasets/useNotebooks"; import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; -import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; -import { useDatasetActions } from "../../hooks/datasets/useDatasetActions"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; -import { useNotebookActions } from "../../hooks/datasets/useNotebooksActions"; -import { useLayoutActions } from "../../hooks/datasets/useLayoutActions"; +import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; export default function DatasetsContent() { const [rightBarContent, setRightBarContent] = useState(null); const tourContext = useTourContext(); - const { enqueueSnackbar } = useSnackbar(); const { t } = useTranslation(["datasets", "common"]); + const threePanelLayout = useThreePanelLayout(); const { datasets, selectedDatasetId, - enrichDatasetsWithInfo, fetchDatasets, selectDataset, clearSelectedDataset, @@ -40,9 +35,10 @@ export default function DatasetsContent() { deleteDatasetRemote, editDataset, addDatasetOptimistically, - startDatasetPolling, + enrichDatasetsWithInfo, replaceDatasets, - } = useDatasets({ enqueueSnackbar, t }); + startDatasetPolling, + } = useDatasets({ t }); const { notebooks, @@ -53,7 +49,7 @@ export default function DatasetsContent() { deleteNotebookById, editNotebook, removeNotebooksByDatasetId, - } = useNotebooks({ enqueueSnackbar, t }); + } = useNotebooks({ t }); const { step, @@ -71,74 +67,87 @@ export default function DatasetsContent() { enrichDatasetsWithInfo, fetchDatasets, replaceDatasets, + addDatasetOptimistically, selectDataset, clearSelectedDataset, - deleteDatasetRemote, - enqueueSnackbar, t, resetUI, + deleteDatasetRemote, }); - const { - handleDatasetClick, - handleNotebookClick, - handleDatasetDelete, - handleNotebookDelete, - handleEditDataset, - handleEditNotebook, - } = useDatasetActions({ - selectedDatasetId, - selectedNotebookId, + const handleDatasetClick = (id) => { + selectDataset(id); + clearSelectedNotebook(); + selectDatasetView(); + }; - selectDataset, - selectNotebook, - clearSelectedDataset, - clearSelectedNotebook, + const handleNotebookClick = (id) => { + selectNotebook(id); + clearSelectedDataset(); + selectNotebookView(); + }; - deleteDatasetLocal, - deleteDatasetRemote, - removeNotebooksByDatasetId, - deleteNotebookById, + const handleDatasetDelete = async (id) => { + if (id === selectedDatasetId) { + clearSelectedDataset(); + resetUI(); + } - editDataset, - editNotebook, + deleteDatasetLocal(id); + removeNotebooksByDatasetId(id); + await deleteDatasetRemote(id); + }; - resetUI, - selectDatasetView, - selectNotebookView, - }); + const handleNotebookDelete = (id) => { + deleteNotebookById(id); - const threePanelLayout = useThreePanelLayout(); + if (id === selectedNotebookId) { + clearSelectedNotebook(); + resetUI(); + } + }; + + const handleNotebookCreated = async (createdNotebook) => { + await fetchNotebooks(); + selectNotebookView(); + selectNotebook(createdNotebook.id); + clearSelectedDataset(); + }; - const { handleNotebookCreated, handleNewNotebookFromDataset } = - useNotebookActions({ - fetchNotebooks, - selectNotebook, - clearSelectedNotebook, - clearSelectedDataset, - selectNotebookView, - selectDatasetView, - goToNotebookCreation, - createDatasetFromNotebook, - }); + const handleNewNotebookFromDataset = () => { + goToNotebookCreation(); + }; - const { goToNextStep, handleNewSessionButton, handleDatasetCreated } = - useLayoutActions({ - goToDatasetFlow, - goToNotebookFlow, - resetUI, + const goToNextStep = (option) => { + if (option === "dataset") { + goToDatasetFlow(); + } else { + goToNotebookFlow(); + } - clearSelectedDataset, - clearSelectedNotebook, + clearSelectedDataset(); + clearSelectedNotebook(); - selectDatasetView, + if (option === "dataset" && tourContext?.run) { + setTimeout(() => { + tourContext.nextStep(); + }, 600); + } + }; - addDatasetOptimistically, - startDatasetPolling, + const handleNewSessionButton = () => { + clearSelectedDataset(); + clearSelectedNotebook(); + resetUI(); + }; - setRightBarContent, - tourContext, - }); + const handleDatasetCreated = (newDataset, datasetJob) => { + addDatasetOptimistically(newDataset); + selectDatasetView(); + clearSelectedNotebook(); + setRightBarContent(null); + startDatasetPolling(newDataset, datasetJob); + }; useEffect(() => { fetchDatasets(); @@ -160,10 +169,10 @@ export default function DatasetsContent() { selectedNotebookId={selectedNotebookId} onDatasetClick={handleDatasetClick} onDatasetDelete={handleDatasetDelete} - onDatasetEdit={handleEditDataset} + onDatasetEdit={editDataset} onNotebookClick={handleNotebookClick} onNotebookDelete={handleNotebookDelete} - onNotebookEdit={handleEditNotebook} + onNotebookEdit={editNotebook} handleNewSessionButton={handleNewSessionButton} onToggle={threePanelLayout.handleToggleLeft} /> @@ -194,6 +203,7 @@ export default function DatasetsContent() { handleNewNotebookFromDataset={ handleNewNotebookFromDataset } + handleAddDatasetFromNotebook={createDatasetFromNotebook} /> @@ -230,6 +240,7 @@ export default function DatasetsContent() { handleDatasetCreated={handleDatasetCreated} handleNotebookCreated={handleNotebookCreated} handleNewNotebookFromDataset={handleNewNotebookFromDataset} + handleAddDatasetFromNotebook={createDatasetFromNotebook} /> From 3ca121646fbdec89efa143a88c5406453e2a406e Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 10:54:37 -0300 Subject: [PATCH 18/42] Rename DatasetsNotebooksLeftBar component for better clarity --- .../notebooks/{LeftBar.jsx => DatasetNotebookLeftBar.jsx} | 2 +- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename DashAI/front/src/components/notebooks/{LeftBar.jsx => DatasetNotebookLeftBar.jsx} (99%) diff --git a/DashAI/front/src/components/notebooks/LeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx similarity index 99% rename from DashAI/front/src/components/notebooks/LeftBar.jsx rename to DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 98c03dc87..d3e452d73 100644 --- a/DashAI/front/src/components/notebooks/LeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -12,7 +12,7 @@ import InfoNotebookModal from "./notebook/InfoNotebookModal"; import { ChevronLeft } from "@mui/icons-material"; import { useTranslation } from "react-i18next"; -export default function DatasetsNotebooksBar({ +export default function DatasetsNotebooksLeftBar({ datasets = [], selectedDatasetId, notebooks = [], diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index d545ab517..1cae049ad 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { useTourContext } from "../../components/tour/TourProvider"; import ModuleContainer from "../../components/layout/ModuleContainer"; import LeftPanel from "../../components/threeSectionLayout/panels/LeftPanel"; -import LeftBar from "../../components/notebooks/LeftBar"; +import DatasetsNotebooksLeftBar from "../../components/notebooks/DatasetNotebookLeftBar"; import CenterPanel from "../../components/threeSectionLayout/panels/CenterPanel"; import RightBar from "../../components/notebooks/RightBar"; import RightPanel from "../../components/threeSectionLayout/panels/RightPanel"; @@ -162,7 +162,7 @@ export default function DatasetsContent() { - Date: Tue, 3 Feb 2026 12:06:02 -0300 Subject: [PATCH 19/42] Adds new DatasetAndNotebooks context and provider to manage all the shared states of dataset page --- .../contexts/DatasetsAndNotebooksContext.jsx | 84 ++++++++++ .../notebooks/DatasetNotebookLeftBar.jsx | 10 +- DashAI/front/src/pages/datasets/Datasets.jsx | 5 +- .../src/pages/datasets/DatasetsContent.jsx | 145 ++++++++---------- 4 files changed, 158 insertions(+), 86 deletions(-) create mode 100644 DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx new file mode 100644 index 000000000..f5a645833 --- /dev/null +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -0,0 +1,84 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +import { useTranslation } from "react-i18next"; +import { useDatasets } from "../../../hooks/datasets/useDatasets"; +import { useNotebooks } from "../../../hooks/datasets/useNotebooks"; + +const DatasetsAndNotebooksContext = createContext(); + +export const useDatasetsAndNotebooks = () => + useContext(DatasetsAndNotebooksContext); + +export const OptionsEnum = Object.freeze({ + DATASET: "dataset", + NOTEBOOK: "notebook", + NEW: "new", +}); + +export const DatasetsAndNotebooksProvider = ({ children }) => { + const { t } = useTranslation(["datasets", "common"]); + const { + datasets, + selectedDatasetId, + fetchDatasets, + selectDataset, + clearSelectedDataset, + deleteDatasetLocal, + deleteDatasetRemote, + editDataset, + addDatasetOptimistically, + enrichDatasetsWithInfo, + replaceDatasets, + startDatasetPolling, + } = useDatasets({ t }); + + const { + notebooks, + selectedNotebookId, + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + deleteNotebookById, + editNotebook, + removeNotebooksByDatasetId, + } = useNotebooks({ t }); + + const [step, setStep] = useState(0); + const [selectedOption, setSelectedOption] = useState(OptionsEnum.NEW); // "datasets" or "notebooks" + + useEffect(() => { + fetchDatasets(); + fetchNotebooks(); + }, []); + + const value = { + datasets, + selectedDatasetId, + fetchDatasets, + selectDataset, + clearSelectedDataset, + deleteDatasetLocal, + deleteDatasetRemote, + editDataset, + addDatasetOptimistically, + enrichDatasetsWithInfo, + replaceDatasets, + startDatasetPolling, + notebooks, + selectedNotebookId, + fetchNotebooks, + selectNotebook, + clearSelectedNotebook, + deleteNotebookById, + editNotebook, + removeNotebooksByDatasetId, + selectedOption, + setSelectedOption, + }; + + return ( + + {children} + + ); +}; diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index d3e452d73..2dcf81ef9 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -12,11 +12,9 @@ import InfoNotebookModal from "./notebook/InfoNotebookModal"; import { ChevronLeft } from "@mui/icons-material"; import { useTranslation } from "react-i18next"; +import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; + export default function DatasetsNotebooksLeftBar({ - datasets = [], - selectedDatasetId, - notebooks = [], - selectedNotebookId, onDatasetClick, onDatasetDelete, onDatasetEdit, @@ -26,10 +24,12 @@ export default function DatasetsNotebooksLeftBar({ onToggle, handleNewSessionButton, }) { - const [searchQuery, setSearchQuery] = useState(""); + const { datasets, notebooks, selectedDatasetId, selectedNotebookId } = + useDatasetsAndNotebooks(); const [filteredDatasets, setFilteredDatasets] = useState(datasets); const [filteredNotebooks, setFilteredNotebooks] = useState(notebooks); const [selectedInfoNotebook, setSelectedInfoNotebook] = useState(null); + const [searchQuery, setSearchQuery] = useState(""); const { t } = useTranslation(["datasets", "common"]); useEffect(() => { diff --git a/DashAI/front/src/pages/datasets/Datasets.jsx b/DashAI/front/src/pages/datasets/Datasets.jsx index f244049a0..140814de8 100644 --- a/DashAI/front/src/pages/datasets/Datasets.jsx +++ b/DashAI/front/src/pages/datasets/Datasets.jsx @@ -1,11 +1,14 @@ import { TourProvider } from "../../components/tour/TourProvider"; import { TOUR_KEYS } from "../../constants/tours"; +import { DatasetsAndNotebooksProvider } from "../../components/custom/contexts/DatasetsAndNotebooksContext"; import DatasetsContent from "./DatasetsContent"; export default function DatasetsPage() { return ( - + + + ); } diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 1cae049ad..1036793af 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { useTourContext } from "../../components/tour/TourProvider"; import ModuleContainer from "../../components/layout/ModuleContainer"; import LeftPanel from "../../components/threeSectionLayout/panels/LeftPanel"; @@ -18,6 +18,7 @@ import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; +import { useDatasetsAndNotebooks } from "../../components/custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsContent() { const [rightBarContent, setRightBarContent] = useState(null); @@ -38,9 +39,6 @@ export default function DatasetsContent() { enrichDatasetsWithInfo, replaceDatasets, startDatasetPolling, - } = useDatasets({ t }); - - const { notebooks, selectedNotebookId, fetchNotebooks, @@ -49,7 +47,7 @@ export default function DatasetsContent() { deleteNotebookById, editNotebook, removeNotebooksByDatasetId, - } = useNotebooks({ t }); + } = useDatasetsAndNotebooks(); const { step, @@ -149,77 +147,28 @@ export default function DatasetsContent() { startDatasetPolling(newDataset, datasetJob); }; - useEffect(() => { - fetchDatasets(); - fetchNotebooks(); - }, []); - const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( - <> - - - - - - - - {selectedNotebookId ? ( - - <> - - - - - {rightBarContent ? ( - rightBarContent - ) : ( - - )} - - - - - ) : ( + + + + + + + + {selectedNotebookId ? ( + <> - + {rightBarContent ? ( rightBarContent ) : ( )} + - )} - - - {!selectedNotebookId && } - - + + ) : ( + <> + + + + + {rightBarContent ? ( + rightBarContent + ) : ( + + )} + + + )} + + + {!selectedNotebookId && } + ); } From c0acd22f6fbf61dbbdcba21e83bef5cce54254cb Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 14:29:05 -0300 Subject: [PATCH 20/42] Refactor Datasets and Notebooks context to enhance state management and streamline component interactions --- .../contexts/DatasetsAndNotebooksContext.jsx | 2 + .../notebooks/DatasetNotebookLeftBar.jsx | 21 +++++- .../dataset/DatasetsCenterContent.jsx | 67 +++++++++++++++---- .../src/hooks/datasets/useDatasetUIState.js | 15 ----- .../front/src/hooks/datasets/useDatasets.js | 5 -- .../src/pages/datasets/DatasetsContent.jsx | 55 --------------- 6 files changed, 75 insertions(+), 90 deletions(-) diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index f5a645833..3d0312f67 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -74,6 +74,8 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { removeNotebooksByDatasetId, selectedOption, setSelectedOption, + step, + setStep, }; return ( diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 2dcf81ef9..d6e14281a 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -15,7 +15,6 @@ import { useTranslation } from "react-i18next"; import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsNotebooksLeftBar({ - onDatasetClick, onDatasetDelete, onDatasetEdit, onNotebookClick, @@ -24,8 +23,17 @@ export default function DatasetsNotebooksLeftBar({ onToggle, handleNewSessionButton, }) { - const { datasets, notebooks, selectedDatasetId, selectedNotebookId } = - useDatasetsAndNotebooks(); + const { + datasets, + notebooks, + selectedDatasetId, + selectedNotebookId, + selectDataset, + clearSelectedNotebook, + setStep, + setSelectedOption, + } = useDatasetsAndNotebooks(); + const [filteredDatasets, setFilteredDatasets] = useState(datasets); const [filteredNotebooks, setFilteredNotebooks] = useState(notebooks); const [selectedInfoNotebook, setSelectedInfoNotebook] = useState(null); @@ -79,6 +87,13 @@ export default function DatasetsNotebooksLeftBar({ return notebook.description || ""; }; + const onDatasetClick = (id) => { + selectDataset(id); + clearSelectedNotebook(); + setStep(0); + setSelectedOption("dataset"); + }; + return ( {/* Header */} diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index f02628f1b..22439cb63 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -1,29 +1,72 @@ +import { useCallback } from "react"; import NotebookVisualization from "../notebook/NotebookVisualization"; import UploadDatasetSteps from "../datasetCreation/UploadDatasetSteps"; import UploadNotebookSteps from "../notebookCreation/UploadNotebookSteps"; import DatasetVisualization from "../../DatasetVisualization"; import SelectOptionMenu from "../../threeSectionLayout/SelectOptionMenu"; +import { useDatasetsAndNotebooks } from "../../custom/contexts/DatasetsAndNotebooksContext"; +import { useTourContext } from "../../tour/TourProvider"; export default function DatasetsCenterContent({ - selectedNotebookId, - selectedNotebook, - step, - selectedOption, - selectedDatasetId, - selectedDataset, - datasets, - notebooks, t, - goToNextStep, - resetUI, - fetchDatasets, - fetchNotebooks, setRightBarContent, handleDatasetCreated, handleNotebookCreated, handleNewNotebookFromDataset, handleAddDatasetFromNotebook, }) { + const { + datasets, + notebooks, + selectedDatasetId, + selectedNotebookId, + step, + fetchDatasets, + fetchNotebooks, + selectedOption, + setStep, + setSelectedOption, + clearSelectedDataset, + clearSelectedNotebook, + } = useDatasetsAndNotebooks(); + + const tourContext = useTourContext(); + + const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); + const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); + + const resetUI = useCallback(() => { + setStep(0); + setSelectedOption(null); + }, []); + + const goToDatasetFlow = useCallback(() => { + setStep(1); + setSelectedOption("dataset"); + }, []); + + const goToNotebookFlow = useCallback(() => { + setStep(1); + setSelectedOption("notebook"); + }, []); + + const goToNextStep = (option) => { + if (option === "dataset") { + goToDatasetFlow(); + } else { + goToNotebookFlow(); + } + + clearSelectedDataset(); + clearSelectedNotebook(); + + if (option === "dataset" && tourContext?.run) { + setTimeout(() => { + tourContext.nextStep(); + }, 600); + } + }; + if (selectedNotebookId) { return ( { - setStep(1); - setSelectedOption("dataset"); - }, []); - - const goToNotebookFlow = useCallback(() => { - setStep(1); - setSelectedOption("notebook"); - }, []); - const selectDatasetView = useCallback(() => { setStep(0); setSelectedOption("dataset"); @@ -43,12 +33,7 @@ export function useDatasetUIState() { }; return { - step, - selectedOption, - resetUI, - goToDatasetFlow, - goToNotebookFlow, goToNotebookCreation, selectDatasetView, selectNotebookView, diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index f46985dc3..8f9ac7cc9 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -152,21 +152,16 @@ export function useDatasets({ t }) { datasets, selectedDatasetId, enrichDatasetsWithInfo, - createDataset, - fetchDatasets, fetchFreshDatasets, selectDataset, clearSelectedDataset, - deleteDatasetLocal, deleteDatasetRemote, - editDataset, addDatasetOptimistically, startDatasetPolling, - removeDatasetById, replaceDatasets, }; diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 1036793af..acc70db9c 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -12,8 +12,6 @@ import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; -import { useDatasets } from "../../hooks/datasets/useDatasets"; -import { useNotebooks } from "../../hooks/datasets/useNotebooks"; import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; @@ -50,11 +48,7 @@ export default function DatasetsContent() { } = useDatasetsAndNotebooks(); const { - step, - selectedOption, resetUI, - goToDatasetFlow, - goToNotebookFlow, goToNotebookCreation, selectDatasetView, selectNotebookView, @@ -73,12 +67,6 @@ export default function DatasetsContent() { deleteDatasetRemote, }); - const handleDatasetClick = (id) => { - selectDataset(id); - clearSelectedNotebook(); - selectDatasetView(); - }; - const handleNotebookClick = (id) => { selectNotebook(id); clearSelectedDataset(); @@ -116,23 +104,6 @@ export default function DatasetsContent() { goToNotebookCreation(); }; - const goToNextStep = (option) => { - if (option === "dataset") { - goToDatasetFlow(); - } else { - goToNotebookFlow(); - } - - clearSelectedDataset(); - clearSelectedNotebook(); - - if (option === "dataset" && tourContext?.run) { - setTimeout(() => { - tourContext.nextStep(); - }, 600); - } - }; - const handleNewSessionButton = () => { clearSelectedDataset(); clearSelectedNotebook(); @@ -147,7 +118,6 @@ export default function DatasetsContent() { startDatasetPolling(newDataset, datasetJob); }; - const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( @@ -155,7 +125,6 @@ export default function DatasetsContent() { Date: Tue, 3 Feb 2026 15:22:11 -0300 Subject: [PATCH 21/42] Refactor Datasets and Notebooks context to include rightBarContent state management and update related components for improved functionality --- .../contexts/DatasetsAndNotebooksContext.jsx | 4 ++ .../dataset/DatasetsCenterContent.jsx | 5 --- .../datasetCreation/UploadDatasetSteps.jsx | 37 +++++++++++++------ .../src/pages/datasets/DatasetsContent.jsx | 15 +------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index 3d0312f67..63fc68faf 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -46,6 +46,8 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { const [step, setStep] = useState(0); const [selectedOption, setSelectedOption] = useState(OptionsEnum.NEW); // "datasets" or "notebooks" + const [rightBarContent, setRightBarContent] = useState(null); + useEffect(() => { fetchDatasets(); fetchNotebooks(); @@ -76,6 +78,8 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { setSelectedOption, step, setStep, + rightBarContent, + setRightBarContent, }; return ( diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 22439cb63..c5136f7e6 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -9,8 +9,6 @@ import { useTourContext } from "../../tour/TourProvider"; export default function DatasetsCenterContent({ t, - setRightBarContent, - handleDatasetCreated, handleNotebookCreated, handleNewNotebookFromDataset, handleAddDatasetFromNotebook, @@ -84,9 +82,6 @@ export default function DatasetsCenterContent({ fetchDatasets(); setRightBarContent(null); }} - handleDatasetCreated={handleDatasetCreated} - existingDatasets={datasets} - renderRightBar={setRightBarContent} /> ); } diff --git a/DashAI/front/src/components/notebooks/datasetCreation/UploadDatasetSteps.jsx b/DashAI/front/src/components/notebooks/datasetCreation/UploadDatasetSteps.jsx index 6520c7d81..c98d5d30b 100644 --- a/DashAI/front/src/components/notebooks/datasetCreation/UploadDatasetSteps.jsx +++ b/DashAI/front/src/components/notebooks/datasetCreation/UploadDatasetSteps.jsx @@ -4,13 +4,19 @@ import ConfigureAndUploadDatasetStep from "./ConfigureAndUploadDatasetStep"; import DataloaderConfigBar from "./DataloaderConfigBar"; import CustomLayout from "../../custom/CustomLayout"; import { useTranslation } from "react-i18next"; +import { useDatasetsAndNotebooks } from "../../custom/contexts/DatasetsAndNotebooksContext"; + +export default function UploadDatasetSteps({ backHome }) { + const { + datasets, + addDatasetOptimistically, + setStep: setGlobalStep, + setSelectedOption, + clearSelectedNotebook, + startDatasetPolling, + setRightBarContent, + } = useDatasetsAndNotebooks(); -export default function UploadDatasetSteps({ - backHome, - handleDatasetCreated, - existingDatasets = [], - renderRightBar, -}) { const [step, setStep] = useState(0); const [selectedDataloader, setSelectedDataloader] = useState({}); const [formValues, setFormValues] = useState({}); @@ -46,22 +52,31 @@ export default function UploadDatasetSteps({ // Update the right sidebar based on current step useEffect(() => { - if (renderRightBar) { + if (setRightBarContent) { if (step === 1 && Object.entries(selectedDataloader).length !== 0) { - renderRightBar( + setRightBarContent( , ); } else { - renderRightBar(null); + setRightBarContent(null); } } - }, [step, selectedDataloader, existingDatasets, renderRightBar]); + }, [step, selectedDataloader, datasets, setRightBarContent]); + + const handleDatasetCreated = (newDataset, datasetJob) => { + addDatasetOptimistically(newDataset); + setGlobalStep(0); + setSelectedOption("dataset"); + clearSelectedNotebook(); + setRightBarContent(null); + startDatasetPolling(newDataset, datasetJob); + }; return ( { - addDatasetOptimistically(newDataset); - selectDatasetView(); - clearSelectedNotebook(); - setRightBarContent(null); - startDatasetPolling(newDataset, datasetJob); - }; - const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( @@ -142,8 +133,6 @@ export default function DatasetsContent() { Date: Tue, 3 Feb 2026 15:31:54 -0300 Subject: [PATCH 22/42] Refactor dataset deletion logic by moving it to DatasetsNotebooksLeftBar and removing redundant code from DatasetsContent --- .../notebooks/DatasetNotebookLeftBar.jsx | 17 ++++++++++++++++- .../src/pages/datasets/DatasetsContent.jsx | 12 ------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index d6e14281a..44d04c381 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -15,7 +15,6 @@ import { useTranslation } from "react-i18next"; import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsNotebooksLeftBar({ - onDatasetDelete, onDatasetEdit, onNotebookClick, onNotebookDelete, @@ -32,6 +31,10 @@ export default function DatasetsNotebooksLeftBar({ clearSelectedNotebook, setStep, setSelectedOption, + clearSelectedDataset, + deleteDatasetLocal, + deleteDatasetRemote, + removeNotebooksByDatasetId, } = useDatasetsAndNotebooks(); const [filteredDatasets, setFilteredDatasets] = useState(datasets); @@ -94,6 +97,18 @@ export default function DatasetsNotebooksLeftBar({ setSelectedOption("dataset"); }; + const onDatasetDelete = async (id) => { + if (id === selectedDatasetId) { + clearSelectedDataset(); + setStep(0); + setSelectedOption(null); + } + + deleteDatasetLocal(id); + removeNotebooksByDatasetId(id); + await deleteDatasetRemote(id); + }; + return ( {/* Header */} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 226f43535..3018c985e 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -72,17 +72,6 @@ export default function DatasetsContent() { selectNotebookView(); }; - const handleDatasetDelete = async (id) => { - if (id === selectedDatasetId) { - clearSelectedDataset(); - resetUI(); - } - - deleteDatasetLocal(id); - removeNotebooksByDatasetId(id); - await deleteDatasetRemote(id); - }; - const handleNotebookDelete = (id) => { deleteNotebookById(id); @@ -116,7 +105,6 @@ export default function DatasetsContent() { Date: Tue, 3 Feb 2026 15:36:47 -0300 Subject: [PATCH 23/42] Refactor DatasetsNotebooksLeftBar and DatasetsContent to streamline notebook deletion logic and improve component interactions --- .../notebooks/DatasetNotebookLeftBar.jsx | 16 +++++++++++++--- .../front/src/pages/datasets/DatasetsContent.jsx | 11 ----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 44d04c381..cca141058 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -15,9 +15,7 @@ import { useTranslation } from "react-i18next"; import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsNotebooksLeftBar({ - onDatasetEdit, onNotebookClick, - onNotebookDelete, onNotebookEdit, onToggle, handleNewSessionButton, @@ -35,6 +33,8 @@ export default function DatasetsNotebooksLeftBar({ deleteDatasetLocal, deleteDatasetRemote, removeNotebooksByDatasetId, + editDataset, + deleteNotebookById, } = useDatasetsAndNotebooks(); const [filteredDatasets, setFilteredDatasets] = useState(datasets); @@ -109,6 +109,16 @@ export default function DatasetsNotebooksLeftBar({ await deleteDatasetRemote(id); }; + const onNotebookDelete = (id) => { + deleteNotebookById(id); + + if (id === selectedNotebookId) { + clearSelectedNotebook(); + setStep(0); + setSelectedOption(null); + } + }; + return ( {/* Header */} @@ -163,7 +173,7 @@ export default function DatasetsNotebooksLeftBar({ selectedItemId={selectedDatasetId} onItemClick={onDatasetClick} onItemDelete={onDatasetDelete} - onItemEdit={onDatasetEdit} + onItemEdit={editDataset} defaultOpen={true} title={t("datasets:label.availableDatasets")} Icon={StorageIcon} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 3018c985e..205057f70 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -72,15 +72,6 @@ export default function DatasetsContent() { selectNotebookView(); }; - const handleNotebookDelete = (id) => { - deleteNotebookById(id); - - if (id === selectedNotebookId) { - clearSelectedNotebook(); - resetUI(); - } - }; - const handleNotebookCreated = async (createdNotebook) => { await fetchNotebooks(); selectNotebookView(); @@ -105,9 +96,7 @@ export default function DatasetsContent() { Date: Tue, 3 Feb 2026 15:41:43 -0300 Subject: [PATCH 24/42] Refactor DatasetsNotebooksLeftBar and DatasetsContent to replace onNotebookEdit prop with editNotebook function for improved code clarity --- .../front/src/components/notebooks/DatasetNotebookLeftBar.jsx | 4 ++-- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index cca141058..6af0a9480 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -16,7 +16,6 @@ import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooks export default function DatasetsNotebooksLeftBar({ onNotebookClick, - onNotebookEdit, onToggle, handleNewSessionButton, }) { @@ -34,6 +33,7 @@ export default function DatasetsNotebooksLeftBar({ deleteDatasetRemote, removeNotebooksByDatasetId, editDataset, + editNotebook, deleteNotebookById, } = useDatasetsAndNotebooks(); @@ -187,7 +187,7 @@ export default function DatasetsNotebooksLeftBar({ selectedItemId={selectedNotebookId} onItemClick={onNotebookClick} onItemDelete={onNotebookDelete} - onItemEdit={onNotebookEdit} + onItemEdit={editNotebook} onItemInfo={handleNotebookInfo} defaultOpen={true} title={t("datasets:label.notebooks")} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 205057f70..6b5f62e2e 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -97,7 +97,6 @@ export default function DatasetsContent() { From 2cb3c3339e0458a5a7ddd8e17d176012223b4f46 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 15:44:58 -0300 Subject: [PATCH 25/42] Refactor DatasetsNotebooksLeftBar and DatasetsContent to implement onNotebookClick function in DatasetsNotebooksLeftBar and remove redundant notebook click handling from DatasetsContent for improved code organization --- .../src/components/notebooks/DatasetNotebookLeftBar.jsx | 9 ++++++++- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 7 ------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 6af0a9480..7fd980f0a 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -15,7 +15,6 @@ import { useTranslation } from "react-i18next"; import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsNotebooksLeftBar({ - onNotebookClick, onToggle, handleNewSessionButton, }) { @@ -25,6 +24,7 @@ export default function DatasetsNotebooksLeftBar({ selectedDatasetId, selectedNotebookId, selectDataset, + selectNotebook, clearSelectedNotebook, setStep, setSelectedOption, @@ -97,6 +97,13 @@ export default function DatasetsNotebooksLeftBar({ setSelectedOption("dataset"); }; + const onNotebookClick = (id) => { + selectNotebook(id); + clearSelectedDataset(); + setStep(0); + setSelectedOption("notebook"); + }; + const onDatasetDelete = async (id) => { if (id === selectedDatasetId) { clearSelectedDataset(); diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 6b5f62e2e..650a69c6f 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -66,12 +66,6 @@ export default function DatasetsContent() { deleteDatasetRemote, }); - const handleNotebookClick = (id) => { - selectNotebook(id); - clearSelectedDataset(); - selectNotebookView(); - }; - const handleNotebookCreated = async (createdNotebook) => { await fetchNotebooks(); selectNotebookView(); @@ -96,7 +90,6 @@ export default function DatasetsContent() { From 27a43da58fbb40bb8a8afbc99b647385200e7522 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 16:05:03 -0300 Subject: [PATCH 26/42] Refactor DatasetsNotebooksLeftBar and DatasetsCenterContent to implement handleNewSessionButton and handleNotebookCreated functions, removing redundant logic from DatasetsContent for improved code clarity and organization --- .../notebooks/DatasetNotebookLeftBar.jsx | 12 ++++++++---- .../notebooks/dataset/DatasetsCenterContent.jsx | 10 +++++++++- .../front/src/pages/datasets/DatasetsContent.jsx | 16 ---------------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 7fd980f0a..ad1f58ec5 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -14,10 +14,7 @@ import { useTranslation } from "react-i18next"; import { useDatasetsAndNotebooks } from "../custom/contexts/DatasetsAndNotebooksContext"; -export default function DatasetsNotebooksLeftBar({ - onToggle, - handleNewSessionButton, -}) { +export default function DatasetsNotebooksLeftBar({ onToggle }) { const { datasets, notebooks, @@ -126,6 +123,13 @@ export default function DatasetsNotebooksLeftBar({ } }; + const handleNewSessionButton = () => { + clearSelectedDataset(); + clearSelectedNotebook(); + setStep(0); + setSelectedOption(null); + }; + return ( {/* Header */} diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index c5136f7e6..2731ef398 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -9,13 +9,13 @@ import { useTourContext } from "../../tour/TourProvider"; export default function DatasetsCenterContent({ t, - handleNotebookCreated, handleNewNotebookFromDataset, handleAddDatasetFromNotebook, }) { const { datasets, notebooks, + selectNotebook, selectedDatasetId, selectedNotebookId, step, @@ -65,6 +65,14 @@ export default function DatasetsCenterContent({ } }; + const handleNotebookCreated = async (createdNotebook) => { + await fetchNotebooks(); + setStep(0); + setSelectedOption("notebook"); + selectNotebook(createdNotebook.id); + clearSelectedDataset(); + }; + if (selectedNotebookId) { return ( { - await fetchNotebooks(); - selectNotebookView(); - selectNotebook(createdNotebook.id); - clearSelectedDataset(); - }; - const handleNewNotebookFromDataset = () => { goToNotebookCreation(); }; - const handleNewSessionButton = () => { - clearSelectedDataset(); - clearSelectedNotebook(); - resetUI(); - }; - const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( @@ -90,7 +77,6 @@ export default function DatasetsContent() { @@ -102,7 +88,6 @@ export default function DatasetsContent() { @@ -125,7 +110,6 @@ export default function DatasetsContent() { From ba477a36a378e7ace738efee7e701da5d1de1e4a Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 17:27:06 -0300 Subject: [PATCH 27/42] Refactor DatasetsCenterContent and DatasetsContent to move handleNewNotebookFromDataset function to DatasetsCenterContent, removing it from DatasetsContent for improved code organization --- .../components/notebooks/dataset/DatasetsCenterContent.jsx | 6 +++++- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 2731ef398..e63c026cb 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -9,7 +9,6 @@ import { useTourContext } from "../../tour/TourProvider"; export default function DatasetsCenterContent({ t, - handleNewNotebookFromDataset, handleAddDatasetFromNotebook, }) { const { @@ -73,6 +72,11 @@ export default function DatasetsCenterContent({ clearSelectedDataset(); }; + const handleNewNotebookFromDataset = () => { + setSelectedOption("notebook"); + setStep(1); + }; + if (selectedNotebookId) { return ( { - goToNotebookCreation(); - }; - const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( @@ -88,7 +84,6 @@ export default function DatasetsContent() { @@ -110,7 +105,6 @@ export default function DatasetsContent() { From d82907d36f18a313b7b7ee1d7a2ade4225d6feb2 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 18:23:16 -0300 Subject: [PATCH 28/42] Refactor DatasetsContent and DatasetsCenterContent to remove handleAddDatasetFromNotebook prop, improving code clarity and organization by utilizing context for dataset creation --- .../contexts/DatasetsAndNotebooksContext.jsx | 3 + .../dataset/DatasetsCenterContent.jsx | 34 +++-- .../notebook/DatasetPreviewNotebook.jsx | 117 +++++++++++++++++- .../notebook/NotebookVisualization.jsx | 2 - .../src/pages/datasets/DatasetsContent.jsx | 23 +--- 5 files changed, 134 insertions(+), 45 deletions(-) diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index 63fc68faf..80068efec 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -3,6 +3,7 @@ import { createContext, useContext, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDatasets } from "../../../hooks/datasets/useDatasets"; import { useNotebooks } from "../../../hooks/datasets/useNotebooks"; +import { create } from "yup/lib/Reference"; const DatasetsAndNotebooksContext = createContext(); @@ -19,6 +20,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { const { t } = useTranslation(["datasets", "common"]); const { datasets, + createDataset, selectedDatasetId, fetchDatasets, selectDataset, @@ -55,6 +57,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { const value = { datasets, + createDataset, selectedDatasetId, fetchDatasets, selectDataset, diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index e63c026cb..b00a78b32 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -7,10 +7,7 @@ import SelectOptionMenu from "../../threeSectionLayout/SelectOptionMenu"; import { useDatasetsAndNotebooks } from "../../custom/contexts/DatasetsAndNotebooksContext"; import { useTourContext } from "../../tour/TourProvider"; -export default function DatasetsCenterContent({ - t, - handleAddDatasetFromNotebook, -}) { +export default function DatasetsCenterContent({ t }) { const { datasets, notebooks, @@ -77,15 +74,28 @@ export default function DatasetsCenterContent({ setStep(1); }; - if (selectedNotebookId) { + if (selectedNotebookId && selectedOption === "notebook") { return ( ); } + + if (selectedDatasetId && selectedOption === "dataset") { + return ( + + ); + } + if (step === 1 && selectedOption === "dataset") { return ( ); } - if (selectedDatasetId) { - return ( - - ); - } if (step === 0) { return ( { + if (!jobId) return; + + startJobPolling( + jobId, + + //Success + async () => { + enqueueSnackbar( + t("datasets:message.datasetCreationSuccess", { datasetName }), + { variant: "success" }, + ); + + try { + const freshDatasets = await fetchDatasets(true); + const dataset = freshDatasets.find((d) => d.id === datasetId); + + if (dataset) { + const enriched = await enrichDatasetsWithInfo( + freshDatasets, + datasets, + ); + replaceDatasets(enriched); + selectDataset(datasetId); + setStep(0); + setSelectedOption("dataset"); + } else { + await fetchDatasets(); + selectDataset(datasetId); + setStep(0); + setSelectedOption("dataset"); + } + } catch (error) { + console.error("Error after dataset job completion:", error); + await fetchDatasets(); + selectDataset(datasetId); + setStep(0); + setSelectedOption("dataset"); + } + }, + + //Failure + async (result) => { + console.error("Dataset job failed:", result); + + enqueueSnackbar( + t("datasets:error.failedToCreateDataset", { + error: result?.error || t("common:unknownError"), + }), + { variant: "error" }, + ); + + deleteDatasetRemote(datasetId).catch(console.error); + clearSelectedDataset(); + setStep(0); + setSelectedOption(null); + }, + ); + }; + + const handleAddDatasetFromNotebook = async (name, notebookId) => { + try { + console.log( + "Creating dataset from notebook:", + notebookId, + "with name:", + name, + ); + const dataset = await createDataset(name); + + enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { + variant: "success", + }); + + // optimistic + replaceDatasets((prev) => [...prev, dataset]); + selectDataset(dataset.id); + setStep(0); + setSelectedOption("dataset"); + + const job = await enqueueDatasetJob(dataset.id, null, "", {}, notebookId); + + pollForDataset( + { datasetId: dataset.id, datasetName: name }, + { jobId: job.id }, + ); + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { + variant: "error", + }); + console.error("Failed to create dataset from notebook:", error); + } + }; return ( diff --git a/DashAI/front/src/components/notebooks/notebook/NotebookVisualization.jsx b/DashAI/front/src/components/notebooks/notebook/NotebookVisualization.jsx index 54ed2b8d0..0f06f84de 100644 --- a/DashAI/front/src/components/notebooks/notebook/NotebookVisualization.jsx +++ b/DashAI/front/src/components/notebooks/notebook/NotebookVisualization.jsx @@ -6,7 +6,6 @@ import JobQueueWidget from "../../jobs/JobQueueWidget"; export default function NotebookVisualization({ notebook, - handleAddDatasetFromNotebook, existingDatasets = [], }) { const [isAccordionExpanded, setIsAccordionExpanded] = useState(true); @@ -21,7 +20,6 @@ export default function NotebookVisualization({ diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 2fd265a1e..2a8c8cf6d 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -53,19 +53,6 @@ export default function DatasetsContent() { selectNotebookView, } = useDatasetUIState(); - const { createDatasetFromNotebook } = useDatasetFlow({ - datasets, - enrichDatasetsWithInfo, - fetchDatasets, - replaceDatasets, - addDatasetOptimistically, - selectDataset, - clearSelectedDataset, - t, - resetUI, - deleteDatasetRemote, - }); - const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); return ( @@ -82,10 +69,7 @@ export default function DatasetsContent() { <> - + {rightBarContent ? ( @@ -103,10 +87,7 @@ export default function DatasetsContent() { ) : ( <> - + {rightBarContent ? ( From 5e9b80c4b0443fe2c37e96130e10fa180a72f997 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 3 Feb 2026 18:44:45 -0300 Subject: [PATCH 29/42] Refactor DatasetsContent and remove unused hooks to improve code clarity and organization --- .../contexts/DatasetsAndNotebooksContext.jsx | 1 - .../src/hooks/datasets/useDatasetFlow.js | 119 ------------------ .../src/hooks/datasets/useDatasetUIState.js | 41 ------ .../src/pages/datasets/DatasetsContent.jsx | 36 +----- 4 files changed, 2 insertions(+), 195 deletions(-) delete mode 100644 DashAI/front/src/hooks/datasets/useDatasetFlow.js delete mode 100644 DashAI/front/src/hooks/datasets/useDatasetUIState.js diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index 80068efec..02715b633 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -3,7 +3,6 @@ import { createContext, useContext, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDatasets } from "../../../hooks/datasets/useDatasets"; import { useNotebooks } from "../../../hooks/datasets/useNotebooks"; -import { create } from "yup/lib/Reference"; const DatasetsAndNotebooksContext = createContext(); diff --git a/DashAI/front/src/hooks/datasets/useDatasetFlow.js b/DashAI/front/src/hooks/datasets/useDatasetFlow.js deleted file mode 100644 index ba884cf56..000000000 --- a/DashAI/front/src/hooks/datasets/useDatasetFlow.js +++ /dev/null @@ -1,119 +0,0 @@ -import { startJobPolling } from "../../utils/jobPoller"; -import { enqueueDatasetJob } from "../../api/job"; -import { createDataset, deleteDataset } from "../../api/datasets"; -import { useSnackbar } from "notistack"; - -export function useDatasetFlow({ - datasets, - enrichDatasetsWithInfo, - fetchDatasets, - replaceDatasets, - addDatasetOptimistically, - selectDataset, - clearSelectedDataset, - t, - resetUI, - deleteDatasetRemote, -}) { - const { enqueueSnackbar } = useSnackbar(); - - const pollForDataset = ({ datasetId, datasetName }, { jobId }) => { - if (!jobId) return; - - startJobPolling( - jobId, - - //Susccess - async () => { - enqueueSnackbar( - t("datasets:message.datasetCreationSuccess", { datasetName }), - { variant: "success" }, - ); - - try { - const freshDatasets = await fetchDatasets(true); - const dataset = freshDatasets.find((d) => d.id === datasetId); - - if (dataset) { - const enriched = await enrichDatasetsWithInfo( - freshDatasets, - datasets, - ); - replaceDatasets(enriched); - selectDataset(datasetId); - } else { - await fetchDatasets(); - selectDataset(datasetId); - } - } catch (error) { - console.error("Error after dataset job completion:", error); - await fetchDatasets(); - selectDataset(datasetId); - } - }, - - //Failure - async (result) => { - console.error("Dataset job failed:", result); - - enqueueSnackbar( - t("datasets:error.failedToCreateDataset", { - error: result?.error || t("common:unknownError"), - }), - { variant: "error" }, - ); - - deleteDatasetRemote(datasetId).catch(console.error); - clearSelectedDataset(); - resetUI(); - }, - ); - }; - - const createDatasetFromNotebook = async (name, notebookId) => { - try { - console.log( - "Creating dataset from notebook:", - notebookId, - "with name:", - name, - ); - const dataset = await createDataset(name); - - enqueueSnackbar(t("datasets:message.datasetCreationStarted"), { - variant: "success", - }); - - // optimistic - replaceDatasets((prev) => [...prev, dataset]); - selectDataset(dataset.id); - - const job = await enqueueDatasetJob(dataset.id, null, "", {}, notebookId); - - pollForDataset( - { datasetId: dataset.id, datasetName: name }, - { jobId: job.id }, - ); - } catch (error) { - enqueueSnackbar(t("datasets:error.failedToCreateDatasetFromNotebook"), { - variant: "error", - }); - console.error("Failed to create dataset from notebook:", error); - } - }; - - const createDatasetFromUpload = (dataset, job) => { - addDatasetOptimistically(dataset); - selectDataset(dataset.id); - pollForDataset( - { datasetId: dataset.id, datasetName: dataset.name }, - { jobId: job.id }, - ); - }; - - return { - createDatasetFromNotebook, - createDatasetFromUpload, - pollForDataset, - }; -} diff --git a/DashAI/front/src/hooks/datasets/useDatasetUIState.js b/DashAI/front/src/hooks/datasets/useDatasetUIState.js deleted file mode 100644 index e86f6bf85..000000000 --- a/DashAI/front/src/hooks/datasets/useDatasetUIState.js +++ /dev/null @@ -1,41 +0,0 @@ -import { useState, useCallback } from "react"; - -/** - * Manages the UI state for dataset module: - * - step - * - selectedOption - * - navigation resets - */ -export function useDatasetUIState() { - const [step, setStep] = useState(0); - const [selectedOption, setSelectedOption] = useState(null); - - // ---------------- navigation helpers ---------------- - - const resetUI = useCallback(() => { - setStep(0); - setSelectedOption(null); - }, []); - - const selectDatasetView = useCallback(() => { - setStep(0); - setSelectedOption("dataset"); - }, []); - - const selectNotebookView = useCallback(() => { - setStep(0); - setSelectedOption("notebook"); - }, []); - - const goToNotebookCreation = () => { - setSelectedOption("notebook"); - setStep(1); - }; - - return { - resetUI, - goToNotebookCreation, - selectDatasetView, - selectNotebookView, - }; -} diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 2a8c8cf6d..73eee5e3d 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -1,4 +1,3 @@ -import { useTourContext } from "../../components/tour/TourProvider"; import ModuleContainer from "../../components/layout/ModuleContainer"; import LeftPanel from "../../components/threeSectionLayout/panels/LeftPanel"; import DatasetsNotebooksLeftBar from "../../components/notebooks/DatasetNotebookLeftBar"; @@ -11,47 +10,16 @@ import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; import { useTranslation } from "react-i18next"; -import { useDatasetUIState } from "../../hooks/datasets/useDatasetUIState"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; -import { useDatasetFlow } from "../../hooks/datasets/useDatasetFlow"; import { useDatasetsAndNotebooks } from "../../components/custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsContent() { - const tourContext = useTourContext(); const { t } = useTranslation(["datasets", "common"]); const threePanelLayout = useThreePanelLayout(); - const { - datasets, - selectedDatasetId, - fetchDatasets, - selectDataset, - clearSelectedDataset, - deleteDatasetLocal, - deleteDatasetRemote, - editDataset, - addDatasetOptimistically, - enrichDatasetsWithInfo, - replaceDatasets, - startDatasetPolling, - notebooks, - selectedNotebookId, - fetchNotebooks, - selectNotebook, - clearSelectedNotebook, - deleteNotebookById, - editNotebook, - removeNotebooksByDatasetId, - rightBarContent, - } = useDatasetsAndNotebooks(); - - const { - resetUI, - goToNotebookCreation, - selectDatasetView, - selectNotebookView, - } = useDatasetUIState(); + const { notebooks, selectedNotebookId, rightBarContent } = + useDatasetsAndNotebooks(); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); From ac07e275da132bc690df067104f770cb0ea96b9c Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 10:51:15 -0300 Subject: [PATCH 30/42] Refactor dataset deletion methods to unify under deleteDatasetById, improving code clarity and reducing redundancy --- .../contexts/DatasetsAndNotebooksContext.jsx | 6 ++-- .../notebooks/DatasetNotebookLeftBar.jsx | 6 ++-- .../front/src/hooks/datasets/useDatasets.js | 28 ++++--------------- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index 02715b633..284345efb 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -24,8 +24,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { fetchDatasets, selectDataset, clearSelectedDataset, - deleteDatasetLocal, - deleteDatasetRemote, + deleteDatasetById, editDataset, addDatasetOptimistically, enrichDatasetsWithInfo, @@ -61,8 +60,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { fetchDatasets, selectDataset, clearSelectedDataset, - deleteDatasetLocal, - deleteDatasetRemote, + deleteDatasetById, editDataset, addDatasetOptimistically, enrichDatasetsWithInfo, diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index ad1f58ec5..2e9ffd32b 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -26,8 +26,7 @@ export default function DatasetsNotebooksLeftBar({ onToggle }) { setStep, setSelectedOption, clearSelectedDataset, - deleteDatasetLocal, - deleteDatasetRemote, + deleteDatasetById, removeNotebooksByDatasetId, editDataset, editNotebook, @@ -108,9 +107,8 @@ export default function DatasetsNotebooksLeftBar({ onToggle }) { setSelectedOption(null); } - deleteDatasetLocal(id); removeNotebooksByDatasetId(id); - await deleteDatasetRemote(id); + await deleteDatasetById(id); }; const onNotebookDelete = (id) => { diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index 8f9ac7cc9..72c04f130 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -1,6 +1,5 @@ import { useState, useCallback } from "react"; import { useSnackbar } from "notistack"; -import { enqueueDatasetJob } from "../../api/job"; import { getDatasets, deleteDataset, @@ -59,10 +58,6 @@ export function useDatasets({ t }) { setDatasets(enriched); }, [datasets, enrichDatasetsWithInfo]); - const fetchFreshDatasets = async () => { - return await getDatasets(); - }; - const selectDataset = (id) => { setSelectedDatasetId(id); }; @@ -71,14 +66,11 @@ export function useDatasets({ t }) { setSelectedDatasetId(null); }; - const deleteDatasetLocal = (id) => { + const deleteDatasetById = async (id) => { setDatasets((prev) => prev.filter((d) => d.id !== id)); if (id === selectedDatasetId) { setSelectedDatasetId(null); } - }; - - const deleteDatasetRemote = async (id) => { await deleteDataset(id); }; @@ -131,19 +123,14 @@ export function useDatasets({ t }) { enqueueSnackbar(t("datasets:error.failedToCreateDataset"), { variant: "error", }); - deleteDatasetLocal(newDataset.id); + setDatasets((prev) => prev.filter((d) => d.id !== newDataset.id)); + if (newDataset.id === selectedDatasetId) { + setSelectedDatasetId(null); + } }, ); }; - const removeDatasetById = (id) => { - setDatasets((prev) => prev.filter((d) => d.id !== id)); - - if (id === selectedDatasetId) { - setSelectedDatasetId(null); - } - }; - const replaceDatasets = (datasets) => { setDatasets(datasets); }; @@ -154,15 +141,12 @@ export function useDatasets({ t }) { enrichDatasetsWithInfo, createDataset, fetchDatasets, - fetchFreshDatasets, selectDataset, clearSelectedDataset, - deleteDatasetLocal, - deleteDatasetRemote, + deleteDatasetById, editDataset, addDatasetOptimistically, startDatasetPolling, - removeDatasetById, replaceDatasets, }; } From fc13a4630cf5834fcc232b53e862b71eb33b6af3 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 11:40:39 -0300 Subject: [PATCH 31/42] Refactor Header and HeaderBox components to improve layout alignment and organization --- .../front/src/components/notebooks/dataset/header/Header.jsx | 2 +- .../src/components/notebooks/dataset/header/HeaderBox.jsx | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DashAI/front/src/components/notebooks/dataset/header/Header.jsx b/DashAI/front/src/components/notebooks/dataset/header/Header.jsx index b020d2b01..c0215beaa 100644 --- a/DashAI/front/src/components/notebooks/dataset/header/Header.jsx +++ b/DashAI/front/src/components/notebooks/dataset/header/Header.jsx @@ -32,7 +32,7 @@ export default function Header({ flexDirection: "row", gap: 1, justifyContent: "flex-start", - alignItems: "flex-start", + alignItems: "stretch", width: "100%", flexWrap: "wrap", flexGrow: 0, diff --git a/DashAI/front/src/components/notebooks/dataset/header/HeaderBox.jsx b/DashAI/front/src/components/notebooks/dataset/header/HeaderBox.jsx index 3006c9588..823600c92 100644 --- a/DashAI/front/src/components/notebooks/dataset/header/HeaderBox.jsx +++ b/DashAI/front/src/components/notebooks/dataset/header/HeaderBox.jsx @@ -1,4 +1,3 @@ -import React from "react"; import { Box, Typography, Tooltip } from "@mui/material"; import { useTheme } from "@mui/material/styles"; @@ -8,13 +7,12 @@ export function HeaderBox({ title, value, IconComponent, iconColor, bgColor }) { Date: Wed, 4 Feb 2026 11:49:00 -0300 Subject: [PATCH 32/42] Refactor DatasetsCenterContent to remove t prop and utilize useTranslation hook directly, improving code clarity and organization --- .../components/notebooks/dataset/DatasetsCenterContent.jsx | 4 +++- DashAI/front/src/pages/datasets/DatasetsContent.jsx | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index b00a78b32..142ee86b4 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -6,8 +6,9 @@ import DatasetVisualization from "../../DatasetVisualization"; import SelectOptionMenu from "../../threeSectionLayout/SelectOptionMenu"; import { useDatasetsAndNotebooks } from "../../custom/contexts/DatasetsAndNotebooksContext"; import { useTourContext } from "../../tour/TourProvider"; +import { useTranslation } from "react-i18next"; -export default function DatasetsCenterContent({ t }) { +export default function DatasetsCenterContent() { const { datasets, notebooks, @@ -25,6 +26,7 @@ export default function DatasetsCenterContent({ t }) { } = useDatasetsAndNotebooks(); const tourContext = useTourContext(); + const { t } = useTranslation(["datasets", "common"]); const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); diff --git a/DashAI/front/src/pages/datasets/DatasetsContent.jsx b/DashAI/front/src/pages/datasets/DatasetsContent.jsx index 73eee5e3d..341b2023a 100644 --- a/DashAI/front/src/pages/datasets/DatasetsContent.jsx +++ b/DashAI/front/src/pages/datasets/DatasetsContent.jsx @@ -9,13 +9,11 @@ import { TourProvider } from "../../components/tour/TourProvider"; import { TourButton } from "../../components/tour/TourButton"; import { TOUR_KEYS } from "../../constants/tours"; import { ExplorersAndConvertersProvider } from "../../components/notebooks/context/ExplorersAndConvertersContext"; -import { useTranslation } from "react-i18next"; import { useThreePanelLayout } from "../../hooks/useThreePanelsLayout"; import { ThreePanelLayoutContext } from "../../components/threeSectionLayout/panels/ThreePanelLayoutContext"; import { useDatasetsAndNotebooks } from "../../components/custom/contexts/DatasetsAndNotebooksContext"; export default function DatasetsContent() { - const { t } = useTranslation(["datasets", "common"]); const threePanelLayout = useThreePanelLayout(); const { notebooks, selectedNotebookId, rightBarContent } = @@ -37,7 +35,7 @@ export default function DatasetsContent() { <> - + {rightBarContent ? ( @@ -55,7 +53,7 @@ export default function DatasetsContent() { ) : ( <> - + {rightBarContent ? ( From fe9729dffe7fd50acf39876ef7fb7d6a1102ec68 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 12:02:22 -0300 Subject: [PATCH 33/42] Refactor DatasetsCenterContent to streamline navigation logic by consolidating step transitions and removing redundant functions, enhancing code clarity and maintainability --- .../dataset/DatasetsCenterContent.jsx | 54 ++++++++----------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index 142ee86b4..f2bd9eb73 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -31,37 +31,27 @@ export default function DatasetsCenterContent() { const selectedDataset = datasets.find((n) => n.id === selectedDatasetId); const selectedNotebook = notebooks.find((n) => n.id === selectedNotebookId); - const resetUI = useCallback(() => { - setStep(0); - setSelectedOption(null); - }, []); - - const goToDatasetFlow = useCallback(() => { - setStep(1); - setSelectedOption("dataset"); - }, []); + const goToNextStep = useCallback( + (option) => { + if (option === "dataset") { + setStep(1); + setSelectedOption("dataset"); + } else { + setStep(1); + setSelectedOption("notebook"); + } - const goToNotebookFlow = useCallback(() => { - setStep(1); - setSelectedOption("notebook"); - }, []); + clearSelectedDataset(); + clearSelectedNotebook(); - const goToNextStep = (option) => { - if (option === "dataset") { - goToDatasetFlow(); - } else { - goToNotebookFlow(); - } - - clearSelectedDataset(); - clearSelectedNotebook(); - - if (option === "dataset" && tourContext?.run) { - setTimeout(() => { - tourContext.nextStep(); - }, 600); - } - }; + if (option === "dataset" && tourContext?.run) { + setTimeout(() => { + tourContext.nextStep(); + }, 600); + } + }, + [tourContext], + ); const handleNotebookCreated = async (createdNotebook) => { await fetchNotebooks(); @@ -102,7 +92,8 @@ export default function DatasetsCenterContent() { return ( { - resetUI(); + setStep(0); + setSelectedOption(null); fetchDatasets(); setRightBarContent(null); }} @@ -113,7 +104,8 @@ export default function DatasetsCenterContent() { return ( { - resetUI(); + setStep(0); + setSelectedOption(null); fetchNotebooks(); }} datasets={datasets} From 1769046337af483a0914dc9351ce13f7b2b81f1c Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 12:44:42 -0300 Subject: [PATCH 34/42] Refactor dataset deletion logic to improve error handling and user feedback, updating related translations for consistency --- DashAI/front/src/api/datasets.ts | 2 +- .../notebooks/DatasetNotebookLeftBar.jsx | 4 ++-- .../front/src/hooks/datasets/useDatasets.js | 19 +++++++++++++++---- .../src/utils/i18n/locales/en/datasets.json | 1 + .../src/utils/i18n/locales/es/datasets.json | 1 + 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/DashAI/front/src/api/datasets.ts b/DashAI/front/src/api/datasets.ts index 813d645ee..eb325a1e4 100644 --- a/DashAI/front/src/api/datasets.ts +++ b/DashAI/front/src/api/datasets.ts @@ -81,7 +81,7 @@ export const updateDataset = async ( export const deleteDataset = async (id: string): Promise => { const response = await api.delete(`${datasetEndpoint}/${id}`); - return response.data; + return response; }; export const getDatasetFile = async (path: string, page = 0, pageSize = 5) => { diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index 2e9ffd32b..e39a7de52 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -101,14 +101,14 @@ export default function DatasetsNotebooksLeftBar({ onToggle }) { }; const onDatasetDelete = async (id) => { + const success = await deleteDatasetById(id); + if (!success) return; if (id === selectedDatasetId) { clearSelectedDataset(); setStep(0); setSelectedOption(null); } - removeNotebooksByDatasetId(id); - await deleteDatasetById(id); }; const onNotebookDelete = (id) => { diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index 72c04f130..2a96b1859 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -67,11 +67,22 @@ export function useDatasets({ t }) { }; const deleteDatasetById = async (id) => { - setDatasets((prev) => prev.filter((d) => d.id !== id)); - if (id === selectedDatasetId) { - setSelectedDatasetId(null); + try { + const response = await deleteDataset(id); + console.log("Delete dataset response:", response); + + setDatasets((prev) => prev.filter((d) => d.id !== id)); + if (id === selectedDatasetId) { + setSelectedDatasetId(null); + } + return true; + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToDeleteDataset"), { + variant: "error", + }); + console.error("Error deleting dataset:", error); } - await deleteDataset(id); + return false; }; const editDataset = async (id, newName) => { diff --git a/DashAI/front/src/utils/i18n/locales/en/datasets.json b/DashAI/front/src/utils/i18n/locales/en/datasets.json index c490ed673..7fab4bedf 100644 --- a/DashAI/front/src/utils/i18n/locales/en/datasets.json +++ b/DashAI/front/src/utils/i18n/locales/en/datasets.json @@ -30,6 +30,7 @@ "failedToCreateDataset": "Error creating dataset: {{error}}", "failedToCreateDatasetFromNotebook": "Failed to create dataset from notebook", "failedToCreateExplorer": "Failed to create explorer", + "failedToDeleteDataset": "Failed to delete dataset", "failedToFetchDatasets": "Failed to fetch datasets", "failedToFetchNotebooks": "Failed to fetch notebooks", "failedToLoadDatasetInfo": "Failed to fetch dataset info", diff --git a/DashAI/front/src/utils/i18n/locales/es/datasets.json b/DashAI/front/src/utils/i18n/locales/es/datasets.json index e34a1e647..e0c57dbb3 100644 --- a/DashAI/front/src/utils/i18n/locales/es/datasets.json +++ b/DashAI/front/src/utils/i18n/locales/es/datasets.json @@ -30,6 +30,7 @@ "failedToCreateDataset": "Error al crear dataset: {{error}}", "failedToCreateDatasetFromNotebook": "Fallo al crear dataset desde cuaderno", "failedToCreateExplorer": "Fallo al crear explorador", + "failedToDeleteDataset": "Fallo al eliminar dataset", "failedToFetchDatasets": "Fallo al obtener datasets", "failedToFetchNotebooks": "Fallo al obtener cuadernos", "failedToLoadDatasetInfo": "Fallo al obtener información del dataset", From 993e3489d8253def657446475dc818dd673fa7d5 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 12:54:19 -0300 Subject: [PATCH 35/42] Refactor deleteDatasetById to remove unnecessary response logging, improving code clarity --- DashAI/front/src/hooks/datasets/useDatasets.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index 2a96b1859..6997dbd96 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -68,9 +68,7 @@ export function useDatasets({ t }) { const deleteDatasetById = async (id) => { try { - const response = await deleteDataset(id); - console.log("Delete dataset response:", response); - + await deleteDataset(id); setDatasets((prev) => prev.filter((d) => d.id !== id)); if (id === selectedDatasetId) { setSelectedDatasetId(null); From b0cb8aef7a73e0801a1c3424f639140ae54dfd18 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 13:24:06 -0300 Subject: [PATCH 36/42] Refactor notebook deletion logic to improve error handling and user feedback, adding translations for failure messages --- DashAI/front/src/api/notebook.ts | 6 +++--- .../components/notebooks/DatasetNotebookLeftBar.jsx | 6 +++--- DashAI/front/src/hooks/datasets/useNotebooks.js | 13 +++++++++++-- .../front/src/utils/i18n/locales/en/datasets.json | 1 + .../front/src/utils/i18n/locales/es/datasets.json | 1 + 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/DashAI/front/src/api/notebook.ts b/DashAI/front/src/api/notebook.ts index 29114fd6d..ed41c413a 100644 --- a/DashAI/front/src/api/notebook.ts +++ b/DashAI/front/src/api/notebook.ts @@ -2,7 +2,6 @@ import api from "./api"; import { INotebook } from "../types/notebook"; import { IExplorer } from "../types/explorer"; import { IConverter } from "../types/converter"; -import { IDataset } from "../types/dataset"; const notebookEndpoint = "/v1/notebook"; @@ -39,8 +38,9 @@ export const getConvertersByNotebookId = async ( return response.data; }; -export const deleteNotebook = async (id: number): Promise => { - await api.delete(`${notebookEndpoint}/${id}`); +export const deleteNotebook = async (id: number): Promise => { + const response = await api.delete(`${notebookEndpoint}/${id}`); + return response; }; export const updateNotebook = async ( diff --git a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx index e39a7de52..fa00bf0af 100644 --- a/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx +++ b/DashAI/front/src/components/notebooks/DatasetNotebookLeftBar.jsx @@ -111,9 +111,9 @@ export default function DatasetsNotebooksLeftBar({ onToggle }) { removeNotebooksByDatasetId(id); }; - const onNotebookDelete = (id) => { - deleteNotebookById(id); - + const onNotebookDelete = async (id) => { + const success = await deleteNotebookById(id); + if (!success) return; if (id === selectedNotebookId) { clearSelectedNotebook(); setStep(0); diff --git a/DashAI/front/src/hooks/datasets/useNotebooks.js b/DashAI/front/src/hooks/datasets/useNotebooks.js index 531d0e437..7803f1489 100644 --- a/DashAI/front/src/hooks/datasets/useNotebooks.js +++ b/DashAI/front/src/hooks/datasets/useNotebooks.js @@ -34,8 +34,17 @@ export function useNotebooks({ t }) { }; const deleteNotebookById = async (id) => { - setNotebooks((prev) => prev.filter((n) => n.id !== id)); - await deleteNotebook(id); + try { + await deleteNotebook(id); + setNotebooks((prev) => prev.filter((n) => n.id !== id)); + return true; + } catch (error) { + enqueueSnackbar(t("datasets:error.failedToDeleteNotebook"), { + variant: "error", + }); + console.error("Error deleting notebook:", error); + } + return false; }; const editNotebook = async (id, newName) => { diff --git a/DashAI/front/src/utils/i18n/locales/en/datasets.json b/DashAI/front/src/utils/i18n/locales/en/datasets.json index 7fab4bedf..eb1e03b88 100644 --- a/DashAI/front/src/utils/i18n/locales/en/datasets.json +++ b/DashAI/front/src/utils/i18n/locales/en/datasets.json @@ -31,6 +31,7 @@ "failedToCreateDatasetFromNotebook": "Failed to create dataset from notebook", "failedToCreateExplorer": "Failed to create explorer", "failedToDeleteDataset": "Failed to delete dataset", + "failedToDeleteNotebook": "Failed to delete notebook", "failedToFetchDatasets": "Failed to fetch datasets", "failedToFetchNotebooks": "Failed to fetch notebooks", "failedToLoadDatasetInfo": "Failed to fetch dataset info", diff --git a/DashAI/front/src/utils/i18n/locales/es/datasets.json b/DashAI/front/src/utils/i18n/locales/es/datasets.json index e0c57dbb3..819dca52c 100644 --- a/DashAI/front/src/utils/i18n/locales/es/datasets.json +++ b/DashAI/front/src/utils/i18n/locales/es/datasets.json @@ -31,6 +31,7 @@ "failedToCreateDatasetFromNotebook": "Fallo al crear dataset desde cuaderno", "failedToCreateExplorer": "Fallo al crear explorador", "failedToDeleteDataset": "Fallo al eliminar dataset", + "failedToDeleteNotebook": "Fallo al eliminar cuaderno", "failedToFetchDatasets": "Fallo al obtener datasets", "failedToFetchNotebooks": "Fallo al obtener cuadernos", "failedToLoadDatasetInfo": "Fallo al obtener información del dataset", From 37c03e4226b8cdde1410f012742ff5e77887b586 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 16:06:32 -0300 Subject: [PATCH 37/42] Refactor dataset handling to unify deleteDataset references across components, improving code consistency and clarity --- .../custom/contexts/DatasetsAndNotebooksContext.jsx | 2 ++ .../notebooks/notebook/DatasetPreviewNotebook.jsx | 8 ++++++-- DashAI/front/src/hooks/datasets/useDatasets.js | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx index 284345efb..095aee6ee 100644 --- a/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx +++ b/DashAI/front/src/components/custom/contexts/DatasetsAndNotebooksContext.jsx @@ -24,6 +24,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { fetchDatasets, selectDataset, clearSelectedDataset, + deleteDataset, deleteDatasetById, editDataset, addDatasetOptimistically, @@ -60,6 +61,7 @@ export const DatasetsAndNotebooksProvider = ({ children }) => { fetchDatasets, selectDataset, clearSelectedDataset, + deleteDataset, deleteDatasetById, editDataset, addDatasetOptimistically, diff --git a/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx b/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx index 4cea177ec..c7ed74475 100644 --- a/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx +++ b/DashAI/front/src/components/notebooks/notebook/DatasetPreviewNotebook.jsx @@ -41,7 +41,7 @@ export default function DatasetPreviewNotebook({ fetchDatasets, selectDataset, clearSelectedDataset, - deleteDatasetRemote, + deleteDataset, enrichDatasetsWithInfo, replaceDatasets, setStep, @@ -172,7 +172,11 @@ export default function DatasetPreviewNotebook({ { variant: "error" }, ); - deleteDatasetRemote(datasetId).catch(console.error); + try { + await deleteDataset(datasetId); + } catch (e) { + console.error(e); + } clearSelectedDataset(); setStep(0); setSelectedOption(null); diff --git a/DashAI/front/src/hooks/datasets/useDatasets.js b/DashAI/front/src/hooks/datasets/useDatasets.js index 6997dbd96..32fcf092e 100644 --- a/DashAI/front/src/hooks/datasets/useDatasets.js +++ b/DashAI/front/src/hooks/datasets/useDatasets.js @@ -152,6 +152,7 @@ export function useDatasets({ t }) { fetchDatasets, selectDataset, clearSelectedDataset, + deleteDataset, deleteDatasetById, editDataset, addDatasetOptimistically, From 07ee9790e5b978e649fd43d54a33cca0cf711865 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 16:14:51 -0300 Subject: [PATCH 38/42] Refactor DatasetVisualization component to remove redundant state declarations and improve code clarity --- DashAI/front/src/components/DatasetVisualization.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DashAI/front/src/components/DatasetVisualization.jsx b/DashAI/front/src/components/DatasetVisualization.jsx index 45c0051a9..51bf904ab 100644 --- a/DashAI/front/src/components/DatasetVisualization.jsx +++ b/DashAI/front/src/components/DatasetVisualization.jsx @@ -52,6 +52,10 @@ export default function DatasetVisualization({ const { t } = useTranslation(["datasets", "common"]); const theme = useTheme(); + const [datasetInfo, setDatasetInfo] = useState(null); + const [tab, setTab] = useState(0); + const tourContext = useTourContext(); + if (!dataset) { return ( { setTab(0); const fetchDatasetInfo = async () => { From cd42c4b97c9181b5184e984431095ee795dfb8bd Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 4 Feb 2026 17:20:14 -0300 Subject: [PATCH 39/42] Refactor DatasetVisualization component to improve dataset loading handling and ensure consistent state checks --- .../src/components/DatasetVisualization.jsx | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/DashAI/front/src/components/DatasetVisualization.jsx b/DashAI/front/src/components/DatasetVisualization.jsx index 51bf904ab..b98f5cc5f 100644 --- a/DashAI/front/src/components/DatasetVisualization.jsx +++ b/DashAI/front/src/components/DatasetVisualization.jsx @@ -56,37 +56,25 @@ export default function DatasetVisualization({ const [tab, setTab] = useState(0); const tourContext = useTourContext(); - if (!dataset) { - return ( - - - {t("common:loading")} - - ); - } - useEffect(() => { + if (!dataset) return; setTab(0); const fetchDatasetInfo = async () => { if (isProcessing) return; - try { - const info = await getDatasetInfo(dataset.id); + const info = await getDatasetInfo(Number(dataset.id)); setDatasetInfo(info); } catch (error) { setDatasetInfo(null); } }; - fetchDatasetInfo(); - }, [dataset.id, dataset.status]); + }, [dataset && dataset.id, dataset && dataset.status]); // fetchPage compatible with server-side filtering const fetchDatasetPage = useCallback( async (page, pageSize, filterModel) => { - if (isProcessing) return { rows: [], total: 0 }; + if (!dataset || isProcessing) return { rows: [], total: 0 }; try { // Use getDatasetFile if no filters, else use getDatasetFileFiltered const hasFilters = @@ -109,9 +97,24 @@ export default function DatasetVisualization({ return { rows: [], total: 0 }; } }, - [dataset.file_path, dataset.status, dataset.id], + [ + dataset && dataset.file_path, + dataset && dataset.status, + dataset && dataset.id, + ], ); + if (!dataset) { + return ( + + + {t("common:loading")} + + ); + } + const status = dataset.status; const isProcessing = !(status === 3 || status === 4); // Finished or Error From 9501adad8b48b9c457a3401a1f48ca34c3d0a7c0 Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 5 Feb 2026 10:00:47 -0300 Subject: [PATCH 40/42] Refactor DatasetVisualization props to improve clarity and consistency in item handling --- .../src/components/notebooks/dataset/DatasetsCenterContent.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx index f2bd9eb73..bc356ca4e 100644 --- a/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx +++ b/DashAI/front/src/components/notebooks/dataset/DatasetsCenterContent.jsx @@ -79,9 +79,7 @@ export default function DatasetsCenterContent() { return ( From 3911abdc9ed28b390670a60dcc5af180bca3837d Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 5 Feb 2026 10:01:10 -0300 Subject: [PATCH 41/42] Refactor DatasetVisualization component to remove unused onItemCreated prop and streamline existing props for clarity --- DashAI/front/src/components/DatasetVisualization.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/DashAI/front/src/components/DatasetVisualization.jsx b/DashAI/front/src/components/DatasetVisualization.jsx index b98f5cc5f..397adcaa7 100644 --- a/DashAI/front/src/components/DatasetVisualization.jsx +++ b/DashAI/front/src/components/DatasetVisualization.jsx @@ -36,17 +36,14 @@ import { useTranslation } from "react-i18next"; * Can be used across different modules (Notebooks, Models) with customizable action buttons. * @param {Object} props * @param {Object} props.dataset - Dataset object containing id, name, file_path, status, and created date - * @param {Function} props.onItemCreated - Callback function when a new item (notebook/session) is created * @param {Function} props.onNewItem - Callback function when "New Item" button is clicked * @param {string} [props.newItemButtonText="New Item"] - Custom text for the action button (e.g., "New Notebook", "New Session") * @param {Array} [props.existingItems=[]] - Array of existing items (notebooks/sessions) for validation */ export default function DatasetVisualization({ dataset, - onItemCreated, onNewItem, newItemButtonText = "New Item", - existingItems = [], tourContextType = null, }) { const { t } = useTranslation(["datasets", "common"]); From 67f3e493eb1fd35fa8d7fb5601b2247a4ef969bc Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 5 Feb 2026 17:05:48 -0300 Subject: [PATCH 42/42] Refactor DatasetVisualization component to improve dataset fetching logic and enhance processing state handling --- .../src/components/DatasetVisualization.jsx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/DashAI/front/src/components/DatasetVisualization.jsx b/DashAI/front/src/components/DatasetVisualization.jsx index 397adcaa7..836811935 100644 --- a/DashAI/front/src/components/DatasetVisualization.jsx +++ b/DashAI/front/src/components/DatasetVisualization.jsx @@ -30,7 +30,7 @@ import CorrelationsTab from "./notebooks/dataset/tabs/CorrelationsTab"; import { QualityAlerts } from "./notebooks/dataset/QualityAlerts"; import { TextTab } from "./notebooks/dataset/tabs/TextTab"; import { useTranslation } from "react-i18next"; - +import { useDatasetsAndNotebooks } from "./custom/contexts/DatasetsAndNotebooksContext"; /** * Component to visualize dataset information including quality metrics, statistics, and data preview. * Can be used across different modules (Notebooks, Models) with customizable action buttons. @@ -53,11 +53,22 @@ export default function DatasetVisualization({ const [tab, setTab] = useState(0); const tourContext = useTourContext(); + const status = dataset.status; + const isProcessing = !(status === 3 || status === 4); // Finished or Error + + const { fetchDatasets } = useDatasetsAndNotebooks(); + useEffect(() => { if (!dataset) return; + setTab(0); const fetchDatasetInfo = async () => { - if (isProcessing) return; + if (isProcessing) { + setTimeout(() => { + fetchDatasets(); + }, 1000); + return; + } try { const info = await getDatasetInfo(Number(dataset.id)); setDatasetInfo(info); @@ -66,7 +77,7 @@ export default function DatasetVisualization({ } }; fetchDatasetInfo(); - }, [dataset && dataset.id, dataset && dataset.status]); + }, [dataset]); // fetchPage compatible with server-side filtering const fetchDatasetPage = useCallback( @@ -112,9 +123,6 @@ export default function DatasetVisualization({ ); } - const status = dataset.status; - const isProcessing = !(status === 3 || status === 4); // Finished or Error - return ( <>