Refactoring according to Puillrequest comments
This commit is contained in:
parent
139bb545d8
commit
bb54aeb145
|
|
@ -5,16 +5,15 @@
|
||||||
v-if="module.id"
|
v-if="module.id"
|
||||||
>
|
>
|
||||||
<div class="module__header">
|
<div class="module__header">
|
||||||
<div>
|
|
||||||
<h2
|
<h2
|
||||||
class="module__meta-title"
|
class="module__meta-title"
|
||||||
id="meta-title"
|
id="meta-title"
|
||||||
>
|
>
|
||||||
{{ module.metaTitle }}
|
{{ module.metaTitle }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div class="module__categoryindicators">
|
||||||
<pill :text="module.level?.name"></pill>
|
<pill :text="module.level?.name"></pill>
|
||||||
<pill :text="module.category?.name"></pill>
|
<pill :text="module.category?.name"></pill>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -178,12 +177,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
margin-bottom: 10px;
|
margin-bottom: $small-spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__meta-title {
|
&__meta-title {
|
||||||
@include meta-title;
|
@include meta-title;
|
||||||
margin-right: 20px;
|
margin-right: $medium-spacing;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import ModuleTeaser from "@/components/modules/ModuleTeaser.vue";
|
import ModuleTeaser from "@/components/modules/ModuleTeaser.vue";
|
||||||
import gql from "graphql-tag";
|
|
||||||
import {useQuery, useMutation} from "@vue/apollo-composable";
|
import {useQuery, useMutation} from "@vue/apollo-composable";
|
||||||
import Dropdown from "@/components/ui/Dropdown.vue";
|
import Dropdown from "@/components/ui/Dropdown.vue";
|
||||||
import PillRadioButtons from "@/components/ui/PillRadioButtons.vue";
|
import PillRadioButtons from "@/components/ui/PillRadioButtons.vue";
|
||||||
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
// TODO: Fix console warnings... onBeforeUnmount is called when there is no active component instance to be associated with.
|
|
||||||
// TODO: Improve Typing
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modules: Object[];
|
modules: Object[];
|
||||||
|
|
@ -106,15 +104,12 @@
|
||||||
filterExpression = filterByLevel(module, selectedLevel) &&
|
filterExpression = filterByLevel(module, selectedLevel) &&
|
||||||
filterByCategory(module, selectedCategory) &&
|
filterByCategory(module, selectedCategory) &&
|
||||||
filterByLanguage(module, selectedLanguage);
|
filterByLanguage(module, selectedLanguage);
|
||||||
//updateLastModuleLevel(selectedLevel.value);
|
|
||||||
|
|
||||||
return filterExpression;
|
return filterExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateLevel = (level) => {
|
const updateLevel = (level) => {
|
||||||
selectedLevel.value = level;
|
selectedLevel.value = level;
|
||||||
updateLastModuleLevelUser(level);
|
updateLastModuleLevelUser(level);
|
||||||
console.log("selectedLevel", selectedLevel.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterByLevel = (module, level) => {
|
const filterByLevel = (module, level) => {
|
||||||
|
|
@ -126,6 +121,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterByLanguage = (module: Object, language: Object) => {
|
const filterByLanguage = (module: Object, language: Object) => {
|
||||||
|
// TODO: implement filter by language here.
|
||||||
console.log("selectedLanguage", selectedLanguage.value, language);
|
console.log("selectedLanguage", selectedLanguage.value, language);
|
||||||
console.log("module.languages", module);
|
console.log("module.languages", module);
|
||||||
return true
|
return true
|
||||||
|
|
@ -134,17 +130,19 @@
|
||||||
|
|
||||||
function updateLastModuleLevelUser(moduleLevel: Object) {
|
function updateLastModuleLevelUser(moduleLevel: Object) {
|
||||||
|
|
||||||
const {mutate: updateLastModuleLevel} = useMutation(gql`
|
const {mutate: updateLastModuleLevel} = useMutation(gql `
|
||||||
mutation ($input: UpdateLastModuleLevelInput!){updateLastModuleLevel(input: $input) {
|
mutation ($input: UpdateLastModuleLevelInput!){
|
||||||
clientMutationId
|
updateLastModuleLevel(input: $input) {
|
||||||
user {
|
clientMutationId
|
||||||
username
|
user {
|
||||||
lastModuleLevel {
|
username
|
||||||
name
|
lastModuleLevel {
|
||||||
id
|
name
|
||||||
}
|
id
|
||||||
}
|
}
|
||||||
}}`);
|
}
|
||||||
|
}
|
||||||
|
}`);
|
||||||
|
|
||||||
updateLastModuleLevel({
|
updateLastModuleLevel({
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -161,21 +159,19 @@
|
||||||
|
|
||||||
.module-filter {
|
.module-filter {
|
||||||
// TODO: how do I correcty set the with of the whole thig including the grid for the modules?
|
// TODO: how do I correcty set the with of the whole thig including the grid for the modules?
|
||||||
// TODO: Farbe des Arrows für Dropdowns muss platfrom habhängig sein
|
// TODO: Farbe des Arrows für Dropdowns muss platfrom habhängig sein MS-775
|
||||||
|
|
||||||
width: 75%;
|
width: 75%;
|
||||||
|
|
||||||
&__filterselection {
|
&__filterselection {
|
||||||
@include desktop;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dropdown {
|
&__dropdown {
|
||||||
margin-right: 20px;
|
margin-right: $medium-spacing;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__language-selection {
|
&__language-selection {
|
||||||
|
|
@ -184,19 +180,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.topic {
|
.topic {
|
||||||
display: grid;
|
|
||||||
padding: $large-spacing $small-spacing;
|
|
||||||
@include desktop {
|
|
||||||
padding: $large-spacing 0;
|
|
||||||
}
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
@include desktop {
|
|
||||||
grid-template-columns: 300px 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
&__modules {
|
&__modules {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -211,14 +195,6 @@
|
||||||
grid-template-columns: repeat(3, minmax(auto, 380px));
|
grid-template-columns: repeat(3, minmax(auto, 380px));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&__teaser {
|
|
||||||
color: $color-charcoal-dark;
|
|
||||||
width: 90%;
|
|
||||||
@include lead-paragraph;
|
|
||||||
margin-bottom: $large-spacing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__pills {
|
&__pills {
|
||||||
margin-top: 20px;
|
margin-top: $medium-spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ import Avatar from '@/components/profile/Avatar.vue';
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent } from 'vue';
|
||||||
const TrashIcon = defineAsyncComponent(() => import('@/components/icons/TrashIcon.vue'));
|
const TrashIcon = defineAsyncComponent(() => import('@/components/icons/TrashIcon.vue'));
|
||||||
|
|
||||||
|
|
||||||
// TODO: Kann das mit me.ts zusammengeführt werden?
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
AvatarUploadForm,
|
AvatarUploadForm,
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,33 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="class-selection"
|
class="dropdown"
|
||||||
v-if="selectedItem"
|
v-if="selectedItem"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
data-cy="class-selection"
|
data-cy="dropdown"
|
||||||
class="class-selection__selected-class selected-class"
|
class="dropdown__selected-item"
|
||||||
@click.stop="toggle()"
|
@click.stop="toggle()"
|
||||||
>
|
>
|
||||||
<span class="selected-class__text"> {{ selectedItem.name }}</span>
|
<span class="dropdown__selected-item-text"> {{ selectedItem.name }}</span>
|
||||||
<ChevronDown class="selected-class__dropdown-icon" :class="{'rotate-chevron': showPopover}"
|
<ChevronDown class="dropdown__dropdown-icon" :class="{'rotate-chevron': showPopover}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<transition name="scaleY">
|
<transition name="scaleY">
|
||||||
<WidgetPopover
|
<WidgetPopover
|
||||||
:mobile="mobile"
|
class="dropdown__popover"
|
||||||
class="class-selection__popover"
|
|
||||||
v-if="showPopover"
|
v-if="showPopover"
|
||||||
@hide-me="showPopover = false"
|
@hide-me="showPopover = false"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
:label="selectedItem.name"
|
:label="selectedItem.name"
|
||||||
:item="selectedItem"
|
:item="selectedItem"
|
||||||
data-cy="class-selection-entry"
|
data-cy="dropdown-item"
|
||||||
class="popover-links__link popover-links__link--large"
|
class="popover-links__link popover-links__link--large"
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@click="updateSelectedItem(item)"
|
@click="updateSelectedItem(item)"
|
||||||
><span>{{ item.name }}</span>
|
>{{ item.name }}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
</WidgetPopover>
|
</WidgetPopover>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -64,12 +61,12 @@
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import 'styles/helpers';
|
@import 'styles/helpers';
|
||||||
|
|
||||||
.class-selection {
|
.dropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-bottom: $medium-spacing;
|
margin-bottom: $medium-spacing;
|
||||||
border-radius: 4px;
|
border-radius: $input-border-radius;
|
||||||
width: 200px;
|
|
||||||
|
|
||||||
&__popover {
|
&__popover {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
@ -77,61 +74,55 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
transform-origin: top;
|
transform-origin: top;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.selected-class {
|
&__selected-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: $small-spacing 0;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border: solid $color-silver 1px;
|
||||||
|
border-radius: $input-border-radius;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
&__selected-item-text {
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border: solid silver 1px;
|
|
||||||
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 12px;
|
|
||||||
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
@include small-text;
|
@include small-text;
|
||||||
margin-right: $small-spacing;
|
margin-right: $small-spacing;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dropdown-icon {
|
&__dropdown-icon {
|
||||||
width: 20px;
|
width: $default-icon-dimension;
|
||||||
height: 20px;
|
height: $default-icon-dimension;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
|
fill: $color-brand;
|
||||||
|
|
||||||
fill: #139EE0;
|
&.rotate-chevron {
|
||||||
|
|
||||||
&.rotate-chevron { // This class will be applied when showPopover is true
|
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.widget-popover {
|
&__popover {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 12px;
|
border-radius: $default-border-radius;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
|
||||||
.popover-links__link {
|
.popover-links__link {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #efefef;
|
background-color: $color-silver-light;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.scaleY-enter-active,
|
.scaleY-enter-active,
|
||||||
.scaleY-leave-active {
|
.scaleY-leave-active {
|
||||||
transition: transform 0.3s;
|
transition: transform 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaleY-enter,
|
.scaleY-enter,
|
||||||
.scaleY-leave-to
|
.scaleY-leave-to {
|
||||||
{
|
|
||||||
transform: scaleY(0);
|
transform: scaleY(0);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@
|
||||||
@import 'styles/helpers';
|
@import 'styles/helpers';
|
||||||
|
|
||||||
.pill {
|
.pill {
|
||||||
background-color: white; /* Replace with your desired background color */
|
background-color: white;
|
||||||
color: #333333; /* Replace with your desired text color */
|
color: $color-charcoal-dark; /* Replace with your desired text color */
|
||||||
padding: 10px 20px;
|
padding: $small-spacing $medium-spacing;
|
||||||
border-radius: 30px;
|
border-radius: $round-border-radius;
|
||||||
border: 1px solid silver;
|
border: 1px solid $color-silver;
|
||||||
display: inline-block; /* Ensures the pill takes only the necessary width */
|
display: inline-block; /* Ensures the pill takes only the necessary width */
|
||||||
margin-right: 10px;
|
margin-right: $small-spacing;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
@include small-text;
|
@include small-text;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import 'styles/helpers';
|
||||||
|
|
||||||
.pill-radio {
|
.pill-radio {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -40,29 +42,28 @@
|
||||||
&__button {
|
&__button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #f0f0f0;
|
background-color: $color-silver-light;
|
||||||
|
|
||||||
outline: none;
|
outline: none;
|
||||||
padding-left: 14px;
|
padding-left: 1rem;
|
||||||
padding-right: 14px;
|
padding-right: 1rem;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: solid silver 1px;
|
border: solid $color-silver 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__button:first-child {
|
&__button:first-child {
|
||||||
border-top-left-radius: 50px;
|
border-top-left-radius: $round-border-radius;
|
||||||
border-bottom-left-radius: 50px;
|
border-bottom-left-radius: $round-border-radius;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__button:last-child {
|
&__button:last-child {
|
||||||
border-top-right-radius: 50px;
|
border-top-right-radius: $round-border-radius;
|
||||||
border-bottom-right-radius: 50px;
|
border-bottom-right-radius: $round-border-radius;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,7 @@
|
||||||
<p class="topic__teaser">
|
<p class="topic__teaser">
|
||||||
{{ topic.teaser }}
|
{{ topic.teaser }}
|
||||||
</p>
|
</p>
|
||||||
<div class="topic__modulefilter">
|
|
||||||
<module-filter :modules="modules" :me="me" v-if="modules.length > 0" ></module-filter>
|
|
||||||
</div>
|
|
||||||
<div class="topic__links">
|
<div class="topic__links">
|
||||||
<div
|
<div
|
||||||
class="topic__video-link topic__link"
|
class="topic__video-link topic__link"
|
||||||
|
|
@ -36,7 +34,9 @@
|
||||||
<span class="topic__link-description">Anweisungen zum {{ $flavor.textTopic }} anzeigen</span>
|
<span class="topic__link-description">Anweisungen zum {{ $flavor.textTopic }} anzeigen</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="topic__modulefilter">
|
||||||
|
<module-filter :modules="modules" :me="me" v-if="modules.length > 0" ></module-filter>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,20 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from wagtail.admin.panels import FieldPanel, InlinePanel, TabbedInterface, ObjectList, MultiFieldPanel, MultipleChooserPanel
|
|
||||||
from wagtail.fields import RichTextField
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from wagtail.admin.panels import FieldPanel, TabbedInterface, ObjectList
|
||||||
|
from wagtail.fields import RichTextField
|
||||||
|
|
||||||
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
from core.constants import DEFAULT_RICH_TEXT_FEATURES
|
||||||
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
from core.wagtail_utils import StrictHierarchyPage, get_default_settings
|
||||||
from users.models import SchoolClass
|
from users.models import SchoolClass
|
||||||
from django.utils.text import slugify
|
|
||||||
|
|
||||||
FILTER_ATTRIBUTE_TYPE = (
|
FILTER_ATTRIBUTE_TYPE = (("all", "All"), ("exact", "Exact"))
|
||||||
('all', 'All'),
|
|
||||||
('exact', 'Exact')
|
|
||||||
)
|
|
||||||
|
|
||||||
class ModuleLevel(models.Model):
|
class ModuleLevel(models.Model):
|
||||||
name = models.CharField(max_length=255, unique=True)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
filter_attribute_type = models.CharField(
|
filter_attribute_type = models.CharField(
|
||||||
max_length=16,
|
max_length=16, choices=FILTER_ATTRIBUTE_TYPE, default="exact"
|
||||||
choices=FILTER_ATTRIBUTE_TYPE,
|
|
||||||
default='exact'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
@ -42,9 +37,7 @@ class ModuleCategory(models.Model):
|
||||||
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
filter_attribute_type = models.CharField(
|
filter_attribute_type = models.CharField(
|
||||||
max_length=16,
|
max_length=16, choices=FILTER_ATTRIBUTE_TYPE, default="exact"
|
||||||
choices=FILTER_ATTRIBUTE_TYPE,
|
|
||||||
default='exact'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
@ -57,9 +50,12 @@ class Module(StrictHierarchyPage):
|
||||||
verbose_name_plural = "Module"
|
verbose_name_plural = "Module"
|
||||||
|
|
||||||
meta_title = models.CharField(max_length=255, help_text="e.g. 'Intro' or 'Modul 1'")
|
meta_title = models.CharField(max_length=255, help_text="e.g. 'Intro' or 'Modul 1'")
|
||||||
level = models.ForeignKey(ModuleLevel, on_delete=models.SET_NULL, blank=True, null=True)
|
level = models.ForeignKey(
|
||||||
category = models.ForeignKey(ModuleCategory, on_delete=models.SET_NULL, blank=True, null=True)
|
ModuleLevel, on_delete=models.SET_NULL, blank=True, null=True
|
||||||
|
)
|
||||||
|
category = models.ForeignKey(
|
||||||
|
ModuleCategory, on_delete=models.SET_NULL, blank=True, null=True
|
||||||
|
)
|
||||||
|
|
||||||
hero_image = models.ForeignKey(
|
hero_image = models.ForeignKey(
|
||||||
"wagtailimages.Image",
|
"wagtailimages.Image",
|
||||||
|
|
@ -86,27 +82,6 @@ class Module(StrictHierarchyPage):
|
||||||
FieldPanel("hero_source"),
|
FieldPanel("hero_source"),
|
||||||
FieldPanel("teaser"),
|
FieldPanel("teaser"),
|
||||||
FieldPanel("intro"),
|
FieldPanel("intro"),
|
||||||
# TODO: Why is this commented out?
|
|
||||||
# InlinePanel(
|
|
||||||
# "assignments",
|
|
||||||
# label=_("Assignment"),
|
|
||||||
# classname="collapsed",
|
|
||||||
# heading=_("linked assignments"),
|
|
||||||
# help_text=_(
|
|
||||||
# "These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here."
|
|
||||||
# )
|
|
||||||
# % _("assignments"),
|
|
||||||
# ),
|
|
||||||
# InlinePanel(
|
|
||||||
# "surveys",
|
|
||||||
# heading=_("linked surveys"),
|
|
||||||
# label=_("Survey"),
|
|
||||||
# classname="collapsed",
|
|
||||||
# help_text=_(
|
|
||||||
# "These %s are automatically linked, they are shown here only to provide an overview. Please don't change anything here."
|
|
||||||
# )
|
|
||||||
# % _("surveys"),
|
|
||||||
# ),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
edit_handler = TabbedInterface(
|
edit_handler = TabbedInterface(
|
||||||
|
|
@ -175,7 +150,6 @@ class Module(StrictHierarchyPage):
|
||||||
return f"{self.meta_title} - {self.title}"
|
return f"{self.meta_title} - {self.title}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RecentModule(models.Model):
|
class RecentModule(models.Model):
|
||||||
module = models.ForeignKey(
|
module = models.ForeignKey(
|
||||||
Module, on_delete=models.CASCADE, related_name="recent_modules"
|
Module, on_delete=models.CASCADE, related_name="recent_modules"
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,5 @@ class UpdateLastModuleLevel(relay.ClientIDMutation):
|
||||||
id = args.get('id')
|
id = args.get('id')
|
||||||
module_level = get_object(ModuleLevel, id)
|
module_level = get_object(ModuleLevel, id)
|
||||||
|
|
||||||
|
|
||||||
User.objects.filter(pk=user.id).update(last_module_level_id=module_level.id)
|
User.objects.filter(pk=user.id).update(last_module_level_id=module_level.id)
|
||||||
return cls(user=user)
|
return cls(user=user)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from graphene import relay
|
||||||
|
|
||||||
from api.types import FailureNode, Success
|
from api.types import FailureNode, Success
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
from books.models import Module, ContentBlock, Chapter
|
from books.models import Module
|
||||||
from books.models.snapshot import Snapshot
|
from books.models.snapshot import Snapshot
|
||||||
from books.schema.nodes import SnapshotNode, ModuleNode
|
from books.schema.nodes import SnapshotNode, ModuleNode
|
||||||
from users.models import SchoolClass
|
from users.models import SchoolClass
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,16 @@ from graphene_django.filter import DjangoFilterConnectionField
|
||||||
|
|
||||||
from assignments.models import StudentSubmission
|
from assignments.models import StudentSubmission
|
||||||
from assignments.schema.types import AssignmentNode, StudentSubmissionNode
|
from assignments.schema.types import AssignmentNode, StudentSubmissionNode
|
||||||
from books.models import Module, Chapter, ContentBlock, RecentModule, ModuleLevel, ModuleCategory
|
from books.models import (
|
||||||
|
Module,
|
||||||
|
Chapter,
|
||||||
|
ContentBlock,
|
||||||
|
RecentModule,
|
||||||
|
)
|
||||||
from books.schema.interfaces.module import ModuleInterface
|
from books.schema.interfaces.module import ModuleInterface
|
||||||
from books.schema.nodes.chapter import ChapterNode
|
from books.schema.nodes.chapter import ChapterNode
|
||||||
from books.schema.nodes.module_level import ModuleLevelNode
|
|
||||||
from books.schema.nodes.module_category import ModuleCategoryNode
|
from books.schema.nodes.module_category import ModuleCategoryNode
|
||||||
|
from books.schema.nodes.module_level import ModuleLevelNode
|
||||||
from notes.models import ModuleBookmark, ContentBlockBookmark, ChapterBookmark
|
from notes.models import ModuleBookmark, ContentBlockBookmark, ChapterBookmark
|
||||||
from notes.schema import (
|
from notes.schema import (
|
||||||
ModuleBookmarkNode,
|
ModuleBookmarkNode,
|
||||||
|
|
@ -50,8 +55,7 @@ class ModuleNode(DjangoObjectType):
|
||||||
bookmark = graphene.Field(ModuleBookmarkNode)
|
bookmark = graphene.Field(ModuleBookmarkNode)
|
||||||
my_submissions = DjangoFilterConnectionField(StudentSubmissionNode)
|
my_submissions = DjangoFilterConnectionField(StudentSubmissionNode)
|
||||||
my_answers = DjangoFilterConnectionField(AnswerNode)
|
my_answers = DjangoFilterConnectionField(AnswerNode)
|
||||||
my_content_bookmarks = DjangoFilterConnectionField(
|
my_content_bookmarks = DjangoFilterConnectionField(ContentBlockBookmarkNode)
|
||||||
ContentBlockBookmarkNode)
|
|
||||||
my_chapter_bookmarks = DjangoFilterConnectionField(ChapterBookmarkNode)
|
my_chapter_bookmarks = DjangoFilterConnectionField(ChapterBookmarkNode)
|
||||||
snapshots = graphene.List("books.schema.nodes.SnapshotNode")
|
snapshots = graphene.List("books.schema.nodes.SnapshotNode")
|
||||||
objective_groups = graphene.List(ObjectiveGroupNode)
|
objective_groups = graphene.List(ObjectiveGroupNode)
|
||||||
|
|
@ -110,12 +114,6 @@ class ModuleNode(DjangoObjectType):
|
||||||
def resolve_objective_groups(parent, info, **kwargs):
|
def resolve_objective_groups(parent, info, **kwargs):
|
||||||
return parent.objective_groups.all().prefetch_related("hidden_for")
|
return parent.objective_groups.all().prefetch_related("hidden_for")
|
||||||
|
|
||||||
def resolve_level(self, info, **kwargs):
|
|
||||||
return ModuleLevel.objects.get(pk=self.level_id) if self.level_id else None
|
|
||||||
|
|
||||||
def resolve_category(self, info, **kwargs):
|
|
||||||
return ModuleCategory.objects.get(pk=self.category_id) if self.category_id else None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_snapshots(parent, info, **kwargs):
|
def resolve_snapshots(parent, info, **kwargs):
|
||||||
user = info.context.user
|
user = info.context.user
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from graphene import relay
|
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from books.models import ModuleCategory
|
from books.models import ModuleCategory
|
||||||
|
|
@ -9,8 +8,4 @@ class ModuleCategoryNode(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleCategory
|
model = ModuleCategory
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
only_fields = [
|
only_fields = "__all__"
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"filter_attribute_type",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from graphene import relay
|
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from books.models import ModuleLevel
|
from books.models import ModuleLevel
|
||||||
|
|
@ -9,9 +8,4 @@ class ModuleLevelNode(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleLevel
|
model = ModuleLevel
|
||||||
interfaces = (relay.Node,)
|
interfaces = (relay.Node,)
|
||||||
only_fields = [
|
only_fields = "__all__"
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"filter_attribute_type",
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,16 @@ from graphene_django.filter import DjangoFilterConnectionField
|
||||||
from api.utils import get_object
|
from api.utils import get_object
|
||||||
from core.logger import get_logger
|
from core.logger import get_logger
|
||||||
from .connections import TopicConnection, ModuleConnection
|
from .connections import TopicConnection, ModuleConnection
|
||||||
from .nodes import ContentBlockNode, ChapterNode, ModuleNode, NotFoundFailure, SnapshotNode, \
|
from .nodes import (
|
||||||
TopicOr404Node
|
ContentBlockNode,
|
||||||
from .nodes.module_level import ModuleLevelNode
|
ChapterNode,
|
||||||
|
ModuleNode,
|
||||||
|
NotFoundFailure,
|
||||||
|
SnapshotNode,
|
||||||
|
TopicOr404Node,
|
||||||
|
)
|
||||||
from .nodes.module_category import ModuleCategoryNode
|
from .nodes.module_category import ModuleCategoryNode
|
||||||
|
from .nodes.module_level import ModuleLevelNode
|
||||||
from ..models import Book, Topic, Module, Chapter, Snapshot, ModuleLevel, ModuleCategory
|
from ..models import Book, Topic, Module, Chapter, Snapshot, ModuleLevel, ModuleCategory
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
@ -17,8 +23,7 @@ logger = get_logger(__name__)
|
||||||
class BookQuery(object):
|
class BookQuery(object):
|
||||||
node = relay.Node.Field()
|
node = relay.Node.Field()
|
||||||
topic = graphene.Field(TopicOr404Node, slug=graphene.String())
|
topic = graphene.Field(TopicOr404Node, slug=graphene.String())
|
||||||
module = graphene.Field(
|
module = graphene.Field(ModuleNode, slug=graphene.String(), id=graphene.ID())
|
||||||
ModuleNode, slug=graphene.String(), id=graphene.ID())
|
|
||||||
chapter = relay.Node.Field(ChapterNode)
|
chapter = relay.Node.Field(ChapterNode)
|
||||||
content_block = relay.Node.Field(ContentBlockNode)
|
content_block = relay.Node.Field(ContentBlockNode)
|
||||||
snapshot = relay.Node.Field(SnapshotNode)
|
snapshot = relay.Node.Field(SnapshotNode)
|
||||||
|
|
@ -46,13 +51,13 @@ class BookQuery(object):
|
||||||
return Chapter.objects.filter(**kwargs).live()
|
return Chapter.objects.filter(**kwargs).live()
|
||||||
|
|
||||||
def resolve_snapshot(self, info, **kwargs):
|
def resolve_snapshot(self, info, **kwargs):
|
||||||
id = kwargs.get('id')
|
id = kwargs.get("id")
|
||||||
snapshot = get_object(Snapshot, id)
|
snapshot = get_object(Snapshot, id)
|
||||||
return snapshot
|
return snapshot
|
||||||
|
|
||||||
def resolve_module(self, info, **kwargs):
|
def resolve_module(self, info, **kwargs):
|
||||||
slug = kwargs.get('slug')
|
slug = kwargs.get("slug")
|
||||||
id = kwargs.get('id')
|
id = kwargs.get("id")
|
||||||
module = None
|
module = None
|
||||||
try:
|
try:
|
||||||
if id is not None:
|
if id is not None:
|
||||||
|
|
@ -67,8 +72,8 @@ class BookQuery(object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def resolve_topic(self, info, **kwargs):
|
def resolve_topic(self, info, **kwargs):
|
||||||
slug = kwargs.get('slug')
|
slug = kwargs.get("slug")
|
||||||
id = kwargs.get('id')
|
id = kwargs.get("id")
|
||||||
|
|
||||||
if id is not None:
|
if id is not None:
|
||||||
return get_object(Topic, id)
|
return get_object(Topic, id)
|
||||||
|
|
@ -79,9 +84,8 @@ class BookQuery(object):
|
||||||
return NotFoundFailure
|
return NotFoundFailure
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def resolve_module_level(self, info, **kwargs):
|
def resolve_module_level(self, info, **kwargs):
|
||||||
module_level_id = kwargs.get('id')
|
module_level_id = kwargs.get("id")
|
||||||
try:
|
try:
|
||||||
if module_level_id is not None:
|
if module_level_id is not None:
|
||||||
return get_object(Module, module_level_id)
|
return get_object(Module, module_level_id)
|
||||||
|
|
@ -90,10 +94,10 @@ class BookQuery(object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def resolve_module_levels(self, *args, **kwargs):
|
def resolve_module_levels(self, *args, **kwargs):
|
||||||
return ModuleLevel.objects.filter(**kwargs)
|
return ModuleLevel.objects.all()
|
||||||
|
|
||||||
def resolve_module_category(self, info, **kwargs):
|
def resolve_module_category(self, info, **kwargs):
|
||||||
id = kwargs.get('id')
|
id = kwargs.get("id")
|
||||||
try:
|
try:
|
||||||
if id is not None:
|
if id is not None:
|
||||||
return get_object(Module, id)
|
return get_object(Module, id)
|
||||||
|
|
@ -102,14 +106,7 @@ class BookQuery(object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def resolve_module_categories(self, *args, **kwargs):
|
def resolve_module_categories(self, *args, **kwargs):
|
||||||
return ModuleCategory.objects.filter(**kwargs)
|
return ModuleCategory.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleTypeQuery(graphene.ObjectType):
|
class ModuleTypeQuery(graphene.ObjectType):
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ from wagtail.contrib.modeladmin.options import (
|
||||||
ModelAdminGroup,
|
ModelAdminGroup,
|
||||||
modeladmin_register,
|
modeladmin_register,
|
||||||
)
|
)
|
||||||
from wagtail import hooks
|
|
||||||
|
|
||||||
from .models.module import ModuleLevel, ModuleCategory, Module
|
from .models.module import ModuleLevel, ModuleCategory, Module
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
python manage.py graphql_schema
|
||||||
|
sed -i '' 's/Node, Node/Node & Node/g' schema.graphql
|
||||||
|
|
||||||
|
python manage.py graphql_schema --schema api.schema_public.schema --out schema-public.graphql
|
||||||
|
sed -i '' 's/Node, Node/Node & Node/g' schema-public.graphql
|
||||||
Loading…
Reference in New Issue