Implements FilterTemplate system for event matching
Introduces flexible key-based filtering for calendar events across different view configurations Adds new FilterTemplate class to: - Define event matching rules based on view configuration - Support multi-level grouping (team/resource/date) - Handle dynamic key generation for columns and events Enhances view configuration with explicit id properties and derived fields
This commit is contained in:
parent
c2f7564f8e
commit
dd647acab8
8 changed files with 331 additions and 41 deletions
180
docs/filter-template.md
Normal file
180
docs/filter-template.md
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
# FilterTemplate System
|
||||
|
||||
## Problem
|
||||
|
||||
En kolonne har en unik nøgle baseret på view-konfigurationen (f.eks. team + resource + date).
|
||||
Events skal matches mod denne nøgle - men kun på de felter viewet definerer.
|
||||
|
||||
## Løsning: FilterTemplate
|
||||
|
||||
ViewConfig definerer hvilke felter (idProperties) der indgår i kolonnens nøgle.
|
||||
Samme template bruges til at bygge nøgle for både kolonne og event.
|
||||
|
||||
**Princip:** Kolonnens nøgle-template bestemmer hvad der matches på.
|
||||
|
||||
---
|
||||
|
||||
## ViewConfig med idProperty
|
||||
|
||||
ViewConfig er kilden til sandhed - den definerer grupper OG deres relations-id property.
|
||||
|
||||
```typescript
|
||||
interface GroupingConfig {
|
||||
type: string; // 'team', 'resource', 'date'
|
||||
values: string[]; // ['EMP001', 'EMP002']
|
||||
idProperty: string; // property-navn på event (eks. 'resourceId')
|
||||
derivedFrom?: string; // for date: udledes fra 'start'
|
||||
}
|
||||
```
|
||||
|
||||
### Eksempler
|
||||
|
||||
**Team → Resource → Date view:**
|
||||
```typescript
|
||||
{
|
||||
groupings: [
|
||||
{ type: 'team', values: ['team-a'], idProperty: 'teamId' },
|
||||
{ type: 'resource', values: ['EMP001', 'EMP002'], idProperty: 'resourceId' },
|
||||
{ type: 'date', values: ['2025-12-09', '2025-12-10'], idProperty: 'date', derivedFrom: 'start' }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Simple date-only view:**
|
||||
```typescript
|
||||
{
|
||||
groupings: [
|
||||
{ type: 'date', values: ['2025-12-09', '2025-12-10'], idProperty: 'date', derivedFrom: 'start' }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FilterTemplate Klasse
|
||||
|
||||
```typescript
|
||||
class FilterTemplate {
|
||||
private fields: Array<{
|
||||
idProperty: string;
|
||||
derivedFrom?: string;
|
||||
}> = [];
|
||||
|
||||
addField(idProperty: string, derivedFrom?: string): this {
|
||||
this.fields.push({ idProperty, derivedFrom });
|
||||
return this;
|
||||
}
|
||||
|
||||
buildKeyFromColumn(column: HTMLElement): string {
|
||||
return this.fields
|
||||
.map(f => column.dataset[f.idProperty] || '')
|
||||
.join(':');
|
||||
}
|
||||
|
||||
buildKeyFromEvent(event: ICalendarEvent, dateService: DateService): string {
|
||||
return this.fields
|
||||
.map(f => {
|
||||
if (f.derivedFrom) {
|
||||
return dateService.getDateKey((event as any)[f.derivedFrom]);
|
||||
}
|
||||
return (event as any)[f.idProperty] || '';
|
||||
})
|
||||
.join(':');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flow
|
||||
|
||||
```
|
||||
Orchestrator
|
||||
│
|
||||
├── Læs ViewConfig.groupings
|
||||
│
|
||||
├── Byg FilterTemplate fra groupings:
|
||||
│ for (grouping of viewConfig.groupings) {
|
||||
│ template.addField(grouping.idProperty, grouping.derivedFrom);
|
||||
│ }
|
||||
│
|
||||
├── Kør group-renderers (bygger headers + kolonner)
|
||||
│ └── DateRenderer sætter column.dataset[idProperty] for ALLE grupperinger
|
||||
│
|
||||
└── EventRenderer.render(ctx, template)
|
||||
│
|
||||
└── for each column:
|
||||
columnKey = template.buildKeyFromColumn(column)
|
||||
columnEvents = events.filter(e =>
|
||||
template.buildKeyFromEvent(e) === columnKey
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Eksempler
|
||||
|
||||
### 3-niveau view: Team → Resource → Date
|
||||
|
||||
**ViewConfig:**
|
||||
```typescript
|
||||
groupings: [
|
||||
{ type: 'team', values: ['team-a'], idProperty: 'teamId' },
|
||||
{ type: 'resource', values: ['EMP001'], idProperty: 'resourceId' },
|
||||
{ type: 'date', values: ['2025-12-09'], idProperty: 'date', derivedFrom: 'start' }
|
||||
]
|
||||
```
|
||||
|
||||
**Template:** `['teamId', 'resourceId', 'date']`
|
||||
|
||||
**Kolonne-nøgle:** `"team-a:EMP001:2025-12-09"`
|
||||
**Event-nøgle:** `"team-a:EMP001:2025-12-09"`
|
||||
|
||||
**Match!**
|
||||
|
||||
---
|
||||
|
||||
### 2-niveau view: Resource → Date
|
||||
|
||||
**ViewConfig:**
|
||||
```typescript
|
||||
groupings: [
|
||||
{ type: 'resource', values: ['EMP001'], idProperty: 'resourceId' },
|
||||
{ type: 'date', values: ['2025-12-09'], idProperty: 'date', derivedFrom: 'start' }
|
||||
]
|
||||
```
|
||||
|
||||
**Template:** `['resourceId', 'date']`
|
||||
|
||||
**Kolonne-nøgle:** `"EMP001:2025-12-09"`
|
||||
**Event-nøgle:** `"EMP001:2025-12-09"` (teamId ignoreres - ikke i template)
|
||||
|
||||
**Match!**
|
||||
|
||||
---
|
||||
|
||||
### 1-niveau view: Kun Date
|
||||
|
||||
**ViewConfig:**
|
||||
```typescript
|
||||
groupings: [
|
||||
{ type: 'date', values: ['2025-12-09'], idProperty: 'date', derivedFrom: 'start' }
|
||||
]
|
||||
```
|
||||
|
||||
**Template:** `['date']`
|
||||
|
||||
**Kolonne-nøgle:** `"2025-12-09"`
|
||||
**Event-nøgle:** `"2025-12-09"` (alle andre felter ignoreres)
|
||||
|
||||
**Match!** Samme event vises i alle views - kun de relevante felter indgår i matching.
|
||||
|
||||
---
|
||||
|
||||
## Kerneprincipper
|
||||
|
||||
1. **ViewConfig definerer nøgle-template** - hvilke idProperties der indgår
|
||||
2. **Samme template til kolonne og event** - sikrer konsistent matching
|
||||
3. **Felter udenfor template ignoreres** - event med ekstra felter matcher stadig
|
||||
4. **idProperty** - eksplicit mapping mellem gruppering og event-felt
|
||||
5. **derivedFrom** - håndterer felter der udledes (f.eks. date fra start)
|
||||
Loading…
Add table
Add a link
Reference in a new issue