diff --git a/src/App.tsx b/src/App.tsx index a6396579..5ce0e9c3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -499,8 +499,8 @@ const AppContent: React.FC = ({ project, setProject }): React.J storage={storage} setAlertErrorMessage={setAlertErrorMessage} gotoTab={setActiveTab} - project={project} - setProject={setProject} + currentProject={project} + setCurrentProject={setProject} onProjectChanged={onProjectChanged} openWPIToolboxSettings={() => setToolboxSettingsModalIsOpen(true)} theme={theme} diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index 065d94e5..155ed722 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -54,6 +54,7 @@ "ACTIONS": "Actions", "DELETE_PROJECT_CONFIRM": "Delete {{projectName}}?", "DELETE_CANNOT_BE_UNDONE": "This action cannot be undone.", + "PROJECT_MANAGEMENT": "Project Management", "NO_PROJECTS_FOUND": "No projects found", "CREATE_PROJECT_TO_START": "Please create a new project to get started.", "PAGINATION_ITEMS": "{{range0}}-{{range1}} of {{total}} items", diff --git a/src/i18n/locales/es/translation.json b/src/i18n/locales/es/translation.json index c2992fb0..6469f9b7 100644 --- a/src/i18n/locales/es/translation.json +++ b/src/i18n/locales/es/translation.json @@ -51,6 +51,7 @@ "ACTIONS": "Acciones", "DELETE_PROJECT_CONFIRM": "¿Eliminar {{projectName}}?", "DELETE_CANNOT_BE_UNDONE": "Esta acción no se puede deshacer.", + "PROJECT_MANAGEMENT": "Gestión de proyectos", "NO_PROJECTS_FOUND": "No se encontraron proyectos", "CREATE_PROJECT_TO_START": "Por favor crea un nuevo proyecto para comenzar.", "PAGINATION_ITEMS": "{{range0}}-{{range1}} de {{total}} elementos", diff --git a/src/i18n/locales/he/translation.json b/src/i18n/locales/he/translation.json index ba07351d..2f81359e 100644 --- a/src/i18n/locales/he/translation.json +++ b/src/i18n/locales/he/translation.json @@ -54,6 +54,7 @@ "ACTIONS": "פעולות", "DELETE_PROJECT_CONFIRM": "מחק את {{projectName}}?", "DELETE_CANNOT_BE_UNDONE": "פעולה זו לא ניתנת לביטול.", + "PROJECT_MANAGEMENT": "ניהול פרויקטים", "NO_PROJECTS_FOUND": "לא נמצאו פרויקטים", "CREATE_PROJECT_TO_START": "אנא צור פרויקט חדש כדי להתחיל.", "PAGINATION_ITEMS": "{{range0}}-{{range1}} מתוך {{total}} פריטים", diff --git a/src/reactComponents/Menu.tsx b/src/reactComponents/Menu.tsx index 4c73bcaf..12d751f7 100644 --- a/src/reactComponents/Menu.tsx +++ b/src/reactComponents/Menu.tsx @@ -58,8 +58,8 @@ export interface MenuProps { storage: commonStorage.Storage | null; setAlertErrorMessage: (message: string) => void; gotoTab: (tabKey: string) => void; - project: storageProject.Project | null; - setProject: (project: storageProject.Project | null) => void; + currentProject: storageProject.Project | null; + setCurrentProject: (project: storageProject.Project | null) => void; onProjectChanged: () => Promise; openWPIToolboxSettings: () => void; theme: string; @@ -137,20 +137,20 @@ function getMenuItems(t: (key: string) => string, project: storageProject.Projec getItem(t('THEME') + '...', 'theme', ), getItem(t('LANGUAGE'), 'language', , [ getItem( - t('ENGLISH'), - 'setlang:en', + t('ENGLISH'), + 'setlang:en', currentLanguage === 'en' ? : undefined ), getItem( - t('SPANISH'), - 'setlang:es', + t('SPANISH'), + 'setlang:es', currentLanguage === 'es' ? : undefined ), getItem( - t('HEBREW'), - 'setlang:he', + t('HEBREW'), + 'setlang:he', currentLanguage === 'he' ? : undefined - ), + ), ]), ]), getItem(t('HELP'), 'help', , [ @@ -223,7 +223,7 @@ export function Component(props: MenuProps): React.JSX.Element { } if (projectNameToFetch) { const project = await storageProject.fetchProject(props.storage, projectNameToFetch); - props.setProject(project); + props.setCurrentProject(project); } } }; @@ -233,15 +233,15 @@ export function Component(props: MenuProps): React.JSX.Element { if (props.storage) { await props.storage.saveEntry( MOST_RECENT_PROJECT_NAME_KEY, - props.project?.projectName || '' + props.currentProject?.projectName || '' ); } }; /** Handles menu item clicks. */ const handleClick: Antd.MenuProps['onClick'] = ({key}): void => { - const newModule = props.project ? - storageProject.findModuleByModulePath(props.project, key) : + const newModule = props.currentProject ? + storageProject.findModuleByModulePath(props.currentProject, key) : null; if (newModule) { @@ -284,7 +284,7 @@ export function Component(props: MenuProps): React.JSX.Element { /** Handles the deploy action to generate and download Python files. */ const handleDeploy = async (): Promise => { - if (!props.project) { + if (!props.currentProject) { props.setAlertErrorMessage(t('NO_PROJECT_SELECTED')); return; } @@ -293,16 +293,16 @@ export function Component(props: MenuProps): React.JSX.Element { } try { - const blobUrl = await createPythonFiles.producePythonProjectBlob(props.project, props.storage); + const blobUrl = await createPythonFiles.producePythonProjectBlob(props.currentProject, props.storage); // Create a temporary link to download the file const link = document.createElement('a'); link.href = blobUrl; - link.download = `${props.project.projectName}.zip`; + link.download = `${props.currentProject.projectName}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); - + // Clean up the blob URL URL.revokeObjectURL(blobUrl); } catch (error) { @@ -314,7 +314,7 @@ export function Component(props: MenuProps): React.JSX.Element { // TODO: Add UI for the download action. /** Handles the download action to generate and download json files. */ const handleDownload = async (): Promise => { - if (!props.project) { + if (!props.currentProject) { props.setAlertErrorMessage(t('NO_PROJECT_SELECTED')); return; } @@ -323,8 +323,8 @@ export function Component(props: MenuProps): React.JSX.Element { } try { - const blobUrl = await storageProject.downloadProject(props.storage, props.project.projectName); - const filename = props.project.projectName + storageNames.UPLOAD_DOWNLOAD_FILE_EXTENSION; + const blobUrl = await storageProject.downloadProject(props.storage, props.currentProject.projectName); + const filename = props.currentProject.projectName + storageNames.UPLOAD_DOWNLOAD_FILE_EXTENSION; // Create a temporary link to download the file const link = document.createElement('a'); @@ -415,19 +415,19 @@ export function Component(props: MenuProps): React.JSX.Element { // Update menu items and save project when project or language changes React.useEffect(() => { - if (props.project) { + if (props.currentProject) { setMostRecentProjectName(); - setMenuItems(getMenuItems(t, props.project, i18n.language)); + setMenuItems(getMenuItems(t, props.currentProject, i18n.language)); setNoProjects(false); } - }, [props.project, i18n.language]); + }, [props.currentProject, i18n.language]); return ( <> } size="small" - disabled={!props.project} + disabled={!props.currentProject} onClick={handleDownload} style={{ color: 'white' }} /> diff --git a/src/reactComponents/ProjectManageModal.tsx b/src/reactComponents/ProjectManageModal.tsx index 61114f10..b55a4c7a 100644 --- a/src/reactComponents/ProjectManageModal.tsx +++ b/src/reactComponents/ProjectManageModal.tsx @@ -31,7 +31,8 @@ interface ProjectManageModalProps { isOpen: boolean; noProjects: boolean; onCancel: () => void; - setProject: (project: storageProject.Project | null) => void; + currentProject: storageProject.Project | null; + setCurrentProject: (project: storageProject.Project | null) => void; setAlertErrorMessage: (message: string) => void; storage: commonStorage.Storage | null; } @@ -87,7 +88,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac if (projectNames.length > 0 && props.noProjects) { // Set the first project as the current project const project = await storageProject.fetchProject(storage, projectNames[0]); - props.setProject(project); + props.setCurrentProject(project); props.onCancel(); // Close the modal after selecting } }; @@ -109,7 +110,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac console.error('Error renaming project:', error); props.setAlertErrorMessage(t('FAILED_TO_RENAME_PROJECT')); } - + setRenameModalOpen(false); }; @@ -130,7 +131,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac console.error('Error copying project:', error); props.setAlertErrorMessage(t('FAILED_TO_COPY_PROJECT')); } - + setCopyModalOpen(false); }; @@ -157,37 +158,37 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac }; /** Handles project deletion with proper cleanup. */ - const handleDeleteProject = async (project: ProjectRecord): Promise => { + const handleDeleteProject = async (projectToDelete: ProjectRecord): Promise => { if (!props.storage) { return; } - const updatedProjectNames = allProjectNames.filter(projectName => projectName !== project.name); + const updatedProjectNames = allProjectNames.filter(projectName => projectName !== projectToDelete.name); setAllProjectNames(updatedProjectNames); - const updatedProjectRecords = allProjectRecords.filter((r) => r.name !== project.name); + const updatedProjectRecords = allProjectRecords.filter((r) => r.name !== projectToDelete.name); setAllProjectRecords(updatedProjectRecords); - // Find another project to set as current - let foundAnotherProject = false; - for (const projectName of allProjectNames) { - if (projectName !== project.name) { - const project = await storageProject.fetchProject(props.storage, projectName); - props.setProject(project); - foundAnotherProject = true; - break; + let projectToSelect: storageProject.Project | null = null; + if (props.currentProject && props.currentProject.projectName === projectToDelete.name) { + // Find another project to set as current + for (const projectName of allProjectNames) { + if (projectName !== projectToDelete.name) { + projectToSelect = await storageProject.fetchProject(props.storage, projectName); + break; + } } } - if (!foundAnotherProject) { - props.setProject(null); - } - try { - await storageProject.deleteProject(props.storage, project.name); + await storageProject.deleteProject(props.storage, projectToDelete.name); } catch (e) { console.error('Failed to delete the project:', e); props.setAlertErrorMessage(t('FAILED_TO_DELETE_PROJECT')); } + + if (projectToSelect) { + props.setCurrentProject(projectToSelect); + } }; /** Handles project selection. */ @@ -197,7 +198,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac } const project = await storageProject.fetchProject(props.storage, projectRecord.name); - props.setProject(project); + props.setCurrentProject(project); props.onCancel(); }; @@ -256,8 +257,8 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac handleRename(currentRecord.name, name); } }} - okText={t('Rename')} - cancelText={t('Cancel')} + okText={t('RENAME')} + cancelText={t('CANCEL')} > {currentRecord && ( {currentRecord && (

{t('CREATE_NEW', { type: t('PROJECT') })} -

+