Finish refactoring the Assignment component

This commit is contained in:
Ramon Wenger 2024-03-13 14:43:20 +01:00
parent cfb20c00c3
commit 8cd508ce31
22 changed files with 372 additions and 192 deletions

View File

@ -23,6 +23,8 @@ const documents = {
"\n fragment AssignmentParts on AssignmentNode {\n id\n title\n assignment\n solution\n submission {\n ...SubmissionParts\n }\n }\n": types.AssignmentPartsFragmentDoc, "\n fragment AssignmentParts on AssignmentNode {\n id\n title\n assignment\n solution\n submission {\n ...SubmissionParts\n }\n }\n": types.AssignmentPartsFragmentDoc,
"\n query AssignmentQuery($id: ID!) {\n assignment(id: $id) {\n ...AssignmentParts\n }\n }\n ": types.AssignmentQueryDocument, "\n query AssignmentQuery($id: ID!) {\n assignment(id: $id) {\n ...AssignmentParts\n }\n }\n ": types.AssignmentQueryDocument,
"\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n ": types.UpdateAssignmentDocument, "\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n ": types.UpdateAssignmentDocument,
"\n mutation UpdateAssignmentWithSuccess($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n successful\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n ": types.UpdateAssignmentWithSuccessDocument,
"\n mutation SpellCheck($input: SpellCheckInput!) {\n spellCheck(input: $input) {\n correct\n results {\n sentence\n offset\n sentenceOffset\n length\n affected\n corrected\n }\n }\n }\n ": types.SpellCheckDocument,
"\n fragment ModuleHighlightsFragment on ModuleNode {\n id\n __typename\n slug\n highlights {\n ...HighlightParts\n }\n }\n": types.ModuleHighlightsFragmentFragmentDoc, "\n fragment ModuleHighlightsFragment on ModuleNode {\n id\n __typename\n slug\n highlights {\n ...HighlightParts\n }\n }\n": types.ModuleHighlightsFragmentFragmentDoc,
"\n fragment ModuleLevelFragment on ModuleLevelNode {\n name\n id\n filterAttributeType\n }\n": types.ModuleLevelFragmentFragmentDoc, "\n fragment ModuleLevelFragment on ModuleLevelNode {\n name\n id\n filterAttributeType\n }\n": types.ModuleLevelFragmentFragmentDoc,
"\n query ModuleFilterQuery {\n moduleLevels {\n ...ModuleLevelFragment\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n ": types.ModuleFilterQueryDocument, "\n query ModuleFilterQuery {\n moduleLevels {\n ...ModuleLevelFragment\n }\n moduleCategories {\n name\n id\n filterAttributeType\n }\n me {\n language @client\n }\n }\n ": types.ModuleFilterQueryDocument,
@ -36,6 +38,11 @@ const documents = {
"\n mutation UpdateHighlight($input: UpdateHighlightInput!) {\n updateHighlight(input: $input) {\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.UpdateHighlightDocument, "\n mutation UpdateHighlight($input: UpdateHighlightInput!) {\n updateHighlight(input: $input) {\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.UpdateHighlightDocument,
"\n mutation AddHighlight($input: AddHighlightInput!) {\n addHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.AddHighlightDocument, "\n mutation AddHighlight($input: AddHighlightInput!) {\n addHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.AddHighlightDocument,
"\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.AddContentHighlightDocument, "\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n": types.AddContentHighlightDocument,
"\n fragment SchoolClassParts on SchoolClassNode {\n id\n name\n }\n": types.SchoolClassPartsFragmentDoc,
"\n fragment UserParts on PrivateUserNode {\n id\n pk\n username\n email\n firstName\n lastName\n avatarUrl\n expiryDate\n readOnly\n lastModuleLevel {\n id\n name\n filterAttributeType\n }\n lastModule {\n id\n slug\n }\n lastTopic {\n id\n slug\n }\n selectedClass {\n id\n readOnly\n }\n recentModules(orderBy: \"-visited\") {\n edges {\n node {\n ...ModuleParts\n }\n }\n }\n schoolClasses {\n ...SchoolClassParts\n }\n }\n": types.UserPartsFragmentDoc,
"\n fragment TeamParts on TeamNode {\n name\n code\n id\n members {\n firstName\n lastName\n id\n isMe\n }\n }\n": types.TeamPartsFragmentDoc,
"\n fragment ModuleParts on ModuleNode {\n id\n title\n metaTitle\n teaser\n intro\n slug\n heroImage\n heroSource\n solutionsEnabled\n highlights {\n ...HighlightParts\n }\n language\n inEditMode @client\n level {\n id\n name\n }\n category {\n id\n name\n }\n topic {\n slug\n title\n }\n bookmark {\n note {\n id\n text\n }\n }\n }\n": types.ModulePartsFragmentDoc,
"\n query MeQuery {\n me {\n ...UserParts\n team {\n ...TeamParts\n }\n isTeacher\n permissions\n onboardingVisited\n }\n }\n ": types.MeQueryDocument,
"\n fragment InstrumentHighlightsWithIdOnlyFragment on InstrumentNode {\n highlights {\n id\n }\n }\n ": types.InstrumentHighlightsWithIdOnlyFragmentFragmentDoc, "\n fragment InstrumentHighlightsWithIdOnlyFragment on InstrumentNode {\n highlights {\n id\n }\n }\n ": types.InstrumentHighlightsWithIdOnlyFragmentFragmentDoc,
"\n fragment ChapterHighlightsWithIdOnlyFragment on ChapterNode {\n highlights {\n id\n }\n }\n ": types.ChapterHighlightsWithIdOnlyFragmentFragmentDoc, "\n fragment ChapterHighlightsWithIdOnlyFragment on ChapterNode {\n highlights {\n id\n }\n }\n ": types.ChapterHighlightsWithIdOnlyFragmentFragmentDoc,
"\n fragment ModuleHighlightsWithIdOnlyFragment on ModuleNode {\n highlights {\n id\n }\n }\n ": types.ModuleHighlightsWithIdOnlyFragmentFragmentDoc, "\n fragment ModuleHighlightsWithIdOnlyFragment on ModuleNode {\n highlights {\n id\n }\n }\n ": types.ModuleHighlightsWithIdOnlyFragmentFragmentDoc,
@ -107,6 +114,14 @@ export function graphql(source: "\n query AssignmentQuery($id: ID!) {\n
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "): (typeof documents)["\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "]; export function graphql(source: "\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "): (typeof documents)["\n mutation UpdateAssignment($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpdateAssignmentWithSuccess($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n successful\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "): (typeof documents)["\n mutation UpdateAssignmentWithSuccess($input: UpdateAssignmentInput!) {\n updateAssignment(input: $input) {\n successful\n updatedAssignment {\n ...AssignmentParts\n }\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation SpellCheck($input: SpellCheckInput!) {\n spellCheck(input: $input) {\n correct\n results {\n sentence\n offset\n sentenceOffset\n length\n affected\n corrected\n }\n }\n }\n "): (typeof documents)["\n mutation SpellCheck($input: SpellCheckInput!) {\n spellCheck(input: $input) {\n correct\n results {\n sentence\n offset\n sentenceOffset\n length\n affected\n corrected\n }\n }\n }\n "];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
@ -159,6 +174,26 @@ export function graphql(source: "\n mutation AddHighlight($input: AddHighlightI
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n"): (typeof documents)["\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n"]; export function graphql(source: "\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n"): (typeof documents)["\n mutation AddContentHighlight($input: AddContentHighlightInput!) {\n addContentHighlight(input: $input) {\n __typename\n highlight {\n ...HighlightParts\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment SchoolClassParts on SchoolClassNode {\n id\n name\n }\n"): (typeof documents)["\n fragment SchoolClassParts on SchoolClassNode {\n id\n name\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment UserParts on PrivateUserNode {\n id\n pk\n username\n email\n firstName\n lastName\n avatarUrl\n expiryDate\n readOnly\n lastModuleLevel {\n id\n name\n filterAttributeType\n }\n lastModule {\n id\n slug\n }\n lastTopic {\n id\n slug\n }\n selectedClass {\n id\n readOnly\n }\n recentModules(orderBy: \"-visited\") {\n edges {\n node {\n ...ModuleParts\n }\n }\n }\n schoolClasses {\n ...SchoolClassParts\n }\n }\n"): (typeof documents)["\n fragment UserParts on PrivateUserNode {\n id\n pk\n username\n email\n firstName\n lastName\n avatarUrl\n expiryDate\n readOnly\n lastModuleLevel {\n id\n name\n filterAttributeType\n }\n lastModule {\n id\n slug\n }\n lastTopic {\n id\n slug\n }\n selectedClass {\n id\n readOnly\n }\n recentModules(orderBy: \"-visited\") {\n edges {\n node {\n ...ModuleParts\n }\n }\n }\n schoolClasses {\n ...SchoolClassParts\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment TeamParts on TeamNode {\n name\n code\n id\n members {\n firstName\n lastName\n id\n isMe\n }\n }\n"): (typeof documents)["\n fragment TeamParts on TeamNode {\n name\n code\n id\n members {\n firstName\n lastName\n id\n isMe\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment ModuleParts on ModuleNode {\n id\n title\n metaTitle\n teaser\n intro\n slug\n heroImage\n heroSource\n solutionsEnabled\n highlights {\n ...HighlightParts\n }\n language\n inEditMode @client\n level {\n id\n name\n }\n category {\n id\n name\n }\n topic {\n slug\n title\n }\n bookmark {\n note {\n id\n text\n }\n }\n }\n"): (typeof documents)["\n fragment ModuleParts on ModuleNode {\n id\n title\n metaTitle\n teaser\n intro\n slug\n heroImage\n heroSource\n solutionsEnabled\n highlights {\n ...HighlightParts\n }\n language\n inEditMode @client\n level {\n id\n name\n }\n category {\n id\n name\n }\n topic {\n slug\n title\n }\n bookmark {\n note {\n id\n text\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query MeQuery {\n me {\n ...UserParts\n team {\n ...TeamParts\n }\n isTeacher\n permissions\n onboardingVisited\n }\n }\n "): (typeof documents)["\n query MeQuery {\n me {\n ...UserParts\n team {\n ...TeamParts\n }\n isTeacher\n permissions\n onboardingVisited\n }\n }\n "];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

File diff suppressed because one or more lines are too long

View File

@ -58,13 +58,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue'; import { defineAsyncComponent, nextTick, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useMutation, useQuery } from '@vue/apollo-composable'; import { useMutation, useQuery } from '@vue/apollo-composable';
import { graphql } from '@/__generated__'; import { graphql } from '@/__generated__';
import { HighlightNode } from '@/__generated__/graphql'; import { HighlightNode } from '@/__generated__/graphql';
import { computed } from '@vue/reactivity'; import { computed } from '@vue/reactivity';
import { markHighlight } from '@/helpers/highlight'; import { markHighlight } from '@/helpers/highlight';
import { sanitize } from '@/helpers/text';
import { matomoTrackEvent } from '@/helpers/matomo-client';
import { getMe } from '@/graphql/queries';
import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts';
import debounce from 'lodash/debounce';
import Mark from 'mark.js'; import Mark from 'mark.js';
export interface Props { export interface Props {
@ -72,6 +77,10 @@ export interface Props {
highlights: HighlightNode[]; highlights: HighlightNode[];
} }
const SubmissionForm = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SubmissionForm.vue'));
const Solution = defineAsyncComponent(() => import('@/components/content-blocks/Solution.vue'));
const SpellCheck = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SpellCheck.vue'));
const route = useRoute(); const route = useRoute();
const assignmentDiv = ref<HTMLElement | null>(null); const assignmentDiv = ref<HTMLElement | null>(null);
@ -84,6 +93,9 @@ const initialSubmission = {
}; };
const assignment = ref({ submission: initialSubmission }); const assignment = ref({ submission: initialSubmission });
const corrections = ref(''); const corrections = ref('');
const unsaved = ref(false);
const saving = ref(0);
const spellcheckLoading = ref(false);
graphql(` graphql(`
fragment SubmissionParts on StudentSubmissionNode { fragment SubmissionParts on StudentSubmissionNode {
@ -102,7 +114,7 @@ graphql(`
} }
`); `);
graphql(` const assignmentFragment = graphql(`
fragment AssignmentParts on AssignmentNode { fragment AssignmentParts on AssignmentNode {
id id
title title
@ -114,6 +126,8 @@ graphql(`
} }
`); `);
const { me } = getMe();
const { result, onResult } = useQuery( const { result, onResult } = useQuery(
graphql(` graphql(`
query AssignmentQuery($id: ID!) { query AssignmentQuery($id: ID!) {
@ -136,6 +150,35 @@ const { mutate: doUpdateAssignment } = useMutation(
} }
`) `)
); );
const { mutate: doUpdateAssignmentWithSuccess } = useMutation(
graphql(`
mutation UpdateAssignmentWithSuccess($input: UpdateAssignmentInput!) {
updateAssignment(input: $input) {
successful
updatedAssignment {
...AssignmentParts
}
}
}
`)
);
const { mutate: doSpellCheck } = useMutation(
graphql(`
mutation SpellCheck($input: SpellCheckInput!) {
spellCheck(input: $input) {
correct
results {
sentence
offset
sentenceOffset
length
affected
corrected
}
}
}
`)
);
onMounted(() => { onMounted(() => {
if (assignmentDiv.value !== null) { if (assignmentDiv.value !== null) {
@ -152,6 +195,23 @@ onMounted(() => {
} }
}); });
const submission = computed(() => {
return assignment.value?.submission || {};
});
const isStudent = computed(() => {
return !me.value.isTeacher;
});
const solution = computed(() => {
return {
text: assignment.value.solution,
};
});
const feedbackText = computed(() => {
let feedback = assignment.value.submission.submissionFeedback;
let sanitizedFeedbackText = sanitize(feedback.text);
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${sanitizedFeedbackText}`;
});
const childElements = computed(() => { const childElements = computed(() => {
// todo: refactor and merge with the one in ContentComponent.vue // todo: refactor and merge with the one in ContentComponent.vue
if (assignmentDiv.value) { if (assignmentDiv.value) {
@ -264,87 +324,20 @@ const reopen = () => {
}, },
}); });
}; };
</script> const _save = debounce(function (submission) {
saving.value++;
<script lang="ts"> const variables = {
import { mapActions, mapGetters } from 'vuex';
import ASSIGNMENT_QUERY from '@/graphql/gql/queries/assignmentQuery.gql';
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
import UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS from '@/graphql/gql/mutations/updateAssignmentMutationWithSuccess.gql';
import SPELL_CHECK_MUTATION from '@/graphql/gql/mutations/spellCheck.gql';
import debounce from 'lodash/debounce';
import { sanitize } from '@/helpers/text';
import { defineAsyncComponent } from 'vue';
import { matomoTrackEvent } from '@/helpers/matomo-client';
import { PAGE_LOAD_TIMEOUT } from '@/consts/navigation.consts';
const SubmissionForm = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SubmissionForm.vue'));
const Solution = defineAsyncComponent(() => import('@/components/content-blocks/Solution.vue'));
const SpellCheck = defineAsyncComponent(() => import('@/components/content-blocks/assignment/SpellCheck.vue'));
export default {
components: {
Solution,
SubmissionForm,
SpellCheck,
},
data() {
return {
me: {
permissions: [],
},
inputType: 'text',
unsaved: false,
saving: 0,
spellcheckLoading: false,
};
},
computed: {
...mapGetters(['scrollToAssignmentId']),
final() {
return !!this.submission && this.submission.final;
},
submission() {
return this.assignment.submission ? this.assignment.submission : {};
},
isStudent() {
return !this.me.permissions.includes('users.can_manage_school_class_content');
},
solution() {
return {
text: this.assignment.solution,
};
},
id() {
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
},
feedbackText() {
let feedback = this.assignment.submission.submissionFeedback;
let sanitizedFeedbackText = sanitize(feedback.text);
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${sanitizedFeedbackText}`;
},
},
methods: {
...mapActions(['scrollToAssignmentReady']),
_save: debounce(function (submission) {
this.saving++;
this.$apollo
.mutate({
mutation: UPDATE_ASSIGNMENT_MUTATION_WITH_SUCCESS,
variables: {
input: { input: {
assignment: { assignment: {
id: this.assignment.id, id: assignment.value.id,
answer: this.assignment.submission.text, answer: assignment.value.submission.text,
document: this.assignment.submission.document, document: assignment.value.submission.document,
},
}, },
}, },
};
doUpdateAssignmentWithSuccess(variables, {
update( update(
store, cache,
{ {
data: { data: {
updateAssignment: { successful, updatedAssignment }, updateAssignment: { successful, updatedAssignment },
@ -353,92 +346,76 @@ export default {
) { ) {
try { try {
if (successful) { if (successful) {
const query = ASSIGNMENT_QUERY; const id = cache.identify({
const variables = {
id: updatedAssignment.id, id: updatedAssignment.id,
}; __typename: updatedAssignment.__typename,
const assignment = Object.assign({}, updatedAssignment, { });
submission, const fragment = assignmentFragment;
const fragmentName = 'AssignmentParts';
cache.writeFragment({
fragment,
fragmentName,
id,
data: {
...updatedAssignment,
submission,
},
}); });
const data = {
assignment,
};
store.writeQuery({ query, variables, data });
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
// Query did not exist in the cache, and apollo throws a generic Error. Do nothing // Query did not exist in the cache, and apollo throws a generic Error. Do nothing
} }
}, },
}) }).then(() => {
.then(() => { saving.value--;
this.saving--; if (saving.value === 0) {
if (this.saving === 0) { unsaved.value = false;
this.unsaved = false;
} }
}); });
}, 500), }, 500);
saveInput: function (answer) { const saveInput = (answer: string) => {
// reset corrections on input // reset corrections on input
this.corrections = ''; corrections.value = '';
this.unsaved = true; unsaved.value = true;
/* /*
We update the assignment on this component, so the changes are reflected on it. The server does not return We update the assignment on this component, so the changes are reflected on it. The server does not return
the updated entity, to prevent the UI to update when the user is entering his input the updated entity, to prevent the UI to update when the user is entering his input
*/ */
this.assignment.submission.text = answer; assignment.value.submission.text = answer;
this._save(this.assignment.submission); _save(assignment.value.submission);
if (this.assignment.submission.text.length > 0) { if (assignment.value.submission.text.length > 0) {
matomoTrackEvent('Auftrag', 'Text mit Eingabe gespeichert', this.assignment.title); matomoTrackEvent('Auftrag', 'Text mit Eingabe gespeichert', assignment.value.title);
} }
}, };
changeDocumentUrl(documentUrl) { const changeDocumentUrl = (documentUrl: string) => {
this.assignment.submission.document = documentUrl; assignment.value.submission.document = documentUrl;
this._save(this.assignment.submission); _save(assignment.value.submission);
}, };
initialSubmission() { const spellcheck = () => {
return { spellcheckLoading.value = true;
text: '', const variables = {
document: '',
final: false,
};
},
spellcheck() {
let self = this;
this.spellcheckLoading = true;
this.$apollo
.mutate({
mutation: SPELL_CHECK_MUTATION,
variables: {
input: { input: {
assignment: this.assignment.id, assignment: assignment.value.id,
text: this.assignment.submission.text, text: assignment.value.submission.text,
},
}, },
};
doSpellCheck(variables, {
update( update(
store, _cache,
{ {
data: { data: {
spellCheck: { results }, spellCheck: { results },
}, },
} }
) { ) {
self.corrections = results; corrections.value = results;
}, },
}) }).then(() => {
.then(() => { spellcheckLoading.value = false;
this.spellcheckLoading = false;
}); });
matomoTrackEvent('Auftrag', 'Rechtschreibung geprüft', this.assignment.title); matomoTrackEvent('Auftrag', 'Rechtschreibung geprüft', assignment.value.title);
},
},
apollo: {
me: {
query: ME_QUERY,
},
},
}; };
</script> </script>

View File

@ -68,7 +68,7 @@ export default {
slug, slug,
}); });
const fragment = MODULE_FRAGMENT; const fragment = MODULE_FRAGMENT;
const fragmentName = 'ModuleParts'; const fragmentName = 'ModuleLegacyParts';
const module = store.readFragment({ fragment, fragmentName, id }); const module = store.readFragment({ fragment, fragmentName, id });
const data = { const data = {
...module, ...module,

View File

@ -1,5 +1,5 @@
#import "./highlightParts.gql" #import "./highlightParts.gql"
fragment ModuleParts on ModuleNode { fragment ModuleLegacyParts on ModuleNode {
id id
title title
metaTitle metaTitle

View File

@ -8,6 +8,6 @@ fragment RoomParts on RoomNode {
description description
restricted restricted
schoolClass { schoolClass {
...SchoolClassParts ...SchoolClassLegacyParts
} }
} }

View File

@ -1,4 +1,4 @@
fragment SchoolClassParts on SchoolClassNode { fragment SchoolClassLegacyParts on SchoolClassNode {
id id
name name
} }

View File

@ -1,4 +1,4 @@
fragment TeamParts on TeamNode { fragment TeamLegacyParts on TeamNode {
name name
code code
id id

View File

@ -8,6 +8,6 @@ fragment TopicParts on TopicNode {
vimeoId vimeoId
instructions instructions
modules { modules {
...ModuleParts ...ModuleLegacyParts
} }
} }

View File

@ -1,6 +1,6 @@
#import "./schoolClassParts.gql" #import "./schoolClassParts.gql"
#import "./moduleParts.gql" #import "./moduleParts.gql"
fragment UserParts on PrivateUserNode { fragment UserLegacyParts on PrivateUserNode {
id id
pk pk
username username
@ -30,11 +30,11 @@ fragment UserParts on PrivateUserNode {
recentModules(orderBy: "-visited") { recentModules(orderBy: "-visited") {
edges { edges {
node { node {
...ModuleParts ...ModuleLegacyParts
} }
} }
} }
schoolClasses { schoolClasses {
...SchoolClassParts ...SchoolClassLegacyParts
} }
} }

View File

@ -4,7 +4,7 @@ mutation CreateTeamMutation($input: CreateTeamInput!) {
result { result {
__typename __typename
... on TeamNode { ... on TeamNode {
...TeamParts ...TeamLegacyParts
} }
... on DuplicateName { ... on DuplicateName {
reason reason

View File

@ -3,7 +3,7 @@ mutation JoinTeamMutation($input: JoinTeamInput!) {
joinTeam(input: $input) { joinTeam(input: $input) {
success success
team { team {
...TeamParts ...TeamLegacyParts
} }
} }
} }

View File

@ -9,7 +9,7 @@ mutation ApplySnapshot($input: ApplySnapshotInput!) {
applySnapshot(input: $input) { applySnapshot(input: $input) {
success success
module { module {
...ModuleParts ...ModuleLegacyParts
objectiveGroups { objectiveGroups {
...ObjectiveGroupParts ...ObjectiveGroupParts
objectives { objectives {

View File

@ -2,7 +2,7 @@
mutation UpdateLastModule($input: UpdateLastModuleInput!) { mutation UpdateLastModule($input: UpdateLastModuleInput!) {
updateLastModule(input: $input) { updateLastModule(input: $input) {
lastModule { lastModule {
...ModuleParts ...ModuleLegacyParts
} }
} }
} }

View File

@ -3,7 +3,7 @@ query ModulesQuery {
modules { modules {
edges { edges {
node { node {
...ModuleParts ...ModuleLegacyParts
} }
} }
} }

View File

@ -12,7 +12,7 @@ query AssignmentWithSubmissions($id: ID!) {
firstName firstName
lastName lastName
schoolClasses { schoolClasses {
...SchoolClassParts ...SchoolClassLegacyParts
} }
} }
submissionFeedback { submissionFeedback {

View File

@ -2,9 +2,9 @@
#import "../fragments/teamParts.gql" #import "../fragments/teamParts.gql"
query MeQuery { query MeQuery {
me { me {
...UserParts ...UserLegacyParts
team { team {
...TeamParts ...TeamLegacyParts
} }
isTeacher isTeacher
permissions permissions

View File

@ -1,7 +1,7 @@
#import "../fragments/moduleParts.gql" #import "../fragments/moduleParts.gql"
query ModuleQuery($id: ID, $slug: String) { query ModuleQuery($id: ID, $slug: String) {
module(id: $id, slug: $slug) { module(id: $id, slug: $slug) {
...ModuleParts ...ModuleLegacyParts
chapters { chapters {
id id
contentBlocks { contentBlocks {

View File

@ -6,7 +6,7 @@
#import "gql/fragments/contentBlockParts.gql" #import "gql/fragments/contentBlockParts.gql"
query ModuleDetailsQuery($slug: String, $id: ID) { query ModuleDetailsQuery($slug: String, $id: ID) {
module(slug: $slug, id: $id) { module(slug: $slug, id: $id) {
...ModuleParts ...ModuleLegacyParts
objectiveGroups { objectiveGroups {
...ObjectiveGroupParts ...ObjectiveGroupParts
objectives { objectives {

View File

@ -31,4 +31,120 @@ export function meQuery() {
}; };
} }
export { getModule }; graphql(`
fragment SchoolClassParts on SchoolClassNode {
id
name
}
`);
graphql(`
fragment UserParts on PrivateUserNode {
id
pk
username
email
firstName
lastName
avatarUrl
expiryDate
readOnly
lastModuleLevel {
id
name
filterAttributeType
}
lastModule {
id
slug
}
lastTopic {
id
slug
}
selectedClass {
id
readOnly
}
recentModules(orderBy: "-visited") {
edges {
node {
...ModuleParts
}
}
}
schoolClasses {
...SchoolClassParts
}
}
`);
graphql(`
fragment TeamParts on TeamNode {
name
code
id
members {
firstName
lastName
id
isMe
}
}
`);
graphql(`
fragment ModuleParts on ModuleNode {
id
title
metaTitle
teaser
intro
slug
heroImage
heroSource
solutionsEnabled
highlights {
...HighlightParts
}
language
inEditMode @client
level {
id
name
}
category {
id
name
}
topic {
slug
title
}
bookmark {
note {
id
text
}
}
}
`);
const getMe = () => {
const query = graphql(`
query MeQuery {
me {
...UserParts
team {
...TeamParts
}
isTeacher
permissions
onboardingVisited
}
}
`);
const { result } = useQuery(query);
const me = computed(() => result.value?.me || { isTeacher: false });
return { me };
};
export { getModule, getMe };

View File

@ -135,7 +135,7 @@ export const constructNoteMutation = (n) => {
}); });
} else { } else {
let fragment = MODULE_FRAGMENT; let fragment = MODULE_FRAGMENT;
const fragmentName = 'ModuleParts'; const fragmentName = 'ModuleLegacyParts';
let id = store.identify({ let id = store.identify({
__typename: 'ModuleNode', __typename: 'ModuleNode',
slug: n.parent, slug: n.parent,

View File

@ -163,7 +163,7 @@ export default {
slug: slug, slug: slug,
}); });
const fragmentName = 'ModuleParts'; const fragmentName = 'ModuleLegacyParts';
const module = store.readFragment({ const module = store.readFragment({
fragment, fragment,
id, id,