Adds hierarchical grouping and entity resolution support
Enhances calendar rendering with dynamic parent-child relationships between entities Introduces EntityResolver for dot-notation references Supports belongsTo configuration in grouping Implements flexible filtering across hierarchical entities Improves rendering flexibility for complex organizational structures
This commit is contained in:
parent
dd647acab8
commit
d4249eecfb
17 changed files with 403 additions and 44 deletions
|
|
@ -12,6 +12,7 @@ export class DateRenderer implements IRenderer {
|
|||
|
||||
// Render dates for HVER resource (eller 1 gang hvis ingen resources)
|
||||
const iterations = resourceIds.length || 1;
|
||||
let columnCount = 0;
|
||||
|
||||
for (let r = 0; r < iterations; r++) {
|
||||
const resourceId = resourceIds[r]; // undefined hvis ingen resources
|
||||
|
|
@ -46,7 +47,15 @@ export class DateRenderer implements IRenderer {
|
|||
}
|
||||
column.innerHTML = '<swp-events-layer></swp-events-layer>';
|
||||
context.columnContainer.appendChild(column);
|
||||
|
||||
columnCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set grid columns on container
|
||||
const container = context.columnContainer.closest('swp-calendar-container');
|
||||
if (container) {
|
||||
(container as HTMLElement).style.setProperty('--grid-columns', String(columnCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,36 @@ export class ResourceRenderer implements IRenderer {
|
|||
|
||||
async render(context: IRenderContext): Promise<void> {
|
||||
const resourceIds = context.filter['resource'] || [];
|
||||
const resources = await this.resourceService.getByIds(resourceIds);
|
||||
const dateCount = context.filter['date']?.length || 1;
|
||||
|
||||
for (const resource of resources) {
|
||||
// Determine render order based on parentChildMap
|
||||
// If parentChildMap exists, render resources grouped by parent (e.g., team)
|
||||
// Otherwise, render in filter order
|
||||
let orderedResourceIds: string[];
|
||||
|
||||
if (context.parentChildMap) {
|
||||
// Render resources in parent-child order
|
||||
orderedResourceIds = [];
|
||||
for (const childIds of Object.values(context.parentChildMap)) {
|
||||
for (const childId of childIds) {
|
||||
if (resourceIds.includes(childId)) {
|
||||
orderedResourceIds.push(childId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
orderedResourceIds = resourceIds;
|
||||
}
|
||||
|
||||
const resources = await this.resourceService.getByIds(orderedResourceIds);
|
||||
|
||||
// Create a map for quick lookup to preserve order
|
||||
const resourceMap = new Map(resources.map(r => [r.id, r]));
|
||||
|
||||
for (const resourceId of orderedResourceIds) {
|
||||
const resource = resourceMap.get(resourceId);
|
||||
if (!resource) continue;
|
||||
|
||||
const header = document.createElement('swp-resource-header');
|
||||
header.dataset.resourceId = resource.id;
|
||||
header.textContent = resource.displayName;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,31 @@
|
|||
import { IRenderer, IRenderContext } from '../../core/IGroupingRenderer';
|
||||
|
||||
interface Team {
|
||||
id: string;
|
||||
name: string;
|
||||
resourceIds: string[];
|
||||
}
|
||||
import { TeamService } from '../../storage/teams/TeamService';
|
||||
|
||||
export class TeamRenderer implements IRenderer {
|
||||
readonly type = 'team';
|
||||
|
||||
// Hardcoded data
|
||||
private teams: Team[] = [
|
||||
{ id: 'team1', name: 'Team Alpha', resourceIds: ['res1', 'res2'] },
|
||||
{ id: 'team2', name: 'Team Beta', resourceIds: ['res3'] }
|
||||
];
|
||||
constructor(private teamService: TeamService) {}
|
||||
|
||||
render(context: IRenderContext): void {
|
||||
const allowedIds = context.filter['team'] || [];
|
||||
const filteredTeams = this.teams.filter(t => allowedIds.includes(t.id));
|
||||
async render(context: IRenderContext): Promise<void> {
|
||||
const allowedIds = context.filter[this.type] || [];
|
||||
if (allowedIds.length === 0) return;
|
||||
|
||||
// Fetch teams from IndexedDB (only for name display)
|
||||
const teams = await this.teamService.getByIds(allowedIds);
|
||||
|
||||
const dateCount = context.filter['date']?.length || 1;
|
||||
const resourceIds = context.filter['resource'] || [];
|
||||
|
||||
// Render ALLE team headers først
|
||||
for (const team of filteredTeams) {
|
||||
// Tæl resources der tilhører dette team OG er i filter
|
||||
const teamResourceCount = team.resourceIds.filter(id => resourceIds.includes(id)).length;
|
||||
const colspan = teamResourceCount * dateCount;
|
||||
// Get child filter values using childType from context (not hardcoded)
|
||||
const childIds = context.childType ? context.filter[context.childType] || [] : [];
|
||||
|
||||
// Render team headers
|
||||
for (const team of teams) {
|
||||
// Get children from parentChildMap (resolved from belongsTo config)
|
||||
const teamChildIds = context.parentChildMap?.[team.id] || [];
|
||||
|
||||
// Count children that belong to this team AND are in the filter
|
||||
const childCount = teamChildIds.filter(id => childIds.includes(id)).length;
|
||||
const colspan = childCount * dateCount;
|
||||
|
||||
const header = document.createElement('swp-team-header');
|
||||
header.dataset.teamId = team.id;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue