Merged in feature/content-block-instrument-type-MS-480 (pull request #119)
Feature/content block instrument type MS-480 Approved-by: Christian Cueni
This commit is contained in:
commit
6476d09f6d
|
|
@ -26,7 +26,11 @@ describe('Instruments on Module page', () => {
|
|||
title: 'Some Chapter',
|
||||
contentBlocks: [
|
||||
{
|
||||
'type': 'base_communication',
|
||||
'type': 'instrument',
|
||||
instrumentCategory: {
|
||||
id: 'category-id',
|
||||
name: 'Sprache & Kommunikation'
|
||||
},
|
||||
'title': 'Das Interview',
|
||||
'contents': [
|
||||
{
|
||||
|
|
@ -40,6 +44,7 @@ describe('Instruments on Module page', () => {
|
|||
{
|
||||
'type': 'normal',
|
||||
'title': 'Normaler Block',
|
||||
instrumentCategory: null,
|
||||
'contents': [
|
||||
{
|
||||
type: 'text_block',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
>
|
||||
<div
|
||||
:class="specialClass"
|
||||
:style="instrumentStyle"
|
||||
class="content-block"
|
||||
data-cy="content-block"
|
||||
>
|
||||
|
|
@ -43,6 +44,7 @@
|
|||
<h3
|
||||
class="content-block__instrument-label"
|
||||
data-cy="instrument-label"
|
||||
:style="instrumentLabelStyle"
|
||||
v-if="instrumentLabel !== ''"
|
||||
>
|
||||
{{ instrumentLabel }}
|
||||
|
|
@ -129,13 +131,37 @@
|
|||
specialClass() {
|
||||
return `content-block--${this.contentBlock.type.toLowerCase()}`;
|
||||
},
|
||||
isInstrumentBlock() {
|
||||
return !!this.contentBlock.instrumentCategory;
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
instrumentStyle() {
|
||||
if (this.isInstrumentBlock) {
|
||||
return {
|
||||
backgroundColor: this.contentBlock.instrumentCategory.background
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
instrumentLabel() {
|
||||
const contentType = this.contentBlock.type.toLowerCase();
|
||||
if (contentType.startsWith('base')) { // all instruments start with `base`
|
||||
if (contentType.startsWith('base')) { // all legacy instruments start with `base`
|
||||
return instrumentCategory(contentType);
|
||||
}
|
||||
if (this.isInstrumentBlock) {
|
||||
return instrumentCategory(this.contentBlock.instrumentCategory.name);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
instrumentLabelStyle() {
|
||||
if (this.isInstrumentBlock) {
|
||||
return {
|
||||
color: this.contentBlock.instrumentCategory.foreground
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
canEditContentBlock() {
|
||||
return this.contentBlock.mine && !this.contentBlock.indent;
|
||||
},
|
||||
|
|
@ -316,6 +342,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
&--instrument {
|
||||
@include content-box-base;
|
||||
}
|
||||
|
||||
/deep/ p {
|
||||
line-height: 1.5;
|
||||
margin-bottom: 1em;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
<router-link
|
||||
:to="{name: 'instrument', params: { slug: value.slug }}"
|
||||
class="instrument-widget__button button"
|
||||
:style="{
|
||||
borderColor: value.foreground
|
||||
}"
|
||||
>
|
||||
{{ $flavor.textInstrument }} anzeigen
|
||||
</router-link>
|
||||
|
|
@ -15,6 +18,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
export default {
|
||||
props: ['value'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,17 @@
|
|||
<a
|
||||
:class="typeClass"
|
||||
class="filter-entry"
|
||||
:style="categoryStyle"
|
||||
>
|
||||
<span class="filter-entry__text">{{ text }}</span>
|
||||
<span class="filter-entry__icon-wrapper">
|
||||
<chevron-right class="filter-entry__icon" />
|
||||
<span
|
||||
:style="activeStyle"
|
||||
class="filter-entry__icon-wrapper"
|
||||
>
|
||||
<chevron-right
|
||||
:style="{fill: category.foreground}"
|
||||
class="filter-entry__icon"
|
||||
/>
|
||||
</span>
|
||||
|
||||
</a>
|
||||
|
|
@ -13,6 +20,7 @@
|
|||
|
||||
<script>
|
||||
import INSTRUMENT_FILTER_QUERY from 'gql/local/instrumentFilter.gql';
|
||||
|
||||
const ChevronRight = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronRight');
|
||||
|
||||
export default {
|
||||
|
|
@ -31,7 +39,7 @@
|
|||
},
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -41,8 +49,8 @@
|
|||
|
||||
apollo: {
|
||||
instrumentFilter: {
|
||||
query: INSTRUMENT_FILTER_QUERY
|
||||
}
|
||||
query: INSTRUMENT_FILTER_QUERY,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -56,12 +64,31 @@
|
|||
computed: {
|
||||
isActive() {
|
||||
if (!this.instrumentFilter.currentFilter) {
|
||||
return this.type === '';
|
||||
return this.id === '';
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const [_, identifier] = this.instrumentFilter.currentFilter.split(':');
|
||||
return this.type === identifier;
|
||||
return this.id === identifier;
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
activeStyle() {
|
||||
if (this.isActive) {
|
||||
return {
|
||||
backgroundColor: this.category.background,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
categoryStyle() {
|
||||
if (this.isCategory) {
|
||||
return {
|
||||
color: this.category.foreground,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
typeClass() {
|
||||
return {
|
||||
'filter-entry--active': this.isActive,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
import {INTERDISCIPLINARY, LANGUAGE_COMMUNICATION, SOCIETY} from '@/consts/instrument.consts';
|
||||
import {instrumentCategory} from '@/helpers/instrumentType';
|
||||
|
||||
// todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
|
||||
export default {
|
||||
props: {
|
||||
instrument: {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ fragment ContentBlockParts on ContentBlockNode {
|
|||
slug
|
||||
userCreated
|
||||
mine
|
||||
instrumentCategory {
|
||||
id
|
||||
foreground
|
||||
background
|
||||
name
|
||||
}
|
||||
bookmarks {
|
||||
uuid
|
||||
note {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ query InstrumentCategoriesQuery {
|
|||
instrumentCategories {
|
||||
name
|
||||
id
|
||||
foreground
|
||||
background
|
||||
types {
|
||||
name
|
||||
id
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const instrumentType = (instrument) => {
|
|||
} else {
|
||||
return instrument.type.category.name;
|
||||
}
|
||||
return typeDictionary[category] || '';
|
||||
return typeDictionary[category] || category || '';
|
||||
};
|
||||
|
||||
const instrumentCategory = (instrument) => {
|
||||
|
|
|
|||
|
|
@ -61,18 +61,25 @@
|
|||
|
||||
}
|
||||
|
||||
@mixin content-box($color-list) {
|
||||
background-color: nth($color-list, 2);
|
||||
@mixin content-box-base {
|
||||
padding: 15px;
|
||||
align-items: start;
|
||||
border-radius: $default-border-radius;
|
||||
|
||||
/deep/ .button {
|
||||
border-color: nth($color-list, 1);
|
||||
background-color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin content-box($color-list) {
|
||||
@include content-box-base;
|
||||
background-color: nth($color-list, 2);
|
||||
|
||||
/deep/ .button {
|
||||
border-color: nth($color-list, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin desktop {
|
||||
@media (min-width: 1200px) {
|
||||
@content
|
||||
|
|
|
|||
|
|
@ -81,9 +81,10 @@ def augment_fields(raw_data):
|
|||
logger.error('Survey {} does not exist'.format(survey_id))
|
||||
if _type == 'basic_knowledge' or _type == 'instrument':
|
||||
_value = data['value']
|
||||
basic_knowledge = BasicKnowledge.objects.get(pk=_value['basic_knowledge'])
|
||||
instrument = BasicKnowledge.objects.get(pk=_value['basic_knowledge'])
|
||||
_value.update({
|
||||
'slug': basic_knowledge.slug
|
||||
'slug': instrument.slug,
|
||||
'foreground': instrument.new_type.category.foreground
|
||||
})
|
||||
data['value'] = _value
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class ContentBlockFactory(BasePageFactory):
|
|||
class Meta:
|
||||
model = ContentBlock
|
||||
|
||||
type = factory.LazyAttribute(lambda x: random.choice(['normal', 'base_communication', 'task', 'base_society']))
|
||||
type = factory.LazyAttribute(lambda x: random.choice(['normal', 'instrument', 'task',]))
|
||||
|
||||
contents = wagtail_factories.StreamFieldFactory({
|
||||
'text_block': TextBlockFactory,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.13 on 2022-09-15 13:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0036_alter_contentblock_contents'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('normal', 'Normal'), ('base_communication', 'Instrument Sprache & Kommunikation'), ('task', 'Auftrag'), ('instrument', 'Instrument'), ('base_society', 'Instrument Gesellschaft'), ('base_interdisciplinary', 'Überfachliches Instrument')], default='normal', max_length=100),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 3.2.13 on 2022-09-15 13:40
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def migrate_instruments(apps, schema_editor):
|
||||
ContentBlock = apps.get_model('books', 'ContentBlock')
|
||||
ContentBlock.objects.filter(type__startswith='base_').update(type='instrument')
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0037_alter_contentblock_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_instruments, migrations.RunPython.noop)
|
||||
]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.13 on 2022-09-15 14:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0038_auto_20220915_1340'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('normal', 'Normal'), ('task', 'Auftrag'), ('instrument', 'Instrument')], default='normal', max_length=100),
|
||||
),
|
||||
]
|
||||
|
|
@ -26,17 +26,13 @@ class ContentBlock(StrictHierarchyPage):
|
|||
verbose_name_plural = 'Inhaltsblöcke'
|
||||
|
||||
NORMAL = 'normal'
|
||||
BASE_COMMUNICATION = 'base_communication'
|
||||
TASK = 'task'
|
||||
BASE_SOCIETY = 'base_society'
|
||||
BASE_INTERDISCIPLINARY = 'base_interdisciplinary'
|
||||
INSTRUMENT = 'instrument'
|
||||
|
||||
TYPE_CHOICES = (
|
||||
(NORMAL, 'Normal'),
|
||||
(BASE_COMMUNICATION, 'Instrument Sprache & Kommunikation'),
|
||||
(TASK, 'Auftrag'),
|
||||
(BASE_SOCIETY, 'Instrument Gesellschaft'),
|
||||
(BASE_INTERDISCIPLINARY, 'Überfachliches Instrument'),
|
||||
(INSTRUMENT, 'Instrument'),
|
||||
)
|
||||
|
||||
# blocks without owner are visible by default, need to be hidden for each class
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import graphene
|
|||
from graphene import relay
|
||||
from graphene_django import DjangoObjectType
|
||||
|
||||
from basicknowledge.models import BasicKnowledge
|
||||
from basicknowledge.queries import InstrumentCategoryNode
|
||||
from books.models import ContentBlock
|
||||
from books.schema.interfaces.contentblock import ContentBlockInterface
|
||||
from books.utils import are_solutions_enabled_for
|
||||
|
|
@ -40,6 +42,7 @@ class ContentBlockNode(DjangoObjectType, HiddenAndVisibleForMixin):
|
|||
mine = graphene.Boolean()
|
||||
bookmarks = graphene.List(ContentBlockBookmarkNode)
|
||||
original_creator = graphene.Field('users.schema.PublicUserNode')
|
||||
instrument_category = graphene.Field(InstrumentCategoryNode)
|
||||
|
||||
class Meta:
|
||||
model = ContentBlock
|
||||
|
|
@ -80,6 +83,17 @@ class ContentBlockNode(DjangoObjectType, HiddenAndVisibleForMixin):
|
|||
content_block=self
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def resolve_instrument_category(root: ContentBlock, info, **kwargs):
|
||||
if root.type == ContentBlock.INSTRUMENT:
|
||||
for content in root.contents.raw_data:
|
||||
if content['type'] == 'instrument' or content['type'] == 'basic_knowledge':
|
||||
_id = content['value']['basic_knowledge']
|
||||
instrument = BasicKnowledge.objects.get(id=_id)
|
||||
category = instrument.new_type.category
|
||||
return category
|
||||
return None
|
||||
|
||||
|
||||
def process_module_room_slug_block(content):
|
||||
if content['type'] == 'module_room_slug':
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ module_1_chapter_2 = {
|
|||
'description': 'Haben Sie sich beim Shoppen schon mal überlegt, aus welchem Beweggrund Sie ein bestimmtes Produkt eigentlich unbedingt haben wollten? Wir gehen im Folgenden anhand Ihres letzten Kleiderkaufs dieser Frage nach.',
|
||||
'content_blocks': [
|
||||
{
|
||||
'type': 'base_society',
|
||||
'type': 'instrument',
|
||||
'title': 'Das Berufsbildungssystem',
|
||||
'contents': [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ type ContentBlockNode implements Node & ContentBlockInterface {
|
|||
mine: Boolean
|
||||
bookmarks: [ContentBlockBookmarkNode]
|
||||
originalCreator: PublicUserNode
|
||||
instrumentCategory: InstrumentCategoryNode
|
||||
}
|
||||
|
||||
type ContentBlockNodeConnection {
|
||||
|
|
@ -511,7 +512,7 @@ type InstrumentBookmarkNode implements Node {
|
|||
instrument: InstrumentNode!
|
||||
}
|
||||
|
||||
type InstrumentCategoryNode {
|
||||
type InstrumentCategoryNode implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
background: String!
|
||||
|
|
@ -539,7 +540,7 @@ type InstrumentNodeEdge {
|
|||
cursor: String!
|
||||
}
|
||||
|
||||
type InstrumentTypeNode {
|
||||
type InstrumentTypeNode implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
category: InstrumentCategoryNode
|
||||
|
|
|
|||
Loading…
Reference in New Issue