Componenti UI — dominio edu
🎯 Cosa fa
Sotto TrainingHub.BackOffice/Components/CRUD/edu/ vivono i
componenti Blazor CRUD auto-generati per le ~38 entità del dominio
formazione. Il pattern di generazione è lo stesso di inv e reg
(triade razor + razor.tt.cs + razor.cs + Forms/ + FormPopups/). Vedi
componenti UI inv per i dettagli.
Questa pagina documenta le particolarità edu-specifiche.
🗺️ Entità core in scope
| Entità | File | Note |
|---|---|---|
Category | Category.razor | Anagrafica semplice |
Course | Course.razor | Form ricco con cascade variante normativa |
Lesson | Lesson.razor | Anagrafica con durata |
LessonsCourse | LessonsCourse.razor | Associazione con metadata programma |
CourseSession | CourseSession.razor | Ciclo vita stati |
Appointment | Appointment.razor (grid CRUD) + Pages/AppointmentsCalendar/ (vista calendario page-level) | Doppia vista griglia + calendario |
Location | Location.razor | Aule con FK a reg.headquarters |
Teacher | Teacher.razor | Anagrafica docente |
AppointmentsTeacher | AppointmentsTeacher.razor | M:N con hourlyAmount |
TeacherCost | TeacherCost.razor | Costi per organizer |
TeacherSkill | TeacherSkill.razor | Competenze docente |
🧩 Pattern chiave edu-specifici
Vista calendario appuntamenti
Pages/AppointmentsCalendar/AppointmentsCalendar.razor (route
/appointments-calendar) è la vista calendario principale degli
appuntamenti, complementare alla griglia standard Appointment.razor.
Scritta a mano (non CRUD-generata). Sub-componenti:
CalendarGrid.razor— rendering mese/settimana/giorno.AppointmentDetailPanel.razor— pannello laterale con dettagli appuntamento + contesto sessione + azioni Edit/Duplica/Modifica sessione.
Caratteristiche principali (per dettaglio vedi panoramica edu — Vista calendario custom):
- Filtri Corso/Sede/Docente/Sessione con cascade Corso → Sessione.
- Colore appuntamento derivato da
trainingTopics.color(primo topic alfabetico della session). - Click slot apre
AppointmentFormPopup; pulsante "Nuova Sessione" apreSessionPlannerPopup. - Conflict detection via
ISessionPlannerService.DetectConflictsAsynccon toast warning post-save. - Query param
?teacherId=<guid>per landing dal teacher-calendar.
⚠️ Esiste ancora un legacy
CRUD/edu/AppointmentsCalendar.razorauto-generato: è la vecchia vista CRUD, mantenuta come placeholder finché i conf JSON non vengono ripuliti. Quella autoritativa è sottoPages/AppointmentsCalendar/.
Wizard pianificazione sessione
Components/edu/SessionPlanner/SessionPlannerPopup.razor è un
wizard 6-step per pianificare una sessione formativa
end-to-end. Le partial class SessionPlannerPopup.Step1Session.cs
… Step6Review.cs contengono la logica per-step.
Il backend è ISessionPlannerService (in Shared/Services/SessionPlanner/)
con stato persistito su SessionPlannerState + SessionCoursePlan[].
Step:
- Sessione — data inizio + argomento opzionale (filtra corsi).
- Corsi — aggiunge uno o più corsi in co-erogazione con finestre orarie per-corso.
- Date e sedi — appuntamenti fisici e sede.
- Docenti — assegnazione con "Suggerisci docenti per skill"
(filtro su
teacherSkillsdel corso). - Iscritti — aggiunta workers con scelta del corso di destinazione; integrazione con coda richieste e scadenziario.
- Riepilogo costi — stima Iscrizioni + Docenze + Aule prima del confirm finale.
Punti d'ingresso: lista corsi, lista sessioni, coda richieste, scadenziario, scheda lavoratore, calendario (pulsante "Nuova Sessione").
Vista dati aggregati
AppointmentsData.razor fornisce una vista di dati aggregati per
analisi (totale ore per docente, saturazione aule, ecc.), distinta
dal CRUD. Non è un CRUD: è una pagina di reportistica.
Componenti analitici cross-dominio
ActiveWorker.razor— vista lavoratori attivi (incrocia reg + edu)AllCompletion.razor— completamenti aggregatiAllRequiredTraining.razor— formazione obbligatoria per lavoratore
Questi componenti non sono CRUD generati: sono viste analitiche
custom che consumano dati edu + job + reg. Tecnicamente violano la
separazione per dominio (stanno in CRUD/edu/ ma toccano altri
domini).
Cascade variante normativa in Course
Il form CourseForm.razor ha un combobox Variante normativa che,
al cambio, pre-popola campi come durata minima e obblighi (logica nel
.razor.cs). Pattern simile al cascade ATECO → riskLevel del form
aziende.
Location con indirizzo inline e FK a reg.companies
Il form LocationForm.razor espone i campi indirizzo direttamente
sull'aula (formattedAddress + geocoded country/province/city/zipCode/address/streetNumber/latitude/longitude)
e un combobox opzionale companyId per il gestore aula (azienda
proprietaria, NULL = aula 3SD). Cross-dominio: edu consuma reg per le
aziende gestrici.
Suggerimento docenti per skill
Il filtro per competenza non vive più sul form
AppointmentForm.razor (l'appuntamento non ha più una lezione
associata): lo step "Docenti" del wizard
SessionPlannerPopup.Step4Teachers usa il pulsante
"Suggerisci docenti per skill" che incrocia
edu.teacherSkills.trainingVariantId con le varianti dei corsi
erogati nella sessione (trainingSessionsCourses → courses → trainingVariantId).
📁 File chiave
Components/CRUD/edu/Course.razor.cs— code-behind principaleComponents/CRUD/edu/Forms/CourseForm.razor— form con cascade varianteComponents/Pages/AppointmentsCalendar/— vista calendario page-level (AppointmentsCalendar.razor,CalendarGrid.razor,AppointmentDetailPanel.razor)Components/edu/SessionPlanner/— wizard 6-step pianificazione sessione (SessionPlannerPopup.razor+ Step1..Step6.cs)Components/CRUD/edu/AppointmentsData.razor— vista dati aggregatiComponents/CRUD/edu/ActiveWorker.razor,AllCompletion.razor,AllRequiredTraining.razor— viste cross-dominioComponents/CRUD/edu/_conf/*.dxgrid.conf.json— configurazione
🔌 Estensione tipica
Segue il pattern generale (vedi
componenti UI inv). Specificità edu:
- Aggiungere un campo a
Course. Rigenera + valuta se il cascade variante va aggiornato per precompilare anche il nuovo campo. - Nuova vista analitica cross-dominio. Aggiungi una nuova pagina
Razor non-CRUD in
CRUD/edu/(es.MyAnalytics.razor), inject i service necessari. Non serveconf.json. Routing dichiarato con@pagedirettiva. - Estendere vista calendario. I file in
Pages/AppointmentsCalendar/sono scritti a mano — non CRUD generato. Modifiche dirette senza rigenerazione. Per aggiungere un filtro nuovo: aggiungi il combobox inAppointmentsCalendar.razor, il backing field nel code-behind, e passa il valore aIAppointmentsCalendarService.GetAppointmentsAsync.
⚠️ Debito tecnico
- Cross-dominio in
CRUD/edu/.ActiveWorker,AllCompletion,AllRequiredTrainingvivono in CRUD edu ma aggregano dati reg/job/edu. Valutare spostamento in cartella dedicataCRUD/analytics/o simile. -
AppointmentsCalendarsenza test UI. Componente complesso custom, non coperto da test automatici. - Duplicazione calendario CRUD vs Pages. Esistono ancora
CRUD/edu/AppointmentsCalendar.razor(legacy CRUD-generato) ePages/AppointmentsCalendar/AppointmentsCalendar.razor(autoritativo page-level). La legacy va droppata quando i conf JSON CRUD vengono ripuliti (vedi BACKLOG.md "Drop partial classes alias"). -
Filtro docenti per competenza. Coperto dallo step 4 delSessionPlannerPopup("Suggerisci docenti per skill") che usa la skill matrixedu.teacherSkills.
🔗 Vedi anche
- Panoramica dominio
- Schema DB
- Logica applicativa
- Dominio
inv: componenti UI — pattern CRUD base