Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
/**
* Widget Registry
*
* Central registry der håndterer widget discovery, queries og relationship management.
* Gør det muligt for widgets at finde hinanden og etablere dataflow.
*/
import {
WidgetMetadata,
WidgetQuery,
WidgetRegistry,
DataType,
securityWidgetSchemas,
calendarScheduleWidgetSchemas
} from '@/types/WidgetSchema';
class WidgetRegistryImpl implements WidgetRegistry {
widgets: Map<string, WidgetMetadata> = new Map();
constructor() {
// Initialize with security widget schemas
Object.values(securityWidgetSchemas).forEach(widget => {
this.register(widget);
});
// Initialize with calendar/schedule widget schemas
Object.values(calendarScheduleWidgetSchemas).forEach(widget => {
this.register(widget);
});
}
register(widget: WidgetMetadata): void {
this.widgets.set(widget.id, widget);
}
unregister(widgetId: string): void {
this.widgets.delete(widgetId);
}
get(widgetId: string): WidgetMetadata | undefined {
return this.widgets.get(widgetId);
}
// Find widgets that provide a specific data type
findByCapability(type: DataType): WidgetMetadata[] {
return Array.from(this.widgets.values()).filter(widget =>
widget.provides.some(cap => cap.outputType === type)
);
}
// Find widgets that require a specific data type
findByRequirement(type: DataType): WidgetMetadata[] {
return Array.from(this.widgets.values()).filter(widget =>
widget.requires.some(req => req.type === type)
);
}
// Find widgets that can connect to a given widget
findCompatible(widgetId: string): WidgetMetadata[] {
const widget = this.widgets.get(widgetId);
if (!widget) return [];
const compatible: Set<WidgetMetadata> = new Set();
// Find widgets that can provide what this widget requires
widget.requires.forEach(req => {
this.findByCapability(req.type).forEach(provider => {
if (provider.id !== widgetId) {
compatible.add(provider);
}
});
});
// Find widgets that require what this widget provides
widget.provides.forEach(cap => {
this.findByRequirement(cap.outputType).forEach(consumer => {
if (consumer.id !== widgetId) {
compatible.add(consumer);
}
});
});
return Array.from(compatible);
}
// Advanced query for widget discovery
query(query: WidgetQuery): WidgetMetadata[] {
return Array.from(this.widgets.values()).filter(widget => {
// Filter by provided type
if (query.providesType &&
!widget.provides.some(cap => cap.outputType === query.providesType)) {
return false;
}
// Filter by specific capability
if (query.providesCapability &&
!widget.provides.some(cap => cap.id === query.providesCapability)) {
return false;
}
// Filter by required type
if (query.requiresType &&
!widget.requires.some(req => req.type === query.requiresType)) {
return false;
}
// Filter by required source
if (query.requiresSource &&
!widget.requires.some(req => req.source === query.requiresSource)) {
return false;
}
// Filter by category
if (query.category && widget.category !== query.category) {
return false;
}
// Filter by tags
if (query.tags && !query.tags.some(tag => widget.tags.includes(tag))) {
return false;
}
// Filter by priority
if (query.priority && widget.priority !== query.priority) {
return false;
}
return true;
});
}
// Get widgets that provide data to the given widget
getProviders(widgetId: string): WidgetMetadata[] {
const widget = this.widgets.get(widgetId);
if (!widget) return [];
return widget.relations
.filter(rel => rel.type === 'depends_on')
.map(rel => this.widgets.get(rel.targetWidgetId))
.filter((w): w is WidgetMetadata => w !== undefined);
}
// Get widgets that consume data from the given widget
getConsumers(widgetId: string): WidgetMetadata[] {
const widget = this.widgets.get(widgetId);
if (!widget) return [];
return widget.relations
.filter(rel => rel.type === 'provides_to')
.map(rel => this.widgets.get(rel.targetWidgetId))
.filter((w): w is WidgetMetadata => w !== undefined);
}
// Build complete dependency graph
getDependencyGraph(): Map<string, string[]> {
const graph = new Map<string, string[]>();
this.widgets.forEach((widget, id) => {
const dependencies = widget.relations
.filter(rel => rel.type === 'depends_on')
.map(rel => rel.targetWidgetId);
graph.set(id, dependencies);
});
return graph;
}
// Get widget's introduction/description for ecosystem
describeWidget(widgetId: string): string {
const widget = this.widgets.get(widgetId);
if (!widget) return 'Widget ikke fundet';
const requires = widget.requires.map(r => ` - ${r.name} (${r.type}): ${r.description}`).join('\n');
const provides = widget.provides.map(p => ` - ${p.name} (${p.outputType}): ${p.description}`).join('\n');
const configs = widget.config.map(c => ` - ${c.name}: ${c.description}`).join('\n');
return `
## ${widget.name} (v${widget.version})
${widget.description}
**Kategori:** ${widget.category}
**Tags:** ${widget.tags.join(', ')}
**Prioritet:** ${widget.priority || 'medium'}
### Kræver Data:
${requires || ' Ingen data-afhængigheder'}
### Leverer Data:
${provides || ' Ingen outputs'}
### Konfiguration:
${configs || ' Ingen konfigurerbare indstillinger'}
${widget.documentation ? `### Dokumentation:\n${widget.documentation}` : ''}
`.trim();
}
// Export registry state for persistence or debugging
export(): Record<string, WidgetMetadata> {
const result: Record<string, WidgetMetadata> = {};
this.widgets.forEach((widget, id) => {
result[id] = widget;
});
return result;
}
}
// Singleton instance
export const widgetRegistry = new WidgetRegistryImpl();
// React hook for widget discovery
export function useWidgetRegistry() {
return widgetRegistry;
}