Merge branch 'ScenarioDriven' into 'master'

Scenario driven

See merge request neviyn/ObservationDatabase!1
This commit is contained in:
neviyn 2018-11-30 15:03:35 +00:00
commit b551e85a19
11 changed files with 729 additions and 800 deletions

View File

@ -20,10 +20,9 @@ data class NewObservation(
val site: Long, val site: Long,
val type: TrainingType, val type: TrainingType,
val observed: String, val observed: String,
val whom: String, val scenarios: List<Scenario>,
val entries: List<Entry>,
val tutors: List<Long>, val tutors: List<Long>,
val persons: List<String> val person: String
) )
data class ObservationsRequest( data class ObservationsRequest(

View File

@ -82,29 +82,22 @@ class Controller {
val tutors = tutorRepository.findAllById(newObservation.tutors).toSet() val tutors = tutorRepository.findAllById(newObservation.tutors).toSet()
if (!site.isPresent) return null if (!site.isPresent) return null
if (tutors.isEmpty() || tutors.size != newObservation.tutors.size) return null if (tutors.isEmpty() || tutors.size != newObservation.tutors.size) return null
val overallScores = newObservation.entries.asSequence().groupBy { it.type }
.map { entry -> entry.key to entry.value.asSequence().mapNotNull { it.rating }.average() }
.map { it.first to if (it.second > 0) it.second else null }.toList()
.toMap()
var observation = Observation( var observation = Observation(
site = site.get(), site = site.get(),
date = LocalDate.now(), date = LocalDate.now(),
type = newObservation.type, type = newObservation.type,
observed = newObservation.observed, observed = newObservation.scenarios.joinToString { it.title },
whom = newObservation.whom, monitoring = newObservation.scenarios.map { it.monitoring.rating }.average(),
monitoring = overallScores[RatingCategory.MONITORING], conservatism = newObservation.scenarios.map { it.conservatism.rating }.average(),
conservatism = overallScores[RatingCategory.CONSERVATISM], controlProcedural = newObservation.scenarios.map { it.controlProcedural.rating }.average(),
controlProcedural = overallScores[RatingCategory.CONTROL_PROCEDURAL], control = newObservation.scenarios.map { it.control.rating }.average(),
control = overallScores[RatingCategory.CONTROL], teamworkCommunications = newObservation.scenarios.map { it.teamworkCommunications.rating }.average(),
teamworkCommunications = overallScores[RatingCategory.TEAMWORK_COMMUNICATIONS], teamworkLeadership = newObservation.scenarios.map { it.teamworkLeadership.rating }.average(),
teamworkLeadership = overallScores[RatingCategory.TEAMWORK_LEADERSHIP], teamworkWorkload = newObservation.scenarios.map { it.teamworkWorkload.rating }.average(),
teamworkWorkload = overallScores[RatingCategory.TEAMWORK_WORKLOAD], knowledge = newObservation.scenarios.map { it.knowledge.rating }.average(),
knowledge = overallScores[RatingCategory.KNOWLEDGE], scenarios = newObservation.scenarios,
entries = newObservation.entries,
tutors = tutors, tutors = tutors,
persons = newObservation.persons.asSequence().map { person = personRepository.findFirstByNameLike(newObservation.person.toUpperCase()) ?: personRepository.save(Person(name = newObservation.person.toUpperCase()))
personRepository.findFirstByNameLike(it.toUpperCase()) ?: personRepository.save(Person(name = it.toUpperCase()))
}.toSet()
) )
observation = observationRepository.save(observation) observation = observationRepository.save(observation)
tutors.forEach { tutors.forEach {
@ -122,34 +115,19 @@ class Controller {
fun getObservations(@Valid @RequestBody observationsRequest: ObservationsRequest): List<Observation> { fun getObservations(@Valid @RequestBody observationsRequest: ObservationsRequest): List<Observation> {
if (observationsRequest.tutor != null) { if (observationsRequest.tutor != null) {
return tutorRepository.findById(observationsRequest.tutor).map { return tutorRepository.findById(observationsRequest.tutor).map {
when { observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(tutor = it,
(observationsRequest.whom == null || observationsRequest.whom.isEmpty()) -> observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(tutor = it,
startDate = observationsRequest.startDate, startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate) endDate = observationsRequest.endDate)
else -> observationRepository.findByTutorsAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(tutor = it,
whom = observationsRequest.whom,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
}
}.orElse(listOf()) }.orElse(listOf())
} else if (observationsRequest.person != null && observationsRequest.person.isNotEmpty() && observationsRequest.site != null) { } else if (observationsRequest.person != null && observationsRequest.person.isNotEmpty() && observationsRequest.site != null) {
val person = personRepository.findFirstByNameLike(observationsRequest.person.toUpperCase()) ?: return listOf() val person = personRepository.findFirstByNameLike(observationsRequest.person.toUpperCase()) ?: return listOf()
val site = siteRepository.findById(observationsRequest.site).get() val site = siteRepository.findById(observationsRequest.site).get()
return if (observationsRequest.whom == null || observationsRequest.whom.isEmpty()) return observationRepository.findBySiteAndPersonAndDateBetweenOrderByDateAsc(site, person, observationsRequest.startDate, observationsRequest.endDate)
observationRepository.findBySiteAndPersonsAndDateBetweenOrderByDateAsc(site, person, observationsRequest.startDate, observationsRequest.endDate)
else
observationRepository.findBySiteAndWhomIgnoreCaseAndPersonsAndDateBetweenOrderByDateAsc(site, observationsRequest.whom, person, observationsRequest.startDate, observationsRequest.endDate)
} else if (observationsRequest.site != null) { } else if (observationsRequest.site != null) {
return siteRepository.findById(observationsRequest.site).map { return siteRepository.findById(observationsRequest.site).map {
when { observationRepository.findBySiteAndDateBetweenOrderByDateAsc(site = it,
(observationsRequest.whom == null || observationsRequest.whom.isEmpty()) -> observationRepository.findBySiteAndDateBetweenOrderByDateAsc(site = it,
startDate = observationsRequest.startDate, startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate) endDate = observationsRequest.endDate)
else -> observationRepository.findBySiteAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(site = it,
whom = observationsRequest.whom,
startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate)
}
}.orElse(listOf()) }.orElse(listOf())
} }
return listOf() return listOf()

View File

@ -3,9 +3,8 @@ package uk.co.neviyn.observationdatabase
import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import org.joda.time.LocalDate import org.joda.time.LocalDate
import javax.persistence.CascadeType
import javax.persistence.Column import javax.persistence.Column
import javax.persistence.ElementCollection
import javax.persistence.Embeddable
import javax.persistence.Entity import javax.persistence.Entity
import javax.persistence.FetchType import javax.persistence.FetchType
import javax.persistence.GeneratedValue import javax.persistence.GeneratedValue
@ -17,6 +16,7 @@ import javax.persistence.JoinTable
import javax.persistence.ManyToMany import javax.persistence.ManyToMany
import javax.persistence.ManyToOne import javax.persistence.ManyToOne
import javax.persistence.OneToMany import javax.persistence.OneToMany
import javax.persistence.OneToOne
import javax.persistence.Table import javax.persistence.Table
import kotlin.math.round import kotlin.math.round
@ -59,10 +59,6 @@ enum class TrainingType {
INITIAL, CONTINUING INITIAL, CONTINUING
} }
enum class RatingCategory {
MONITORING, CONTROL_PROCEDURAL, CONTROL, CONSERVATISM, TEAMWORK_COMMUNICATIONS, TEAMWORK_LEADERSHIP, TEAMWORK_WORKLOAD, KNOWLEDGE
}
/** /**
* Data record for a training observation. * Data record for a training observation.
*/ */
@ -81,8 +77,6 @@ data class Observation(
val type: TrainingType, val type: TrainingType,
@Column(nullable = false) @Column(nullable = false)
val observed: String, val observed: String,
@Column(nullable = false)
val whom: String,
val monitoring: Double?, val monitoring: Double?,
val controlProcedural: Double?, val controlProcedural: Double?,
val control: Double?, val control: Double?,
@ -91,33 +85,25 @@ data class Observation(
val teamworkLeadership: Double?, val teamworkLeadership: Double?,
val teamworkWorkload: Double?, val teamworkWorkload: Double?,
val knowledge: Double?, val knowledge: Double?,
@ElementCollection @OneToMany(cascade = [CascadeType.ALL])
val entries: List<Entry>, val scenarios: List<Scenario>,
@ManyToMany(mappedBy = "observations") @ManyToMany(mappedBy = "observations")
val tutors: Set<Tutor>, val tutors: Set<Tutor>,
@ManyToMany @ManyToOne
val persons: Set<Person> val person: Person
) { ) {
fun toCsvFormat(): String { fun toCsvFormat(): String {
return ",,\"${tutors.joinToString { it.name }}\",$date,\"$observed\",\"Training\",\"Performance Improvement - Training\",\"${site.name}\",\"N/A\"," + return ",,\"${tutors.joinToString { it.name }}\",$date,\"${scenarios.joinToString { it.title }}\",\"Training\",\"Performance Improvement - Training\",\"${site.name}\",\"N/A\"," +
"${roundScore(monitoring)},${roundScore(controlProcedural)},${roundScore(control)}," + "${roundScore(monitoring)},${roundScore(controlProcedural)},${roundScore(control)}," +
"${roundScore(conservatism)},${roundScore(teamworkCommunications)},${roundScore(teamworkLeadership)}," + "${roundScore(conservatism)},${roundScore(teamworkCommunications)},${roundScore(teamworkLeadership)}," +
"${roundScore(teamworkWorkload)},${roundScore(knowledge)},\"${getStrengths(RatingCategory.MONITORING)}\"," + "${roundScore(teamworkWorkload)},${roundScore(knowledge)},\"${scenarios.joinToString { it.monitoring.strengths }}\"," +
"\"${getStrengths(RatingCategory.CONTROL_PROCEDURAL)}\",\"${getStrengths(RatingCategory.CONTROL)}\",\"${getStrengths(RatingCategory.CONSERVATISM)}\"," + "\"${scenarios.joinToString { it.controlProcedural.strengths }}\",\"${scenarios.joinToString { it.control.strengths }}\",\"${scenarios.joinToString { it.conservatism.strengths }}\"," +
"\"${getStrengths(RatingCategory.TEAMWORK_COMMUNICATIONS)}\",\"${getStrengths(RatingCategory.TEAMWORK_LEADERSHIP)}\"," + "\"${scenarios.joinToString { it.teamworkCommunications.strengths }}\",\"${scenarios.joinToString { it.teamworkLeadership.strengths }}\"," +
"\"${getStrengths(RatingCategory.TEAMWORK_WORKLOAD)}\",\"${getStrengths(RatingCategory.KNOWLEDGE)}\"," + "\"${scenarios.joinToString { it.teamworkWorkload.strengths }}\",\"${scenarios.joinToString { it.knowledge.strengths }}\"," +
"\"${getImprovements(RatingCategory.MONITORING)}\",\"${getImprovements(RatingCategory.CONTROL_PROCEDURAL)}\"," + "\"${scenarios.joinToString { it.monitoring.improvements }}\",\"${scenarios.joinToString { it.controlProcedural.improvements }}\"," +
"\"${getImprovements(RatingCategory.CONTROL)}\",\"${getImprovements(RatingCategory.CONSERVATISM)}\"," + "\"${scenarios.joinToString { it.control.improvements }}\",\"${scenarios.joinToString { it.conservatism.improvements }}\"," +
"\"${getImprovements(RatingCategory.TEAMWORK_COMMUNICATIONS)}\",\"${getImprovements(RatingCategory.TEAMWORK_LEADERSHIP)}\"," + "\"${scenarios.joinToString { it.teamworkCommunications.improvements }}\",\"${scenarios.joinToString { it.teamworkLeadership.improvements }}\"," +
"\"${getImprovements(RatingCategory.TEAMWORK_WORKLOAD)}\",\"${getImprovements(RatingCategory.KNOWLEDGE)}\"" "\"${scenarios.joinToString { it.teamworkWorkload.improvements }}\",\"${scenarios.joinToString { it.knowledge.improvements }}\""
}
private fun getStrengths(category: RatingCategory): String {
return entries.asSequence().filter { it.type == category && it.strengths.isNotBlank() }.map { it.strengths }.joinToString()
}
private fun getImprovements(category: RatingCategory): String {
return entries.asSequence().filter { it.type == category && it.improvements.isNotBlank() }.map { it.improvements }.joinToString()
} }
private fun roundScore(input: Double?): String { private fun roundScore(input: Double?): String {
@ -128,25 +114,41 @@ data class Observation(
} }
} }
/** @Entity
* Entry giving specific details on observation performance for a tutor defined constraint. data class RatingComponent(
*/ @Id
@Embeddable @GeneratedValue(strategy = GenerationType.IDENTITY)
data class Entry( val id: Long = 0,
@Column(nullable = false)
@JsonProperty
val type: RatingCategory,
@Column(nullable = false)
@JsonProperty
val rating: Int, val rating: Int,
@Column(nullable = false, columnDefinition = "TEXT")
@JsonProperty
val strengths: String, val strengths: String,
@Column(nullable = false, columnDefinition = "TEXT")
@JsonProperty
val improvements: String val improvements: String
) )
@Entity
data class Scenario(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val title: String,
@OneToOne(cascade = [CascadeType.ALL])
val monitoring: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val controlProcedural: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val control: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val conservatism: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val teamworkCommunications: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val teamworkLeadership: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val teamworkWorkload: RatingComponent,
@OneToOne(cascade = [CascadeType.ALL])
val knowledge: RatingComponent
)
@Entity @Entity
data class Person( data class Person(
@Id @Id

View File

@ -17,13 +17,7 @@ interface ObservationRepository : CrudRepository<Observation, Long> {
fun findByTutorsAndDateBetweenOrderByDateAsc(tutor: Tutor, startDate: LocalDate, endDate: LocalDate): List<Observation> fun findByTutorsAndDateBetweenOrderByDateAsc(tutor: Tutor, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findBySiteAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(site: Site, whom: String, startDate: LocalDate, endDate: LocalDate): List<Observation> fun findBySiteAndPersonAndDateBetweenOrderByDateAsc(site: Site, person: Person, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findByTutorsAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(tutor: Tutor, whom: String, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findBySiteAndPersonsAndDateBetweenOrderByDateAsc(site: Site, person: Person, startDate: LocalDate, endDate: LocalDate): List<Observation>
fun findBySiteAndWhomIgnoreCaseAndPersonsAndDateBetweenOrderByDateAsc(site: Site, whom: String, person: Person, startDate: LocalDate, endDate: LocalDate): List<Observation>
} }
@Repository @Repository

View File

@ -93,10 +93,13 @@ class ControllerTest {
fun testAddObservation() { fun testAddObservation() {
val site = Site(1, "X") val site = Site(1, "X")
val tutor = Tutor(1, "Foo Bar", site) val tutor = Tutor(1, "Foo Bar", site)
val person = Person(name = "Mr X")
doReturn(Optional.of(site)).`when`(siteRepository).findById(1) doReturn(Optional.of(site)).`when`(siteRepository).findById(1)
doReturn(listOf(tutor)).`when`(tutorRepository).findAllById(listOf(1)) doReturn(listOf(tutor)).`when`(tutorRepository).findAllById(listOf(1))
val newData = NewObservation(1, TrainingType.INITIAL, "An Observation", "Group A", listOf(Entry(RatingCategory.MONITORING, 5, "", "")), listOf(1), listOf()) doReturn(person).`when`(personRepository).findFirstByNameLike("MR X")
val observation = Observation(1, site, LocalDate.now(), TrainingType.INITIAL, "An Observation", "Group A", 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, newData.entries, setOf(tutor), setOf()) val defaultComponent = RatingComponent(rating = 5, strengths = "", improvements = "")
val newData = NewObservation(1, TrainingType.INITIAL, "An Observation", listOf(Scenario(title = "Something", monitoring = defaultComponent, controlProcedural = defaultComponent, control = defaultComponent, conservatism = defaultComponent, teamworkCommunications = defaultComponent, teamworkLeadership = defaultComponent, teamworkWorkload = defaultComponent, knowledge = defaultComponent)), listOf(1), "Mr X")
val observation = Observation(1, site, LocalDate.now(), TrainingType.INITIAL, "An Observation", 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, newData.scenarios, setOf(tutor), person)
doReturn(observation).`when`(observationRepository).save(ArgumentMatchers.any()) doReturn(observation).`when`(observationRepository).save(ArgumentMatchers.any())
val result = controller.addObservation(newData) val result = controller.addObservation(newData)
assertEquals(1L, result) assertEquals(1L, result)
@ -110,13 +113,13 @@ class ControllerTest {
} }
@Test @Test
fun testGetObservations_WithSite_TutorNull_NoWhom() { fun testGetObservations_WithSite_TutorNull() {
val request = ObservationsRequest(1, null, "", "", LocalDate.now(), LocalDate.now()) val request = ObservationsRequest(1, null, "", "", LocalDate.now(), LocalDate.now())
val site = Site(1, "Area 51") val site = Site(1, "Area 51")
val observation = Observation(site = site, date = LocalDate.now(), val observation = Observation(site = site, date = LocalDate.now(),
type = TrainingType.INITIAL, observed = "1", whom = "G1", monitoring = 5.0, controlProcedural = 3.0, type = TrainingType.INITIAL, observed = "1", monitoring = 5.0, controlProcedural = 3.0,
control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0, control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, knowledge = 1.0, entries = listOf(), tutors = setOf(), persons = setOf()) teamworkWorkload = 1.0, knowledge = 1.0, scenarios = listOf(), tutors = setOf(), person = Person(name = "noone"))
doReturn(Optional.of(site)).`when`(siteRepository).findById(1) doReturn(Optional.of(site)).`when`(siteRepository).findById(1)
doReturn(listOf(observation)) doReturn(listOf(observation))
.`when`(observationRepository).findBySiteAndDateBetweenOrderByDateAsc(site, LocalDate.now(), LocalDate.now()) .`when`(observationRepository).findBySiteAndDateBetweenOrderByDateAsc(site, LocalDate.now(), LocalDate.now())
@ -126,30 +129,14 @@ class ControllerTest {
} }
@Test @Test
fun testGetObservations_WithSite_TutorNull_WithWhom() { fun testGetObservations_WithSite_WithTutor() {
val request = ObservationsRequest(1, null, "Group A", "", LocalDate.now(), LocalDate.now())
val site = Site(1, "Area 51")
val observation = Observation(site = site, date = LocalDate.now(),
type = TrainingType.INITIAL, observed = "1", whom = "Group A", monitoring = 5.0, controlProcedural = 3.0,
control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, knowledge = 1.0, entries = listOf(), tutors = setOf(), persons = setOf())
doReturn(Optional.of(site)).`when`(siteRepository).findById(1)
doReturn(listOf(observation))
.`when`(observationRepository).findBySiteAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(site, "Group A", LocalDate.now(), LocalDate.now())
val result = controller.getObservations(request)
assertEquals(1, result.size)
assertEquals(observation, result[0])
}
@Test
fun testGetObservations_WithSite_WithTutor_NoWhom() {
val request = ObservationsRequest(null, 1, "", "", LocalDate.now(), LocalDate.now()) val request = ObservationsRequest(null, 1, "", "", LocalDate.now(), LocalDate.now())
val site = Site(1, "Area 51") val site = Site(1, "Area 51")
val tutor = Tutor(1, "Mr Unknown", site) val tutor = Tutor(1, "Mr Unknown", site)
val observation = Observation(site = site, date = LocalDate.now(), val observation = Observation(site = site, date = LocalDate.now(),
type = TrainingType.INITIAL, observed = "1", whom = "G1", monitoring = 5.0, controlProcedural = 3.0, type = TrainingType.INITIAL, observed = "1", monitoring = 5.0, controlProcedural = 3.0,
control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0, control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, knowledge = 1.0, entries = listOf(), tutors = setOf(tutor), persons = setOf()) teamworkWorkload = 1.0, knowledge = 1.0, scenarios = listOf(), tutors = setOf(tutor), person = Person(name = "noone"))
doReturn(Optional.of(tutor)).`when`(tutorRepository).findById(1) doReturn(Optional.of(tutor)).`when`(tutorRepository).findById(1)
doReturn(listOf(observation)) doReturn(listOf(observation))
.`when`(observationRepository).findByTutorsAndDateBetweenOrderByDateAsc(tutor, LocalDate.now(), LocalDate.now()) .`when`(observationRepository).findByTutorsAndDateBetweenOrderByDateAsc(tutor, LocalDate.now(), LocalDate.now())
@ -158,23 +145,6 @@ class ControllerTest {
assertEquals(observation, result[0]) assertEquals(observation, result[0])
} }
@Test
fun testGetObservations_WithSite_WithTutor_WithWhom() {
val request = ObservationsRequest(null, 1, "Group A", "", LocalDate.now(), LocalDate.now())
val site = Site(1, "Area 51")
val tutor = Tutor(1, "Mr Unknown", site)
val observation = Observation(site = site, date = LocalDate.now(),
type = TrainingType.INITIAL, observed = "1", whom = "Group A", monitoring = 5.0, controlProcedural = 3.0,
control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, knowledge = 1.0, entries = listOf(), tutors = setOf(tutor), persons = setOf())
doReturn(Optional.of(tutor)).`when`(tutorRepository).findById(1)
doReturn(listOf(observation))
.`when`(observationRepository).findByTutorsAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(tutor, "Group A", LocalDate.now(), LocalDate.now())
val result = controller.getObservations(request)
assertEquals(1, result.size)
assertEquals(observation, result[0])
}
@Test @Test
fun testGetObservations_WithPerson() { fun testGetObservations_WithPerson() {
val request = ObservationsRequest(1, null, null, "Foo Bar", LocalDate.now(), LocalDate.now()) val request = ObservationsRequest(1, null, null, "Foo Bar", LocalDate.now(), LocalDate.now())
@ -182,12 +152,12 @@ class ControllerTest {
val tutor = Tutor(1, "Mr Unknown", site) val tutor = Tutor(1, "Mr Unknown", site)
val person = Person(1, "Foo Bar") val person = Person(1, "Foo Bar")
val observation = Observation(site = site, date = LocalDate.now(), val observation = Observation(site = site, date = LocalDate.now(),
type = TrainingType.INITIAL, observed = "1", whom = "Group A", monitoring = 5.0, controlProcedural = 3.0, type = TrainingType.INITIAL, observed = "1", monitoring = 5.0, controlProcedural = 3.0,
control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0, control = 4.0, conservatism = 3.0, teamworkCommunications = 2.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, knowledge = 1.0, entries = listOf(), tutors = setOf(tutor), persons = setOf(person)) teamworkWorkload = 1.0, knowledge = 1.0, scenarios = listOf(), tutors = setOf(tutor), person = person)
doReturn(Optional.of(site)).`when`(siteRepository).findById(1) doReturn(Optional.of(site)).`when`(siteRepository).findById(1)
doReturn(person).`when`(personRepository).findFirstByNameLike("FOO BAR") doReturn(person).`when`(personRepository).findFirstByNameLike("FOO BAR")
doReturn(listOf(observation)).`when`(observationRepository).findBySiteAndPersonsAndDateBetweenOrderByDateAsc(site, person, LocalDate.now(), LocalDate.now()) doReturn(listOf(observation)).`when`(observationRepository).findBySiteAndPersonAndDateBetweenOrderByDateAsc(site, person, LocalDate.now(), LocalDate.now())
val result = controller.getObservations(request) val result = controller.getObservations(request)
assertEquals(1, result.size) assertEquals(1, result.size)
assertEquals(observation, result[0]) assertEquals(observation, result[0])

View File

@ -31,15 +31,6 @@ class RepositoryTest {
assertTrue(result.isEmpty()) assertTrue(result.isEmpty())
} }
@Test
fun testFindBySiteAndWhomIgnoreCaseAndDateBetween_EmptyRepository() {
val result = observationRepository.findBySiteAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(Site(
id = 1,
name = "x"
), "none", LocalDate.now(), LocalDate.now())
assertTrue(result.isEmpty())
}
@Test @Test
fun testFindByTutorsAndDateBetween_EmptyRepository() { fun testFindByTutorsAndDateBetween_EmptyRepository() {
val result = observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(Tutor( val result = observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(Tutor(
@ -50,16 +41,6 @@ class RepositoryTest {
assertTrue(result.isEmpty()) assertTrue(result.isEmpty())
} }
@Test
fun testFindByTutorsAndWhomIgnoreCaseAndDateBetween_EmptyRepository() {
val result = observationRepository.findByTutorsAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(Tutor(
id = 1,
name = "x",
site = Site(1, "x")
), "none", LocalDate.now(), LocalDate.now())
assertTrue(result.isEmpty())
}
@Test @Test
fun testFindBySiteAndDateBetween() { fun testFindBySiteAndDateBetween() {
val correctSite = entityManager.persist(Site(name = "Correct")) val correctSite = entityManager.persist(Site(name = "Correct"))
@ -72,7 +53,6 @@ class RepositoryTest {
date = LocalDate.now().minusDays(5), date = LocalDate.now().minusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -81,16 +61,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
val tooLate = Observation( val tooLate = Observation(
site = correctSite, site = correctSite,
date = LocalDate.now().plusDays(5), date = LocalDate.now().plusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -99,16 +78,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
val wrongSite = Observation( val wrongSite = Observation(
site = incorrectSite, site = incorrectSite,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -117,16 +95,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor2), tutors = setOf(tutor2),
persons = setOf(person) person = person
) )
val justRight = Observation( val justRight = Observation(
site = correctSite, site = correctSite,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -135,9 +112,9 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
entityManager.persist(tooEarly) entityManager.persist(tooEarly)
entityManager.persist(tooLate) entityManager.persist(tooLate)
@ -152,118 +129,6 @@ class RepositoryTest {
assertEquals(justRight, result.first()) assertEquals(justRight, result.first())
} }
@Test
fun testFindBySiteAndWhomIgnoreCaseAndDateBetween() {
val correctSite = entityManager.persist(Site(name = "Correct"))
val incorrectSite = entityManager.persist(Site(name = "Incorrect"))
val person = entityManager.persist(Person(name = "Foo Bar"))
val tutor = entityManager.persist(Tutor(name = "X", site = correctSite))
val tutor2 = entityManager.persist(Tutor(name = "N", site = incorrectSite))
val tooEarly = Observation(
site = correctSite,
date = LocalDate.now().minusDays(5),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(tutor),
persons = setOf(person)
)
val tooLate = Observation(
site = correctSite,
date = LocalDate.now().plusDays(5),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(tutor),
persons = setOf(person)
)
val wrongSite = Observation(
site = incorrectSite,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(tutor2),
persons = setOf(person)
)
val justRight = Observation(
site = correctSite,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(tutor),
persons = setOf(person)
)
val wrongWhom = Observation(
site = correctSite,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G2",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(tutor),
persons = setOf(person)
)
entityManager.persist(tooEarly)
entityManager.persist(tooLate)
entityManager.persist(wrongSite)
entityManager.persist(justRight)
entityManager.persist(wrongWhom)
val result = observationRepository.findBySiteAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(
site = correctSite,
startDate = LocalDate.now().minusDays(1),
endDate = LocalDate.now().plusDays(1),
whom = "G1"
)
assertEquals(1, result.size)
assertEquals(justRight, result.first())
}
@Test @Test
fun testFindByTutorsAndDateBetween() { fun testFindByTutorsAndDateBetween() {
val site = entityManager.persist(Site(name = "Correct")) val site = entityManager.persist(Site(name = "Correct"))
@ -275,7 +140,6 @@ class RepositoryTest {
date = LocalDate.now().minusDays(5), date = LocalDate.now().minusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -284,16 +148,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(correctTutor), tutors = setOf(correctTutor),
persons = setOf(person) person = person
) )
val tooLate = Observation( val tooLate = Observation(
site = site, site = site,
date = LocalDate.now().plusDays(5), date = LocalDate.now().plusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -302,16 +165,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(correctTutor), tutors = setOf(correctTutor),
persons = setOf(person) person = person
) )
val wrongTutor = Observation( val wrongTutor = Observation(
site = site, site = site,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -320,16 +182,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(incorrectTutor), tutors = setOf(incorrectTutor),
persons = setOf(person) person = person
) )
val justRight = Observation( val justRight = Observation(
site = site, site = site,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -338,16 +199,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(correctTutor), tutors = setOf(correctTutor),
persons = setOf(person) person = person
) )
val justRightMultipleTutors = Observation( val justRightMultipleTutors = Observation(
site = site, site = site,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -356,9 +216,9 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(correctTutor, incorrectTutor), tutors = setOf(correctTutor, incorrectTutor),
persons = setOf(person) person = person
) )
entityManager.persist(tooEarly) entityManager.persist(tooEarly)
entityManager.persist(tooLate) entityManager.persist(tooLate)
@ -380,143 +240,6 @@ class RepositoryTest {
assertFalse(result.contains(wrongTutor)) assertFalse(result.contains(wrongTutor))
} }
@Test
fun testFindByTutorsAndWhomIgnoreCaseAndDateBetween() {
val site = entityManager.persist(Site(name = "Correct"))
val person = entityManager.persist(Person(name = "Foo Bar"))
val correctTutor = entityManager.persist(Tutor(name = "X", site = site))
val incorrectTutor = entityManager.persist(Tutor(name = "N", site = site))
val tooEarly = Observation(
site = site,
date = LocalDate.now().minusDays(5),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(correctTutor),
persons = setOf(person)
)
val tooLate = Observation(
site = site,
date = LocalDate.now().plusDays(5),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(correctTutor),
persons = setOf(person)
)
val wrongTutor = Observation(
site = site,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(incorrectTutor),
persons = setOf(person)
)
val justRight = Observation(
site = site,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(correctTutor),
persons = setOf(person)
)
val wrongGroup = Observation(
site = site,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G2",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(correctTutor),
persons = setOf(person)
)
val justRightMultipleTutors = Observation(
site = site,
date = LocalDate.now(),
type = TrainingType.INITIAL,
observed = "1",
whom = "G1",
monitoring = 5.0,
controlProcedural = 3.0,
control = 4.0,
conservatism = 3.0,
teamworkCommunications = 2.0,
teamworkLeadership = 3.0,
teamworkWorkload = 1.0,
knowledge = 1.0,
entries = listOf(),
tutors = setOf(correctTutor, incorrectTutor),
persons = setOf(person)
)
entityManager.persist(tooEarly)
entityManager.persist(tooLate)
entityManager.persist(wrongTutor)
entityManager.persist(justRight)
entityManager.persist(wrongGroup)
entityManager.persist(justRightMultipleTutors)
correctTutor.observations.addAll(listOf(tooEarly, tooLate, justRight, justRightMultipleTutors, wrongGroup))
entityManager.persist(correctTutor)
incorrectTutor.observations.addAll(listOf(wrongTutor, justRightMultipleTutors))
entityManager.persist(incorrectTutor)
val result = observationRepository.findByTutorsAndWhomIgnoreCaseAndDateBetweenOrderByDateAsc(
tutor = correctTutor,
startDate = LocalDate.now().minusDays(1),
endDate = LocalDate.now().plusDays(1),
whom = "G1"
)
assertEquals(2, result.size)
assertTrue(result.contains(justRight))
assertTrue(result.contains(justRightMultipleTutors))
assertFalse(result.contains(wrongTutor))
assertFalse(result.contains(wrongGroup))
}
@Test @Test
fun testFindBySiteAndPersonsAndDateBetween() { fun testFindBySiteAndPersonsAndDateBetween() {
val person = entityManager.persist(Person(name = "Foo Bar")) val person = entityManager.persist(Person(name = "Foo Bar"))
@ -528,7 +251,6 @@ class RepositoryTest {
date = LocalDate.now().minusDays(5), date = LocalDate.now().minusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -537,16 +259,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
val tooLate = Observation( val tooLate = Observation(
site = site, site = site,
date = LocalDate.now().plusDays(5), date = LocalDate.now().plusDays(5),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -555,16 +276,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
val wrongPerson = Observation( val wrongPerson = Observation(
site = site, site = site,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -573,16 +293,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(otherPerson) person = otherPerson
) )
val justRight = Observation( val justRight = Observation(
site = site, site = site,
date = LocalDate.now(), date = LocalDate.now(),
type = TrainingType.INITIAL, type = TrainingType.INITIAL,
observed = "1", observed = "1",
whom = "G1",
monitoring = 5.0, monitoring = 5.0,
controlProcedural = 3.0, controlProcedural = 3.0,
control = 4.0, control = 4.0,
@ -591,15 +310,15 @@ class RepositoryTest {
teamworkLeadership = 3.0, teamworkLeadership = 3.0,
teamworkWorkload = 1.0, teamworkWorkload = 1.0,
knowledge = 1.0, knowledge = 1.0,
entries = listOf(), scenarios = listOf(),
tutors = setOf(tutor), tutors = setOf(tutor),
persons = setOf(person) person = person
) )
entityManager.persist(tooEarly) entityManager.persist(tooEarly)
entityManager.persist(tooLate) entityManager.persist(tooLate)
entityManager.persist(wrongPerson) entityManager.persist(wrongPerson)
entityManager.persist(justRight) entityManager.persist(justRight)
val result = observationRepository.findBySiteAndPersonsAndDateBetweenOrderByDateAsc( val result = observationRepository.findBySiteAndPersonAndDateBetweenOrderByDateAsc(
site = site, site = site,
person = person, person = person,
startDate = LocalDate.now().minusDays(1), startDate = LocalDate.now().minusDays(1),

View File

@ -0,0 +1,48 @@
<template>
<b-col cols="6">
<b-row>
<b-col cols="3">
<p>{{ description }}</p>
<h4 v-bind:class="{ scorewarn: scenariofundamental.rating < 3 }">{{ scenariofundamental.rating }}</h4>
</b-col>
<b-col cols="9">
<b-form-textarea
:value="scenariofundamental.strengths"
placeholder="-"
:rows="1"
:max-rows="2"
no-resize
class="strength"
readonly
></b-form-textarea>
<b-form-textarea
:value="scenariofundamental.improvements"
placeholder="-"
:rows="1"
:max-rows="2"
no-resize
class="afi"
readonly
></b-form-textarea>
</b-col>
</b-row>
</b-col>
</template>
<script>
export default {
props: ["scenariofundamental", "description"]
};
</script>
<style scoped>
.strength {
background-color: honeydew;
}
.afi {
background-color: mistyrose;
}
.scorewarn {
color: red;
}
</style>

View File

@ -1,117 +1,221 @@
<template> <template>
<b-container fluid> <b-container fluid>
<b-container v-if="description != null && type != null && whom != null && site != null && tutors != null" fluid style="padding-left: 130px;"> <b-container v-if="type != null && whom != null && site != null && tutors != null" fluid style="padding-left: 130px;">
<h3> <h3>
<v-icon name="tag" scale="1.5"/> <v-icon name="tag" scale="1.5"/>
{{type}}&nbsp;/&nbsp;{{description}} {{type}}&nbsp;/&nbsp;{{whom}}
</h3> </h3>
<br />
<b-container class="sidebar"> <b-container class="sidebar">
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[0] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[0] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Monitoring.svg" class="image-opacity"/> <img src="../assets/Monitoring.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[0] < 2.5 }"/>
<div class="image-centered-text">{{ totals[0] }}</div> <div class="image-centered-text">{{ totals[0] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[1] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[1] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Control.svg" class="image-opacity"/> <img src="../assets/Control.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[1] < 2.5 }"/>
<div class="image-centered-text">{{ totals[1] }}</div> <div class="image-centered-text">{{ totals[1] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[2] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[2] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Control.svg" class="image-opacity"/> <img src="../assets/Control.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[2] < 2.5 }"/>
<div class="image-centered-text">{{ totals[2] }}</div> <div class="image-centered-text">{{ totals[2] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[3] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[3] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Conservatism.svg" class="image-opacity"/> <img src="../assets/Conservatism.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[3] < 2.5 }"/>
<div class="image-centered-text">{{ totals[3] }}</div> <div class="image-centered-text">{{ totals[3] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[4] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[4] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Teamwork.svg" class="image-opacity"/> <img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[4] < 2.5 }"/>
<div class="image-centered-text">{{ totals[4] }}</div> <div class="image-centered-text">{{ totals[4] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[5] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[5] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Teamwork.svg" class="image-opacity"/> <img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[5] < 2.5 }"/>
<div class="image-centered-text">{{ totals[5] }}</div> <div class="image-centered-text">{{ totals[5] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[6] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[6] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Teamwork.svg" class="image-opacity"/> <img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[6] < 2.5 }"/>
<div class="image-centered-text">{{ totals[6] }}</div> <div class="image-centered-text">{{ totals[6] }}</div>
</b-col> </b-col>
</b-row> </b-row>
<b-row align-v="center" class="sidebar-vert-padding" v-if="totals[7] > 0"> <b-row align-v="center" class="sidebar-vert-padding" v-if="totals[7] > 0">
<b-col class="centered-image"> <b-col class="centered-image">
<img src="../assets/Knowledge.svg" class="image-opacity"/> <img src="../assets/Knowledge.svg" class="image-opacity" v-bind:class="{ scorewarning: totals[7] < 2.5 }"/>
<div class="image-centered-text">{{ totals[7] }}</div> <div class="image-centered-text">{{ totals[7] }}</div>
</b-col> </b-col>
</b-row> </b-row>
</b-container> </b-container>
<b-row>
<b-col>
<b-form-input v-model="personInput" v-on:keyup.enter.native="addPerson()" placeholder="Enter a name."></b-form-input>
</b-col>
<b-col cols="1">
<b-button variant="outline-secondary" v-on:click="addPerson()">+</b-button>
</b-col>
</b-row>
<b-row align-v="center">
<b-col class="mt-1" v-if="persons == null || persons.length === 0">Enter your name(s) one at a time!</b-col>
<b-col class="mt-1" cols="2" v-bind:key="index" v-for="(item, index) in persons">{{ item }}&nbsp;<a v-on:click="deletePerson(index)"><v-icon name="times-circle"/></a></b-col>
</b-row>
<br /> <br />
<b-form @submit="onSubmit" id="submission-form" novalidate> <b-form @submit="onSubmit" id="submission-form" novalidate>
<b-container v-for="(item, index) in observations" v-bind:key="index" class="border bottom-buffer" fluid> <b-container v-for="(item, index) in scenarios" v-bind:key="index" class="border bottom-buffer" fluid>
<b-row class="top-buffer"> <b-row>
<b-col cols="2">
<b-form-group label="Type">
<b-form-select v-bind:value="item.type" @change="changeType(index, $event)" required>
<option :value=null>Please select an option</option>
<option value="MONITORING">Monitoring</option>
<option value="CONTROL_PROCEDURAL">Control Procedural</option>
<option value="CONTROL">Control</option>
<option value="CONSERVATISM">Conservatism</option>
<option value="TEAMWORK_COMMUNICATIONS">Teamwork Communications</option>
<option value="TEAMWORK_LEADERSHIP">Teamwork Leadership</option>
<option value="TEAMWORK_WORKLOAD">Teamwork Workload</option>
<option value="KNOWLEDGE">Knowledge</option>
</b-form-select>
</b-form-group>
<b-form-group label="Rating">
<b-form-radio-group buttons button-variant="outline-info" size="lg"
v-bind:value="item.rating" @change="changeRating(index, $event)"
required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-form-group>
</b-col>
<b-col> <b-col>
<b-form-group label="Strengths"> <b-form-input v-model="item.title" type="text" placeholder="Enter scenario description."></b-form-input>
<b-form-textarea v-model="item.strengths" placeholder="Enter Strengths" :rows="1"
:max-rows="2" no-resize>
</b-form-textarea>
</b-form-group>
<b-form-group label="Areas of Improvement">
<b-form-textarea v-model="item.improvements" placeholder="Enter Areas of Improvement"
:rows="1" :max-rows="2" no-resize>
</b-form-textarea>
</b-form-group>
</b-col> </b-col>
<b-col cols="1" align-self="center"> <b-col cols="1">
<b-button v-on:click="deleteObservation(index)">Delete</b-button> <b-button v-on:click="deleteObservation(index)" variant="danger"><b>Delete</b></b-button>
</b-col>
</b-row>
<b-row>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Monitoring</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.monitoring.rating" @change="item.monitoring.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.monitoring.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.monitoring.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Control Procedural</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.controlProcedural.rating" @change="item.controlProcedural.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.controlProcedural.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.controlProcedural.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Control</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.control.rating" @change="item.control.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.control.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.control.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Conservatism</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.conservatism.rating" @change="item.conservatism.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.conservatism.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.conservatism.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Teamwork Communications</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.teamworkCommunications.rating" @change="item.teamworkCommunications.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.teamworkCommunications.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.teamworkCommunications.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Teamwork Leadership</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.teamworkLeadership.rating" @change="item.teamworkLeadership.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.teamworkLeadership.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.teamworkLeadership.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Teamwork Workload</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.teamworkWorkload.rating" @change="item.teamworkWorkload.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.teamworkWorkload.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.teamworkWorkload.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col>
<b-col cols="6" class="border">
<b-row>
<b-col cols="4">
<h5>Knowledge</h5>
<b-form-radio-group buttons button-variant="outline-info" size="lg" v-model="item.knowledge.rating" @change="item.knowledge.rating = $event; updateTotals();" required>
<b-form-radio button-variant="1" value=1>1</b-form-radio>
<b-form-radio button-variant="2" value=2>2</b-form-radio>
<b-form-radio button-variant="3" value=3>3</b-form-radio>
<b-form-radio button-variant="4" value=4>4</b-form-radio>
<b-form-radio button-variant="5" value=5>5</b-form-radio>
</b-form-radio-group>
</b-col>
<b-col cols="8">
<b-form-textarea v-model="item.knowledge.strengths" placeholder="Strengths" :rows="1" :max-rows="2" no-resize class="strength"></b-form-textarea>
<b-form-textarea v-model="item.knowledge.improvements" placeholder="AFIs" :rows="1" :max-rows="2" no-resize class="afi"></b-form-textarea>
</b-col>
</b-row>
</b-col> </b-col>
</b-row> </b-row>
</b-container> </b-container>
@ -120,7 +224,7 @@
<b-button type="submit" variant="primary">Submit</b-button> <b-button type="submit" variant="primary">Submit</b-button>
</b-col> </b-col>
<b-col offset="1" cols="1"> <b-col offset="1" cols="1">
<b-button v-on:click="this.addAnotherObservation">Add Entry</b-button> <b-button v-on:click="this.addAnotherObservation">Add Scenario</b-button>
</b-col> </b-col>
</b-row> </b-row>
</b-form> </b-form>
@ -167,30 +271,102 @@ export default {
title: "Observation", title: "Observation",
data: function() { data: function() {
return { return {
observations: [ scenarios: [
{ {
type: null, title: "",
monitoring: {
rating: null,
strengths: "",
improvements: ""
},
controlProcedural: {
rating: null,
strengths: "",
improvements: ""
},
control: {
rating: null,
strengths: "",
improvements: ""
},
conservatism: {
rating: null,
strengths: "",
improvements: ""
},
teamworkCommunications: {
rating: null,
strengths: "",
improvements: ""
},
teamworkLeadership: {
rating: null,
strengths: "",
improvements: ""
},
teamworkWorkload: {
rating: null,
strengths: "",
improvements: ""
},
knowledge: {
rating: null,
strengths: "",
improvements: ""
}
}
],
totals: [0, 0, 0, 0, 0, 0, 0, 0],
submitPassword: null
};
},
computed: {
...mapState(["type", "whom", "site", "tutors"])
},
methods: {
addAnotherObservation: function() {
this.scenarios.push({
title: "",
monitoring: {
rating: null,
strengths: "",
improvements: ""
},
controlProcedural: {
rating: null,
strengths: "",
improvements: ""
},
control: {
rating: null,
strengths: "",
improvements: ""
},
conservatism: {
rating: null,
strengths: "",
improvements: ""
},
teamworkCommunications: {
rating: null,
strengths: "",
improvements: ""
},
teamworkLeadership: {
rating: null,
strengths: "",
improvements: ""
},
teamworkWorkload: {
rating: null,
strengths: "",
improvements: ""
},
knowledge: {
rating: null, rating: null,
strengths: "", strengths: "",
improvements: "" improvements: ""
} }
],
totals: [0, 0, 0, 0, 0, 0, 0, 0],
submitPassword: null,
persons: [],
personInput: null
};
},
computed: {
...mapState(["description", "type", "whom", "site", "tutors"])
},
methods: {
addAnotherObservation: function() {
this.observations.push({
type: null,
rating: null,
strengths: "",
improvements: ""
}); });
Vue.nextTick(function() { Vue.nextTick(function() {
window.scrollTo( window.scrollTo(
@ -200,66 +376,54 @@ export default {
}); });
}, },
deleteObservation: function(index) { deleteObservation: function(index) {
this.observations.splice(index, 1); this.$delete(this.scenarios, index);
if (this.observations.length === 0) { if (this.scenarios.length === 0) {
this.addAnotherObservation(); this.addAnotherObservation();
} }
this.updateTotals(); this.updateTotals();
}, },
changeType: function(index, ev) {
this.observations[index].type = ev;
this.updateTotals();
},
changeRating: function(index, ev) {
this.observations[index].rating = parseInt(ev);
this.updateTotals();
},
updateTotals: function() { updateTotals: function() {
var iTotals = [0, 0, 0, 0, 0, 0, 0, 0]; var iTotals = [0, 0, 0, 0, 0, 0, 0, 0];
var counts = [0, 0, 0, 0, 0, 0, 0, 0]; var counts = [0, 0, 0, 0, 0, 0, 0, 0];
this.observations.forEach(function(element) { this.scenarios.forEach(function(element) {
if (element.rating > 0) { if (element.monitoring.rating) {
switch (element.type) { iTotals[0] += parseInt(element.monitoring.rating);
case "MONITORING": counts[0] += 1;
iTotals[0] += element.rating; }
counts[0] += 1; if (element.controlProcedural.rating) {
break; iTotals[1] += parseInt(element.controlProcedural.rating);
case "CONTROL_PROCEDURAL": counts[1] += 1;
iTotals[1] += element.rating; }
counts[1] += 1; if (element.control.rating) {
break; iTotals[2] += parseInt(element.control.rating);
case "CONTROL": counts[2] += 1;
iTotals[2] += element.rating; }
counts[2] += 1; if (element.conservatism.rating) {
break; iTotals[3] += parseInt(element.conservatism.rating);
case "CONSERVATISM": counts[3] += 1;
iTotals[3] += element.rating; }
counts[3] += 1; if (element.teamworkCommunications.rating) {
break; iTotals[4] += parseInt(element.teamworkCommunications.rating);
case "TEAMWORK_COMMUNICATIONS": counts[4] += 1;
iTotals[4] += element.rating; }
counts[4] += 1; if (element.teamworkLeadership.rating) {
break; iTotals[5] += parseInt(element.teamworkLeadership.rating);
case "TEAMWORK_LEADERSHIP": counts[5] += 1;
iTotals[5] += element.rating; }
counts[5] += 1; if (element.teamworkWorkload.rating) {
break; iTotals[6] += parseInt(element.teamworkWorkload.rating);
case "TEAMWORK_WORKLOAD": counts[6] += 1;
iTotals[6] += element.rating; }
counts[6] += 1; if (element.knowledge.rating) {
break; iTotals[7] += parseInt(element.knowledge.rating);
case "KNOWLEDGE": counts[7] += 1;
iTotals[7] += element.rating;
counts[7] += 1;
break;
}
} }
}); });
for (var i = 0; i < iTotals.length; i++) { for (var i = 0; i < iTotals.length; i++) {
if (counts[i] !== 0) { if (counts[i] !== 0) {
this.totals[i] = (iTotals[i] / counts[i]).toFixed(1); Vue.set(this.totals, i, (iTotals[i] / counts[i]).toFixed(1));
} else { } else {
this.totals[i] = 0; Vue.set(this.totals, i, 0);
} }
} }
}, },
@ -301,11 +465,10 @@ export default {
{ {
site: this.site, site: this.site,
tutors: this.tutors, tutors: this.tutors,
observed: this.description, person: this.whom,
whom: this.whom,
type: this.type, type: this.type,
persons: this.persons, observed: this.scenarios.map(x => x.title).join(', '),
entries: JSON.parse(JSON.stringify(this.observations)) scenarios: JSON.parse(JSON.stringify(this.scenarios))
}, },
axiosConfig axiosConfig
) )
@ -332,6 +495,16 @@ export default {
</script> </script>
<style scoped> <style scoped>
.strength {
background-color: honeydew;
}
.afi {
background-color: mistyrose;
}
.scorewarning {
background-color: red;
}
.top-buffer { .top-buffer {
margin-top: 10px; margin-top: 10px;
} }
@ -363,7 +536,7 @@ export default {
width: 160px; /* Set the width of the sidebar */ width: 160px; /* Set the width of the sidebar */
position: fixed; /* Fixed Sidebar (stay in place on scroll) */ position: fixed; /* Fixed Sidebar (stay in place on scroll) */
z-index: 1; /* Stay on top */ z-index: 1; /* Stay on top */
top: 20%; /* Stay at the top */ top: 10%; /* Stay at the top */
left: 0; left: 0;
overflow-x: hidden; /* Disable horizontal scroll */ overflow-x: hidden; /* Disable horizontal scroll */
overflow-y: hidden; overflow-y: hidden;
@ -385,24 +558,28 @@ img {
object-fit: contain; object-fit: contain;
} }
h5 {
padding-top: 2px;
}
.btn-1 { .btn-1 {
color: #ffffff; color: #ffffff;
background-color: #CC3232; background-color: #cc3232;
border-color: #000000; border-color: #000000;
} }
.btn-1:hover, .btn-1:hover,
.btn-1:focus, .btn-1:focus,
.btn-1:active, .btn-1:active,
.btn-1.active, .btn-1.active,
.open .dropdown-toggle.btn-1 { .open .dropdown-toggle.btn-1 {
color: #ffffff; color: #ffffff;
background-color: #4285F4; background-color: #4285f4;
border-color: #000000; border-color: #000000;
} }
.btn-1:active, .btn-1:active,
.btn-1.active, .btn-1.active,
.open .dropdown-toggle.btn-1 { .open .dropdown-toggle.btn-1 {
background-image: none; background-image: none;
} }
.btn-1.disabled, .btn-1.disabled,
.btn-1[disabled], .btn-1[disabled],
@ -419,32 +596,32 @@ fieldset[disabled] .btn-1:active,
.btn-1.disabled.active, .btn-1.disabled.active,
.btn-1[disabled].active, .btn-1[disabled].active,
fieldset[disabled] .btn-1.active { fieldset[disabled] .btn-1.active {
background-color: #CC3232; background-color: #cc3232;
border-color: #4285F4; border-color: #4285f4;
} }
.btn-1 .badge { .btn-1 .badge {
color: #CC3232; color: #cc3232;
background-color: #ffffff; background-color: #ffffff;
} }
.btn-2 { .btn-2 {
color: #ffffff; color: #ffffff;
background-color: #DB7B2B; background-color: #db7b2b;
border-color: #000000; border-color: #000000;
} }
.btn-2:hover, .btn-2:hover,
.btn-2:focus, .btn-2:focus,
.btn-2:active, .btn-2:active,
.btn-2.active, .btn-2.active,
.open .dropdown-toggle.btn-2 { .open .dropdown-toggle.btn-2 {
color: #ffffff; color: #ffffff;
background-color: #4285F4; background-color: #4285f4;
border-color: #000000; border-color: #000000;
} }
.btn-2:active, .btn-2:active,
.btn-2.active, .btn-2.active,
.open .dropdown-toggle.btn-2 { .open .dropdown-toggle.btn-2 {
background-image: none; background-image: none;
} }
.btn-2.disabled, .btn-2.disabled,
.btn-2[disabled], .btn-2[disabled],
@ -461,32 +638,32 @@ fieldset[disabled] .btn-2:active,
.btn-2.disabled.active, .btn-2.disabled.active,
.btn-2[disabled].active, .btn-2[disabled].active,
fieldset[disabled] .btn-2.active { fieldset[disabled] .btn-2.active {
background-color: #DB7B2B; background-color: #db7b2b;
border-color: #4285F4; border-color: #4285f4;
} }
.btn-2 .badge { .btn-2 .badge {
color: #DB7B2B; color: #db7b2b;
background-color: #ffffff; background-color: #ffffff;
} }
.btn-3 { .btn-3 {
color: #ffffff; color: #ffffff;
background-color: #E7B416; background-color: #e7b416;
border-color: #000000; border-color: #000000;
} }
.btn-3:hover, .btn-3:hover,
.btn-3:focus, .btn-3:focus,
.btn-3:active, .btn-3:active,
.btn-3.active, .btn-3.active,
.open .dropdown-toggle.btn-3 { .open .dropdown-toggle.btn-3 {
color: #ffffff; color: #ffffff;
background-color: #4285F4; background-color: #4285f4;
border-color: #000000; border-color: #000000;
} }
.btn-3:active, .btn-3:active,
.btn-3.active, .btn-3.active,
.open .dropdown-toggle.btn-3 { .open .dropdown-toggle.btn-3 {
background-image: none; background-image: none;
} }
.btn-3.disabled, .btn-3.disabled,
.btn-3[disabled], .btn-3[disabled],
@ -503,32 +680,32 @@ fieldset[disabled] .btn-3:active,
.btn-3.disabled.active, .btn-3.disabled.active,
.btn-3[disabled].active, .btn-3[disabled].active,
fieldset[disabled] .btn-3.active { fieldset[disabled] .btn-3.active {
background-color: #E7B416; background-color: #e7b416;
border-color: #4285F4; border-color: #4285f4;
} }
.btn-3 .badge { .btn-3 .badge {
color: #E7B416; color: #e7b416;
background-color: #ffffff; background-color: #ffffff;
} }
.btn-4 { .btn-4 {
color: #ffffff; color: #ffffff;
background-color: #99C140; background-color: #99c140;
border-color: #000000; border-color: #000000;
} }
.btn-4:hover, .btn-4:hover,
.btn-4:focus, .btn-4:focus,
.btn-4:active, .btn-4:active,
.btn-4.active, .btn-4.active,
.open .dropdown-toggle.btn-4 { .open .dropdown-toggle.btn-4 {
color: #ffffff; color: #ffffff;
background-color: #4285F4; background-color: #4285f4;
border-color: #000000; border-color: #000000;
} }
.btn-4:active, .btn-4:active,
.btn-4.active, .btn-4.active,
.open .dropdown-toggle.btn-4 { .open .dropdown-toggle.btn-4 {
background-image: none; background-image: none;
} }
.btn-4.disabled, .btn-4.disabled,
.btn-4[disabled], .btn-4[disabled],
@ -545,32 +722,32 @@ fieldset[disabled] .btn-4:active,
.btn-4.disabled.active, .btn-4.disabled.active,
.btn-4[disabled].active, .btn-4[disabled].active,
fieldset[disabled] .btn-4.active { fieldset[disabled] .btn-4.active {
background-color: #99C140; background-color: #99c140;
border-color: #4285F4; border-color: #4285f4;
} }
.btn-4 .badge { .btn-4 .badge {
color: #99C140; color: #99c140;
background-color: #ffffff; background-color: #ffffff;
} }
.btn-5 { .btn-5 {
color: #ffffff; color: #ffffff;
background-color: #2DC937; background-color: #2dc937;
border-color: #000000; border-color: #000000;
} }
.btn-5:hover, .btn-5:hover,
.btn-5:focus, .btn-5:focus,
.btn-5:active, .btn-5:active,
.btn-5.active, .btn-5.active,
.open .dropdown-toggle.btn-5 { .open .dropdown-toggle.btn-5 {
color: #ffffff; color: #ffffff;
background-color: #4285F4; background-color: #4285f4;
border-color: #000000; border-color: #000000;
} }
.btn-5:active, .btn-5:active,
.btn-5.active, .btn-5.active,
.open .dropdown-toggle.btn-5 { .open .dropdown-toggle.btn-5 {
background-image: none; background-image: none;
} }
.btn-5.disabled, .btn-5.disabled,
.btn-5[disabled], .btn-5[disabled],
@ -587,11 +764,11 @@ fieldset[disabled] .btn-5:active,
.btn-5.disabled.active, .btn-5.disabled.active,
.btn-5[disabled].active, .btn-5[disabled].active,
fieldset[disabled] .btn-5.active { fieldset[disabled] .btn-5.active {
background-color: #2DC937; background-color: #2dc937;
border-color: #4285F4; border-color: #4285f4;
} }
.btn-5 .badge { .btn-5 .badge {
color: #2DC937; color: #2dc937;
background-color: #ffffff; background-color: #ffffff;
} }
</style> </style>

View File

@ -2,7 +2,7 @@
<b-container> <b-container>
<h2>Submission Complete</h2> <h2>Submission Complete</h2>
<p>{{ type }}/{{ description }} has been submitted successfully.</p> <p>{{ type }}/{{ description }} has been submitted successfully.</p>
<b-button size="lg" variant="primary" to="/"> <b-button size="lg" variant="primary" to="/new">
Start New Observation Start New Observation
</b-button> </b-button>
</b-container> </b-container>

View File

@ -33,23 +33,8 @@
</b-row> </b-row>
<b-row align-h="center"> <b-row align-h="center">
<b-col> <b-col>
<b-form-group label="Shift"> <b-form-group label="Participant">
<b-form-select v-bind:value="whom" @change="setWhom($event)" style="text-align:center;" required> <b-form-input :value="whom" @change="setWhom($event)" type="text"
<option :value=null>Please select an option</option>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
<option value="DAY">Day</option>
</b-form-select>
</b-form-group>
</b-col>
</b-row>
<b-row align-h="center">
<b-col>
<b-form-group label="Description">
<b-form-input :value="description" @input="setDescription" type="text"
style="text-align:center;" required></b-form-input> style="text-align:center;" required></b-form-input>
</b-form-group> </b-form-group>
</b-col> </b-col>
@ -127,7 +112,7 @@ export default {
} }
}, },
computed: { computed: {
...mapState(["site", "description", "type", "tutors", "whom"]) ...mapState(["site", "type", "tutors", "whom"])
}, },
watch: { watch: {
site: function() { site: function() {
@ -145,7 +130,6 @@ export default {
methods: { methods: {
...mapMutations([ ...mapMutations([
"setSite", "setSite",
"setDescription",
"setType", "setType",
"setTutors", "setTutors",
"setWhom", "setWhom",

View File

@ -1,139 +1,196 @@
<template> <template>
<b-container fluid> <b-container fluid>
<b-modal ref="errorModal" class="text-center" centered hide-header hide-footer> <b-modal ref="errorModal" class="text-center" centered hide-header hide-footer>
<div class="modal-header"> <div class="modal-header">
<h3 class="modal-title w-100">{{ errorStatus }}</h3> <h3 class="modal-title w-100">{{ errorStatus }}</h3>
</div> </div>
<div class="d-block"> <div class="d-block">
<br/> <br>
<span style="font-size:20px;" v-html="errorMessage"/> <span style="font-size:20px;" v-html="errorMessage"/>
<button class="btn btn-warning" @click="$refs.errorModal.hide()"> <button class="btn btn-warning" @click="$refs.errorModal.hide()">
<v-icon name="exclamation-circle"/> <v-icon name="exclamation-circle"/>Dismiss
Dismiss </button>
</button> </div>
</div> </b-modal>
</b-modal> <b-row>
<b-row> <b-col>
<b-col> <b-form-group label="Site">
<b-form-group label="Site"> <b-form-select class="text-center" v-model="siteSelection" :options="siteOptions"/>
<b-form-select class="text-center" v-model="siteSelection" </b-form-group>
:options="siteOptions"/> </b-col>
</b-form-group> <b-col>
</b-col> <b-form-group label="Tutor">
<b-col> <b-form-select class="text-center" v-model="tutorSelection" :options="tutorOptions"/>
<b-form-group label="Tutor"> </b-form-group>
<b-form-select class="text-center" v-model="tutorSelection" </b-col>
:options="tutorOptions"/> <b-col>
</b-form-group> <b-form-group label="Shift">
</b-col> <b-form-input v-model="whom" type="text" class="text-center"></b-form-input>
<b-col> </b-form-group>
<b-form-group label="Shift"> </b-col>
<b-form-input v-model="whom" type="text" class="text-center"></b-form-input> <b-col>
</b-form-group> <b-form-group label="Person">
</b-col> <b-form-input v-model="person" type="text" class="text-center"></b-form-input>
<b-col> </b-form-group>
<b-form-group label="Person"> </b-col>
<b-form-input v-model="person" type="text" class="text-center"></b-form-input> <b-col>
</b-form-group> <b-form-group label="From">
</b-col> <date-picker
<b-col> v-model="startDate"
<b-form-group label="From"> @dp-change="changeStartDate"
<date-picker v-model="startDate" @dp-change="changeStartDate" value="startDate" value="startDate"
:config="dateOptions"/> :config="dateOptions"
</b-form-group> />
</b-col> </b-form-group>
<b-col> </b-col>
<b-form-group label="To"> <b-col>
<date-picker v-model="endDate" @dp-change="changeEndDate" value="endDate" <b-form-group label="To">
:config="dateOptions"/> <date-picker
</b-form-group> v-model="endDate"
</b-col> @dp-change="changeEndDate"
<b-col> value="endDate"
<b-button v-on:click="getFiltered()">Refresh</b-button> :config="dateOptions"
</b-col> />
</b-row> </b-form-group>
<b-container v-if="observationData != null && observationData.length > 0" fluid> </b-col>
<b-card no-body> <b-col>
<b-tabs pills card vertical> <b-button v-on:click="getFiltered()">Refresh</b-button>
<b-tab v-for="(observation, index) in observationData" v-bind:key="index"> </b-col>
<p slot="title">{{ observation.date }}<br/>{{ observation.whom }} {{ observation.type }}<br/>{{ shortenedString(observation.observed) }}</p> </b-row>
<h2>{{ observation.date }}, {{ observation.whom }}<br/>{{ observation.type }}, {{ observation.observed }}</h2> <b-container v-if="observationData != null && observationData.length > 0" fluid>
<b-row align-h="center"> <b-card no-body>
<h4>Observed by:&nbsp;<span v-bind:key="index" v-for="(tutor, index) in observation.tutors"><i>{{ tutor.name }}<span v-if="index+1 < observation.tutors.length">,&nbsp;</span></i></span></h4> <b-tabs pills card vertical>
</b-row> <b-tab v-for="(observation, index) in observationData" v-bind:key="index">
<b-row align-h="center"> <p slot="title">
<h4>Participants:&nbsp;<span v-bind:key="index" v-for="(person, index) in observation.persons"><i>{{ person.name }}<span v-if="index+1 < observation.persons.length">,&nbsp;</span></i></span></h4> {{ observation.date }}
</b-row> <br>
<br /> {{ observation.whom }} {{ observation.type }}
<b-row class="mb-2"> <br>
<b-col class="centered-image" v-if="observation.monitoring"> {{ shortenedString(observation.observed) }}
<img src="../assets/Monitoring.svg" class="image-opacity"/> </p>
<div class="image-centered-text">{{ observation.monitoring.toFixed(1) }}</div> <h2>
</b-col> {{ observation.date }}, {{ observation.whom }}
<b-col class="centered-image" v-if="observation.controlProcedural"> <br>
<img src="../assets/Control.svg" class="image-opacity"/> {{ observation.type }} / {{ observation.observed }}
<div class="image-centered-text">{{ observation.controlProcedural.toFixed(1) }}</div> </h2>
</b-col> <b-row align-h="center">
<b-col class="centered-image" v-if="observation.control"> <h4>Observed by:
<img src="../assets/Control.svg" class="image-opacity"/> <span v-bind:key="index" v-for="(tutor, index) in observation.tutors">
<div class="image-centered-text">{{ observation.control.toFixed(1) }}</div> <i>
</b-col> {{ tutor.name }}
<b-col class="centered-image" v-if="observation.conservatism"> <span v-if="index+1 < observation.tutors.length">,&nbsp;</span>
<img src="../assets/Conservatism.svg" class="image-opacity"/> </i>
<div class="image-centered-text">{{ observation.conservatism.toFixed(1) }}</div> </span>
</b-col> </h4>
<b-col class="centered-image" v-if="observation.teamworkCommunications">
<img src="../assets/Teamwork.svg" class="image-opacity"/>
<div class="image-centered-text">{{ observation.teamworkCommunications.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.teamworkLeadership">
<img src="../assets/Teamwork.svg" class="image-opacity"/>
<div class="image-centered-text">{{ observation.teamworkLeadership.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.teamworkWorkload">
<img src="../assets/Teamwork.svg" class="image-opacity"/>
<div class="image-centered-text">{{ observation.teamworkWorkload.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.knowledge">
<img src="../assets/Knowledge.svg" class="image-opacity"/>
<div class="image-centered-text">{{ observation.knowledge.toFixed(1) }}</div>
</b-col>
</b-row>
<div v-for="(entry, index2) in observation.entries" v-bind:key="index2">
<p>{{ entry.type }} - {{ entry.rating }}</p>
<b-form-group label="Strengths">
<b-form-textarea :value="entry.strengths" readonly>
</b-form-textarea>
</b-form-group>
<b-form-group label="Areas of Improvement">
<b-form-textarea :value="entry.improvements" readonly>
</b-form-textarea>
</b-form-group>
</div>
</b-tab>
</b-tabs>
</b-card>
<b-button class="mt-2" variant="success" @click="getCSV()">CSV Dump</b-button>
</b-container>
<b-container v-else>
<b-row>
<b-col>
<v-icon name="search"></v-icon>
<p>No data found with the given search parameters.</p>
</b-col>
</b-row> </b-row>
</b-container> <b-row align-h="center">
<h4>Participant:&nbsp;{{ observation.person.name }}</h4>
</b-row>
<br>
<b-row class="mb-2">
<b-col class="centered-image" v-if="observation.monitoring">
<img src="../assets/Monitoring.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.monitoring < 2.5 }">
<div class="image-centered-text">{{ observation.monitoring.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.controlProcedural">
<img src="../assets/Control.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.controlProcedural < 2.5 }">
<div class="image-centered-text">{{ observation.controlProcedural.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.control">
<img src="../assets/Control.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.control < 2.5 }">
<div class="image-centered-text">{{ observation.control.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.conservatism">
<img src="../assets/Conservatism.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.conservatism < 2.5 }">
<div class="image-centered-text">{{ observation.conservatism.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.teamworkCommunications">
<img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.teamworkCommunications < 2.5 }">
<div class="image-centered-text">{{ observation.teamworkCommunications.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.teamworkLeadership">
<img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.teamworkLeadership < 2.5 }">
<div class="image-centered-text">{{ observation.teamworkLeadership.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.teamworkWorkload">
<img src="../assets/Teamwork.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.teamworkWorkload < 2.5 }">
<div class="image-centered-text">{{ observation.teamworkWorkload.toFixed(1) }}</div>
</b-col>
<b-col class="centered-image" v-if="observation.knowledge">
<img src="../assets/Knowledge.svg" class="image-opacity" v-bind:class="{ scorewarning: observation.knowledge < 2.5 }">
<div class="image-centered-text">{{ observation.knowledge.toFixed(1) }}</div>
</b-col>
</b-row>
<b-row v-for="(entry, index2) in observation.scenarios" v-bind:key="index2">
<b-col class="border">
<b-row align-h="center">
<h3>{{ entry.title }}</h3>
</b-row>
<b-row>
<observation-entry
:scenariofundamental="entry.monitoring"
:description="'Monitoring'"
></observation-entry>
<observation-entry
:scenariofundamental="entry.controlProcedural"
:description="'Control Procedural'"
></observation-entry>
</b-row>
<b-row>
<observation-entry :scenariofundamental="entry.control" :description="'Control'"></observation-entry>
<observation-entry
:scenariofundamental="entry.conservatism"
:description="'Conservatism'"
></observation-entry>
</b-row>
<b-row>
<observation-entry
:scenariofundamental="entry.teamworkCommunications"
:description="'Teamwork Communications'"
></observation-entry>
<observation-entry
:scenariofundamental="entry.teamworkLeadership"
:description="'Teamwork Leadership'"
></observation-entry>
</b-row>
<b-row>
<observation-entry
:scenariofundamental="entry.teamworkWorkload"
:description="'Teamwork Workload'"
></observation-entry>
<observation-entry
:scenariofundamental="entry.knowledge"
:description="'Knowledge'"
></observation-entry>
</b-row>
</b-col>
</b-row>
</b-tab>
</b-tabs>
</b-card>
<b-button class="mt-2" variant="success" @click="getCSV()">CSV Dump</b-button>
</b-container> </b-container>
<b-container v-else>
<b-row>
<b-col>
<v-icon name="search"></v-icon>
<p>No data found with the given search parameters.</p>
</b-col>
</b-row>
</b-container>
</b-container>
</template> </template>
<script> <script>
import Vue from "vue"; import Vue from "vue";
import "vue-awesome/icons/search"; import "vue-awesome/icons/search";
import ObservationEntry from "../components/ObservationEntry.vue";
var moment = require("moment"); var moment = require("moment");
export default { export default {
name: "viewobservations", name: "viewobservations",
title: "Observations History", title: "Observations History",
components: { ObservationEntry },
data: function() { data: function() {
return { return {
dateOptions: { dateOptions: {
@ -158,58 +215,57 @@ export default {
this.$router.push("/dberror"); this.$router.push("/dberror");
return; return;
} }
console.log(error);
}); });
this.getTutors(); this.getTutors();
this.getFiltered(); this.getFiltered();
}, },
computed: { computed: {
startDate: { startDate: {
get(){ get() {
return this.$store.state.search.start; return this.$store.state.search.start;
}, },
set(data){ set(data) {
this.$store.commit('setSearchStartDate', data); this.$store.commit("setSearchStartDate", data);
} }
}, },
endDate: { endDate: {
get(){ get() {
return this.$store.state.search.end; return this.$store.state.search.end;
}, },
set(data){ set(data) {
this.$store.commit('setSearchEndDate', data); this.$store.commit("setSearchEndDate", data);
} }
}, },
siteSelection: { siteSelection: {
get(){ get() {
return this.$store.state.search.site; return this.$store.state.search.site;
}, },
set(data){ set(data) {
this.$store.commit('setSearchSite', data); this.$store.commit("setSearchSite", data);
} }
}, },
tutorSelection: { tutorSelection: {
get(){ get() {
return this.$store.state.search.tutor; return this.$store.state.search.tutor;
}, },
set(data){ set(data) {
this.$store.commit('setSearchTutor', data) this.$store.commit("setSearchTutor", data);
} }
}, },
whom: { whom: {
get(){ get() {
return this.$store.state.search.whom; return this.$store.state.search.whom;
}, },
set(data){ set(data) {
this.$store.commit('setSearchWhom', data) this.$store.commit("setSearchWhom", data);
} }
}, },
person: { person: {
get(){ get() {
return this.$store.state.search.person; return this.$store.state.search.person;
}, },
set(data){ set(data) {
this.$store.commit('setSearchPerson', data) this.$store.commit("setSearchPerson", data);
} }
} }
}, },
@ -276,12 +332,11 @@ export default {
}); });
}, },
shortenedString: function(data) { shortenedString: function(data) {
if(data.len < 20){ if (data.len < 20) {
return data; return data;
} } else {
else{ return data.substr(0, 20) + "...";
return data.substr(0, 20) + "..."; }
}
} }
}, },
watch: { watch: {
@ -302,6 +357,9 @@ export default {
position: relative; position: relative;
text-align: center; text-align: center;
} }
.scorewarning {
background-color: red;
}
.image-centered-text { .image-centered-text {
position: absolute; position: absolute;
top: 50%; top: 50%;