feat: add domains, ideas, layouts, widgets API modules

- Add DomainsModule with full CRUD, search, and activity logging
- Add IdeasModule with quick capture endpoint
- Add LayoutsModule for user dashboard layouts
- Add WidgetsModule for widget definitions (read-only)
- Update ActivityService with domain/idea logging methods
- Register all new modules in AppModule
This commit is contained in:
Jason Woltje
2026-01-29 13:47:03 -06:00
parent 973502f26e
commit f47dd8bc92
66 changed files with 4277 additions and 29 deletions

View File

@@ -0,0 +1,74 @@
/**
* Widget renderer - renders the appropriate widget component based on type
*/
import { WidgetWrapper } from "./WidgetWrapper";
import { TasksWidget, CalendarWidget, QuickCaptureWidget, AgentStatusWidget } from "@/components/widgets";
import type { WidgetPlacement } from "@mosaic/shared";
export interface WidgetRendererProps {
widget: WidgetPlacement;
isEditing?: boolean;
onRemove?: (widgetId: string) => void;
}
const WIDGET_COMPONENTS = {
tasks: TasksWidget,
calendar: CalendarWidget,
"quick-capture": QuickCaptureWidget,
"agent-status": AgentStatusWidget,
};
const WIDGET_CONFIG = {
tasks: {
displayName: "Tasks",
description: "View and manage your tasks",
},
calendar: {
displayName: "Calendar",
description: "Upcoming events and schedule",
},
"quick-capture": {
displayName: "Quick Capture",
description: "Capture ideas and notes",
},
"agent-status": {
displayName: "Agent Status",
description: "View running agent sessions",
},
};
export function WidgetRenderer({ widget, isEditing = false, onRemove }: WidgetRendererProps) {
// Extract widget type from ID (e.g., "tasks-123" -> "tasks")
const widgetType = widget.i.split("-")[0] as keyof typeof WIDGET_COMPONENTS;
const WidgetComponent = WIDGET_COMPONENTS[widgetType];
const config = WIDGET_CONFIG[widgetType] || { displayName: "Widget", description: "" };
if (!WidgetComponent) {
const wrapperProps = {
id: widget.i,
title: "Unknown Widget",
isEditing: isEditing,
...(onRemove && { onRemove: () => onRemove(widget.i) }),
};
return (
<WidgetWrapper {...wrapperProps}>
<div className="text-gray-500 text-sm">Widget type not found: {widgetType}</div>
</WidgetWrapper>
);
}
const wrapperProps = {
id: widget.i,
title: config.displayName,
isEditing: isEditing,
...(onRemove && { onRemove: () => onRemove(widget.i) }),
};
return (
<WidgetWrapper {...wrapperProps}>
<WidgetComponent id={widget.i} />
</WidgetWrapper>
);
}