Merge pull request #4032 from FinnStutzenstein/new_configs
new configs for statute amendments; improved the majorityMethod confi…
This commit is contained in:
commit
10714bbbe4
@ -67,10 +67,10 @@ export class ConfigService extends OpenSlidesComponent {
|
||||
*
|
||||
* @param key The config value to get from.
|
||||
*/
|
||||
public get(key: string): Observable<any> {
|
||||
public get<T = any>(key: string): Observable<T> {
|
||||
if (!this.configSubjects[key]) {
|
||||
this.configSubjects[key] = new BehaviorSubject<any>(this.instant(key));
|
||||
}
|
||||
return this.configSubjects[key].asObservable();
|
||||
return this.configSubjects[key].asObservable() as Observable<T>;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
<mat-form-field [formGroup]="form">
|
||||
<mat-select [formControl]="formControl" [placeholder]="listname" [multiple]="multiple" #thisSelector>
|
||||
<mat-select [formControl]="formControl" placeholder="{{ listname | translate }}" [multiple]="multiple" #thisSelector>
|
||||
<ngx-mat-select-search [formControl]="filterControl"></ngx-mat-select-search>
|
||||
<div *ngIf="!multiple">
|
||||
<mat-option [value]="null"><span translate>None</span></mat-option>
|
||||
<div *ngIf="!multiple && includeNone">
|
||||
<mat-option [value]="null">
|
||||
<span translate>None</span>
|
||||
</mat-option>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<mat-option *ngFor="let selectedItem of filteredItems | async" [value]="selectedItem.id">
|
||||
{{selectedItem.getTitle(translate)}}
|
||||
{{ selectedItem.getTitle(translate) }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
@ -15,7 +17,8 @@
|
||||
<span translate>Selected values</span>:
|
||||
</p>
|
||||
<mat-chip-list #chipList>
|
||||
<mat-chip *ngFor="let selectedItem of thisSelector?.value" (removed)="remove(selectedItem)">{{selectedItem.name}}
|
||||
<mat-chip *ngFor="let selectedItem of thisSelector?.value" (removed)="remove(selectedItem)">
|
||||
{{ selectedItem.name }}
|
||||
<mat-icon (click)="remove(selectedItem)">cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
@ -22,8 +22,8 @@ import { Selectable } from '../selectable';
|
||||
* ngDefaultControl
|
||||
* [multiple]="true"
|
||||
* placeholder="Placeholder"
|
||||
* [InputListValues]="myListValues",
|
||||
* [form]="myform_name",
|
||||
* [InputListValues]="myListValues"
|
||||
* [form]="myform_name"
|
||||
* [formControl]="myformcontrol">
|
||||
* </os-search-value-selector>
|
||||
* ```
|
||||
@ -68,6 +68,12 @@ export class SearchValueSelectorComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
public multiple: boolean;
|
||||
|
||||
/**
|
||||
* Decide, if none should be included, if multiple is false.
|
||||
*/
|
||||
@Input()
|
||||
public includeNone = false;
|
||||
|
||||
/**
|
||||
* The inputlist subject. Subscribes to it and updates the selector, if the subject
|
||||
* changes its values.
|
||||
|
@ -10,6 +10,10 @@ import { DataStoreService } from 'app/core/services/data-store.service';
|
||||
import { AgendaRepositoryService } from '../../services/agenda-repository.service';
|
||||
import { ViewItem } from '../../models/view-item';
|
||||
import { OperatorService } from 'app/core/services/operator.service';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
|
||||
/**
|
||||
* The list of speakers for agenda items.
|
||||
@ -19,7 +23,7 @@ import { OperatorService } from 'app/core/services/operator.service';
|
||||
templateUrl: './speaker-list.component.html',
|
||||
styleUrls: ['./speaker-list.component.scss']
|
||||
})
|
||||
export class SpeakerListComponent implements OnInit {
|
||||
export class SpeakerListComponent extends BaseViewComponent implements OnInit {
|
||||
/**
|
||||
* Holds the view item to the given topic
|
||||
*/
|
||||
@ -52,17 +56,24 @@ export class SpeakerListComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Constructor for speaker list component
|
||||
* @param title
|
||||
* @param translate
|
||||
* @param snackBar
|
||||
* @param route Angulars ActivatedRoute
|
||||
* @param DS the DataStore
|
||||
* @param itemRepo Repository fpr agenda items
|
||||
* @param op the current operator
|
||||
*/
|
||||
public constructor(
|
||||
title: Title,
|
||||
translate: TranslateService,
|
||||
snackBar: MatSnackBar,
|
||||
private route: ActivatedRoute,
|
||||
private DS: DataStoreService,
|
||||
private itemRepo: AgendaRepositoryService,
|
||||
private op: OperatorService
|
||||
) {
|
||||
super(title, translate, snackBar)
|
||||
this.addSpeakerForm = new FormGroup({ user_id: new FormControl([]) });
|
||||
this.getAgendaItemByUrl();
|
||||
}
|
||||
@ -115,9 +126,8 @@ export class SpeakerListComponent implements OnInit {
|
||||
* Create a speaker out of an id
|
||||
* @param userId the user id to add to the list. No parameter adds the operators user as speaker.
|
||||
*/
|
||||
public async addNewSpeaker(userId?: number): Promise<void> {
|
||||
await this.itemRepo.addSpeaker(userId, this.viewItem.item);
|
||||
this.addSpeakerForm.reset();
|
||||
public addNewSpeaker(userId?: number): void {
|
||||
this.itemRepo.addSpeaker(userId, this.viewItem.item).then(() => this.addSpeakerForm.reset(), this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +138,7 @@ export class SpeakerListComponent implements OnInit {
|
||||
public onSortingChange(listInNewOrder: ViewSpeaker[]): void {
|
||||
// extract the ids from the ViewSpeaker array
|
||||
const userIds = listInNewOrder.map(speaker => speaker.id);
|
||||
this.itemRepo.sortSpeakers(userIds, this.viewItem.item);
|
||||
this.itemRepo.sortSpeakers(userIds, this.viewItem.item).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,14 +146,14 @@ export class SpeakerListComponent implements OnInit {
|
||||
* @param item the speaker marked in the list
|
||||
*/
|
||||
public onStartButton(item: ViewSpeaker): void {
|
||||
this.itemRepo.startSpeaker(item.id, this.viewItem.item);
|
||||
this.itemRepo.startSpeaker(item.id, this.viewItem.item).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the mic-cross button
|
||||
*/
|
||||
public onStopButton(): void {
|
||||
this.itemRepo.stopSpeaker(this.viewItem.item);
|
||||
this.itemRepo.stopSpeaker(this.viewItem.item).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,7 +161,7 @@ export class SpeakerListComponent implements OnInit {
|
||||
* @param item
|
||||
*/
|
||||
public onMarkButton(item: ViewSpeaker): void {
|
||||
this.itemRepo.markSpeaker(item.user.id, !item.marked, this.viewItem.item);
|
||||
this.itemRepo.markSpeaker(item.user.id, !item.marked, this.viewItem.item).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +169,7 @@ export class SpeakerListComponent implements OnInit {
|
||||
* @param item
|
||||
*/
|
||||
public onDeleteButton(item?: ViewSpeaker): void {
|
||||
this.itemRepo.deleteSpeaker(this.viewItem.item, item ? item.id : null);
|
||||
this.itemRepo.deleteSpeaker(this.viewItem.item, item ? item.id : null).then(null, this.raiseError);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,6 @@ type ConfigInputType =
|
||||
| 'boolean'
|
||||
| 'markupText'
|
||||
| 'integer'
|
||||
| 'majorityMethod'
|
||||
| 'choice'
|
||||
| 'datetimepicker'
|
||||
| 'colorpicker'
|
||||
|
@ -220,8 +220,7 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
* @param config
|
||||
*/
|
||||
public createViewModel(config: Config): ViewConfig {
|
||||
const vm = new ViewConfig(config);
|
||||
return vm;
|
||||
return new ViewConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,8 +79,7 @@
|
||||
<mat-accordion multi='true' class='on-transition-fade'>
|
||||
|
||||
<!-- MetaInfo Panel-->
|
||||
<mat-expansion-panel #metaInfoPanel [expanded]="this.editMotion" class='meta-info-block meta-info-panel'>
|
||||
<!-- <mat-expansion-panel #metaInfoPanel [expanded]="this.editReco && this.newReco" class='meta-info-block meta-info-panel'> -->
|
||||
<mat-expansion-panel #metaInfoPanel [expanded]="editMotion" class='meta-info-block meta-info-panel'>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<mat-icon>info</mat-icon>
|
||||
@ -155,8 +154,8 @@
|
||||
<div *ngIf="motion && motion.submitters || newMotion">
|
||||
<div *ngIf="newMotion">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('submitters_id')"
|
||||
[multiple]="true" listname="{{ 'Submitters' | translate }}" [InputListValues]="this.submitterObserver"></os-search-value-selector>
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="metaInfoForm.get('submitters_id')"
|
||||
[multiple]="true" listname="{{ 'Submitters' | translate }}" [InputListValues]="submitterObserver"></os-search-value-selector>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="!editMotion && !newMotion">
|
||||
@ -172,8 +171,8 @@
|
||||
<!-- print all motion supporters -->
|
||||
<div *ngIf="editMotion">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('supporters_id')"
|
||||
[multiple]="true" listname="{{ 'Supporters' | translate }}" [InputListValues]="this.supporterObserver"></os-search-value-selector>
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="metaInfoForm.get('supporters_id')"
|
||||
[multiple]="true" listname="{{ 'Supporters' | translate }}" [InputListValues]="supporterObserver"></os-search-value-selector>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="!editMotion && motion.hasSupporters()">
|
||||
@ -230,8 +229,16 @@
|
||||
{{ motion.category }}
|
||||
</div>
|
||||
<div *ngIf="editMotion || newMotion">
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="this.metaInfoForm.get('category_id')"
|
||||
[multiple]="false" listname="{{ 'Category' | translate }}" [InputListValues]="this.categoryObserver"></os-search-value-selector>
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="metaInfoForm.get('category_id')"
|
||||
[multiple]="false" listname="{{ 'Category' | translate }}" [InputListValues]="categoryObserver" includeNone="true"></os-search-value-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Workflow (just during creation) -->
|
||||
<div *ngIf="editMotion">
|
||||
<div *osPerms="['motions.can_manage', 'motions.can_manage_metadata']">
|
||||
<os-search-value-selector ngDefaultControl [form]="metaInfoForm" [formControl]="metaInfoForm.get('workflow_id')"
|
||||
[multiple]="false" listname="{{ 'Workflow' | translate }}" [InputListValues]="workflowObserver"></os-search-value-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { User } from '../../../../shared/models/users/user';
|
||||
import { DataStoreService } from '../../../../core/services/data-store.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Motion } from '../../../../shared/models/motions/motion';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject, Subscription, ReplaySubject, concat } from 'rxjs';
|
||||
import { LineRange } from '../../services/diff.service';
|
||||
import {
|
||||
MotionChangeRecommendationComponent,
|
||||
@ -26,6 +26,8 @@ import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
|
||||
import { StatuteParagraphRepositoryService } from '../../services/statute-paragraph-repository.service';
|
||||
import { ConfigService } from '../../../../core/services/config.service';
|
||||
import { Workflow } from 'app/shared/models/motions/workflow';
|
||||
import { take, takeWhile, multicast, skipWhile } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Component for the motion detail view
|
||||
@ -71,9 +73,25 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
public newMotion = false;
|
||||
|
||||
/**
|
||||
* Target motion. Might be new or old
|
||||
* Sets the motions, e.g. via an autoupdate. Reload important things here:
|
||||
* - Reload the recommendation. Not changed with autoupdates, but if the motion is loaded this needs to run.
|
||||
*/
|
||||
public motion: ViewMotion;
|
||||
public set motion(value: ViewMotion) {
|
||||
this._motion = value;
|
||||
this.setupRecommender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target motion. Might be the new one or old.
|
||||
*/
|
||||
public get motion(): ViewMotion {
|
||||
return this._motion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the target motion. Accessed via the getter and setter.
|
||||
*/
|
||||
private _motion: ViewMotion;
|
||||
|
||||
/**
|
||||
* Value of the configuration variable `motions_statutes_enabled` - are statutes enabled?
|
||||
@ -121,6 +139,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public categoryObserver: BehaviorSubject<Category[]>;
|
||||
|
||||
/**
|
||||
* Subject for the Categories
|
||||
*/
|
||||
public workflowObserver: BehaviorSubject<Workflow[]>;
|
||||
|
||||
/**
|
||||
* Subject for the Submitters
|
||||
*/
|
||||
@ -141,6 +164,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public recommender: string;
|
||||
|
||||
/**
|
||||
* The subscription to the recommender config variable.
|
||||
*/
|
||||
private recommenderSubscription: Subscription;
|
||||
|
||||
/**
|
||||
* Constuct the detail view.
|
||||
*
|
||||
@ -185,15 +213,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
this.submitterObserver = new BehaviorSubject(DS.getAll(User));
|
||||
this.supporterObserver = new BehaviorSubject(DS.getAll(User));
|
||||
this.categoryObserver = new BehaviorSubject(DS.getAll(Category));
|
||||
this.workflowObserver = new BehaviorSubject(DS.getAll(Workflow));
|
||||
|
||||
// Make sure the subjects are updated, when a new Model for the type arrives
|
||||
this.DS.changeObservable.subscribe(newModel => {
|
||||
if (newModel instanceof User) {
|
||||
this.submitterObserver.next(DS.getAll(User));
|
||||
this.supporterObserver.next(DS.getAll(User));
|
||||
}
|
||||
if (newModel instanceof Category) {
|
||||
} else if (newModel instanceof Category) {
|
||||
this.categoryObserver.next(DS.getAll(Category));
|
||||
} else if (newModel instanceof Workflow) {
|
||||
this.workflowObserver.next(DS.getAll(Workflow));
|
||||
}
|
||||
});
|
||||
this.configService.get('motions_statutes_enabled').subscribe(
|
||||
@ -282,6 +312,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
recommendation_id: [''],
|
||||
submitters_id: [],
|
||||
supporters_id: [],
|
||||
workflow_id: [],
|
||||
origin: ['']
|
||||
});
|
||||
this.contentForm = this.formBuilder.group({
|
||||
@ -291,6 +322,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
statute_amendment: [''], // Internal value for the checkbox, not saved to the model
|
||||
statute_paragraph_id: ['']
|
||||
});
|
||||
this.updateWorkflowIdForCreateForm();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -474,6 +506,21 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public updateWorkflowIdForCreateForm(): void {
|
||||
const isStatuteAmendment = !!this.contentForm.get('statute_amendment').value;
|
||||
const configKey = isStatuteAmendment ? 'motions_statute_amendments_workflow' : 'motions_workflow';
|
||||
// TODO: This should just be a takeWhile(id => !id), but should include the last one where the id is OK.
|
||||
// takeWhile will get a inclusive parameter, see https://github.com/ReactiveX/rxjs/pull/4115
|
||||
this.configService.get<string>(configKey).pipe(multicast(
|
||||
() => new ReplaySubject(1),
|
||||
(ids) => ids.pipe(takeWhile(id => !id), o => concat(o, ids.pipe(take(1))))
|
||||
), skipWhile(id => !id)).subscribe(id => {
|
||||
this.metaInfoForm.patchValue({
|
||||
workflow_id: parseInt(id, 10),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If the checkbox is deactivated, the statute_paragraph_id-field needs to be reset, as only that field is saved
|
||||
* @param {MatCheckboxChange} $event
|
||||
@ -482,6 +529,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
this.contentForm.patchValue({
|
||||
statute_paragraph_id: null
|
||||
});
|
||||
this.updateWorkflowIdForCreateForm();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -548,9 +596,13 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
/**
|
||||
* Observes the repository for changes in the motion recommender
|
||||
*/
|
||||
public getRecommender(): void {
|
||||
this.repo.getRecommenderObservable().subscribe(newRecommender => {
|
||||
this.recommender = newRecommender;
|
||||
public setupRecommender(): void {
|
||||
const configKey = this.motion.isStatuteAmendment() ? 'motions_statute_recommendations_by' : 'motions_recommendations_by';
|
||||
if (this.recommenderSubscription) {
|
||||
this.recommenderSubscription.unsubscribe();
|
||||
}
|
||||
this.recommenderSubscription = this.configService.get(configKey).subscribe(recommender => {
|
||||
this.recommender = recommender;
|
||||
});
|
||||
}
|
||||
|
||||
@ -571,10 +623,9 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* Calls getRecommender and sets the surrounding motions to navigate back and forth
|
||||
* Sets the surrounding motions to navigate back and forth
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.getRecommender();
|
||||
this.repo.getViewModelListObservable().subscribe(newMotionList => {
|
||||
if (newMotionList) {
|
||||
this.allMotions = newMotionList;
|
||||
|
@ -126,6 +126,10 @@ export class ViewMotion extends BaseViewModel {
|
||||
return this._workflow;
|
||||
}
|
||||
|
||||
public get workflow_id(): number {
|
||||
return this.motion ? this.motion.workflow_id : null;
|
||||
}
|
||||
|
||||
public get state(): WorkflowState {
|
||||
return this._state;
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import { ViewStatuteParagraph } from '../models/view-statute-paragraph';
|
||||
import { Identifiable } from '../../../shared/models/base/identifiable';
|
||||
import { CollectionStringModelMapperService } from '../../../core/services/collectionStringModelMapper.service';
|
||||
import { HttpService } from 'app/core/services/http.service';
|
||||
import { ConfigService } from 'app/core/services/config.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||
|
||||
@ -52,7 +50,6 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
mapperService: CollectionStringModelMapperService,
|
||||
private dataSend: DataSendService,
|
||||
private httpService: HttpService,
|
||||
private configService: ConfigService,
|
||||
private readonly lineNumbering: LinenumberingService,
|
||||
private readonly diff: DiffService
|
||||
) {
|
||||
@ -144,15 +141,6 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
await this.httpService.put(restPath, { recommendation: stateId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the motions_recommendations_by observable from the config service
|
||||
*
|
||||
* @return an observable that contains the motions "Recommended by" string
|
||||
*/
|
||||
public getRecommenderObservable(): Observable<string> {
|
||||
return this.configService.get('motions_recommendations_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the changed nodes to the server.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.core.validators import MinValueValidator
|
||||
|
||||
from openslides.core.config import ConfigVariable
|
||||
from openslides.poll.majority import majorityMethods
|
||||
|
||||
|
||||
def get_config_variables():
|
||||
@ -47,8 +48,9 @@ def get_config_variables():
|
||||
# TODO: Add server side validation of the choices.
|
||||
yield ConfigVariable(
|
||||
name='assignments_poll_default_majority_method',
|
||||
default_value='simple_majority',
|
||||
input_type='majorityMethod',
|
||||
default_value=majorityMethods[0]['value'],
|
||||
input_type='choice',
|
||||
choices=majorityMethods,
|
||||
label='Required majority',
|
||||
help_text='Default method to check whether a candidate has reached the required majority.',
|
||||
weight=425,
|
||||
|
@ -29,7 +29,6 @@ INPUT_TYPE_MAPPING = {
|
||||
'choice': str,
|
||||
'colorpicker': str,
|
||||
'datetimepicker': int,
|
||||
'majorityMethod': str,
|
||||
'static': dict,
|
||||
'translations': list,
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.core.validators import MinValueValidator
|
||||
|
||||
from openslides.core.config import ConfigVariable
|
||||
from openslides.poll.majority import majorityMethods
|
||||
|
||||
from .models import Workflow
|
||||
|
||||
@ -34,6 +35,16 @@ def get_config_variables():
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
yield ConfigVariable(
|
||||
name='motions_statute_amendments_workflow',
|
||||
default_value='1',
|
||||
input_type='choice',
|
||||
label='Workflow of new statute amendments',
|
||||
choices=get_workflow_choices,
|
||||
weight=312,
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
yield ConfigVariable(
|
||||
name='motions_identifier',
|
||||
default_value='per_category',
|
||||
@ -124,6 +135,16 @@ def get_config_variables():
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
yield ConfigVariable(
|
||||
name='motions_statute_recommendations_by',
|
||||
default_value='',
|
||||
label='Name of statute recommender',
|
||||
help_text='Will be displayed as label before selected statute recommendation. ' +
|
||||
'Use an empty value to disable the statute recommendation system.',
|
||||
weight=333,
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
yield ConfigVariable(
|
||||
name='motions_recommendation_text_mode',
|
||||
default_value='original',
|
||||
@ -134,7 +155,7 @@ def get_config_variables():
|
||||
{'value': 'changed', 'display_name': 'Changed version'},
|
||||
{'value': 'diff', 'display_name': 'Diff version'},
|
||||
{'value': 'agreed', 'display_name': 'Final version'}),
|
||||
weight=333,
|
||||
weight=334,
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
@ -145,7 +166,7 @@ def get_config_variables():
|
||||
default_value=False,
|
||||
input_type='boolean',
|
||||
label='Activate statutes',
|
||||
weight=334,
|
||||
weight=335,
|
||||
group='Motions',
|
||||
subgroup='General')
|
||||
|
||||
@ -155,7 +176,7 @@ def get_config_variables():
|
||||
default_value=False,
|
||||
input_type='boolean',
|
||||
label='Activate amendments',
|
||||
weight=335,
|
||||
weight=336,
|
||||
group='Motions',
|
||||
subgroup='Amendments')
|
||||
|
||||
@ -233,8 +254,9 @@ def get_config_variables():
|
||||
# TODO: Add server side validation of the choices.
|
||||
yield ConfigVariable(
|
||||
name='motions_poll_default_majority_method',
|
||||
default_value='simple_majority',
|
||||
input_type='majorityMethod',
|
||||
default_value=majorityMethods[0]['value'],
|
||||
input_type='choice',
|
||||
choices=majorityMethods,
|
||||
label='Required majority',
|
||||
help_text='Default method to check whether a motion has reached the required majority.',
|
||||
weight=357,
|
||||
|
7
openslides/poll/majority.py
Normal file
7
openslides/poll/majority.py
Normal file
@ -0,0 +1,7 @@
|
||||
# Common majority methods for all apps using polls. The first one should be the default.
|
||||
majorityMethods = (
|
||||
{'value': 'simple_majority', 'display_name': 'Simple majority'},
|
||||
{'value': 'two-thirds_majority', 'display_name': 'Two-thirds majority'},
|
||||
{'value': 'three-quarters_majority', 'display_name': 'Three-quarters majority'},
|
||||
{'value': 'disabled', 'display_name': 'Disabled'},
|
||||
)
|
Loading…
Reference in New Issue
Block a user