Group sessions now show current data in a scenario format.

Remote users are now informed when session is closed.
This commit is contained in:
neviyn 2019-02-28 15:07:29 +00:00
parent 6f7e5596c3
commit 6f4da05ddc
6 changed files with 499 additions and 388 deletions

View File

@ -147,7 +147,19 @@ data class Scenario(
@OneToOne(cascade = [CascadeType.ALL])
val knowledge: RatingComponent
)
) {
fun ratingsAllValid(): Boolean {
val limitation = 1..5
return monitoring.rating in limitation &&
controlProcedural.rating in limitation &&
control.rating in limitation &&
conservatism.rating in limitation &&
teamworkCommunications.rating in limitation &&
teamworkLeadership.rating in limitation &&
teamworkWorkload.rating in limitation &&
knowledge.rating in limitation
}
}
@Entity
data class Person(

View File

@ -15,7 +15,7 @@ object GroupSessionManager {
var tutors: List<Long>? = null
var trainingType: TrainingType? = null
var scenarioTitles: List<String>? = null
var observations: MutableList<Observation> = mutableListOf()
var observations: MutableMap<String, GroupObservation> = mutableMapOf()
fun startNewSession(site: Site, tutors: Set<Tutor>, trainingType: TrainingType, scenarioTitles: List<String>): Int {
logger.info("Starting new Group Session")
@ -29,11 +29,19 @@ object GroupSessionManager {
this.tutors = tutors.map { it.id }
this.trainingType = trainingType
this.scenarioTitles = scenarioTitles
observations = mutableListOf()
observations = mutableMapOf()
logger.debug("Group session initialized")
return sessionId
}
fun invalidate() {
this.site = null
this.tutors = null
this.trainingType = null
this.scenarioTitles = null
this.observations = mutableMapOf()
}
fun isValid(sessionId: Int): Boolean {
return isValid() && sessionId == this.sessionId
}
@ -42,7 +50,30 @@ object GroupSessionManager {
return site != null && tutors != null && trainingType != null && scenarioTitles != null
}
fun addObservation(observation: Observation) {
observations.add(observation)
fun asScenarioView(): MutableMap<String, MutableList<Scenario>> {
val output: MutableMap<String, MutableList<Scenario>> = mutableMapOf()
scenarioTitles?.forEach { title ->
output[title] = mutableListOf()
}
observations.forEach { k, v ->
v.scenarios.forEach {
output[it.title]?.add(it.copy(title = k))
}
}
return output
}
fun dataComplete(): Boolean {
observations.values.forEach {
it.scenarios.forEach { x ->
if (!x.ratingsAllValid())
return false
}
}
return true
}
fun updateObservationData(input: GroupObservation) {
observations[input.person] = input
}
}

View File

@ -40,7 +40,7 @@ class CustomWebSecurityConfigurerAdapter : WebSecurityConfigurerAdapter() {
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/site", "/api/tutor", "/api/observation", "/api/grpob/start").authenticated()
.antMatchers(HttpMethod.POST, "/api/site", "/api/tutor", "/api/observation", "/api/grpob/start", "/api/grpob/complete").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic()

View File

@ -73,7 +73,7 @@ class GroupSessionController {
fun reconnectToGroupObservation(): Map<String, Any> {
if (GroupSessionManager.isValid()) {
logger.info("Previous group observation requested, current id ${GroupSessionManager.sessionId}")
return getConnectionDetails().plus(mapOf("id" to GroupSessionManager.sessionId.toString(), "observations" to GroupSessionManager.observations))
return getConnectionDetails().plus(mapOf("id" to GroupSessionManager.sessionId.toString(), "scenarios" to GroupSessionManager.asScenarioView()))
}
logger.info("Tried to recover a session but no session is active")
return mapOf("error" to "No session currently active")
@ -119,29 +119,41 @@ class GroupSessionController {
*/
@PostMapping("/submit")
fun addGroupObservation(@Valid @RequestBody observationData: GroupObservation) {
val tutors = tutorRepository.findAllById(GroupSessionManager.tutors!!).toSet()
if (GroupSessionManager.isValid()) {
var observation = Observation(
site = GroupSessionManager.site!!,
date = LocalDate.now(),
type = GroupSessionManager.trainingType!!,
observed = observationData.scenarios.joinToString { it.title },
monitoring = observationData.scenarios.map { it.monitoring.rating }.average(),
conservatism = observationData.scenarios.map { it.conservatism.rating }.average(),
controlProcedural = observationData.scenarios.map { it.controlProcedural.rating }.average(),
control = observationData.scenarios.map { it.control.rating }.average(),
teamworkCommunications = observationData.scenarios.map { it.teamworkCommunications.rating }.average(),
teamworkLeadership = observationData.scenarios.map { it.teamworkLeadership.rating }.average(),
teamworkWorkload = observationData.scenarios.map { it.teamworkWorkload.rating }.average(),
knowledge = observationData.scenarios.map { it.knowledge.rating }.average(),
scenarios = observationData.scenarios,
tutors = tutors,
person = personRepository.findFirstByNameLike(observationData.person.toUpperCase()) ?: personRepository.save(Person(name = observationData.person.toUpperCase()))
)
observation = saveObservation(observation)
GroupSessionManager.addObservation(observation)
websocketMessenger.convertAndSend("/ws/observations", mapOf("observations" to GroupSessionManager.observations))
GroupSessionManager.updateObservationData(observationData)
websocketMessenger.convertAndSend("/ws/scenarios", mapOf("scenarios" to GroupSessionManager.asScenarioView()))
}
@PostMapping("/complete")
fun pushObservationsToDatabase(): Map<String, String> {
if (GroupSessionManager.isValid() && GroupSessionManager.dataComplete()) {
val tutors = tutorRepository.findAllById(GroupSessionManager.tutors!!).toSet()
GroupSessionManager.observations.values.forEach { x ->
saveObservation(Observation(
site = GroupSessionManager.site!!,
date = LocalDate.now(),
type = GroupSessionManager.trainingType!!,
observed = x.scenarios.joinToString { it.title },
monitoring = x.scenarios.map { it.monitoring.rating }.average(),
conservatism = x.scenarios.map { it.conservatism.rating }.average(),
controlProcedural = x.scenarios.map { it.controlProcedural.rating }.average(),
control = x.scenarios.map { it.control.rating }.average(),
teamworkCommunications = x.scenarios.map { it.teamworkCommunications.rating }.average(),
teamworkLeadership = x.scenarios.map { it.teamworkLeadership.rating }.average(),
teamworkWorkload = x.scenarios.map { it.teamworkWorkload.rating }.average(),
knowledge = x.scenarios.map { it.knowledge.rating }.average(),
scenarios = x.scenarios,
tutors = tutors,
person = personRepository.findFirstByNameLike(x.person.toUpperCase())
?: personRepository.save(Person(name = x.person.toUpperCase()))
))
}
GroupSessionManager.invalidate()
websocketMessenger.convertAndSend("/ws/status", mapOf("status" to "complete"))
return mapOf("success" to "The submission was successfully completed.")
} else if (!GroupSessionManager.dataComplete()) {
return mapOf("error" to "Data is incomplete")
}
return mapOf("error" to "Session was not valid")
}
/**

View File

@ -1,17 +1,47 @@
<template>
<b-container>
<b-container fluid>
<b-row v-if="active">
<b-col cols="3">
<b-col cols="12" md="3">
<vue-qrcode v-model="qrdata" :options="{ width: 250 }"></vue-qrcode>
<p>Scan the code or navigate to
<br>
{{ qrdata }}
</p>
</b-col>
<b-col cols="12" md="9">
<b-card-group v-for="(item, index) in data" v-bind:key="index">
<b-card border-variant="secondary" header-border-variant="secondary" :header="index">
<b-card-text>
<b-table :fields="tableFields" :items="item"></b-table>
</b-card-text>
</b-card>
</b-card-group>
</b-col>
<b-col>
<b-list-group v-for="(item, index) in data" v-bind:key="index">
<b-list-group-item>{{ item.person.name }}</b-list-group-item>
</b-list-group>
<b-button size="lg" variant="primary" v-on:click="showCompletionModal()">Finish Session</b-button>
</b-col>
</b-row>
<b-row v-else-if="complete">
<b-col>
<b-row>
<b-col>
<h2>Session Complete</h2>
</b-col>
</b-row>
<b-row>
<b-col>
<p>Observation data for this session is now saved in the database.</p>
</b-col>
</b-row>
<b-row>
<b-col>
<b-button
size="lg"
variant="primary"
v-on:click="window.location.reload()"
>Start a New Session</b-button>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row v-else>
@ -99,7 +129,7 @@
<b-modal
id="submissionModal"
ref="submissionModal"
title="Enter password to confirm submission"
title="Enter password to confirm session start"
@ok="handleOk"
@shown="clearPassword"
>
@ -107,6 +137,17 @@
<b-form-input type="password" placeholder="Enter password" v-model="submitPassword"></b-form-input>
</form>
</b-modal>
<b-modal
id="completionModal"
ref="completionModal"
title="Enter password to confirm submission"
@ok="handleSubmitComplete"
@shown="clearPassword"
>
<form @submit.stop.prevent="handleSubmit">
<b-form-input type="password" placeholder="Enter password" v-model="submitPassword"></b-form-input>
</form>
</b-modal>
</b-container>
</template>
<script>
@ -122,15 +163,30 @@ export default {
return {
active: false,
stompclient: null,
complete: false,
qrdata: "N/A",
data: [{person:{name:"No data yet received."}}],
data: [{ person: { name: "No data yet received." } }],
site: null,
tutors: null,
siteOptions: [],
tutorOptions: [],
scenarioTitles: [{ data: "" }, { data: "" }, { data: "" }],
type: null,
submitPassword: null
submitPassword: null,
tableFields: [
{ key: "title", label: "Name" },
{ key: "monitoring.rating", label: "Monitoring" },
{ key: "controlProcedural.rating", label: "Control Procedural" },
{ key: "control.rating", label: "Control" },
{ key: "conservatism.rating", label: "Conservatism" },
{
key: "teamworkCommunications.rating",
label: "Teamwork Communications"
},
{ key: "teamworkLeadership.rating", label: "Teamwork Leadership" },
{ key: "teamworkWorkload.rating", label: "Teamwork Workload" },
{ key: "knowledge.rating", label: "Knowledge" }
]
};
},
watch: {
@ -183,27 +239,7 @@ export default {
console.log(response);
if ("error" in response.data) {
} else {
let rdata = response.data;
self.qrdata = `http://${rdata.ip}:${rdata.port}/#/groupsession/${
rdata.id
}`;
self.active = true;
self.stompclient = webstomp.over(
new SockJS("http://127.0.0.1:8080/websocket", {
heartbeat: true
})
);
self.stompclient.connect([], function() {
self.stompclient.subscribe("/ws/observations", function(
incomingData
) {
self.data = JSON.parse(incomingData.body).observations;
console.log("data #")
console.log(self.data)
});
});
self.$refs.submissionModal.hide();
self.clearPassword();
self.setupSession(response.data);
}
})
.catch(function(error) {
@ -219,28 +255,7 @@ export default {
console.log(response);
if ("error" in response.data) {
} else {
let rdata = response.data;
self.data = rdata.observations;
self.qrdata = `http://${rdata.ip}:${rdata.port}/#/groupsession/${
rdata.id
}`;
console.log(self.active);
self.active = true;
console.log(self.active);
self.stompclient = webstomp.over(
new SockJS("http://127.0.0.1:8080/websocket", {
heartbeat: false
})
);
self.stompclient.connect([], function() {
self.stompclient.subscribe("/ws/observations", function(
incomingData
) {
self.data = JSON.parse(incomingData.body).observations;
});
});
self.$refs.submissionModal.hide();
self.clearPassword();
self.setupSession(response.data);
}
})
.catch(function(error) {
@ -250,6 +265,27 @@ export default {
}
});
},
setupSession: function(rdata) {
console.log("rdata");
console.log(rdata);
var self = this;
self.qrdata = `http://${rdata.ip}:${rdata.port}/#/groupsession/${
rdata.id
}`;
self.active = true;
self.stompclient = webstomp.over(
new SockJS("http://127.0.0.1:8080/websocket", {
heartbeat: false
})
);
self.stompclient.connect([], function() {
self.stompclient.subscribe("/ws/scenarios", function(incomingData) {
self.data = JSON.parse(incomingData.body).scenarios;
});
});
self.$refs.submissionModal.hide();
self.clearPassword();
},
getTutors: function() {
if (this.site != null) {
Vue.axios
@ -277,6 +313,9 @@ export default {
showModal() {
this.$refs.submissionModal.show();
},
showCompletionModal() {
this.$refs.completionModal.show();
},
clearPassword() {
this.submitPassword = null;
},
@ -286,6 +325,31 @@ export default {
if (this.submitPassword !== null) {
this.startSession();
}
},
handleSubmitComplete(evt) {
// Prevent modal from closing
var self = this;
evt.preventDefault();
if (this.submitPassword !== null) {
let axiosConfig = {
auth: {
username: "admin",
password: this.submitPassword
}
};
Vue.axios
.post("/grpob/complete", {}, axiosConfig)
.then(function(response) {
console.log(response.data);
if ("success" in response.data) {
self.complete = true;
self.active = false;
}
})
.catch(function(error) {
console.log(error);
});
}
}
},
beforeDestroy() {

View File

@ -7,8 +7,8 @@
</b-container>
<b-container v-else-if="complete">
<h2>Submission Complete</h2>
<p>Thank you. Your observation data has been submitted.</p>
<p>Your observation summary will shortly appear on the session display.</p>
<p>Thank you.</p>
<p>This observation session is now closed and your data submitted to the database.</p>
</b-container>
<b-container v-else-if="!valid">
<p>Getting session data from server</p>
@ -17,7 +17,7 @@
<p>No scenarios defined for this session, please setup a new group session</p>
</b-container>
<b-container v-else fluid>
<b-form @submit="onSubmit" id="submission-form" novalidate>
<b-form>
<b-row align-h="center">
<b-col>
<b-form-group label="Participant">
@ -33,283 +33,274 @@
</b-row>
<b-row v-for="(item, index) in scenarios" v-bind:key="index" class="border bottom-buffer">
<b-col>
<b-row>
<b-col>
<b-form-input
v-model="item.title"
type="text"
placeholder="Enter scenario description."
readonly
></b-form-input>
</b-col>
</b-row>
<b-row>
<b-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Monitoring</h5>
<score-selector
:score-value="item.monitoring.rating"
v-on:newselection="item.monitoring.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Control Procedural</h5>
<score-selector
:score-value="item.controlProcedural.rating"
v-on:newselection="item.controlProcedural.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Control</h5>
<score-selector
:score-value="item.control.rating"
v-on:newselection="item.control.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Conservatism</h5>
<score-selector
:score-value="item.conservatism.rating"
v-on:newselection="item.conservatism.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Communications</h5>
<score-selector
:score-value="item.teamworkCommunications.rating"
v-on:newselection="item.teamworkCommunications.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Leadership</h5>
<score-selector
:score-value="item.teamworkLeadership.rating"
v-on:newselection="item.teamworkLeadership.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Workload</h5>
<score-selector
:score-value="item.teamworkWorkload.rating"
v-on:newselection="item.teamworkWorkload.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Knowledge</h5>
<score-selector
:score-value="item.knowledge.rating"
v-on:newselection="item.knowledge.rating = $event;"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-row>
<b-row>
<b-col>
<b-form-input v-model="item.title" type="text" readonly></b-form-input>
</b-col>
</b-row>
<b-row>
<b-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Monitoring</h5>
<score-selector
:score-value="item.monitoring.rating"
v-on:newselection="item.monitoring.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Control Procedural</h5>
<score-selector
:score-value="item.controlProcedural.rating"
v-on:newselection="item.controlProcedural.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Control</h5>
<score-selector
:score-value="item.control.rating"
v-on:newselection="item.control.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Conservatism</h5>
<score-selector
:score-value="item.conservatism.rating"
v-on:newselection="item.conservatism.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Communications</h5>
<score-selector
:score-value="item.teamworkCommunications.rating"
v-on:newselection="item.teamworkCommunications.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Leadership</h5>
<score-selector
:score-value="item.teamworkLeadership.rating"
v-on:newselection="item.teamworkLeadership.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-col cols="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Teamwork Workload</h5>
<score-selector
:score-value="item.teamworkWorkload.rating"
v-on:newselection="item.teamworkWorkload.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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="12" md="6" xl="3" class="border">
<b-row>
<b-col>
<h5>Knowledge</h5>
<score-selector
:score-value="item.knowledge.rating"
v-on:newselection="item.knowledge.rating = $event; actuallySubmit()"
></score-selector>
</b-col>
</b-row>
<b-row>
<b-col>
<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-row>
</b-col>
</b-row>
<br>
<b-button type="submit" variant="primary" v-on:click="onSubmit()">Submit</b-button>
<b-button variant="primary" v-on:click="actuallySubmit()">Update</b-button>
</b-form>
</b-container>
<b-modal id="submissionModal" ref="submissionModal" title="Confirm Submission" @ok="actuallySubmit()">
<form @submit.stop.prevent="handleSubmit">
<p>Once submitted, data cannot be changed.</p>
<p>Are you sure you wish to submit?</p>
</form>
</b-modal>
</b-container>
</template>
<script>
import Vue from "vue";
import ScoreSelector from "../components/ScoreSelector.vue";
import webstomp from "webstomp-client";
import SockJS from "sockjs-client";
export default {
name: "groupsessioninput",
title: "Group Session - Input",
@ -321,7 +312,8 @@ export default {
participant: null,
valid: false,
complete: false,
error: null
error: null,
stompclient: null
};
},
mounted() {
@ -335,6 +327,7 @@ export default {
self.addAnotherObservation(x);
});
self.valid = true;
self.setupSession()
}
})
.catch(function(error) {
@ -352,80 +345,79 @@ export default {
this.scenarios.push({
title: newTitle,
monitoring: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
controlProcedural: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
control: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
conservatism: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
teamworkCommunications: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
teamworkLeadership: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
teamworkWorkload: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
},
knowledge: {
rating: null,
rating: 0,
strengths: "",
improvements: ""
}
});
},
onSubmit: function(e) {
e.preventDefault();
e.stopPropagation();
var form = document.getElementById("submission-form");
if (form.checkValidity()) {
this.showModal();
}
form.classList.add("was-validated");
},
showModal() {
this.$refs.submissionModal.show();
},
actuallySubmit() {
var self = this;
var payload = {
person: self.participant,
scenarios: self.scenarios
}
var form = document.getElementById("submission-form");
if (form.checkValidity()) {
console.log(payload)
Vue.axios
.post("/grpob/submit", payload)
.then(function(response) {
person: self.participant,
scenarios: self.scenarios
};
Vue.axios
.post("/grpob/submit", payload)
.then(function(response) {
console.log(response);
})
.catch(function(error) {
self.error = error;
console.log(error);
});
},
setupSession: function() {
var self = this;
self.stompclient = webstomp.over(
new SockJS(`http://${window.location.host}/websocket`, {
heartbeat: false
})
);
self.stompclient.connect([], function() {
self.stompclient.subscribe("/ws/status", function(incomingData) {
var data = JSON.parse(incomingData.body);
if (data.status === "complete") {
self.complete = true;
console.log(response);
})
.catch(function(error) {
self.error = error;
console.log(error);
});
}
form.classList.add("was-validated");
self.stompclient.disconnect()
}
});
});
}
}
};