Skip to content

Commit 1c1f494

Browse files
committed
Modified App to fetch the contents of all the modules in the current project from storage and put them in modulePathToContentText object.
App passes modulePathToContentText to editor during loadModuleBlocks. When a module is saved, App updates modulePathToContentText. Modified editor to use modulePathToContentText instead of fetching module content from storage. Renamed saveBlocks to saveModule.
1 parent cb6502b commit 1c1f494

File tree

2 files changed

+65
-50
lines changed

2 files changed

+65
-50
lines changed

src/App.tsx

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
161161
const [messageApi, contextHolder] = Antd.message.useMessage();
162162
const [generatedCode, setGeneratedCode] = React.useState<string>('');
163163
const [toolboxSettingsModalIsOpen, setToolboxSettingsModalIsOpen] = React.useState(false);
164+
const [modulePathToContentText, setModulePathToContentText] = React.useState<{[modulePath: string]: string}>({});
164165
const [tabItems, setTabItems] = React.useState<Tabs.TabItem[]>([]);
165166
const [activeTab, setActiveTab] = React.useState('');
166167
const [shownPythonToolboxCategories, setShownPythonToolboxCategories] = React.useState<Set<string>>(new Set());
@@ -208,7 +209,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
208209
// Save current blocks before language change
209210
if (currentModule && areBlocksModified()) {
210211
try {
211-
await saveBlocks();
212+
await saveModule();
212213
} catch (e) {
213214
console.error('Failed to save blocks before language change:', e);
214215
}
@@ -303,15 +304,17 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
303304
};
304305

305306
/** Saves blocks to storage with success/error messaging. */
306-
const saveBlocks = async (): Promise<boolean> => {
307+
const saveModule = async (): Promise<boolean> => {
307308
return new Promise(async (resolve, reject) => {
308-
if (!blocksEditor.current) {
309+
if (!currentModule ||
310+
!blocksEditor.current) {
309311
reject(new Error('Blocks editor not initialized'));
310312
return;
311313
}
312314

313315
try {
314-
await blocksEditor.current.saveBlocks();
316+
const moduleContentText = await blocksEditor.current.saveModule();
317+
modulePathToContentText[currentModule.modulePath] = moduleContentText;
315318
messageApi.open({
316319
type: 'success',
317320
content: SAVE_SUCCESS_MESSAGE,
@@ -346,7 +349,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
346349
/** Changes current module with automatic saving if modified. */
347350
const changeModule = async (module: storageModule.Module | null): Promise<void> => {
348351
if (currentModule && areBlocksModified()) {
349-
await saveBlocks();
352+
await saveModule();
350353
}
351354
setCurrentModule(module);
352355
};
@@ -424,8 +427,8 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
424427
if (generatorContext.current) {
425428
generatorContext.current.setModule(currentModule);
426429
}
427-
if (blocksEditor.current) {
428-
blocksEditor.current.loadModuleBlocks(currentModule, project);
430+
if (blocksEditor.current && currentModule) {
431+
blocksEditor.current.loadModuleBlocks(currentModule, project, modulePathToContentText);
429432
}
430433
}, [currentModule]);
431434

@@ -434,7 +437,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
434437
};
435438

436439
const setupWorkspace = (newWorkspace: Blockly.WorkspaceSvg) => {
437-
if (!blocklyComponent.current || !storage) {
440+
if (!blocklyComponent.current || !storage || !generatorContext.current) {
438441
return;
439442
}
440443
// Recreate workspace when Blockly component is ready
@@ -456,7 +459,7 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
456459

457460
// Set the current module in the editor after creating it
458461
if (currentModule) {
459-
blocksEditor.current.loadModuleBlocks(currentModule, project);
462+
blocksEditor.current.loadModuleBlocks(currentModule, project, modulePathToContentText);
460463
}
461464

462465
blocksEditor.current.updateToolbox(shownPythonToolboxCategories);
@@ -494,14 +497,38 @@ const AppContent: React.FC<AppContentProps> = ({ project, setProject }): React.J
494497
}
495498
}, [currentModule, shownPythonToolboxCategories]);
496499

497-
// Update tab items when project changes
500+
// Fetch modules when project changes.
501+
React.useEffect(() => {
502+
if (project && storage) {
503+
const fetchModules = async () => {
504+
const promises: {[modulePath: string]: Promise<string>} = {}; // value is promise of module content.
505+
promises[project.robot.modulePath] = storage.fetchFileContentText(project.robot.modulePath);
506+
project.mechanisms.forEach(mechanism => {
507+
promises[mechanism.modulePath] = storage.fetchFileContentText(mechanism.modulePath);
508+
});
509+
project.opModes.forEach(opmode => {
510+
promises[opmode.modulePath] = storage.fetchFileContentText(opmode.modulePath);
511+
});
512+
const modulePathToContentText: {[modulePath: string]: string} = {}; // value is module content text
513+
await Promise.all(
514+
Object.entries(promises).map(async ([modulePath, promise]) => {
515+
modulePathToContentText[modulePath] = await promise;
516+
})
517+
);
518+
setModulePathToContentText(modulePathToContentText);
519+
};
520+
fetchModules();
521+
}
522+
}, [project]);
523+
524+
// Update tab items when fetching modules is done.
498525
React.useEffect(() => {
499526
if (project) {
500527
const tabs = createTabItemsFromProject(project);
501528
setTabItems(tabs);
502529
setActiveTab(project.robot.modulePath);
503530
}
504-
}, [project]);
531+
}, [modulePathToContentText]);
505532

506533
const { Sider, Content } = Antd.Layout;
507534

src/editor/editor.ts

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export class Editor {
4848
private storage: commonStorage.Storage;
4949
private module: storageModule.Module | null = null;
5050
private project: storageProject.Project | null = null;
51+
private modulePathToModuleContent: {[modulePath: string]: storageModuleContent.ModuleContent} = {};
5152
private modulePath: string = '';
5253
private robotPath: string = '';
5354
private moduleContentText: string = '';
@@ -117,57 +118,43 @@ export class Editor {
117118

118119
public async loadModuleBlocks(
119120
module: storageModule.Module | null,
120-
project: storageProject.Project | null) {
121+
project: storageProject.Project | null,
122+
modulePathToContentText: {[modulePath: string]: string}) {
121123
this.generatorContext.setModule(module);
122124
this.module = module;
123125
this.project = project;
124126

125-
if (this.module && this.project) {
126-
this.modulePath = this.module.modulePath;
127-
this.robotPath = this.project.robot.modulePath;
127+
if (module && project) {
128+
this.modulePath = module.modulePath;
129+
this.robotPath = project.robot.modulePath;
130+
this.moduleContentText = modulePathToContentText[this.modulePath];
128131
} else {
129132
this.modulePath = '';
130133
this.robotPath = '';
134+
this.moduleContentText = '';
131135
}
132-
this.moduleContentText = '';
133-
this.robotContent = null;
134-
this.mechanismClassNameToModuleContent = {}
136+
this.parseModules(modulePathToContentText);
135137
this.clearBlocklyWorkspace();
138+
this.loadBlocksIntoBlocklyWorkspace();
139+
}
136140

137-
if (this.module && this.project) {
138-
// Fetch the content for the current module, the robot, and the mechanisms.
139-
const promises: { [modulePath: string]: Promise<string> } = {}; // value is promise of module content.
140-
promises[this.modulePath] = this.storage.fetchFileContentText(this.modulePath);
141-
if (this.robotPath !== this.modulePath) {
142-
// Also fetch the robot module content. It contains components, etc, that can be used in OpModes.
143-
promises[this.robotPath] = this.storage.fetchFileContentText(this.robotPath)
144-
}
145-
for (const mechanism of this.project.mechanisms) {
146-
// Fetch the module content text for the mechanism.
147-
if (mechanism.modulePath !== this.modulePath) {
148-
promises[mechanism.modulePath] = this.storage.fetchFileContentText(mechanism.modulePath);
149-
}
150-
}
141+
private parseModules(modulePathToContentText: {[modulePath: string]: string}) {
142+
// Parse the modules.
143+
this.modulePathToModuleContent = {}
144+
for (const modulePath in modulePathToContentText) {
145+
const moduleContentText = modulePathToContentText[modulePath];
146+
this.modulePathToModuleContent[modulePath] = storageModuleContent.parseModuleContentText(
147+
moduleContentText);
148+
}
151149

152-
const modulePathToContentText: { [modulePath: string]: string } = {}; // value is module content
153-
await Promise.all(
154-
Object.entries(promises).map(async ([modulePath, promise]) => {
155-
modulePathToContentText[modulePath] = await promise;
156-
})
157-
);
158-
this.moduleContentText = modulePathToContentText[this.modulePath];
159-
this.robotContent = storageModuleContent.parseModuleContentText(
160-
(this.robotPath === this.modulePath)
161-
? this.moduleContentText
162-
: modulePathToContentText[this.robotPath]);
150+
this.robotContent = this.robotPath ? this.modulePathToModuleContent[this.robotPath] : null;
151+
152+
this.mechanismClassNameToModuleContent = {};
153+
if (this.project) {
163154
for (const mechanism of this.project.mechanisms) {
164155
this.mechanismClassNameToModuleContent[mechanism.className] =
165-
storageModuleContent.parseModuleContentText(
166-
(mechanism.modulePath === this.modulePath)
167-
? this.moduleContentText
168-
: modulePathToContentText[mechanism.modulePath]);
156+
this.modulePathToModuleContent[mechanism.modulePath];
169157
}
170-
this.loadBlocksIntoBlocklyWorkspace();
171158
}
172159
}
173160

@@ -194,7 +181,7 @@ export class Editor {
194181
// Add the while-loading listener.
195182
this.bindedOnChange = this.onChangeWhileLoading.bind(this);
196183
this.blocklyWorkspace.addChangeListener(this.bindedOnChange);
197-
const moduleContent = storageModuleContent.parseModuleContentText(this.moduleContentText);
184+
const moduleContent = this.modulePathToModuleContent[this.modulePath];
198185
Blockly.serialization.workspaces.load(moduleContent.getBlocks(), this.blocklyWorkspace);
199186
}
200187

@@ -334,7 +321,7 @@ export class Editor {
334321
return eventHandlerBlocks;
335322
}
336323

337-
public async saveBlocks() {
324+
public async saveModule(): Promise<string> {
338325
const moduleContentText = this.getModuleContentText();
339326
try {
340327
await this.storage.saveFile(this.modulePath, moduleContentText);
@@ -345,6 +332,7 @@ export class Editor {
345332
} catch (e) {
346333
throw e;
347334
}
335+
return moduleContentText;
348336
}
349337

350338
/**

0 commit comments

Comments
 (0)