Skip to content

Commit 5785939

Browse files
committed
rename is functional
1 parent 7451f04 commit 5785939

File tree

3 files changed

+119
-38
lines changed

3 files changed

+119
-38
lines changed

src/reactComponents/ModuleNameComponent.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default function ModuleNameComponent(props: ModuleNameComponentProps) {
6262
<Antd.Typography.Paragraph>{(props.tabType == TabType.MECHANISM) ? t("example_mechanism") : t("example_opmode")}</Antd.Typography.Paragraph>
6363
<Antd.Space.Compact style={{ width: '100%' }}>
6464
<Antd.Input
65-
style={{ width: 'calc(100% - 80px)' }}
65+
style={{ width: props.buttonLabel ? 'calc(100% - 80px)' : '100%' }}
6666
placeholder={t("addTabDialog.newItemPlaceholder")}
6767
value={props.newItemName}
6868
onChange={(e) => {
@@ -78,12 +78,15 @@ export default function ModuleNameComponent(props: ModuleNameComponentProps) {
7878
}}
7979
onPressEnter={handleAddNewItem}
8080
/>
81-
<Antd.Button
82-
type="primary"
83-
onClick={handleAddNewItem}
84-
>
85-
{props.buttonLabel}
86-
</Antd.Button>
81+
82+
{props.buttonLabel && (
83+
<Antd.Button
84+
type="primary"
85+
onClick={handleAddNewItem}
86+
>
87+
{props.buttonLabel}
88+
</Antd.Button>
89+
)}
8790
</Antd.Space.Compact>
8891
{alertErrorVisible && (
8992
<Antd.Alert

src/reactComponents/Tabs.tsx

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
CloseCircleOutlined
3636
} from '@ant-design/icons';
3737
import AddTabDialog from './AddTabDialog';
38+
import ModuleNameComponent from './ModuleNameComponent';
3839

3940
export enum TabType {
4041
ROBOT,
@@ -46,7 +47,7 @@ export namespace TabTypeUtils {
4647
export function toString(type: TabType): string {
4748
switch (type) {
4849
case TabType.ROBOT: return "Robot";
49-
case TabType.MECHANISM: return "Mechanism";
50+
case TabType.MECHANISM: return "Mechanism";
5051
case TabType.OPMODE: return "OpMode";
5152
default: return "";
5253
}
@@ -80,7 +81,7 @@ export interface TabsProps {
8081
setAlertErrorMessage: (message: string) => void;
8182
currentModule: commonStorage.Module | null;
8283
setCurrentModule: (module: commonStorage.Module | null) => void;
83-
storage : commonStorage.Storage | null;
84+
storage: commonStorage.Storage | null;
8485
}
8586

8687
export function Component(props: TabsProps) {
@@ -89,6 +90,9 @@ export function Component(props: TabsProps) {
8990

9091
const [activeKey, setActiveKey] = React.useState(props.activeTab);
9192
const [addTabDialogOpen, setAddTabDialogOpen] = React.useState(false);
93+
const [name, setName] = React.useState('');
94+
const [renameModalOpen, setRenameModalOpen] = React.useState(false);
95+
const [currentTab, setCurrentTab] = React.useState<TabItem | null>(null);
9296

9397
const onChange = (key: string) => {
9498
if (props.project) {
@@ -149,24 +153,35 @@ export function Component(props: TabsProps) {
149153
}
150154
};
151155

152-
const handleAddTabOk = (newTabs : TabItem[]) => {
156+
const handleAddTabOk = (newTabs: TabItem[]) => {
153157
props.setTabList([props.tabList[0], ...newTabs]);
154158
setActiveKey(props.tabList[0].key);
155159
setAddTabDialogOpen(false);
156160
};
157161

158-
const handleOk = (key: string) => {
159-
const input = document.querySelector('input') as HTMLInputElement;
160-
if (input && input.value.trim()) {
161-
const newTabs = props.tabList.map(t => {
162-
if (t.key === key) {
163-
return { ...t, title: input.value.trim() };
164-
}
165-
return t;
166-
});
167-
props.setTabList(newTabs);
162+
const handleRename = async (key: string, newName: string) => {
163+
if (props.storage && props.project) {
164+
try {
165+
let newPath = await commonStorage.renameModuleInProject(
166+
props.storage,
167+
props.project,
168+
newName,
169+
key
170+
);
171+
const newTabs = props.tabList.map((tab) => {
172+
if (tab.key === key) {
173+
return { ...tab, title: newName, key: newPath };
174+
}
175+
return tab;
176+
});
177+
props.setTabList(newTabs);
178+
setActiveKey(newPath); // Use newPath instead of key
179+
} catch (error) {
180+
console.error('Error renaming module:', error);
181+
props.setAlertErrorMessage('Failed to rename module');
182+
}
168183
}
169-
Antd.Modal.destroyAll();
184+
setRenameModalOpen(false);
170185
};
171186

172187
return (
@@ -180,6 +195,36 @@ export function Component(props: TabsProps) {
180195
currentTabs={props.tabList}
181196
storage={props.storage}
182197
/>
198+
199+
<Antd.Modal
200+
title={`Rename ${currentTab ? TabTypeUtils.toString(currentTab.type) : ''}: ${currentTab ? currentTab.title : ''}`}
201+
open={renameModalOpen}
202+
onCancel={() => setRenameModalOpen(false)}
203+
onOk={() => {
204+
if (currentTab) {
205+
handleRename(currentTab.key, name);
206+
}
207+
}}
208+
okText={t("Rename")}
209+
cancelText={t("Cancel")}
210+
>
211+
{currentTab && (
212+
<ModuleNameComponent
213+
tabType={currentTab.type}
214+
newItemName={name}
215+
setNewItemName={setName}
216+
onAddNewItem={() => {
217+
if (currentTab) {
218+
handleRename(currentTab.key, name);
219+
}
220+
}}
221+
project={props.project}
222+
storage={props.storage}
223+
buttonLabel=""
224+
/>
225+
)}
226+
</Antd.Modal>
227+
183228
<Antd.Tabs
184229
type="editable-card"
185230
onChange={onChange}
@@ -219,18 +264,9 @@ export function Component(props: TabsProps) {
219264
label: t("Rename..."),
220265
disabled: tab.type === TabType.ROBOT,
221266
onClick: () => {
222-
modal.confirm({
223-
title: 'Rename ' + TabTypeUtils.toString(tab.type) + ': ' + tab.title,
224-
content: (
225-
<Antd.Input
226-
autoFocus
227-
defaultValue={tab.title}
228-
onPressEnter={e => { handleOk(tab.key) }}
229-
/>
230-
),
231-
icon: null,
232-
onOk: () => { handleOk(tab.key) }
233-
});
267+
setName(tab.title);
268+
setCurrentTab(tab);
269+
setRenameModalOpen(true);
234270
},
235271
icon: <EditOutlined />
236272
},
@@ -249,8 +285,8 @@ export function Component(props: TabsProps) {
249285
onOk: async () => {
250286
const newTabs = props.tabList.filter(t => t.key !== tab.key);
251287
props.setTabList(newTabs);
252-
if(props.storage && props.project) {
253-
commonStorage.removeModuleFromProject(props.storage, props.project, tab.key);
288+
if (props.storage && props.project) {
289+
commonStorage.removeModuleFromProject(props.storage, props.project, tab.key);
254290
}
255291
setActiveKey(props.tabList[0].key);
256292
},

src/storage/common_storage.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,51 @@ export async function removeModuleFromProject(
142142
}
143143
}
144144

145-
/*
146-
* Returns true if the given class name is a valid class name and if not, why not.
147-
*/
145+
/**
146+
* Renames a module in the project.
147+
* @param storage The storage interface to use for renaming the module.
148+
* @param project The project containing the module to rename.
149+
* @param proposedName The new name for the module.
150+
* @param oldModuleName The current name of the module.
151+
* @returns A promise that resolves when the module has been renamed.
152+
*/
153+
export async function renameModuleInProject(
154+
storage: Storage, project: Project, proposedName: string, oldModulePath: string): Promise<string> {
155+
const module = findModuleInProject(project, oldModulePath);
156+
if (module) {
157+
const newModuleName = classNameToModuleName(proposedName);
158+
const newModulePath = makeModulePath(project.projectName, newModuleName);
159+
await storage.renameModule(module.moduleType, project.projectName, module.moduleName, newModuleName);
160+
module.modulePath = newModulePath;
161+
module.moduleName = newModuleName;
162+
module.className = proposedName;
163+
164+
if (module.moduleType === MODULE_TYPE_MECHANISM) {
165+
const mechanism = project.mechanisms.find(m => m.modulePath === module.modulePath);
166+
if (mechanism) {
167+
mechanism.modulePath = newModulePath;
168+
mechanism.moduleName = newModuleName;
169+
mechanism.className = proposedName;
170+
}
171+
} else if (module.moduleType === MODULE_TYPE_OPMODE) {
172+
const opMode = project.opModes.find(o => o.modulePath === module.modulePath);
173+
if (opMode) {
174+
opMode.modulePath = newModulePath;
175+
opMode.moduleName = newModuleName;
176+
opMode.className = proposedName;
177+
}
178+
return newModulePath
179+
}
180+
}
181+
return '';
182+
}
183+
184+
/**
185+
* Checks if the proposed class name is valid and does not conflict with existing names in the project.
186+
* @param project The project to check against.
187+
* @param proposedName The proposed class name to validate.
188+
* @returns An object containing a boolean `ok` indicating if the name is valid, and an `error` message if it is not.
189+
*/
148190
export function isClassNameOk(project: Project, proposedName: string) {
149191
let ok = true;
150192
let error = '';

0 commit comments

Comments
 (0)