Problemet: Uforutsigbar datadybde Ulike organisasjoner strukturerer operasjonene sine med forskjellig dybde og terminologi. Å hardkode brukergrensesnittet for én struktur var ikke praktisk; systemet måtte tilpasse seg vilkårlig nesting.
Hvert nivå kunne også bruke forskjellige felttyper og valideringsregler. Grensesnittet måtte rendre disse feltene dynamisk fra konfigurasjon.
Datamengdene var store nok til at rendering av alle rader samtidig ville svekke responsiviteten. Derfor måtte systemet utsette arbeid til brukeren åpnet eller nådde den relevante delen av hierarkiet.
Rekursiv komponentarkitektur Jeg designet en `ActivityRow`-komponent som rekursivt rendrer seg selv. Hver rad sjekker: 'Har jeg barn?' Hvis ja, render en nestet tabell med en annen `ActivityRow` for hvert barn. Hvis nei, render en bladnode. Denne rekursjonen fortsetter til dataene tar slutt, og håndterer naturlig enhver dybde.
Nøkkelen var ytelsesoptimalisering. Jeg implementerte en virtualiseringsstrategi hvor bare synlige rader er i DOM-en. Kollapsede rader rendrer en placeholder og utsetter rendering av barn til det er nødvendig.
Tilstandshåndtering var vanskelig. Jeg brukte Redux for å lagre tabelldataene i en normalisert struktur (aktiviteter lagret etter ID, ikke som nestede objekter). Dette tillot effektive oppdateringer - endring av en dyp nestet aktivitet krever bare oppdatering av én Redux-slice, ikke traversering av hele treet. Komponenttreet re-rendrer, men Reacts reconciliation håndterer det effektivt.
For UI-responsivitet implementerte jeg 'debounced' input-felter. Når en bruker skriver i en celle, oppdateres verdien umiddelbart i lokal tilstand (optimistisk UI), mens Redux-dispatch debounces med 300ms. Dette gjør at tabellen føles øyeblikkelig samtidig som det forhindrer Redux fra å behandle hundrevis av handlinger per sekund under rask skriving.
Brukerdefinerte skjemaer og forretningsregler For å gjøre verktøyet fleksibelt bygde jeg et konfigurerbart skjemalag som lar administratorer definere felttyper og valideringsregler uten å endre tabellkomponentene.
Dette skjemaet lagres som JSON og lastes ved app-initialisering. `ActivityRow`-komponenten leser skjemaet for sitt nåværende nivå og rendrer dynamisk de passende input-typene. Trenger du en dropdown? Skjemaet inkluderer alternativene. Trenger du en datoplukker? Skjemaet spesifiserer formatet.
Valideringslaget støtter regler som avhenger av andre felt og aktiviteter, samtidig som reglene holdes adskilt fra tabellens visningslogikk.
D3.js-visualiseringer: Dual-Axis-grafer Utover tabellen krevde systemet visualiseringer for å hjelpe operatører med å forstå fremdriften. Jeg bygde grafer som sammenligner planlagt og faktisk fremdrift på tvers av flere dimensjoner.
Utfordringen var å vise flere dataserier på samme graf uten å miste lesbarheten. Jeg brukte separate skalaer og interaktive legender slik at brukere kan fokusere på bestemte aspekter.
En annen visualisering viste forholdet mellom aktiviteter på forskjellige nivåer. Klikking på en node filtrerer tabellen til den aktiviteten og dens underordnede data.
PDF-eksport for rapportering Operasjonelle planer måtte også kunne deles som PDF-dokumenter. Jeg bygde et eksportsystem som konverterer tabellen og grafene til en multi-side PDF ved bruk av jsPDF.
Utfordringen var paginering. Tabellen kunne være vilkårlig stor og strekke seg over dusinvis av sider. Jeg implementerte et 'virtuelt side'-system som måler høyden på hver rad, beregner sideskift og deler tabellen over sider samtidig som hierarkiet bevares (en foreldrerekke og dens barn holdes sammen).
For grafer rendret jeg dem til Canvas med egnet oppløsning og bygde resultatet inn i PDF-en sammen med tabelldataene.