Merge pull request #4275 from MaximilianKrambach/sortLists

sort categories (+ motions) in dropdowns etc.
This commit is contained in:
Sean 2019-02-08 15:24:02 +01:00 committed by GitHub
commit 76210e807f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 40 deletions

View File

@ -1,14 +1,17 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { BaseRepository } from '../base-repository';
import { Category } from 'app/shared/models/motions/category'; import { Category } from 'app/shared/models/motions/category';
import { ViewCategory } from 'app/site/motions/models/view-category'; import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { DataSendService } from '../../core-services/data-send.service'; import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service'; import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Motion } from 'app/shared/models/motions/motion';
import { HttpService } from '../../core-services/http.service'; import { HttpService } from '../../core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable'; import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service'; import { Motion } from 'app/shared/models/motions/motion';
import { ViewCategory } from 'app/site/motions/models/view-category';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
/** /**
@ -34,13 +37,17 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
* @param mapperService Maps collection strings to classes * @param mapperService Maps collection strings to classes
* @param dataSend sending changed objects * @param dataSend sending changed objects
* @param httpService OpenSlides own HTTP service * @param httpService OpenSlides own HTTP service
* @param configService to get the default sorting
* @param translate translationService to get the currently selected locale
*/ */
public constructor( public constructor(
protected DS: DataStoreService, protected DS: DataStoreService,
mapperService: CollectionStringMapperService, mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService, viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService, private dataSend: DataSendService,
private httpService: HttpService private httpService: HttpService,
private configService: ConfigService,
private translate: TranslateService
) { ) {
super(DS, mapperService, viewModelStoreService, Category); super(DS, mapperService, viewModelStoreService, Category);
} }
@ -103,4 +110,38 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
const collectionString = 'rest/motions/category/' + category.id + '/numbering/'; const collectionString = 'rest/motions/category/' + category.id + '/numbering/';
await this.httpService.post(collectionString, { motions: motionIds }); await this.httpService.post(collectionString, { motions: motionIds });
} }
/**
* @ returns the observable for categories sorted according to configuration
*/
public getSortedViewModelListObservable(): Observable<ViewCategory[]> {
const subject = new BehaviorSubject<ViewCategory[]>([]);
this.getViewModelListObservable().subscribe(categories => {
subject.next(this.sortViewCategoriesByConfig(categories));
});
return subject.asObservable();
}
/**
* Sort viewCategories by the configured settings
*
* @param categories
* @returns the categories sorted by prefix or name, according to the config setting
*/
public sortViewCategoriesByConfig(categories: ViewCategory[]): ViewCategory[] {
const sort = this.configService.instant<'prefix' | 'name'>('motions_category_sorting') || 'prefix';
return categories.sort((a, b) => {
if (a[sort] && b[sort]) {
return a[sort].localeCompare(b[sort], this.translate.currentLang);
} else if (sort === 'prefix') {
if (a.prefix) {
return 1;
} else if (b.prefix) {
return -1;
} else {
return a.name.localeCompare(b.name);
}
}
});
}
} }

View File

@ -3,7 +3,6 @@ import { BehaviorSubject } from 'rxjs';
import { BaseViewModel } from '../../site/base/base-view-model'; import { BaseViewModel } from '../../site/base/base-view-model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { StorageService } from '../core-services/storage.service'; import { StorageService } from '../core-services/storage.service';
/** /**
* Describes the sorting columns of an associated ListView, and their state. * Describes the sorting columns of an associated ListView, and their state.
*/ */

View File

@ -110,9 +110,8 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Category'); super.setTitle('Category');
this.repo.getViewModelListObservable().subscribe(newViewCategories => { this.repo.getSortedViewModelListObservable().subscribe(newViewCategories => {
this.categories = newViewCategories; this.categories = newViewCategories;
this.sortDataSource();
}); });
} }
@ -186,13 +185,6 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
} }
} }
/**
* sorts the categories by prefix
*/
private sortDataSource(): void {
this.categories.sort((viewCategory1, viewCategory2) => (viewCategory1 > viewCategory2 ? 1 : -1));
}
/** /**
* executed on cancel button * executed on cancel button
* @param viewCategory * @param viewCategory

View File

@ -10,6 +10,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service'; import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
import { BaseViewComponent } from '../../../base/base-view'; import { BaseViewComponent } from '../../../base/base-view';
import { Category } from 'app/shared/models/motions/category'; import { Category } from 'app/shared/models/motions/category';
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service'; import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../../models/view-motion'; import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../../models/view-motion';
import { CreateMotion } from '../../models/create-motion'; import { CreateMotion } from '../../models/create-motion';
@ -338,6 +339,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
* @param promptService ensure safe deletion * @param promptService ensure safe deletion
* @param pdfExport export the motion to pdf * @param pdfExport export the motion to pdf
* @param personalNoteService: personal comments and favorite marker * @param personalNoteService: personal comments and favorite marker
* @param categoryRepo
*/ */
public constructor( public constructor(
title: Title, title: Title,
@ -361,14 +363,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
private pdfExport: MotionPdfExportService, private pdfExport: MotionPdfExportService,
private personalNoteService: PersonalNoteService, private personalNoteService: PersonalNoteService,
private linenumberingService: LinenumberingService, private linenumberingService: LinenumberingService,
private viewModelStore: ViewModelStoreService private viewModelStore: ViewModelStoreService,
private categoryRepo: CategoryRepositoryService
) { ) {
super(title, translate, matSnackBar); super(title, translate, matSnackBar);
// Initial Filling of the Subjects // Initial Filling of the Subjects
this.submitterObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewUser)); this.submitterObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewUser));
this.supporterObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewUser)); this.supporterObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewUser));
this.categoryObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewCategory)); this.categoryObserver = new BehaviorSubject(
this.categoryRepo.sortViewCategoriesByConfig(this.viewModelStore.getAll(ViewCategory))
);
this.workflowObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewWorkflow)); this.workflowObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewWorkflow));
this.blockObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMotionBlock)); this.blockObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMotionBlock));
this.mediafilesObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMediafile)); this.mediafilesObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMediafile));
@ -382,7 +387,9 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
this.submitterObserver.next(this.viewModelStore.getAll(ViewUser)); this.submitterObserver.next(this.viewModelStore.getAll(ViewUser));
this.supporterObserver.next(this.viewModelStore.getAll(ViewUser)); this.supporterObserver.next(this.viewModelStore.getAll(ViewUser));
} else if (newModel instanceof Category) { } else if (newModel instanceof Category) {
this.categoryObserver.next(this.viewModelStore.getAll(ViewCategory)); this.categoryObserver.next(
this.categoryRepo.sortViewCategoriesByConfig(this.viewModelStore.getAll(ViewCategory))
);
} else if (newModel instanceof Workflow) { } else if (newModel instanceof Workflow) {
this.workflowObserver.next(this.viewModelStore.getAll(ViewWorkflow)); this.workflowObserver.next(this.viewModelStore.getAll(ViewWorkflow));
} else if (newModel instanceof MotionBlock) { } else if (newModel instanceof MotionBlock) {

View File

@ -127,7 +127,7 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
.get<string>('motions_recommendations_by') .get<string>('motions_recommendations_by')
.subscribe(recommender => (this.recomendationEnabled = !!recommender)); .subscribe(recommender => (this.recomendationEnabled = !!recommender));
this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => (this.motionBlocks = mBs)); this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => (this.motionBlocks = mBs));
this.categoryRepo.getViewModelListObservable().subscribe(cats => (this.categories = cats)); this.categoryRepo.getSortedViewModelListObservable().subscribe(cats => (this.categories = cats));
this.tagRepo.getViewModelListObservable().subscribe(tags => (this.tags = tags)); this.tagRepo.getViewModelListObservable().subscribe(tags => (this.tags = tags));
this.workflowRepo.getViewModelListObservable().subscribe(wfs => (this.workflows = wfs)); this.workflowRepo.getViewModelListObservable().subscribe(wfs => (this.workflows = wfs));
this.filterService.filter().subscribe(filteredData => (this.sortService.data = filteredData)); this.filterService.filter().subscribe(filteredData => (this.sortService.data = filteredData));

View File

@ -184,7 +184,7 @@ export class MotionFilterListService extends BaseFilterListService<Motion, ViewM
* Subscibes to changing Categories, and updates the filter accordingly * Subscibes to changing Categories, and updates the filter accordingly
*/ */
private subscribeCategories(): void { private subscribeCategories(): void {
this.categoryRepo.getViewModelListObservable().subscribe(categories => { this.categoryRepo.getSortedViewModelListObservable().subscribe(categories => {
const categoryOptions: (OsFilterOption | string)[] = []; const categoryOptions: (OsFilterOption | string)[] = [];
categories.forEach(cat => { categories.forEach(cat => {
categoryOptions.push({ categoryOptions.push({

View File

@ -136,7 +136,7 @@ export class MotionMultiselectService {
const clearChoice = 'No category'; const clearChoice = 'No category';
const selectedChoice = await this.choiceService.open( const selectedChoice = await this.choiceService.open(
title, title,
this.categoryRepo.getViewModelList(), this.categoryRepo.sortViewCategoriesByConfig(this.categoryRepo.getViewModelList()),
false, false,
null, null,
clearChoice clearChoice

View File

@ -2,6 +2,9 @@ import { Injectable } from '@angular/core';
import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service'; import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service';
import { ViewMotion } from '../models/view-motion'; import { ViewMotion } from '../models/view-motion';
import { TranslateService } from '@ngx-translate/core';
import { StorageService } from 'app/core/core-services/storage.service';
import { ConfigService } from 'app/core/ui-services/config.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -24,4 +27,16 @@ export class MotionSortListService extends BaseSortListService<ViewMotion> {
] ]
}; };
protected name = 'Motion'; protected name = 'Motion';
/**
* Constructor. Sets the default sorting if none is set locally
*
* @param translate
* @param store
* @param config
*/
public constructor(translate: TranslateService, store: StorageService, config: ConfigService) {
super(translate, store);
this.sortOptions.sortProperty = config.instant<keyof ViewMotion>('motions_motions_sorting');
}
} }

View File

@ -177,6 +177,34 @@ def get_config_variables():
subgroup="General", subgroup="General",
) )
yield ConfigVariable(
name="motions_category_sorting",
default_value="prefix",
input_type="choice",
label="Sort categories by",
choices=(
{"value": "prefix", "display_name": "Prefix"},
{"value": "name", "display_name": "Name"},
),
weight=335,
group="Motions",
subgroup="General",
)
yield ConfigVariable(
name="motions_motions_sorting",
default_value="identifier",
input_type="choice",
label="Sort motions by",
choices=(
{"value": "callListWeight", "display_name": "Call list"},
{"value": "identifier", "display_name": "Identifier"},
),
weight=335,
group="Motions",
subgroup="General",
)
# Amendments # Amendments
yield ConfigVariable( yield ConfigVariable(
@ -184,7 +212,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Activate statute amendments", label="Activate statute amendments",
weight=335, weight=338,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -194,7 +222,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Activate amendments", label="Activate amendments",
weight=336, weight=339,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -204,7 +232,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Show amendments together with motions", label="Show amendments together with motions",
weight=337, weight=340,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -213,7 +241,7 @@ def get_config_variables():
name="motions_amendments_prefix", name="motions_amendments_prefix",
default_value="-", default_value="-",
label="Prefix for the identifier for amendments", label="Prefix for the identifier for amendments",
weight=340, weight=341,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -341,26 +369,12 @@ def get_config_variables():
subgroup="Export", subgroup="Export",
) )
yield ConfigVariable(
name="motions_export_category_sorting",
default_value="prefix",
input_type="choice",
label="Sort categories by",
choices=(
{"value": "prefix", "display_name": "Prefix"},
{"value": "name", "display_name": "Name"},
),
weight=380,
group="Motions",
subgroup="Export",
)
yield ConfigVariable( yield ConfigVariable(
name="motions_export_sequential_number", name="motions_export_sequential_number",
default_value=True, default_value=True,
input_type="boolean", input_type="boolean",
label="Include the sequential number in PDF and DOCX", label="Include the sequential number in PDF and DOCX",
weight=385, weight=380,
group="Motions", group="Motions",
subgroup="Export", subgroup="Export",
) )