Skip to content

Commit d847a74

Browse files
authored
Merge pull request #50 from BrainDriveAI/bugfix/duplicate-module
PR: Harden Legacy Module Resolution for Complex IDs & Improve Dev Diagnostics
2 parents f1f8e71 + 89d8450 commit d847a74

File tree

2 files changed

+71
-25
lines changed

2 files changed

+71
-25
lines changed

frontend/src/features/unified-dynamic-page-renderer/adapters/LegacyModuleAdapter.tsx

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -304,25 +304,44 @@ export const LegacyModuleAdapter: React.FC<LegacyModuleAdapterProps> = React.mem
304304

305305
if (!targetModule) {
306306
// Enhanced module ID extraction for complex generated IDs
307-
// Format: PluginName_actualModuleId_timestamp
307+
// Format: ServiceExample_Theme_userId_ServiceExample_Theme_actualModuleId_timestamp
308308
const parts = moduleId.split('_');
309-
if (parts.length >= 2) {
310-
const extractedModuleId = parts[1]; // Get the actual module ID
309+
if (parts.length >= 6) {
310+
const extractedModuleId = parts[5]; // Get the actual module ID (ThemeDisplay/ThemeController)
311311
targetModule = remotePlugin.loadedModules.find(m => m.id === extractedModuleId);
312312

313313
if (process.env.NODE_ENV === 'development') {
314314
console.log(`[LegacyModuleAdapter] Trying extracted module ID: "${extractedModuleId}" from complex ID: "${moduleId}"`);
315+
console.log(`[LegacyModuleAdapter] Module ID parts:`, parts);
315316
if (targetModule) {
316-
console.log(`[LegacyModuleAdapter] Successfully found module with extracted ID:`, {
317+
console.log(`[LegacyModuleAdapter] Successfully found module with extracted ID:`, {
317318
id: targetModule.id,
318319
name: targetModule.name,
320+
displayName: targetModule.displayName,
319321
hasComponent: !!targetModule.component
320322
});
321323
}
322324
}
323325
}
324326
}
325327

328+
if (!targetModule) {
329+
// Enhanced fallback for complex IDs: try combined plugin_module format
330+
const parts = moduleId.split('_');
331+
if (parts.length >= 4) {
332+
const combinedModuleId = `${parts[1]}_${parts[2]}`; // ServiceExample_Theme_ThemeDisplay
333+
targetModule = remotePlugin.loadedModules.find(m =>
334+
m.id === combinedModuleId ||
335+
(m.id && m.id.endsWith(parts[2])) ||
336+
m.name === parts[2]
337+
);
338+
339+
if (process.env.NODE_ENV === 'development') {
340+
console.log(`[LegacyModuleAdapter] Trying combined module ID: "${combinedModuleId}" and module name: "${parts[2]}"`);
341+
}
342+
}
343+
}
344+
326345
if (!targetModule) {
327346
// Try simple pattern removal (original logic)
328347
const baseModuleId = moduleId.replace(/-\d+$/, '');
@@ -334,17 +353,19 @@ export const LegacyModuleAdapter: React.FC<LegacyModuleAdapterProps> = React.mem
334353
}
335354

336355
if (!targetModule) {
337-
// For complex generated IDs like "BrainDriveChat_1830586da8834501bea1ef1d39c3cbe8_BrainDriveChat_BrainDriveChat_1754404718788"
338-
// Try to extract the plugin name (first part before underscore)
339-
const pluginNameFromId = moduleId.split('_')[0];
340-
targetModule = remotePlugin.loadedModules.find(m =>
341-
m.id === pluginNameFromId ||
342-
m.name === pluginNameFromId ||
343-
(m.id && m.id.includes(pluginNameFromId))
344-
);
345-
346-
if (process.env.NODE_ENV === 'development') {
347-
console.log(`[LegacyModuleAdapter] Trying plugin name extraction: "${pluginNameFromId}" from moduleId: "${moduleId}"`);
356+
// Final module name fallback: try exact match with the extracted module name
357+
const parts = moduleId.split('_');
358+
if (parts.length >= 3) {
359+
const moduleNameOnly = parts[2];
360+
targetModule = remotePlugin.loadedModules.find(m =>
361+
m.name === moduleNameOnly ||
362+
m.displayName === moduleNameOnly ||
363+
(m.id && m.id.toLowerCase().includes(moduleNameOnly.toLowerCase()))
364+
);
365+
366+
if (process.env.NODE_ENV === 'development') {
367+
console.log(`[LegacyModuleAdapter] Trying module name fallback: "${moduleNameOnly}"`);
368+
}
348369
}
349370
}
350371

@@ -383,12 +404,36 @@ export const LegacyModuleAdapter: React.FC<LegacyModuleAdapterProps> = React.mem
383404
}
384405

385406
if (process.env.NODE_ENV === 'development') {
386-
console.log(`[LegacyModuleAdapter] Target module found:`, targetModule);
407+
if (targetModule) {
408+
const parts = moduleId ? moduleId.split('_') : [];
409+
console.log(`[LegacyModuleAdapter] ✅ Module resolution successful:`, {
410+
originalModuleId: moduleId,
411+
extractedParts: parts,
412+
extractedModuleId: parts.length >= 6 ? parts[5] : 'N/A',
413+
resolvedModule: {
414+
id: targetModule.id,
415+
name: targetModule.name,
416+
displayName: targetModule.displayName,
417+
componentType: typeof targetModule.component,
418+
hasComponent: !!targetModule.component
419+
}
420+
});
421+
} else {
422+
console.warn(`[LegacyModuleAdapter] ❌ Module resolution failed:`, {
423+
originalModuleId: moduleId,
424+
pluginId: pluginId,
425+
moduleName: moduleName,
426+
extractedParts: moduleId ? moduleId.split('_') : [],
427+
availableModules: remotePlugin?.loadedModules?.map(m => ({
428+
id: m.id,
429+
name: m.name,
430+
displayName: m.displayName
431+
})) || []
432+
});
433+
}
387434
}
435+
388436
if (!targetModule) {
389-
if (process.env.NODE_ENV === 'development') {
390-
console.log(`[LegacyModuleAdapter] No target module found for ${pluginId}/${moduleId || moduleName}`);
391-
}
392437
return null;
393438
}
394439

frontend/src/features/unified-dynamic-page-renderer/components/LayoutEngine.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ export const LayoutEngine: React.FC<LayoutEngineProps> = React.memo(({
580580
// Pattern: BrainDriveBasicAIChat_59898811a4b34d9097615ed6698d25f6_1754507768265
581581
// We want: 59898811a4b34d9097615ed6698d25f6
582582
const parts = item.moduleId.split('_');
583-
const extractedModuleId = parts.length >= 2 ? parts[1] : item.moduleId;
583+
const extractedModuleId = parts.length >= 6 ? parts[5] : item.moduleId;
584584

585585
// Create stable breakpoint object
586586
const breakpointConfig = {
@@ -651,12 +651,13 @@ export const LayoutEngine: React.FC<LayoutEngineProps> = React.memo(({
651651
pluginId={item.pluginId}
652652
moduleId={module._legacy?.moduleId || (() => {
653653
// Extract simple module ID from complex ID
654-
// Pattern: BrainDriveBasicAIChat_59898811a4b34d9097615ed6698d25f6_1754507768265
655-
// We want: 59898811a4b34d9097615ed6698d25f6
654+
// Pattern: ServiceExample_Theme_userId_ServiceExample_Theme_actualModuleId_timestamp
655+
// Example: ServiceExample_Theme_c34bfc30de004813ad5b5d3a4ab9df34_ServiceExample_Theme_ThemeDisplay_1756311722722
656+
// We want: ThemeDisplay (or ThemeController)
656657
const parts = item.moduleId.split('_');
657-
if (parts.length >= 2) {
658-
// The module ID is typically the second part (after plugin name)
659-
return parts[1];
658+
if (parts.length >= 6) {
659+
// The actual module ID is the sixth part (after ServiceExample_Theme_userId_ServiceExample_Theme)
660+
return parts[5];
660661
}
661662
return item.moduleId; // fallback to original if pattern doesn't match
662663
})()}

0 commit comments

Comments
 (0)