Calendar/.workbench/plan-comparison.md
Janus C. H. Knudsen c16e432b29 Refactors rendering pipeline with flexible data handling
Removes hardcoded data from render context, allowing more dynamic renderer implementation

Changes include:
- Decoupling data retrieval from render context
- Simplifying renderer interface
- Supporting more flexible data traversal strategies

Prepares for more modular and adaptable rendering approach
2025-12-09 15:24:19 +01:00

6.1 KiB

Plan Sammenligning: Spec vs Min Plan

1. Grid Container

Spec Min Plan Kommentar
Ét grid (ctx.grid) To containers (headerContainer + columnContainer) Afvigelse: Vi har 2 containers for at understøtte header drawer og sticky headers. Spec'en bruger ét grid hvor append-rækkefølge = rækker.

Spørgsmål: Er 2 containers ok, eller skal vi følge spec'en med ét grid?


2. RenderContext

Spec Min Plan
{ grid: HTMLElement, teams: Team[] } { headerContainer: HTMLElement, columnContainer: HTMLElement }

Spec:

interface RenderContext {
  grid: HTMLElement;
  teams: Team[];
}

Min plan:

interface RenderContext {
  headerContainer: HTMLElement;
  columnContainer: HTMLElement;
}

Kommentar: Spec'en har teams data i context. Min plan har ingen data i context - renderers henter selv. Er det korrekt at fjerne data fra context?


3. Data Model

Spec Min Plan
Nested: team.resources[], resource.dates[] Flad med id-relationer, renderers henter selv

Spec:

interface Team {
  id: string;
  name: string;
  resources: Resource[];  // nested
}

Min plan:

// Hardcoded i renderer
private resourcesByTeam = {
  'team1': ['res1', 'res2'],  // kun ids
  'team2': ['res3']
};

Kommentar: Spec'en har nested data. Min plan bruger id-relationer og renderers slår selv op. Begge dele virker - min plan er mere fleksibel for store datasets.


4. Renderer Interface

Spec Min Plan
render(ctx): void render(ids, next, context): void

Spec:

interface Renderer {
  id: string;
  next: Renderer | null;
  render(ctx: RenderContext): void;
}

Min plan:

interface IGroupingRenderer {
  readonly type: string;
  count?(ids: string[], next: NextFunction): number;
  render(ids: string[], next: NextFunction, context: RenderContext): void;
}

Kommentar:

  • Spec'en: Renderer har next som property, kalder selv this.next.render(ctx)
  • Min plan: next kommer som parameter, kalder next.render(ids)

Min plan sender ids eksplicit. Spec'en bruger nested data så ids er unødvendige.


5. Pipeline / Builder

Spec Min Plan
buildPipeline() linker renderer.next RenderBuilder med buildChain()

Spec:

function buildPipeline(renderers: Renderer[]) {
  for (let i = 0; i < renderers.length - 1; i++) {
    renderers[i].next = renderers[i + 1];
  }
  return { run(ctx) { first.render(ctx); } };
}

Min plan:

class RenderBuilder {
  add(renderer): this { ... }
  build(startIds): void { ... }
  private buildChain(index): NextFunction { ... }
}

Kommentar: Samme koncept, forskellig implementering. Spec'en muterer renderers (next property). Min plan bruger closures (functional chain).


6. Colspan Beregning

Spec Min Plan
Beregnes før render: team.resources.length Beregnes via next.count()

Spec:

// I renderer
cell.style.setProperty('--team-cols', team.resources.length.toString());

Min plan:

// I renderer
const colspan = next.count(resourceIds);
cell.style.setProperty('--team-cols', String(colspan));

Kommentar: Spec'en ved colspan direkte fra nested data. Min plan kalder next.count() rekursivt for at beregne. Resultat er det samme.


7. CSS Custom Properties

Spec Min Plan
--total-cols, --team-cols --grid-columns, --team-cols

Kommentar: Næsten identisk. Begge bruger CSS vars til dynamisk colspan.


8. Append Rækkefølge

Spec Min Plan
Alle teams → alle resources → alle dates Per team: resources → dates

Spec flow:

TeamRenderer: append team1, team2, team3 headers
ResourceRenderer: append res1, res2, res3, res4 headers
DateRenderer: append alle dates

Min plan flow:

TeamRenderer:
  append team1 header → next.render(['res1','res2'])
    ResourceRenderer: append res1 → next.render(dates)
                      append res2 → next.render(dates)
  append team2 header → next.render(['res3'])
    ResourceRenderer: append res3 → next.render(dates)

Kommentar: Dette er en væsentlig forskel.

Spec'en renderer alle teams først, så alle resources, så alle dates - CSS grid auto-row placerer dem.

Min plan renderer nested: team1 → team1's resources → team1's dates → team2 → osv.

Spørgsmål: Hvilken approach foretrækker du? Spec'ens "lag for lag" eller min "nested traversal"?


9. Hvem kalder next?

Spec Min Plan
Renderer kalder this.next.render(ctx) efter egen render Renderer kalder next.render(ids) per item

Spec:

render(ctx) {
  // render alle teams
  for (const team of ctx.teams) { ... }
  // derefter kald next
  if (this.next) this.next.render(ctx);
}

Min plan:

render(ids, next, context) {
  for (const id of ids) {
    // render ét team
    next.render(childIds);  // kald next PER team
  }
}

Kommentar: Spec'en kalder next ÉN gang efter alle items. Min plan kalder next PER item. Dette hænger sammen med punkt 8.


Opsummering af Afvigelser

# Emne Status
1 2 containers vs 1 grid Accepteret (header drawer)
2 Data i context Afvigelse - fjernet
3 Nested vs flad data Accepteret (id-relationer)
4 next som parameter vs property Afvigelse - funktionel
5 Pipeline implementation Lignende
6 Colspan beregning Lignende
7 CSS vars Identisk
8 Render rækkefølge Væsentlig afvigelse
9 Hvornår next kaldes Væsentlig afvigelse

Åbne Spørgsmål

  1. Render rækkefølge: Skal vi følge spec'ens "lag for lag" approach, eller er "nested traversal" ok?

  2. Context data: Spec'en har teams i context. Skal vi have noget data i context, eller er det ok at renderers henter selv?

  3. 2 containers: Er det ok at beholde 2 containers for header drawer support?