diff --git a/README.md b/README.md index 0db71dcf..3b6d5a4c 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,4 @@ WARNING! This is not ready for use and is under heavy development of basic featu 1. Mechanisms aren't limited to init 2. Mechanisms aren't limited to only Robot or Mechanism class 3. No way to specify whether an opmode is auto or teleop -4. Since we changed the "Workspace" terminology to "Project", existing Workspaces are no longer supported. They can be deleted via the browser's Developer Tools - Application tab. +4. Since we changed the "Project" terminology to "Robot", existing Projects are no longer supported. They can be deleted via the browser's Developer Tools - Application tab. diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index b47a6209..1a1af731 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -1,24 +1,24 @@ { - "mechanism_delete": "Delete Project", - "mechanism_rename": "Rename Project", - "mechanism_copy": "Copy Project", - "opmode_delete": "Delete Project", - "opmode_rename": "Rename Project", - "opmode_copy": "Copy Project", - "project_delete": "Delete Project", - "project_rename": "Rename Project", - "project_copy": "Copy Project", + "mechanism_delete": "Delete Robot", + "mechanism_rename": "Rename Robot", + "mechanism_copy": "Copy Robot", + "opmode_delete": "Delete Robot", + "opmode_rename": "Rename Robot", + "opmode_copy": "Copy Robot", + "robot_delete": "Delete Robot", + "robot_rename": "Rename Robot", + "robot_copy": "Copy Robot", "fail_list_modules": "Failed to load the list of modules.", "mechanism": "Mechanism", "opmode": "OpMode", "class_rule_description": "No spaces are allowed in the name. Each word in the name should start with a capital letter.", "example_mechanism": "For example: GamePieceShooter", "example_opmode": "For example: AutoParkAndShoot", - "example_project": "For example: WackyWheelerRobot", + "example_robot": "For example: WackyWheelerRobot", "addTabDialog": { "title": "Add Tab", "newItemPlaceholder": "Add Module", "search": "Search..." } -} \ No newline at end of file +} diff --git a/src/App.tsx b/src/App.tsx index 1dd0cfb5..2c95e238 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -82,7 +82,7 @@ const LAYOUT_BACKGROUND_COLOR = '#0F0'; /** * Main application component that manages the Blockly interface, code generation, - * project management, and user interface layout. + * robot management, and user interface layout. */ const App: React.FC = (): React.JSX.Element => { const [alertErrorMessage, setAlertErrorMessage] = React.useState(''); @@ -91,7 +91,7 @@ const App: React.FC = (): React.JSX.Element => { const [messageApi, contextHolder] = Antd.message.useMessage(); const [generatedCode, setGeneratedCode] = React.useState(''); const [toolboxSettingsModalIsOpen, setToolboxSettingsModalIsOpen] = React.useState(false); - const [project, setProject] = React.useState(null); + const [robot, setRobot] = React.useState(null); const [tabItems, setTabItems] = React.useState([]); const [activeTab, setActiveTab] = React.useState(''); const [shownPythonToolboxCategories, setShownPythonToolboxCategories] = React.useState>(new Set()); @@ -225,17 +225,17 @@ const App: React.FC = (): React.JSX.Element => { handleToolboxSettingsOk(updatedShownCategories); }; - /** Creates tab items from project data. */ - const createTabItemsFromProject = (projectData: commonStorage.Project): Tabs.TabItem[] => { + /** Creates tab items from robot data. */ + const createTabItemsFromRobot = (robotData: commonStorage.Robot): Tabs.TabItem[] => { const tabs: Tabs.TabItem[] = [ { - key: projectData.modulePath, + key: robotData.modulePath, title: 'Robot', type: TabType.ROBOT, }, ]; - projectData.mechanisms.forEach((mechanism) => { + robotData.mechanisms.forEach((mechanism) => { tabs.push({ key: mechanism.modulePath, title: mechanism.className, @@ -243,7 +243,7 @@ const App: React.FC = (): React.JSX.Element => { }); }); - projectData.opModes.forEach((opmode) => { + robotData.opModes.forEach((opmode) => { tabs.push({ key: opmode.modulePath, title: opmode.className, @@ -327,14 +327,14 @@ const App: React.FC = (): React.JSX.Element => { } }, [currentModule, shownPythonToolboxCategories]); - // Update tab items when project changes + // Update tab items when robot changes React.useEffect(() => { - if (project) { - const tabs = createTabItemsFromProject(project); + if (robot) { + const tabs = createTabItemsFromRobot(robot); setTabItems(tabs); - setActiveTab(project.modulePath); + setActiveTab(robot.modulePath); } - }, [project]); + }, [robot]); const {Sider,Content} = Antd.Layout; @@ -359,7 +359,7 @@ const App: React.FC = (): React.JSX.Element => {
{ storage={storage} setAlertErrorMessage={setAlertErrorMessage} gotoTab={setActiveTab} - project={project} - setProject={setProject} + robot={robot} + setRobot={setRobot} openWPIToolboxSettings={() => setToolboxSettingsModalIsOpen(true)} /> @@ -389,8 +389,8 @@ const App: React.FC = (): React.JSX.Element => { setAlertErrorMessage={setAlertErrorMessage} currentModule={currentModule} setCurrentModule={changeModule} - project={project} - setProject={setProject} + robot={robot} + setRobot={setRobot} storage={storage} /> diff --git a/src/blocks/mrc_call_python_function.ts b/src/blocks/mrc_call_python_function.ts index 66dfa2fb..4015693d 100644 --- a/src/blocks/mrc_call_python_function.ts +++ b/src/blocks/mrc_call_python_function.ts @@ -331,8 +331,7 @@ type CallPythonFunctionExtraState = { */ actualFunctionName?: string, /** - * True if this blocks refers to an exported function (for example, from a - * user's Project). + * True if this blocks refers to an exported function (for example, from the Robot). */ exportedFunction?: boolean, /** @@ -679,7 +678,7 @@ export const pythonFromBlock = function( : block.getFieldValue(FIELD_FUNCTION_NAME); // Generate the correct code depending on the module type. switch (generator.getModuleType()) { - case commonStorage.MODULE_TYPE_PROJECT: + case commonStorage.MODULE_TYPE_ROBOT: case commonStorage.MODULE_TYPE_MECHANISM: code = 'self.'; break; diff --git a/src/blocks/mrc_get_python_variable.ts b/src/blocks/mrc_get_python_variable.ts index 5539b7c7..a7196c32 100644 --- a/src/blocks/mrc_get_python_variable.ts +++ b/src/blocks/mrc_get_python_variable.ts @@ -228,8 +228,7 @@ type GetPythonVariableExtraState = { */ actualVariableName?: string, /** - * True if this blocks refers to an exported variable (for example, from a - * user's Project). + * True if this blocks refers to an exported variable (for example, from the Robot). */ exportedVariable?: boolean, }; diff --git a/src/blocks/mrc_set_python_variable.ts b/src/blocks/mrc_set_python_variable.ts index d43d9c7f..218decf2 100644 --- a/src/blocks/mrc_set_python_variable.ts +++ b/src/blocks/mrc_set_python_variable.ts @@ -178,8 +178,7 @@ type SetPythonVariableExtraState = { */ actualVariableName?: string, /** - * True if this blocks refers to an exported variable (for example, from a - * user's Project). + * True if this blocks refers to an exported variable (for example, from the Robot). */ exportedVariable?: boolean, }; diff --git a/src/editor/editor.ts b/src/editor/editor.ts index 86d6f5a5..8dfdd300 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -44,10 +44,10 @@ export class Editor { private methodsCategory: MethodsCategory; private eventsCategory: EventsCategory; private currentModule: commonStorage.Module | null = null; - private modulePath: string = ''; - private projectPath: string = ''; - private moduleContent: string = ''; - private projectContent: string = ''; + private currentModulePath: string = ''; + private robotPath: string = ''; + private currentModuleContent: string = ''; + private robotContent: string = ''; private bindedOnChange: any = null; private toolbox: Blockly.utils.toolbox.ToolboxDefinition = EMPTY_TOOLBOX; @@ -73,11 +73,11 @@ export class Editor { // TODO(lizlooney): As blocks are loaded, determine whether any blocks // are accessing variable or calling functions thar are defined in another - // blocks file (like a Project) and check whether the variable or function + // blocks file (like the Robot) and check whether the variable or function // definition has changed. This might happen if the user defines a variable - // or function in the Project, uses the variable or function in the + // or function in the Robot, uses the variable or function in the // OpMode, and then removes or changes the variable or function in the - // Project. + // Robot. // TODO(lizlooney): We will need a way to identify which variable or // function, other than by the variable name or function name, because the @@ -88,7 +88,7 @@ export class Editor { // TODO(lizlooney): Look at blocks with type 'mrc_get_python_variable' or // 'mrc_set_python_variable', and where block.mrcExportedVariable === true. // Look at block.mrcImportModule and get the exported blocks for that module. - // (It should be the project and we already have the project content.) + // (It should be the Robot and we already have the Robot content.) // Check whether block.mrcActualVariableName matches any exportedBlock's // extraState.actualVariableName. If there is no match, put a warning on the // block. @@ -96,7 +96,7 @@ export class Editor { // TODO(lizlooney): Look at blocks with type 'mrc_call_python_function' and // where block.mrcExportedFunction === true. // Look at block.mrcImportModule and get the exported blocks for that module. - // (It should be the project and we already have the project content.) + // (It should be the Robot and we already have the Robot content.) // Check whether block.mrcActualFunctionName matches any exportedBlock's // extraState.actualFunctionName. If there is no match, put a warning on the block. // If there is a match, check whether @@ -123,35 +123,35 @@ export class Editor { this.eventsCategory.setCurrentModule(currentModule); if (currentModule) { - this.modulePath = currentModule.modulePath; - this.projectPath = commonStorage.makeProjectPath(currentModule.projectName); + this.currentModulePath = currentModule.modulePath; + this.robotPath = commonStorage.makeRobotPath(currentModule.robotName); } else { - this.modulePath = ''; - this.projectPath = ''; + this.currentModulePath = ''; + this.robotPath = ''; } - this.moduleContent = ''; - this.projectContent = ''; + this.currentModuleContent = ''; + this.robotContent = ''; this.clearBlocklyWorkspace(); if (currentModule) { const promises: {[key: string]: Promise} = {}; // key is module path, value is promise of module content. - promises[this.modulePath] = this.storage.fetchModuleContent(this.modulePath); - if (this.projectPath !== this.modulePath) { - // Also fetch the project module content. It contains exported blocks that can be used. - promises[this.projectPath] = this.storage.fetchModuleContent(this.projectPath) + promises[this.currentModulePath] = this.storage.fetchModuleContent(this.currentModulePath); + if (this.robotPath !== this.currentModulePath) { + // Also fetch the robot module content. It contains exported blocks that can be used. + promises[this.robotPath] = this.storage.fetchModuleContent(this.robotPath) } const moduleContents: {[key: string]: string} = {}; // key is module path, value is module content await Promise.all( - Object.entries(promises).map(async ([modulePath, promise]) => { - moduleContents[modulePath] = await promise; + Object.entries(promises).map(async ([currentModulePath, promise]) => { + moduleContents[currentModulePath] = await promise; }) ); - this.moduleContent = moduleContents[this.modulePath]; - if (this.projectPath === this.modulePath) { - this.projectContent = this.moduleContent + this.currentModuleContent = moduleContents[this.currentModulePath]; + if (this.robotPath === this.currentModulePath) { + this.robotContent = this.currentModuleContent; } else { - this.projectContent = moduleContents[this.projectPath]; + this.robotContent = moduleContents[this.robotPath]; } this.loadBlocksIntoBlocklyWorkspace(); } @@ -179,7 +179,7 @@ export class Editor { // Add the while-loading listener. this.bindedOnChange = this.onChangeWhileLoading.bind(this); this.blocklyWorkspace.addChangeListener(this.bindedOnChange); - const blocksContent = commonStorage.extractBlocksContent(this.moduleContent); + const blocksContent = commonStorage.extractBlocksContent(this.currentModuleContent); if (blocksContent) { Blockly.serialization.workspaces.load(JSON.parse(blocksContent), this.blocklyWorkspace); } @@ -187,8 +187,8 @@ export class Editor { public updateToolbox(shownPythonToolboxCategories: Set): void { if (this.currentModule) { - if (!this.projectContent) { - // The Project content hasn't been fetched yet. Try again in a bit. + if (!this.robotContent) { + // The Robot content hasn't been fetched yet. Try again in a bit. setTimeout(() => { this.updateToolbox(shownPythonToolboxCategories) }, 50); @@ -204,13 +204,13 @@ export class Editor { /* // This code is helpful for debugging issues where the editor says // 'Blocks have been modified!'. - if (this.getModuleContent() !== this.moduleContent) { + if (this.getModuleContent() !== this.currentModuleContent) { console.log('isModified will return true'); console.log('this.getModuleContent() is ' + this.getModuleContent()); - console.log('this.moduleContent is ' + this.moduleContent); + console.log('this.currentModuleContent is ' + this.currentModuleContent); } */ - return this.getModuleContent() !== this.moduleContent; + return this.getModuleContent() !== this.currentModuleContent; } private getModuleContent(): string { @@ -229,7 +229,7 @@ export class Editor { private getComponents(): commonStorage.Component[] { const components: commonStorage.Component[] = []; - if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_PROJECT) { + if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT) { // TODO(lizlooney): Fill the components array. } return components; @@ -238,7 +238,7 @@ export class Editor { public async saveBlocks() { const moduleContent = this.getModuleContent(); try { - await this.storage.saveModule(this.modulePath, moduleContent); + await this.storage.saveModule(this.currentModulePath, moduleContent); this.moduleContent = moduleContent; } catch (e) { throw e; diff --git a/src/editor/generator_context.ts b/src/editor/generator_context.ts index e6007ade..4b230306 100644 --- a/src/editor/generator_context.ts +++ b/src/editor/generator_context.ts @@ -58,7 +58,7 @@ export class GeneratorContext { if (!this.module) { throw new Error('getClassName: this.module is null.'); } - if (this.module.moduleType === commonStorage.MODULE_TYPE_PROJECT) { + if (this.module.moduleType === commonStorage.MODULE_TYPE_ROBOT) { return 'Robot'; } @@ -69,7 +69,7 @@ export class GeneratorContext { if (!this.module) { throw new Error('getClassParent: this.module is null.'); } - if (this.module.moduleType === commonStorage.MODULE_TYPE_PROJECT) { + if (this.module.moduleType === commonStorage.MODULE_TYPE_ROBOT) { return 'RobotBase'; } if (this.module.moduleType === commonStorage.MODULE_TYPE_OPMODE) { diff --git a/src/reactComponents/AddTabDialog.tsx b/src/reactComponents/AddTabDialog.tsx index 519b8f9e..bbfb64fc 100644 --- a/src/reactComponents/AddTabDialog.tsx +++ b/src/reactComponents/AddTabDialog.tsx @@ -38,8 +38,8 @@ interface AddTabDialogProps { isOpen: boolean; onOk: (newTabs: TabItem[]) => void; onCancel: () => void; - project: commonStorage.Project | null; - setProject: (project: commonStorage.Project | null) => void; + robot: commonStorage.Robot | null; + setRobot: (robot: commonStorage.Robot | null) => void; currentTabs: TabItem[]; storage: commonStorage.Storage | null; } @@ -66,17 +66,17 @@ export default function AddTabDialog(props: AddTabDialogProps) { const [searchText, setSearchText] = React.useState(''); React.useEffect(() => { - if (!props.project) { + if (!props.robot) { return; } - // Initialize available items based on project data - const mechanisms = props.project.mechanisms.map((m) => ({ + // Initialize available items based on robot data + const mechanisms = props.robot.mechanisms.map((m) => ({ path: m.modulePath, title: m.className, type: TabType.MECHANISM, })); - const opModes = props.project.opModes.map((o) => ({ + const opModes = props.robot.opModes.map((o) => ({ path: o.modulePath, title: o.className, type: TabType.OPMODE, @@ -96,11 +96,11 @@ export default function AddTabDialog(props: AddTabDialogProps) { setAvailableItems(availableModules); setSelectedItems(selectedModules); - }, [props.project, props.currentTabs]); + }, [props.robot, props.currentTabs]); - const triggerProjectUpdate = (): void => { - if (props.project) { - props.setProject({...props.project}); + const triggerRobotUpdate = (): void => { + if (props.robot) { + props.setRobot({...props.robot}); } } @@ -123,7 +123,7 @@ export default function AddTabDialog(props: AddTabDialogProps) { return; } - if (!props.storage || !props.project) { + if (!props.storage || !props.robot) { return; } @@ -131,10 +131,10 @@ export default function AddTabDialog(props: AddTabDialogProps) { commonStorage.MODULE_TYPE_MECHANISM : commonStorage.MODULE_TYPE_OPMODE; - await commonStorage.addModuleToProject( - props.storage, props.project, storageType, trimmedName); + await commonStorage.addModuleToRobot( + props.storage, props.robot, storageType, trimmedName); - const newModule = commonStorage.getClassInProject(props.project, trimmedName); + const newModule = commonStorage.getClassInRobot(props.robot, trimmedName); if (newModule) { const module: Module = { path: newModule.modulePath, @@ -142,7 +142,7 @@ export default function AddTabDialog(props: AddTabDialogProps) { type: tabType, }; setSelectedItems([...selectedItems, module]); - triggerProjectUpdate(); + triggerRobotUpdate(); } @@ -311,7 +311,7 @@ export default function AddTabDialog(props: AddTabDialogProps) { newItemName={newItemName} setNewItemName={setNewItemName} onAddNewItem={handleAddNewItem} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel={t('New')} /> diff --git a/src/reactComponents/FileManageModal.tsx b/src/reactComponents/FileManageModal.tsx index 14a2f714..7506bf15 100644 --- a/src/reactComponents/FileManageModal.tsx +++ b/src/reactComponents/FileManageModal.tsx @@ -37,8 +37,8 @@ interface Module { interface FileManageModalProps { isOpen: boolean; onCancel: () => void; - project: commonStorage.Project | null; - setProject: (project: commonStorage.Project | null) => void; + robot: commonStorage.Robot | null; + setRobot: (robot: commonStorage.Robot | null) => void; gotoTab: (path: string) => void; setAlertErrorMessage: (message: string) => void; storage: commonStorage.Storage | null; @@ -55,7 +55,7 @@ const MODAL_WIDTH = 800; const ACTIONS_COLUMN_WIDTH = 120; /** - * Modal component for managing files (mechanisms and opmodes) within a project. + * Modal component for managing files (mechanisms and opmodes) within a robot. * Provides functionality to create, rename, copy, and delete modules. */ export default function FileManageModal(props: FileManageModalProps) { @@ -67,13 +67,13 @@ export default function FileManageModal(props: FileManageModalProps) { const [name, setName] = React.useState(''); const [copyModalOpen, setCopyModalOpen] = React.useState(false); - const triggerProjectUpdate = (): void => { - if (props.project) { - props.setProject({...props.project}); + const triggerRobotUpdate = (): void => { + if (props.robot) { + props.setRobot({...props.robot}); } } React.useEffect(() => { - if (!props.project || props.moduleType === null) { + if (!props.robot || props.moduleType === null) { setModules([]); return; } @@ -81,13 +81,13 @@ export default function FileManageModal(props: FileManageModalProps) { let moduleList: Module[] = []; if (props.moduleType === TabType.MECHANISM) { - moduleList = props.project.mechanisms.map((m) => ({ + moduleList = props.robot.mechanisms.map((m) => ({ path: m.modulePath, title: m.className, type: TabType.MECHANISM, })); } else if (props.moduleType === TabType.OPMODE) { - moduleList = props.project.opModes.map((o) => ({ + moduleList = props.robot.opModes.map((o) => ({ path: o.modulePath, title: o.className, type: TabType.OPMODE, @@ -97,18 +97,18 @@ export default function FileManageModal(props: FileManageModalProps) { // Sort modules alphabetically by title moduleList.sort((a, b) => a.title.localeCompare(b.title)); setModules(moduleList); - }, [props.project, props.moduleType]); + }, [props.robot, props.moduleType]); /** Handles renaming a module. */ const handleRename = async (origModule: Module, newName: string): Promise => { - if (!props.storage || !props.project) { + if (!props.storage || !props.robot) { return; } try { - const newPath = await commonStorage.renameModuleInProject( + const newPath = await commonStorage.renameModuleInRobot( props.storage, - props.project, + props.robot, newName, origModule.path ); @@ -121,7 +121,7 @@ export default function FileManageModal(props: FileManageModalProps) { }); setModules(newModules); - triggerProjectUpdate(); + triggerRobotUpdate(); } catch (error) { console.error('Error renaming module:', error); props.setAlertErrorMessage('Failed to rename module'); @@ -132,14 +132,14 @@ export default function FileManageModal(props: FileManageModalProps) { /** Handles copying a module. */ const handleCopy = async (origModule: Module, newName: string): Promise => { - if (!props.storage || !props.project) { + if (!props.storage || !props.robot) { return; } try { - const newPath = await commonStorage.copyModuleInProject( + const newPath = await commonStorage.copyModuleInRobot( props.storage, - props.project, + props.robot, newName, origModule.path ); @@ -159,7 +159,7 @@ export default function FileManageModal(props: FileManageModalProps) { }); setModules(newModules); - triggerProjectUpdate(); + triggerRobotUpdate(); } catch (error) { console.error('Error copying module:', error); props.setAlertErrorMessage('Failed to copy module'); @@ -171,7 +171,7 @@ export default function FileManageModal(props: FileManageModalProps) { /** Handles adding a new module. */ const handleAddNewItem = async (): Promise => { const trimmedName = newItemName.trim(); - if (!trimmedName || !props.storage || !props.project) { + if (!trimmedName || !props.storage || !props.robot) { return; } @@ -179,14 +179,14 @@ export default function FileManageModal(props: FileManageModalProps) { commonStorage.MODULE_TYPE_MECHANISM : commonStorage.MODULE_TYPE_OPMODE; - await commonStorage.addModuleToProject( + await commonStorage.addModuleToRobot( props.storage, - props.project, + props.robot, storageType, trimmedName ); - const newModule = commonStorage.getClassInProject(props.project, trimmedName); + const newModule = commonStorage.getClassInRobot(props.robot, trimmedName); if (newModule) { const module: Module = { path: newModule.modulePath, @@ -197,20 +197,20 @@ export default function FileManageModal(props: FileManageModalProps) { } setNewItemName(''); - triggerProjectUpdate();}; + triggerRobotUpdate();}; /** Handles delete confirmation for a module. */ const handleDeleteConfirm = async (record: Module): Promise => { const newModules = modules.filter((m) => m.path !== record.path); setModules(newModules); - if (props.storage && props.project) { - await commonStorage.removeModuleFromProject( + if (props.storage && props.robot) { + await commonStorage.removeModuleFromRobot( props.storage, - props.project, + props.robot, record.path ); - triggerProjectUpdate(); + triggerRobotUpdate(); } }; @@ -356,7 +356,7 @@ export default function FileManageModal(props: FileManageModalProps) { handleRename(currentRecord, name); } }} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel="" /> @@ -385,7 +385,7 @@ export default function FileManageModal(props: FileManageModalProps) { handleCopy(currentRecord, name); } }} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel="" /> @@ -414,7 +414,7 @@ export default function FileManageModal(props: FileManageModalProps) { newItemName={newItemName} setNewItemName={setNewItemName} onAddNewItem={handleAddNewItem} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel={t('New')} /> diff --git a/src/reactComponents/Header.tsx b/src/reactComponents/Header.tsx index ceb8edf1..40db95c3 100644 --- a/src/reactComponents/Header.tsx +++ b/src/reactComponents/Header.tsx @@ -29,7 +29,7 @@ type StringFunction = (input: string) => void; interface HeaderProps { alertErrorMessage: string; setAlertErrorMessage: StringFunction; - project: commonStorage.Project | null; + robot: commonStorage.Robot | null; } /** Height of the logo image in pixels. */ @@ -45,7 +45,7 @@ const TEXT_FONT_SIZE = '20px'; const TEXT_PADDING_LEFT = 20; /** - * Header component that displays the application logo, title, current project, + * Header component that displays the application logo, title, current robot, * and any error messages. */ export default function Header(props: HeaderProps): React.JSX.Element { @@ -70,9 +70,9 @@ export default function Header(props: HeaderProps): React.JSX.Element { ); }; - /** Gets the project name or fallback text. */ - const getProjectName = (): string => { - return props.project?.className || 'No Project Selected'; + /** Gets the robot name or fallback text. */ + const getRobotName = (): string => { + return props.robot?.className || 'No Robot Selected'; }; return ( @@ -102,7 +102,7 @@ export default function Header(props: HeaderProps): React.JSX.Element { fontWeight: 'normal', }} > - Project: {getProjectName()} + Robot: {getRobotName()} {renderErrorAlert()} diff --git a/src/reactComponents/Menu.tsx b/src/reactComponents/Menu.tsx index 25bc82b8..a4ab5b53 100644 --- a/src/reactComponents/Menu.tsx +++ b/src/reactComponents/Menu.tsx @@ -36,7 +36,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import FileManageModal from './FileManageModal'; -import ProjectManageModal from './ProjectManageModal'; +import RobotManageModal from './RobotManageModal'; import AboutDialog from './AboutModal'; /** Type definition for menu items. */ @@ -47,16 +47,16 @@ export interface MenuProps { setAlertErrorMessage: (message: string) => void; storage: commonStorage.Storage | null; gotoTab: (tabKey: string) => void; - project: commonStorage.Project | null; + robot: commonStorage.Robot | null; openWPIToolboxSettings: () => void; - setProject: (project: commonStorage.Project | null) => void; + setRobot: (robot: commonStorage.Robot | null) => void; } /** Default selected menu keys. */ const DEFAULT_SELECTED_KEYS = ['1']; -/** Storage key for the most recent project. */ -const MOST_RECENT_PROJECT_KEY = 'mostRecentProject'; +/** Storage key for the most recent robot. */ +const MOST_RECENT_ROBOT_KEY = 'mostRecentRobot'; /** * Creates a menu item with the specified properties. @@ -87,14 +87,14 @@ function getDivider(): MenuItem { } /** - * Generates menu items for a given project. + * Generates menu items for a given robot. */ -function getMenuItems(t: (key: string) => string, project: commonStorage.Project): MenuItem[] { +function getMenuItems(t: (key: string) => string, robot: commonStorage.Robot): MenuItem[] { const mechanisms: MenuItem[] = []; const opmodes: MenuItem[] = []; // Build mechanisms menu items - project.mechanisms.forEach((mechanism) => { + robot.mechanisms.forEach((mechanism) => { mechanisms.push(getItem( mechanism.className, mechanism.modulePath, @@ -107,7 +107,7 @@ function getMenuItems(t: (key: string) => string, project: commonStorage.Project mechanisms.push(getItem('Manage...', 'manageMechanisms')); // Build opmodes menu items - project.opModes.forEach((opmode) => { + robot.opModes.forEach((opmode) => { opmodes.push(getItem( opmode.className, opmode.modulePath, @@ -120,14 +120,14 @@ function getMenuItems(t: (key: string) => string, project: commonStorage.Project opmodes.push(getItem('Manage...', 'manageOpmodes')); return [ - getItem(t('Project'), 'project', , [ + getItem(t('Robot'), 'robot', , [ getItem(t('Save'), 'save', ), getItem(t('Deploy'), 'deploy', undefined, undefined, true), getDivider(), - getItem(t('Manage') + '...', 'manageProjects'), + getItem(t('Manage') + '...', 'manageRobots'), ]), getItem(t('Explorer'), 'explorer', , [ - getItem(t('Robot'), project.modulePath, ), + getItem(t('Robot'), robot.modulePath, ), getItem(t('Mechanisms'), 'mechanisms', , mechanisms), getItem(t('OpModes'), 'opmodes', , opmodes), ]), @@ -143,22 +143,22 @@ function getMenuItems(t: (key: string) => string, project: commonStorage.Project } /** - * Menu component that displays the project structure and navigation options. - * Provides access to mechanisms, opmodes, and project management functionality. + * Menu component that displays the robot structure and navigation options. + * Provides access to mechanisms, opmodes, and robot management functionality. */ export function Component(props: MenuProps): React.JSX.Element { const {t} = I18Next.useTranslation(); - const [modules, setModules] = React.useState([]); + const [modules, setModules] = React.useState([]); const [menuItems, setMenuItems] = React.useState([]); const [fileModalOpen, setFileModalOpen] = React.useState(false); - const [projectModalOpen, setProjectModalOpen] = React.useState(false); + const [robotModalOpen, setRobotModalOpen] = React.useState(false); const [moduleType, setModuleType] = React.useState(TabType.MECHANISM); - const [noProjects, setNoProjects] = React.useState(false); + const [noRobots, setNoRobots] = React.useState(false); const [aboutDialogVisible, setAboutDialogVisible] = React.useState(false); /** Fetches the list of modules from storage. */ - const fetchListOfModules = async (): Promise => { + const fetchListOfModules = async (): Promise => { return new Promise(async (resolve, reject) => { if (!props.storage) { reject(new Error('Storage not available')); @@ -176,50 +176,50 @@ export function Component(props: MenuProps): React.JSX.Element { }); }; - /** Initializes the modules and handles empty project state. */ + /** Initializes the modules and handles empty robot state. */ const initializeModules = async (): Promise => { const array = await fetchListOfModules(); if (array.length === 0) { - setNoProjects(true); - setProjectModalOpen(true); + setNoRobots(true); + setRobotModalOpen(true); } }; - /** Fetches and sets the most recent project. */ - const fetchMostRecentProject = async (): Promise => { + /** Fetches and sets the most recent robot. */ + const fetchMostRecentRobot = async (): Promise => { let found = false; if (props.storage) { - const mostRecentProject = await props.storage.fetchEntry( - MOST_RECENT_PROJECT_KEY, + const mostRecentRobot = await props.storage.fetchEntry( + MOST_RECENT_ROBOT_KEY, '' ); modules.forEach((module) => { - if (module.projectName === mostRecentProject) { - props.setProject(module); + if (module.robotName === mostRecentRobot) { + props.setRobot(module); found = true; } }); if (!found && modules.length > 0) { - props.setProject(modules[0]); + props.setRobot(modules[0]); } } }; - /** Saves the most recent project to storage. */ - const setMostRecentProject = async (): Promise => { + /** Saves the most recent robot to storage. */ + const setMostRecentRobot = async (): Promise => { if (props.storage) { await props.storage.saveEntry( - MOST_RECENT_PROJECT_KEY, - props.project?.projectName || '' + MOST_RECENT_ROBOT_KEY, + props.robot?.robotName || '' ); } }; /** Handles menu item clicks. */ const handleClick: Antd.MenuProps['onClick'] = ({key}): void => { - const newModule = props.project ? - commonStorage.findModuleInProject(props.project, key) : + const newModule = props.robot ? + commonStorage.findModuleInRobot(props.robot, key) : null; if (newModule) { @@ -244,9 +244,9 @@ export function Component(props: MenuProps): React.JSX.Element { console.log('Setting fileModalOpen to true'); setFileModalOpen(true); }, 0); - } else if (key === 'manageProjects') { - console.log('Opening projects modal'); - setProjectModalOpen(true); + } else if (key === 'manageRobots') { + console.log('Opening robots modal'); + setRobotModalOpen(true); } else if (key === 'about') { setAboutDialogVisible(true); } else if (key === 'wpi_toolbox'){ @@ -263,9 +263,9 @@ export function Component(props: MenuProps): React.JSX.Element { setFileModalOpen(false); }; - /** Handles closing the project management modal. */ - const handleProjectModalClose = (): void => { - setProjectModalOpen(false); + /** Handles closing the robot management modal. */ + const handleRobotModalClose = (): void => { + setRobotModalOpen(false); }; // Initialize modules when storage is available @@ -276,39 +276,39 @@ export function Component(props: MenuProps): React.JSX.Element { initializeModules(); }, [props.storage]); - // Fetch most recent project when modules change + // Fetch most recent robot when modules change React.useEffect(() => { - fetchMostRecentProject(); + fetchMostRecentRobot(); }, [modules]); - // Update menu items and save project when project changes + // Update menu items and save robot when robot changes React.useEffect(() => { - if (props.project) { - setMostRecentProject(); - setMenuItems(getMenuItems(t, props.project)); - setNoProjects(false); + if (props.robot) { + setMostRecentRobot(); + setMenuItems(getMenuItems(t, props.robot)); + setNoRobots(false); } - }, [props.project]); + }, [props.robot]); return ( <> - void; onAddNewItem: () => void; - project: commonStorage.Project | null; + robot: commonStorage.Robot | null; storage: commonStorage.Storage | null; buttonLabel: string; } @@ -61,11 +61,11 @@ export default function ModuleNameComponent(props: ModuleNameComponentProps): Re return; } - if (!props.project) { + if (!props.robot) { return; } - const {ok, error} = commonStorage.isClassNameOk(props.project, trimmedName); + const {ok, error} = commonStorage.isClassNameOk(props.robot, trimmedName); if (ok) { clearError(); props.onAddNewItem(); diff --git a/src/reactComponents/ProjectManageModal.tsx b/src/reactComponents/RobotManageModal.tsx similarity index 71% rename from src/reactComponents/ProjectManageModal.tsx rename to src/reactComponents/RobotManageModal.tsx index 047258af..8f9e917f 100644 --- a/src/reactComponents/ProjectManageModal.tsx +++ b/src/reactComponents/RobotManageModal.tsx @@ -24,14 +24,14 @@ import * as I18Next from 'react-i18next'; import * as React from 'react'; import * as commonStorage from '../storage/common_storage'; import {EditOutlined, DeleteOutlined, CopyOutlined, SelectOutlined} from '@ant-design/icons'; -import ProjectNameComponent from './ProjectNameComponent'; +import RobotNameComponent from './RobotNameComponent'; -/** Props for the ProjectManageModal component. */ -interface ProjectManageModalProps { +/** Props for the RobotManageModal component. */ +interface RobotManageModalProps { isOpen: boolean; - noProjects: boolean; + noRobots: boolean; onCancel: () => void; - setProject: (project: commonStorage.Project | null) => void; + setRobot: (robot: commonStorage.Robot | null) => void; setAlertErrorMessage: (message: string) => void; storage: commonStorage.Storage | null; moduleType: TabType; @@ -46,7 +46,7 @@ const MODAL_WIDTH = 800; /** Actions column width in pixels. */ const ACTIONS_COLUMN_WIDTH = 160; -/** Default copy suffix for project names. */ +/** Default copy suffix for robot names. */ const COPY_SUFFIX = 'Copy'; /** Alert margin bottom in pixels. */ @@ -59,41 +59,41 @@ const CONTAINER_BORDER_RADIUS = '6px'; const CONTAINER_PADDING = '12px'; /** - * Modal component for managing projects. - * Provides functionality to create, rename, copy, delete, and select projects. + * Modal component for managing robots. + * Provides functionality to create, rename, copy, delete, and select robots. */ -export default function ProjectManageModal(props: ProjectManageModalProps): React.JSX.Element { +export default function RobotManageModal(props: RobotManageModalProps): React.JSX.Element { const {t} = I18Next.useTranslation(); - const [modules, setModules] = React.useState([]); + const [modules, setModules] = React.useState([]); const [newItemName, setNewItemName] = React.useState(''); - const [currentRecord, setCurrentRecord] = React.useState(null); + const [currentRecord, setCurrentRecord] = React.useState(null); const [renameModalOpen, setRenameModalOpen] = React.useState(false); const [name, setName] = React.useState(''); const [copyModalOpen, setCopyModalOpen] = React.useState(false); /** Loads modules from storage and sorts them alphabetically. */ const loadModules = async (storage: commonStorage.Storage): Promise => { - const projects = await storage.listModules(); + const robots = await storage.listModules(); // Sort modules alphabetically by class name - projects.sort((a, b) => a.className.localeCompare(b.className)); - setModules(projects); + robots.sort((a, b) => a.className.localeCompare(b.className)); + setModules(robots); - if (projects.length > 0 && props.noProjects) { - props.setProject(projects[0]); // Set the first project as the current project + if (robots.length > 0 && props.noRobots) { + props.setRobot(robots[0]); // Set the first robot as the current robot props.onCancel(); // Close the modal after selecting } }; - /** Handles renaming a project. */ - const handleRename = async (origModule: commonStorage.Project, newName: string): Promise => { + /** Handles renaming a robot. */ + const handleRename = async (origModule: commonStorage.Robot, newName: string): Promise => { if (!props.storage) { return; } try { await props.storage.renameModule( - commonStorage.MODULE_TYPE_PROJECT, + commonStorage.MODULE_TYPE_ROBOT, origModule.className, origModule.className, newName @@ -107,15 +107,15 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac setRenameModalOpen(false); }; - /** Handles copying a project. */ - const handleCopy = async (origModule: commonStorage.Project, newName: string): Promise => { + /** Handles copying a robot. */ + const handleCopy = async (origModule: commonStorage.Robot, newName: string): Promise => { if (!props.storage) { return; } try { await props.storage.copyModule( - commonStorage.MODULE_TYPE_PROJECT, + commonStorage.MODULE_TYPE_ROBOT, origModule.className, origModule.className, newName @@ -129,34 +129,34 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac setCopyModalOpen(false); }; - /** Handles adding a new project. */ + /** Handles adding a new robot. */ const handleAddNewItem = async (): Promise => { const trimmedName = newItemName.trim(); if (!trimmedName || !props.storage) { return; } - const newProjectName = commonStorage.classNameToModuleName(trimmedName); - const newProjectPath = commonStorage.makeProjectPath(newProjectName); - const projectContent = commonStorage.newProjectContent(newProjectName); + const newRobotName = commonStorage.classNameToModuleName(trimmedName); + const newRobotPath = commonStorage.makeRobotPath(newRobotName); + const robotContent = commonStorage.newRobotContent(newRobotName); try { await props.storage.createModule( - commonStorage.MODULE_TYPE_PROJECT, - newProjectPath, - projectContent + commonStorage.MODULE_TYPE_ROBOT, + newRobotPath, + robotContent ); } catch (e) { - console.error('Failed to create a new project:', e); - props.setAlertErrorMessage('Failed to create a new project.'); + console.error('Failed to create a new robot:', e); + props.setAlertErrorMessage('Failed to create a new robot.'); } setNewItemName(''); await loadModules(props.storage); }; - /** Handles project deletion with proper cleanup. */ - const handleDeleteProject = async (record: commonStorage.Project): Promise => { + /** Handles robot deletion with proper cleanup. */ + const handleDeleteRobot = async (record: commonStorage.Robot): Promise => { if (!props.storage) { return; } @@ -164,43 +164,43 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac const newModules = modules.filter((m) => m.modulePath !== record.modulePath); setModules(newModules); - // Find another project to set as current - let foundAnotherProject = false; - for (const project of modules) { - if (project.modulePath !== record.modulePath) { - props.setProject(project); - foundAnotherProject = true; + // Find another robot to set as current + let foundAnotherRobot = false; + for (const robot of modules) { + if (robot.modulePath !== record.modulePath) { + props.setRobot(robot); + foundAnotherRobot = true; break; } } - if (!foundAnotherProject) { - props.setProject(null); + if (!foundAnotherRobot) { + props.setRobot(null); } try { - await props.storage.deleteModule(commonStorage.MODULE_TYPE_PROJECT, record.modulePath); + await props.storage.deleteModule(commonStorage.MODULE_TYPE_ROBOT, record.modulePath); } catch (e) { - console.error('Failed to delete the project:', e); - props.setAlertErrorMessage('Failed to delete the project.'); + console.error('Failed to delete the robot:', e); + props.setAlertErrorMessage('Failed to delete the robot.'); } }; - /** Handles project selection. */ - const handleSelectProject = (record: commonStorage.Project): void => { - props.setProject(record); + /** Handles robot selection. */ + const handleSelectRobot = (record: commonStorage.Robot): void => { + props.setRobot(record); props.onCancel(); }; - /** Opens the rename modal for a specific project. */ - const openRenameModal = (record: commonStorage.Project): void => { + /** Opens the rename modal for a specific robot. */ + const openRenameModal = (record: commonStorage.Robot): void => { setCurrentRecord(record); setName(record.className); setRenameModalOpen(true); }; - /** Opens the copy modal for a specific project. */ - const openCopyModal = (record: commonStorage.Project): void => { + /** Opens the copy modal for a specific robot. */ + const openCopyModal = (record: commonStorage.Robot): void => { setCurrentRecord(record); setName(record.className + COPY_SUFFIX); setCopyModalOpen(true); @@ -208,12 +208,12 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac /** Gets the rename modal title. */ const getRenameModalTitle = (): string => { - return `Rename Project: ${currentRecord ? currentRecord.className : ''}`; + return `Rename Robot: ${currentRecord ? currentRecord.className : ''}`; }; /** Gets the copy modal title. */ const getCopyModalTitle = (): string => { - return `Copy Project: ${currentRecord ? currentRecord.className : ''}`; + return `Copy Robot: ${currentRecord ? currentRecord.className : ''}`; }; /** Creates the container style object. */ @@ -230,7 +230,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac }); /** Table column configuration. */ - const columns: Antd.TableProps['columns'] = [ + const columns: Antd.TableProps['columns'] = [ { title: 'Name', dataIndex: 'className', @@ -248,14 +248,14 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac title: 'Actions', key: 'actions', width: ACTIONS_COLUMN_WIDTH, - render: (_, record: commonStorage.Project) => ( + render: (_, record: commonStorage.Robot) => ( } - onClick={() => handleSelectProject(record)} + onClick={() => handleSelectRobot(record)} /> @@ -279,7 +279,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac handleDeleteProject(record)} + onConfirm={() => handleDeleteRobot(record)} okText={t('Delete')} cancelText={t('Cancel')} okType="danger" @@ -320,7 +320,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac cancelText={t('Cancel')} > {currentRecord && ( - { @@ -328,8 +328,8 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac handleRename(currentRecord, name); } }} - projects={modules} - setProjects={setModules} + robots={modules} + setRobots={setModules} /> )} @@ -347,7 +347,7 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac cancelText={t('Cancel')} > {currentRecord && ( - { @@ -355,14 +355,14 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac handleCopy(currentRecord, name); } }} - projects={modules} - setProjects={setModules} + robots={modules} + setRobots={setModules} /> )} - {props.noProjects && ( + {props.noRobots && ( )}
-
- {!props.noProjects && ( - + {!props.noRobots && ( + columns={columns} dataSource={modules} rowKey="modulePath" @@ -405,10 +405,10 @@ export default function ProjectManageModal(props: ProjectManageModalProps): Reac } : false} bordered locale={{ - emptyText: 'No projects found', + emptyText: 'No robots found', }} onRow={(record) => ({ - onDoubleClick: () => handleSelectProject(record), + onDoubleClick: () => handleSelectRobot(record), })} /> )} diff --git a/src/reactComponents/ProjectNameComponent.tsx b/src/reactComponents/RobotNameComponent.tsx similarity index 82% rename from src/reactComponents/ProjectNameComponent.tsx rename to src/reactComponents/RobotNameComponent.tsx index 3e8c0b82..c029dfaa 100644 --- a/src/reactComponents/ProjectNameComponent.tsx +++ b/src/reactComponents/RobotNameComponent.tsx @@ -23,13 +23,13 @@ import * as I18Next from 'react-i18next'; import * as React from 'react'; import * as commonStorage from '../storage/common_storage'; -/** Props for the ProjectNameComponent. */ -interface ProjectNameComponentProps { +/** Props for the RobotNameComponent. */ +interface RobotNameComponentProps { newItemName: string; setNewItemName: (name: string) => void; onAddNewItem: () => void; - projects: commonStorage.Project[] | null; - setProjects: (projects: commonStorage.Project[]) => void; + robots: commonStorage.Robot[] | null; + setRobots: (robots: commonStorage.Robot[]) => void; } /** Full width style for input components. */ @@ -38,20 +38,20 @@ const FULL_WIDTH_STYLE = {width: '100%'}; /** Top margin for error alert. */ const ERROR_ALERT_MARGIN_TOP = 8; -/** Invalid project name message suffix. */ -const INVALID_NAME_MESSAGE_SUFFIX = ' is not a valid project name. Please enter a different name.'; +/** Invalid robot name message suffix. */ +const INVALID_NAME_MESSAGE_SUFFIX = ' is not a valid robot name. Please enter a different name.'; -/** Duplicate project name message prefix. */ -const DUPLICATE_NAME_MESSAGE_PREFIX = 'There is already a project named '; +/** Duplicate robot name message prefix. */ +const DUPLICATE_NAME_MESSAGE_PREFIX = 'There is already a robot named '; -/** Duplicate project name message suffix. */ +/** Duplicate robot name message suffix. */ const DUPLICATE_NAME_MESSAGE_SUFFIX = '. Please enter a different name.'; /** - * Component for entering and validating project names. + * Component for entering and validating robot names. * Provides input validation, error display, and automatic capitalization. */ -export default function ProjectNameComponent(props: ProjectNameComponentProps): React.JSX.Element { +export default function RobotNameComponent(props: RobotNameComponentProps): React.JSX.Element { const {t} = I18Next.useTranslation(); const [alertErrorMessage, setAlertErrorMessage] = React.useState(''); const [alertErrorVisible, setAlertErrorVisible] = React.useState(false); @@ -59,7 +59,7 @@ export default function ProjectNameComponent(props: ProjectNameComponentProps): /** Handles adding a new item with validation. */ const handleAddNewItem = (): void => { const trimmedName = props.newItemName.trim(); - if (!trimmedName || !props.projects) { + if (!trimmedName || !props.robots) { return; } @@ -68,7 +68,7 @@ export default function ProjectNameComponent(props: ProjectNameComponentProps): return; } - if (props.projects.some((project) => project.className === trimmedName)) { + if (props.robots.some((robot) => robot.className === trimmedName)) { showError(DUPLICATE_NAME_MESSAGE_PREFIX + trimmedName + DUPLICATE_NAME_MESSAGE_SUFFIX); return; } @@ -117,7 +117,7 @@ export default function ProjectNameComponent(props: ProjectNameComponentProps): /> ); - /** Renders the new project button. */ + /** Renders the new robot button. */ const renderButton = (): React.JSX.Element => ( - {t('example_project')} + {t('example_robot')} {renderInput()} diff --git a/src/reactComponents/Tabs.tsx b/src/reactComponents/Tabs.tsx index 253e1147..be799bdc 100644 --- a/src/reactComponents/Tabs.tsx +++ b/src/reactComponents/Tabs.tsx @@ -48,8 +48,8 @@ export interface TabsProps { tabList: TabItem[]; setTabList: (items: TabItem[]) => void; activeTab: string; - project: commonStorage.Project | null; - setProject: (project: commonStorage.Project | null) => void; + robot: commonStorage.Robot | null; + setRobot: (robot: commonStorage.Robot | null) => void; setAlertErrorMessage: (message: string) => void; currentModule: commonStorage.Module | null; setCurrentModule: (module: commonStorage.Module | null) => void; @@ -63,7 +63,7 @@ const COPY_SUFFIX = 'Copy'; const MIN_TABS_FOR_CLOSE_OTHERS = 2; /** - * Tab component that manages project module tabs with add, edit, delete, and rename functionality. + * Tab component that manages robot module tabs with add, edit, delete, and rename functionality. * Provides context menus for tab operations and modal dialogs for user input. */ export function Component(props: TabsProps): React.JSX.Element { @@ -77,14 +77,14 @@ export function Component(props: TabsProps): React.JSX.Element { const [copyModalOpen, setCopyModalOpen] = React.useState(false); const [currentTab, setCurrentTab] = React.useState(null); - const triggerProjectUpdate = (): void => { - props.setProject(structuredClone(props.project)); + const triggerRobotUpdate = (): void => { + props.setRobot(structuredClone(props.robot)); } /** Handles tab change and updates current module. */ const handleTabChange = (key: string): void => { - if (props.project) { - props.setCurrentModule(commonStorage.findModuleInProject(props.project, key)); + if (props.robot) { + props.setCurrentModule(commonStorage.findModuleInRobot(props.robot, key)); setActiveKey(key); } }; @@ -97,11 +97,11 @@ export function Component(props: TabsProps): React.JSX.Element { /** Adds a new tab for the given module key. */ const addTab = (key: string): void => { const newTabs = [...props.tabList]; - if (!props.project) { + if (!props.robot) { return; } - const module = commonStorage.findModuleInProject(props.project, key); + const module = commonStorage.findModuleInRobot(props.robot, key); if (!module) { return; } @@ -157,14 +157,14 @@ export function Component(props: TabsProps): React.JSX.Element { /** Handles renaming a module tab. */ const handleRename = async (key: string, newName: string): Promise => { - if (!props.storage || !props.project) { + if (!props.storage || !props.robot) { return; } try { - const newPath = await commonStorage.renameModuleInProject( + const newPath = await commonStorage.renameModuleInRobot( props.storage, - props.project, + props.robot, newName, key ); @@ -178,7 +178,7 @@ export function Component(props: TabsProps): React.JSX.Element { props.setTabList(newTabs); setActiveKey(newPath); - triggerProjectUpdate(); + triggerRobotUpdate(); } catch (error) { console.error('Error renaming module:', error); props.setAlertErrorMessage('Failed to rename module'); @@ -189,14 +189,14 @@ export function Component(props: TabsProps): React.JSX.Element { /** Handles copying a module tab. */ const handleCopy = async (key: string, newName: string): Promise => { - if (!props.storage || !props.project) { + if (!props.storage || !props.robot) { return; } try { - const newPath = await commonStorage.copyModuleInProject( + const newPath = await commonStorage.copyModuleInRobot( props.storage, - props.project, + props.robot, newName, key ); @@ -213,7 +213,7 @@ export function Component(props: TabsProps): React.JSX.Element { newTabs.push({ key: newPath, title: newName, type: originalTab.type }); props.setTabList(newTabs); setActiveKey(newPath); - triggerProjectUpdate(); + triggerRobotUpdate(); } catch (error) { console.error('Error copying module:', error); props.setAlertErrorMessage('Failed to copy module'); @@ -262,9 +262,9 @@ export function Component(props: TabsProps): React.JSX.Element { const newTabs = props.tabList.filter((t) => t.key !== tab.key); props.setTabList(newTabs); - if (props.storage && props.project) { - await commonStorage.removeModuleFromProject(props.storage, props.project, tab.key); - triggerProjectUpdate(); + if (props.storage && props.robot) { + await commonStorage.removeModuleFromRobot(props.storage, props.robot, tab.key); + triggerRobotUpdate(); } if (newTabs.length > 0) { @@ -352,8 +352,8 @@ export function Component(props: TabsProps): React.JSX.Element { isOpen={addTabDialogOpen} onCancel={() => setAddTabDialogOpen(false)} onOk={handleAddTabOk} - project={props.project} - setProject={props.setProject} + robot={props.robot} + setRobot={props.setRobot} currentTabs={props.tabList} storage={props.storage} /> @@ -381,7 +381,7 @@ export function Component(props: TabsProps): React.JSX.Element { handleRename(currentTab.key, name); } }} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel="" /> @@ -411,7 +411,7 @@ export function Component(props: TabsProps): React.JSX.Element { handleCopy(currentTab.key, name); } }} - project={props.project} + robot={props.robot} storage={props.storage} buttonLabel="" /> diff --git a/src/storage/client_side_storage.ts b/src/storage/client_side_storage.ts index 9540fb6f..bd837e28 100644 --- a/src/storage/client_side_storage.ts +++ b/src/storage/client_side_storage.ts @@ -118,13 +118,13 @@ class ClientSideStorage implements commonStorage.Storage { }); } - async listModules(): Promise { + async listModules(): Promise { return new Promise((resolve, reject) => { - const projects: {[key: string]: commonStorage.Project} = {}; // key is project name, value is Project + const robots: {[key: string]: commonStorage.Robot} = {}; // key is robot name, value is Robot // The mechanisms and opModes variables hold any Mechanisms and OpModes that - // are read before the Project to which they belong is read. - const mechanisms: {[key: string]: commonStorage.Mechanism[]} = {}; // key is project name, value is list of Mechanisms - const opModes: {[key: string]: commonStorage.OpMode[]} = {}; // key is project name, value is list of OpModes + // are read before the Robot to which they belong is read. + const mechanisms: {[key: string]: commonStorage.Mechanism[]} = {}; // key is robot name, value is list of Mechanisms + const opModes: {[key: string]: commonStorage.OpMode[]} = {}; // key is robot name, value is list of OpModes const openCursorRequest = this.db.transaction(['modules'], 'readonly') .objectStore('modules') .openCursor(); @@ -143,70 +143,70 @@ class ClientSideStorage implements commonStorage.Storage { const module: commonStorage.Module = { modulePath: path, moduleType: moduleType, - projectName: commonStorage.getProjectName(path), + robotName: commonStorage.getRobotName(path), moduleName: moduleName, dateModifiedMillis: value.dateModifiedMillis, className: commonStorage.moduleNameToClassName(moduleName), } - if (moduleType === commonStorage.MODULE_TYPE_PROJECT) { - const project: commonStorage.Project = { + if (moduleType === commonStorage.MODULE_TYPE_ROBOT) { + const robot: commonStorage.Robot = { ...module, mechanisms: [], opModes: [], }; - projects[project.projectName] = project; - // Add any Mechanisms that belong to this project that have already + robots[robot.robotName] = robot; + // Add any Mechanisms that belong to this robot that have already // been read. - if (project.projectName in mechanisms) { - project.mechanisms = mechanisms[project.projectName]; - delete mechanisms[project.projectName]; + if (robot.robotName in mechanisms) { + robot.mechanisms = mechanisms[robot.robotName]; + delete mechanisms[robot.robotName]; } - // Add any OpModes that belong to this project that have already been + // Add any OpModes that belong to this robot that have already been // read. - if (project.projectName in opModes) { - project.opModes = opModes[project.projectName]; - delete opModes[project.projectName]; + if (robot.robotName in opModes) { + robot.opModes = opModes[robot.robotName]; + delete opModes[robot.robotName]; } } else if (moduleType === commonStorage.MODULE_TYPE_MECHANISM) { const mechanism: commonStorage.Mechanism = { ...module, }; - if (mechanism.projectName in projects) { - // If the Project to which this Mechanism belongs has already been read, + if (mechanism.robotName in robots) { + // If the Robot to which this Mechanism belongs has already been read, // add this Mechanism to it. - projects[mechanism.projectName].mechanisms.push(mechanism); + robots[mechanism.robotName].mechanisms.push(mechanism); } else { // Otherwise, add this Mechanism to the mechanisms local variable. - if (mechanism.projectName in mechanisms) { - mechanisms[mechanism.projectName].push(mechanism); + if (mechanism.robotName in mechanisms) { + mechanisms[mechanism.robotName].push(mechanism); } else { - mechanisms[mechanism.projectName] = [mechanism]; + mechanisms[mechanism.robotName] = [mechanism]; } } } else if (moduleType === commonStorage.MODULE_TYPE_OPMODE) { const opMode: commonStorage.OpMode = { ...module, }; - if (opMode.projectName in projects) { - // If the Project to which this OpMode belongs has already been read, + if (opMode.robotName in robots) { + // If the Robot to which this OpMode belongs has already been read, // add this OpMode to it. - projects[opMode.projectName].opModes.push(opMode); + robots[opMode.robotName].opModes.push(opMode); } else { // Otherwise, add this OpMode to the opModes local variable. - if (opMode.projectName in opModes) { - opModes[opMode.projectName].push(opMode); + if (opMode.robotName in opModes) { + opModes[opMode.robotName].push(opMode); } else { - opModes[opMode.projectName] = [opMode]; + opModes[opMode.robotName] = [opMode]; } } } cursor.continue(); } else { // The cursor is done. We have finished reading all the modules. - const modules: commonStorage.Project[] = []; - const sortedProjectNames = Object.keys(projects).sort(); - sortedProjectNames.forEach((projectName) => { - modules.push(projects[projectName]); + const modules: commonStorage.Robot[] = []; + const sortedRobotNames = Object.keys(robots).sort(); + sortedRobotNames.forEach((robotName) => { + modules.push(robots[robotName]); }); resolve(modules); } @@ -299,7 +299,7 @@ class ClientSideStorage implements commonStorage.Storage { }); } - private async _renameOrCopyProject(oldProjectName: string, newProjectName: string, copy: boolean): Promise { + private async _renameOrCopyRobot(oldRobotName: string, newRobotName: string, copy: boolean): Promise { return new Promise((resolve, reject) => { const transaction = this.db.transaction(['modules'], 'readwrite'); transaction.oncomplete = () => { @@ -310,7 +310,7 @@ class ClientSideStorage implements commonStorage.Storage { reject(new Error('IndexedDB transaction aborted.')); }; const modulesObjectStore = transaction.objectStore('modules'); - // First get the list of modules in the project. + // First get the list of modules in the robot. const oldToNewModulePaths: {[key: string]: string} = {}; const openCursorRequest = modulesObjectStore.openCursor(); openCursorRequest.onerror = () => { @@ -324,19 +324,19 @@ class ClientSideStorage implements commonStorage.Storage { const value = cursor.value; const path = value.path; const moduleType = value.type; - if (commonStorage.getProjectName(path) === oldProjectName) { + if (commonStorage.getRobotName(path) === oldRobotName) { let newPath; - if (moduleType === commonStorage.MODULE_TYPE_PROJECT) { - newPath = commonStorage.makeProjectPath(newProjectName); + if (moduleType === commonStorage.MODULE_TYPE_ROBOT) { + newPath = commonStorage.makeRobotPath(newRobotName); } else { const moduleName = commonStorage.getModuleName(path); - newPath = commonStorage.makeModulePath(newProjectName, moduleName); + newPath = commonStorage.makeModulePath(newRobotName, moduleName); } oldToNewModulePaths[path] = newPath; } cursor.continue(); } else { - // Now rename the project for each of the modules. + // Now rename the robot for each of the modules. Object.entries(oldToNewModulePaths).forEach(([oldModulePath, newModulePath]) => { const getRequest = modulesObjectStore.get(oldModulePath); getRequest.onerror = () => { @@ -376,25 +376,25 @@ class ClientSideStorage implements commonStorage.Storage { } async renameModule( - moduleType: string, projectName: string, + moduleType: string, robotName: string, oldModuleName: string, newModuleName: string): Promise { return this._renameOrCopyModule( - moduleType, projectName, oldModuleName, newModuleName, false); + moduleType, robotName, oldModuleName, newModuleName, false); } async copyModule( - moduleType: string, projectName: string, + moduleType: string, robotName: string, oldModuleName: string, newModuleName: string): Promise { return this._renameOrCopyModule( - moduleType, projectName, oldModuleName, newModuleName, true); + moduleType, robotName, oldModuleName, newModuleName, true); } private async _renameOrCopyModule( - moduleType: string, projectName: string, + moduleType: string, robotName: string, oldModuleName: string, newModuleName: string, copy: boolean): Promise { - if (moduleType == commonStorage.MODULE_TYPE_PROJECT) { - return this._renameOrCopyProject(oldModuleName, newModuleName, copy); + if (moduleType == commonStorage.MODULE_TYPE_ROBOT) { + return this._renameOrCopyRobot(oldModuleName, newModuleName, copy); } return new Promise((resolve, reject) => { @@ -407,8 +407,8 @@ class ClientSideStorage implements commonStorage.Storage { reject(new Error('IndexedDB transaction aborted.')); }; const modulesObjectStore = transaction.objectStore('modules'); - const oldModulePath = commonStorage.makeModulePath(projectName, oldModuleName); - const newModulePath = commonStorage.makeModulePath(projectName, newModuleName); + const oldModulePath = commonStorage.makeModulePath(robotName, oldModuleName); + const newModulePath = commonStorage.makeModulePath(robotName, newModuleName); const getRequest = modulesObjectStore.get(oldModulePath); getRequest.onerror = () => { console.log('IndexedDB get request failed. getRequest.error is...'); @@ -446,7 +446,7 @@ class ClientSideStorage implements commonStorage.Storage { }); } - private async _deleteProject(projectName: string): Promise { + private async _deleteRobot(robotName: string): Promise { return new Promise((resolve, reject) => { const transaction = this.db.transaction(['modules'], 'readwrite'); transaction.oncomplete = () => { @@ -457,7 +457,7 @@ class ClientSideStorage implements commonStorage.Storage { reject(new Error('IndexedDB transaction aborted.')); }; const modulesObjectStore = transaction.objectStore('modules'); - // First get the list of modulePaths in the project. + // First get the list of modulePaths in the robot. const modulePaths: string[] = []; const openCursorRequest = modulesObjectStore.openCursor(); openCursorRequest.onerror = () => { @@ -470,7 +470,7 @@ class ClientSideStorage implements commonStorage.Storage { if (cursor) { const value = cursor.value; const path = value.path; - if (commonStorage.getProjectName(path) === projectName) { + if (commonStorage.getRobotName(path) === robotName) { modulePaths.push(path); } cursor.continue(); @@ -492,9 +492,9 @@ class ClientSideStorage implements commonStorage.Storage { } async deleteModule(moduleType: string, modulePath: string): Promise { - if (moduleType == commonStorage.MODULE_TYPE_PROJECT) { - const projectName = commonStorage.getProjectName(modulePath); - return this._deleteProject(projectName); + if (moduleType == commonStorage.MODULE_TYPE_ROBOT) { + const robotName = commonStorage.getRobotName(modulePath); + return this._deleteRobot(robotName); } return new Promise((resolve, reject) => { @@ -518,9 +518,9 @@ class ClientSideStorage implements commonStorage.Storage { }); } - async downloadProject(projectName: string): Promise { + async downloadRobot(robotName: string): Promise { return new Promise((resolve, reject) => { - // Collect all the modules in the project. + // Collect all the modules in the robot. const moduleContents: {[key: string]: string} = {}; // key is module name, value is module content const openCursorRequest = this.db.transaction(['modules'], 'readonly') .objectStore('modules') @@ -534,29 +534,29 @@ class ClientSideStorage implements commonStorage.Storage { const cursor = openCursorRequest.result; if (cursor) { const value = cursor.value; - if (commonStorage.getProjectName(value.path) === projectName) { + if (commonStorage.getRobotName(value.path) === robotName) { const moduleName = commonStorage.getModuleName(value.path); moduleContents[moduleName] = value.content; } cursor.continue(); } else { - // The cursor is done. We have finished collecting all the modules in the project. + // The cursor is done. We have finished collecting all the modules in the robot. // Now create the blob for download. - const blobUrl = await commonStorage.produceDownloadProjectBlob(projectName, moduleContents); + const blobUrl = await commonStorage.produceDownloadRobotBlob(robotName, moduleContents); resolve(blobUrl); } }; }); } - async uploadProject(projectName: string, blobUrl: string): Promise { + async uploadRobot(robotName: string, blobUrl: string): Promise { return new Promise(async (resolve, reject) => { // Process the uploaded blob to get the module types and contents. let moduleTypes: {[key: string]: string}; // key is module name, value is module content let moduleContents: {[key: string]: string}; // key is module name, value is module content try { [moduleTypes, moduleContents] = await commonStorage.processUploadedBlob( - projectName, blobUrl); + robotName, blobUrl); } catch (e) { console.log('commonStorage.processUploadedBlob failed.'); reject(new Error('commonStorage.processUploadedBlob failed.')); @@ -577,7 +577,7 @@ class ClientSideStorage implements commonStorage.Storage { for (const moduleName in moduleTypes) { const moduleType = moduleTypes[moduleName]; const moduleContent = moduleContents[moduleName]; - const modulePath = commonStorage.makeModulePath(projectName, moduleName); + const modulePath = commonStorage.makeModulePath(robotName, moduleName); const getRequest = modulesObjectStore.get(modulePath); getRequest.onerror = () => { console.log('IndexedDB get request failed. getRequest.error is...'); diff --git a/src/storage/common_storage.ts b/src/storage/common_storage.ts index 76912caf..de81f5b3 100644 --- a/src/storage/common_storage.ts +++ b/src/storage/common_storage.ts @@ -36,7 +36,7 @@ import { createGeneratorContext } from '../editor/generator_context'; export type Module = { modulePath: string, moduleType: string, - projectName: string, + robotName: string, moduleName: string, dateModifiedMillis: number, className: string, @@ -45,7 +45,7 @@ export type Module = { export type Mechanism = Module; export type OpMode = Module; -export type Project = Module & { +export type Robot = Module & { mechanisms: Mechanism[] opModes: OpMode[], }; @@ -56,7 +56,7 @@ export type Component = { } export const MODULE_TYPE_UNKNOWN = 'unknown'; -export const MODULE_TYPE_PROJECT = 'project'; +export const MODULE_TYPE_ROBOT = 'robot'; export const MODULE_TYPE_MECHANISM = 'mechanism'; export const MODULE_TYPE_OPMODE = 'opmode'; @@ -78,98 +78,98 @@ export const UPLOAD_DOWNLOAD_FILE_EXTENSION = '.blocks'; export interface Storage { saveEntry(entryKey: string, entryValue: string): Promise; fetchEntry(entryKey: string, defaultValue: string): Promise; - listModules(): Promise; + listModules(): Promise; fetchModuleContent(modulePath: string): Promise; createModule(moduleType: string, modulePath: string, moduleContent: string): Promise; saveModule(modulePath: string, moduleContent: string): Promise; - renameModule(moduleType: string, projectName: string, oldModuleName: string, newModuleName: string): Promise; - copyModule(moduleType: string, projectName: string, oldModuleName: string, newModuleName: string): Promise; + renameModule(moduleType: string, robotName: string, oldModuleName: string, newModuleName: string): Promise; + copyModule(moduleType: string, robotName: string, oldModuleName: string, newModuleName: string): Promise; deleteModule(moduleType: string, modulePath: string): Promise; - downloadProject(projectName: string): Promise; - uploadProject(projectName: string, blobUrl: string): Promise; + downloadRobot(robotName: string): Promise; + uploadRobot(robotName: string, blobUrl: string): Promise; } /** - * Adds a new module to the project. + * Adds a new module to the robot. * @param storage The storage interface to use for creating the module. - * @param project The project to add the module to. + * @param robot The robot to add the module to. * @param moduleType The type of the module (e.g., 'mechanism', 'opmode'). * @param className The name of the class. */ -export async function addModuleToProject( - storage: Storage, project: Project, moduleType: string, className: string): Promise { +export async function addModuleToRobot( + storage: Storage, robot: Robot, moduleType: string, className: string): Promise { let newModuleName = classNameToModuleName(className); - let newModulePath = makeModulePath(project.projectName, newModuleName); + let newModulePath = makeModulePath(robot.robotName, newModuleName); if (moduleType === MODULE_TYPE_MECHANISM) { - const mechanismContent = newMechanismContent(project.projectName, newModuleName); + const mechanismContent = newMechanismContent(robot.robotName, newModuleName); await storage.createModule(MODULE_TYPE_MECHANISM, newModulePath, mechanismContent); - project.mechanisms.push({ + robot.mechanisms.push({ modulePath: newModulePath, moduleType: MODULE_TYPE_MECHANISM, - projectName: project.projectName, + robotName: robot.robotName, moduleName: newModuleName, className: className } as Mechanism); } else if (moduleType === MODULE_TYPE_OPMODE) { - const opModeContent = newOpModeContent(project.projectName, newModuleName); + const opModeContent = newOpModeContent(robot.robotName, newModuleName); await storage.createModule(MODULE_TYPE_OPMODE, newModulePath, opModeContent); - project.opModes.push({ + robot.opModes.push({ modulePath: newModulePath, moduleType: MODULE_TYPE_OPMODE, - projectName: project.projectName, + robotName: robot.robotName, moduleName: newModuleName, className: className } as OpMode); } } /** - * Removes a module from the project. + * Removes a module from the robot. * @param storage The storage interface to use for deleting the module. - * @param project The project to remove the module from. + * @param robot The robot to remove the module from. * @param modulePath The path of the module to remove. */ -export async function removeModuleFromProject( - storage: Storage, project: Project, modulePath: string): Promise { - const module = findModuleInProject(project, modulePath); +export async function removeModuleFromRobot( + storage: Storage, robot: Robot, modulePath: string): Promise { + const module = findModuleInRobot(robot, modulePath); if (module) { await storage.deleteModule(module.moduleType, modulePath); if (module.moduleType === MODULE_TYPE_MECHANISM) { - project.mechanisms = project.mechanisms.filter(m => m.modulePath !== modulePath); + robot.mechanisms = robot.mechanisms.filter(m => m.modulePath !== modulePath); } else if (module.moduleType === MODULE_TYPE_OPMODE) { - project.opModes = project.opModes.filter(o => o.modulePath !== modulePath); + robot.opModes = robot.opModes.filter(o => o.modulePath !== modulePath); } } } /** - * Renames a module in the project. + * Renames a module in the robot. * @param storage The storage interface to use for renaming the module. - * @param project The project containing the module to rename. + * @param robot The robot containing the module to rename. * @param proposedName The new name for the module. * @param oldModuleName The current name of the module. * @returns A promise that resolves when the module has been renamed. */ -export async function renameModuleInProject( - storage: Storage, project: Project, proposedName: string, oldModulePath: string): Promise { - const module = findModuleInProject(project, oldModulePath); +export async function renameModuleInRobot( + storage: Storage, robot: Robot, proposedName: string, oldModulePath: string): Promise { + const module = findModuleInRobot(robot, oldModulePath); if (module) { const newModuleName = classNameToModuleName(proposedName); - const newModulePath = makeModulePath(project.projectName, newModuleName); - await storage.renameModule(module.moduleType, project.projectName, module.moduleName, newModuleName); + const newModulePath = makeModulePath(robot.robotName, newModuleName); + await storage.renameModule(module.moduleType, robot.robotName, module.moduleName, newModuleName); module.modulePath = newModulePath; module.moduleName = newModuleName; module.className = proposedName; if (module.moduleType === MODULE_TYPE_MECHANISM) { - const mechanism = project.mechanisms.find(m => m.modulePath === module.modulePath); + const mechanism = robot.mechanisms.find(m => m.modulePath === module.modulePath); if (mechanism) { mechanism.modulePath = newModulePath; mechanism.moduleName = newModuleName; mechanism.className = proposedName; } } else if (module.moduleType === MODULE_TYPE_OPMODE) { - const opMode = project.opModes.find(o => o.modulePath === module.modulePath); + const opMode = robot.opModes.find(o => o.modulePath === module.modulePath); if (opMode) { opMode.modulePath = newModulePath; opMode.moduleName = newModuleName; @@ -181,34 +181,34 @@ export async function renameModuleInProject( return ''; } /** - * Copies a module in the project. + * Copies a module in the robot. * @param storage The storage interface to use for copying the module. - * @param project The project containing the module to copy. + * @param robot The robot containing the module to copy. * @param proposedName The new name for the module. * @param oldModuleName The current name of the module. * @returns A promise that resolves when the module has been copied. */ -export async function copyModuleInProject( - storage: Storage, project: Project, proposedName: string, oldModulePath: string): Promise { - const module = findModuleInProject(project, oldModulePath); +export async function copyModuleInRobot( + storage: Storage, robot: Robot, proposedName: string, oldModulePath: string): Promise { + const module = findModuleInRobot(robot, oldModulePath); if (module) { const newModuleName = classNameToModuleName(proposedName); - const newModulePath = makeModulePath(project.projectName, newModuleName); - await storage.copyModule(module.moduleType, project.projectName, module.moduleName, newModuleName); + const newModulePath = makeModulePath(robot.robotName, newModuleName); + await storage.copyModule(module.moduleType, robot.robotName, module.moduleName, newModuleName); if (module.moduleType === MODULE_TYPE_MECHANISM) { - project.mechanisms.push({ + robot.mechanisms.push({ modulePath: newModulePath, moduleType: MODULE_TYPE_MECHANISM, - projectName: project.projectName, + robotName: robot.robotName, moduleName: newModuleName, className: proposedName } as Mechanism); } else if (module.moduleType === MODULE_TYPE_OPMODE) { - project.opModes.push({ + robot.opModes.push({ modulePath: newModulePath, moduleType: MODULE_TYPE_OPMODE, - projectName: project.projectName, + robotName: robot.robotName, moduleName: newModuleName, className: proposedName } as OpMode); @@ -219,12 +219,12 @@ export async function copyModuleInProject( } /** - * Checks if the proposed class name is valid and does not conflict with existing names in the project. - * @param project The project to check against. + * Checks if the proposed class name is valid and does not conflict with existing names in the robot. + * @param robot The robot to check against. * @param proposedName The proposed class name to validate. * @returns An object containing a boolean `ok` indicating if the name is valid, and an `error` message if it is not. */ -export function isClassNameOk(project: Project, proposedName: string) { +export function isClassNameOk(robot: Robot, proposedName: string) { let ok = true; let error = ''; @@ -232,11 +232,11 @@ export function isClassNameOk(project: Project, proposedName: string) { ok = false; error = proposedName + ' is not a valid name. Please enter a different name.'; } - else if (proposedName == project.className) { + else if (proposedName == robot.className) { ok = false; - error = 'The project is already named ' + proposedName + '. Please enter a different name.'; + error = 'The robot is already named ' + proposedName + '. Please enter a different name.'; } - else if (getClassInProject(project, proposedName) != null) { + else if (getClassInRobot(robot, proposedName) != null) { ok = false; error = 'Another Mechanism or OpMode is already named ' + proposedName + '. Please enter a different name.' } @@ -248,15 +248,15 @@ export function isClassNameOk(project: Project, proposedName: string) { } /** - * Returns true if the given classname is in the project + * Returns true if the given classname is in the robot */ -export function getClassInProject(project: Project, name: string): Module | null { - for (const mechanism of project.mechanisms) { +export function getClassInRobot(robot: Robot, name: string): Module | null { + for (const mechanism of robot.mechanisms) { if (mechanism.className === name) { return mechanism; } } - for (const opMode of project.opModes) { + for (const opMode of robot.opModes) { if (opMode.className === name) { return opMode; } @@ -267,9 +267,9 @@ export function getClassInProject(project: Project, name: string): Module | null /** * Returns the module with the given module path, or null if it is not found. */ -export function findModule(modules: Project[], modulePath: string): Module | null { - for (const project of modules) { - const result = findModuleInProject(project, modulePath); +export function findModule(modules: Robot[], modulePath: string): Module | null { + for (const robot of modules) { + const result = findModuleInRobot(robot, modulePath); if (result) { return result; } @@ -279,18 +279,18 @@ export function findModule(modules: Project[], modulePath: string): Module | nul } /** - * Returns the module with the given module path inside the given project, or null if it is not found. + * Returns the module with the given module path inside the given robot, or null if it is not found. */ -export function findModuleInProject(project: Project, modulePath: string): Module | null { - if (project.modulePath === modulePath) { - return project; +export function findModuleInRobot(robot: Robot, modulePath: string): Module | null { + if (robot.modulePath === modulePath) { + return robot; } - for (const mechanism of project.mechanisms) { + for (const mechanism of robot.mechanisms) { if (mechanism.modulePath === modulePath) { return mechanism; } } - for (const opMode of project.opModes) { + for (const opMode of robot.opModes) { if (opMode.modulePath === modulePath) { return opMode; } @@ -388,27 +388,27 @@ export function isValidPythonModuleName(name: string): boolean { } /** - * Returns the module path for the given project and module names. + * Returns the module path for the given robot and module names. */ -export function makeModulePath(projectName: string, moduleName: string): string { - return projectName + '/' + moduleName + '.py'; +export function makeModulePath(robotName: string, moduleName: string): string { + return robotName + '/' + moduleName + '.py'; } /** - * Returns the project path for the given project names. + * Returns the robot path for the given robot names. */ -export function makeProjectPath(projectName: string): string { - return makeModulePath(projectName, projectName); +export function makeRobotPath(robotName: string): string { + return makeModulePath(robotName, robotName); } /** - * Returns the project name for given module path. + * Returns the robot name for given module path. */ -export function getProjectName(modulePath: string): string { +export function getRobotName(modulePath: string): string { const regex = new RegExp('^([a-z_A-Z][a-z0-9_]*)/([a-z_A-Z][a-z0-9_]*).py$'); const result = regex.exec(modulePath) if (!result) { - throw new Error('Unable to extract the project name.'); + throw new Error('Unable to extract the robot name.'); } return result[1]; } @@ -446,16 +446,16 @@ function startingBlocksToModuleContent( } /** - * Returns the module content for a new Project. + * Returns the module content for a new Robot. */ -export function newProjectContent(projectName: string): string { +export function newRobotContent(robotName: string): string { const module: Module = { - modulePath: makeProjectPath(projectName), - moduleType: MODULE_TYPE_PROJECT, - projectName: projectName, - moduleName: projectName, + modulePath: makeRobotPath(robotName), + moduleType: MODULE_TYPE_ROBOT, + robotName: robotName, + moduleName: robotName, dateModifiedMillis: 0, - className: moduleNameToClassName(projectName), + className: moduleNameToClassName(robotName), }; return startingBlocksToModuleContent(module, startingRobotBlocks); @@ -464,11 +464,11 @@ export function newProjectContent(projectName: string): string { /** * Returns the module content for a new Mechanism. */ -export function newMechanismContent(projectName: string, mechanismName: string): string { +export function newMechanismContent(robotName: string, mechanismName: string): string { const module: Module = { - modulePath: makeModulePath(projectName, mechanismName), + modulePath: makeModulePath(robotName, mechanismName), moduleType: MODULE_TYPE_MECHANISM, - projectName: projectName, + robotName: robotName, moduleName: mechanismName, dateModifiedMillis: 0, className: moduleNameToClassName(mechanismName), @@ -480,11 +480,11 @@ export function newMechanismContent(projectName: string, mechanismName: string): /** * Returns the module content for a new OpMode. */ -export function newOpModeContent(projectName: string, opModeName: string): string { +export function newOpModeContent(robotName: string, opModeName: string): string { const module: Module = { - modulePath: makeModulePath(projectName, opModeName), + modulePath: makeModulePath(robotName, opModeName), moduleType: MODULE_TYPE_OPMODE, - projectName: projectName, + robotName: robotName, moduleName: opModeName, dateModifiedMillis: 0, className: moduleNameToClassName(opModeName), @@ -554,7 +554,7 @@ function getParts(moduleContent: string): string[] { } if (parts.length <= PARTS_INDEX_MODULE_TYPE) { // This module was saved without the module type. - // This module is either a Project or an OpMode, but we don't know which from just the content. + // This module is either a Robot or an OpMode, but we don't know which from just the content. parts.push(MODULE_TYPE_UNKNOWN); } if (parts.length <= PARTS_INDEX_COMPONENTS) { @@ -624,15 +624,15 @@ export function extractComponents(moduleContent: string): Component[] { } /** - * Produce the blob for downloading a project. + * Produce the blob for downloading a robot. */ -export async function produceDownloadProjectBlob( - projectName: string, moduleContents: { [key: string]: string }): Promise { +export async function produceDownloadRobotBlob( + robotName: string, moduleContents: { [key: string]: string }): Promise { const zip = new JSZip(); for (const moduleName in moduleContents) { const moduleContent = moduleContents[moduleName]; const moduleContentForDownload = _processModuleContentForDownload( - projectName, moduleName, moduleContent); + robotName, moduleName, moduleContent); zip.file(moduleName, moduleContentForDownload); } const content = await zip.generateAsync({ type: "blob" }); @@ -644,7 +644,7 @@ export async function produceDownloadProjectBlob( * Process the module content so it can be downloaded. */ function _processModuleContentForDownload( - projectName: string, moduleName: string, moduleContent: string): string { + robotName: string, moduleName: string, moduleContent: string): string { const parts = getParts(moduleContent); let blocksContent = parts[PARTS_INDEX_BLOCKS_CONTENT]; if (blocksContent.startsWith(MARKER_BLOCKS_CONTENT)) { @@ -656,9 +656,9 @@ function _processModuleContentForDownload( } const module: Module = { - modulePath: makeModulePath(projectName, moduleName), + modulePath: makeModulePath(robotName, moduleName), moduleType: moduleType, - projectName: projectName, + robotName: robotName, moduleName: moduleName, dateModifiedMillis: 0, className: moduleNameToClassName(moduleName), @@ -673,18 +673,18 @@ function _processModuleContentForDownload( } /** - * Make a unique project name for an uploaded project. + * Make a unique robot name for an uploaded robot. */ -export function makeUploadProjectName( - uploadFileName: string, existingProjectNames: string[]): string { +export function makeUploadRobotName( + uploadFileName: string, existingRobotNames: string[]): string { const preferredName = uploadFileName.substring( 0, uploadFileName.length - UPLOAD_DOWNLOAD_FILE_EXTENSION.length); let name = preferredName; // No suffix. let suffix = 0; while (true) { let nameClash = false; - for (const existingProjectName of existingProjectNames) { - if (name == existingProjectName) { + for (const existingRobotName of existingRobotNames) { + if (name == existingRobotName) { nameClash = true; break; } @@ -701,7 +701,7 @@ export function makeUploadProjectName( * Process the uploaded blob to get the module types and contents. */ export async function processUploadedBlob( - projectName: string, blobUrl: string) + robotName: string, blobUrl: string) : Promise<[{ [key: string]: string }, { [key: string]: string }]> { const prefix = 'data:application/octet-stream;base64,'; if (!blobUrl.startsWith(prefix)) { @@ -729,7 +729,7 @@ export async function processUploadedBlob( for (const filename in files) { const uploadedContent = files[filename]; let [moduleName, moduleType, moduleContent] = _processUploadedModule( - projectName, filename, uploadedContent); + robotName, filename, uploadedContent); moduleTypes[moduleName] = moduleType; moduleContents[moduleName] = moduleContent; @@ -742,7 +742,7 @@ export async function processUploadedBlob( * Processes an uploaded module to get the module name, type, and content. */ export function _processUploadedModule( - projectName: string, filename: string, uploadedContent: string) + robotName: string, filename: string, uploadedContent: string) : [string, string, string] { const parts = getParts(uploadedContent); let blocksContent = parts[PARTS_INDEX_BLOCKS_CONTENT]; @@ -754,13 +754,13 @@ export function _processUploadedModule( moduleType = moduleType.substring(MARKER_MODULE_TYPE.length); } - const moduleName = (moduleType === MODULE_TYPE_PROJECT) - ? projectName : filename; + const moduleName = (moduleType === MODULE_TYPE_ROBOT) + ? robotName : filename; const module: Module = { - modulePath: makeModulePath(projectName, moduleName), + modulePath: makeModulePath(robotName, moduleName), moduleType: moduleType, - projectName: projectName, + robotName: robotName, moduleName: moduleName, dateModifiedMillis: 0, className: moduleNameToClassName(moduleName), diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index a19c1a96..133e2363 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -43,7 +43,7 @@ export function getHardwareCategory(currentModule: commonStorage.Module) { ] }; } - if (currentModule.moduleType === commonStorage.MODULE_TYPE_PROJECT) { + if (currentModule.moduleType === commonStorage.MODULE_TYPE_ROBOT) { return { kind: 'category', name: 'Hardware', diff --git a/src/toolbox/methods_category.ts b/src/toolbox/methods_category.ts index d41ced35..4e72acba 100644 --- a/src/toolbox/methods_category.ts +++ b/src/toolbox/methods_category.ts @@ -67,8 +67,8 @@ export class MethodsCategory { } }); - if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_PROJECT) { - // Add the methods for a Project (Robot). + if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_ROBOT) { + // Add the methods for a Robot. this.addClassBlocksForCurrentModule( 'More Robot Methods', robot_class_blocks, methodNamesAlreadyUsed, contents); diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index 1509966a..2aec4211 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -8,7 +8,7 @@ export function getToolboxJSON( shownPythonToolboxCategories: Set | null, currentModule: commonStorage.Module): Blockly.utils.toolbox.ToolboxDefinition { switch (currentModule.moduleType) { - case commonStorage.MODULE_TYPE_PROJECT: + case commonStorage.MODULE_TYPE_ROBOT: case commonStorage.MODULE_TYPE_MECHANISM: return { kind: 'categoryToolbox',