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:

  1. BasicWidgetRegistry (widget-builder library)

    • Contains 13 hardcoded basic widgets
    • Always available
    • Cannot be modified by users
    • Provides base widgets + variants
  2. 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)

  1. ✅ Create basic-widget.types.ts (DONE)
  2. 🔄 Create BasicWidgetRegistryService with 13 widgets
  3. Export from widget-builder library
  4. Add to tsconfig.base.json paths

Phase 2: Integrate with WidgetRegistryService

  1. Inject BasicWidgetRegistryService
  2. Modify loadRegistry() to combine basic + user widgets
  3. Test in editor-web-lib

Phase 3: Ensure Editability

  1. Add variant editing to properties panel
  2. Connect save to storage-system
  3. 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

  1. Complete BasicWidgetRegistryService with all 13 widgets
  2. Export from widget-builder library
  3. Integrate into WidgetRegistryService
  4. Test in editor-web-lib
  5. 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