Add content to bookmark on Activity page

Resolves MS-903 #complete
This commit is contained in:
Ramon Wenger 2024-03-11 11:47:09 +01:00
parent 3cdbfa8abf
commit 7af5f07137
9 changed files with 1330 additions and 1961 deletions

3175
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@
"@babel/preset-stage-2": "^7.0.0", "@babel/preset-stage-2": "^7.0.0",
"@babel/preset-typescript": "^7.16.7", "@babel/preset-typescript": "^7.16.7",
"@babel/runtime": "^7.5.4", "@babel/runtime": "^7.5.4",
"@graphql-codegen/cli": "^5.0.0", "@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/client-preset": "^4.1.0", "@graphql-codegen/client-preset": "^4.1.0",
"@graphql-tools/jest-transform": "^1.2.2", "@graphql-tools/jest-transform": "^1.2.2",
"@graphql-tools/mock": "^8.6.5", "@graphql-tools/mock": "^8.6.5",
@ -84,7 +84,7 @@
"eslint-plugin-cypress": "^2.12.1", "eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-vue": "^9.6.0", "eslint-plugin-vue": "^9.6.0",
"graphql": "^16.3.0", "graphql": "^16.3.0",
"graphql-config": "^4.3.0", "graphql-config": "^5.0.3",
"graphql-tag": "^2.10.1", "graphql-tag": "^2.10.1",
"graphql-tools": "^8.2.5", "graphql-tools": "^8.2.5",
"jest": "^29.2.2", "jest": "^29.2.2",

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
import { FragmentDefinitionNode } from 'graphql'; import { FragmentDefinitionNode } from 'graphql';
import { Incremental } from './graphql'; import { Incremental } from './graphql';

View File

@ -38,7 +38,7 @@ const documents = {
"\n fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode {\n highlights {\n id\n }\n }\n ": types.ContentBlockHighlightsWithIdOnlyFragmentFragmentDoc, "\n fragment ContentBlockHighlightsWithIdOnlyFragment on ContentBlockNode {\n highlights {\n id\n }\n }\n ": types.ContentBlockHighlightsWithIdOnlyFragmentFragmentDoc,
"\n mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {\n updateInstrumentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateInstrumentBookmarkDocument, "\n mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {\n updateInstrumentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateInstrumentBookmarkDocument,
"\n mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {\n updateContentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateContentBookmarkDocument, "\n mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {\n updateContentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateContentBookmarkDocument,
"\n query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\n }\n }\n }\n ": types.MyActivitiesQueryDocument, "\n query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n content\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n content\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n content\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n content\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\n }\n }\n }\n ": types.MyActivitiesQueryDocument,
"\n query ChapterQuery($id: ID!) {\n chapter(id: $id) {\n path\n }\n }\n ": types.ChapterQueryDocument, "\n query ChapterQuery($id: ID!) {\n chapter(id: $id) {\n path\n }\n }\n ": types.ChapterQueryDocument,
"\n query ContentBlockQuery($id: ID!) {\n contentBlock(id: $id) {\n path\n }\n }\n ": types.ContentBlockQueryDocument, "\n query ContentBlockQuery($id: ID!) {\n contentBlock(id: $id) {\n path\n }\n }\n ": types.ContentBlockQueryDocument,
"\n fragment InstrumentParts on InstrumentNode {\n id\n title\n intro\n slug\n language\n bookmarks {\n uuid\n note {\n id\n text\n }\n }\n type {\n id\n name\n category {\n id\n name\n foreground\n background\n }\n type\n }\n contents\n highlights {\n ...HighlightParts\n }\n }\n": types.InstrumentPartsFragmentDoc, "\n fragment InstrumentParts on InstrumentNode {\n id\n title\n intro\n slug\n language\n bookmarks {\n uuid\n note {\n id\n text\n }\n }\n type {\n id\n name\n category {\n id\n name\n foreground\n background\n }\n type\n }\n contents\n highlights {\n ...HighlightParts\n }\n }\n": types.InstrumentPartsFragmentDoc,
@ -166,7 +166,7 @@ export function graphql(source: "\n mutation UpdateContentBookmark($input:
/** /**
* 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 query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\n }\n }\n }\n "): (typeof documents)["\n query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\n }\n }\n }\n "]; export function graphql(source: "\n query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n content\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n content\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n content\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n content\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\n }\n }\n }\n "): (typeof documents)["\n query MyActivitiesQuery {\n myActivities {\n instruments {\n id\n slug\n title\n path\n highlights {\n ...HighlightParts\n }\n bookmarks {\n ... on InstrumentBookmarkNode {\n path\n content\n }\n }\n }\n topics {\n id\n title\n modules {\n id\n slug\n title\n metaTitle\n myHighlights {\n ...HighlightParts\n }\n myBookmarks {\n ... on ChapterBookmarkNode {\n chapter {\n path\n }\n path\n content\n note {\n id\n text\n }\n }\n ... on ContentBlockBookmarkNode {\n id\n uuid\n path\n content\n contentBlock {\n id\n path\n }\n note {\n id\n text\n }\n }\n ... on ModuleBookmarkNode {\n path\n content\n note {\n id\n text\n }\n }\n }\n mySubmissions {\n id\n text\n assignment {\n id\n title\n path\n module {\n slug\n }\n }\n }\n myAnswers {\n id\n survey {\n path\n id\n title\n }\n }\n }\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.
*/ */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,31 @@
<template>
<div>
Lesezeichen: <span>{{ content }}</span>
<div v-if="item.note">Notiz: {{ item.note.text }}</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface Item {
content: string;
note: {
text: string;
};
}
export interface Props {
item: Item;
}
const props = defineProps<Props>();
const stripHtml = (htmlString) => {
return htmlString.replace(/<[^>]*>?/gm, '') || '';
};
const content = computed(() => {
const strippedText = stripHtml(props.item.content) || '';
if (strippedText.length > 50) {
return strippedText.substring(0, 50) + '...';
}
return strippedText;
});
</script>

View File

@ -66,8 +66,7 @@
v-if="selectedCategory === BOOKMARKS" v-if="selectedCategory === BOOKMARKS"
v-slot="{ item }" v-slot="{ item }"
> >
<div>Lesezeichen: {{ item.id }}</div> <bookmark :item="item" />
<div v-if="item.note">Notiz: {{ item.note.text }}</div>
</instrument-activity-list> </instrument-activity-list>
<activity-list <activity-list
:topics="bookmarkTopics" :topics="bookmarkTopics"
@ -75,8 +74,7 @@
v-if="selectedCategory === BOOKMARKS" v-if="selectedCategory === BOOKMARKS"
v-slot="{ item }" v-slot="{ item }"
> >
<div>Lesezeichen: {{ item.id }}</div> <bookmark :item="item" />
<div v-if="item.note">Notiz: {{ item.note.text }}</div>
</activity-list> </activity-list>
<activity-list <activity-list
:topics="submissionsTopics" :topics="submissionsTopics"
@ -106,6 +104,7 @@ import { ref, computed } from 'vue';
import ActivityList from '@/components/profile/ActivityList.vue'; import ActivityList from '@/components/profile/ActivityList.vue';
import InstrumentActivityList from '@/components/profile/InstrumentActivityList.vue'; import InstrumentActivityList from '@/components/profile/InstrumentActivityList.vue';
import LoadingMessage from '@/components/ui/LoadingMessage.vue'; import LoadingMessage from '@/components/ui/LoadingMessage.vue';
import Bookmark from '@/components/Bookmark.vue';
import { TopicNode } from '@/__generated__/graphql'; import { TopicNode } from '@/__generated__/graphql';
const HIGHLIGHTS = 'highlights'; const HIGHLIGHTS = 'highlights';
@ -131,6 +130,7 @@ const { result, loading } = useQuery(
bookmarks { bookmarks {
... on InstrumentBookmarkNode { ... on InstrumentBookmarkNode {
path path
content
} }
} }
} }
@ -151,6 +151,7 @@ const { result, loading } = useQuery(
path path
} }
path path
content
note { note {
id id
text text
@ -160,6 +161,7 @@ const { result, loading } = useQuery(
id id
uuid uuid
path path
content
contentBlock { contentBlock {
id id
path path
@ -171,6 +173,7 @@ const { result, loading } = useQuery(
} }
... on ModuleBookmarkNode { ... on ModuleBookmarkNode {
path path
content
note { note {
id id
text text

View File

@ -1,3 +1,4 @@
import uuid
import graphene import graphene
from basicknowledge.queries import InstrumentNode from basicknowledge.queries import InstrumentNode
from books.schema.nodes import ContentBlockNode, ModuleNode from books.schema.nodes import ContentBlockNode, ModuleNode
@ -16,6 +17,32 @@ from notes.models import (
logger = get_logger(__name__) logger = get_logger(__name__)
content_dict = {
'assignment': 'Auftrag',
'basic_knowledge': '',
'survey': 'Übung',
'image_block': 'Bild',
'link_block': 'Link',
'solution': 'Lösung',
'video_block': 'Video',
'document_block': 'Dokument',
'infogram_block': 'Infografik',
'genially_block': 'Infografik',
'thinglink_block': 'Infografik',
'subtitle': 'Titel',
'instruction': 'Anweisung',
'cms_document_block': 'Dokument',
}
def find_content(content_list, bookmark):
found = (content for content in content_list if uuid.UUID(content['id']) == bookmark.uuid)
content = next(found, None)
if content is None:
return ''
if content['type'] in ['text_block', 'subtitle', 'solution', 'basic_knowledge']:
return content['value']['text']
return content_dict.get(content['type'], '')
class NoteNode(DjangoObjectType): class NoteNode(DjangoObjectType):
pk = graphene.Int() pk = graphene.Int()
@ -33,6 +60,7 @@ class ContentBlockBookmarkNode(DjangoObjectType):
uuid = graphene.UUID() uuid = graphene.UUID()
note = graphene.Field(NoteNode) note = graphene.Field(NoteNode)
path = graphene.String() path = graphene.String()
content = graphene.String()
class Meta: class Meta:
model = ContentBlockBookmark model = ContentBlockBookmark
@ -44,10 +72,17 @@ class ContentBlockBookmarkNode(DjangoObjectType):
def resolve_path(root: ContentBlockBookmark, info, **kwargs): def resolve_path(root: ContentBlockBookmark, info, **kwargs):
return root.content_block.route return root.content_block.route
@staticmethod
def resolve_content(root: ContentBlockBookmark, info, **kwargs):
contents = root.content_block.contents.raw_data
return find_content(contents, root)
class ModuleBookmarkNode(DjangoObjectType): class ModuleBookmarkNode(DjangoObjectType):
note = graphene.Field(NoteNode) note = graphene.Field(NoteNode)
path = graphene.String() path = graphene.String()
content = graphene.String()
class Meta: class Meta:
model = ModuleBookmark model = ModuleBookmark
@ -57,10 +92,15 @@ class ModuleBookmarkNode(DjangoObjectType):
def resolve_path(root: ModuleBookmark, info, **kwargs): def resolve_path(root: ModuleBookmark, info, **kwargs):
return root.module.route return root.module.route
@staticmethod
def resolve_content(root: ModuleBookmark, info, **kwargs):
return root.module.intro
class ChapterBookmarkNode(DjangoObjectType): class ChapterBookmarkNode(DjangoObjectType):
note = graphene.Field(NoteNode) note = graphene.Field(NoteNode)
path = graphene.String() path = graphene.String()
content = graphene.String()
class Meta: class Meta:
model = ChapterBookmark model = ChapterBookmark
@ -72,11 +112,17 @@ class ChapterBookmarkNode(DjangoObjectType):
def resolve_path(root: ChapterBookmark, info, **kwargs): def resolve_path(root: ChapterBookmark, info, **kwargs):
return root.chapter.route return root.chapter.route
@staticmethod
def resolve_content(root: ChapterBookmark, info, **kwargs):
return root.chapter.description
class InstrumentBookmarkNode(DjangoObjectType): class InstrumentBookmarkNode(DjangoObjectType):
uuid = graphene.UUID() uuid = graphene.UUID()
note = graphene.Field(NoteNode) note = graphene.Field(NoteNode)
path = graphene.String(required=True) path = graphene.String(required=True)
content = graphene.String()
class Meta: class Meta:
model = InstrumentBookmark model = InstrumentBookmark
@ -88,6 +134,11 @@ class InstrumentBookmarkNode(DjangoObjectType):
def resolve_path(root: InstrumentBookmark, info, **kwargs): def resolve_path(root: InstrumentBookmark, info, **kwargs):
return root.instrument.route return root.instrument.route
@staticmethod
def resolve_content(root: InstrumentBookmark, info, **kwargs):
contents = root.instrument.contents.raw_data
return find_content(contents, root)
class BookmarkNode(graphene.Union): class BookmarkNode(graphene.Union):
class Meta: class Meta:

View File

@ -363,6 +363,7 @@ type ContentBlockBookmarkNode implements Node {
uuid: UUID uuid: UUID
contentBlock: ContentBlockNode! contentBlock: ContentBlockNode!
path: String path: String
content: String
} }
type NoteNode implements Node { type NoteNode implements Node {
@ -383,6 +384,7 @@ type ModuleBookmarkNode {
note: NoteNode note: NoteNode
module: ModuleNode! module: ModuleNode!
path: String path: String
content: String
} }
type ChapterBookmarkNode implements Node { type ChapterBookmarkNode implements Node {
@ -392,6 +394,7 @@ type ChapterBookmarkNode implements Node {
note: NoteNode note: NoteNode
chapter: ChapterNode! chapter: ChapterNode!
path: String path: String
content: String
} }
type ChapterNode implements Node & ChapterInterface { type ChapterNode implements Node & ChapterInterface {
@ -426,6 +429,7 @@ type InstrumentBookmarkNode implements Node {
uuid: UUID uuid: UUID
instrument: InstrumentNode! instrument: InstrumentNode!
path: String! path: String!
content: String
} }
""" """