Toggle visibility by class / user group
This commit is contained in:
parent
2db6464f8d
commit
7038721bfd
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<label class="checkbox-container">
|
<label class="checkbox-container">
|
||||||
<input type="checkbox" class="checkbox-container__input" v-model="checked">
|
<input type="checkbox"
|
||||||
|
class="checkbox-container__input"
|
||||||
|
:checked="checked"
|
||||||
|
v-on:input="$emit('input', $event.target.checked, item)">
|
||||||
<span class="checkbox-container__checkbox">
|
<span class="checkbox-container__checkbox">
|
||||||
<tick></tick>
|
<tick></tick>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -16,9 +19,9 @@
|
||||||
props: {
|
props: {
|
||||||
label: String,
|
label: String,
|
||||||
checked: {
|
checked: {
|
||||||
type: Boolean,
|
type: Boolean
|
||||||
default: false
|
},
|
||||||
}
|
item: Object
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -37,7 +40,7 @@
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 12px;
|
width: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__input {
|
&__input {
|
||||||
|
|
@ -50,7 +53,7 @@
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
display: block;
|
display: block;
|
||||||
fill: white;
|
fill: $color-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
<div class="content-block__container">
|
<div class="content-block__container">
|
||||||
<div class="content-block" :class="specialClass">
|
<div class="content-block" :class="specialClass">
|
||||||
<div class="content-block__visibility-button">
|
<div class="content-block__visibility-button">
|
||||||
<eye-icon class="content-block__visibility-icon"></eye-icon>
|
<a @click="toggleVisibility()">
|
||||||
|
<eye-icon class="content-block__visibility-icon"></eye-icon>
|
||||||
|
</a>
|
||||||
|
<visibility-popover :show="showVisibility" :content-block="contentBlock"></visibility-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="content-block__title">{{contentBlock.title}}</h4>
|
<h4 class="content-block__title">{{contentBlock.title}}</h4>
|
||||||
|
|
@ -31,6 +34,7 @@
|
||||||
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
||||||
import StudentEntry from '@/components/content-blocks/StudentEntry';
|
import StudentEntry from '@/components/content-blocks/StudentEntry';
|
||||||
import AddContentBlockButton from '@/components/AddContentBlockButton';
|
import AddContentBlockButton from '@/components/AddContentBlockButton';
|
||||||
|
import VisibilityPopover from '@/components/VisibilityPopover';
|
||||||
import EyeIcon from '@/components/icons/EyeIcon';
|
import EyeIcon from '@/components/icons/EyeIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -46,6 +50,7 @@
|
||||||
'document_block': DocumentBlock,
|
'document_block': DocumentBlock,
|
||||||
Task,
|
Task,
|
||||||
AddContentBlockButton,
|
AddContentBlockButton,
|
||||||
|
VisibilityPopover,
|
||||||
EyeIcon
|
EyeIcon
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -53,6 +58,18 @@
|
||||||
specialClass() {
|
specialClass() {
|
||||||
return `content-block--${this.contentBlock.type.toLowerCase()}`
|
return `content-block--${this.contentBlock.type.toLowerCase()}`
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleVisibility() {
|
||||||
|
this.showVisibility = !this.showVisibility;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showVisibility: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -80,6 +97,9 @@
|
||||||
fill: $color-grey;
|
fill: $color-grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__visibility-menu {
|
||||||
|
}
|
||||||
|
|
||||||
&--yellow {
|
&--yellow {
|
||||||
background-color: rgba($color-accent-1, 0.15);
|
background-color: rgba($color-accent-1, 0.15);
|
||||||
border: 1px solid $color-accent-1;
|
border: 1px solid $color-accent-1;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import USER_GROUPS_QUERY from '@/graphql/gql/userGroupsQuery.gql';
|
import {userGroupsQuery} from '@/helpers/user-groups'
|
||||||
|
|
||||||
import Checkbox from '@/components/Checkbox.vue';
|
import Checkbox from '@/components/Checkbox.vue';
|
||||||
|
|
||||||
|
|
@ -17,16 +17,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
userGroupsQuery: {
|
userGroupsQuery: userGroupsQuery
|
||||||
query: USER_GROUPS_QUERY,
|
|
||||||
manual: true,
|
|
||||||
result({data, loading, networkStatus}) {
|
|
||||||
if (!loading) {
|
|
||||||
const cleanedData = this.$getRidOfEdges(data)
|
|
||||||
this.userGroups = cleanedData.userGroups || {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<div class="visibility-menu" v-if="show">
|
||||||
|
<h3 class="visibility-menu__title">Sichtbarkeit</h3>
|
||||||
|
<div v-for="group in userGroupsWithVisibilityInfo" :key="group.id" class="visibility-menu__item">
|
||||||
|
<checkbox :checked="!group.hidden"
|
||||||
|
:item="group"
|
||||||
|
:label="group.name"
|
||||||
|
v-on:input="updateVisibility"
|
||||||
|
></checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CHANGE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/mutateContentBlock.gql';
|
||||||
|
|
||||||
|
import Checkbox from '@/components/Checkbox';
|
||||||
|
import {userGroupsQuery} from '@/helpers/user-groups'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['show', 'content-block'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Checkbox
|
||||||
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
userGroupsQuery: userGroupsQuery
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userGroups: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateVisibility(checked, item) {
|
||||||
|
item.hidden = !checked;
|
||||||
|
|
||||||
|
this.$apollo.mutate({
|
||||||
|
mutation: CHANGE_CONTENT_BLOCK_MUTATION,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: this.contentBlock.id,
|
||||||
|
visibility: this.userGroupsWithVisibilityInfo.map(g => {
|
||||||
|
return {
|
||||||
|
userGroupId: g.id,
|
||||||
|
hidden: g.hidden || false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: (store, {data: {mutateContentBlock: {contentBlock}}}) => {
|
||||||
|
this.$store.dispatch('updateContentBlocks');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
userGroupsWithVisibilityInfo() {
|
||||||
|
return this.userGroups.map(userGroup => {
|
||||||
|
return {
|
||||||
|
...userGroup,
|
||||||
|
hidden: !!this.contentBlock.hiddenFor.find(el => el.id === userGroup.id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "@/styles/_variables.scss";
|
||||||
|
@import "@/styles/_functions.scss";
|
||||||
|
|
||||||
|
.visibility-menu {
|
||||||
|
border-radius: 13px;
|
||||||
|
border: 1px solid $color-lightgrey;
|
||||||
|
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.15);
|
||||||
|
width: 180px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 19px;
|
||||||
|
left: -130px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9;
|
||||||
|
background-color: $color-white;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: toRem(19px);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
mutation MutateContentBlock($input: MutateContentBlockInput!) {
|
||||||
|
mutateContentBlock(input: $input) {
|
||||||
|
contentBlock {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
hiddenFor {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#// input
|
||||||
|
#
|
||||||
|
#{
|
||||||
|
# "input": {
|
||||||
|
# "id": "Q29udGVudEJsb2NrTm9kZToyMQ==",
|
||||||
|
# "type": "plain",
|
||||||
|
# "title": "Hallo Daniel"
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#{
|
||||||
|
# "input": {
|
||||||
|
# "id": "Q29udGVudEJsb2NrTm9kZToyMQ==",
|
||||||
|
# "type": "plain",
|
||||||
|
# "title": "Hallo Daniel",
|
||||||
|
# "contents": "[{\"type\":\"text_block\",\"value\":{\"text\": \"<p>Beatae odio</p>\"}}]"
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
mutation MutateContentBlock($input: MutateContentBlockInput!) {
|
|
||||||
mutateContentBlock(input: $input) {
|
|
||||||
contentBlock {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// input
|
|
||||||
|
|
||||||
{
|
|
||||||
"input": {
|
|
||||||
"id": "Q29udGVudEJsb2NrTm9kZToyMQ==",
|
|
||||||
"type": "plain",
|
|
||||||
"title": "Hallo Daniel"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
"input": {
|
|
||||||
"id": "Q29udGVudEJsb2NrTm9kZToyMQ==",
|
|
||||||
"type": "plain",
|
|
||||||
"title": "Hallo Daniel",
|
|
||||||
"contents": "[{\"type\":\"text_block\",\"value\":{\"text\": \"<p>Beatae odio</p>\"}}]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import USER_GROUPS_QUERY from '@/graphql/gql/userGroupsQuery.gql';
|
||||||
|
|
||||||
|
export const userGroupsQuery = {
|
||||||
|
query: USER_GROUPS_QUERY,
|
||||||
|
manual: true,
|
||||||
|
result({data, loading, networkStatus}) {
|
||||||
|
if (!loading) {
|
||||||
|
const cleanedData = this.$getRidOfEdges(data)
|
||||||
|
this.userGroups = cleanedData.userGroups || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -10,7 +10,6 @@ export default new Vuex.Store({
|
||||||
specialContainerClass: '',
|
specialContainerClass: '',
|
||||||
showFilter: true,
|
showFilter: true,
|
||||||
showModal: false,
|
showModal: false,
|
||||||
showNewContentBlockModal: false,
|
|
||||||
contentBlockPosition: {},
|
contentBlockPosition: {},
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
moduleSlug: 'mein-neues-umfeld',
|
moduleSlug: 'mein-neues-umfeld',
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,6 @@ class MutateContentBlock(relay.ClientIDMutation):
|
||||||
class AddContentBlock(relay.ClientIDMutation):
|
class AddContentBlock(relay.ClientIDMutation):
|
||||||
class Input:
|
class Input:
|
||||||
content_block = graphene.Argument(ContentBlockInput)
|
content_block = graphene.Argument(ContentBlockInput)
|
||||||
# todo: handle both of these differently, one for a new chapter maybe
|
|
||||||
parent = graphene.ID() # ID of chapter node; new content block will be inserted at the start of it
|
parent = graphene.ID() # ID of chapter node; new content block will be inserted at the start of it
|
||||||
after = graphene.ID() # ID of content block node; new content block will be inserted after this content block node
|
after = graphene.ID() # ID of content block node; new content block will be inserted after this content block node
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ class BookQuery(object):
|
||||||
topic = relay.Node.Field(TopicNode)
|
topic = relay.Node.Field(TopicNode)
|
||||||
module = relay.Node.Field(ModuleNode)
|
module = relay.Node.Field(ModuleNode)
|
||||||
chapter = relay.Node.Field(FilteredChapterNode)
|
chapter = relay.Node.Field(FilteredChapterNode)
|
||||||
|
content_block = relay.Node.Field(ContentBlockNode)
|
||||||
|
|
||||||
books = DjangoFilterConnectionField(BookNode)
|
books = DjangoFilterConnectionField(BookNode)
|
||||||
topics = DjangoFilterConnectionField(TopicNode)
|
topics = DjangoFilterConnectionField(TopicNode)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue