Merged in feature/instrument-notes (pull request #43)
Feature/instrument notes Approved-by: Christian Cueni <christian.cueni@iterativ.ch>
This commit is contained in:
commit
0d6a7522f2
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
hideModal() {
|
hideModal() {
|
||||||
this.$store.dispatch('resetCurrentContentBlock');
|
this.$store.dispatch('resetCurrentNoteBlock');
|
||||||
this.$store.dispatch('hideModal');
|
this.$store.dispatch('hideModal');
|
||||||
},
|
},
|
||||||
saveContentBlock(contentBlock) {
|
saveContentBlock(contentBlock) {
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
return {
|
return {
|
||||||
query: CONTENT_BLOCK_QUERY,
|
query: CONTENT_BLOCK_QUERY,
|
||||||
variables: {
|
variables: {
|
||||||
id: store.state.currentContentBlock
|
id: store.state.currentNoteBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@
|
||||||
import Solution from '@/components/content-blocks/Solution';
|
import Solution from '@/components/content-blocks/Solution';
|
||||||
import BookmarkActions from '@/components/notes/BookmarkActions';
|
import BookmarkActions from '@/components/notes/BookmarkActions';
|
||||||
|
|
||||||
import UPDATE_CONTENT_BOOKMARK from '@/graphql/gql/mutations/updateContentBookmark.gql';
|
import {constructContentComponentBookmarkMutation} from '@/helpers/update-content-bookmark-mutation';
|
||||||
import CONTENT_BLOCK_QUERY from '@/graphql/gql/contentBlockQuery.gql';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['component', 'parent', 'bookmarks', 'notes', 'root'],
|
props: ['component', 'parent', 'bookmarks', 'notes', 'root'],
|
||||||
|
|
@ -84,63 +83,15 @@
|
||||||
addNote(id) {
|
addNote(id) {
|
||||||
this.$store.dispatch('addNote', {
|
this.$store.dispatch('addNote', {
|
||||||
content: id,
|
content: id,
|
||||||
contentBlock: this.root
|
type: this.parent.__typename,
|
||||||
|
block: this.root
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
editNote() {
|
editNote() {
|
||||||
this.$store.dispatch('editNote', this.note);
|
this.$store.dispatch('editNote', this.note);
|
||||||
},
|
},
|
||||||
bookmarkContent(uuid, bookmarked) {
|
bookmarkContent(uuid, bookmarked) {
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate(constructContentComponentBookmarkMutation(uuid, bookmarked, this.parent, this.root));
|
||||||
mutation: UPDATE_CONTENT_BOOKMARK,
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
uuid,
|
|
||||||
contentBlock: this.root,
|
|
||||||
bookmarked
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update: (store, response) => {
|
|
||||||
const query = CONTENT_BLOCK_QUERY;
|
|
||||||
const variables = {id: this.root};
|
|
||||||
const data = store.readQuery({
|
|
||||||
query,
|
|
||||||
variables
|
|
||||||
});
|
|
||||||
|
|
||||||
const bookmarks = data.contentBlock.bookmarks;
|
|
||||||
|
|
||||||
if (bookmarked) {
|
|
||||||
bookmarks.push({
|
|
||||||
note: null,
|
|
||||||
uuid: uuid,
|
|
||||||
__typename: 'ContentBlockBookmarkNode'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let index = bookmarks.findIndex(element => {
|
|
||||||
return element.uuid === uuid;
|
|
||||||
});
|
|
||||||
if (index > -1) {
|
|
||||||
bookmarks.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.contentBlock.bookmarks = bookmarks;
|
|
||||||
|
|
||||||
store.writeQuery({
|
|
||||||
data,
|
|
||||||
query,
|
|
||||||
variables
|
|
||||||
});
|
|
||||||
},
|
|
||||||
optimisticResponse: {
|
|
||||||
__typename: 'Mutation',
|
|
||||||
updateContentBookmark: {
|
|
||||||
__typename: 'UpdateContentBookmarkPayload',
|
|
||||||
success: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import UPDATE_NOTE_MUTATION from '@/graphql/gql/mutations/updateNote.gql';
|
import UPDATE_NOTE_MUTATION from '@/graphql/gql/mutations/updateNote.gql';
|
||||||
import MODULE_DETAILS_QUERY from '@/graphql/gql/moduleDetailsQuery.gql';
|
import MODULE_DETAILS_QUERY from '@/graphql/gql/moduleDetailsQuery.gql';
|
||||||
|
import INSTRUMENT_QUERY from '@/graphql/gql/instrumentQuery.gql';
|
||||||
|
|
||||||
import {mapGetters} from 'vuex';
|
import {mapGetters} from 'vuex';
|
||||||
|
|
||||||
|
|
@ -21,6 +22,9 @@
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
editNote(note) {
|
editNote(note) {
|
||||||
|
const slug = this.$route.params.slug;
|
||||||
|
const routeName = this.$route.name;
|
||||||
|
|
||||||
this.$apollo.mutate({
|
this.$apollo.mutate({
|
||||||
mutation: UPDATE_NOTE_MUTATION,
|
mutation: UPDATE_NOTE_MUTATION,
|
||||||
variables: {
|
variables: {
|
||||||
|
|
@ -28,12 +32,25 @@
|
||||||
note
|
note
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refetchQueries: [{
|
refetchQueries() {
|
||||||
query: MODULE_DETAILS_QUERY,
|
let query;
|
||||||
variables: {
|
if (routeName === 'instrument') {
|
||||||
slug: this.$route.params.slug
|
query = {
|
||||||
|
query: INSTRUMENT_QUERY,
|
||||||
|
variables: {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
query = {
|
||||||
|
query: MODULE_DETAILS_QUERY,
|
||||||
|
variables: {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}]
|
return [query];
|
||||||
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$store.dispatch('hideModal');
|
this.$store.dispatch('hideModal');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,23 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['currentContent', 'currentContentBlock', 'currentNoteParent'])
|
...mapGetters(['currentContent', 'currentNoteBlock', 'currentNoteParent', 'noteType'])
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
addNote(n) {
|
addNote(n) {
|
||||||
const content = this.currentContent;
|
const content = this.currentContent;
|
||||||
const contentBlock = this.currentContentBlock;
|
const block = this.currentNoteBlock;
|
||||||
const parent = this.currentNoteParent;
|
const parent = this.currentNoteParent;
|
||||||
|
const type = this.noteType;
|
||||||
const text = n.text;
|
const text = n.text;
|
||||||
let note = {};
|
let note = {};
|
||||||
if (content > '') {
|
if (content > '') {
|
||||||
note = {
|
note = {
|
||||||
content,
|
content,
|
||||||
contentBlock,
|
block,
|
||||||
text
|
text,
|
||||||
|
type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
note = {
|
note = {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {InMemoryCache} from 'apollo-cache-inmemory/lib/index'
|
import {InMemoryCache, defaultDataIdFromObject} from 'apollo-cache-inmemory/lib/index'
|
||||||
import {createHttpLink} from 'apollo-link-http'
|
import {createHttpLink} from 'apollo-link-http'
|
||||||
import {ApolloClient} from 'apollo-client'
|
import {ApolloClient} from 'apollo-client'
|
||||||
import {ApolloLink} from 'apollo-link'
|
import {ApolloLink} from 'apollo-link'
|
||||||
|
|
@ -43,6 +43,14 @@ export default function (uri) {
|
||||||
const composedLink = ApolloLink.from([createOmitTypenameLink, consoleLink, httpLink]);
|
const composedLink = ApolloLink.from([createOmitTypenameLink, consoleLink, httpLink]);
|
||||||
|
|
||||||
const cache = new InMemoryCache({
|
const cache = new InMemoryCache({
|
||||||
|
dataIdFromObject: obj => {
|
||||||
|
switch (obj.__typename) {
|
||||||
|
case 'InstrumentNode':
|
||||||
|
return `${obj.__typename}:${obj.slug}`;
|
||||||
|
default:
|
||||||
|
return defaultDataIdFromObject(obj);
|
||||||
|
}
|
||||||
|
},
|
||||||
cacheRedirects: {
|
cacheRedirects: {
|
||||||
Query: {
|
Query: {
|
||||||
contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}),
|
contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}),
|
||||||
|
|
@ -51,7 +59,7 @@ export default function (uri) {
|
||||||
objective: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveNode', id: args.id}),
|
objective: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveNode', id: args.id}),
|
||||||
objectiveGroup: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveGroupNode', id: args.id}),
|
objectiveGroup: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveGroupNode', id: args.id}),
|
||||||
// todo: remove, the new client seems to cache this correctly by itself
|
// todo: remove, the new client seems to cache this correctly by itself
|
||||||
// module: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ModuleNode', id: args.id}),
|
// module: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ModuleNode', id: args.slug}),
|
||||||
projectEntry: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ProjectEntryNode', id: args.id}),
|
projectEntry: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ProjectEntryNode', id: args.id}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
query BookQuery {
|
|
||||||
books {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
topics {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
teaser
|
|
||||||
description
|
|
||||||
modules {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
teaser
|
|
||||||
heroImage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
fragment InstrumentParts on InstrumentNode {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
bookmarks {
|
||||||
|
uuid
|
||||||
|
note {
|
||||||
|
id
|
||||||
|
text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
|
#import "./fragments/instrumentParts.gql"
|
||||||
query InstrumentQuery($slug: String!){
|
query InstrumentQuery($slug: String!){
|
||||||
instrument(slug: $slug) {
|
instrument(slug: $slug) {
|
||||||
id
|
...InstrumentParts
|
||||||
title
|
|
||||||
slug
|
|
||||||
type
|
|
||||||
contents
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#import "./fragments/instrumentParts.gql"
|
||||||
|
query InstrumentQuery($id: ID!){
|
||||||
|
instrument(id: $id) {
|
||||||
|
...InstrumentParts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {
|
||||||
|
updateInstrumentBookmark(input: $input) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,41 +2,68 @@ import ADD_NOTE_MUTATION from '@/graphql/gql/mutations/addNote.gql';
|
||||||
import CONTENT_BLOCK_QUERY from '@/graphql/gql/contentBlockQuery.gql';
|
import CONTENT_BLOCK_QUERY from '@/graphql/gql/contentBlockQuery.gql';
|
||||||
import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql';
|
import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql';
|
||||||
import MODULE_QUERY from '@/graphql/gql/moduleByIdQuery.gql';
|
import MODULE_QUERY from '@/graphql/gql/moduleByIdQuery.gql';
|
||||||
|
import INSTRUMENT_FRAGMENT from '@/graphql/gql/fragments/instrumentParts.gql';
|
||||||
|
|
||||||
const getBlockType = id => atob(id).split(':')[0]
|
const getBlockType = id => atob(id).split(':')[0];
|
||||||
|
const compareUuid = note => element => element.uuid === note.content;
|
||||||
|
|
||||||
export const constructNoteMutation = (n) => {
|
export const constructNoteMutation = (n) => {
|
||||||
let update = () => {
|
let update = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (n.contentBlock) { // has a content block, so it is a content block bookmark
|
if (n.block) { // has a block, so it is a content block or instrument bookmark
|
||||||
update = (store, {data: {addNote: {note}}}) => {
|
update = (store, {data: {addNote: {note}}}) => {
|
||||||
const query = CONTENT_BLOCK_QUERY;
|
if (n.type === 'ContentBlockNode') {
|
||||||
const variables = {id: n.contentBlock};
|
const query = CONTENT_BLOCK_QUERY;
|
||||||
const data = store.readQuery({
|
const variables = {id: n.block};
|
||||||
query,
|
const data = store.readQuery({
|
||||||
variables
|
query,
|
||||||
});
|
variables
|
||||||
|
});
|
||||||
|
|
||||||
const bookmarks = data.contentBlock.bookmarks;
|
const bookmarks = data.contentBlock.bookmarks;
|
||||||
|
|
||||||
let index = bookmarks.findIndex(element => {
|
let index = bookmarks.findIndex(compareUuid(n));
|
||||||
return element.uuid === n.content;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
let el = bookmarks[index];
|
let el = bookmarks[index];
|
||||||
el.note = note;
|
el.note = note;
|
||||||
bookmarks.splice(index, 1, el);
|
bookmarks.splice(index, 1, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.contentBlock.bookmarks = bookmarks;
|
||||||
|
|
||||||
|
store.writeQuery({
|
||||||
|
data,
|
||||||
|
query,
|
||||||
|
variables
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const fragment = INSTRUMENT_FRAGMENT;
|
||||||
|
const id = `InstrumentNode:${n.block}`;
|
||||||
|
const data = store.readFragment({
|
||||||
|
fragment,
|
||||||
|
id
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarks = data.bookmarks;
|
||||||
|
|
||||||
|
let index = bookmarks.findIndex(compareUuid(n));
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
let el = bookmarks[index];
|
||||||
|
el.note = note;
|
||||||
|
bookmarks.splice(index, 1, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.bookmarks = bookmarks;
|
||||||
|
|
||||||
|
store.writeFragment({
|
||||||
|
data,
|
||||||
|
fragment,
|
||||||
|
id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
data.contentBlock.bookmarks = bookmarks;
|
|
||||||
|
|
||||||
store.writeQuery({
|
|
||||||
data,
|
|
||||||
query,
|
|
||||||
variables
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
} else { // it's a chapter bookmark or a module bookmark
|
} else { // it's a chapter bookmark or a module bookmark
|
||||||
update = (store, {data: {addNote: {note}}}) => {
|
update = (store, {data: {addNote: {note}}}) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
import UPDATE_CONTENT_BOOKMARK from '@/graphql/gql/mutations/updateContentBookmark.gql';
|
||||||
|
import UPDATE_INSTRUMENT_BOOKMARK from '@/graphql/gql/mutations/updateInstrumentBookmark.gql';
|
||||||
|
import CONTENT_BLOCK_QUERY from '@/graphql/gql/contentBlockQuery.gql';
|
||||||
|
import INSTRUMENT_FRAGMENT from '@/graphql/gql/fragments/instrumentParts.gql';
|
||||||
|
|
||||||
|
const compareUuid = uuid => element => element.uuid === uuid;
|
||||||
|
|
||||||
|
export const constructContentComponentBookmarkMutation = (uuid, bookmarked, parent, root) => {
|
||||||
|
let mutation = {};
|
||||||
|
|
||||||
|
if (parent.__typename === 'ContentBlockNode') {
|
||||||
|
mutation = {
|
||||||
|
mutation: UPDATE_CONTENT_BOOKMARK,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
uuid,
|
||||||
|
contentBlock: root,
|
||||||
|
bookmarked
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: (store, response) => {
|
||||||
|
const query = CONTENT_BLOCK_QUERY;
|
||||||
|
const variables = {id: root};
|
||||||
|
const data = store.readQuery({
|
||||||
|
query,
|
||||||
|
variables
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarks = data.contentBlock.bookmarks;
|
||||||
|
|
||||||
|
if (bookmarked) {
|
||||||
|
bookmarks.push({
|
||||||
|
note: null,
|
||||||
|
uuid,
|
||||||
|
__typename: 'ContentBlockBookmarkNode'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let index = bookmarks.findIndex(compareUuid(uuid));
|
||||||
|
if (index > -1) {
|
||||||
|
bookmarks.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.contentBlock.bookmarks = bookmarks;
|
||||||
|
|
||||||
|
store.writeQuery({
|
||||||
|
data,
|
||||||
|
query,
|
||||||
|
variables
|
||||||
|
});
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: 'Mutation',
|
||||||
|
updateContentBookmark: {
|
||||||
|
__typename: 'UpdateContentBookmarkPayload',
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mutation = {
|
||||||
|
mutation: UPDATE_INSTRUMENT_BOOKMARK,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
uuid,
|
||||||
|
instrument: root,
|
||||||
|
bookmarked
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: (store, response) => {
|
||||||
|
const fragment = INSTRUMENT_FRAGMENT;
|
||||||
|
const id = `InstrumentNode:${root}`;
|
||||||
|
const data = store.readFragment({
|
||||||
|
fragment,
|
||||||
|
id
|
||||||
|
});
|
||||||
|
|
||||||
|
const bookmarks = data.bookmarks;
|
||||||
|
|
||||||
|
if (bookmarked) {
|
||||||
|
bookmarks.push({
|
||||||
|
note: null,
|
||||||
|
uuid,
|
||||||
|
__typename: 'InstrumentBookmarkNode'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let index = bookmarks.findIndex(compareUuid(uuid));
|
||||||
|
if (index > -1) {
|
||||||
|
bookmarks.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.bookmarks = bookmarks;
|
||||||
|
|
||||||
|
store.writeFragment({
|
||||||
|
data,
|
||||||
|
fragment,
|
||||||
|
id
|
||||||
|
});
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: 'Mutation',
|
||||||
|
updateInstrumentBookmark: {
|
||||||
|
__typename: 'UpdateInstrumentBookmarkPayload',
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return mutation;
|
||||||
|
};
|
||||||
|
|
@ -2,11 +2,15 @@
|
||||||
<div class="instrument">
|
<div class="instrument">
|
||||||
<h1 class="instrument__title">{{instrument.title}}</h1>
|
<h1 class="instrument__title">{{instrument.title}}</h1>
|
||||||
|
|
||||||
<component v-for="component in instrument.contents"
|
<content-component v-for="component in instrument.contents"
|
||||||
:key="component.id"
|
:key="component.id"
|
||||||
:is="component.type"
|
:component="component"
|
||||||
v-bind="component">
|
:root="instrument.slug"
|
||||||
</component>
|
:parent="instrument"
|
||||||
|
:bookmarks="instrument.bookmarks"
|
||||||
|
:notes="instrument.notes"
|
||||||
|
>
|
||||||
|
</content-component>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -14,17 +18,7 @@
|
||||||
<script>
|
<script>
|
||||||
import INSTRUMENT_QUERY from '@/graphql/gql/instrumentQuery.gql';
|
import INSTRUMENT_QUERY from '@/graphql/gql/instrumentQuery.gql';
|
||||||
|
|
||||||
import TextBlock from '@/components/content-blocks/TextBlock';
|
import ContentComponent from '@/components/content-blocks/ContentComponent';
|
||||||
import InstrumentWidget from '@/components/content-blocks/InstrumentWidget';
|
|
||||||
import ImageBlock from '@/components/content-blocks/ImageBlock';
|
|
||||||
import ImageUrlBlock from '@/components/content-blocks/ImageUrlBlock';
|
|
||||||
import VideoBlock from '@/components/content-blocks/VideoBlock';
|
|
||||||
import LinkBlock from '@/components/content-blocks/LinkBlock';
|
|
||||||
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
|
||||||
import SectionTitleBlock from '@/components/content-blocks/SectionTitleBlock';
|
|
||||||
import SubtitleBlock from '@/components/content-blocks/SubtitleBlock';
|
|
||||||
import GeniallyBlock from '@/components/content-blocks/GeniallyBlock';
|
|
||||||
import ThinglinkBlock from '@/components/content-blocks/ThinglinkBlock';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
apollo: {
|
apollo: {
|
||||||
|
|
@ -39,18 +33,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
'text_block': TextBlock,
|
ContentComponent
|
||||||
'basic_knowledge': InstrumentWidget, // for legacy
|
|
||||||
'instrument': InstrumentWidget,
|
|
||||||
'image_block': ImageBlock,
|
|
||||||
'image_url_block': ImageUrlBlock,
|
|
||||||
'video_block': VideoBlock,
|
|
||||||
'link_block': LinkBlock,
|
|
||||||
'document_block': DocumentBlock,
|
|
||||||
'section_title': SectionTitleBlock,
|
|
||||||
'subtitle': SubtitleBlock,
|
|
||||||
'genially_block': GeniallyBlock,
|
|
||||||
'thinglink_block': ThinglinkBlock
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ export default new Vuex.Store({
|
||||||
contentBlockPosition: {},
|
contentBlockPosition: {},
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
currentContent: '',
|
currentContent: '',
|
||||||
currentContentBlock: '',
|
currentNoteBlock: '',
|
||||||
|
noteType: '',
|
||||||
currentRoomEntry: '',
|
currentRoomEntry: '',
|
||||||
parentRoom: null,
|
parentRoom: null,
|
||||||
parentModule: '',
|
parentModule: '',
|
||||||
|
|
@ -46,9 +47,10 @@ export default new Vuex.Store({
|
||||||
editModule: state => state.editModule,
|
editModule: state => state.editModule,
|
||||||
currentObjectiveGroup: state => state.currentObjectiveGroup,
|
currentObjectiveGroup: state => state.currentObjectiveGroup,
|
||||||
currentContent: state => state.currentContent,
|
currentContent: state => state.currentContent,
|
||||||
currentContentBlock: state => state.currentContentBlock,
|
currentNoteBlock: state => state.currentNoteBlock,
|
||||||
currentNote: state => state.currentNote,
|
currentNote: state => state.currentNote,
|
||||||
currentNoteParent: state => state.currentNoteParent,
|
currentNoteParent: state => state.currentNoteParent,
|
||||||
|
noteType: state => state.noteType,
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
@ -63,7 +65,7 @@ export default new Vuex.Store({
|
||||||
resetModalState({commit}) {
|
resetModalState({commit}) {
|
||||||
commit('setCurrentRoomEntry', '');
|
commit('setCurrentRoomEntry', '');
|
||||||
commit('setCurrentContent', '');
|
commit('setCurrentContent', '');
|
||||||
commit('setCurrentContentBlock', '');
|
commit('setCurrentNoteBlock', '');
|
||||||
commit('setCurrentNoteParent', '');
|
commit('setCurrentNoteParent', '');
|
||||||
commit('setContentBlockPosition', {});
|
commit('setContentBlockPosition', {});
|
||||||
commit('setParentRoom', null);
|
commit('setParentRoom', null);
|
||||||
|
|
@ -80,15 +82,16 @@ export default new Vuex.Store({
|
||||||
});
|
});
|
||||||
commit('setVimeoId', null);
|
commit('setVimeoId', null);
|
||||||
commit('setCurrentNote', null);
|
commit('setCurrentNote', null);
|
||||||
|
commit('setNoteType', '');
|
||||||
},
|
},
|
||||||
resetContentBlockPosition({commit}) {
|
resetContentBlockPosition({commit}) {
|
||||||
commit('setContentBlockPosition', {});
|
commit('setContentBlockPosition', {});
|
||||||
},
|
},
|
||||||
resetCurrentContentBlock({commit}) {
|
resetCurrentNoteBlock({commit}) {
|
||||||
commit('setCurrentContentBlock', '');
|
commit('setCurrentNoteBlock', '');
|
||||||
},
|
},
|
||||||
editContentBlock({commit, dispatch}, payload) {
|
editContentBlock({commit, dispatch}, payload) {
|
||||||
commit('setCurrentContentBlock', payload);
|
commit('setCurrentNoteBlock', payload);
|
||||||
dispatch('showModal', 'edit-content-block-wizard');
|
dispatch('showModal', 'edit-content-block-wizard');
|
||||||
},
|
},
|
||||||
addContentBlock({commit, dispatch}, payload) {
|
addContentBlock({commit, dispatch}, payload) {
|
||||||
|
|
@ -130,8 +133,9 @@ export default new Vuex.Store({
|
||||||
dispatch('showModal', 'edit-project-entry-wizard');
|
dispatch('showModal', 'edit-project-entry-wizard');
|
||||||
},
|
},
|
||||||
addNote({commit, dispatch}, payload) {
|
addNote({commit, dispatch}, payload) {
|
||||||
if (payload.contentBlock) {
|
if (payload.block) {
|
||||||
commit('setCurrentContentBlock', payload.contentBlock);
|
commit('setCurrentNoteBlock', payload.block);
|
||||||
|
commit('setNoteType', payload.type);
|
||||||
commit('setCurrentContent', payload.content);
|
commit('setCurrentContent', payload.content);
|
||||||
} else {
|
} else {
|
||||||
commit('setCurrentNoteParent', payload.parent);
|
commit('setCurrentNoteParent', payload.parent);
|
||||||
|
|
@ -197,8 +201,8 @@ export default new Vuex.Store({
|
||||||
setCurrentContent(state, payload) {
|
setCurrentContent(state, payload) {
|
||||||
state.currentContent = payload;
|
state.currentContent = payload;
|
||||||
},
|
},
|
||||||
setCurrentContentBlock(state, payload) {
|
setCurrentNoteBlock(state, payload) {
|
||||||
state.currentContentBlock = payload;
|
state.currentNoteBlock = payload;
|
||||||
},
|
},
|
||||||
setParentRoom(state, payload) {
|
setParentRoom(state, payload) {
|
||||||
state.parentRoom = payload;
|
state.parentRoom = payload;
|
||||||
|
|
@ -251,6 +255,9 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
setCurrentNoteParent(state, payload) {
|
setCurrentNoteParent(state, payload) {
|
||||||
state.currentNoteParent = payload;
|
state.currentNoteParent = payload;
|
||||||
|
},
|
||||||
|
setNoteType(state, payload) {
|
||||||
|
state.noteType = payload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@ from graphene_django import DjangoObjectType
|
||||||
from graphene_django.filter import DjangoFilterConnectionField
|
from graphene_django.filter import DjangoFilterConnectionField
|
||||||
|
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
|
from notes.models import InstrumentBookmark
|
||||||
|
from notes.schema import InstrumentBookmarkNode
|
||||||
from .models import BasicKnowledge
|
from .models import BasicKnowledge
|
||||||
|
|
||||||
|
|
||||||
class BasicKnowledgeNode(DjangoObjectType):
|
class InstrumentNode(DjangoObjectType):
|
||||||
|
bookmarks = graphene.List(InstrumentBookmarkNode)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BasicKnowledge
|
model = BasicKnowledge
|
||||||
filter_fields = ['slug', 'type']
|
filter_fields = ['slug', 'type']
|
||||||
|
|
@ -16,17 +20,23 @@ class BasicKnowledgeNode(DjangoObjectType):
|
||||||
'slug', 'title', 'type', 'contents',
|
'slug', 'title', 'type', 'contents',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def resolve_bookmarks(self, info, **kwargs):
|
||||||
|
return InstrumentBookmark.objects.filter(
|
||||||
|
user=info.context.user,
|
||||||
|
instrument=self
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BasicKnowledgeQuery(object):
|
class BasicKnowledgeQuery(object):
|
||||||
instrument = graphene.Field(BasicKnowledgeNode, slug=graphene.String(), id=graphene.ID())
|
instrument = graphene.Field(InstrumentNode, slug=graphene.String(), id=graphene.ID())
|
||||||
instruments = DjangoFilterConnectionField(BasicKnowledgeNode)
|
instruments = DjangoFilterConnectionField(InstrumentNode)
|
||||||
|
|
||||||
def resolve_instrument(self, info, **kwargs):
|
def resolve_instrument(self, info, **kwargs):
|
||||||
slug = kwargs.get('slug')
|
slug = kwargs.get('slug')
|
||||||
room_id = kwargs.get('id')
|
instrument_id = kwargs.get('id')
|
||||||
|
|
||||||
if room_id is not None:
|
if instrument_id is not None:
|
||||||
return get_object(BasicKnowledge, room_id)
|
return get_object(BasicKnowledge, instrument_id)
|
||||||
if slug is not None:
|
if slug is not None:
|
||||||
return BasicKnowledge.objects.get(slug=slug)
|
return BasicKnowledge.objects.get(slug=slug)
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class ContentBlockNode(DjangoObjectType):
|
||||||
def resolve_contents(self, info, **kwargs):
|
def resolve_contents(self, info, **kwargs):
|
||||||
updated_stream_data = []
|
updated_stream_data = []
|
||||||
for content in self.contents.stream_data:
|
for content in self.contents.stream_data:
|
||||||
if not are_solutions_enabled_for(info.context.user, self.module) and content['type'] == 'solution':
|
if content['type'] == 'solution' and not are_solutions_enabled_for(info.context.user, self.module):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if content['type'] == 'content_list_item':
|
if content['type'] == 'content_list_item':
|
||||||
|
|
@ -85,18 +85,21 @@ class ChapterNode(DjangoObjectType):
|
||||||
def resolve_content_blocks(self, info, **kwargs):
|
def resolve_content_blocks(self, info, **kwargs):
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
school_classes = user.school_classes.values_list('pk')
|
school_classes = user.school_classes.values_list('pk')
|
||||||
|
by_parent = ContentBlock.get_by_parent(self).prefetch_related(
|
||||||
|
'visible_for__schoolclass').prefetch_related(
|
||||||
|
'hidden_for__schoolclass')
|
||||||
|
|
||||||
if user.has_perm('users.can_manage_school_class_content'): # teacher
|
if user.has_perm('users.can_manage_school_class_content'): # teacher
|
||||||
publisher_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=False)
|
publisher_content_blocks = by_parent.filter(user_created=False)
|
||||||
user_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True, owner=user)
|
user_created_content_blocks = by_parent.filter(user_created=True, owner=user)
|
||||||
else: # student
|
else: # student
|
||||||
publisher_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=False).exclude(
|
publisher_content_blocks = by_parent.filter(user_created=False).exclude(
|
||||||
hidden_for__in=school_classes)
|
hidden_for__in=school_classes)
|
||||||
|
|
||||||
self_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True, owner=user)
|
self_created_content_blocks = by_parent.filter(user_created=True, owner=user)
|
||||||
|
|
||||||
user_created_content_blocks = ContentBlock.get_by_parent(self).filter(user_created=True,
|
user_created_content_blocks = by_parent.filter(user_created=True,
|
||||||
visible_for__in=school_classes).union(
|
visible_for__in=school_classes).union(
|
||||||
self_created_content_blocks)
|
self_created_content_blocks)
|
||||||
|
|
||||||
return publisher_content_blocks.union(user_created_content_blocks)
|
return publisher_content_blocks.union(user_created_content_blocks)
|
||||||
|
|
@ -180,6 +183,12 @@ class ModuleNode(DjangoObjectType):
|
||||||
chapters = Chapter.objects.live().descendant_of(self)
|
chapters = Chapter.objects.live().descendant_of(self)
|
||||||
return ChapterBookmark.objects.filter(chapter__in=chapters, user=user)
|
return ChapterBookmark.objects.filter(chapter__in=chapters, user=user)
|
||||||
|
|
||||||
|
def resolve_objective_groups(self, root, **kwargs):
|
||||||
|
return self.objective_groups.all() \
|
||||||
|
.prefetch_related('hidden_for__schoolclass') \
|
||||||
|
.prefetch_related('visible_for__schoolclass') \
|
||||||
|
.prefetch_related('objectives__objective_progress')
|
||||||
|
|
||||||
|
|
||||||
class TopicNode(DjangoObjectType):
|
class TopicNode(DjangoObjectType):
|
||||||
pk = graphene.Int()
|
pk = graphene.Int()
|
||||||
|
|
@ -278,6 +287,7 @@ class BookQuery(object):
|
||||||
elif slug is not None:
|
elif slug is not None:
|
||||||
module = Module.objects.get(slug=slug)
|
module = Module.objects.get(slug=slug)
|
||||||
|
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|
||||||
def resolve_topic(self, info, **kwargs):
|
def resolve_topic(self, info, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ if DEBUG:
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||||
|
'django.middleware.gzip.GZipMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware'
|
'django.contrib.sessions.middleware.SessionMiddleware'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ from graphene import InputObjectType
|
||||||
|
|
||||||
class AddNoteArgument(InputObjectType):
|
class AddNoteArgument(InputObjectType):
|
||||||
content = graphene.UUID()
|
content = graphene.UUID()
|
||||||
content_block = graphene.ID()
|
block = graphene.String()
|
||||||
|
type = graphene.String()
|
||||||
parent = graphene.ID()
|
parent = graphene.ID()
|
||||||
text = graphene.String(required=True)
|
text = graphene.String(required=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 2.0.6 on 2020-01-08 12:54
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('basicknowledge', '0004_auto_20191128_1601'),
|
||||||
|
('notes', '0002_chapterbookmark_modulebookmark'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='InstrumentBookmark',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('uuid', models.UUIDField(unique=True)),
|
||||||
|
('instrument', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='basicknowledge.BasicKnowledge')),
|
||||||
|
('note', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to='notes.Note')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -28,3 +28,7 @@ class ModuleBookmark(Bookmark):
|
||||||
|
|
||||||
class ChapterBookmark(Bookmark):
|
class ChapterBookmark(Bookmark):
|
||||||
chapter = models.ForeignKey('books.Chapter', on_delete=models.CASCADE)
|
chapter = models.ForeignKey('books.Chapter', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class InstrumentBookmark(Bookmark):
|
||||||
|
uuid = models.UUIDField(unique=True)
|
||||||
|
instrument = models.ForeignKey('basicknowledge.BasicKnowledge', on_delete=models.CASCADE)
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ from graphene import relay
|
||||||
from graphql_relay import from_global_id
|
from graphql_relay import from_global_id
|
||||||
|
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
|
from basicknowledge.models import BasicKnowledge
|
||||||
from books.models import ContentBlock, Chapter, Module
|
from books.models import ContentBlock, Chapter, Module
|
||||||
from notes.inputs import AddNoteArgument, UpdateNoteArgument
|
from notes.inputs import AddNoteArgument, UpdateNoteArgument
|
||||||
from notes.models import ContentBlockBookmark, Note, ChapterBookmark, ModuleBookmark
|
from notes.models import ContentBlockBookmark, Note, ChapterBookmark, ModuleBookmark, InstrumentBookmark
|
||||||
from notes.schema import NoteNode
|
from notes.schema import NoteNode
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,18 +59,27 @@ class AddNote(relay.ClientIDMutation):
|
||||||
|
|
||||||
note = kwargs.get('note')
|
note = kwargs.get('note')
|
||||||
content_uuid = note.get('content', '')
|
content_uuid = note.get('content', '')
|
||||||
content_block_id = note.get('content_block', '')
|
content_block_id = note.get('block', '')
|
||||||
parent = note.get('parent')
|
parent = note.get('parent')
|
||||||
text = note.get('text')
|
text = note.get('text')
|
||||||
|
|
||||||
if content_uuid != '':
|
if content_uuid != '':
|
||||||
content_block = get_object(ContentBlock, content_block_id)
|
type = note.get('type')
|
||||||
|
if type == 'ContentBlockNode':
|
||||||
|
content_block = get_object(ContentBlock, content_block_id)
|
||||||
|
|
||||||
bookmark = ContentBlockBookmark.objects.get(
|
bookmark = ContentBlockBookmark.objects.get(
|
||||||
content_block=content_block,
|
content_block=content_block,
|
||||||
uuid=content_uuid,
|
uuid=content_uuid,
|
||||||
user=user
|
user=user
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
instrument = BasicKnowledge.objects.get(slug=content_block_id)
|
||||||
|
bookmark = InstrumentBookmark.objects.get(
|
||||||
|
instrument=instrument,
|
||||||
|
uuid=content_uuid,
|
||||||
|
user=user
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
type, id = from_global_id(parent)
|
type, id = from_global_id(parent)
|
||||||
if type == 'ModuleNode':
|
if type == 'ModuleNode':
|
||||||
|
|
@ -172,9 +182,43 @@ class UpdateModuleBookmark(relay.ClientIDMutation):
|
||||||
return cls(success=True)
|
return cls(success=True)
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateInstrumentBookmark(relay.ClientIDMutation):
|
||||||
|
class Input:
|
||||||
|
uuid = graphene.UUID(required=True)
|
||||||
|
instrument = graphene.String(required=True)
|
||||||
|
bookmarked = graphene.Boolean(required=True)
|
||||||
|
|
||||||
|
success = graphene.Boolean()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate_and_get_payload(cls, root, info, **kwargs):
|
||||||
|
user = info.context.user
|
||||||
|
instrument_slug = kwargs.get('instrument')
|
||||||
|
uuid = kwargs.get('uuid')
|
||||||
|
bookmarked = kwargs.get('bookmarked')
|
||||||
|
|
||||||
|
instrument = BasicKnowledge.objects.get(slug=instrument_slug)
|
||||||
|
|
||||||
|
if bookmarked:
|
||||||
|
InstrumentBookmark.objects.create(
|
||||||
|
instrument=instrument,
|
||||||
|
uuid=uuid,
|
||||||
|
user=user
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
InstrumentBookmark.objects.get(
|
||||||
|
instrument=instrument,
|
||||||
|
uuid=uuid,
|
||||||
|
user=user
|
||||||
|
).delete()
|
||||||
|
|
||||||
|
return cls(success=True)
|
||||||
|
|
||||||
|
|
||||||
class NoteMutations:
|
class NoteMutations:
|
||||||
add_note = AddNote.Field()
|
add_note = AddNote.Field()
|
||||||
update_note = UpdateNote.Field()
|
update_note = UpdateNote.Field()
|
||||||
update_content_bookmark = UpdateContentBookmark.Field()
|
update_content_bookmark = UpdateContentBookmark.Field()
|
||||||
update_chapter_bookmark = UpdateChapterBookmark.Field()
|
update_chapter_bookmark = UpdateChapterBookmark.Field()
|
||||||
update_module_bookmark = UpdateModuleBookmark.Field()
|
update_module_bookmark = UpdateModuleBookmark.Field()
|
||||||
|
update_instrument_bookmark = UpdateInstrumentBookmark.Field()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import graphene
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from notes.models import Note, ContentBlockBookmark, ModuleBookmark, ChapterBookmark
|
from notes.models import Note, ContentBlockBookmark, ModuleBookmark, ChapterBookmark, InstrumentBookmark
|
||||||
|
|
||||||
|
|
||||||
class NoteNode(DjangoObjectType):
|
class NoteNode(DjangoObjectType):
|
||||||
|
|
@ -17,7 +17,6 @@ class NoteNode(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class ContentBlockBookmarkNode(DjangoObjectType):
|
class ContentBlockBookmarkNode(DjangoObjectType):
|
||||||
# note = graphene.
|
|
||||||
uuid = graphene.UUID()
|
uuid = graphene.UUID()
|
||||||
note = graphene.Field(NoteNode)
|
note = graphene.Field(NoteNode)
|
||||||
|
|
||||||
|
|
@ -41,3 +40,13 @@ class ChapterBookmarkNode(DjangoObjectType):
|
||||||
model = ChapterBookmark
|
model = ChapterBookmark
|
||||||
filter_fields = []
|
filter_fields = []
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
|
|
||||||
|
|
||||||
|
class InstrumentBookmarkNode(DjangoObjectType):
|
||||||
|
uuid = graphene.UUID()
|
||||||
|
note = graphene.Field(NoteNode)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InstrumentBookmark
|
||||||
|
filter_fields = []
|
||||||
|
interfaces = (relay.Node,)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue