From 76b3f70a87148a22b6331f155355da8f31ea3556 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Wed, 21 Aug 2019 16:26:51 +0200 Subject: [PATCH 1/5] Hide single objectives instead of whole groups --- .../components/objective-groups/Objective.vue | 21 ++++++++++++ .../objective-groups/ObjectiveGroup.vue | 16 +++------- .../visibility/VisibilityAction.vue | 20 ++++++------ .../graphql/gql/fragments/objectiveParts.gql | 28 ++++++++++++++++ client/src/graphql/gql/moduleDetailsQuery.gql | 12 ++----- .../updateObjectiveGroupVisibility.gql | 9 ------ .../mutations/updateObjectiveVisibility.gql | 9 ++++++ server/books/schema/queries.py | 18 +---------- server/objectives/admin.py | 4 +-- .../migrations/0008_auto_20190821_1252.py | 32 +++++++++++++++++++ server/objectives/models.py | 3 ++ server/objectives/mutations.py | 22 ++++++------- server/objectives/schema.py | 16 ++++++++++ 13 files changed, 140 insertions(+), 70 deletions(-) create mode 100644 client/src/components/objective-groups/Objective.vue create mode 100644 client/src/graphql/gql/fragments/objectiveParts.gql delete mode 100644 client/src/graphql/gql/mutations/updateObjectiveGroupVisibility.gql create mode 100644 client/src/graphql/gql/mutations/updateObjectiveVisibility.gql create mode 100644 server/objectives/migrations/0008_auto_20190821_1252.py diff --git a/client/src/components/objective-groups/Objective.vue b/client/src/components/objective-groups/Objective.vue new file mode 100644 index 00000000..60e1b450 --- /dev/null +++ b/client/src/components/objective-groups/Objective.vue @@ -0,0 +1,21 @@ + + + diff --git a/client/src/components/objective-groups/ObjectiveGroup.vue b/client/src/components/objective-groups/ObjectiveGroup.vue index 76192b83..195869fe 100644 --- a/client/src/components/objective-groups/ObjectiveGroup.vue +++ b/client/src/components/objective-groups/ObjectiveGroup.vue @@ -1,20 +1,12 @@ @@ -19,6 +21,7 @@ import PenIcon from '@/components/icons/PenIcon'; import ME_QUERY from '@/graphql/gql/meQuery.gql'; + import AddContentButton from '@/components/AddContentButton'; export default { props: { @@ -29,6 +32,7 @@ }, components: { + AddContentButton, VisibilityAction, Objective, EyeIcon, @@ -44,7 +48,10 @@ computed: { canManageContent() { return this.me.permissions.includes('users.can_manage_school_class_content'); - } + }, + currentFilter() { + return this.me.selectedClass; + }, }, methods: { diff --git a/client/src/components/visibility/VisibilityAction.vue b/client/src/components/visibility/VisibilityAction.vue index f1ab774b..4d956387 100644 --- a/client/src/components/visibility/VisibilityAction.vue +++ b/client/src/components/visibility/VisibilityAction.vue @@ -35,7 +35,7 @@ }, hidden() { // is this content block / objective group user created? - return (this.isContentBlock ? this.block.userCreated : !!this.block.owner) + return this.block.userCreated // if so, is visibility not explicitly set for this school class? ? this.block.visibleFor.findIndex(el => el.id === this.schoolClass.id) === -1 // otherwise, is it explicitly hidden for this school class? @@ -66,9 +66,7 @@ } } } - } - // todo: refactor for single objectives when concept is clear - else { + } else { mutation = UPDATE_OBJECTIVE_VISIBILITY_MUTATION; variables = { input: { @@ -106,6 +104,11 @@ .visibility-action { margin-top: 9px; + position: absolute; + left: -70px; + top: 0px; + display: grid; + &__visibility-menu { top: 40px; } diff --git a/client/src/graphql/gql/fragments/objectiveParts.gql b/client/src/graphql/gql/fragments/objectiveParts.gql index fe1a97cf..9eabd6e7 100644 --- a/client/src/graphql/gql/fragments/objectiveParts.gql +++ b/client/src/graphql/gql/fragments/objectiveParts.gql @@ -1,6 +1,7 @@ fragment ObjectiveParts on ObjectiveNode { id text + userCreated hiddenFor { edges { node { diff --git a/client/src/graphql/gql/mutations/addObjective.gql b/client/src/graphql/gql/mutations/addObjective.gql new file mode 100644 index 00000000..46b844aa --- /dev/null +++ b/client/src/graphql/gql/mutations/addObjective.gql @@ -0,0 +1,16 @@ +#import "../fragments/objectiveParts.gql" +mutation AddObjective($input: AddObjectiveInput!){ + addObjective(input: $input) { + objective { + ...ObjectiveParts + } + } +} + + +#{"input": { +# "objective": { +# "objectiveGroup": "asdas", +# "text": "Lern etwas" +# }} +#} diff --git a/client/src/store/index.js b/client/src/store/index.js index 6b6b41cb..5ab7966f 100644 --- a/client/src/store/index.js +++ b/client/src/store/index.js @@ -43,7 +43,8 @@ export default new Vuex.Store({ scrollToAssignmentReady: state => state.scrollToAssignmentReady, scrollingToAssignment: state => state.scrollingToAssignment, currentProjectEntry: state => state.currentProjectEntry, - editModule: state => state.editModule + editModule: state => state.editModule, + currentObjectiveGroup: state => state.currentObjectiveGroup }, actions: { @@ -61,6 +62,7 @@ export default new Vuex.Store({ commit('setContentBlockPosition', {}); commit('setParentRoom', null); commit('setParentModule', ''); + // todo: remove commit('setObjectiveGroupType', ''); commit('setCurrentObjectiveGroup', ''); commit('setParentProject', null); @@ -86,6 +88,10 @@ export default new Vuex.Store({ commit('setContentBlockPosition', payload); dispatch('showModal', 'new-content-block-wizard'); }, + addObjective({commit, dispatch}, payload) { + commit('setCurrentObjectiveGroup', payload); + dispatch('showModal', 'new-objective-wizard'); + }, addRoomEntry({commit, dispatch}, payload) { commit('setParentRoom', payload); dispatch('showModal', 'new-room-entry-wizard'); @@ -94,6 +100,7 @@ export default new Vuex.Store({ commit('setCurrentRoomEntry', payload); dispatch('showModal', 'edit-room-entry-wizard'); }, + // todo: remove addObjectiveGroup({commit, dispatch}, {module, type}) { commit('setParentModule', module); commit('setObjectiveGroupType', type); @@ -179,6 +186,7 @@ export default new Vuex.Store({ setParentModule(state, payload) { state.parentModule = payload; }, + // todo: remove setObjectiveGroupType(state, payload) { state.objectiveGroupType = payload; }, diff --git a/client/src/styles/_visibility.scss b/client/src/styles/_visibility.scss new file mode 100644 index 00000000..6eaee061 --- /dev/null +++ b/client/src/styles/_visibility.scss @@ -0,0 +1,17 @@ +.hideable-element { + position: relative; + + &--hidden { + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(255, 255, 255, 0.5); + z-index: 10; + } + } +} + diff --git a/client/src/styles/main.scss b/client/src/styles/main.scss index 74e4914d..e6984b50 100644 --- a/client/src/styles/main.scss +++ b/client/src/styles/main.scss @@ -16,3 +16,4 @@ @import "actions"; @import "navigation"; @import "survey"; +@import "visibility"; diff --git a/server/objectives/inputs.py b/server/objectives/inputs.py index 2c08ea01..56106574 100644 --- a/server/objectives/inputs.py +++ b/server/objectives/inputs.py @@ -7,6 +7,10 @@ class ObjectiveInput(InputObjectType): id = graphene.ID() +class AddObjectiveArgument(InputObjectType): + text = graphene.String(required=True) + objective_group = graphene.ID(reuired=True) + class AddObjectiveGroupArgument(InputObjectType): title = graphene.String(required=True) module = graphene.ID(required=True) diff --git a/server/objectives/models.py b/server/objectives/models.py index fdd2cb77..422aabdd 100644 --- a/server/objectives/models.py +++ b/server/objectives/models.py @@ -27,7 +27,7 @@ class ObjectiveGroup(models.Model): visible_for = models.ManyToManyField(SchoolClass, related_name='visible_objective_groups', blank=True) def __str__(self): - return 'ObjectiveGroup {}-{}-{}'.format(self.id, self.module, self.title) + return '{} - {}'.format(self.module, self.title) class Objective(models.Model): diff --git a/server/objectives/mutations.py b/server/objectives/mutations.py index f0373408..3299c6bc 100644 --- a/server/objectives/mutations.py +++ b/server/objectives/mutations.py @@ -7,7 +7,7 @@ from api.utils import get_object from books.models import Module from books.schema.inputs import UserGroupBlockVisibility from core.utils import set_visible_for, set_hidden_for -from objectives.inputs import AddObjectiveGroupArgument, UpdateObjectiveGroupArgument +from objectives.inputs import AddObjectiveGroupArgument, UpdateObjectiveGroupArgument, AddObjectiveArgument from objectives.models import ObjectiveProgressStatus, Objective, ObjectiveGroup from objectives.schema import ObjectiveNode, ObjectiveGroupNode @@ -60,6 +60,30 @@ class UpdateObjectiveVisibility(relay.ClientIDMutation): return cls(objective=objective) +class AddObjective(relay.ClientIDMutation): + class Input: + objective = graphene.Argument(AddObjectiveArgument) + + objective = graphene.Field(ObjectiveNode) + + @classmethod + def mutate_and_get_payload(cls, root, info, **kwargs): + owner = info.context.user + if not owner.has_perm('users.can_manage_school_class_content'): + raise PermissionDenied('Missing permissions') + + objective_data = kwargs.get('objective') + objective_group_id = objective_data.get('objective_group') + text = objective_data.get('text') + + objective_group = get_object(ObjectiveGroup, objective_group_id) + + objective = Objective.objects.create(text=text, owner=owner, group=objective_group) + + return cls(objective=objective) + + + class AddObjectiveGroup(relay.ClientIDMutation): class Input: objective_group = graphene.Argument(AddObjectiveGroupArgument) @@ -127,5 +151,6 @@ class UpdateObjectiveGroup(relay.ClientIDMutation): class ObjectiveMutations: update_objective_progress = UpdateObjectiveProgress.Field() update_objective_visibility = UpdateObjectiveVisibility.Field() + add_objective = AddObjective.Field() add_objective_group = AddObjectiveGroup.Field() update_objective_group = UpdateObjectiveGroup.Field() diff --git a/server/objectives/schema.py b/server/objectives/schema.py index c49fc404..02fde6c7 100644 --- a/server/objectives/schema.py +++ b/server/objectives/schema.py @@ -44,6 +44,7 @@ class ObjectiveGroupNode(DjangoObjectType): class ObjectiveNode(DjangoObjectType): pk = graphene.Int() + user_created = graphene.Boolean() class Meta: model = Objective @@ -53,6 +54,9 @@ class ObjectiveNode(DjangoObjectType): def resolve_objective_progress(self, info, **kwargs): return self.objective_progress.filter(user=info.context.user) + def resolve_user_created(self, info, **kwargs): + return self.owner is not None + class ObjectiveProgressStatusNode(DjangoObjectType): pk = graphene.Int() From 6020da859824e127c7fc6d16dc45708ef58b40f3 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Mon, 26 Aug 2019 11:15:10 +0200 Subject: [PATCH 3/5] Add action menu and delete method to objectives --- client/src/components/ContentBlock.vue | 18 ++--- client/src/components/UserWidget.vue | 1 + .../components/objective-groups/Objective.vue | 70 ++++++++++++++++++- .../graphql/gql/fragments/objectiveParts.gql | 1 + .../graphql/gql/mutations/deleteObjective.gql | 11 +++ .../src/graphql/gql/objectiveGroupQuery.gql | 16 +++++ client/src/styles/_actions.scss | 13 ++++ server/objectives/mutations.py | 23 ++++++ server/objectives/schema.py | 3 + 9 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 client/src/graphql/gql/mutations/deleteObjective.gql diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue index cf504bc6..ef34254c 100644 --- a/client/src/components/ContentBlock.vue +++ b/client/src/components/ContentBlock.vue @@ -1,8 +1,8 @@