<template> <div> <base-annotated-submission> <annotated-submission-top-toolbar class="mb-1 elevation-1" slot="header" /> <template slot="table-content" id='sub-lines'> <tr v-for="(code, lineNo) in submission" :key="`${submissionObj.pk}${lineNo}`" :id="`sub-line-${lineNo}`"> <submission-line :code="code" :line-no="lineNo" @toggleEditor="toggleEditorOnLine(lineNo)" > <template v-if="showFeedback"> <div v-if="origFeedback[lineNo]"> <feedback-comment v-for="(comment, index) in getSortedComments(lineNo)" v-bind="comment" :visibleToStudent="updatedFeedback[lineNo] ? false : comment.visibleToStudent" :line-no="lineNo" :key="index" :deletable="comment.ofTutor === user || isReviewer" @click.native="toggleEditorOnLine(lineNo, comment)" /> </div> <feedback-comment v-if="updatedFeedback[lineNo]" v-bind="updatedFeedback[lineNo]" :line-no="lineNo" :deletable="true" @click.native="toggleEditorOnLine(lineNo, updatedFeedback[lineNo])" /> </template> <comment-form v-if="showEditorOnLine[lineNo]" :feedback="selectedComment[lineNo].text" :lineNo="lineNo" @collapseFeedbackForm="toggleEditorOnLine(lineNo)" > </comment-form> </submission-line> </tr> </template> <label-selector id="feedback-label-selector" :assignedToFeedback="true" class="mt-1 elevation-1" slot="labels" /> <annotated-submission-bottom-toolbar class="mt-1 elevation-1" slot="footer" :loading="loading" :fullScore="submissionObj['fullScore']" :skippable="assignment !== undefined" :feedback="feedbackObj ? feedbackObj : {}" @submitFeedback="submitFeedback" /> </base-annotated-submission> </div> </template> <script> import { mapState, mapGetters } from 'vuex' import CommentForm from '@/components/submission_notes/base/CommentForm.vue' import FeedbackComment from '@/components/submission_notes/base/FeedbackComment.vue' import AnnotatedSubmissionTopToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar' import AnnotatedSubmissionBottomToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar' import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnnotatedSubmission' import FeedbackLabel from "@/components/feedback_labels/FeedbackLabel.vue" import { FeedbackLabels as Labels } from '@/store/modules/feedback-labels' import LabelSelector from '@/components/feedback_labels/LabelSelector.vue' import SubmissionLine from '@/components/submission_notes/base/SubmissionLine' import { SubmissionNotes } from '@/store/modules/submission-notes' import { Authentication } from '@/store/modules/authentication' import { actions } from '@/store/actions' import { fetchFeedback } from '@/api' export default { components: { SubmissionLine, BaseAnnotatedSubmission, AnnotatedSubmissionBottomToolbar, AnnotatedSubmissionTopToolbar, FeedbackComment, LabelSelector, CommentForm }, name: 'submission-correction', data () { return { loading: false, feedbackShortPollInterval: null } }, props: { assignment: { type: Object }, // either pass in an assignment or a submission and feedback submissionWithoutAssignment: { type: Object }, feedback: { type: Object }, ignoreHiddenState: { type: Boolean, default: false, } }, computed: { showEditorOnLine () { return SubmissionNotes.state.ui.showEditorOnLine }, selectedComment () { return SubmissionNotes.state.ui.selectedCommentOnLine }, origFeedback () { return SubmissionNotes.state.origFeedback.feedbackLines }, updatedFeedback () { return SubmissionNotes.state.updatedFeedback.feedbackLines }, showFeedback () { return SubmissionNotes.state.ui.showFeedback }, workInProgress () { return SubmissionNotes.workInProgress }, isStudent () { return Authentication.isStudent }, isTutor () { return Authentication.isTutor }, isReviewer () { return Authentication.isReviewer }, user () { return Authentication.state.user.username }, submission () { return SubmissionNotes.submission }, submissionObj () { return this.assignment ? this.assignment.submission : this.submissionWithoutAssignment }, feedbackObj () { return this.assignment ? this.assignment.feedback : this.feedback } }, methods: { toggleEditorOnLine (lineNo, comment = '') { SubmissionNotes.TOGGLE_EDITOR_ON_LINE({ lineNo, comment }) }, submitFeedback ({ isFinal }) { this.loading = true SubmissionNotes.submitFeedback({ isFinal: isFinal }).then(feedback => { SubmissionNotes.RESET_UPDATED_FEEDBACK() SubmissionNotes.SET_ORIG_FEEDBACK(feedback) this.$emit('feedbackCreated') }).catch(err => { // ignore trivial errors as those are handled // by an interceptor if (err.message.includes("Request failed")) return this.$notify({ title: 'Feedback creation Error!', text: err.message, type: 'error', duration: -1 }) }).finally(() => { this.$emit('feedbackChanged') SubmissionNotes.RESET_MARKED_COMMENTS_FOR_DELETE() this.loading = false }) }, shortPollOrigFeedback () { this.feedbackShortPollInterval = setInterval(() => { if (this.feedbackObj && this.feedbackObj.ofSubmission) { fetchFeedback({ ofSubmission: this.feedbackObj.ofSubmission }).then(feedback => { SubmissionNotes.SET_ORIG_FEEDBACK(feedback) }) } }, 5e3) }, getSortedComments (lineNo) { if (!this.origFeedback || (!this.origFeedback && !this.origFeedback[lineNo])) return new Array() let feedback = [...this.origFeedback[lineNo]] return feedback.sort((a, b) => { const da = new Date(a.modified) const db = new Date(b.modified) return da.getTime() - db.getTime() }) }, init () { SubmissionNotes.RESET_STATE() SubmissionNotes.SET_SUBMISSION(this.submissionObj) SubmissionNotes.SET_ORIG_FEEDBACK(this.feedbackObj) SubmissionNotes.SET_SHOW_FEEDBACK(this.ignoreHiddenState ? true : !SubmissionNotes.state.hasOrigFeedback) } }, watch: { assignment: function (newVar, oldVar) { this.init() }, submissionWithoutAssignment: function () { this.init() } }, created () { this.init() this.shortPollOrigFeedback() }, beforeDestroy () { clearInterval(this.feedbackShortPollInterval) } } </script> <style scoped> </style>