From 48f34a2af151a90938c8415e84eccb3e4b5182cd Mon Sep 17 00:00:00 2001 From: jeafreezy Date: Sat, 16 Nov 2024 03:09:09 +0000 Subject: [PATCH] revert confirmation page after training settings validation --- frontend/src/app/providers/auth-provider.tsx | 2 +- frontend/src/app/providers/map-provider.tsx | 25 +- .../src/app/providers/models-provider.tsx | 70 ++---- .../src/app/routes/models/confirmation.tsx | 76 +++--- .../src/app/routes/models/models-list.tsx | 6 +- frontend/src/components/map/draw-control.tsx | 9 +- frontend/src/components/map/index.ts | 2 +- frontend/src/components/map/layer-control.tsx | 2 +- .../src/components/map/map-cursor-tooltip.tsx | 44 ++-- frontend/src/components/map/map.tsx | 9 +- frontend/src/components/ui/dialog/dialog.css | 4 +- frontend/src/components/ui/dialog/dialog.tsx | 4 +- .../src/components/ui/form/input/input.tsx | 6 +- .../src/components/ui/form/select/select.tsx | 10 +- .../src/components/ui/tooltip/tooltip.tsx | 6 +- frontend/src/enums/common.ts | 2 +- .../model-creation/api/get-trainings.ts | 2 +- .../components/dialogs/file-upload-dialog.tsx | 15 +- .../model-details/model-details.tsx | 15 +- .../components/progress-buttons.tsx | 16 +- .../training-area/training-area-item.tsx | 23 +- .../training-area/training-area-map.tsx | 72 ++++-- .../training-settings-form.tsx | 132 ++++++----- frontend/src/features/models/api/factory.ts | 3 +- .../src/features/models/api/get-trainings.ts | 7 +- .../dialogs/mobile-filters-dialog.tsx | 2 +- .../dialogs/model-enhancement-dialog.tsx | 30 ++- .../components/dialogs/model-files-dialog.tsx | 18 +- .../dialogs/training-area-dialog.tsx | 2 +- .../dialogs/training-details-dialog.tsx | 10 +- .../dialogs/training-settings-dialog.tsx | 70 +++--- .../models/components/directory-tree.tsx | 33 ++- .../src/features/models/components/header.tsx | 8 +- .../models/components/model-details-info.tsx | 16 +- .../components/model-details-properties.tsx | 14 +- .../components/training-history-table.tsx | 222 +++++++++--------- .../src/features/models/hooks/use-dataset.ts | 14 +- frontend/src/hooks/use-screen-size.ts | 10 +- frontend/src/hooks/use-tooltip-visibility.ts | 49 ++-- frontend/src/services/api-routes.ts | 3 +- frontend/src/styles/index.css | 23 +- frontend/src/utils/constants.ts | 4 +- frontend/src/utils/content.ts | 23 +- frontend/src/utils/geometry-utils.ts | 7 +- 44 files changed, 588 insertions(+), 532 deletions(-) diff --git a/frontend/src/app/providers/auth-provider.tsx b/frontend/src/app/providers/auth-provider.tsx index d6e9ccb3..1a1a30f4 100644 --- a/frontend/src/app/providers/auth-provider.tsx +++ b/frontend/src/app/providers/auth-provider.tsx @@ -97,7 +97,7 @@ export const AuthProvider: React.FC = ({ children }) => { const user = await authService.getUser(); setUser(user); } catch (error) { - showErrorToast(error) + showErrorToast(error); } }; diff --git a/frontend/src/app/providers/map-provider.tsx b/frontend/src/app/providers/map-provider.tsx index a70dc512..b4267a75 100644 --- a/frontend/src/app/providers/map-provider.tsx +++ b/frontend/src/app/providers/map-provider.tsx @@ -1,4 +1,11 @@ -import { createContext, useContext, ReactNode, useState, useMemo, useEffect } from "react"; +import { + createContext, + useContext, + ReactNode, + useState, + useMemo, + useEffect, +} from "react"; import { Map } from "maplibre-gl"; import { TerraDraw } from "terra-draw"; import { setupTerraDraw } from "@/components/map/setup-terra-draw"; @@ -8,14 +15,14 @@ const MapContext = createContext<{ map: Map | null; setMap: React.Dispatch>; terraDraw: TerraDraw | undefined; - drawingMode: DrawingModes, + drawingMode: DrawingModes; setDrawingMode: React.Dispatch>; }>({ map: null, - setMap: () => { }, + setMap: () => {}, terraDraw: undefined, drawingMode: DrawingModes.STATIC, - setDrawingMode: () => DrawingModes + setDrawingMode: () => DrawingModes, }); export const MapProvider = ({ children }: { children: ReactNode }) => { @@ -29,14 +36,18 @@ export const MapProvider = ({ children }: { children: ReactNode }) => { } }, [map]); - const [drawingMode, setDrawingMode] = useState(DrawingModes.STATIC); + const [drawingMode, setDrawingMode] = useState( + DrawingModes.STATIC, + ); // sync the modes useEffect(() => { terraDraw?.setMode(drawingMode); - }, [terraDraw, drawingMode]) + }, [terraDraw, drawingMode]); return ( - + {children} ); diff --git a/frontend/src/app/providers/models-provider.tsx b/frontend/src/app/providers/models-provider.tsx index cb37ff3a..0f3de6c0 100644 --- a/frontend/src/app/providers/models-provider.tsx +++ b/frontend/src/app/providers/models-provider.tsx @@ -5,7 +5,6 @@ import { useSessionStorage } from "@/hooks/use-storage"; import { APPLICATION_ROUTES, HOT_FAIR_MODEL_CREATION_LOCAL_STORAGE_KEY, - MODEL_CREATION_CONTENT, showErrorToast, showSuccessToast, TMS_URL_REGEX_PATTERN, @@ -52,9 +51,7 @@ export enum MODEL_CREATION_FORM_NAME { OAM_TIME_NAME = "oamTileName", OAM_BOUNDS = "oamBounds", TRAINING_AREAS = "trainingAreas", - TRAINING_REQUEST_SUCCESS = 'trainingRequestIsSuccessful', - TRAINING_REQUEST_MESSAGE = 'trainingRequestMessage', - TRAINING_SETTINGS_IS_VALID = 'trainingSettingsIsValid' + TRAINING_SETTINGS_IS_VALID = "trainingSettingsIsValid", } export const FORM_VALIDATION_CONFIG = { @@ -129,8 +126,7 @@ export const FORM_VALIDATION_CONFIG = { max: 8, min: 1, }, - } - + }, }; type FormData = { @@ -154,9 +150,9 @@ type FormData = { batchSize: number; boundaryWidth: number; zoomLevels: number[]; - trainingRequestIsSuccessful: boolean - trainingRequestMessage: string - trainingSettingsIsValid: boolean + trainingRequestIsSuccessful: boolean; + trainingRequestMessage: string; + trainingSettingsIsValid: boolean; }; const initialFormState: FormData = { @@ -185,9 +181,6 @@ const initialFormState: FormData = { boundaryWidth: 3, zoomLevels: [19, 20, 21], trainingSettingsIsValid: true, - // Training requests response - trainingRequestIsSuccessful: true, - trainingRequestMessage: "" }; const ModelsContext = createContext<{ @@ -217,11 +210,11 @@ const ModelsContext = createContext<{ >; hasLabeledTrainingAreas: boolean; hasAOIsWithGeometry: boolean; - resetState: () => void + resetState: () => void; }>({ formData: initialFormState, - setFormData: () => { }, - handleChange: () => { }, + setFormData: () => {}, + handleChange: () => {}, createNewTrainingDatasetMutation: {} as UseMutationResult< TTrainingDataset, Error, @@ -236,7 +229,7 @@ const ModelsContext = createContext<{ >, hasLabeledTrainingAreas: false, hasAOIsWithGeometry: false, - resetState: () => { } + resetState: () => {}, }); export const ModelsProvider: React.FC<{ @@ -278,47 +271,13 @@ export const ModelsProvider: React.FC<{ mutationConfig: { onSuccess: () => { showSuccessToast(TOAST_NOTIFICATIONS.trainingRequestSubmittedSuccess); - handleChange( - MODEL_CREATION_FORM_NAME.TRAINING_REQUEST_SUCCESS, - true - ); - handleChange( - MODEL_CREATION_FORM_NAME.TRAINING_REQUEST_MESSAGE, - MODEL_CREATION_CONTENT.confirmation.trainingRequestSuccess - ); - // delay for a few seconds before resetting the state timeOutRef.current = setTimeout(() => { - setFormData((prevFormData) => ({ - ...initialFormState, - // Preserve the training requests information because it's needed in the confirmation page. - trainingRequestMessage: prevFormData.trainingRequestMessage, - trainingRequestIsSuccessful: prevFormData.trainingRequestIsSuccessful, - })); + setFormData(initialFormState); }, 2000); }, onError: (error) => { showErrorToast(error); - // delay for a few seconds before resetting the state, but keep the data that will be needed for submitting training - // request incase the user wants to do that. - timeOutRef.current = setTimeout(() => { - setFormData((prevFormData) => ({ - ...initialFormState, - // Preserve the training requests information because it's needed in the confirmation page. - trainingRequestMessage: prevFormData.trainingRequestMessage, - trainingRequestIsSuccessful: prevFormData.trainingRequestIsSuccessful, - })); - }, 2000); - - handleChange( - MODEL_CREATION_FORM_NAME.TRAINING_REQUEST_SUCCESS, - false - ); - handleChange( - MODEL_CREATION_FORM_NAME.TRAINING_REQUEST_MESSAGE, - // @ts-expect-error bad type definition - `Your created model could not be trained because ${String(error?.response?.data[0]).toLocaleLowerCase()}. Click on the enhance button below to retrain your model.` - ); }, }, }); @@ -372,7 +331,6 @@ export const ModelsProvider: React.FC<{ ); }, [formData]); - // Confirm that all the training areas labels has been retrieved const hasLabeledTrainingAreas = useMemo(() => { return ( @@ -389,8 +347,8 @@ export const ModelsProvider: React.FC<{ ); }, [formData]); const resetState = () => { - setFormData(initialFormState) - } + setFormData(initialFormState); + }; const memoizedValues = useMemo( () => ({ setFormData, @@ -400,7 +358,7 @@ export const ModelsProvider: React.FC<{ hasLabeledTrainingAreas, hasAOIsWithGeometry, formData, - resetState + resetState, }), [ setFormData, @@ -410,7 +368,7 @@ export const ModelsProvider: React.FC<{ createNewModelMutation, hasLabeledTrainingAreas, hasAOIsWithGeometry, - resetState + resetState, ], ); diff --git a/frontend/src/app/routes/models/confirmation.tsx b/frontend/src/app/routes/models/confirmation.tsx index f44a6c5c..1c94fc6c 100644 --- a/frontend/src/app/routes/models/confirmation.tsx +++ b/frontend/src/app/routes/models/confirmation.tsx @@ -1,59 +1,49 @@ -import { useModelsContext } from "@/app/providers/models-provider"; import ModelFormConfirmation from "@/assets/images/model_creation_success.png"; import { Button } from "@/components/ui/button"; import { Image } from "@/components/ui/image"; import { Link } from "@/components/ui/link"; -import ModelEnhancementDialog from "@/features/models/components/dialogs/model-enhancement-dialog"; -import { useDialog } from "@/hooks/use-dialog"; import { APPLICATION_ROUTES, MODEL_CREATION_CONTENT } from "@/utils"; import ConfettiExplosion from "react-confetti-explosion"; -import { useNavigate, useSearchParams } from "react-router-dom"; +import { useSearchParams } from "react-router-dom"; export const ModelConfirmationPage = () => { const [searchParams] = useSearchParams(); - const modelId = searchParams.get("id"); - const { formData } = useModelsContext(); - const { isOpened, openDialog, closeDialog } = useDialog(); - const navigate = useNavigate(); - const handleClick = () => { - if (formData.trainingRequestIsSuccessful) { - navigate(`${APPLICATION_ROUTES.MODELS}/${modelId}`) - } else { - openDialog() - } - } + const modelId = searchParams.get("id"); return ( - <> - -
-
- - Model Creation Success Icon -

Model {modelId} is Created!

-

- {formData.trainingRequestMessage} -

-
- + + + - - - -
+
- + ); }; diff --git a/frontend/src/app/routes/models/models-list.tsx b/frontend/src/app/routes/models/models-list.tsx index 50db3d0d..eb1d3c9d 100644 --- a/frontend/src/app/routes/models/models-list.tsx +++ b/frontend/src/app/routes/models/models-list.tsx @@ -59,9 +59,9 @@ const ClearFilters = ({ }) => { const canClearAllFilters = Boolean( query[SEARCH_PARAMS.searchQuery] || - query[SEARCH_PARAMS.startDate] || - query[SEARCH_PARAMS.endDate] || - query[SEARCH_PARAMS.id], + query[SEARCH_PARAMS.startDate] || + query[SEARCH_PARAMS.endDate] || + query[SEARCH_PARAMS.id], ); return ( diff --git a/frontend/src/components/map/draw-control.tsx b/frontend/src/components/map/draw-control.tsx index b47b1230..4a66d051 100644 --- a/frontend/src/components/map/draw-control.tsx +++ b/frontend/src/components/map/draw-control.tsx @@ -4,11 +4,8 @@ import { ToolTip } from "@/components/ui/tooltip"; import { PenIcon } from "@/components/ui/icons"; import { useMap } from "@/app/providers/map-provider"; - const DrawControl = () => { - - const { drawingMode, terraDraw, setDrawingMode } = useMap() - + const { drawingMode, terraDraw, setDrawingMode } = useMap(); const changeMode = useCallback( (newMode: DrawingModes) => { @@ -50,8 +47,6 @@ const DrawControl = () => { ); - - return ( <> {renderButton( @@ -61,7 +56,7 @@ const DrawControl = () => { drawingMode === DrawingModes.RECTANGLE, )} - ) + ); }; export default DrawControl; diff --git a/frontend/src/components/map/index.ts b/frontend/src/components/map/index.ts index 65c9f071..3a3aa324 100644 --- a/frontend/src/components/map/index.ts +++ b/frontend/src/components/map/index.ts @@ -3,4 +3,4 @@ export { default as ZoomControls } from "./zoom-controls"; export { default as DrawControl } from "./draw-control"; export { default as ZoomLevel } from "./zoom-level"; export { default as LayerControl } from "./layer-control"; -export { default as MapCursorToolTip } from './map-cursor-tooltip' \ No newline at end of file +export { default as MapCursorToolTip } from "./map-cursor-tooltip"; diff --git a/frontend/src/components/map/layer-control.tsx b/frontend/src/components/map/layer-control.tsx index 434e7774..fe34b4b6 100644 --- a/frontend/src/components/map/layer-control.tsx +++ b/frontend/src/components/map/layer-control.tsx @@ -17,7 +17,7 @@ const LayerControl = ({ }: { map: Map | null; layers: TLayers; - basemaps: TBasemaps + basemaps: TBasemaps; }) => { const { dropdownIsOpened, onDropdownHide, onDropdownShow } = useDropdownMenu(); diff --git a/frontend/src/components/map/map-cursor-tooltip.tsx b/frontend/src/components/map/map-cursor-tooltip.tsx index 55e5b6cc..91b37571 100644 --- a/frontend/src/components/map/map-cursor-tooltip.tsx +++ b/frontend/src/components/map/map-cursor-tooltip.tsx @@ -1,20 +1,30 @@ +import { Map } from "maplibre-gl"; -import { Map, } from "maplibre-gl"; +const MapCursorToolTip = ({ + color, + tooltipVisible, + tooltipPosition, + children, +}: { + map: Map | null; + color?: string; + tooltipPosition: Record; + tooltipVisible: boolean; + children: React.ReactNode; +}) => { + if (!tooltipVisible) return null; -const MapCursorToolTip = ({ color, tooltipVisible, tooltipPosition, children }: { map: Map | null, color?: string, tooltipPosition: Record, tooltipVisible: boolean, children: React.ReactNode }) => { - if (!tooltipVisible) return null + return ( +
+ {children} +
+ ); +}; - return ( -
- {children} -
- ) -} - -export default MapCursorToolTip \ No newline at end of file +export default MapCursorToolTip; diff --git a/frontend/src/components/map/map.tsx b/frontend/src/components/map/map.tsx index cff71952..7a5530ed 100644 --- a/frontend/src/components/map/map.tsx +++ b/frontend/src/components/map/map.tsx @@ -24,7 +24,7 @@ type MapComponentProps = { value: string; subLayer: string; }[]; - children?: React.ReactNode + children?: React.ReactNode; }; const MapComponent: React.FC = ({ @@ -35,7 +35,7 @@ const MapComponent: React.FC = ({ layerControl = false, layerControlLayers = [], layerControlBasemaps = [], - children + children, }) => { const mapContainerRef = useRef(null); const { map, setMap, terraDraw } = useMap(); @@ -48,7 +48,6 @@ const MapComponent: React.FC = ({ maplibreMap.on("load", () => { setMap(maplibreMap); }); - }, []); return ( @@ -60,9 +59,7 @@ const MapComponent: React.FC = ({ <> {geolocationControl && } - {drawControl && terraDraw && ( - - )} + {drawControl && terraDraw && } )} diff --git a/frontend/src/components/ui/dialog/dialog.css b/frontend/src/components/ui/dialog/dialog.css index 82e86220..80bd3743 100644 --- a/frontend/src/components/ui/dialog/dialog.css +++ b/frontend/src/components/ui/dialog/dialog.css @@ -3,8 +3,6 @@ sl-dialog::part(title) { font-weight: var(--hot-fair-font-weight-semibold); } - - sl-dialog.primary::part(title) { - color:var(--hot-fair-color-primary) + color: var(--hot-fair-color-primary); } diff --git a/frontend/src/components/ui/dialog/dialog.tsx b/frontend/src/components/ui/dialog/dialog.tsx index 2ff65a22..21e94186 100644 --- a/frontend/src/components/ui/dialog/dialog.tsx +++ b/frontend/src/components/ui/dialog/dialog.tsx @@ -9,7 +9,7 @@ type DialogProps = { children: React.ReactNode; size?: SHOELACE_SIZES; preventClose?: boolean; - labelColor?: 'default' | "primary" + labelColor?: "default" | "primary"; }; const Dialog: React.FC = ({ isOpened, @@ -18,7 +18,7 @@ const Dialog: React.FC = ({ children, size = "medium", preventClose, - labelColor = "default" + labelColor = "default", }) => { // Prevent the dialog from closing when the user clicks on the overlay function handleRequestClose(event: any) { diff --git a/frontend/src/components/ui/form/input/input.tsx b/frontend/src/components/ui/form/input/input.tsx index ed05375c..b22881b2 100644 --- a/frontend/src/components/ui/form/input/input.tsx +++ b/frontend/src/components/ui/form/input/input.tsx @@ -63,7 +63,7 @@ const Input: React.FC = ({ }; const inputRef = useRef(null); - const { isMobile } = useScreenSize();; + const { isMobile } = useScreenSize(); return ( = ({ ref={inputRef} label={label} // @ts-expect-error bad type definition - size={size ? size : isMobile ? SHOELACE_SIZES.MEDIUM : SHOELACE_SIZES.LARGE} + size={ + size ? size : isMobile ? SHOELACE_SIZES.MEDIUM : SHOELACE_SIZES.LARGE + } minlength={minLength} maxlength={maxLength} // @ts-expect-error bad type definition diff --git a/frontend/src/components/ui/form/select/select.tsx b/frontend/src/components/ui/form/select/select.tsx index 0ba1f2d6..877aec4e 100644 --- a/frontend/src/components/ui/form/select/select.tsx +++ b/frontend/src/components/ui/form/select/select.tsx @@ -12,7 +12,7 @@ type SelectProps = { options?: { name: string; value: string; - suffix?: string + suffix?: string; }[]; defaultValue: string; handleChange: (e: React.ChangeEvent) => void; @@ -30,7 +30,7 @@ const Select: React.FC = ({ handleChange, required, }) => { - const { isMobile } = useScreenSize();; + const { isMobile } = useScreenSize(); return ( = ({ )} {helpText && } {options?.map((option, id) => ( - + {option.name} {option.suffix} diff --git a/frontend/src/components/ui/tooltip/tooltip.tsx b/frontend/src/components/ui/tooltip/tooltip.tsx index aeabb196..acc98f16 100644 --- a/frontend/src/components/ui/tooltip/tooltip.tsx +++ b/frontend/src/components/ui/tooltip/tooltip.tsx @@ -8,9 +8,9 @@ type ToolTipProps = { content?: string; children?: React.ReactNode; placement?: - | ToolTipPlacement.RIGHT - | ToolTipPlacement.BOTTOM - | ToolTipPlacement.TOP; + | ToolTipPlacement.RIGHT + | ToolTipPlacement.BOTTOM + | ToolTipPlacement.TOP; open?: boolean; }; const ToolTip: React.FC = ({ diff --git a/frontend/src/enums/common.ts b/frontend/src/enums/common.ts index a63cb473..529e6ab4 100644 --- a/frontend/src/enums/common.ts +++ b/frontend/src/enums/common.ts @@ -45,5 +45,5 @@ export enum SHOELACE_SIZES { SMALL = "small", MEDIUM = "medium", LARGE = "large", - EXTRA_LARGE = 'extra-large' + EXTRA_LARGE = "extra-large", } diff --git a/frontend/src/features/model-creation/api/get-trainings.ts b/frontend/src/features/model-creation/api/get-trainings.ts index 58618a13..47ca9b9a 100644 --- a/frontend/src/features/model-creation/api/get-trainings.ts +++ b/frontend/src/features/model-creation/api/get-trainings.ts @@ -7,7 +7,7 @@ import { export const getTrainingDatasets = async ( searchQuery: string, - ordering: string = '-id' + ordering: string = "-id", ): Promise => { const res = await apiClient.get( API_ENDPOINTS.GET_TRAINING_DATASETS(searchQuery, ordering), diff --git a/frontend/src/features/model-creation/components/dialogs/file-upload-dialog.tsx b/frontend/src/features/model-creation/components/dialogs/file-upload-dialog.tsx index db4c23eb..de0d7e69 100644 --- a/frontend/src/features/model-creation/components/dialogs/file-upload-dialog.tsx +++ b/frontend/src/features/model-creation/components/dialogs/file-upload-dialog.tsx @@ -48,10 +48,12 @@ const FileUploadDialog: React.FC = ({ }); const onDrop = useCallback((files: FileWithPath[]) => { - const initialValidFiles = files.filter((file) => { if (!file.name.endsWith(".geojson") && !file.name.endsWith(".json")) { - showErrorToast(undefined, `File ${file.name} is not a supported format`); + showErrorToast( + undefined, + `File ${file.name} is not a supported format`, + ); return false; } if (file.size > MAX_TRAINING_AREA_UPLOAD_FILE_SIZE) { @@ -61,7 +63,6 @@ const FileUploadDialog: React.FC = ({ return true; }); - const validateFiles = async () => { const validFiles: { file: FileWithPath; id: string }[] = []; @@ -70,7 +71,10 @@ const FileUploadDialog: React.FC = ({ try { const geojson: FeatureCollection | Feature = JSON.parse(text); if (validateGeoJSONArea(geojson as Feature)) { - showErrorToast(undefined, `File area for ${file.name} exceeds area limit.`); + showErrorToast( + undefined, + `File area for ${file.name} exceeds area limit.`, + ); } else { validFiles.push({ file, id: generateUniqueId() }); } @@ -85,7 +89,6 @@ const FileUploadDialog: React.FC = ({ validateFiles(); }, []); - const clearAcceptedFiles = () => { setAcceptedFiles([]); }; @@ -192,7 +195,7 @@ const FileUploadDialog: React.FC = ({ )); - const { isMobile } = useScreenSize();; + const { isMobile } = useScreenSize(); return ( = ({ case APPLICATION_ROUTES.CREATE_NEW_MODEL: return ( formData.modelName.length >= - FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.MODEL_NAME] - .minLength && + FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.MODEL_NAME] + .minLength && formData.modelDescription.length >= - FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.MODEL_DESCRIPTION] - .minLength + FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.MODEL_DESCRIPTION] + .minLength ); case APPLICATION_ROUTES.CREATE_NEW_MODEL_TRAINING_DATASET: @@ -126,8 +126,8 @@ const ProgressButtons: React.FC = ({ return ( formData.tmsURLValidation.valid && formData.datasetName.length >= - FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.DATASET_NAME] - .minLength + FORM_VALIDATION_CONFIG[MODEL_CREATION_FORM_NAME.DATASET_NAME] + .minLength ); } else if ( formData.trainingDatasetOption === TrainingDatasetOption.USE_EXISTING @@ -139,7 +139,9 @@ const ProgressButtons: React.FC = ({ } case APPLICATION_ROUTES.CREATE_NEW_MODEL_TRAINING_SETTINGS: // confirm that the user has selected at least an option - return formData.zoomLevels.length > 0 && formData.trainingSettingsIsValid; + return ( + formData.zoomLevels.length > 0 && formData.trainingSettingsIsValid + ); case APPLICATION_ROUTES.CREATE_NEW_MODEL_TRAINING_AREA: return ( hasLabeledTrainingAreas && hasAOIsWithGeometry && formData.oamBounds diff --git a/frontend/src/features/model-creation/components/training-area/training-area-item.tsx b/frontend/src/features/model-creation/components/training-area/training-area-item.tsx index 19a64259..2cd83001 100644 --- a/frontend/src/features/model-creation/components/training-area/training-area-item.tsx +++ b/frontend/src/features/model-creation/components/training-area/training-area-item.tsx @@ -55,9 +55,7 @@ const TrainingAreaItem: React.FC< showSuccessToast(TOAST_NOTIFICATIONS.trainingLabelsFetchSuccess); }, onError: (error) => { - showErrorToast( - error - ); + showErrorToast(error); }, }, }); @@ -200,9 +198,10 @@ const TrainingAreaItem: React.FC< return () => clearInterval(intervalId); }, [trainingArea?.properties?.label_fetched]); - const trainingAreaSize = useMemo(() => { - return trainingArea.geometry ? formatAreaInAppropriateUnit(calculateGeoJSONArea(trainingArea)) : '0 m²' + return trainingArea.geometry + ? formatAreaInAppropriateUnit(calculateGeoJSONArea(trainingArea)) + : "0 m²"; }, [trainingArea]); return ( @@ -212,17 +211,19 @@ const TrainingAreaItem: React.FC<

ID: {trainingArea.id}

-

+

{truncateString(trainingAreaSize, 15)}

-

+

{trainingAreaLabelsMutation.isPending ? "Fetching labels..." : trainingArea.properties.label_fetched !== null - ? truncateString(`Fetched ${timeSinceLabelFetch === "0 sec" ? 'just now' : `${timeSinceLabelFetch} ago`}`, 20) + ? truncateString( + `Fetched ${timeSinceLabelFetch === "0 sec" ? "just now" : `${timeSinceLabelFetch} ago`}`, + 20, + ) : "No labels yet"}

diff --git a/frontend/src/features/model-creation/components/training-area/training-area-map.tsx b/frontend/src/features/model-creation/components/training-area/training-area-map.tsx index 37ca5e72..390b2408 100644 --- a/frontend/src/features/model-creation/components/training-area/training-area-map.tsx +++ b/frontend/src/features/model-creation/components/training-area/training-area-map.tsx @@ -58,7 +58,10 @@ const TrainingAreaMap = ({ const [featureArea, setFeatureArea] = useState(0); - const { setTooltipVisible, tooltipPosition, } = useToolTipVisibility([drawingMode, currentZoom]); + const { setTooltipVisible, tooltipPosition } = useToolTipVisibility([ + drawingMode, + currentZoom, + ]); const debouncedBbox = useDebounce(bbox, 300); const debouncedZoom = useDebounce(currentZoom.toString(), 300); @@ -95,12 +98,16 @@ const TrainingAreaMap = ({ "https://mt3.google.com/vt/lyrs=s&x={x}&y={y}&z={z}", ], attribution: "© Google", - tileSize: 256 + tileSize: 256, }); } if (!map.getSource(TMSSourceId)) { - map.addSource(TMSSourceId, { type: "raster", url: tileJSONURL, tileSize: 256 }); + map.addSource(TMSSourceId, { + type: "raster", + url: tileJSONURL, + tileSize: 256, + }); } if (data?.results && !map.getSource(trainingAreasSourceId)) { @@ -144,7 +151,6 @@ const TrainingAreaMap = ({ layout: { visibility: "none" }, minzoom: 0, maxzoom: 22, - }); } @@ -154,7 +160,6 @@ const TrainingAreaMap = ({ type: "raster", source: TMSSourceId, layout: { visibility: "visible" }, - }); } if (data?.results && !map.getLayer(trainingAreasFillLayerId)) { @@ -174,7 +179,10 @@ const TrainingAreaMap = ({ id: trainingAreasLayerId, type: "line", source: trainingAreasSourceId, - paint: { "line-color": TRAINING_AREAS_AOI_OUTLINE_COLOR, "line-width": 4 }, + paint: { + "line-color": TRAINING_AREAS_AOI_OUTLINE_COLOR, + "line-width": 4, + }, layout: { visibility: "visible" }, }); } @@ -216,7 +224,6 @@ const TrainingAreaMap = ({ "line-width": 1, }, layout: { visibility: "visible" }, - }); } }, [map, tileJSONURL, data?.results, labels]); @@ -319,7 +326,6 @@ const TrainingAreaMap = ({ updateTrainingLabels(); }, [labels]); - // drawing events and tooltip useEffect(() => { if (!terraDraw || !map) return; @@ -332,7 +338,7 @@ const TrainingAreaMap = ({ const handleFinish = async () => { const snapshot = terraDraw.getSnapshot(); setFeatureArea(0); - setDrawingMode(DrawingModes.STATIC) + setDrawingMode(DrawingModes.STATIC); setTooltipVisible(false); if (snapshot) { const drawnFeature = snapshot[snapshot.length - 1]; @@ -362,14 +368,13 @@ const TrainingAreaMap = ({ }; }, [terraDraw, drawingMode, setDrawingMode]); - const showLabelsToolTip = currentZoom >= 14 && currentZoom < 18; - const showTooltip = Boolean(drawingMode === DrawingModes.RECTANGLE || showLabelsToolTip); - + const showTooltip = Boolean( + drawingMode === DrawingModes.RECTANGLE || showLabelsToolTip, + ); const getTooltipColor = () => { - if (featureArea !== 0) { if ( featureArea < MIN_TRAINING_AREA_SIZE || @@ -399,9 +404,7 @@ const TrainingAreaMap = ({ return; }; - return ( - 0 - ? [{ value: "Training Labels", subLayers: [trainingDatasetLabelsLayerId, trainingDatasetLabelsOutlineLayerId] }] + ? [ + { + value: "Training Labels", + subLayers: [ + trainingDatasetLabelsLayerId, + trainingDatasetLabelsOutlineLayerId, + ], + }, + ] : []), ]} > - - {!showLabelsToolTip &&

- {drawingMode === DrawingModes.RECTANGLE && featureArea === 0 - ? "Click and drag to draw a rectangle." - : `Current area: ${formatAreaInAppropriateUnit(featureArea)}`} -

- } + + {!showLabelsToolTip && ( +

+ {drawingMode === DrawingModes.RECTANGLE && featureArea === 0 + ? "Click and drag to draw a rectangle." + : `Current area: ${formatAreaInAppropriateUnit(featureArea)}`} +

+ )}

{getFeedbackMessage()}

- - ); }; diff --git a/frontend/src/features/model-creation/components/training-settings/training-settings-form.tsx b/frontend/src/features/model-creation/components/training-settings/training-settings-form.tsx index 44cab9b1..d0e028e0 100644 --- a/frontend/src/features/model-creation/components/training-settings/training-settings-form.tsx +++ b/frontend/src/features/model-creation/components/training-settings/training-settings-form.tsx @@ -21,13 +21,10 @@ const trainingTypes = [ { label: TrainingType.ADVANCED, Icon: AdvancedGuageIcon }, ]; - - - const TrainingSettingsForm = () => { const [showAdvancedSettings, setShowAdvancedSettings] = useState(false); - const [validationMessage, setValidationMessage] = useState('Hellow') + const [validationMessage, setValidationMessage] = useState("Hellow"); const { formData, handleChange } = useModelsContext(); const advancedSettings = [ @@ -35,7 +32,7 @@ const TrainingSettingsForm = () => { label: MODEL_CREATION_CONTENT.trainingSettings.form.epoch.label, value: MODEL_CREATION_FORM_NAME.EPOCH, toolTip: MODEL_CREATION_CONTENT.trainingSettings.form.epoch.toolTip, - enabled: true + enabled: true, }, { label: MODEL_CREATION_CONTENT.trainingSettings.form.contactSpacing.label, @@ -43,19 +40,19 @@ const TrainingSettingsForm = () => { toolTip: MODEL_CREATION_CONTENT.trainingSettings.form.contactSpacing.toolTip, enabled: formData.baseModel === BASE_MODELS.RAMP, - }, { label: MODEL_CREATION_CONTENT.trainingSettings.form.batchSize.label, value: MODEL_CREATION_FORM_NAME.BATCH_SIZE, toolTip: MODEL_CREATION_CONTENT.trainingSettings.form.batchSize.toolTip, - enabled: true + enabled: true, }, { label: MODEL_CREATION_CONTENT.trainingSettings.form.boundaryWidth.label, value: MODEL_CREATION_FORM_NAME.BOUNDARY_WIDTH, - toolTip: MODEL_CREATION_CONTENT.trainingSettings.form.boundaryWidth.toolTip, - enabled: formData.baseModel === BASE_MODELS.RAMP + toolTip: + MODEL_CREATION_CONTENT.trainingSettings.form.boundaryWidth.toolTip, + enabled: formData.baseModel === BASE_MODELS.RAMP, }, ]; @@ -80,7 +77,6 @@ const TrainingSettingsForm = () => { }, }; - useEffect(() => { handleChange( MODEL_CREATION_FORM_NAME.EPOCH, @@ -182,58 +178,74 @@ const TrainingSettingsForm = () => { /> - {showAdvancedSettings && (<> -
- {advancedSettings.filter(setting => setting.enabled).map((setting, id) => ( -
- { - const inputValue = Number(e.target.value); - - const min = + {showAdvancedSettings && ( + <> +
+ {advancedSettings + .filter((setting) => setting.enabled) + .map((setting, id) => ( +
+ max) { - // Set validation message for out-of-range values - setValidationMessage( - `${setting.label} must be between ${min} and ${max}.` - ); - handleChange(MODEL_CREATION_FORM_NAME.TRAINING_SETTINGS_IS_VALID, false) - } else { - // Clear the validation message if the value is valid - setValidationMessage(""); - handleChange(setting.value, inputValue); - handleChange(MODEL_CREATION_FORM_NAME.TRAINING_SETTINGS_IS_VALID, true) - } - }} - toolTipContent={setting.toolTip} - /> -
- ))} -
-

{validationMessage}

- + value={formData[setting.value]} + min={ + // @ts-expect-error bad type definition + FORM_VALIDATION_CONFIG[formData.baseModel][ + setting.value + ].min + } + max={ + // @ts-expect-error bad type definition + FORM_VALIDATION_CONFIG[formData.baseModel][ + setting.value + ].max + } + handleInput={(e) => { + const inputValue = Number(e.target.value); + + const min = + // @ts-expect-error bad type definition + FORM_VALIDATION_CONFIG[formData.baseModel][ + setting.value + ].min; + const max = + // @ts-expect-error bad type definition + FORM_VALIDATION_CONFIG[formData.baseModel][ + setting.value + ].max; + handleChange(setting.value, inputValue); + if (inputValue < min || inputValue > max) { + // Set validation message for out-of-range values + setValidationMessage( + `${setting.label} must be between ${min} and ${max}.`, + ); + handleChange( + MODEL_CREATION_FORM_NAME.TRAINING_SETTINGS_IS_VALID, + false, + ); + } else { + // Clear the validation message if the value is valid + setValidationMessage(""); + handleChange(setting.value, inputValue); + handleChange( + MODEL_CREATION_FORM_NAME.TRAINING_SETTINGS_IS_VALID, + true, + ); + } + }} + toolTipContent={setting.toolTip} + /> +
+ ))} +
+

{validationMessage}

+ )} - ); diff --git a/frontend/src/features/models/api/factory.ts b/frontend/src/features/models/api/factory.ts index a9c2cfc8..f0ea3d52 100644 --- a/frontend/src/features/models/api/factory.ts +++ b/frontend/src/features/models/api/factory.ts @@ -110,10 +110,9 @@ export const getTrainingHistoryQueryOptions = ( }); }; - export const getTrainingDatasetQueryOptions = (id: number) => { return queryOptions({ queryKey: ["training-dataset", id], queryFn: () => getTrainingDataset(id), }); -}; \ No newline at end of file +}; diff --git a/frontend/src/features/models/api/get-trainings.ts b/frontend/src/features/models/api/get-trainings.ts index 22780bb5..f9e4119f 100644 --- a/frontend/src/features/models/api/get-trainings.ts +++ b/frontend/src/features/models/api/get-trainings.ts @@ -61,12 +61,9 @@ export const getTrainingWorkspace = async ( return res.data; }; - export const getTrainingDataset = async ( id: number, ): Promise => { - const res = await apiClient.get( - API_ENDPOINTS.GET_TRAINING_DATASET(id), - ); - return res.data + const res = await apiClient.get(API_ENDPOINTS.GET_TRAINING_DATASET(id)); + return res.data; }; diff --git a/frontend/src/features/models/components/dialogs/mobile-filters-dialog.tsx b/frontend/src/features/models/components/dialogs/mobile-filters-dialog.tsx index da1f2e53..eca6b938 100644 --- a/frontend/src/features/models/components/dialogs/mobile-filters-dialog.tsx +++ b/frontend/src/features/models/components/dialogs/mobile-filters-dialog.tsx @@ -36,7 +36,7 @@ const MobileModelFiltersDialog: React.FC = ({ updateQuery, disabled, }) => { - const { isMobile } = useScreenSize();; + const { isMobile } = useScreenSize(); return ( void; - modelId: string + modelId: string; }; const ModelEnhancementDialog: React.FC = ({ isOpened, - closeDialog, modelId + closeDialog, + modelId, }) => { - const { isOpened: isTrainingSettingsDialogOpened, openDialog, closeDialog: closeTrainingSettingsDialog } = useDialog(); + const { + isOpened: isTrainingSettingsDialogOpened, + openDialog, + closeDialog: closeTrainingSettingsDialog, + } = useDialog(); const options = [ { @@ -22,7 +27,7 @@ const ModelEnhancementDialog: React.FC = ({ description: APP_CONTENT.models.modelsDetailsCard.modelEnhancement.newSettings .description, - onClick: openDialog + onClick: openDialog, }, { name: APP_CONTENT.models.modelsDetailsCard.modelEnhancement.trainingData @@ -34,9 +39,9 @@ const ModelEnhancementDialog: React.FC = ({ ]; const handleClose = () => { - closeDialog() - closeTrainingSettingsDialog() - } + closeDialog(); + closeTrainingSettingsDialog(); + }; return ( = ({ closeDialog={closeDialog} label={APP_CONTENT.models.modelsDetailsCard.modelUpdate.dialogHeading} > - +
    {options.map((option, id) => (
  • -