Merged in feature/detailpage (pull request #5)

Feature/detailpage

Approved-by: Ramon Wenger <ramon.wenger@iterativ.ch>
This commit is contained in:
Christian Cueni 2018-10-22 17:22:38 +00:00 committed by Ramon Wenger
commit 033372848e
12 changed files with 215 additions and 55 deletions

View File

@ -1,13 +1,15 @@
<template>
<div class="assignment-with-submissions">
<h1 class="assignment-with-submissions__title">{{assignment.title}}</h1>
<student-submission class="assignment-with-submissions__submission"
v-for="(submission, index) in assignment.submissions"
:key="index"
:submission="submission"
>
</student-submission>
<router-link
:to="submissionLink(submission)"
v-for="(submission, index) in assignment.submissions"
:key="index">
<student-submission class="assignment-with-submissions__submission"
:submission="submission"
>
</student-submission>
</router-link>
</div>
</template>
@ -19,6 +21,11 @@
components: {
StudentSubmission
},
methods: {
submissionLink(submission) {
return `/submission/${submission.id}`
}
}
}
</script>

View File

@ -3,20 +3,43 @@
<div class="student-submission__student-name">
{{name}}
</div>
<div class="student-submission__entry">
{{submission.text}}
<div class="student-submission__entry entry">
<p>{{submission.text | trimToLength(50)}}</p>
<p v-if="submission.document && submission.document.length > 0" class="entry__document">
<student-submission-document :document="submission.document" class="entry-document"></student-submission-document>
</p>
</div>
</div>
</template>
<script>
import DocumentIcon from '@/components/icons/DocumentIcon'
import StudentSubmissionDocument from '@/components/StudentSubmissionDocument';
export default {
props: ['submission'],
components: { DocumentIcon, StudentSubmissionDocument },
computed: {
name() {
return this.submission && this.submission.student
? `${this.submission.student.firstName} ${this.submission.student.lastName}` : '';
},
},
filters: {
trimToLength: function(text, numberOfChars) {
if (!text) {
return '';
}
if (text.length <= numberOfChars) {
return text;
}
const index = text.indexOf(' ', numberOfChars - 1);
if (index === -1) {
return text;
}
return `${text.substring(0, index)}`;
}
}
}
@ -43,5 +66,9 @@
font-size: toRem(14px);
font-family: $sans-serif-font-family;
}
.entry-document {
margin-top: 1rem;
}
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<div class="submission-document">
<p v-if="document && document.length > 0" class="submission-document__content content">
<document-icon class="content__icon"></document-icon><span class="content__text">{{filename}}</span>
</p>
</div>
</template>
<script>
import DocumentIcon from '@/components/icons/DocumentIcon'
import filenameFromUrl from '@/helpers/urls';
export default {
props: ['document'],
name: 'student-submission-document',
components: { DocumentIcon },
computed: {
filename() {
return filenameFromUrl(this.document)
}
},
}
</script>
<style scoped lang="scss">
.content {
display: flex;
&__icon {
width: 25px;
align-self: center;
}
&__text {
align-self: center;
padding-left: 5px;
}
}
</style>

View File

@ -0,0 +1,14 @@
query StudentSubmissions($id: ID!) {
studentSubmission(id: $id) {
id
text
document
student {
firstName
lastName
}
assignment {
title
}
}
}

View File

@ -0,0 +1,6 @@
export default function filenameFromUrl(url) {
const index = url.lastIndexOf('/');
if (index === -1) { return url }
return url.substring(index + 1);
}

View File

@ -64,46 +64,3 @@
}
}
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
@import "@/styles/_functions.scss";
.article {
&__header {
grid-template-rows: 50px minmax(50px, max-content) auto;
grid-row-gap: 30px;
display: -ms-grid;
display: grid;
}
&__meta {
border-bottom: 1px solid $color-lightgrey;
align-self: end;
padding: 20px 0;
}
&__title {
grid-row: 3;
}
&__subtitle {
grid-row: 2;
font-family: $serif-font-family;
font-weight: 400;
}
&__content {
display: -ms-grid;
display: grid;
grid-row-gap: 40px;
padding-bottom: 40px;
/deep/ p {
font-size: toRem(18px);
line-height: 1.5;
}
}
}
</style>

View File

@ -0,0 +1,62 @@
<template>
<div class="article submission-page">
<div class="article__header">
<h1 class="article__title">{{studentSubmission.assignment.title}}</h1>
<h2 class="article__subtitle">{{`${studentSubmission.student.firstName} ${studentSubmission.student.lastName}`}}</h2>
</div>
<div class="article__content article-content">
<p v-if="studentSubmission.document && studentSubmission.document.length > 0" class="article-content__document">
<a :href="studentSubmission.document" class="entry-document__link link" target="_blank">
<student-submission-document :document="studentSubmission.document"></student-submission-document>
</a>
</p>
<p>{{studentSubmission.text}}</p>
</div>
</div>
</template>
<script>
import DocumentIcon from '@/components/icons/DocumentIcon';
import StudentSubmissionDocument from '@/components/StudentSubmissionDocument';
import STUDENT_SUBMISSIONS_QUERY from '@/graphql/gql/studentSubmissionQuery.gql';
export default {
components: { DocumentIcon, StudentSubmissionDocument },
data() {
return {
studentSubmission: {
assignment: {
title: ''
},
student: {
firstName: '',
lastName: ''
},
text: '',
document: ''
}
}
},
apollo: {
studentSubmission() {
return {
query: STUDENT_SUBMISSIONS_QUERY,
variables() {
return {
id: this.$route.params.id
}
}
}
},
},
}
</script>
<style scoped lang="scss">
.article-content {
&__document {
margin-bottom: 1rem;
}
}
</style>

View File

@ -14,6 +14,7 @@ import basicknowledge from '@/pages/basicknowledge'
import submissions from '@/pages/submissions'
import p404 from '@/pages/p404'
import start from '@/pages/start'
import submission from '@/pages/studentSubmission'
const routes = [
{path: '/', component: start, meta: {layout: 'blank'}},
@ -43,6 +44,7 @@ const routes = [
{path: '/room/:slug', name: 'room', component: room, props: true},
{path: '/article/:slug', name: 'article', component: article, meta: {layout: 'simple'}},
{path: '/basic-knowledge', name: 'basic-knowledge', component: basicknowledge, meta: {layout: 'simple'}},
{path: '/submission/:id', name: 'submission', component: submission, meta: {layout: 'simple'}},
{
path: '/book',
name: 'book',

View File

@ -0,0 +1,37 @@
.article {
&__header {
grid-template-rows: 50px minmax(50px, max-content) auto;
grid-row-gap: 30px;
display: -ms-grid;
display: grid;
}
&__meta {
border-bottom: 1px solid $color-lightgrey;
align-self: end;
padding: 20px 0;
}
&__title {
grid-row: 3;
}
&__subtitle {
grid-row: 2;
font-family: $serif-font-family;
font-weight: 400;
}
&__content {
display: -ms-grid;
display: grid;
grid-row-gap: 40px;
padding-bottom: 40px;
/deep/ p {
font-size: toRem(18px);
line-height: 1.5;
}
}
}

View File

@ -11,3 +11,4 @@
@import "uploadcare_overwrite";
@import "help-text";
@import "objective-group";
@import "article";

View File

@ -6,7 +6,7 @@ from graphene_django.debug import DjangoDebug
# noinspection PyUnresolvedReferences
from api import graphene_wagtail # Keep this import exactly here, it's necessary for StreamField conversion
from assignments.schema.mutations import AssignmentMutations
from assignments.schema.queries import AssignmentsQuery
from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery
from books.schema.mutations.main import BookMutations
from books.schema.queries import BookQuery
from objectives.mutations import ObjectiveMutations
@ -16,7 +16,8 @@ from rooms.schema import RoomsQuery
from users.schema import UsersQuery
class Query(UsersQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, graphene.ObjectType):
class Query(UsersQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, StudentSubmissionQuery,
graphene.ObjectType):
node = relay.Node.Field()
if settings.DEBUG:

View File

@ -1,9 +1,14 @@
from graphene import relay
from graphene_django.filter import DjangoFilterConnectionField
from assignments.schema.types import AssignmentNode
from assignments.schema.types import AssignmentNode, StudentSubmissionNode
class AssignmentsQuery(object):
assignment = relay.Node.Field(AssignmentNode)
assignments = DjangoFilterConnectionField(AssignmentNode)
class StudentSubmissionQuery(object):
studentSubmission = relay.Node.Field(StudentSubmissionNode)