Merge pull request #4411 from MaximilianKrambach/sort_alternative
fix sort performance issues for dropdowns
This commit is contained in:
commit
398ffc30ea
@ -2,6 +2,8 @@ import { Injectable } from '@angular/core';
|
||||
import { tap, map } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { BaseAgendaViewModel } from 'app/site/base/base-agenda-view-model';
|
||||
@ -13,7 +15,6 @@ import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { TreeService } from 'app/core/ui-services/tree.service';
|
||||
import { ViewItem } from 'app/site/agenda/models/view-item';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
@ -39,15 +40,15 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
translate: TranslateService,
|
||||
private httpService: HttpService,
|
||||
private config: ConfigService,
|
||||
private treeService: TreeService,
|
||||
private translate: TranslateService
|
||||
private treeService: TreeService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Item);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Item);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
@ -85,7 +86,7 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
|
||||
const repo = this.collectionStringMapperService.getRepository(
|
||||
viewItem.item.content_object.collection
|
||||
) as BaseAgendaContentObjectRepository<any, any>;
|
||||
return numberPrefix + repo.getAgendaTitleWithType(viewItem);
|
||||
return numberPrefix + repo.getAgendaTitleWithType(viewItem.title_information);
|
||||
}
|
||||
};
|
||||
viewItem.getListTitle = viewItem.getTitle;
|
||||
|
@ -30,12 +30,12 @@ export class TopicRepositoryService extends BaseAgendaContentObjectRepository<Vi
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Topic, [Mediafile, Item]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Topic, [Mediafile, Item]);
|
||||
}
|
||||
|
||||
public getAgendaTitle = (topic: Partial<Topic> | Partial<ViewTopic>) => {
|
||||
|
@ -36,9 +36,9 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Assignment, [User, Item, Tag]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Assignment, [User, Item, Tag]);
|
||||
}
|
||||
|
||||
public getAgendaTitle = (assignment: Partial<Assignment> | Partial<ViewAssignment>) => {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
import { CollectionStringMapperService } from '../core-services/collectionStringMapper.service';
|
||||
@ -25,9 +27,18 @@ export abstract class BaseAgendaContentObjectRepository<
|
||||
dataSend: DataSendService,
|
||||
collectionStringMapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
translate: TranslateService,
|
||||
baseModelCtor: ModelConstructor<M>,
|
||||
depsModelCtors?: ModelConstructor<BaseModel>[]
|
||||
) {
|
||||
super(DS, dataSend, collectionStringMapperService, viewModelStoreService, baseModelCtor, depsModelCtors);
|
||||
super(
|
||||
DS,
|
||||
dataSend,
|
||||
collectionStringMapperService,
|
||||
viewModelStoreService,
|
||||
translate,
|
||||
baseModelCtor,
|
||||
depsModelCtors
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
@ -24,17 +25,35 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
protected viewModelSubjects: { [modelId: number]: BehaviorSubject<V> } = {};
|
||||
|
||||
/**
|
||||
* Observable subject for the whole list
|
||||
* Observable subject for the whole list. These entries are unsorted an not piped through
|
||||
* autodTime. Just use this internally.
|
||||
*
|
||||
* It's used to debounce messages on the sortedViewModelListSubject
|
||||
*/
|
||||
protected readonly viewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
|
||||
private readonly viewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
|
||||
|
||||
protected readonly viewModelListAuditSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
|
||||
/**
|
||||
* Observable subject for the sorted view model list.
|
||||
*
|
||||
* All data is piped through an auditTime of 1ms. This is to prevent massive
|
||||
* updates, if e.g. an autoupdate with a lot motions come in. The result is just one
|
||||
* update of the new list instead of many unnecessary updates.
|
||||
*/
|
||||
protected readonly sortedViewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
|
||||
|
||||
/**
|
||||
* Observable subject for any changes of view models.
|
||||
*/
|
||||
protected readonly generalViewModelSubject: Subject<V> = new Subject<V>();
|
||||
|
||||
/**
|
||||
* Can be used by the sort functions.
|
||||
*/
|
||||
protected languageCollator: Intl.Collator;
|
||||
|
||||
/**
|
||||
* The collection string of the managed model.
|
||||
*/
|
||||
private _collectionString: string;
|
||||
|
||||
public get collectionString(): string {
|
||||
@ -65,16 +84,28 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
protected dataSend: DataSendService,
|
||||
protected collectionStringMapperService: CollectionStringMapperService,
|
||||
protected viewModelStoreService: ViewModelStoreService,
|
||||
protected translate: TranslateService,
|
||||
protected baseModelCtor: ModelConstructor<M>,
|
||||
protected depsModelCtors?: ModelConstructor<BaseModel>[]
|
||||
) {
|
||||
this._collectionString = baseModelCtor.COLLECTIONSTRING;
|
||||
|
||||
this.getViewModelListObservable().subscribe(x => this.viewModelListAuditSubject.next(x));
|
||||
// All data is piped through an auditTime of 1ms. This is to prevent massive
|
||||
// updates, if e.g. an autoupdate with a lot motions come in. The result is just one
|
||||
// update of the new list instead of many unnecessary updates.
|
||||
this.viewModelListSubject.pipe(auditTime(1)).subscribe(models => {
|
||||
this.sortedViewModelListSubject.next(models.sort(this.viewModelSortFn));
|
||||
});
|
||||
|
||||
this.languageCollator = new Intl.Collator(this.translate.currentLang);
|
||||
}
|
||||
|
||||
public onAfterAppsLoaded(): void {
|
||||
this.DS.clearObservable.subscribe(() => this.clear());
|
||||
this.translate.onLangChange.subscribe(change => {
|
||||
this.languageCollator = new Intl.Collator(change.lang);
|
||||
this.updateViewModelListObservable();
|
||||
});
|
||||
|
||||
// Populate the local viewModelStore with ViewModel Objects.
|
||||
this.DS.getAll(this.baseModelCtor).forEach((model: M) => {
|
||||
@ -202,6 +233,19 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
*/
|
||||
protected clear(): void {
|
||||
this.viewModelStore = {};
|
||||
}
|
||||
/**
|
||||
* The function used for sorting the data of this repository. The defualt sorts by ID.
|
||||
*/
|
||||
protected viewModelSortFn: (a: V, b: V) => number = (a: V, b: V) => a.id - b.id;
|
||||
|
||||
/**
|
||||
* Setter for a sort function. Updates the sorting.
|
||||
*
|
||||
* @param fn a sort function
|
||||
*/
|
||||
public setSortFunction(fn: (a: V, b: V) => number): void {
|
||||
this.viewModelSortFn = fn;
|
||||
this.updateViewModelListObservable();
|
||||
}
|
||||
|
||||
@ -213,14 +257,24 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to return the viewModel as array
|
||||
* @returns all view models stored in this repository. Sorting is not guaranteed
|
||||
*/
|
||||
public getViewModelList(): V[] {
|
||||
return Object.values(this.viewModelStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current observable for one viewModel
|
||||
* Get a sorted ViewModelList. This passes through a (1ms short) delay,
|
||||
* thus may not be accurate, especially on application loading.
|
||||
*
|
||||
* @returns all sorted view models stored in this repository.
|
||||
*/
|
||||
public getSortedViewModelList(): V[] {
|
||||
return this.sortedViewModelListSubject.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the current observable for one viewModel
|
||||
*/
|
||||
public getViewModelObservable(id: number): Observable<V> {
|
||||
if (!this.viewModelSubjects[id]) {
|
||||
@ -230,14 +284,10 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Observable of the whole store.
|
||||
*
|
||||
* All data is piped through an auditTime of 1ms. This is to prevent massive
|
||||
* updates, if e.g. an autoupdate with a lot motions come in. The result is just one
|
||||
* update of the new list instead of many unnecessary updates.
|
||||
* @returns the (sorted) Observable of the whole store.
|
||||
*/
|
||||
public getViewModelListObservable(): Observable<V[]> {
|
||||
return this.viewModelListSubject.asObservable().pipe(auditTime(1));
|
||||
return this.sortedViewModelListSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -247,7 +297,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
* @returns A subject that holds the model list
|
||||
*/
|
||||
public getViewModelListBehaviorSubject(): BehaviorSubject<V[]> {
|
||||
return this.viewModelListAuditSubject;
|
||||
return this.sortedViewModelListSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,7 +318,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
}
|
||||
|
||||
/**
|
||||
* update the observable of the list
|
||||
* update the observable of the list. Also updates the sorting of the view model list.
|
||||
*/
|
||||
protected updateViewModelListObservable(): void {
|
||||
this.viewModelListSubject.next(this.getViewModelList());
|
||||
|
@ -17,9 +17,9 @@ export class ChatMessageRepositoryService extends BaseRepository<ViewChatMessage
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, ChatMessage);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, ChatMessage);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -100,11 +100,11 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
translate: TranslateService,
|
||||
private constantsService: ConstantsService,
|
||||
private http: HttpService,
|
||||
private translate: TranslateService
|
||||
private http: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Config);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Config);
|
||||
|
||||
this.constantsService.get('OpenSlidesConfigVariables').subscribe(constant => {
|
||||
this.createConfigStructure(constant);
|
||||
|
@ -35,11 +35,11 @@ export class HistoryRepositoryService extends BaseRepository<ViewHistory, Histor
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
translate: TranslateService,
|
||||
private httpService: HttpService,
|
||||
private timeTravel: TimeTravelService,
|
||||
private translate: TranslateService
|
||||
private timeTravel: TimeTravelService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, History, [User]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, History, [User]);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -32,11 +32,12 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
|
||||
DS: DataStoreService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
translate: TranslateService,
|
||||
protected dataSend: DataSendService,
|
||||
private httpService: HttpService,
|
||||
private translate: TranslateService
|
||||
private httpService: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Mediafile, [User]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Mediafile, [User]);
|
||||
this.initSorting();
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
@ -69,4 +70,13 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
|
||||
const emptyHeader = new HttpHeaders();
|
||||
return this.httpService.post<Identifiable>(restPath, file, {}, emptyHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default sorting (e.g. in dropdowns and for new users) to 'title'
|
||||
*/
|
||||
private initSorting(): void {
|
||||
this.setSortFunction((a: ViewMediafile, b: ViewMediafile) => {
|
||||
return this.languageCollator.compare(a.title, b.title);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
@ -13,6 +12,8 @@ import { HttpService } from '../../core-services/http.service';
|
||||
import { ViewCategory } from 'app/site/motions/models/view-category';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
|
||||
type SortProperty = 'prefix' | 'name';
|
||||
|
||||
/**
|
||||
* Repository Services for Categories
|
||||
*
|
||||
@ -27,6 +28,8 @@ import { ViewModelStoreService } from 'app/core/core-services/view-model-store.s
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CategoryRepositoryService extends BaseRepository<ViewCategory, Category> {
|
||||
private sortProperty: SortProperty;
|
||||
|
||||
/**
|
||||
* Creates a CategoryRepository
|
||||
* Converts existing and incoming category to ViewCategories
|
||||
@ -40,15 +43,21 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
|
||||
* @param translate translationService to get the currently selected locale
|
||||
*/
|
||||
public constructor(
|
||||
protected DS: DataStoreService,
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
translate: TranslateService,
|
||||
private httpService: HttpService,
|
||||
private configService: ConfigService,
|
||||
private translate: TranslateService
|
||||
private configService: ConfigService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Category);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Category);
|
||||
|
||||
this.sortProperty = this.configService.instant('motions_category_sorting');
|
||||
this.configService.get<SortProperty>('motions_category_sorting').subscribe(conf => {
|
||||
this.sortProperty = conf;
|
||||
this.setConfigSortFn();
|
||||
});
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
@ -66,8 +75,7 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
|
||||
* @param category_id category ID
|
||||
*/
|
||||
public getCategoryByID(category_id: number): Category {
|
||||
const catList = this.DS.getAll(Category);
|
||||
return catList.find(category => category.id === category_id);
|
||||
return this.DS.find<Category>(Category, cat => cat.id === category_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,36 +89,19 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
|
||||
}
|
||||
|
||||
/**
|
||||
* @ returns the observable for categories sorted according to configuration
|
||||
* Triggers an update for the sort function responsible for the default sorting of data items
|
||||
*/
|
||||
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
|
||||
*
|
||||
* TODO: That operation is HEAVY
|
||||
*/
|
||||
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') {
|
||||
public setConfigSortFn(): void {
|
||||
this.setSortFunction((a: ViewCategory, b: ViewCategory) => {
|
||||
if (a[this.sortProperty] && b[this.sortProperty]) {
|
||||
return this.languageCollator.compare(a[this.sortProperty], b[this.sortProperty]);
|
||||
} else if (this.sortProperty === 'prefix') {
|
||||
if (a.prefix) {
|
||||
return 1;
|
||||
} else if (b.prefix) {
|
||||
return -1;
|
||||
} else {
|
||||
return a.name.localeCompare(b.name);
|
||||
return this.languageCollator.compare(a.name, b.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -45,12 +45,12 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, MotionChangeRecommendation, [
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionChangeRecommendation, [
|
||||
Category,
|
||||
User,
|
||||
Workflow
|
||||
@ -85,7 +85,7 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<
|
||||
* return the Observable of all change recommendations belonging to the given motion
|
||||
*/
|
||||
public getChangeRecosOfMotionObservable(motion_id: number): Observable<ViewMotionChangeRecommendation[]> {
|
||||
return this.viewModelListSubject.asObservable().pipe(
|
||||
return this.getViewModelListObservable().pipe(
|
||||
map((recos: ViewMotionChangeRecommendation[]) => {
|
||||
return recos.filter(reco => reco.motion_id === motion_id);
|
||||
})
|
||||
|
@ -36,14 +36,14 @@ export class MotionBlockRepositoryService extends BaseAgendaContentObjectReposit
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
translate: TranslateService,
|
||||
private motionRepo: MotionRepositoryService,
|
||||
private httpService: HttpService,
|
||||
private translate: TranslateService
|
||||
private httpService: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, MotionBlock, [Item]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionBlock, [Item]);
|
||||
}
|
||||
|
||||
public getAgendaTitle = (motionBlock: Partial<MotionBlock> | Partial<ViewMotionBlock>) => {
|
||||
|
@ -42,13 +42,13 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private http: HttpService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService,
|
||||
private http: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, MotionCommentSection, [Group]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionCommentSection, [Group]);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -7,6 +7,8 @@ import { tap, map } from 'rxjs/operators';
|
||||
import { Category } from 'app/shared/models/motions/category';
|
||||
import { ChangeRecoMode, ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
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 { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { DiffLinesInParagraph, DiffService, LineRange, ModificationType } from '../../ui-services/diff.service';
|
||||
@ -42,6 +44,8 @@ import { PersonalNote, PersonalNoteContent } from 'app/shared/models/users/perso
|
||||
import { ViewPersonalNote } from 'app/site/users/models/view-personal-note';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
|
||||
type SortProperty = 'callListWeight' | 'identifier';
|
||||
|
||||
/**
|
||||
* Repository Services for motions (and potentially categories)
|
||||
*
|
||||
@ -56,6 +60,11 @@ import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionRepositoryService extends BaseAgendaContentObjectRepository<ViewMotion, Motion> {
|
||||
/**
|
||||
* The property the incoming data is sorted by
|
||||
*/
|
||||
protected sortProperty: SortProperty;
|
||||
|
||||
/**
|
||||
* Creates a MotionRepository
|
||||
*
|
||||
@ -68,20 +77,23 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
|
||||
* @param httpService OpenSlides own Http service
|
||||
* @param lineNumbering Line numbering for motion text
|
||||
* @param diff Display changes in motion text as diff.
|
||||
* @param personalNoteService service fo personal notes
|
||||
* @param config ConfigService (subscribe to sorting config)
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
translate: TranslateService,
|
||||
config: ConfigService,
|
||||
private httpService: HttpService,
|
||||
private readonly lineNumbering: LinenumberingService,
|
||||
private readonly diff: DiffService,
|
||||
private treeService: TreeService,
|
||||
private translate: TranslateService,
|
||||
private operator: OperatorService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Motion, [
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Motion, [
|
||||
Category,
|
||||
User,
|
||||
Workflow,
|
||||
@ -92,6 +104,10 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
|
||||
MotionChangeRecommendation,
|
||||
PersonalNote
|
||||
]);
|
||||
config.get<SortProperty>('motions_motions_sorting').subscribe(conf => {
|
||||
this.sortProperty = conf;
|
||||
this.setConfigSortFn();
|
||||
});
|
||||
}
|
||||
|
||||
public getTitle = (motion: Partial<Motion> | Partial<ViewMotion>) => {
|
||||
@ -839,4 +855,30 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an update for the sort function responsible for the default sorting of data items
|
||||
*/
|
||||
public setConfigSortFn(): void {
|
||||
this.setSortFunction((a: ViewMotion, b: ViewMotion) => {
|
||||
if (a[this.sortProperty] && b[this.sortProperty]) {
|
||||
if (a[this.sortProperty] === b[this.sortProperty]) {
|
||||
return this.languageCollator.compare(a.title, b.title);
|
||||
} else {
|
||||
if (this.sortProperty === 'callListWeight') {
|
||||
// handling numerical values
|
||||
return a.callListWeight - b.callListWeight;
|
||||
} else {
|
||||
return this.languageCollator.compare(a[this.sortProperty], b[this.sortProperty]);
|
||||
}
|
||||
}
|
||||
} else if (a[this.sortProperty]) {
|
||||
return -1;
|
||||
} else if (b[this.sortProperty]) {
|
||||
return 1;
|
||||
} else {
|
||||
return this.languageCollator.compare(a.title, b.title);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ export class StatuteParagraphRepositoryService extends BaseRepository<ViewStatut
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, StatuteParagraph);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, StatuteParagraph);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { auditTime } from 'rxjs/operators';
|
||||
|
||||
import { Workflow } from 'app/shared/models/motions/workflow';
|
||||
import { ViewWorkflow } from 'app/site/motions/models/view-workflow';
|
||||
@ -43,14 +42,15 @@ export class WorkflowRepositoryService extends BaseRepository<ViewWorkflow, Work
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private httpService: HttpService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService,
|
||||
private httpService: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Workflow);
|
||||
this.viewModelListSubject.pipe(auditTime(1)).subscribe(models => {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Workflow);
|
||||
|
||||
this.sortedViewModelListSubject.subscribe(models => {
|
||||
if (models && models.length > 0) {
|
||||
this.initSorting(models);
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ import { ServertimeService } from 'app/core/core-services/servertime.service';
|
||||
export class CountdownRepositoryService extends BaseRepository<ViewCountdown, Countdown> {
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService,
|
||||
translate: TranslateService,
|
||||
private servertimeService: ServertimeService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Countdown);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Countdown);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -14,12 +14,12 @@ import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjectorMessage, ProjectorMessage> {
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, ProjectorMessage);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, ProjectorMessage);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -37,13 +37,13 @@ export class ProjectorRepositoryService extends BaseRepository<ViewProjector, Pr
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private http: HttpService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService,
|
||||
private http: HttpService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Projector, [Projector]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Projector, [Projector]);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -34,12 +34,12 @@ export class TagRepositoryService extends BaseRepository<ViewTag, Tag> {
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Tag);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Tag);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -49,13 +49,13 @@ export class GroupRepositoryService extends BaseRepository<ViewGroup, Group> {
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private constants: ConstantsService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService,
|
||||
private constants: ConstantsService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, Group);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Group);
|
||||
this.sortPermsPerApp();
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { PersonalNote } from 'app/shared/models/users/personal-note';
|
||||
import { ViewPersonalNote } from 'app/site/users/models/view-personal-note';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -24,9 +25,9 @@ export class PersonalNoteRepositoryService extends BaseRepository<ViewPersonalNo
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
private translate: TranslateService
|
||||
translate: TranslateService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, PersonalNote);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, PersonalNote);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
@ -22,6 +22,8 @@ import { ViewModelStoreService } from 'app/core/core-services/view-model-store.s
|
||||
*/
|
||||
type StringNamingSchema = 'lastCommaFirst' | 'firstSpaceLast';
|
||||
|
||||
type SortProperty = 'first_name' | 'last_name' | 'number';
|
||||
|
||||
/**
|
||||
* Repository service for users
|
||||
*
|
||||
@ -31,23 +33,36 @@ type StringNamingSchema = 'lastCommaFirst' | 'firstSpaceLast';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
/**
|
||||
* The property the incoming data is sorted by
|
||||
*/
|
||||
protected sortProperty: SortProperty;
|
||||
|
||||
/**
|
||||
* Constructor for the user repo
|
||||
*
|
||||
* @param DS The DataStore
|
||||
* @param mapperService Maps collection strings to classes
|
||||
* @param dataSend sending changed objects
|
||||
* @param translate
|
||||
* @param httpService
|
||||
* @param configService
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
dataSend: DataSendService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
protected dataSend: DataSendService,
|
||||
private translate: TranslateService,
|
||||
translate: TranslateService,
|
||||
private httpService: HttpService,
|
||||
private configService: ConfigService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, User, [Group]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, User, [Group]);
|
||||
this.sortProperty = this.configService.instant('users_sort_by');
|
||||
this.configService.get<SortProperty>('users_sort_by').subscribe(conf => {
|
||||
this.sortProperty = conf;
|
||||
this.setConfigSortFn();
|
||||
});
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
@ -219,7 +234,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
* Searches and returns Users by full name
|
||||
*
|
||||
* @param name
|
||||
* @returns all users matching that name
|
||||
* @returns all users matching that name (unsorted)
|
||||
*/
|
||||
public getUsersByName(name: string): ViewUser[] {
|
||||
return this.getViewModelList().filter(user => {
|
||||
@ -301,43 +316,22 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the observable for users sorted according to configuration
|
||||
*
|
||||
* TODO: This is leading to heavy operations
|
||||
* Triggers an update for the sort function responsible for the default sorting of data items
|
||||
*/
|
||||
public getSortedViewModelListObservable(): Observable<ViewUser[]> {
|
||||
const subject = new BehaviorSubject<ViewUser[]>([]);
|
||||
this.getViewModelListObservable().subscribe(users => {
|
||||
subject.next(this.sortViewUsersByConfig(users));
|
||||
});
|
||||
return subject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort viewUsers by the configured settings
|
||||
*
|
||||
* @param users
|
||||
* @returns the users sorted by first name, last name or number, according
|
||||
* to the config setting. Fallthrough and identical cases will be sorted by
|
||||
* 'short_name'
|
||||
*
|
||||
* TODO: That operation is HEAVY
|
||||
*/
|
||||
public sortViewUsersByConfig(users: ViewUser[]): ViewUser[] {
|
||||
const sort = this.configService.instant<'first_name' | 'last_name' | 'number'>('users_sort_by') || 'last_name';
|
||||
return users.sort((a, b) => {
|
||||
if (a[sort] && b[sort]) {
|
||||
if (a[sort] === b[sort]) {
|
||||
return a.short_name.localeCompare(b.short_name, this.translate.currentLang);
|
||||
public setConfigSortFn(): void {
|
||||
this.setSortFunction((a: ViewUser, b: ViewUser) => {
|
||||
if (a[this.sortProperty] && b[this.sortProperty]) {
|
||||
if (a[this.sortProperty] === b[this.sortProperty]) {
|
||||
return this.languageCollator.compare(a.short_name, b.short_name);
|
||||
} else {
|
||||
return a[sort].localeCompare(b[sort], this.translate.currentLang);
|
||||
return this.languageCollator.compare(a[this.sortProperty], b[this.sortProperty]);
|
||||
}
|
||||
} else if (a[sort] && !b[sort]) {
|
||||
} else if (a[this.sortProperty] && !b[this.sortProperty]) {
|
||||
return -1;
|
||||
} else if (b[sort]) {
|
||||
} else if (b[this.sortProperty]) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.short_name.localeCompare(b.short_name);
|
||||
return this.languageCollator.compare(a.short_name, b.short_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ export abstract class BaseFilterListService<M extends BaseModel, V extends BaseV
|
||||
public filter(): Observable<V[]> {
|
||||
this.repo
|
||||
.getViewModelListObservable()
|
||||
.pipe(auditTime(100))
|
||||
.pipe(auditTime(10))
|
||||
.subscribe(data => {
|
||||
this.currentRawData = data;
|
||||
this.filteredData = this.filterData(data);
|
||||
|
@ -50,6 +50,11 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
*/
|
||||
private sortFn: (a: V, b: V) => number;
|
||||
|
||||
/**
|
||||
* default sorting to use if the client was not initialized before
|
||||
*/
|
||||
protected defaultSorting: keyof V = 'id';
|
||||
|
||||
/**
|
||||
* Constructor. Does nothing. TranslateService is used for localeCompeare.
|
||||
*/
|
||||
@ -113,7 +118,7 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
* get the property of the viewModel the sorting is based on.
|
||||
*/
|
||||
public get sortProperty(): string {
|
||||
return this.sortOptions.sortProperty as string;
|
||||
return this.sortOptions ? (this.sortOptions.sortProperty as string) : '';
|
||||
}
|
||||
|
||||
public get isActive(): boolean {
|
||||
@ -138,7 +143,7 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
* @param option
|
||||
*/
|
||||
public getSortIcon(option: OsSortingItem<V>): string {
|
||||
if (this.sortProperty !== (option.property as string)) {
|
||||
if (!this.sortProperty || this.sortProperty !== (option.property as string)) {
|
||||
return '';
|
||||
}
|
||||
return this.ascending ? 'arrow_downward' : 'arrow_upward';
|
||||
@ -156,20 +161,21 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
* Retrieve the currently saved sorting definition from the borwser's
|
||||
* store
|
||||
*/
|
||||
private loadStorageDefinition(): void {
|
||||
const me = this;
|
||||
this.store.get('sorting_' + this.name).then(function(sorting: OsSortingDefinition<V> | null): void {
|
||||
if (sorting) {
|
||||
if (sorting.sortProperty) {
|
||||
me.sortOptions.sortProperty = sorting.sortProperty;
|
||||
if (sorting.sortAscending !== undefined) {
|
||||
me.sortOptions.sortAscending = sorting.sortAscending;
|
||||
}
|
||||
private async loadStorageDefinition(): Promise<void> {
|
||||
const sorting: OsSortingDefinition<V> | null = await this.store.get('sorting_' + this.name);
|
||||
if (sorting) {
|
||||
if (sorting.sortProperty) {
|
||||
this.sortOptions.sortProperty = sorting.sortProperty;
|
||||
if (sorting.sortAscending !== undefined) {
|
||||
this.sortOptions.sortAscending = sorting.sortAscending;
|
||||
}
|
||||
}
|
||||
me.updateSortFn();
|
||||
me.doAsyncSorting();
|
||||
});
|
||||
} else {
|
||||
this.sortOptions.sortProperty = this.defaultSorting;
|
||||
this.sortOptions.sortAscending = true;
|
||||
}
|
||||
this.updateSortFn();
|
||||
this.doAsyncSorting();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,10 +203,10 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
* Recreates the sorting function. Is supposed to be called on init and
|
||||
* every time the sorting (property, ascending/descending) or the language changes
|
||||
*/
|
||||
private updateSortFn(): void {
|
||||
protected updateSortFn(): void {
|
||||
const property = this.sortProperty as string;
|
||||
const ascending = this.ascending;
|
||||
const lang = this.translate.currentLang; // TODO: observe and update sorting on change
|
||||
const intl = new Intl.Collator(this.translate.currentLang); // TODO: observe and update sorting on language change
|
||||
|
||||
this.sortFn = function(itemA: V, itemB: V): number {
|
||||
const firstProperty = ascending ? itemA[property] : itemB[property];
|
||||
@ -234,16 +240,16 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
if (!firstProperty) {
|
||||
return 1;
|
||||
}
|
||||
return firstProperty.localeCompare(secondProperty, lang);
|
||||
return intl.compare(firstProperty, secondProperty);
|
||||
case 'function':
|
||||
const a = firstProperty();
|
||||
const b = secondProperty();
|
||||
return a.localeCompare(b, lang);
|
||||
return intl.compare(a, b);
|
||||
case 'object':
|
||||
if (firstProperty instanceof Date) {
|
||||
return firstProperty > secondProperty ? 1 : -1;
|
||||
} else {
|
||||
return firstProperty.toString().localeCompare(secondProperty.toString(), lang);
|
||||
return intl.compare(firstProperty.toString(), secondProperty.toString());
|
||||
}
|
||||
case 'undefined':
|
||||
return 1;
|
||||
|
@ -140,7 +140,7 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
this.addSpeakerForm = new FormGroup({ user_id: new FormControl([]) });
|
||||
|
||||
if (this.currentListOfSpeakers) {
|
||||
this.projectors = projectorRepo.getViewModelList();
|
||||
this.projectors = projectorRepo.getSortedViewModelList();
|
||||
this.updateClosProjector();
|
||||
projectorRepo.getViewModelListObservable().subscribe(newProjectors => {
|
||||
this.projectors = newProjectors;
|
||||
@ -160,11 +160,6 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
|
||||
public ngOnInit(): void {
|
||||
// load and observe users
|
||||
this.users = this.userRepository.getViewModelListBehaviorSubject();
|
||||
this.userRepository.getViewModelListBehaviorSubject().subscribe(newUsers => {
|
||||
if (this.viewItem) {
|
||||
this.setSpeakerList(this.viewItem.id);
|
||||
}
|
||||
});
|
||||
|
||||
// detect changes in the form
|
||||
this.addSpeakerForm.valueChanges.subscribe(formResult => {
|
||||
|
@ -13,13 +13,13 @@ export class ViewItem extends BaseViewModel {
|
||||
/**
|
||||
* virtual weight defined by the order in the agenda tree, representing a shortcut to sorting by
|
||||
* weight, parent_id and the parents' weight(s)
|
||||
* TODO will be accurate if the viewMotion is observed via {@link getViewModelListObservable}, else, it will be undefined
|
||||
* TODO will be accurate if the viewMotion is observed via {@link getSortedViewModelListObservable}, else, it will be undefined
|
||||
*/
|
||||
public agendaListWeight: number;
|
||||
|
||||
/**
|
||||
* The amount of parents in the agenda list tree.
|
||||
* TODO will be accurate if the viewMotion is observed via {@link getViewModelListObservable}, else, it will be undefined
|
||||
* TODO will be accurate if the viewMotion is observed via {@link getSortedViewModelListObservable}, else, it will be undefined
|
||||
*/
|
||||
public agendaListLevel: number;
|
||||
|
||||
@ -39,6 +39,10 @@ export class ViewItem extends BaseViewModel {
|
||||
return this.item.item_number;
|
||||
}
|
||||
|
||||
public get title_information(): object {
|
||||
return this.item.title_information;
|
||||
}
|
||||
|
||||
public get duration(): number {
|
||||
return this.item.duration;
|
||||
}
|
||||
|
@ -98,9 +98,13 @@ export abstract class ListViewBaseComponent<V extends BaseViewModel, M extends B
|
||||
* Standard filtering function. Sufficient for most list views but can be overwritten
|
||||
*/
|
||||
protected onFilter(): void {
|
||||
this.subscriptions.push(
|
||||
this.filterService.filter().subscribe(filteredData => (this.sortService.data = filteredData))
|
||||
);
|
||||
if (this.sortService) {
|
||||
this.subscriptions.push(
|
||||
this.filterService.filter().subscribe(filteredData => (this.sortService.data = filteredData))
|
||||
);
|
||||
} else {
|
||||
this.filterService.filter().subscribe(filteredData => (this.dataSource.data = filteredData));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +101,7 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Category');
|
||||
this.repo.getSortedViewModelListObservable().subscribe(newViewCategories => {
|
||||
this.repo.getViewModelListObservable().subscribe(newViewCategories => {
|
||||
this.categories = newViewCategories;
|
||||
});
|
||||
}
|
||||
@ -187,21 +187,7 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
* @returns all motions in the category
|
||||
*/
|
||||
public motionsInCategory(category: Category): ViewMotion[] {
|
||||
const coll = new Intl.Collator(this.translate.currentLang);
|
||||
return this.motionRepo
|
||||
.getViewModelList()
|
||||
.filter(m => m.category_id === category.id)
|
||||
.sort((motion1, motion2) => {
|
||||
if (motion1.identifier && motion2.identifier) {
|
||||
return coll.compare(motion1.identifier, motion2.identifier);
|
||||
} else if (motion1.identifier) {
|
||||
return 1;
|
||||
} else if (motion2.identifier) {
|
||||
return -1;
|
||||
} else {
|
||||
return coll.compare(motion1.getTitle(), motion2.getTitle());
|
||||
}
|
||||
});
|
||||
return this.motionRepo.getSortedViewModelList().filter(m => m.category_id === category.id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,6 @@ export class MotionBlockListComponent extends ListViewBaseComponent<ViewMotionBl
|
||||
|
||||
this.items = this.itemRepo.getViewModelListBehaviorSubject();
|
||||
|
||||
// TODO: Should fall under generic sorting in PR 4411
|
||||
this.repo.getViewModelListObservable().subscribe(newMotionblocks => {
|
||||
newMotionblocks.sort((a, b) => (a > b ? 1 : -1));
|
||||
this.dataSource.data = newMotionblocks;
|
||||
|
@ -18,6 +18,7 @@ import { itemVisibilityChoices } from 'app/shared/models/agenda/item';
|
||||
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
||||
import { LocalPermissionsService } from 'app/site/motions/services/local-permissions.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { Motion } from 'app/shared/models/motions/motion';
|
||||
import {
|
||||
MotionChangeRecommendationComponentData,
|
||||
@ -49,7 +50,6 @@ import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-parag
|
||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
|
||||
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
|
||||
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
|
||||
@ -368,6 +368,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
* @param agendaRepo Read out agenda variables
|
||||
* @param changeRecoRepo Change Recommendation Repository
|
||||
* @param statuteRepo: Statute Paragraph Repository
|
||||
* @param mediafileRepo Mediafile Repository
|
||||
* @param DS The DataStoreService
|
||||
* @param configService The configuration provider
|
||||
* @param sanitizer For making HTML SafeHTML
|
||||
@ -863,7 +864,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
const content = this.motion.getTitle();
|
||||
if (await this.promptService.open(title, content)) {
|
||||
await this.repo.delete(this.motion);
|
||||
this.router.navigate(['./motions/']);
|
||||
this.router.navigate(['../motions/']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1112,18 +1113,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
* then appending motion without identifiers sorted by title
|
||||
*/
|
||||
public setSurroundingMotions(): void {
|
||||
// TODO: that operation is HEAVY
|
||||
this.motionObserver.value.sort((a, b) => {
|
||||
if (a.identifier && b.identifier) {
|
||||
return a.identifier.localeCompare(b.identifier, this.translate.currentLang);
|
||||
} else if (a.identifier) {
|
||||
return 1;
|
||||
} else if (b.identifier) {
|
||||
return -1;
|
||||
} else {
|
||||
return a.title.localeCompare(b.title, this.translate.currentLang);
|
||||
}
|
||||
});
|
||||
const indexOfCurrent = this.motionObserver.value.findIndex(motion => {
|
||||
return motion === this.motion;
|
||||
});
|
||||
|
@ -61,7 +61,7 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
* @returns a list of availavble commentSections
|
||||
*/
|
||||
public get commentsToExport(): ViewMotionCommentSection[] {
|
||||
return this.commentRepo.getViewModelList();
|
||||
return this.commentRepo.getSortedViewModelList();
|
||||
}
|
||||
/**
|
||||
* Hold the default lnMode. Will be set by the constructor.
|
||||
|
@ -128,7 +128,7 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motio
|
||||
.get<string>('motions_recommendations_by')
|
||||
.subscribe(recommender => (this.recomendationEnabled = !!recommender));
|
||||
this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => (this.motionBlocks = mBs));
|
||||
this.categoryRepo.getSortedViewModelListObservable().subscribe(cats => (this.categories = cats));
|
||||
this.categoryRepo.getViewModelListObservable().subscribe(cats => (this.categories = cats));
|
||||
this.tagRepo.getViewModelListObservable().subscribe(tags => (this.tags = tags));
|
||||
this.workflowRepo.getViewModelListObservable().subscribe(wfs => (this.workflows = wfs));
|
||||
this.setFulltextFilter();
|
||||
|
@ -182,7 +182,7 @@ export class MotionFilterListService extends BaseFilterListService<Motion, ViewM
|
||||
* Subscibes to changing Categories, and updates the filter accordingly
|
||||
*/
|
||||
private subscribeCategories(): void {
|
||||
this.categoryRepo.getSortedViewModelListObservable().subscribe(categories => {
|
||||
this.categoryRepo.getViewModelListObservable().subscribe(categories => {
|
||||
const categoryOptions: OsFilterOptions = categories.map(cat => ({
|
||||
condition: cat.id,
|
||||
label: cat.prefixedName,
|
||||
|
@ -74,7 +74,7 @@ export class MotionMultiselectService {
|
||||
*/
|
||||
public async moveToItem(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will move all selected motions as childs to:');
|
||||
const choices: (Displayable & Identifiable)[] = this.agendaRepo.getViewModelList();
|
||||
const choices: (Displayable & Identifiable)[] = this.agendaRepo.getSortedViewModelList();
|
||||
const selectedChoice = await this.choiceService.open(title, choices);
|
||||
if (selectedChoice) {
|
||||
const requestData = {
|
||||
@ -139,7 +139,7 @@ export class MotionMultiselectService {
|
||||
const clearChoice = this.translate.instant('No category');
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.categoryRepo.sortViewCategoriesByConfig(this.categoryRepo.getViewModelList()),
|
||||
this.categoryRepo.getSortedViewModelList(),
|
||||
false,
|
||||
null,
|
||||
clearChoice
|
||||
@ -164,7 +164,12 @@ export class MotionMultiselectService {
|
||||
'This will add or remove the following submitters for all selected motions:'
|
||||
);
|
||||
const choices = [this.translate.instant('Add'), this.translate.instant('Remove')];
|
||||
const selectedChoice = await this.choiceService.open(title, this.userRepo.getViewModelList(), true, choices);
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.userRepo.getSortedViewModelList(),
|
||||
true,
|
||||
choices
|
||||
);
|
||||
if (selectedChoice && selectedChoice.action === choices[0]) {
|
||||
const requestData = motions.map(motion => {
|
||||
let submitterIds = [...motion.sorted_submitters_id, ...(selectedChoice.items as number[])];
|
||||
@ -200,7 +205,12 @@ export class MotionMultiselectService {
|
||||
this.translate.instant('Remove'),
|
||||
this.translate.instant('Clear tags')
|
||||
];
|
||||
const selectedChoice = await this.choiceService.open(title, this.tagRepo.getViewModelList(), true, choices);
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.tagRepo.getSortedViewModelList(),
|
||||
true,
|
||||
choices
|
||||
);
|
||||
if (selectedChoice && selectedChoice.action === choices[0]) {
|
||||
const requestData = motions.map(motion => {
|
||||
let tagIds = [...motion.tags_id, ...(selectedChoice.items as number[])];
|
||||
@ -242,7 +252,7 @@ export class MotionMultiselectService {
|
||||
const clearChoice = this.translate.instant('Clear motion block');
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.motionBlockRepo.getViewModelList(),
|
||||
this.motionBlockRepo.getSortedViewModelList(),
|
||||
false,
|
||||
null,
|
||||
clearChoice
|
||||
@ -280,7 +290,7 @@ export class MotionMultiselectService {
|
||||
// insert after chosen
|
||||
const olderSibling = this.repo.getViewModel(selectedChoice.items as number);
|
||||
const parentId = olderSibling ? olderSibling.sort_parent_id : null;
|
||||
const siblings = this.repo.getViewModelList().filter(motion => motion.sort_parent_id === parentId);
|
||||
const siblings = allMotions.filter(motion => motion.sort_parent_id === parentId);
|
||||
const idx = siblings.findIndex(sib => sib.id === olderSibling.id);
|
||||
const before = siblings.slice(0, idx + 1);
|
||||
const after = siblings.slice(idx + 1);
|
||||
|
@ -48,7 +48,7 @@ export class MotionPdfService {
|
||||
*
|
||||
* @param translate handle translations
|
||||
* @param motionRepo get parent motions
|
||||
* @param statureRepo To get formated stature paragraphs
|
||||
* @param statuteRepo To get formated stature paragraphs
|
||||
* @param changeRecoRepo to get the change recommendations
|
||||
* @param configService Read config variables
|
||||
* @param htmlToPdfService To convert HTML text into pdfmake doc def
|
||||
@ -59,7 +59,7 @@ export class MotionPdfService {
|
||||
public constructor(
|
||||
private translate: TranslateService,
|
||||
private motionRepo: MotionRepositoryService,
|
||||
private statureRepo: StatuteParagraphRepositoryService,
|
||||
private statuteRepo: StatuteParagraphRepositoryService,
|
||||
private changeRecoRepo: ChangeRecommendationRepositoryService,
|
||||
private configService: ConfigService,
|
||||
private htmlToPdfService: HtmlToPdfService,
|
||||
@ -123,7 +123,7 @@ export class MotionPdfService {
|
||||
}
|
||||
|
||||
if (infoToExport && infoToExport.includes('allcomments')) {
|
||||
commentsToExport = this.commentRepo.getViewModelList().map(vm => vm.id);
|
||||
commentsToExport = this.commentRepo.getSortedViewModelList().map(vm => vm.id);
|
||||
}
|
||||
if (commentsToExport) {
|
||||
motionPdfContent.push(this.createComments(motion, commentsToExport));
|
||||
@ -495,7 +495,7 @@ export class MotionPdfService {
|
||||
}
|
||||
} else if (motion.isStatuteAmendment()) {
|
||||
// statute amendments
|
||||
const statutes = this.statureRepo.getViewModelList();
|
||||
const statutes = this.statuteRepo.getViewModelList();
|
||||
motionText = this.motionRepo.formatStatuteAmendment(statutes, motion, lineLength);
|
||||
} else {
|
||||
// lead motion or normal amendments
|
||||
|
@ -37,6 +37,6 @@ export class MotionSortListService extends BaseSortListService<ViewMotion> {
|
||||
*/
|
||||
public constructor(translate: TranslateService, store: StorageService, config: ConfigService) {
|
||||
super(translate, store);
|
||||
this.sortOptions.sortProperty = config.instant<keyof ViewMotion>('motions_motions_sorting');
|
||||
this.defaultSorting = config.instant<keyof ViewMotion>('motions_motions_sorting');
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
Reference projector for current list of speakers:
|
||||
</span>
|
||||
<mat-form-field>
|
||||
<mat-select [disabled]="!!editId" [value]="projectors[0].reference_projector_id" (selectionChange)="onSelectReferenceProjector($event)">
|
||||
<mat-select [disabled]="!!editId" [value]="projectors.length ? projectors[0].reference_projector_id : null" (selectionChange)="onSelectReferenceProjector($event)">
|
||||
<mat-option *ngFor="let projector of projectors" [value]="projector.id">
|
||||
{{ projector.getTitle() | translate }}
|
||||
</mat-option>
|
||||
|
@ -120,6 +120,7 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Projectors');
|
||||
this.projectors = this.repo.getViewModelList();
|
||||
this.repo.getViewModelListObservable().subscribe(projectors => (this.projectors = projectors));
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export class ProjectorMessageListComponent extends BaseViewComponent implements
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Messages');
|
||||
this.messages = this.repo.getViewModelList();
|
||||
this.messages = this.repo.getSortedViewModelList();
|
||||
this.repo.getViewModelListObservable().subscribe(messages => (this.messages = messages));
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
this.createForm();
|
||||
|
||||
this.groups = this.groupRepo.getViewModelList().filter(group => group.id !== 1);
|
||||
this.groups = this.groupRepo.getSortedViewModelList().filter(group => group.id !== 1);
|
||||
this.groupRepo
|
||||
.getViewModelListObservable()
|
||||
.subscribe(groups => (this.groups = groups.filter(group => group.id !== 1)));
|
||||
|
@ -167,7 +167,8 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser, User> imp
|
||||
this.setFulltextFilter();
|
||||
|
||||
// Initialize the groups
|
||||
this.groups = this.groupRepo.getViewModelList().filter(group => group.id !== 1);
|
||||
this.groups = this.groupRepo.getSortedViewModelList().filter(group => group.id !== 1);
|
||||
this.groupRepo.getViewModelListObservable().subscribe(groups => (this.groups = groups));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,6 @@ export class UserSortListService extends BaseSortListService<ViewUser> {
|
||||
*/
|
||||
public constructor(translate: TranslateService, store: StorageService, config: ConfigService) {
|
||||
super(translate, store);
|
||||
this.sortOptions.sortProperty = config.instant<keyof ViewUser>('motions_motions_sorting');
|
||||
this.defaultSorting = config.instant<keyof ViewUser>('users_sort_by');
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user