Skip to content

Commit 2a026dc

Browse files
committed
Copy working
1 parent 2c0ab3a commit 2a026dc

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

src/reactComponents/Tabs.tsx

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function Component(props: TabsProps) {
9292
const [addTabDialogOpen, setAddTabDialogOpen] = React.useState(false);
9393
const [name, setName] = React.useState('');
9494
const [renameModalOpen, setRenameModalOpen] = React.useState(false);
95+
const [copyModalOpen, setCopyModalOpen] = React.useState(false);
9596
const [currentTab, setCurrentTab] = React.useState<TabItem | null>(null);
9697

9798
const onChange = (key: string) => {
@@ -184,7 +185,37 @@ export function Component(props: TabsProps) {
184185
}
185186
setRenameModalOpen(false);
186187
};
188+
const handleCopy = async (key: string, newName: string) => {
189+
if (props.storage && props.project) {
190+
try {
191+
let newPath = await commonStorage.copyModuleInProject(
192+
props.storage,
193+
props.project,
194+
newName,
195+
key
196+
);
197+
const newTabs = [...props.tabList];
198+
199+
// find the original tab to copy its type
200+
const originalTab = props.tabList.find(tab => tab.key === key);
201+
if (!originalTab) {
202+
console.error('Original tab not found for copying:', key);
203+
props.setAlertErrorMessage('Original tab not found for copying');
204+
return;
205+
}
206+
// Add the new tab with the copied name and type
207+
newTabs.push({ key: newPath, title: newName, type: originalTab.type });
187208

209+
props.setTabList(newTabs);
210+
setActiveKey(newPath); // Use newPath instead of key
211+
props.setProject({ ...props.project, });
212+
} catch (error) {
213+
console.error('Error copying module:', error);
214+
props.setAlertErrorMessage('Failed to copy module');
215+
}
216+
}
217+
setCopyModalOpen(false);
218+
};
188219
return (
189220
<>
190221
{contextHolder}
@@ -225,7 +256,34 @@ export function Component(props: TabsProps) {
225256
/>
226257
)}
227258
</Antd.Modal>
228-
259+
<Antd.Modal
260+
title={`Copy ${currentTab ? TabTypeUtils.toString(currentTab.type) : ''}: ${currentTab ? currentTab.title : ''}`}
261+
open={copyModalOpen}
262+
onCancel={() => setCopyModalOpen(false)}
263+
onOk={() => {
264+
if (currentTab) {
265+
handleCopy(currentTab.key, name);
266+
}
267+
}}
268+
okText={t("Copy")}
269+
cancelText={t("Cancel")}
270+
>
271+
{currentTab && (
272+
<ModuleNameComponent
273+
tabType={currentTab.type}
274+
newItemName={name}
275+
setNewItemName={setName}
276+
onAddNewItem={() => {
277+
if (currentTab) {
278+
handleCopy(currentTab.key, name);
279+
}
280+
}}
281+
project={props.project}
282+
storage={props.storage}
283+
buttonLabel=""
284+
/>
285+
)}
286+
</Antd.Modal>
229287
<Antd.Tabs
230288
type="editable-card"
231289
onChange={onChange}
@@ -293,7 +351,7 @@ export function Component(props: TabsProps) {
293351
props.setTabList(newTabs);
294352
if (props.storage && props.project) {
295353
commonStorage.removeModuleFromProject(props.storage, props.project, tab.key);
296-
props.setProject({...props.project,});
354+
props.setProject({ ...props.project, });
297355
}
298356
setActiveKey(props.tabList[0].key);
299357
},
@@ -304,7 +362,14 @@ export function Component(props: TabsProps) {
304362
key: 'copy',
305363
label: t('Copy...'),
306364
disabled: tab.type === TabType.ROBOT,
307-
icon: <CopyOutlined />
365+
icon: <CopyOutlined />,
366+
onClick: () => {
367+
// Find the current tab to get the latest title
368+
const currentTab = props.tabList.find(t => t.key === tab.key);
369+
setName((currentTab ? currentTab.title : tab.title) + "Copy");
370+
setCurrentTab(currentTab || tab);
371+
setCopyModalOpen(true);
372+
},
308373
},
309374
],
310375
}}

src/storage/common_storage.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,43 @@ export async function renameModuleInProject(
180180
}
181181
return '';
182182
}
183+
/**
184+
* Copies a module in the project.
185+
* @param storage The storage interface to use for copying the module.
186+
* @param project The project containing the module to copy.
187+
* @param proposedName The new name for the module.
188+
* @param oldModuleName The current name of the module.
189+
* @returns A promise that resolves when the module has been copied.
190+
*/
191+
export async function copyModuleInProject(
192+
storage: Storage, project: Project, proposedName: string, oldModulePath: string): Promise<string> {
193+
const module = findModuleInProject(project, oldModulePath);
194+
if (module) {
195+
const newModuleName = classNameToModuleName(proposedName);
196+
const newModulePath = makeModulePath(project.projectName, newModuleName);
197+
await storage.copyModule(module.moduleType, project.projectName, module.moduleName, newModuleName);
198+
199+
if (module.moduleType === MODULE_TYPE_MECHANISM) {
200+
project.mechanisms.push({
201+
modulePath: newModulePath,
202+
moduleType: MODULE_TYPE_MECHANISM,
203+
projectName: project.projectName,
204+
moduleName: newModuleName,
205+
className: proposedName
206+
} as Mechanism);
207+
} else if (module.moduleType === MODULE_TYPE_OPMODE) {
208+
project.opModes.push({
209+
modulePath: newModulePath,
210+
moduleType: MODULE_TYPE_OPMODE,
211+
projectName: project.projectName,
212+
moduleName: newModuleName,
213+
className: proposedName
214+
} as OpMode);
215+
}
216+
return newModulePath;
217+
}
218+
return '';
219+
}
183220

184221
/**
185222
* Checks if the proposed class name is valid and does not conflict with existing names in the project.

0 commit comments

Comments
 (0)