Add snapshot module header
Also refactor some queries and other code
This commit is contained in:
parent
046b741458
commit
3d78761e20
|
|
@ -42,6 +42,7 @@ module.exports = {
|
|||
alias: {
|
||||
'@': resolve('src'),
|
||||
styles: resolve('src/styles'),
|
||||
gql: resolve('src/graphql/gql')
|
||||
},
|
||||
},
|
||||
module: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
<template>
|
||||
<div class="snapshot-header">
|
||||
<h1>Snapshot {{ id }}</h1>
|
||||
<div class="snapshot-header__meta">
|
||||
{{ created }} – {{ creator }}
|
||||
</div>
|
||||
|
||||
<section class="snapshot-header__section">
|
||||
<h2 class="snapshot-header__subtitle">
|
||||
In diesem Snapshot sind {{ changesCount }} Anpassungen gespeichert:
|
||||
</h2>
|
||||
<ul class="snapshot-header__list">
|
||||
<li class="snapshot-header__list-item">{{ hiddenObjectives }} Lernziele wurden ausgeblendet
|
||||
</li>
|
||||
<li class="snapshot-header__list-item">{{ newObjectives }} Lernziele wurde erfasst</li>
|
||||
<li class="snapshot-header__list-item">{{ hiddenContentBlocks }} Inhaltsblöcke wurden
|
||||
ausgeblendet
|
||||
</li>
|
||||
<li class="snapshot-header__list-item">{{ newContentBlocks }} Inhaltsblock wurde erfasst</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="snapshot-header__section">
|
||||
<h2 class="snapshot-header__subtitle">
|
||||
Willst du diesen Snapshot anwenden?
|
||||
</h2>
|
||||
<div>
|
||||
<checkbox
|
||||
:checked="agreement"
|
||||
label="Ich will die Anpassungen aus diesem Snapshot in das Modul kopieren."
|
||||
@input="agreement = $event"/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="snapshot-header__buttons snapshot-header__section">
|
||||
<button
|
||||
:disabled="!agreement"
|
||||
:class="{'button--disabled-alt': !agreement}"
|
||||
class="button button--primary"
|
||||
@click="apply">Snapshot anwenden
|
||||
</button>
|
||||
<button
|
||||
class="button button--secondary"
|
||||
@click="back">Abbrechen
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dateformat from '@/helpers/date-format';
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
|
||||
import me from '@/mixins/me';
|
||||
|
||||
import APPLY_SNAPSHOT_MUTATION from 'gql/mutations/snapshots/applySnapshot.gql';
|
||||
import {MODULE_PAGE} from '@/router/module.names';
|
||||
|
||||
const _getChange = (snapshot, index) => {
|
||||
try {
|
||||
return snapshot.changes[index];
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
props: {
|
||||
snapshot: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [me],
|
||||
|
||||
components: {
|
||||
Checkbox,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
agreement: false,
|
||||
}),
|
||||
|
||||
computed: {
|
||||
created() {
|
||||
return dateformat(this.snapshot.created);
|
||||
},
|
||||
creator() {
|
||||
const {firstName, lastName} = this.snapshot.creator || {};
|
||||
return `${firstName} ${lastName}`;
|
||||
},
|
||||
hiddenObjectives() {
|
||||
return _getChange(this.snapshot, 'hiddenObjectives');
|
||||
},
|
||||
newObjectives() {
|
||||
return _getChange(this.snapshot, 'newObjectives');
|
||||
},
|
||||
hiddenContentBlocks() {
|
||||
return _getChange(this.snapshot, 'hiddenContentBlocks');
|
||||
},
|
||||
newContentBlocks() {
|
||||
return _getChange(this.snapshot, 'newContentBlocks');
|
||||
},
|
||||
changesCount() {
|
||||
return this.hiddenObjectives + this.newObjectives + this.hiddenContentBlocks + this.newContentBlocks;
|
||||
},
|
||||
id() {
|
||||
try {
|
||||
return atob(this.snapshot.id).split(':')[1];
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
apply() {
|
||||
this.$apollo.mutate({
|
||||
mutation: APPLY_SNAPSHOT_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
snapshot: this.snapshot.id,
|
||||
selectedClass: this.me.selectedClass.id,
|
||||
},
|
||||
},
|
||||
}).then(({data: {applySnapshot: {module: {slug}}}}) => {
|
||||
this.$router.push({
|
||||
name: MODULE_PAGE,
|
||||
params: {
|
||||
slug: slug,
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
back() {
|
||||
this.$router.go(-1);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
|
||||
.snapshot-header {
|
||||
&__subtitle {
|
||||
@include heading-3;
|
||||
margin-bottom: $small-spacing;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
@include regular-text;
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__list {
|
||||
padding-left: $small-spacing;
|
||||
}
|
||||
|
||||
&__list-item {
|
||||
@include regular-text;
|
||||
line-height: 1.5;
|
||||
list-style-type: '–';
|
||||
padding-left: $small-spacing;
|
||||
}
|
||||
|
||||
&__section {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -59,6 +59,7 @@
|
|||
|
||||
&__link {
|
||||
@include default-link;
|
||||
color: $color-brand;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
#import "../fragments/moduleParts.gql"
|
||||
query ModuleQuery($id: ID!) {
|
||||
module(id: $id) {
|
||||
...ModuleParts
|
||||
chapters {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
contentBlocks {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
slug
|
||||
title
|
||||
type
|
||||
contents
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#import "../fragments/moduleParts.gql"
|
||||
query ModuleQuery($id: ID, $slug: String) {
|
||||
module(id: $id, slug:$slug) {
|
||||
...ModuleParts
|
||||
chapters {
|
||||
id
|
||||
contentBlocks {
|
||||
id
|
||||
slug
|
||||
title
|
||||
type
|
||||
contents
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#import "../../fragments/chapterParts.gql"
|
||||
#import "../../fragments/assignmentParts.gql"
|
||||
#import "../../fragments/objectiveGroupParts.gql"
|
||||
#import "../../fragments/objectiveParts.gql"
|
||||
#import "../../fragments/moduleParts.gql"
|
||||
#import "../../fragments/contentBlockInterfaceParts.gql"
|
||||
#import "../../fragments/contentBlockParts.gql"
|
||||
query ModuleDetailsQuery($slug: String!) {
|
||||
module(slug: $slug) {
|
||||
#import "gql/fragments/chapterParts.gql"
|
||||
#import "gql/fragments/assignmentParts.gql"
|
||||
#import "gql/fragments/objectiveGroupParts.gql"
|
||||
#import "gql/fragments/objectiveParts.gql"
|
||||
#import "gql/fragments/moduleParts.gql"
|
||||
#import "gql/fragments/contentBlockInterfaceParts.gql"
|
||||
#import "gql/fragments/contentBlockParts.gql"
|
||||
query ModuleDetailsQuery($slug: String, $id: ID) {
|
||||
module(slug: $slug, id: $id) {
|
||||
...ModuleParts
|
||||
assignments {
|
||||
edges {
|
||||
|
|
@ -16,22 +16,12 @@ query ModuleDetailsQuery($slug: String!) {
|
|||
}
|
||||
}
|
||||
objectiveGroups {
|
||||
edges {
|
||||
node {
|
||||
...ObjectiveGroupParts
|
||||
objectives {
|
||||
edges {
|
||||
node {
|
||||
...ObjectiveParts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
chapters {
|
||||
edges {
|
||||
node {
|
||||
...ChapterParts
|
||||
contentBlocks {
|
||||
...ContentBlockInterfaceParts
|
||||
|
|
@ -40,5 +30,3 @@ query ModuleDetailsQuery($slug: String!) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import ADD_NOTE_MUTATION from '@/graphql/gql/mutations/addNote.gql';
|
||||
import CONTENT_BLOCK_QUERY from '@/graphql/gql/queries/contentBlockQuery.gql';
|
||||
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
||||
import MODULE_QUERY from '@/graphql/gql/queries/moduleByIdQuery.gql';
|
||||
import MODULE_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
|
||||
import INSTRUMENT_FRAGMENT from '@/graphql/gql/fragments/instrumentParts.gql';
|
||||
|
||||
const getBlockType = id => atob(id).split(':')[0];
|
||||
|
|
|
|||
|
|
@ -45,9 +45,3 @@
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import "@/styles/_default-layout.scss";
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<div class="skillbox layout layout--simple">
|
||||
<div
|
||||
:class="{'layout--full-width': $route.meta.fullWidth}"
|
||||
class="skillbox layout layout--simple">
|
||||
<div
|
||||
class="close-button"
|
||||
@click="back">
|
||||
<cross class="close-button__icon"/>
|
||||
</div>
|
||||
<router-view/>
|
||||
<router-view class="layout__content" />
|
||||
<simple-footer
|
||||
class="layout__footer"
|
||||
v-if="enableFooter"/>
|
||||
|
|
@ -36,8 +38,7 @@
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import "~styles/helpers";
|
||||
|
||||
.layout {
|
||||
&--simple {
|
||||
|
|
@ -60,6 +61,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
$parent: &;
|
||||
|
||||
&--full-width {
|
||||
#{$parent}__content {
|
||||
grid-column: 1 / span 3;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
|
|
@ -74,7 +84,9 @@
|
|||
|
||||
@include desktop {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
-ms-grid-column: 3;
|
||||
-ms-grid-row: 1;
|
||||
margin-right: $medium-spacing;
|
||||
margin-top: $medium-spacing;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
<template>
|
||||
<module :module="snapshot"/>
|
||||
<div class="snapshot">
|
||||
<header class="snapshot__header">
|
||||
<snapshot-header
|
||||
:snapshot="snapshot"
|
||||
/>
|
||||
</header>
|
||||
|
||||
<module
|
||||
:module="snapshot"
|
||||
class="snapshot__module"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SNAPSHOT_DETAIL_QUERY from '@/graphql/gql/queries/snapshots/detail.gql';
|
||||
|
||||
import Module from '@/components/modules/Module';
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import SnapshotHeader from '@/components/modules/SnapshotHeader';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -16,6 +28,8 @@
|
|||
},
|
||||
|
||||
components: {
|
||||
SnapshotHeader,
|
||||
Checkbox,
|
||||
Module,
|
||||
},
|
||||
|
||||
|
|
@ -37,4 +51,21 @@
|
|||
<style scoped lang="scss">
|
||||
@import '~styles/helpers';
|
||||
|
||||
.snapshot {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 800px 1fr;
|
||||
grid-template-rows: auto auto;
|
||||
|
||||
&__header {
|
||||
background-color: $color-brand-light;
|
||||
grid-column: 1 / span 3;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__module {
|
||||
grid-column: 2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
<script>
|
||||
import * as SurveyVue from 'survey-vue';
|
||||
import {css} from '@/survey.config';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import SURVEY_QUERY from '@/graphql/gql/queries/surveyQuery.gql';
|
||||
import MODULE_QUERY from '@/graphql/gql/queries/moduleByIdQuery.gql';
|
||||
import UPDATE_ANSWER from '@/graphql/gql/mutations/updateAnswer.gql';
|
||||
import Solution from '@/components/content-blocks/Solution';
|
||||
|
||||
|
|
@ -30,12 +30,20 @@
|
|||
|
||||
const Survey = SurveyVue.Survey;
|
||||
|
||||
const MODULE_QUERY = gql`
|
||||
query Module($id: ID) {
|
||||
module(id: $id) {
|
||||
solutionsEnabled
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
|
||||
components: {
|
||||
Solution,
|
||||
Survey
|
||||
Survey,
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -45,9 +53,9 @@
|
|||
module: {},
|
||||
completed: false,
|
||||
me: {
|
||||
permissions: []
|
||||
permissions: [],
|
||||
},
|
||||
saveDisabled: false
|
||||
saveDisabled: false,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -80,7 +88,7 @@
|
|||
<p class="solution-text__answer">${answer.answer}</p>
|
||||
`;
|
||||
}
|
||||
}, '')
|
||||
}, ''),
|
||||
};
|
||||
},
|
||||
answers() {
|
||||
|
|
@ -90,7 +98,7 @@
|
|||
},
|
||||
isTeacher() {
|
||||
return isTeacher(this);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
@ -116,21 +124,21 @@
|
|||
let question = sender.getQuestionByName(k);
|
||||
data[k] = {
|
||||
answer: survey.data[k],
|
||||
correct: question && question.correctAnswer ? question.correctAnswer : ''
|
||||
correct: question && question.correctAnswer ? question.correctAnswer : '',
|
||||
};
|
||||
}
|
||||
}
|
||||
const answer = {
|
||||
surveyId: this.id,
|
||||
data: JSON.stringify(data)
|
||||
data: JSON.stringify(data),
|
||||
};
|
||||
|
||||
this.$apollo.mutate({
|
||||
mutation: UPDATE_ANSWER,
|
||||
variables: {
|
||||
input: {
|
||||
answer
|
||||
}
|
||||
answer,
|
||||
},
|
||||
},
|
||||
update: (store, {data: {updateAnswer: {answer}}}) => {
|
||||
const query = SURVEY_QUERY;
|
||||
|
|
@ -140,7 +148,7 @@
|
|||
queryData.survey.answer = answer;
|
||||
store.writeQuery({query, variables, data: queryData});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -160,7 +168,7 @@
|
|||
this.survey.clear();
|
||||
this.survey.data = data; // reapply it
|
||||
this.saveDisabled = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
apollo: {
|
||||
|
|
@ -168,7 +176,7 @@
|
|||
query: SURVEY_QUERY,
|
||||
variables() {
|
||||
return {
|
||||
id: this.id
|
||||
id: this.id,
|
||||
};
|
||||
},
|
||||
manual: true,
|
||||
|
|
@ -190,14 +198,14 @@
|
|||
this.$apollo.addSmartQuery('module', {
|
||||
query: MODULE_QUERY,
|
||||
variables: {
|
||||
id: module.id
|
||||
}
|
||||
id: module.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
me: meQuery
|
||||
}
|
||||
me: meQuery,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import authRoutes from './auth.routes';
|
|||
import roomRoutes from './room.routes';
|
||||
|
||||
import store from '@/store/index';
|
||||
import {LAYOUT_SIMPLE} from '@/router/core.constants';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
|
|
@ -34,24 +35,25 @@ const routes = [
|
|||
...moduleRoutes,
|
||||
...authRoutes,
|
||||
...roomRoutes,
|
||||
{path: '/article/:slug', name: 'article', component: article, meta: {layout: 'simple'}},
|
||||
...onboardingRoutes,
|
||||
...portfolioRoutes,
|
||||
...meRoutes,
|
||||
{path: '/article/:slug', name: 'article', component: article, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{
|
||||
path: '/instruments/',
|
||||
name: 'instrument-overview',
|
||||
component: instrumentOverview,
|
||||
},
|
||||
{path: '/instrument/:slug', name: 'instrument', component: instrument, meta: {layout: 'simple'}},
|
||||
{path: '/submission/:id', name: 'submission', component: submission, meta: {layout: 'simple'}},
|
||||
...portfolioRoutes,
|
||||
{path: '/instrument/:slug', name: 'instrument', component: instrument, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{path: '/submission/:id', name: 'submission', component: submission, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{path: '/topic/:topicSlug', name: 'topic', component: topic, alias: '/book/topic/:topicSlug'},
|
||||
...meRoutes,
|
||||
{path: '/join-class', name: 'join-class', component: joinClass, meta: {layout: 'simple'}},
|
||||
{path: '/join-class', name: 'join-class', component: joinClass, meta: {layout: LAYOUT_SIMPLE}},
|
||||
{
|
||||
path: '/survey/:id',
|
||||
component: surveyPage,
|
||||
name: 'survey',
|
||||
props: true,
|
||||
meta: {layout: 'simple'},
|
||||
meta: {layout: LAYOUT_SIMPLE},
|
||||
},
|
||||
{
|
||||
path: '/check-email',
|
||||
|
|
@ -93,7 +95,6 @@ const routes = [
|
|||
component: news,
|
||||
name: 'news',
|
||||
},
|
||||
...onboardingRoutes,
|
||||
{path: '/styleguide', component: styleGuidePage},
|
||||
{
|
||||
path: '*',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import joinTeam from '@/pages/me/joinTeam';
|
|||
import createTeam from '@/pages/me/createTeam';
|
||||
|
||||
import {CREATE_TEAM, JOIN_TEAM, MY_TEAM, SHOW_SCHOOL_CLASS_CODE, SHOW_TEAM_CODE} from './me.names';
|
||||
import {LAYOUT_SIMPLE} from '@/router/core.constants';
|
||||
|
||||
export default [
|
||||
{
|
||||
|
|
@ -32,23 +33,23 @@ export default [
|
|||
alias: 'create-class',
|
||||
name: 'create-class',
|
||||
component: createClass,
|
||||
meta: {layout: 'simple'},
|
||||
meta: {layout: LAYOUT_SIMPLE},
|
||||
},
|
||||
{
|
||||
path: 'class/code',
|
||||
alias: 'show-code',
|
||||
name: SHOW_SCHOOL_CLASS_CODE,
|
||||
component: showSchoolClassCode,
|
||||
meta: {layout: 'simple'},
|
||||
meta: {layout: LAYOUT_SIMPLE},
|
||||
},
|
||||
{path: 'team', name: MY_TEAM, component: myTeam, meta: {isProfile: true}},
|
||||
{path: 'team/join', name: JOIN_TEAM, component: joinTeam, meta: {isProfile: true, layout: 'simple'}},
|
||||
{path: 'team/create', name: CREATE_TEAM, component: createTeam, meta: {isProfile: true, layout: 'simple'}},
|
||||
{path: 'team/join', name: JOIN_TEAM, component: joinTeam, meta: {isProfile: true, layout: LAYOUT_SIMPLE}},
|
||||
{path: 'team/create', name: CREATE_TEAM, component: createTeam, meta: {isProfile: true, layout: LAYOUT_SIMPLE}},
|
||||
{
|
||||
path: 'team/code',
|
||||
name: SHOW_TEAM_CODE,
|
||||
component: showTeamCode,
|
||||
meta: {layout: 'simple'},
|
||||
meta: {layout: LAYOUT_SIMPLE},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,10 +2,18 @@ import moduleBase from '@/pages/module/module-base';
|
|||
import module from '@/pages/module/module';
|
||||
import submissions from '@/pages/submissions';
|
||||
import moduleVisibility from '@/pages/module/moduleVisibility';
|
||||
import {MODULE_PAGE, MODULE_SETTINGS_PAGE, SUBMISSIONS_PAGE, VISIBILITY_PAGE, SNAPSHOT_LIST, SNAPSHOT_DETAIL} from '@/router/module.names';
|
||||
import {
|
||||
MODULE_PAGE,
|
||||
MODULE_SETTINGS_PAGE,
|
||||
SNAPSHOT_DETAIL,
|
||||
SNAPSHOT_LIST,
|
||||
SUBMISSIONS_PAGE,
|
||||
VISIBILITY_PAGE,
|
||||
} from '@/router/module.names';
|
||||
import settingsPage from '@/pages/module/moduleSettings';
|
||||
import snapshots from '@/pages/snapshot/snapshots';
|
||||
import snapshot from '@/pages/snapshot/snapshot';
|
||||
import {LAYOUT_SIMPLE} from '@/router/core.constants';
|
||||
|
||||
export default [
|
||||
{
|
||||
|
|
@ -40,7 +48,7 @@ export default [
|
|||
name: VISIBILITY_PAGE,
|
||||
component: moduleVisibility,
|
||||
meta: {
|
||||
layout: 'simple',
|
||||
layout: LAYOUT_SIMPLE,
|
||||
hideNavigation: true,
|
||||
},
|
||||
},
|
||||
|
|
@ -56,8 +64,13 @@ export default [
|
|||
path: 'snapshot/:id',
|
||||
component: snapshot,
|
||||
name: SNAPSHOT_DETAIL,
|
||||
props: true
|
||||
}
|
||||
props: true,
|
||||
meta: {
|
||||
layout: LAYOUT_SIMPLE,
|
||||
hideNavigation: true,
|
||||
fullWidth: true
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -12,9 +12,17 @@
|
|||
&--white-bg {
|
||||
background-color: $color-white;
|
||||
}
|
||||
@mixin disabled {
|
||||
cursor: default;
|
||||
}
|
||||
&--disabled {
|
||||
@include disabled;
|
||||
background-color: $color-silver-light;
|
||||
}
|
||||
&--disabled-alt {
|
||||
@include disabled;
|
||||
opacity: 0.3;
|
||||
}
|
||||
&--big {
|
||||
padding: 15px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ $icon-size: 20px;
|
|||
&__icon {
|
||||
width: $icon-size;
|
||||
height: $icon-size;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
border: 2px solid $color-silver-dark;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from books.schema.interfaces.module import ModuleInterface
|
|||
from books.schema.nodes.chapter import ChapterNode
|
||||
from notes.models import ModuleBookmark, ContentBlockBookmark, ChapterBookmark
|
||||
from notes.schema import ModuleBookmarkNode, ContentBlockBookmarkNode, ChapterBookmarkNode
|
||||
from objectives.schema import ObjectiveGroupNode
|
||||
from surveys.models import Answer
|
||||
from surveys.schema import AnswerNode
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ class ModuleNode(DjangoObjectType):
|
|||
}
|
||||
interfaces = (ModuleInterface,)
|
||||
|
||||
chapters = DjangoFilterConnectionField(ChapterNode)
|
||||
chapters = graphene.List(ChapterNode)
|
||||
solutions_enabled = graphene.Boolean()
|
||||
bookmark = graphene.Field(ModuleBookmarkNode)
|
||||
my_submissions = DjangoFilterConnectionField(StudentSubmissionNode)
|
||||
|
|
@ -34,6 +35,7 @@ class ModuleNode(DjangoObjectType):
|
|||
my_content_bookmarks = DjangoFilterConnectionField(ContentBlockBookmarkNode)
|
||||
my_chapter_bookmarks = DjangoFilterConnectionField(ChapterBookmarkNode)
|
||||
snapshots = graphene.List('books.schema.nodes.SnapshotNode')
|
||||
objective_groups = graphene.List(ObjectiveGroupNode)
|
||||
|
||||
def resolve_chapters(self, info, **kwargs):
|
||||
return Chapter.get_by_parent(self)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class BookQuery(object):
|
|||
slug = kwargs.get('slug')
|
||||
id = kwargs.get('id')
|
||||
module = None
|
||||
|
||||
try:
|
||||
if id is not None:
|
||||
module = get_object(Module, id)
|
||||
|
||||
|
|
@ -53,6 +53,9 @@ class BookQuery(object):
|
|||
|
||||
return module
|
||||
|
||||
except Module.DoesNotExist:
|
||||
return None
|
||||
|
||||
def resolve_topic(self, info, **kwargs):
|
||||
slug = kwargs.get('slug')
|
||||
id = kwargs.get('id')
|
||||
|
|
|
|||
|
|
@ -6,16 +6,15 @@ from api.schema import schema
|
|||
from books.factories import ModuleFactory, ChapterFactory, ContentBlockFactory
|
||||
from books.models import Snapshot, ChapterSnapshot
|
||||
from core.tests.base_test import SkillboxTestCase
|
||||
from users.factories import SchoolClassFactory
|
||||
from users.models import User, SchoolClass
|
||||
|
||||
MODULE_QUERY = """
|
||||
query ModulesQuery($slug: String!) {
|
||||
module(slug: $slug) {
|
||||
query ModulesQuery($slug: String, $id: ID) {
|
||||
module(slug: $slug, id: $id) {
|
||||
id
|
||||
title
|
||||
chapters {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
contentBlocks {
|
||||
id
|
||||
|
|
@ -30,8 +29,6 @@ query ModulesQuery($slug: String!) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
CREATE_SNAPSHOT_MUTATION = """
|
||||
|
|
@ -226,3 +223,43 @@ class CreateSnapshotTestCase(SkillboxTestCase):
|
|||
self.assertEqual(second['title'], 'hidden')
|
||||
self.assertEqual(second['hidden'], True)
|
||||
self.assertEqual(third['title'], 'custom')
|
||||
|
||||
def test_not_too_much_user_creator_info(self):
|
||||
self.assertTrue(False)
|
||||
|
||||
def test_apply_initial_snapshot(self):
|
||||
teacher2 = User.objects.get(username='teacher2')
|
||||
teacher2_client = self.get_client(user=teacher2)
|
||||
third_class = SchoolClassFactory(
|
||||
users=[teacher2],
|
||||
name='third_class'
|
||||
)
|
||||
|
||||
# make a neutral snapshot, nothing new, nothing hidden
|
||||
result = teacher2_client.execute(CREATE_SNAPSHOT_MUTATION, variables={
|
||||
'input': {
|
||||
'module': self.slug,
|
||||
'selectedClass': to_global_id('SchoolClassNode', third_class.pk),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
snapshot_id = result['data']['createSnapshot']['snapshot']['id']
|
||||
|
||||
result = self.client.execute(APPLY_SNAPSHOT_MUTATION, variables={
|
||||
'input': {
|
||||
'snapshot': snapshot_id,
|
||||
'selectedClass': to_global_id('SchoolClassNode', self.skillbox_class.pk),
|
||||
}
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
|
||||
result = self.client.execute(MODULE_QUERY, variables={
|
||||
'slug': self.module.slug
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
module = result['data']['module']
|
||||
chapter1, chapter2 = module['chapters']
|
||||
cb1, cb2, cb3 = chapter1['contentBlocks']
|
||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb1['hiddenFor']])
|
||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb2['hiddenFor']])
|
||||
self.assertTrue(self.skillbox_class.name not in [sc['name'] for sc in cb3['visibleFor']])
|
||||
|
|
|
|||
|
|
@ -8,9 +8,30 @@ from core.mixins import HiddenAndVisibleForMixin, HiddenForMixin
|
|||
from objectives.models import ObjectiveGroup, Objective
|
||||
|
||||
|
||||
class ObjectiveNode(DjangoObjectType, HiddenAndVisibleForMixin):
|
||||
pk = graphene.Int()
|
||||
user_created = graphene.Boolean()
|
||||
mine = graphene.Boolean()
|
||||
|
||||
class Meta:
|
||||
model = Objective
|
||||
filter_fields = ['text']
|
||||
interfaces = (relay.Node,)
|
||||
|
||||
def resolve_objective_progress(self, info, **kwargs):
|
||||
return self.objective_progress.filter(user=info.context.user)
|
||||
|
||||
def resolve_user_created(self, info, **kwargs):
|
||||
return self.owner is not None
|
||||
|
||||
def resolve_mine(self, info, **kwargs):
|
||||
return self.owner is not None and self.owner.pk == info.context.user.pk
|
||||
|
||||
|
||||
class ObjectiveGroupNode(DjangoObjectType, HiddenForMixin):
|
||||
pk = graphene.Int()
|
||||
display_title = graphene.String()
|
||||
objectives = graphene.List(ObjectiveNode)
|
||||
|
||||
class Meta:
|
||||
model = ObjectiveGroup
|
||||
|
|
@ -37,26 +58,6 @@ class ObjectiveGroupNode(DjangoObjectType, HiddenForMixin):
|
|||
return self.objectives.filter(objectives_from_publisher | objectives_from_teacher)
|
||||
|
||||
|
||||
class ObjectiveNode(DjangoObjectType, HiddenAndVisibleForMixin):
|
||||
pk = graphene.Int()
|
||||
user_created = graphene.Boolean()
|
||||
mine = graphene.Boolean()
|
||||
|
||||
class Meta:
|
||||
model = Objective
|
||||
filter_fields = ['text']
|
||||
interfaces = (relay.Node,)
|
||||
|
||||
def resolve_objective_progress(self, info, **kwargs):
|
||||
return self.objective_progress.filter(user=info.context.user)
|
||||
|
||||
def resolve_user_created(self, info, **kwargs):
|
||||
return self.owner is not None
|
||||
|
||||
def resolve_mine(self, info, **kwargs):
|
||||
return self.owner is not None and self.owner.pk == info.context.user.pk
|
||||
|
||||
|
||||
class ObjectivesQuery(object):
|
||||
objective_group = relay.Node.Field(ObjectiveGroupNode)
|
||||
objective_groups = DjangoFilterConnectionField(ObjectiveGroupNode)
|
||||
|
|
|
|||
Loading…
Reference in New Issue