Skip to content
Snippets Groups Projects
Commit 623ff42d authored by robinwilliam.hundt's avatar robinwilliam.hundt
Browse files

subscriptions module is type safe

Use postgres:9.6 is ci
parent b1cfeeb5
No related branches found
No related tags found
1 merge request!119Typesafe store
Showing
with 229 additions and 226 deletions
......@@ -39,7 +39,7 @@ test_pytest:
<<: *test_definition_virtualenv
stage: test
services:
- postgres:9.5
- postgres:9.6
script:
- pytest --cov --ds=grady.settings.test core/tests
artifacts:
......
declare module 'v-clipboard';
\ No newline at end of file
declare module 'v-clipboard'
<template>
<v-dialog
v-model="dialog"
max-width="fit-content"
max-width="30%"
>
<v-card>
<v-card class="text-xs-center">
<v-card-title class="title">
Are you sure?
</v-card-title>
......@@ -19,6 +19,8 @@
</template>
<script>
import { SubmissionNotes } from '@/store/modules/submission-notes'
export default {
name: 'route-change-confirmation',
props: {
......@@ -40,7 +42,7 @@ export default {
},
watch: {
nextRoute (newVal, oldVal) {
if (newVal !== oldVal && this.$store.getters['submissionNotes/workInProgress']) {
if (newVal !== oldVal && SubmissionNotes.workInProgress) {
this.dialog = true
} else {
this.nextRoute()
......
......@@ -63,9 +63,10 @@ import AnnotatedSubmissionTopToolbar from '@/components/submission_notes/toolbar
import AnnotatedSubmissionBottomToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar'
import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnnotatedSubmission'
import SubmissionLine from '@/components/submission_notes/base/SubmissionLine'
import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
import RouteChangeConfirmation from '@/components/submission_notes/RouteChangeConfirmation'
import {Authentication} from '@/store/modules/authentication'
import { actions } from '@/store/actions'
export default {
components: {
......@@ -96,22 +97,20 @@ export default {
}
},
computed: {
...mapState({
showEditorOnLine: state => state.submissionNotes.ui.showEditorOnLine,
selectedComment: state => state.submissionNotes.ui.selectedCommentOnLine,
origFeedback: state => state.submissionNotes.origFeedback.feedbackLines,
updatedFeedback: state => state.submissionNotes.updatedFeedback.feedbackLines,
showFeedback: state => state.submissionNotes.ui.showFeedback
}),
...mapGetters([
'workInProgress'
]),
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 this.$store.getters['submissionNotes/submission']
return SubmissionNotes.submission
},
submissionObj () {
return this.assignment ? this.assignment.submission : this.submissionWithoutAssignment
......@@ -122,15 +121,15 @@ export default {
},
methods: {
toggleEditorOnLine (lineNo, comment = '') {
this.$store.commit(subNotesNamespace(subNotesMut.TOGGLE_EDITOR_ON_LINE), {lineNo, comment})
SubmissionNotes.TOGGLE_EDITOR_ON_LINE({lineNo, comment})
},
submitFeedback ({isFinal}) {
this.loading = true
this.$store.dispatch(subNotesNamespace('submitFeedback'), {
SubmissionNotes.submitFeedback({
isFinal: isFinal
}).then(feedback => {
this.$store.commit(subNotesNamespace(subNotesMut.RESET_UPDATED_FEEDBACK))
this.$store.commit(subNotesNamespace(subNotesMut.SET_ORIG_FEEDBACK), feedback)
SubmissionNotes.RESET_UPDATED_FEEDBACK()
SubmissionNotes.SET_ORIG_FEEDBACK(feedback)
this.$emit('feedbackCreated')
}).catch(err => {
this.$notify({
......@@ -145,16 +144,16 @@ export default {
shortPollOrigFeedback () {
this.feedbackShortPollInterval = setInterval(() => {
if (this.feedbackObj && this.feedbackObj.ofSubmission) {
this.$store.dispatch('getFeedback', {ofSubmission: this.feedbackObj.ofSubmission}).then(feedback => {
this.$store.commit(subNotesNamespace(subNotesMut.SET_ORIG_FEEDBACK), feedback)
actions.getFeedback({ofSubmission: this.feedbackObj.ofSubmission}).then(feedback => {
SubmissionNotes.SET_ORIG_FEEDBACK(feedback)
})
}
}, 5e3)
},
init () {
this.$store.commit(subNotesNamespace(subNotesMut.RESET_STATE))
this.$store.commit(subNotesNamespace(subNotesMut.SET_SUBMISSION), this.submissionObj)
this.$store.commit(subNotesNamespace(subNotesMut.SET_ORIG_FEEDBACK), this.feedbackObj)
SubmissionNotes.RESET_STATE()
SubmissionNotes.SET_SUBMISSION(this.submissionObj)
SubmissionNotes.SET_ORIG_FEEDBACK(this.feedbackObj)
}
},
watch: {
......
......@@ -19,7 +19,7 @@
</template>
<script>
import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
export default {
name: 'comment-form',
......@@ -48,7 +48,7 @@ export default {
this.$emit('collapseFeedbackForm')
},
submitFeedback () {
this.$store.commit(subNotesNamespace(subNotesMut.UPDATE_FEEDBACK_LINE), {
SubmissionNotes.UPDATE_FEEDBACK_LINE({
lineNo: this.lineNo,
comment: {
text: this.currentFeedback
......
......@@ -38,7 +38,7 @@
<script>
import {mapState} from 'vuex'
import {UI} from '@/store/modules/ui'
import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
export default {
name: 'feedback-comment',
......@@ -77,9 +77,7 @@ export default {
}
},
computed: {
...mapState({
markedForDeletion: state => state.submissionNotes.commentsMarkedForDeletion
}),
markedForDeletion () { return SubmissionNotes.state.commentsMarkedForDeletion },
parsedCreated () {
if (this.created) {
return new Date(this.created).toLocaleString()
......@@ -101,12 +99,12 @@ export default {
toggleDeleteComment () {
if (this.pk) {
if (!this.markedForDeletion.hasOwnProperty(this.pk)) {
this.$store.commit(subNotesNamespace(subNotesMut.MARK_COMMENT_FOR_DELETION), {pk: this.pk})
SubmissionNotes.MARK_COMMENT_FOR_DELETION({pk: this.pk})
} else {
this.$store.commit(subNotesNamespace(subNotesMut.UN_MARK_COMMENT_FOR_DELETION), {pk: this.pk})
SubmissionNotes.UN_MARK_COMMENT_FOR_DELETION({pk: this.pk})
}
}
this.$store.commit(subNotesNamespace(subNotesMut.DELETE_FEEDBACK_LINE), this.lineNo)
SubmissionNotes.DELETE_FEEDBACK_LINE(this.lineNo)
}
}
}
......
......@@ -54,9 +54,9 @@
</template>
<script>
import {subNotesMut, subNotesNamespace} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
import {Authentication} from '@/store/modules/authentication'
import { Subscriptions } from '@/store/modules/subscriptions';
import { Subscriptions } from '@/store/modules/subscriptions'
export default {
name: 'annotated-submission-bottom-toolbar',
......@@ -87,14 +87,14 @@ export default {
computed: {
score: {
get: function () {
return this.$store.getters['submissionNotes/score']
return SubmissionNotes.score
},
set: function (score) {
this.$store.commit(subNotesNamespace(subNotesMut.UPDATE_FEEDBACK_SCORE), Number(score))
SubmissionNotes.UPDATE_FEEDBACK_SCORE(Number(score))
}
},
showFinalCheckbox () {
return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
return !SubmissionNotes.isFeedbackCreation || Authentication.isReviewer
}
},
watch: {
......@@ -108,12 +108,12 @@ export default {
methods: {
initialFinalStatus () {
if (this.$route.name === 'subscription') {
return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
return !SubmissionNotes.isFeedbackCreation || Authentication.isReviewer
} else {
if (this.feedback.hasOwnProperty('isFinal')) {
return this.feedback.isFinal
} else {
return !this.$store.getters['submissionNotes/isFeedbackCreation'] || Authentication.isReviewer
return !SubmissionNotes.isFeedbackCreation || Authentication.isReviewer
}
}
},
......
......@@ -6,16 +6,15 @@
</template>
<script>
import {subNotesMut} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
import {createComputedGetterSetter} from '@/util/helpers'
export default {
name: 'toggle-feedback-visibility-button',
computed: {
showFeedback: createComputedGetterSetter({
path: 'submissionNotes.ui.showFeedback',
mutation: subNotesMut.SET_SHOW_FEEDBACK,
namespace: 'submissionNotes'
path: 'SubmissionNotes.ui.showFeedback',
mutation: SubmissionNotes.SET_SHOW_FEEDBACK
})
}
}
......
......@@ -30,7 +30,7 @@
<script>
import {Authentication} from '@/store/modules/authentication'
import { Subscriptions } from '@/store/modules/subscriptions';
import { Subscriptions } from '@/store/modules/subscriptions'
const stages = [
{
......
......@@ -21,7 +21,7 @@
<script lang="ts">
import {Vue, Component, Prop} from 'vue-property-decorator'
import {Assignment, Subscription} from '@/models'
import { Subscriptions } from '@/store/modules/subscriptions';
import { Subscriptions } from '@/store/modules/subscriptions'
@Component
export default class SubscriptionForList extends Vue {
......
......@@ -14,7 +14,7 @@
<script>
import SubscriptionForList from '@/components/subscriptions/SubscriptionForList'
import { Subscriptions } from '@/store/modules/subscriptions';
import { Subscriptions } from '@/store/modules/subscriptions'
export default {
components: {
SubscriptionForList
......
......@@ -60,7 +60,7 @@ import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnno
import SubmissionLine from '@/components/submission_notes/base/SubmissionLine'
import FeedbackComment from '@/components/submission_notes/base/FeedbackComment'
import {studentPageMut} from '@/store/modules/student-page'
import {subNotesMut} from '@/store/modules/submission-notes'
import {SubmissionNotes} from '@/store/modules/submission-notes'
import ToggleFeedbackVisibilityButton from '@/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton'
import SubmissionTests from '@/components/SubmissionTests'
import NonFinalFeedbackAlert from '@/components/student/NonFinalFeedbackAlert'
......@@ -80,24 +80,22 @@ export default {
id: function () {
return this.$route.params.id
},
...mapGetters('submissionNotes', [
'submission'
]),
submission () { return SubmissionNotes.submission },
...mapState({
submissionType (state) { return state.studentPage.submissionData[this.id].type },
feedback (state) {
return state.studentPage.submissionData[this.$route.params.id].feedback
},
showFeedback: function (state) {
return state.submissionNotes.ui.showFeedback
return SubmissionNotes.state.ui.showFeedback
}
})
},
methods: {
onRouteMountOrUpdate (routeId) {
this.$store.commit(studentPageMut.SET_VISITED, { index: routeId, visited: true })
this.$store.commit('submissionNotes/' + subNotesMut.SET_SUBMISSION,
this.$store.state.studentPage.submissionData[this.id])
// TODO this seems fishy and there probably is the student page bug in here
SubmissionNotes.SET_SUBMISSION(this.$store.state.studentPage.submissionData[this.id])
}
},
mounted () {
......
import { ActionContext } from "vuex";
import { BareActionContext, getStoreBuilder } from "vuex-typex";
import { ActionContext } from 'vuex'
import { BareActionContext, getStoreBuilder } from 'vuex-typex'
import { mutations as mut } from "./mutations";
import { Authentication } from "@/store/modules/authentication";
import { subNotesMut } from "@/store/modules/submission-notes";
import * as api from "@/api";
import router from "@/router/index";
import { RootState } from "@/store/store";
import { FeedbackTable } from '@/store/modules/feedback_list/feedback-table';
import { Subscriptions } from '@/store/modules/subscriptions';
import { mutations as mut } from './mutations'
import { Authentication } from '@/store/modules/authentication'
import { SubmissionNotes } from '@/store/modules/submission-notes'
import * as api from '@/api'
import router from '@/router/index'
import { RootState } from '@/store/store'
import { FeedbackTable } from '@/store/modules/feedback_list/feedback-table'
import { Subscriptions } from '@/store/modules/subscriptions'
async function getExamTypes(context: BareActionContext<RootState, RootState>) {
const examTypes = await api.fetchExamTypes({});
mut.SET_EXAM_TYPES(examTypes);
const examTypes = await api.fetchExamTypes({})
mut.SET_EXAM_TYPES(examTypes)
}
async function updateSubmissionTypes(
context: BareActionContext<RootState, RootState>,
fields: Array<string> = []
) {
const submissionTypes = await api.fetchSubmissionTypes(fields);
const submissionTypes = await api.fetchSubmissionTypes(fields)
submissionTypes.forEach(type => {
mut.UPDATE_SUBMISSION_TYPE(type);
});
mut.UPDATE_SUBMISSION_TYPE(type)
})
}
async function getStudents(
context: BareActionContext<RootState, RootState>,
opt: { studentPks: Array<string>; fields: Array<string> } = {
opt: { studentPks: Array<string>, fields: Array<string> } = {
studentPks: [],
fields: []
}
) {
if (opt.studentPks.length === 0) {
const students = await api.fetchAllStudents();
mut.SET_STUDENTS(students);
return students;
const students = await api.fetchAllStudents()
mut.SET_STUDENTS(students)
return students
} else {
const students = await Promise.all(
opt.studentPks.map((pk: string) =>
......@@ -42,33 +42,33 @@ async function getStudents(
fields: opt.fields
})
)
);
students.forEach(student => mut.SET_STUDENT(student));
return students;
)
students.forEach(student => mut.SET_STUDENT(student))
return students
}
}
async function getTutors() {
const tutors = await api.fetchAllTutors();
mut.SET_TUTORS(tutors);
const tutors = await api.fetchAllTutors()
mut.SET_TUTORS(tutors)
}
async function getFeedback(
context: BareActionContext<RootState, RootState>,
fetchFeedbackArg: { ofSubmission: string }
) {
const feedback = await api.fetchFeedback(fetchFeedbackArg);
mut.SET_FEEDBACK(feedback);
return feedback;
const feedback = await api.fetchFeedback(fetchFeedbackArg)
mut.SET_FEEDBACK(feedback)
return feedback
}
async function getSubmissionFeedbackTest(
context: BareActionContext<RootState, RootState>,
submissionPkObj: { pk: string }
) {
const submission = await api.fetchSubmissionFeedbackTests(submissionPkObj);
mut.SET_SUBMISSION(submission);
const submission = await api.fetchSubmissionFeedbackTests(submissionPkObj)
mut.SET_SUBMISSION(submission)
}
async function getStatistics() {
const statistics = await api.fetchStatistics();
mut.SET_STATISTICS(statistics);
const statistics = await api.fetchStatistics()
mut.SET_STATISTICS(statistics)
}
function logout(
context: BareActionContext<RootState, RootState>,
......@@ -78,23 +78,23 @@ function logout(
// TODO there has to be a better way
const { commit, getters, state } = <ActionContext<RootState, RootState>>(
context
);
)
if (Authentication.isStudent) {
// change active to false when user logs out
// TODO this should belong in auth module
api.changeActiveForUser(Authentication.state.user.pk, false);
api.changeActiveForUser(Authentication.state.user.pk, false)
}
mut.RESET_STATE();
mut.RESET_STATE()
FeedbackTable.RESET_STATE()
Authentication.RESET_STATE()
Subscriptions.RESET_STATE()
commit("submissionNotes/" + subNotesMut.RESET_STATE);
Authentication.SET_MESSAGE(message);
router.push({ name: "login" });
router.go(0);
SubmissionNotes.RESET_STATE()
Authentication.SET_MESSAGE(message)
router.push({ name: "login" })
router.go(0)
}
const mb = getStoreBuilder<RootState>();
const mb = getStoreBuilder<RootState>()
export const actions = {
updateSubmissionTypes: mb.dispatch(updateSubmissionTypes),
......@@ -105,4 +105,4 @@ export const actions = {
getSubmissionFeedbackTest: mb.dispatch(getSubmissionFeedbackTest),
getStatistics: mb.dispatch(getStatistics),
logout: mb.dispatch(logout)
};
}
......@@ -5,24 +5,11 @@ import {nameSpacer} from '@/util/helpers'
import {Feedback, FeedbackComment, Submission, SubmissionNoType} from '@/models'
import {RootState} from '@/store/store'
import {Module} from 'vuex'
import { getStoreBuilder, BareActionContext } from 'vuex-typex'
export const subNotesNamespace = nameSpacer('submissionNotes/')
export const subNotesMut = Object.freeze({
SET_SUBMISSION: 'SET_SUBMISSION',
SET_ORIG_FEEDBACK: 'SET_ORIG_FEEDBACK',
SET_SHOW_FEEDBACK: 'SET_SHOW_FEEDBACK',
UPDATE_FEEDBACK_LINE: 'UPDATE_FEEDBACK_LINE',
UPDATE_FEEDBACK_SCORE: 'UPDATE_FEEDBACK_SCORE',
DELETE_FEEDBACK_LINE: 'DELETE_FEEDBACK_LINE',
TOGGLE_EDITOR_ON_LINE: 'TOGGLE_EDITOR_ON_LINE',
MARK_COMMENT_FOR_DELETION: 'MARK_COMMENT_FOR_DELETION',
UN_MARK_COMMENT_FOR_DELETION: 'UN_MARK_COMMENT_FOR_DELETION',
RESET_UPDATED_FEEDBACK: 'RESET_UPDATED_FEEDBACK',
RESET_STATE: 'RESET_STATE'
})
interface SubmissionNotesState {
export interface SubmissionNotesState {
submission: SubmissionNoType
ui: {
showEditorOnLine: {[lineNo: number]: boolean}
......@@ -64,114 +51,133 @@ function initialState (): SubmissionNotesState {
}
}
const submissionNotes: Module<SubmissionNotesState, RootState> = {
namespaced: true,
state: initialState(),
getters: {
submissionType: (state, getters, rootState) => {
return rootState.submissionTypes[state.submission.type]
},
// highlight the submission the reduce the string
// submission.text into an object where the keys are the
// line indexes starting at one and the values the corresponding submission line
// this makes iterating over the submission much more pleasant
submission: (state, getters) => {
const language = getters.submissionType
? getters.submissionType.programmingLanguage
: 'c'
const highlighted = hljs.highlight(language, state.submission.text || '', true).value
return highlighted.split('\n').reduce((acc: {[k: number]: string}, cur, index) => {
acc[index + 1] = cur
return acc
}, {})
},
score: state => {
return state.updatedFeedback.score !== undefined ? state.updatedFeedback.score : state.origFeedback.score
},
workInProgress: state => {
const openEditor = Object.values(state.ui.showEditorOnLine).reduce((acc, curr) => acc || curr, false)
const feedbackWritten = Object.entries(state.updatedFeedback.feedbackLines || {}).length > 0
return openEditor || feedbackWritten
},
isFeedbackCreation: state => {
return !state.origFeedback['feedbackStageForUser'] ||
state.origFeedback['feedbackStageForUser'] === 'feedback-creation'
}
},
mutations: {
[subNotesMut.SET_SUBMISSION]: function (state, submission: SubmissionNoType) {
state.submission = submission
},
[subNotesMut.SET_ORIG_FEEDBACK]: function (state, feedback: Feedback) {
if (feedback) {
state.origFeedback = feedback
state.hasOrigFeedback = true
}
},
[subNotesMut.SET_SHOW_FEEDBACK]: function (state, val: boolean) {
state.ui.showFeedback = val
},
[subNotesMut.UPDATE_FEEDBACK_LINE]: function (state, feedback: {lineNo: number, comment: Partial<FeedbackComment>}) {
// explicit .toString() on lineNo is necessary because of Vue.set typings
if (state.updatedFeedback.feedbackLines) {
Vue.set(state.updatedFeedback.feedbackLines, feedback.lineNo.toString(), feedback.comment)
}
},
[subNotesMut.UPDATE_FEEDBACK_SCORE]: function (state, score) {
state.updatedFeedback.score = score
},
[subNotesMut.DELETE_FEEDBACK_LINE]: function (state, lineNo) {
if (state.updatedFeedback.feedbackLines) {
Vue.delete(state.updatedFeedback.feedbackLines, lineNo)
}
},
[subNotesMut.TOGGLE_EDITOR_ON_LINE]: function (state, {lineNo, comment}) {
Vue.set(state.ui.selectedCommentOnLine, lineNo, comment)
Vue.set(state.ui.showEditorOnLine, lineNo, !state.ui.showEditorOnLine[lineNo])
},
[subNotesMut.MARK_COMMENT_FOR_DELETION]: function (state, comment) {
Vue.set(state.commentsMarkedForDeletion, comment.pk, comment)
},
[subNotesMut.UN_MARK_COMMENT_FOR_DELETION]: function (state, comment) {
Vue.delete(state.commentsMarkedForDeletion, comment.pk)
},
[subNotesMut.RESET_UPDATED_FEEDBACK]: function (state) {
state.updatedFeedback = initialState().updatedFeedback
},
[subNotesMut.RESET_STATE]: function (state) {
Object.assign(state, initialState())
}
},
actions: {
deleteComments: async function ({state}) {
return Promise.all(
Object.values(state.commentsMarkedForDeletion).map(comment => {
return api.deleteComment(comment)
})
)
},
submitFeedback: async function ({state, dispatch, getters}, {isFinal = false}) {
let feedback: Partial<Feedback> = {
isFinal: isFinal,
ofSubmission: state.submission.pk
}
if (Object.keys(state.updatedFeedback.feedbackLines || {}).length > 0) {
feedback.feedbackLines = state.updatedFeedback.feedbackLines
}
if (state.origFeedback.score === undefined && state.updatedFeedback.score === undefined) {
throw new Error('You need to give a score.')
} else if (state.updatedFeedback.score !== undefined) {
feedback.score = state.updatedFeedback.score
}
await dispatch('deleteComments')
if (!state.hasOrigFeedback) {
return api.submitFeedbackForAssignment({feedback})
} else {
feedback.pk = state.origFeedback.pk
return api.submitUpdatedFeedback(<{feedback: Feedback}> {feedback})
}
}
const mb = getStoreBuilder<RootState>().module('SubmissionNotes', initialState())
const stateGetter = mb.state()
const submissionTypeGetter = mb.read(function submissionType (state, getters, rootState) {
return rootState.submissionTypes[state.submission.type]
})
// highlight the submission the reduce the string
// submission.text into an object where the keys are the
// line indexes starting at one and the values the corresponding submission line
// this makes iterating over the submission much more pleasant
const submissionGetter = mb.read(function submission (state, getters) {
const language = getters.submissionType
? getters.submissionType.programmingLanguage
: 'c'
const highlighted = hljs.highlight(language, state.submission.text || '', true).value
return highlighted.split('\n').reduce((acc: {[k: number]: string}, cur, index) => {
acc[index + 1] = cur
return acc
}, {})
})
const scoreGetter = mb.read(function score (state) {
return state.updatedFeedback.score !== undefined ? state.updatedFeedback.score : state.origFeedback.score
})
const workInProgressGetter = mb.read(function workInProgress (state) {
const openEditor = Object.values(state.ui.showEditorOnLine).reduce((acc, curr) => acc || curr, false)
const feedbackWritten = Object.entries(state.updatedFeedback.feedbackLines || {}).length > 0
return openEditor || feedbackWritten
})
const isFeedbackCreationGetter = mb.read(function isFeedbackCreation (state) {
return !state.origFeedback['feedbackStageForUser'] ||
state.origFeedback['feedbackStageForUser'] === 'feedback-creation'
})
function SET_SUBMISSION (state: SubmissionNotesState, submission: SubmissionNoType) {
state.submission = submission
}
function SET_ORIG_FEEDBACK (state: SubmissionNotesState, feedback: Feedback) {
if (feedback) {
state.origFeedback = feedback
state.hasOrigFeedback = true
}
}
function SET_SHOW_FEEDBACK (state: SubmissionNotesState, val: boolean) {
state.ui.showFeedback = val
}
function UPDATE_FEEDBACK_LINE (state: SubmissionNotesState, feedback: {lineNo: number, comment: Partial<FeedbackComment>}) {
// explicit .toString() on lineNo is necessary because of Vue.set typings
if (state.updatedFeedback.feedbackLines) {
Vue.set(state.updatedFeedback.feedbackLines, feedback.lineNo.toString(), feedback.comment)
}
}
function UPDATE_FEEDBACK_SCORE (state: SubmissionNotesState, score: number) {
state.updatedFeedback.score = score
}
function DELETE_FEEDBACK_LINE (state: SubmissionNotesState, lineNo: number) {
if (state.updatedFeedback.feedbackLines) {
// Vue dosn't like objects that are indexed with numbers...
Vue.delete(state.updatedFeedback.feedbackLines, <string><any>lineNo)
}
}
function TOGGLE_EDITOR_ON_LINE (state: SubmissionNotesState, {lineNo, comment}: {lineNo: number, comment: FeedbackComment}) {
Vue.set(state.ui.selectedCommentOnLine, <string><any>lineNo, comment)
Vue.set(state.ui.showEditorOnLine, <string><any> lineNo, !state.ui.showEditorOnLine[lineNo])
}
function MARK_COMMENT_FOR_DELETION (state: SubmissionNotesState, comment: FeedbackComment) {
Vue.set(state.commentsMarkedForDeletion, comment.pk, comment)
}
function UN_MARK_COMMENT_FOR_DELETION (state: SubmissionNotesState, comment: FeedbackComment) {
Vue.delete(state.commentsMarkedForDeletion, comment.pk)
}
function RESET_UPDATED_FEEDBACK (state: SubmissionNotesState) {
state.updatedFeedback = initialState().updatedFeedback
}
function RESET_STATE (state: SubmissionNotesState) {
Object.assign(state, initialState())
}
async function deleteComments ({state}: BareActionContext<SubmissionNotesState, RootState>) {
return Promise.all(
Object.values(state.commentsMarkedForDeletion).map(comment => {
return api.deleteComment(comment)
})
)
}
async function submitFeedback ({state}: BareActionContext<SubmissionNotesState, RootState>, {isFinal = false}) {
let feedback: Partial<Feedback> = {
isFinal: isFinal,
ofSubmission: state.submission.pk
}
if (Object.keys(state.updatedFeedback.feedbackLines || {}).length > 0) {
feedback.feedbackLines = state.updatedFeedback.feedbackLines
}
if (state.origFeedback.score === undefined && state.updatedFeedback.score === undefined) {
throw new Error('You need to give a score.')
} else if (state.updatedFeedback.score !== undefined) {
feedback.score = state.updatedFeedback.score
}
await SubmissionNotes.deleteComments()
if (!state.hasOrigFeedback) {
return api.submitFeedbackForAssignment({feedback})
} else {
feedback.pk = state.origFeedback.pk
return api.submitUpdatedFeedback(<{feedback: Feedback}> {feedback})
}
}
export default submissionNotes
export const SubmissionNotes = {
get state () { return stateGetter() },
get submissionType () { return submissionTypeGetter() },
get submission () { return submissionGetter() },
get score () { return scoreGetter() },
get workInProgress () { return workInProgressGetter() },
get isFeedbackCreation () { return isFeedbackCreationGetter() },
SET_SUBMISSION: mb.commit(SET_SUBMISSION),
SET_ORIG_FEEDBACK: mb.commit(SET_ORIG_FEEDBACK),
SET_SHOW_FEEDBACK: mb.commit(SET_SHOW_FEEDBACK),
UPDATE_FEEDBACK_LINE: mb.commit(UPDATE_FEEDBACK_LINE),
UPDATE_FEEDBACK_SCORE: mb.commit(UPDATE_FEEDBACK_SCORE),
DELETE_FEEDBACK_LINE: mb.commit(DELETE_FEEDBACK_LINE),
TOGGLE_EDITOR_ON_LINE: mb.commit(TOGGLE_EDITOR_ON_LINE),
MARK_COMMENT_FOR_DELETION: mb.commit(MARK_COMMENT_FOR_DELETION),
UN_MARK_COMMENT_FOR_DELETION: mb.commit(UN_MARK_COMMENT_FOR_DELETION),
RESET_UPDATED_FEEDBACK: mb.commit(RESET_UPDATED_FEEDBACK),
RESET_STATE: mb.commit(RESET_STATE),
deleteComments: mb.dispatch(deleteComments),
submitFeedback: mb.dispatch(submitFeedback)
}
......@@ -4,13 +4,13 @@ import createPersistedState from 'vuex-persistedstate'
import {getStoreBuilder} from 'vuex-typex'
import studentPage from './modules/student-page'
import submissionNotes from './modules/submission-notes'
import './modules/ui'
import './modules/authentication'
import './modules/feedback_list/feedback-search-options'
import './modules/feedback_list/feedback-table'
import './modules/subscriptions'
import './modules/submission-notes'
import './mutations'
import './actions'
......@@ -22,6 +22,7 @@ import {AuthState} from './modules/authentication'
import {FeedbackSearchOptionsState, FeedbackSearchOptions} from './modules/feedback_list/feedback-search-options'
import {Subscriptions, SubscriptionsState} from './modules/subscriptions'
import {FeedbackTableState, FeedbackTable} from './modules/feedback_list/feedback-table'
import { SubmissionNotesState } from './modules/submission-notes'
import {lastInteraction} from '@/store/plugins/lastInteractionPlugin'
import {
......@@ -51,7 +52,8 @@ export interface RootState extends RootInitialState{
Authentication: AuthState,
FeedbackSearchOptions: FeedbackSearchOptionsState,
FeedbackTable: FeedbackTableState,
Subscriptions: SubscriptionsState
Subscriptions: SubscriptionsState,
SubmissionNotes: SubmissionNotesState
}
export function initialState (): RootInitialState {
......@@ -78,8 +80,7 @@ export const persistedStateKey = 'grady'
const store = getStoreBuilder<RootState>().vuexStore({
strict: process.env.NODE_ENV === 'development',
modules: {
studentPage,
submissionNotes
studentPage
},
plugins: [
createPersistedState({
......
import {AxiosError} from "axios";
import {Dispatch} from "vuex";
import {MutationHandler} from "vuex-typex";
import {AxiosError} from "axios"
import {Dispatch} from "vuex"
import {MutationHandler} from "vuex-typex"
export function nameSpacer (namespace: string) {
return function (commitType: string) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment