Implements dependency injection with Brandi

Replaces manual manager creation with Brandi DI container
for improved dependency management and testability.

Removes the ManagerFactory and its usages.
This commit is contained in:
Janus C. H. Knudsen 2025-10-15 20:09:12 +02:00
parent b3b930c1f9
commit a80e4a7603
4 changed files with 93 additions and 132 deletions

View file

@ -3,7 +3,7 @@
* Configures all bindings with proper dependency resolution
*/
import { Container } from 'brandi';
import { Container, injected } from 'brandi';
import { TOKENS } from './tokens';
import { eventBus } from '../core/EventBus';
import { calendarConfig } from '../core/CalendarConfig';
@ -57,57 +57,103 @@ export function createContainer(): Container {
container.bind(TOKENS.eventRendererStrategy).toConstant(new DateEventRenderer());
}
// Create instances manually and bind as constants (singletons)
// This is simpler than using decorators or complex factory setup
// Proper Brandi DI bindings with injected() declarations
const eventManager = new EventManager(eventBus);
container.bind(TOKENS.eventManager).toConstant(eventManager);
// EventManager
injected(EventManager, TOKENS.eventBus);
container
.bind(TOKENS.eventManager)
.toInstance(EventManager)
.inSingletonScope();
const eventRenderer = new EventRenderingService(eventBus, eventManager, container.get(TOKENS.eventRendererStrategy));
container.bind(TOKENS.eventRenderer).toConstant(eventRenderer);
// EventRenderingService
injected(EventRenderingService, TOKENS.eventBus, TOKENS.eventManager, TOKENS.eventRendererStrategy);
container
.bind(TOKENS.eventRenderer)
.toInstance(EventRenderingService)
.inSingletonScope();
const gridRenderer = new GridRenderer(container.get(TOKENS.columnRenderer));
container.bind(TOKENS.gridRenderer).toConstant(gridRenderer);
// GridRenderer
injected(GridRenderer, TOKENS.columnRenderer);
container
.bind(TOKENS.gridRenderer)
.toInstance(GridRenderer)
.inSingletonScope();
const gridManager = new GridManager(gridRenderer);
container.bind(TOKENS.gridManager).toConstant(gridManager);
// GridManager
injected(GridManager, TOKENS.gridRenderer);
container
.bind(TOKENS.gridManager)
.toInstance(GridManager)
.inSingletonScope();
const scrollManager = new ScrollManager();
container.bind(TOKENS.scrollManager).toConstant(scrollManager);
// ScrollManager (no dependencies)
container
.bind(TOKENS.scrollManager)
.toInstance(ScrollManager)
.inSingletonScope();
const navigationManager = new NavigationManager(eventBus, eventRenderer, gridRenderer);
container.bind(TOKENS.navigationManager).toConstant(navigationManager);
// NavigationManager
injected(NavigationManager, TOKENS.eventBus, TOKENS.eventRenderer, TOKENS.gridRenderer);
container
.bind(TOKENS.navigationManager)
.toInstance(NavigationManager)
.inSingletonScope();
const viewManager = new ViewManager(eventBus);
container.bind(TOKENS.viewManager).toConstant(viewManager);
// ViewManager
injected(ViewManager, TOKENS.eventBus);
container
.bind(TOKENS.viewManager)
.toInstance(ViewManager)
.inSingletonScope();
const dragDropManager = new DragDropManager(eventBus);
container.bind(TOKENS.dragDropManager).toConstant(dragDropManager);
// DragDropManager
injected(DragDropManager, TOKENS.eventBus);
container
.bind(TOKENS.dragDropManager)
.toInstance(DragDropManager)
.inSingletonScope();
const allDayManager = new AllDayManager(eventManager);
container.bind(TOKENS.allDayManager).toConstant(allDayManager);
// AllDayManager
injected(AllDayManager, TOKENS.eventManager);
container
.bind(TOKENS.allDayManager)
.toInstance(AllDayManager)
.inSingletonScope();
const resizeHandleManager = new ResizeHandleManager();
container.bind(TOKENS.resizeHandleManager).toConstant(resizeHandleManager);
// ResizeHandleManager (no dependencies)
container
.bind(TOKENS.resizeHandleManager)
.toInstance(ResizeHandleManager)
.inSingletonScope();
const edgeScrollManager = new EdgeScrollManager(eventBus);
container.bind(TOKENS.edgeScrollManager).toConstant(edgeScrollManager);
// EdgeScrollManager
injected(EdgeScrollManager, TOKENS.eventBus);
container
.bind(TOKENS.edgeScrollManager)
.toInstance(EdgeScrollManager)
.inSingletonScope();
const dragHoverManager = new DragHoverManager(eventBus);
container.bind(TOKENS.dragHoverManager).toConstant(dragHoverManager);
// DragHoverManager
injected(DragHoverManager, TOKENS.eventBus);
container
.bind(TOKENS.dragHoverManager)
.toInstance(DragHoverManager)
.inSingletonScope();
const headerManager = new HeaderManager(container.get(TOKENS.headerRenderer));
container.bind(TOKENS.headerManager).toConstant(headerManager);
// HeaderManager
injected(HeaderManager, TOKENS.headerRenderer);
container
.bind(TOKENS.headerManager)
.toInstance(HeaderManager)
.inSingletonScope();
// CalendarManager depends on multiple managers
const calendarManager = new CalendarManager(
eventBus,
eventManager,
gridManager,
eventRenderer,
scrollManager
);
container.bind(TOKENS.calendarManager).toConstant(calendarManager);
// CalendarManager
injected(CalendarManager, TOKENS.eventBus, TOKENS.eventManager, TOKENS.gridManager, TOKENS.eventRenderer, TOKENS.scrollManager);
container
.bind(TOKENS.calendarManager)
.toInstance(CalendarManager)
.inSingletonScope();
return container;
}

View file

@ -1,92 +0,0 @@
import { IEventBus } from '../types/CalendarTypes';
import { EventManager } from '../managers/EventManager';
import { EventRenderingService } from '../renderers/EventRendererManager';
import { GridManager } from '../managers/GridManager';
import { ScrollManager } from '../managers/ScrollManager';
import { NavigationManager } from '../managers/NavigationManager';
import { ViewManager } from '../managers/ViewManager';
import { CalendarManager } from '../managers/CalendarManager';
import { DragDropManager } from '../managers/DragDropManager';
import { AllDayManager } from '../managers/AllDayManager';
import { ResizeHandleManager } from '../managers/ResizeHandleManager';
import { EdgeScrollManager } from '../managers/EdgeScrollManager';
import { DragHoverManager } from '../managers/DragHoverManager';
import { CalendarManagers } from '../types/ManagerTypes';
import { HeaderManager } from '../managers/HeaderManager';
/**
* Factory for creating and managing calendar managers with proper dependency injection
*/
export class ManagerFactory {
private static instance: ManagerFactory;
private constructor() {}
public static getInstance(): ManagerFactory {
if (!ManagerFactory.instance) {
ManagerFactory.instance = new ManagerFactory();
}
return ManagerFactory.instance;
}
/**
* Create all managers with proper dependency injection
*/
public createManagers(eventBus: IEventBus): CalendarManagers {
// Create managers in dependency order
const eventManager = new EventManager(eventBus);
const eventRenderer = new EventRenderingService(eventBus, eventManager);
const gridManager = new GridManager();
const scrollManager = new ScrollManager();
const navigationManager = new NavigationManager(eventBus, eventRenderer);
const viewManager = new ViewManager(eventBus);
const dragDropManager = new DragDropManager(eventBus);
const allDayManager = new AllDayManager(eventManager);
const resizeHandleManager = new ResizeHandleManager();
const edgeScrollManager = new EdgeScrollManager(eventBus);
const dragHoverManager = new DragHoverManager(eventBus);
// HeaderManager now requires HeaderRenderer via DI - will be created in Brandi container
// const headerManager = new HeaderManager();
// CalendarManager depends on all other managers
const calendarManager = new CalendarManager(
eventBus,
eventManager,
gridManager,
eventRenderer,
scrollManager
);
return {
eventManager,
eventRenderer,
gridManager,
scrollManager,
navigationManager,
viewManager,
calendarManager,
dragDropManager,
allDayManager,
resizeHandleManager,
edgeScrollManager,
dragHoverManager,
headerManager: null as any // HeaderManager created in Brandi container
};
}
/**
* Initialize all managers in the correct order
*/
public async initializeManagers(managers: CalendarManagers): Promise<void> {
try {
await managers.calendarManager.initialize?.();
await managers.resizeHandleManager.initialize?.();
} catch (error) {
throw error;
}
}
}

View file

@ -52,6 +52,13 @@ async function initializeCalendar(): Promise<void> {
const calendarManager = container.get(TOKENS.calendarManager);
const eventManager = container.get(TOKENS.eventManager);
const resizeHandleManager = container.get(TOKENS.resizeHandleManager);
const headerManager = container.get(TOKENS.headerManager);
const dragDropManager = container.get(TOKENS.dragDropManager);
const viewManager = container.get(TOKENS.viewManager);
const navigationManager = container.get(TOKENS.navigationManager);
const edgeScrollManager = container.get(TOKENS.edgeScrollManager);
const dragHoverManager = container.get(TOKENS.dragHoverManager);
const allDayManager = container.get(TOKENS.allDayManager);
// Initialize managers
await calendarManager.initialize?.();

View file

@ -1,7 +1,7 @@
import { calendarConfig } from '../core/CalendarConfig';
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
import { ColumnRenderContext } from './ColumnRenderer';
import { ColumnRenderer, ColumnRenderContext } from './ColumnRenderer';
import { eventBus } from '../core/EventBus';
import { DateService } from '../utils/DateService';
import { CoreEvents } from '../constants/CoreEvents';