diff --git a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts index a1f8750f3..476b7d605 100644 --- a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts +++ b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit, Input, ViewChild } from '@angular/core'; +import { Component, OnInit, Input, ViewChild, OnDestroy } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; -import { Subject, ReplaySubject, BehaviorSubject } from 'rxjs'; +import { Subject, ReplaySubject, BehaviorSubject, Subscription } from 'rxjs'; import { MatSelect } from '@angular/material'; import { takeUntil } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; @@ -35,7 +35,7 @@ import { Selectable } from '../selectable'; templateUrl: './search-value-selector.component.html', styleUrls: ['./search-value-selector.component.scss'] }) -export class SearchValueSelectorComponent implements OnInit { +export class SearchValueSelectorComponent implements OnInit, OnDestroy { /** * ngModel variable - Deprecated with Angular 7 * DO NOT USE: READ AT remove() FUNCTION! @@ -52,6 +52,16 @@ export class SearchValueSelectorComponent implements OnInit { */ public filteredItems: ReplaySubject = new ReplaySubject(1); + /** + * The inputlist subject. + */ + private _inputListSubject: BehaviorSubject; + + /** + * Saves the current subscription to _inputListSubject. + */ + private _inputListSubscription: Subscription = null; + /** * Decide if this should be a single or multi-select-field */ @@ -59,10 +69,20 @@ export class SearchValueSelectorComponent implements OnInit { public multiple: boolean; /** - * The Input List Values + * The inputlist subject. Subscribes to it and updates the selector, if the subject + * changes its values. */ @Input() - public InputListValues: BehaviorSubject; + public set InputListValues(value: BehaviorSubject) { + // unsubscribe to old subscription. + if (this._inputListSubscription) { + this._inputListSubscription.unsubscribe(); + } + this._inputListSubject = value; + this._inputListSubscription = this._inputListSubject.subscribe(values => { + this.filterItems(); + }); + } /** * Placeholder of the List @@ -111,31 +131,43 @@ export class SearchValueSelectorComponent implements OnInit { * onInit with filter ans subscription on filter */ public ngOnInit(): void { - this.filteredItems.next(this.InputListValues.getValue()); + if (this._inputListSubject) { + this.filteredItems.next(this._inputListSubject.getValue()); + } // listen to value changes this.filterControl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => { this.filterItems(); }); } + /** + * Unsubscribe on destroing. + */ + public ngOnDestroy(): void { + if (this._inputListSubscription) { + this._inputListSubscription.unsubscribe(); + } + this._onDestroy.next(); + } + /** * the filter function itself */ private filterItems(): void { - if (!this.InputListValues) { + if (!this._inputListSubject) { return; } // get the search keyword let search = this.filterControl.value; if (!search) { - this.filteredItems.next(this.InputListValues.getValue()); + this.filteredItems.next(this._inputListSubject.getValue()); return; } else { search = search.toLowerCase(); } // filter the values this.filteredItems.next( - this.InputListValues.getValue().filter( + this._inputListSubject.getValue().filter( selectedItem => selectedItem .toString() diff --git a/client/src/app/shared/directives/perms.directive.ts b/client/src/app/shared/directives/perms.directive.ts index 866b05785..5cb632352 100644 --- a/client/src/app/shared/directives/perms.directive.ts +++ b/client/src/app/shared/directives/perms.directive.ts @@ -39,6 +39,13 @@ export class PermsDirective extends OpenSlidesComponent { */ private alternative: boolean; + /** + * Switch, to invert the result of checkPermission. Usefull for using osPerms as if-else: + * For one element you can use `*osPerms="'perm'"` and for the else-element use + * `*osPerms="'perm';complement: true"`. + */ + private complement: boolean; + /** * Constructs the directive once. Observes the operator for it's groups so the * directive can perform changes dynamically @@ -85,6 +92,15 @@ export class PermsDirective extends OpenSlidesComponent { this.updateView(); } + /** + * COmes from the view. + */ + @Input('osPermsComplement') + public set osPermsComplement(value: boolean) { + this.complement = value; + this.updateView(); + } + /** * Shows or hides certain content in the view. */ @@ -108,6 +124,11 @@ export class PermsDirective extends OpenSlidesComponent { * Returns true if the users permissions fit. */ private checkPermissions(): boolean { - return this.permissions.length === 0 || this.operator.hasPerms(...this.permissions); + const hasPerms = this.permissions.length === 0 || this.operator.hasPerms(...this.permissions); + if (this.complement) { + return !hasPerms; + } else { + return hasPerms; + } } } diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html index e1d55fb1b..a7f280886 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html @@ -94,8 +94,8 @@ - - + + @@ -122,8 +122,8 @@ - - + +
@@ -153,8 +153,8 @@
-
-
+
+
@@ -171,7 +171,7 @@
-
+
@@ -179,24 +179,33 @@

Supporters

    -
  • {{supporter.full_name}}
  • +
  • {{ supporter.full_name }}
- - - {{motion.state}} - - {{state}} - - - replayReset State - - - +
+ +

State

+ {{ motion.state }} +
+
+
+ + + {{ motion.state }} + + {{ state }} + + + replay + Reset State + + + +
@@ -204,7 +213,7 @@
- {{state}} + {{ recommendation }}
@@ -215,7 +224,7 @@

Category

{{motion.category}}
-
+
@@ -225,11 +234,13 @@

Origin

- {{motion.origin}} + {{ motion.origin }} +
+
+ + +
- - -
@@ -258,7 +269,8 @@

{{motion.title}}

- +
@@ -278,7 +290,7 @@ [scrollToChange]="scrollToChange" (createChangeRecommendation)="createChangeRecommendation($event)"> - + diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts index dcb394bc5..b6d9f69ea 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts @@ -105,17 +105,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit { /** * Subject for the Categories */ - public categoryObserver: BehaviorSubject>; + public categoryObserver: BehaviorSubject; /** * Subject for the Submitters */ - public submitterObserver: BehaviorSubject>; + public submitterObserver: BehaviorSubject; /** * Subject for the Supporters */ - public supporterObserver: BehaviorSubject>; + public supporterObserver: BehaviorSubject; /** * Value for os-motion-detail-diff: when this is set, that component scrolls to the given change @@ -503,7 +503,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit { * Determine if the user has the correct requirements to alter the motion */ public opCanEdit(): boolean { - return this.op.hasPerms('motions.can_manage'); + return this.op.hasPerms('motions.can_manage', 'motions.can_manage_metadata'); } /** diff --git a/openslides/motions/views.py b/openslides/motions/views.py index 4596070ad..b766f1ab1 100644 --- a/openslides/motions/views.py +++ b/openslides/motions/views.py @@ -134,14 +134,15 @@ class MotionViewSet(ModelViewSet): 'title', 'text', 'reason', + 'category_id', ] if parent_motion is not None: # For creating amendments. whitelist.extend([ 'parent_id', 'amendment_paragraphs', - 'category_id', # This will be set to the matching - 'motion_block_id', # values from parent_motion. + 'motion_block_id', # This and the category_id will be set to the matching + # values from parent_motion. ]) request.data['category_id'] = parent_motion.category_id request.data['motion_block_id'] = parent_motion.motion_block_id