Эх сурвалжийг харах

Working on ORM refactoring

Andrea Fazzi 5 жил өмнө
parent
commit
868698449c

+ 2 - 0
main.go

@@ -38,6 +38,8 @@ var (
 		&orm.Class{},
 		&orm.Student{},
 		&orm.Activity{},
+		&orm.Office{},
+		&orm.Administrative{},
 	}
 )
 

+ 10 - 1
orm/activity.go

@@ -167,6 +167,9 @@ func (a *Activity) Update(args map[string]string, r *http.Request) (interface{},
 		if err != nil {
 			return nil, err
 		}
+
+		activity.(*Activity).GroupActivity = false
+
 		err = renderer.Decode(activity, r)
 		if err != nil {
 			return nil, err
@@ -196,7 +199,13 @@ func (a *Activity) Delete(args map[string]string, r *http.Request) (interface{},
 }
 
 func SaveActivity(activity interface{}) (interface{}, error) {
-	if err := DB().Save(activity).Error; err != nil {
+	if err := DB().Omit(
+		"Class",
+		"Teacher",
+		"Subject",
+		"SupplyTeacher",
+		"Student",
+	).Save(activity).Error; err != nil {
 		return nil, err
 	}
 	return activity, nil

+ 63 - 87
orm/administrative.go

@@ -13,30 +13,37 @@ type Administrative struct {
 	Office *Office
 
 	OfficeID uint `schema:"office_id"`
-}
 
-type AdministrativeForUpdate struct {
-	Administrative Administrative
 	AllOffices     []*Office
-
-	SelectedOffice map[uint]string
+	SelectedOffice map[uint]string `gorm:"-"`
 }
 
-type AdministrativeForAdd struct {
-	AllOffices []*Office
-}
+func (s *Administrative) GetID() uint    { return s.ID }
+func (a *Administrative) String() string { return a.CompleteName() }
 
-func (s *Administrative) GetID() uint { return s.ID }
+func (a *Administrative) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		administrative := new(Administrative)
+		if err := DB().Find(&administrative.AllOffices).Error; err != nil {
+			return nil, err
+		}
+		return administrative, nil
+	} else {
+		administrative := new(Administrative)
+		err := renderer.Decode(administrative, r)
+		if err != nil {
+			return nil, err
+		}
+		administrative, err = CreateAdministrative(administrative)
+		if err != nil {
+			return nil, err
+		}
 
-func GetAdministrative(args map[string]string) (interface{}, error) {
-	var administrative Administrative
-	if err := DB().First(&administrative, args["id"]).Error; err != nil {
-		return nil, err
+		return administrative, nil
 	}
-	return &administrative, nil
 }
 
-func GetAdministrativeAll(args map[string]string) (interface{}, error) {
+func (a *Administrative) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var administrative Administrative
 
 	id := args["id"]
@@ -48,74 +55,58 @@ func GetAdministrativeAll(args map[string]string) (interface{}, error) {
 	return &administrative, nil
 }
 
-func GetAdministratives(args map[string]string) (interface{}, error) {
+func (a *Administrative) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var administratives []*Administrative
-	if err := DB().Order("surname,name").Find(&administratives).Error; err != nil {
-		return nil, err
-	}
-	return administratives, nil
-}
 
-func GetAdministrativesAll(args map[string]string) (interface{}, error) {
-	var administratives []*Administrative
 	if err := DB().Preload("Office").Order("surname,name").Find(&administratives).Error; err != nil {
 		return nil, err
 	}
+
 	return administratives, nil
 }
 
-func SaveAdministrative(administrative interface{}) (interface{}, error) {
-	if err := DB().Omit("Office").Save(administrative).Error; err != nil {
-		return nil, err
-	}
-	return administrative, nil
-}
+func (a *Administrative) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := a.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-func UpdateAdministrative(args map[string]string, r *http.Request) (IDer, error) {
-	administrative, err := GetAdministrative(args)
-	if err != nil {
-		return nil, err
-	}
+		administrative := result.(*Administrative)
 
-	err = renderer.Decode(administrative, r)
-	if err != nil {
-		return nil, err
-	}
+		if err := DB().Find(&administrative.AllOffices).Error; err != nil {
+			return nil, err
+		}
 
-	_, err = SaveAdministrative(administrative)
-	if err != nil {
-		return nil, err
-	}
-	administrative, err = GetAdministrative(args)
-	if err != nil {
-		return nil, err
-	}
-	return administrative.(*Administrative), nil
-}
+		administrative.SelectedOffice = make(map[uint]string)
+		administrative.SelectedOffice[administrative.OfficeID] = "selected"
 
-func AddAdministrative(args map[string]string, r *http.Request) (IDer, error) {
-	administrative := new(Administrative)
-	err := renderer.Decode(administrative, r)
-	if err != nil {
-		return nil, err
-	}
-	administrative, err = CreateAdministrative(administrative)
-	if err != nil {
-		return nil, err
-	}
+		return administrative, nil
+	} else {
+		administrative, err := a.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-	return administrative, nil
-}
+		err = renderer.Decode(administrative, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveAdministrative(administrative)
+		if err != nil {
+			return nil, err
+		}
+		administrative, err = a.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-func CreateAdministrative(administrative *Administrative) (*Administrative, error) {
-	if err := DB().Create(administrative).Error; err != nil {
-		return nil, err
+		return administrative.(*Administrative), nil
 	}
-	return administrative, nil
 }
 
-func DeleteAdministrative(args map[string]string, r *http.Request) (IDer, error) {
-	administrative, err := GetAdministrative(args)
+func (a *Administrative) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	administrative, err := a.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
@@ -125,33 +116,18 @@ func DeleteAdministrative(args map[string]string, r *http.Request) (IDer, error)
 	return administrative.(*Administrative), nil
 }
 
-func GetAdministrativeForUpdate(args map[string]string) (interface{}, error) {
-	var data AdministrativeForUpdate
-
-	id := args["id"]
-
-	if err := DB().Preload("Office").First(&data.Administrative, id).Error; err != nil {
-		return nil, err
-	}
-
-	if err := DB().Find(&data.AllOffices).Error; err != nil {
+func SaveAdministrative(administrative interface{}) (interface{}, error) {
+	if err := DB().Omit("Office").Save(administrative).Error; err != nil {
 		return nil, err
 	}
-
-	data.SelectedOffice = make(map[uint]string)
-	data.SelectedOffice[data.Administrative.OfficeID] = "selected"
-
-	return data, nil
+	return administrative, nil
 }
 
-func GetAdministrativeForAdd(args map[string]string) (interface{}, error) {
-	var data AdministrativeForAdd
-
-	if err := DB().Find(&data.AllOffices).Error; err != nil {
+func CreateAdministrative(administrative *Administrative) (*Administrative, error) {
+	if err := DB().Create(administrative).Error; err != nil {
 		return nil, err
 	}
-
-	return data, nil
+	return administrative, nil
 }
 
 func (s *Administrative) CompleteName() string {

+ 55 - 90
orm/office.go

@@ -16,23 +16,31 @@ type Office struct {
 	Administratives []*Administrative
 }
 
-type OfficeForUpdate struct {
-	Office Office
-}
-
-type OfficeForAdd struct{}
-
 func (d *Office) GetID() uint { return d.ID }
 
-func GetOffice(args map[string]string) (interface{}, error) {
-	var office Office
-	if err := DB().First(&office, args["id"]).Error; err != nil {
-		return nil, err
+func (o *Office) String() string {
+	return o.Name
+}
+
+func (o *Office) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		return nil, nil
+	} else {
+		office := new(Office)
+		err := renderer.Decode(office, r)
+		if err != nil {
+			return nil, err
+		}
+		office, err = CreateOffice(office)
+		if err != nil {
+			return nil, err
+		}
+
+		return office, nil
 	}
-	return &office, nil
 }
 
-func GetOfficeAll(args map[string]string) (interface{}, error) {
+func (o *Office) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var office Office
 
 	id := args["id"]
@@ -40,67 +48,64 @@ func GetOfficeAll(args map[string]string) (interface{}, error) {
 	if err := DB().Preload("Administratives").Where("id = ?", id).Find(&office).Error; err != nil {
 		return nil, err
 	}
-
 	return &office, nil
 }
 
-func GetOffices(args map[string]string) (interface{}, error) {
-	var offices []*Office
-	if err := DB().Order("name").Find(&offices).Error; err != nil {
-		return nil, err
-	}
-	return offices, nil
-}
-
-func GetOfficesAll(args map[string]string) (interface{}, error) {
+func (o *Office) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var offices []*Office
 	if err := DB().Preload("Administratives").Order("name").Find(&offices).Error; err != nil {
 		return nil, err
 	}
-	// for _, office := range offices {
-	// 	office.GetAdministratives()
-	// }
 	return offices, nil
 }
 
-func SaveOffice(office interface{}) (interface{}, error) {
-	if err := DB().Omit("Administratives").Save(office).Error; err != nil {
-		return nil, err
+func (o *Office) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		office := result.(*Office)
+
+		return office, nil
+	} else {
+		office, err := o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		err = renderer.Decode(office, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveOffice(office)
+		if err != nil {
+			return nil, err
+		}
+		office, err = o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		return office.(*Office), nil
 	}
-	return office, nil
 }
 
-func UpdateOffice(args map[string]string, r *http.Request) (IDer, error) {
-	office, err := GetOffice(args)
-	if err != nil {
-		return nil, err
-	}
-	err = renderer.Decode(office, r)
-	if err != nil {
-		return nil, err
-	}
-	_, err = SaveOffice(office)
+func (o *Office) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	office, err := o.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
-	office, err = GetOffice(args)
-	if err != nil {
+	if err := DB().Unscoped().Delete(office.(*Office)).Error; err != nil {
 		return nil, err
 	}
 	return office.(*Office), nil
 }
 
-func AddOffice(args map[string]string, r *http.Request) (IDer, error) {
-	office := new(Office)
-	err := renderer.Decode(office, r)
-	if err != nil {
-		return nil, err
-	}
-	office, err = CreateOffice(office)
-	if err != nil {
+func SaveOffice(office interface{}) (interface{}, error) {
+	if err := DB().Omit("Administratives").Save(office).Error; err != nil {
 		return nil, err
 	}
-
 	return office, nil
 }
 
@@ -110,43 +115,3 @@ func CreateOffice(office *Office) (*Office, error) {
 	}
 	return office, nil
 }
-
-func DeleteOffice(args map[string]string, r *http.Request) (IDer, error) {
-	office, err := GetOffice(args)
-	if err != nil {
-		return nil, err
-	}
-	if err := DB().Unscoped().Delete(office.(*Office)).Error; err != nil {
-		return nil, err
-	}
-	return office.(*Office), nil
-}
-
-func GetOfficeForAdd(args map[string]string) (interface{}, error) {
-	var data OfficeForAdd
-
-	// if err := DB().Find(&data.AllTeachers).Error; err != nil {
-	// 	return nil, err
-	// }
-
-	return data, nil
-}
-
-func GetOfficeForUpdate(args map[string]string) (interface{}, error) {
-	var data OfficeForUpdate
-
-	id := args["id"]
-
-	if err := DB().First(&data.Office, id).Error; err != nil {
-		return nil, err
-	}
-
-	return data, nil
-}
-
-// func (t *Office) GetAdministratives() ([]*Administrative, error) {
-// 	if err := DB().Raw(selectUniqueOfficeTeachers, t.ID).Scan(&t.Teachers).Error; err != nil {
-// 		return nil, err
-// 	}
-// 	return t.Teachers, nil
-// }

+ 51 - 161
templates/activities_add_update.html.tpl

@@ -2,171 +2,61 @@
 
 <div class="container">
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/activities?{{query "tpl_layout" "base" "tpl_content" "activities"}}">Attività</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna l'attività</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/activities?{{query "tpl_layout" "base" "tpl_content" "activities"}}">Attività</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Aggiorna l'attività</h1>
-      </div>
-      <div class="col-md-4">
-	<a href="/activities/{{.Data.Activity.ID}}/delete"
-	   data-url="/activities/{{.Data.Activity.ID}}/delete"
-	   class="btn btn-danger karmen-ajax-delete float-right">
-	  <span class="fa fa-trash" aria-hidden="true"></span>
-	  Elimina
-	</a>
-      </div>
-    </div>
-  </div>
-  
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Attività" (all "Activity") (.Data|string) (.Data.ID|show "Activity") "Aggiorna" "current"}}
   {{else}}
-  <h1 class="karmen-info-header">Crea una nuova attività</h1>
+  {{template "breadcrumb" toSlice "Attività" (all "Activity") "Aggiungi" "current"}}
   {{end}}
-
-  {{if .Options.Get "update"}}
-  <form id="form_activities_add_update" action="/activities/{{.Data.Activity.ID}}/update" method="POST" role="form" class="needs-validation">
-  {{else}}
-  <form id="form_activities_add_update" action="/activities/add/" method="POST" role="form" class="needs-validation">
-  {{end}}
-   
-    <div class="form-group">
-      <label class="control-label" for="subject_id">Materia</label>
-      <select name="subject_id" class="form-control selectpicker" id="subject_id" placeholder="Materia" data-live-search="true" form="form_activities_add_update" title="Seleziona il nome della materia" data-dropup-auto="false" required>
-	<option value="0"></option>
-  	{{range $subject := .Data.AllSubjects}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$subject.ID}}"
-	   {{index $.Data.SelectedSubject $subject.ID}}>{{$subject.Name}}
-	</option>
-	{{else}}
-  	<option value="{{$subject.ID}}">{{$subject.Name}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-    
-    <div class="form-group">
-      <label class="control-label" for="class_id">Classe</label>
-      <select name="class_id" class="form-control selectpicker" id="class_id" placeholder="Classe" data-live-search="true" form="form_activities_add_update" title="Seleziona la classe" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $class := .Data.AllClasses}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$class.ID}}"
-	   {{index $.Data.SelectedClass $class.ID}}>{{$class.Name}}
-	</option>
-	{{else}}
-  	<option value="{{$class.ID}}">{{$class.Name}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="student_id">Studente</label>
-      <select name="student_id" class="form-control selectpicker" id="student_id" placeholder="Docente" data-live-search="true" form="form_activities_add_update" title="Seleziona il nome del docente" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $student := .Data.AllStudents}}
-	{{if $.Options.Get "update"}}
-  	<option
-	  value="{{$student.ID}}"
-	  {{index $.Data.SelectedStudent $student.ID}}>{{$student.Name}} {{$student.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$student.ID}}">{{$student.Name}} {{$student.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="teacher_id">Docente</label>
-      <select name="teacher_id" class="form-control selectpicker" id="teacher_id" placeholder="Docente" data-live-search="true" form="form_activities_add_update" title="Seleziona il nome del docente" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $teacher := .Data.AllTeachers}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$teacher.ID}}"
-	   {{index $.Data.SelectedTeacher $teacher.ID}}>{{$teacher.Name}} {{$teacher.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$teacher.ID}}">{{$teacher.Name}} {{$teacher.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="supply_teacher_id">Docente supplente</label>
-      <select name="supply_teacher_id" class="form-control selectpicker" id="supply_teacher_id" placeholder="Docente supplente" data-live-search="true" form="form_activities_add_update" title="Seleziona il nome del docente supplente" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $supplyTeacher := .Data.AllTeachers}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$supplyTeacher.ID}}"
-	   {{index $.Data.SelectedSupplyTeacher $supplyTeacher.ID}}>{{$supplyTeacher.Name}} {{$supplyTeacher.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$supplyTeacher.ID}}">{{$supplyTeacher.Name}} {{$supplyTeacher.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-
-    <div class="form-group">
-      <label class="control-label" for="hours">Numero di ore</label>
-      <input class="form-control" min="0" type="number" name="hours" id="hours" {{if .Options.Get "update"}}value="{{.Data.Activity.Hours}}"{{end}} required>
-    </div>
-
-    
-    <div class="form-group">
-      <div class="form-check">
-        <input type="checkbox" name="GroupActivity" class="form-check-input" id="activity_group_activity" {{if .Options.Get "update"}}{{if .Data.Activity.GroupActivity}}checked{{end}}{{end}}>
-        <label class="form-check-label" for="activity_group_activity">Attività di gruppo</label>
-        <small id="activity_group_help_box" class="form-text text-muted">
-          Spuntare la casella sopra nel caso di attività che coinvolgono più studenti contemporaneamente.
-        </small>
-      </div>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="group_activity_hours">Numero di ore dell'attività di gruppo</label>
-      <input class="form-control" min="0" type="number" name="group_activity_hours" id="group_activity_hours" {{if .Options.Get "update"}}value="{{.Data.Activity.GroupActivityHours}}"{{end}}>
-      <small id="activity_group_hours_help_box" class="form-text text-muted">
-        Indicare il numero totale di ore che il docente spende nell'attività di gruppo.
-      </small>        
-    </div>
-
-
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/activities/{{.Data.Activity.ID}}?{{query "tpl_layout" "base" "tpl_content" "activities_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/activities?{{query "tpl_layout" "base" "tpl_content" "activities"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
-    
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuova attività" "updateTitle" (printf "Aggiorna attività %s" (.Data|string))}}
+
+  {{$form := "form_activities_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Activity"}}{{else}}{{create "Activity"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
+
+    {{$options := ` { name: "subject_id", id: "subject_id", label: "Materia", title: "Seleziona la materia"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllSubjects") "selected" (.Data|field "SelectedSubject") "update" $update "form" $form}}
+
+    {{$options := ` { name: "class_id", id: "class_id", label: "Classe", title: "Seleziona la classe"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllClasses") "selected" (.Data|field "SelectedClass") "update" $update "form" $form}}
+
+    {{$options := ` { name: "teacher_id", id: "teacher_id", label: "Docente", title: "Seleziona il docente"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedTeacher") "update" $update "form" $form}}
+
+    {{$options := ` { name: "supply_teacher_id", id: "supply_teacher_id", label: "Docente supplente", title: "Seleziona il docente"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedSupplyTeacher") "update" $update "form" $form}}
+
+    {{$options := ` { name: "Hours",id: "hours",label: "Numero di ore",type: "number",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
+
+    {{$options := `
+    name: "GroupActivity"
+    id: "group_activity"
+    label: "Attività di gruppo"
+    formClass: "form-group form-check"
+    help: "Spuntare la casella sopra nel caso di attività che coinvolgono più studenti contemporaneamente."
+    `}}
+    {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "GroupActivity") "update" $update}}
+
+    {{$options := `
+    name: "group_activity_hours"
+    id: "group_activity_hours"
+    label: "Numero di ore dell'attività di gruppo"
+    type: "number"
+    help: "Indicare il numero totale di ore che il docente spende nell'attività di gruppo."
+    `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
+
+    {{$options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Activity"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}  
   </form>
-
+  
 </div>
 
 {{ end }}

+ 16 - 32
templates/administratives.html.tpl

@@ -2,47 +2,31 @@
 
 <div class="container">
   
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Amministrativi ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<a href="/administratives/add/?{{query "tpl_layout" "base" "tpl_content" "administratives_add_update"}}" class="btn btn-primary float-right">
-	  <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	  Crea nuovo amministrativo
-	</a>
-      </div>
-    </div>
-  </div>
-
-  <div class="input-group" style="margin-bottom: 20px">
-    <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-    <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-  </div>
+  {{$options := `
+  title: "Personale ATA"
+  buttonTitle: "Crea nuovo ATA"
+  `}}
   
-  {{if not .Data}}
-  <p>Non c'è alcun elemento da visualizzare</p>
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Administrative")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
   {{else}}
   <div class="list-group" id="myUL">
     {{range $administrative := .Data}}
-    <a class="list-group-item list-group-item-action" href="/administratives/{{$administrative.ID}}?{{query "tpl_layout" "base" "tpl_content" "administratives_show"}}">
+    <a class="list-group-item list-group-item-action" href={{$administrative.ID|show "Administrative"}}>
       <span class="fa fa-user"></span>
-      {{$administrative.Surname}} {{$administrative.Name}}
+      {{$administrative|string}}
       <div class="text-right">
-	{{if $administrative.Office}}
-	<small>{{$administrative.Office.Name}}</small>
-	{{else}}
-	<small>nessun ufficio</small>
-	{{end}}
-        {{if $administrative.InternalTelephoneNumber}}
-	<small>Interno {{$administrative.InternalTelephoneNumber}}</small>
-	{{end}}
+        {{$options := `noElements: "nessun ufficio"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $administrative.Office}}
       </div>
     </a>
     {{end}}
+    {{end}}
   </div>
-  {{end}}
+
 </div>
-  
+
 {{ end }}

+ 35 - 94
templates/administratives_add_update.html.tpl

@@ -2,125 +2,66 @@
 
 <div class="container">
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/administratives?{{query "tpl_layout" "base" "tpl_content" "administratives"}}">Amministrativi</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna amministrativo</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/administratives?{{query "tpl_layout" "base" "tpl_content" "administratives"}}">Amministrativi</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
- {{if .Options.Get "update"}}
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Aggiorna amministrativo</h1>
-      </div>
-    </div>
-  </div>
-  
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Docenti" (all "Administrative") (.Data|string) (.Data.ID|show "Administrative") "Aggiorna" "current"}}
   {{else}}
-  <h1 class="karmen-info-header">Crea nuovo amministrativo</h1>
+  {{template "breadcrumb" toSlice "Docenti" (all "Administrative") "Aggiungi" "current"}}
   {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo docente" "updateTitle" (printf "Aggiorna docente %s" (.Data|string))}}
 
-  {{if .Options.Get "update"}}
-  <form id="form_administratives_add_update" action="/administratives/{{.Data.Administrative.ID}}/update" method="POST" role="form" class="needs-validation">
-  {{else}}
-  <form id="form_administratives_add_update" action="/administratives/add/" method="POST" role="form" class="needs-validation">
-  {{end}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Administrative"}}{{else}}{{create "Administrative"}}{{end}}" method="POST" role="form">
 
-    <div class="form-group">
-      <label class="control-label" for="administrative_name">Nome</label>
-      <input type="text" name="Name" class="form-control" id="administrative_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Administrative.Name}}" {{end}} required>
-    </div>
+    {{$options := ` { name: "Name",id: "administrative_name",label: "Nome",placeholder: "Nome",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
+    
+    {{$options := ` { name: "Surname",id: "administrative_surname",label: "Cognome",placeholder: "Cognome",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Surname") "update" $update}}
 
-    <div class="form-group">
-      <label class="control-label" for="administrative_surname">Cognome</label>
-      <input type="text" name="Surname" class="form-control" id="administrative_surname" placeholder="Cognome" {{if .Options.Get "update"}} value="{{.Data.Administrative.Surname}}" {{end}} required>
-    </div>
+    {{$options := ` { name: "Hours",id: "administrative_hours",label: "Numero di ore",placeholder: "",type: "number" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
 
-    <div class="form-group">
-      <label class="control-label" for="administrative_internal_telephone">Telefono (interno)</label>
-      <input type="text" name="InternalTelephoneNumber" class="form-control" id="administrative_internal_telephone_number" placeholder="Numero di telefono (interno)" {{if .Options.Get "update"}} value="{{.Data.Administrative.InternalTelephoneNumber}}" {{end}}>
-    </div>
+    {{$options := ` { name: "AltEmail",id: "administrative_altemail",label: "Email alternativa",placeholder: "Inserire indirizzo email",type: "email" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "AltEmail") "update" $update}}
 
     <div class="form-row">
       <div class="col">
-	<input type="email" name="AltEmail" class="form-control" id="administrative_altemail" placeholder="Email alternativa" {{if .Options.Get "update"}} value="{{.Data.Administrative.AltEmail}}" {{end}}>
+        {{$options := ` { name: "Regenerate",id: "administrative_regenerate",label: "Rigenerare/inviare le credenziali",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "Regenerate") "update" $update}}
       </div>
       <div class="col">
-	<div class="form-check">
-	  <input type="checkbox" name="Regenerate" class="form-check-input" id="administrative_regenerate" {{if .Options.Get "update"}}{{if .Data.Administrative.Regenerate}}checked{{end}}{{end}}>
-	  <label class="form-check-label has-feedback" for="administrative_regenerate">Rigenerare/inviare le credenziali</label>
-	</div>
+        {{$options := ` { name: "Exclude",id: "administrative_exclude",label: "Escludere dalle utenze",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "Exclude") "update" $update}}
       </div>
       <div class="col">
-	<div class="form-check">
-	  <input type="checkbox" name="Exclude" class="form-check-input" id="administrative_exclude" {{if .Options.Get "update"}}{{if .Data.Administrative.Exclude}}checked{{end}}{{end}}>
-	  <label class="form-check-label has-feedback" for="administrative_exclude">Escludere dalle utenze</label>
-	</div>
-      </div>
-    </div>
-    <div class="col">
-      <div class="form-check">
-	<input type="checkbox" name="NotInvited" class="form-check-input" id="administrative_not_invited" {{if .Options.Get "update"}}{{if .Data.Administrative.NotInvited}}checked{{end}}{{end}}>
-	<label class="form-check-label has-feedback" for="administrative_not_invited">Escludere dagli inviti</label>
+        {{$options := ` { name: "NotInvited",id: "administrative_not_invited",label: "Escludere dagli inviti",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "NotInvited") "update" $update}}
       </div>
     </div>
 
-    
     <div class="form-row">
       <div class="col">
-	<label class="control-label" for="administrative_date_from">In servizio dal</label>
-	<input type="date" name="DateFrom" class="form-control" id="administrative_date_from" {{if .Options.Get "update"}} value="{{convertDate .Data.Administrative.DateFrom}}" {{end}}>
+        {{$options := ` { name: "DateFrom",id: "administrative_date_from",label: "In servizio dal",type: "date" } `}}
+        {{template "input" dict "options" ($options|yaml) "value" (.Data|field "DateFrom"|convertDate) "update" $update}}
       </div>
       <div class="col">
-	<label class="control-label" for="administrative_date_to">In servizio fino al</label>
-	<input type="date" name="DateTo" class="form-control" id="administrative_date_to" {{if .Options.Get "update"}} value="{{convertDate .Data.Administrative.DateTo}}" {{end}}>
+        {{$options := ` { name: "DateTo",id: "administrative_date_to",label: "In servizio fino al",type: "date" } `}}
+        {{template "input" dict "options" ($options|yaml) "value" (.Data|field "DateTo"|convertDate) "update" $update}}
       </div>
     </div>
-
-    <div class="form-group">
-      <label class="control-label" for="office_id">Associato all'ufficio</label>
-      <select name="office_id" class="form-control selectpicker" id="office_id" placeholder="Seleziona l'ufficio" data-live-search="true" form="form_administratives_add_update" title="Seleziona l'ufficio" data-dropup-auto="false">
-    	<option value="0"></option>
-    	{{range $office := .Data.AllOffices}}
-    	{{if $.Options.Get "update"}}
-    	<option
-    	  value="{{$office.ID}}"
-    	  {{index $.Data.SelectedOffice $office.ID}}>{{$office.Name}}
-    	</option>
-    	{{else}}
-    	<option value="{{$office.ID}}">{{$office.Name}}</option>
-    	{{end}}
-    	{{end}}
-      </select>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label has-feedback" for="administrative_ldapdnfmt">Stringa DN per LDAP</label>
-      <input type="text" name="LdapDNFmt" class="form-control" id="administrative_ldapdnfmt" placeholder="cn=%s %s,ou=People,dc=foo,dc=org" {{if .Options.Get "update"}}value="{{.Data.Administrative.LdapDNFmt}}"{{end}}>
-    </div>
-
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/administratives/{{.Data.Administrative.ID}}?{{query "tpl_layout" "base" "tpl_content" "administratives_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/administratives?{{query "tpl_layout" "base" "tpl_content" "administratives"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
     
-  </form>
+    {{$options := ` { name: "LdapDNFmt",id: "administrative_ldapfnfmt",label: "Stringa DN per LDAP",placeholder: "cn=%s %s,ou=People,dc=foo,dc=org",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "LdapDNFmt") "update" $update}}
 
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Administrative"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}
+  
+  </form>
+  
 </div>
 
 {{ end }}

+ 16 - 61
templates/administratives_show.html.tpl

@@ -2,67 +2,22 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/administratives?{{query "tpl_layout" "base" "tpl_content" "administratives"}}">Amministrativi</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Surname}} {{.Data.Name}}</a></li>
-    </ol>
-  </nav>
-
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>{{.Data.Surname}} {{.Data.Name}}</h1>
-      </div>
-      <div class="col-md-4">
-
-	<div class="btn-group float-right" role="group">
-	  <a href="/administratives/add/?{{query "tpl_layout" "base" "tpl_content" "administratives_add_update"}}" class="btn btn-success">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Crea
-	  </a>
-
-	  <a href="/administratives/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "administratives_add_update" "update" "true"}}"  class="btn btn-primary">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/administratives/{{.Data.ID}}/delete"
-		  data-url="/administratives/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-	    <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
-
-      </div>
-    </div>
-  </div>
-
-  <div class="row">
-    <div class="col-md-12">
-      <h2 class="karmen-relation-header">Informazioni sull'amministrativo</h2>
-      {{if .Data.Office}}
-      <p>
-        L'amministrativo è associato con l'ufficio <a href="/offices/{{.Data.Office.ID}}?{{query "tpl_layout" "base" "tpl_content" "offices_show"}}">{{.Data.Office.Name}}</a>.
-      </p>
-      {{else}}
-      <p>Nessun ufficio associato all'amministrativo</p>
-      {{end}}
-
-      {{if .Data.InternalTelephoneNumber}}
-      <p>Il numero di telefono dell'amministrativo è {{.Data.InternalTelephoneNumber}}.</p>
-      {{else}}
-      <p>Non è stato associato alcun numero di telefono all'amministrativo.</p>
-      {{end}}
-
-      {{if .Data.AltEmail}}
-      <p>La mail alternativa dell'amministrativo è <a href="mailto:{{.Data.AltEmail}}">{{.Data.AltEmail}}</a>.</p>
-      {{else}}
-      <p>Non è stato associata alcuna mail alternativa.</p>
-      {{end}}
-
-    </div>
-  </div>
+  {{template "breadcrumb" toSlice "Personale ATA" (all "Administrative") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Administrative") "deletePath" (.Data.ID|delete "Administrative")}}
+
+  <h2 class="karmen-relation-header">Informazioni</h2>
+  
+  {{if .Data.Office}}
+  <p>L'amministrativo è associato con l'ufficio di {{(.Data.Office.ID|show "Office")|anchor (.Data.Office|string)}}.</p>
+  {{else}}
+  <p>L'amministrativo non è associato con alcun ufficio.</p>
+  {{end}}
+
+  {{if .Data.InternalTelephoneNumber}}
+  <p>L'amministrativo risponde al numero di telefono interno {{.Data.InternalTelephoneNumber}}.</p>
+  {{else}}
+  <p>L'amministrativo non ha un numero di telefono interno assegnato.</p>
+  {{end}}
 
 </div>    
 

+ 1 - 0
templates/layout/checkbox.html.tpl

@@ -6,5 +6,6 @@
          id="{{.options.id}}"
          {{if .update}}{{if eq true .value}}checked{{end}}{{end}} {{.options.required}}>
   <label class="form-check-label" for="{{.options.id}}">{{.options.label}}</label>
+  {{if .options.help}}<small class="form-text text-muted">{{.options.help}}</small>{{end}}
 </div>
 {{end}}

+ 1 - 0
templates/layout/input.html.tpl

@@ -6,5 +6,6 @@
          class="{{if .options.inputClass}}{{.options.inputClass}}{{else}}form-control{{end}}"
          id="{{.options.id}}"
          placeholder="{{.options.placeholder}}" {{if .update}}value="{{.value}}"{{end}} {{if .options.required}}required{{end}}>
+  {{if .options.help}}<small class="form-text text-muted">{{.options.help}}</small>{{end}}
 </div>
 {{end}}

+ 18 - 34
templates/offices.html.tpl

@@ -1,49 +1,33 @@
 {{ define "content" }}
 
-<div class="container">
-  
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Uffici ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<a href="/offices/add/?{{query "tpl_layout" "base" "tpl_content" "offices_add_update"}}" class="btn btn-primary float-right">
-	  <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	  Crea nuovo ufficio
-	</a>
-      </div>
-    </div>
-  </div>
+<div class="container">  
 
-  <div class="input-group" style="margin-bottom: 20px">
-    <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-    <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-  </div>
+  {{$options := `
+  title: "Uffici"
+  buttonTitle: "Crea nuovo ufficio"
+  `}}
   
-  {{if not .Data}}
-  <p>Non c'è alcun elemento da visualizzare</p>
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Office")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
   {{else}}
   <div class="list-group" id="myUL">
     {{range $office := .Data}}
-    <a class="list-group-item list-group-item-action" href="/offices/{{$office.ID}}?{{query "tpl_layout" "base" "tpl_content" "offices_show"}}">
-      <span class="fa fa-layer-group"></span>
+    <a class="list-group-item list-group-item-action" href={{$office.ID|show "Office"}}>
+      <span class="fa fa-user"></span>
       {{$office.Name}}
-
       <div class="text-right">
-	
-	{{if $office.Administratives}}
-	{{range $administrative := $office.Administratives}}
-	<small>{{$administrative.Surname}}</small>
-	{{end}}
-	{{end}}
-        
+        {{$options := `noElements: "nessun personale amministrativo"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $office.Administratives}}
       </div>
-
     </a>
     {{end}}
+    {{end}}
   </div>
-  {{end}}
+
 </div>
-  
+
 {{ end }}
+

+ 20 - 49
templates/offices_add_update.html.tpl

@@ -1,64 +1,35 @@
 {{ define "content" }}
 
 <div class="container">
-
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/offices?{{query "tpl_layout" "base" "tpl_content" "offices"}}">Segreteria</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna la segreteria</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/offices?{{query "tpl_layout" "base" "tpl_content" "offices"}}">Segreteria</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
-
- {{if .Options.Get "update"}}
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Aggiorna la segreteria</h1>
-      </div>
-    </div>
-  </div>
   
-  {{else}}
-  <h1 class="karmen-info-header">Crea nuova segreteria</h1>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <form id="form_offices_add_update" action="/offices/{{.Data.Office.ID}}/update" method="POST" role="form" class="needs-validation">
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Uffici" (all "Office") (.Data|string) (.Data.ID|show "Office") "Aggiorna" "current"}}
   {{else}}
-  <form id="form_offices_add_update" action="/offices/add/" method="POST" role="form" class="needs-validation">
+  {{template "breadcrumb" toSlice "Uffici" (all "Office") "Aggiungi" "current"}}
   {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo ufficio" "updateTitle" (printf "Aggiorna ufficio %s" (.Data|string))}}
 
-    <div class="form-group">
-      <label class="control-label" for="office_name">Nome</label>
-      <input type="text" name="Name" class="form-control" id="office_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Office.Name}}" {{end}} required>
-    </div>
+  {{$form := "form_offices_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Office"}}{{else}}{{create "Office"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
 
-    <div class="form-group">
-      <label class="control-label" for="office_name">Email</label>
-      <input type="text" name="Email" class="form-control" id="office_email" placeholder="Email dell'ufficio" {{if .Options.Get "update"}} value="{{.Data.Office.Email}}" {{end}} required>
-    </div>
+    {{$options := ` { name: "Name",id: "office_name",label: "Nome",placeholder: "Nome",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
 
+    {{$options := ` { name: "Email",id: "office_email",label: "Email",placeholder: "Inserire l'indirizzo di posta elettronica",type: "email"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Email") "update" $update}}
 
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/offices/{{.Data.Office.ID}}?{{query "tpl_layout" "base" "tpl_content" "offices_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/offices?{{query "tpl_layout" "base" "tpl_content" "offices"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
-    
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Office"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}  
   </form>
-
+  
 </div>
 
 {{ end }}

+ 24 - 63
templates/offices_show.html.tpl

@@ -2,70 +2,31 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/offices?{{query "tpl_layout" "base" "tpl_content" "offices"}}">Uffici</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-    </ol>
-  </nav>
-
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Ufficio di {{.Data.Name}}</h1>
-      </div>
-      <div class="col-md-4">
-
-	<div class="btn-group float-right" role="group">
-	  <a href="/offices/add/?{{query "tpl_layout" "base" "tpl_content" "offices_add_update"}}" class="btn btn-success">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Crea
-	  </a>
-
-	  <a href="/offices/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "offices_add_update" "update" "true"}}"  class="btn btn-primary">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/offices/{{.Data.ID}}/delete"
-		  data-url="/offices/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-	    <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
-
-      </div>
-    </div>
-  </div>
-
+  {{template "breadcrumb" toSlice "Uffici" (all "Office") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Office") "deletePath" (.Data.ID|delete "Office")}}
+
+  <h2 class="karmen-relation-header">Informazioni generali</h2>
+  {{if .Data.Email}}
+  <p>L'indirizzo di posta elettronica dell'ufficio è <a href="mailto:{{.Data.Email}}">{{.Data.Email}}</a></p>
+  {{else}}
+  <p>Nessuna informazione</p>
+  {{end}}
+  
   <div class="row">
-
     <div class="col-md-12">
-      <h2 class="karmen-relation-header">Informazioni sull'ufficio</h2>
-      {{if .Data.Email}}
-      <span class="fa fa-envelope"></span>
-      <a href="mailto:{{.Data.Email}}">{{.Data.Email}}</a>
-      {{else}}
-      <span class="list-group-item list-group-item-action">Nessun coordinatore</span>
-      {{end}}
-    </div>
+
+      {{$options := `
+      title: "Personale ATA afferente all'ufficio"
+      model: "Administrative"
+      icon: "fa fa-user"
+      `}}
+      
+      {{$noElements := "All'ufficio non è associato personale ATA"}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Administratives "noElements" $noElements}}
     
-    <div class="col-md-12">
-      <h2 class="karmen-relation-header">Personale amministrativo presente nell'ufficio</h2>
-      {{if not .Data.Administratives}}
-      <p>All'ufficio non è associato nessun personale amministrativo
-	didattica. Clicca <a href="/administratives/add/?{{query "tpl_layout" "base" "tpl_content" "administratives_add_update"}}">qui</a> per creare
-	una nuova utenza amministrativa.</p>
-      {{else}}
-      <div class="list-group" id="administratives_list_group">
-	{{range $administrative := .Data.Administratives}}
-	<a class="list-group-item list-group-item-action" href="/administratives/{{$administrative.ID}}?{{query "tpl_layout" "base" "tpl_content" "administratives_show"}}">
-	  <span class="fa fa-user"></span>
-	  {{$administrative.Surname}} {{$administrative.Name}}
-	</a>
-	{{end}}
-      </div>
-      {{end}}
-    </div>    
+    </div>
+  </div>
+  
+</div>    
 
-    {{ end }}
+{{ end }}