diff --git a/src/App.tsx b/src/App.tsx index 074247aa..a449a07d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -581,12 +581,17 @@ const AppContent: React.FC = ({ project, setProject }): React.J } }, [project]); - // Update tab items when fetching modules is done. + // Update tab items when ever the modules in the project change. React.useEffect(() => { if (project) { const tabs = createTabItemsFromProject(project); setTabItems(tabs); - setActiveTab(project.robot.modulePath); + + // Only set active tab to robot if no active tab is set or if the current active tab no longer exists + const currentActiveTabExists = tabs.some(tab => tab.key === activeTab); + if (!activeTab || !currentActiveTabExists) { + setActiveTab(project.robot.modulePath); + } } }, [modulePathToContentText]); diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index f45f0106..f2561b70 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -20,6 +20,7 @@ "search": "Search..." }, "PROJECT": "Project", + "PROJECTS": "Projects", "SAVE": "Save", "DEPLOY": "Deploy", "MANAGE": "Manage", @@ -37,11 +38,35 @@ "SELECT_HIDDEN": "Select Hidden", "NO_HIDDEN_MECHANISMS": "No Hidden Mechanisms", "NO_HIDDEN_OPMODES": "No Hidden Opmodes", - "CREATE_NEW": "Create New", + "CREATE_NEW": "Create New {{type}}", "CREATE": "Create", "BLOCKS": "Blocks", "CODE": "Code", "COPY": "Copy", + "FAILED_TO_RENAME_PROJECT": "Failed to rename project", + "FAILED_TO_COPY_PROJECT": "Failed to copy project", + "FAILED_TO_CREATE_PROJECT": "Failed to create a new project.", + "FAILED_TO_DELETE_PROJECT": "Failed to delete the project.", + "RENAME_PROJECT": "Rename Project", + "COPY_PROJECT": "Copy Project", + "NAME": "Name", + "ACTIONS": "Actions", + "DELETE_PROJECT_CONFIRM": "Delete {{projectName}}?", + "DELETE_CANNOT_BE_UNDONE": "This action cannot be undone.", + "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", + "FAILED_TO_RENAME_MODULE": "Failed to rename module", + "FAILED_TO_COPY_MODULE": "Failed to copy module", + "MODULE_NOT_FOUND_FOR_COPYING": "Original module not found for copying", + "COPY_SUFFIX": "{{name}} (copy)", + "DELETE_MODULE_CONFIRM": "Delete {{title}}?", + "MANAGEMENT": "Management", + "TYPE_MANAGEMENT": "{{type}} Management", + "RENAME_TYPE_TITLE": "Rename {{type}}: {{title}}", + "COPY_TYPE_TITLE": "Copy {{type}}: {{title}}", + "RENAME": "Rename", + "NO_FILES_FOUND": "No {{type}} files found", "MECHANISMS": "Mechanisms", "OPMODES": "OpModes", "BLOCKLY":{ @@ -103,7 +128,8 @@ "EVENTS": "Events", "ADD_MECHANISM": "+ Mechanism", "ADD_COMPONENT": "+ Component", - "TEST": "Test" + "TEST": "Test", + "PAGINATION_TOTAL": "{{start}}-{{end}} of {{total}} items" }, "WARNING":{ "CALL_COMPONENT_INSTANCE_METHOD_PRIVATE_COMPONENT": "This blocks calls a method on a private component in the {{mechanismClassName}} mechanism.", diff --git a/src/i18n/locales/es/translation.json b/src/i18n/locales/es/translation.json index 60565328..b7c84a1e 100644 --- a/src/i18n/locales/es/translation.json +++ b/src/i18n/locales/es/translation.json @@ -17,6 +17,7 @@ "example_opmode": "Por ejemplo: AutoEstacionarYDisparar", "example_project": "Por ejemplo: RobotRuedasLocas", "PROJECT": "Proyecto", + "PROJECTS": "Proyectos", "SAVE": "Guardar", "DEPLOY": "Desplegar", "MANAGE": "Gestionar", @@ -34,11 +35,35 @@ "SELECT_HIDDEN": "Seleccionar Oculto", "NO_HIDDEN_MECHANISMS": "No Hay Mecanismos Ocultos", "NO_HIDDEN_OPMODES": "No Hay Opmodes Ocultos", - "CREATE_NEW": "Crear Nuevo", + "CREATE_NEW": "Crear Nuevo {{type}}", "CREATE": "Crear", "BLOCKS": "Bloques", "CODE": "Código", "COPY": "Copiar", + "FAILED_TO_RENAME_PROJECT": "Error al renombrar proyecto", + "FAILED_TO_COPY_PROJECT": "Error al copiar proyecto", + "FAILED_TO_CREATE_PROJECT": "Error al crear un nuevo proyecto.", + "FAILED_TO_DELETE_PROJECT": "Error al eliminar el proyecto.", + "RENAME_PROJECT": "Renombrar Proyecto", + "COPY_PROJECT": "Copiar Proyecto", + "NAME": "Nombre", + "ACTIONS": "Acciones", + "DELETE_PROJECT_CONFIRM": "¿Eliminar {{projectName}}?", + "DELETE_CANNOT_BE_UNDONE": "Esta acción no se puede deshacer.", + "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", + "FAILED_TO_RENAME_MODULE": "Error al renombrar módulo", + "FAILED_TO_COPY_MODULE": "Error al copiar módulo", + "MODULE_NOT_FOUND_FOR_COPYING": "Módulo original no encontrado para copiar", + "COPY_SUFFIX": "{{name}} (copia)", + "DELETE_MODULE_CONFIRM": "¿Eliminar {{title}}?", + "MANAGEMENT": "Gestión", + "TYPE_MANAGEMENT": "Gestión de {{type}}", + "RENAME_TYPE_TITLE": "Renombrar {{type}}: {{title}}", + "COPY_TYPE_TITLE": "Copiar {{type}}: {{title}}", + "RENAME": "Renombrar", + "NO_FILES_FOUND": "No se encontraron archivos de {{type}}", "addTabDialog": { "title": "Agregar Pestaña", "search": "Buscar..." @@ -104,7 +129,8 @@ "EVENTS": "Eventos", "ADD_MECHANISM": "+ Mecanismo", "ADD_COMPONENT": "+ Componente", - "TEST": "Prueba" + "TEST": "Prueba", + "PAGINATION_TOTAL": "{{start}}-{{end}} de {{total}} elementos" }, "WARNING":{ "CALL_COMPONENT_INSTANCE_METHOD_PRIVATE_COMPONENT": "Este bloque llama a un método en un componente privado en el mecanismo {{mechanismClassName}}.", diff --git a/src/i18n/locales/he/translation.json b/src/i18n/locales/he/translation.json index 911fc987..f748ff3a 100644 --- a/src/i18n/locales/he/translation.json +++ b/src/i18n/locales/he/translation.json @@ -20,6 +20,7 @@ "search": "חיפוש..." }, "PROJECT": "פרויקט", + "PROJECTS": "פרויקטים", "SAVE": "שמור", "DEPLOY": "העלה לרובוט", "MANAGE": "ניהול", @@ -37,11 +38,35 @@ "SELECT_HIDDEN": "בחר נסתר", "NO_HIDDEN_MECHANISMS": "אין מנגנונים נסתרים", "NO_HIDDEN_OPMODES": "אין אופמודים נסתרים", - "CREATE_NEW": "צור חדש", + "CREATE_NEW": "צור {{type}} חדש", "CREATE": "צור", "BLOCKS": "בלוקים", "CODE": "קוד", "COPY": "העתק", + "FAILED_TO_RENAME_PROJECT": "נכשל בשינוי שם הפרויקט", + "FAILED_TO_COPY_PROJECT": "נכשל בהעתקת הפרויקט", + "FAILED_TO_CREATE_PROJECT": "נכשל ביצירת פרויקט חדש.", + "FAILED_TO_DELETE_PROJECT": "נכשל במחיקת הפרויקט.", + "RENAME_PROJECT": "שנה שם פרויקט", + "COPY_PROJECT": "העתק פרויקט", + "NAME": "שם", + "ACTIONS": "פעולות", + "DELETE_PROJECT_CONFIRM": "מחק את {{projectName}}?", + "DELETE_CANNOT_BE_UNDONE": "פעולה זו לא ניתנת לביטול.", + "NO_PROJECTS_FOUND": "לא נמצאו פרויקטים", + "CREATE_PROJECT_TO_START": "אנא צור פרויקט חדש כדי להתחיל.", + "PAGINATION_ITEMS": "{{range0}}-{{range1}} מתוך {{total}} פריטים", + "FAILED_TO_RENAME_MODULE": "נכשל בשינוי שם המודול", + "FAILED_TO_COPY_MODULE": "נכשל בהעתקת המודול", + "MODULE_NOT_FOUND_FOR_COPYING": "המודול המקורי לא נמצא להעתקה", + "COPY_SUFFIX": "{{name}} (עותק)", + "DELETE_MODULE_CONFIRM": "מחק את {{title}}?", + "MANAGEMENT": "ניהול", + "TYPE_MANAGEMENT": "ניהול {{type}}", + "RENAME_TYPE_TITLE": "שינוי שם {{type}}: {{title}}", + "COPY_TYPE_TITLE": "העתקת {{type}}: {{title}}", + "RENAME": "שנה שם", + "NO_FILES_FOUND": "לא נמצאו קבצי {{type}}", "MECHANISMS": "מנגנונים", "OPMODES": "אופמודים", "BLOCKLY": { @@ -103,7 +128,8 @@ "EVENTS": "אירועים", "ADD_MECHANISM": "+ מנגנון", "ADD_COMPONENT": "+ רכיב", - "TEST": "בדיקה" + "TEST": "בדיקה", + "PAGINATION_TOTAL": "{{start}}-{{end}} מתוך {{total}} פריטים" }, "WARNING": { "CALL_COMPONENT_INSTANCE_METHOD_PRIVATE_COMPONENT": "בלוק זה קורא למתודה על רכיב פרטי במנגנון {{mechanismClassName}}.", diff --git a/src/reactComponents/AddTabDialog.tsx b/src/reactComponents/AddTabDialog.tsx index 2e54142e..9da8ff3a 100644 --- a/src/reactComponents/AddTabDialog.tsx +++ b/src/reactComponents/AddTabDialog.tsx @@ -185,7 +185,7 @@ export default function AddTabDialog(props: AddTabDialogProps) { locale={{emptyText: tabType === TabType.MECHANISM ? t('NO_HIDDEN_MECHANISMS') : t('NO_HIDDEN_OPMODES')}} />

- {t('CREATE_NEW')} + {t('CREATE_NEW', { type: TabTypeUtils.toString(tabType) })}

void; + onClose: () => void; project: storageProject.Project | null; setProject: (project: storageProject.Project | null) => void; gotoTab: (path: string) => void; @@ -54,7 +54,7 @@ const DEFAULT_PAGE_SIZE = 5; const MODAL_WIDTH = 800; /** Actions column width in pixels. */ -const ACTIONS_COLUMN_WIDTH = 120; +const ACTIONS_COLUMN_WIDTH = 160; /** * Modal component for managing files (mechanisms and opmodes) within a project. @@ -62,6 +62,7 @@ const ACTIONS_COLUMN_WIDTH = 120; */ export default function FileManageModal(props: FileManageModalProps) { const {t} = I18Next.useTranslation(); + const { token } = Antd.theme.useToken(); const [modules, setModules] = React.useState([]); const [newItemName, setNewItemName] = React.useState(''); const [currentRecord, setCurrentRecord] = React.useState(null); @@ -124,12 +125,19 @@ export default function FileManageModal(props: FileManageModalProps) { setModules(newModules); triggerProjectUpdate(); + + // Close the rename modal first + setRenameModalOpen(false); + + // Automatically select and open the newly created module + props.gotoTab(newModulePath); + props.onClose(); + } catch (error) { console.error('Error renaming module:', error); - props.setAlertErrorMessage('Failed to rename module'); + props.setAlertErrorMessage(t('FAILED_TO_RENAME_MODULE')); + setRenameModalOpen(false); } - - setRenameModalOpen(false); }; /** Handles copying a module. */ @@ -149,25 +157,33 @@ export default function FileManageModal(props: FileManageModalProps) { const originalModule = modules.find((module) => module.path === origModule.path); if (!originalModule) { console.error('Original module not found for copying:', origModule.path); - props.setAlertErrorMessage('Original module not found for copying'); + props.setAlertErrorMessage(t('MODULE_NOT_FOUND_FOR_COPYING')); return; } - const newModules = [...modules]; - newModules.push({ + const newModule = { path: newModulePath, title: newClassName, type: originalModule.type, - }); + }; + + const newModules = [...modules]; + newModules.push(newModule); setModules(newModules); triggerProjectUpdate(); + + // Close the copy modal first + setCopyModalOpen(false); + + // Automatically select and open the newly created module + props.gotoTab(newModulePath); + props.onClose(); } catch (error) { console.error('Error copying module:', error); - props.setAlertErrorMessage('Failed to copy module'); + props.setAlertErrorMessage(t('FAILED_TO_COPY_MODULE')); + setCopyModalOpen(false); } - - setCopyModalOpen(false); }; /** Handles adding a new module. */ @@ -199,7 +215,12 @@ export default function FileManageModal(props: FileManageModalProps) { } setNewItemName(''); - triggerProjectUpdate();}; + if(newModule){ + props.gotoTab(newModule.modulePath); + } + triggerProjectUpdate(); + props.onClose(); + }; /** Handles delete confirmation for a module. */ const handleDeleteConfirm = async (record: Module): Promise => { @@ -224,7 +245,7 @@ export default function FileManageModal(props: FileManageModalProps) { /** Handles row double-click to open module in tab. */ const handleRowDoubleClick = (record: Module): void => { props.gotoTab(record.path); - props.onCancel(); + props.onClose(); }; /** Opens the rename modal for a specific module. */ @@ -237,14 +258,14 @@ export default function FileManageModal(props: FileManageModalProps) { /** Opens the copy modal for a specific module. */ const openCopyModal = (record: Module): void => { setCurrentRecord(record); - setName(record.title + 'Copy'); + setName(t('COPY_SUFFIX', { name: record.title })); setCopyModalOpen(true); }; /** Table column configuration. */ const columns: Antd.TableProps['columns'] = [ { - title: 'Name', + title: t('NAME'), dataIndex: 'title', key: 'title', ellipsis: { @@ -257,12 +278,20 @@ export default function FileManageModal(props: FileManageModalProps) { ), }, { - title: 'Actions', + title: t('ACTIONS'), key: 'actions', width: ACTIONS_COLUMN_WIDTH, render: (_, record: Module) => ( - + + } + onClick={() => handleRowDoubleClick(record)} + /> + + - + handleDeleteConfirm(record)} okText={t('Delete')} cancelText={t('Cancel')} @@ -309,29 +338,35 @@ export default function FileManageModal(props: FileManageModalProps) { /** Gets the modal title based on module type. */ const getModalTitle = (): string => { - return `${TabTypeUtils.toString(props.tabType)} Management`; + return t('TYPE_MANAGEMENT', { type: TabTypeUtils.toString(props.tabType) }); }; /** Gets the rename modal title. */ const getRenameModalTitle = (): string => { if (!currentRecord) { - return 'Rename'; + return t('RENAME'); } - return `Rename ${TabTypeUtils.toString(currentRecord.type)}: ${currentRecord.title}`; + return t('RENAME_TYPE_TITLE', { + type: TabTypeUtils.toString(currentRecord.type), + title: currentRecord.title + }); }; /** Gets the copy modal title. */ const getCopyModalTitle = (): string => { if (!currentRecord) { - return 'Copy'; + return t('COPY'); } - return `Copy ${TabTypeUtils.toString(currentRecord.type)}: ${currentRecord.title}`; + return t('COPY_TYPE_TITLE', { + type: TabTypeUtils.toString(currentRecord.type), + title: currentRecord.title + }); }; /** Gets the empty table text based on tab type. */ const getEmptyText = (): string => { const tabTypeString = TabTypeUtils.toString(props.tabType || TabType.OPMODE); - return `No ${tabTypeString.toLowerCase()} files found`; + return t('NO_FILES_FOUND', { type: tabTypeString.toLowerCase() }); }; return ( @@ -397,30 +432,10 @@ export default function FileManageModal(props: FileManageModalProps) { - {t('Close')} - , - ]} + onCancel={props.onClose} + footer={null} width={MODAL_WIDTH} > -
- -
columns={columns} dataSource={modules} @@ -431,7 +446,7 @@ export default function FileManageModal(props: FileManageModalProps) { showSizeChanger: false, showQuickJumper: false, showTotal: (total, range) => - `${range[0]}-${range[1]} of ${total} items`, + t('PAGINATION_TOTAL', { start: range[0], end: range[1], total }), } : false} bordered locale={{ @@ -441,6 +456,26 @@ export default function FileManageModal(props: FileManageModalProps) { onDoubleClick: () => handleRowDoubleClick(record), })} /> +
+

+ {t('CREATE_NEW', { type: TabTypeUtils.toString(props.tabType) })} +

+
+ +
); diff --git a/src/reactComponents/Menu.tsx b/src/reactComponents/Menu.tsx index 4f70d609..68c50f80 100644 --- a/src/reactComponents/Menu.tsx +++ b/src/reactComponents/Menu.tsx @@ -43,6 +43,7 @@ import { CheckOutlined, DownloadOutlined, UploadOutlined, + ControlOutlined } from '@ant-design/icons'; import FileManageModal from './FileManageModal'; import ProjectManageModal from './ProjectManageModal'; @@ -89,14 +90,6 @@ function getItem( } as MenuItem; } -/** - * Creates a divider menu item. - */ -function getDivider(): MenuItem { - return { - type: 'divider', - } as MenuItem; -} /** * Generates menu items for a given project. @@ -113,10 +106,6 @@ function getMenuItems(t: (key: string) => string, project: storageProject.Projec )); }); - if (mechanisms.length > 0) { - mechanisms.push(getDivider()); - } - mechanisms.push(getItem('Manage...', 'manageMechanisms')); // Build opmodes menu items project.opModes.forEach((opmode) => { @@ -126,17 +115,16 @@ function getMenuItems(t: (key: string) => string, project: storageProject.Projec )); }); - if (opmodes.length > 0) { - opmodes.push(getDivider()); - } - opmodes.push(getItem('Manage...', 'manageOpmodes')); return [ getItem(t('PROJECT'), 'project', , [ getItem(t('SAVE'), 'save', ), getItem(t('DEPLOY'), 'deploy'), - getDivider(), - getItem(t('MANAGE') + '...', 'manageProjects'), + ]), + getItem(t('MANAGE'), 'manage', , [ + getItem(t('PROJECTS') + '...', 'manageProjects', ), + getItem(t('MECHANISMS') + '...', 'manageMechanisms', ), + getItem(t('OPMODES') + '...', 'manageOpmodes', ), ]), getItem(t('EXPLORER'), 'explorer', , [ getItem(t('ROBOT'), project.robot.modulePath, ), @@ -262,23 +250,18 @@ export function Component(props: MenuProps): React.JSX.Element { // Handle management actions if (key === 'manageMechanisms') { - console.log('Opening mechanisms modal'); setFileModalOpen(false); setTabType(TabType.MECHANISM); setTimeout(() => { - console.log('Setting fileModalOpen to true'); setFileModalOpen(true); }, 0); } else if (key === 'manageOpmodes') { - console.log('Opening opmodes modal'); setFileModalOpen(false); setTabType(TabType.OPMODE); setTimeout(() => { - console.log('Setting fileModalOpen to true'); setFileModalOpen(true); }, 0); } else if (key === 'manageProjects') { - console.log('Opening projects modal'); setProjectModalOpen(true); } else if (key === 'about') { setAboutDialogVisible(true); @@ -408,7 +391,6 @@ export function Component(props: MenuProps): React.JSX.Element { /** Handles closing the file management modal. */ const handleFileModalClose = (): void => { - console.log('Modal onCancel called'); setFileModalOpen(false); }; @@ -443,7 +425,7 @@ export function Component(props: MenuProps): React.JSX.Element { <> ([]); const [allProjectRecords, setAllProjectRecords] = React.useState([]); const [newItemName, setNewItemName] = React.useState(''); @@ -112,7 +113,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac await loadProjectNames(props.storage); } catch (error) { console.error('Error renaming project:', error); - props.setAlertErrorMessage('Failed to rename project'); + props.setAlertErrorMessage(t('FAILED_TO_RENAME_PROJECT')); } setRenameModalOpen(false); @@ -133,7 +134,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac await loadProjectNames(props.storage); } catch (error) { console.error('Error copying project:', error); - props.setAlertErrorMessage('Failed to copy project'); + props.setAlertErrorMessage(t('FAILED_TO_COPY_PROJECT')); } setCopyModalOpen(false); @@ -153,11 +154,12 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac ); } catch (e) { console.error('Failed to create a new project:', e); - props.setAlertErrorMessage('Failed to create a new project.'); + props.setAlertErrorMessage(t('FAILED_TO_CREATE_PROJECT')); } setNewItemName(''); await loadProjectNames(props.storage); + handleSelectProject(newProjectName); }; /** Handles project deletion with proper cleanup. */ @@ -190,7 +192,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac await storageProject.deleteProject(props.storage, projectNameToDelete); } catch (e) { console.error('Failed to delete the project:', e); - props.setAlertErrorMessage('Failed to delete the project.'); + props.setAlertErrorMessage(t('FAILED_TO_DELETE_PROJECT')); } }; @@ -221,18 +223,18 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac /** Gets the rename modal title. */ const getRenameModalTitle = (): string => { - return `Rename Project: ${currentRecord ? currentRecord.projectName : ''}`; + return `${t('RENAME_PROJECT')}: ${currentRecord ? currentRecord.projectName : ''}`; }; /** Gets the copy modal title. */ const getCopyModalTitle = (): string => { - return `Copy Project: ${currentRecord ? currentRecord.projectName : ''}`; + return `${t('COPY_PROJECT')}: ${currentRecord ? currentRecord.projectName : ''}`; }; /** Creates the container style object. */ const getContainerStyle = (): React.CSSProperties => ({ marginBottom: ALERT_MARGIN_BOTTOM, - border: '1px solid #d9d9d9', + border: `1px solid ${token.colorBorder}`, borderRadius: CONTAINER_BORDER_RADIUS, padding: CONTAINER_PADDING, }); @@ -245,7 +247,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac /** Table column configuration. */ const columns: Antd.TableProps['columns'] = [ { - title: 'Name', + title: t('NAME'), dataIndex: 'projectName', key: 'projectName', ellipsis: { @@ -258,7 +260,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac ), }, { - title: 'Actions', + title: t('ACTIONS'), key: 'actions', width: ACTIONS_COLUMN_WIDTH, render: (_, record: ProjectRecord) => ( @@ -290,8 +292,8 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac {allProjectRecords.length > 1 && ( handleDeleteProject(record.projectName)} okText={t('Delete')} cancelText={t('Cancel')} @@ -376,30 +378,18 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac title={t('Project Management')} open={props.isOpen} onCancel={props.onCancel} - footer={[ - - {t('Close')} - , - ]} + footer={null} width={MODAL_WIDTH} > {props.noProjects && ( )} -
- -
{!props.noProjects && ( columns={columns} @@ -411,17 +401,29 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac showSizeChanger: false, showQuickJumper: false, showTotal: (total, range) => - `${range[0]}-${range[1]} of ${total} items`, + t('PAGINATION_ITEMS', { range0: range[0], range1: range[1], total }), } : false} bordered locale={{ - emptyText: 'No projects found', + emptyText: t('NO_PROJECTS_FOUND'), }} onRow={(record) => ({ onDoubleClick: () => handleSelectProject(record.projectName), })} /> )} +
+

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

+
+ +
); diff --git a/src/reactComponents/ProjectNameComponent.tsx b/src/reactComponents/ProjectNameComponent.tsx index 6f20d320..faf235c4 100644 --- a/src/reactComponents/ProjectNameComponent.tsx +++ b/src/reactComponents/ProjectNameComponent.tsx @@ -121,7 +121,7 @@ export default function ProjectNameComponent(props: ProjectNameComponentProps): type="primary" onClick={handleAddNewItem} > - {t('New')} + {t('CREATE')} ); diff --git a/src/reactComponents/Tabs.tsx b/src/reactComponents/Tabs.tsx index 60e59080..dfe96c53 100644 --- a/src/reactComponents/Tabs.tsx +++ b/src/reactComponents/Tabs.tsx @@ -114,6 +114,8 @@ export function Component(props: TabsProps): React.JSX.Element { case storageModule.ModuleType.OPMODE: newTabs.push({ key, title: module.className, type: TabType.OPMODE }); break; + case storageModule.ModuleType.ROBOT: + break; // Robot tab is always first and cannot be added again. default: console.warn('Unknown module type:', module.moduleType); break; diff --git a/src/storage/project.ts b/src/storage/project.ts index 7e616ac0..78645074 100644 --- a/src/storage/project.ts +++ b/src/storage/project.ts @@ -313,24 +313,7 @@ export async function copyModuleInProject( moduleContent.changeIds(); moduleContentText = moduleContent.getModuleContentText(); - await storage.saveFile(newModulePath, moduleContentText); - - // Update the project's mechanisms or opModes. - const newModule = { - modulePath: newModulePath, - moduleType: oldModule.moduleType, - projectName: project.projectName, - className: newClassName - }; - switch (oldModule.moduleType) { - case storageModule.ModuleType.MECHANISM: - project.mechanisms.push(newModule as storageModule.Mechanism); - break; - case storageModule.ModuleType.OPMODE: - project.opModes.push(newModule as storageModule.OpMode); - break; - } - await saveProjectInfo(storage, project.projectName); + await addModuleToProject(storage, project, oldModule.moduleType, newClassName); return newModulePath; }