Widget Registry Integration Analysis
Critical analysis of why widgets aren't showing in editor-web-lib
Widget Registry Integration Analysis
🔴 Critical Issue Identified
Problem: The editor's widget library shows 0 widgets because there's no widget seeding mechanism.
Current Flow (Broken)
1. WidgetRegistryService initializes
↓
2. loadRegistry() from GgStorage
↓
3. Storage key 'widget-registry' is EMPTY
↓
4. Result: 0 widgets displayed
Root Cause Analysis
File: editor-web-lib/src/lib/services/widget-registry.service.ts
constructor() {
this.logger.info('WidgetRegistryService initialized');
this.loadRegistry(); // ← Loads from storage
}
private loadRegistry(): void {
this._loading.set(true);
from(this.storage.get<RegisteredWidget[]>(this.REGISTRY_KEY)).pipe(
tap(widgets => {
if (widgets) { // ← NULL on first load!
const widgetMap = new Map<string, RegisteredWidget>();
widgets.forEach(w => widgetMap.set(w.id, w));
this._widgets.set(widgetMap);
this.logger.info('Widget registry loaded', { count: widgets.length });
}
this._loading.set(false);
}),
//...
).subscribe();
}
The Problem: No fallback to seed basic widgets when storage is empty!
🎯 Solution Strategy
Approach 1: Seed Basic Widgets on First Load (RECOMMENDED)
constructor() {
this.logger.info('WidgetRegistryService initialized');
this.loadRegistry();
this.seedBasicWidgetsIfEmpty(); // ← NEW
}
private async seedBasicWidgetsIfEmpty(): Promise<void> {
// Wait for initial load
await firstValueFrom(from(this.storage.get(this.REGISTRY_KEY)));
if (this.widgets().length === 0) {
console.log('[WidgetRegistry] No widgets found - seeding basic widgets');
await this.seedBasicWidgets();
}
}
private async seedBasicWidgets(): Promise<void> {
const basicWidgets = BASIC_WIDGETS_DEFINITION; // From our taxonomy
for (const widget of basicWidgets) {
await firstValueFrom(this.registerWidget(widget));
}
console.log(`[WidgetRegistry] Seeded ${basicWidgets.length} basic widgets`);
}
Approach 2: Separate Basic Widget Registry (ARCHITECTURAL FIX)
Current (Broken):
WidgetRegistryService (editor-web-lib)
↓ tries to load from storage
↓ EMPTY!
↓ 0 widgets
New (Fixed):
BasicWidgetRegistry (widget-builder) ← 13 widgets always available
↓ provides basic widgets
↓
WidgetRegistryService (editor-web-lib) ← user-created widgets
↓ loads user widgets + basic widgets
↓ ALL widgets available
🏗️ Architectural Decision
###Based on the taxonomy design, we need:
BasicWidgetRegistry (widget-builder library)
- Contains 13 hardcoded basic widgets
- Always available
- Cannot be modified by users
- Provides base widgets + variants
WidgetRegistryService (editor-web-lib)
- Combines basic widgets + user-created composites
- Stores user composites in GgStorage
- Displays all in editor
Integration Point
// In WidgetRegistryService
constructor() {
private readonly basicRegistry = inject(BasicWidgetRegistryService);
this.loadRegistry();
}
private loadRegistry(): void {
// 1. Get basic widgets (always available)
const basicWidgets = this.basicRegistry.widgets();
// 2. Get user widgets from storage
from(this.storage.get<RegisteredWidget[]>(this.REGISTRY_KEY)).pipe(
tap(userWidgets => {
// 3. Combine both
const allWidgets = [
...this.convertBasicToRegistered(basicWidgets),
...(userWidgets || [])
];
const widgetMap = new Map<string, RegisteredWidget>();
allWidgets.forEach(w => widgetMap.set(w.id, w));
this._widgets.set(widgetMap);
this.logger.info('Widget registry loaded', {
basic: basicWidgets.length,
user: userWidgets?.length || 0,
total: allWidgets.length
});
})
).subscribe();
}
✅ Action Plan
Phase 1: Create BasicWidgetRegistry (URGENT)
- ✅ Create basic-widget.types.ts (DONE)
- 🔄 Create BasicWidgetRegistryService with 13 widgets
- Export from widget-builder library
- Add to tsconfig.base.json paths
Phase 2: Integrate with WidgetRegistryService
- Inject BasicWidgetRegistryService
- Modify loadRegistry() to combine basic + user widgets
- Test in editor-web-lib
Phase 3: Ensure Editability
- Add variant editing to properties panel
- Connect save to storage-system
- Universe-scoped persistence
🔗 Key Files to Modify
1. widget-builder/src/lib/services/basic-widget-registry.service.ts
@Injectable({ providedIn: 'root' })
export class BasicWidgetRegistryService {
private readonly _widgets = signal<BasicWidget[]>(BASIC_WIDGETS_13);
readonly widgets = this._widgets.asReadonly();
getWidget(type: BasicWidgetType): BasicWidget | undefined {
return this._widgets().find(w => w.type === type);
}
}
2. widget-builder/src/index.ts
// Export basic widget registry
export * from './lib/services/basic-widget-registry.service';
export * from './lib/models/basic-widget.types';
3. tsconfig.base.json
{
"paths": {
"@libs-structural/widget-builder": [
"libs/libs-structural/widget-builder/src/index.ts"
]
}
}
4. editor-web-lib/src/lib/services/widget-registry.service.ts
import { BasicWidgetRegistryService } from '@libs-structural/widget-builder';
constructor() {
private readonly basicRegistry = inject(BasicWidgetRegistryService);
// ...
}
📊 Impact Analysis
Before (Current - Broken)
Widget Library Panel:
Total widgets: 0
Filtered widgets: 0
Result: Empty library ❌
After (Fixed)
Widget Library Panel:
Basic widgets: 13
User composites: 0 (initially)
Total: 13
Result: Full library ✅
🎯 Next Immediate Steps
- Complete BasicWidgetRegistryService with all 13 widgets
- Export from widget-builder library
- Integrate into WidgetRegistryService
- Test in editor-web-lib
- Add variant editing to properties panel
Priority: 🔴 CRITICAL - This blocks all widget functionality
Estimated Time: 2-3 hours
Session: 1.2.4
Status: Analysis complete, ready for implementation