Merge pull request #4974 from tsiegleauq/amendment-sort-by-line

Add sort service for amendments
This commit is contained in:
Emanuel Schütze 2019-09-05 14:14:11 +02:00 committed by GitHub
commit 5c83eb824a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 245 additions and 87 deletions

View File

@ -82,12 +82,18 @@ export class RelationManagerService {
);
viewModel['_' + relation.ownKey] = foreignViewModels;
this.sortByRelation(relation, viewModel);
if (relation.afterSetRelation) {
relation.afterSetRelation(viewModel, foreignViewModels);
}
} else if (relation.type === 'M2O') {
const foreignViewModel = this.viewModelStoreService.get(
relation.foreignViewModel,
model[relation.ownIdKey]
);
viewModel['_' + relation.ownKey] = foreignViewModel;
if (relation.afterSetRelation) {
relation.afterSetRelation(viewModel, foreignViewModel);
}
}
} else if (isReverseRelationDefinition(relation) && !initialLoading) {
if (relation.type === 'M2M') {
@ -203,12 +209,19 @@ export class RelationManagerService {
) {
const foreignViewModel = <any>this.viewModelStoreService.get(collection, changedId);
this.setForeingViewModelInOwnViewModelArray(foreignViewModel, ownViewModel, relation.ownKey);
if (relation.afterDependencyChange) {
relation.afterDependencyChange(ownViewModel, foreignViewModel);
}
return true;
}
} else if (relation.type === 'M2O') {
if (ownViewModel[relation.ownIdKey] === <any>changedId) {
// Check, if this is the matching foreign view model.
ownViewModel['_' + relation.ownKey] = <any>this.viewModelStoreService.get(collection, changedId);
const foreignViewModel = this.viewModelStoreService.get(collection, changedId);
ownViewModel['_' + relation.ownKey] = <any>foreignViewModel;
if (relation.afterDependencyChange) {
relation.afterDependencyChange(ownViewModel, foreignViewModel);
}
return true;
}
}

View File

@ -39,6 +39,8 @@ interface BaseNormalRelationDefinition<VForeign extends BaseViewModel> extends B
* the model and view model. E.g. `category_id` in a motion.
*/
ownIdKey: string;
afterDependencyChange?: (ownViewModel: BaseViewModel, foreignViewModel: BaseViewModel) => void;
}
/**
@ -56,16 +58,19 @@ interface NormalM2MRelationDefinition<VForeign extends BaseViewModel>
extends BaseNormalRelationDefinition<VForeign>,
BaseOrderedRelation<VForeign> {
type: 'M2M';
afterSetRelation?: (ownViewModel: BaseViewModel, foreignViewModels: BaseViewModel[]) => void;
}
interface NormalO2MRelationDefinition<VForeign extends BaseViewModel>
extends BaseNormalRelationDefinition<VForeign>,
BaseOrderedRelation<VForeign> {
type: 'O2M';
afterSetRelation?: (ownViewModel: BaseViewModel, foreignViewModels: BaseViewModel[]) => void;
}
interface NormalM2ORelationDefinition<VForeign extends BaseViewModel> extends BaseNormalRelationDefinition<VForeign> {
type: 'M2O';
afterSetRelation?: (ownViewModel: BaseViewModel, foreignViewModel: BaseViewModel | null) => void;
}
export type NormalRelationDefinition<VForeign extends BaseViewModel = BaseViewModel> =

View File

@ -133,12 +133,6 @@ const MotionRelations: RelationDefinition[] = [
ownKey: 'tags',
foreignViewModel: ViewTag
},
{
type: 'M2O',
ownIdKey: 'parent_id',
ownKey: 'parent',
foreignViewModel: ViewMotion
},
{
type: 'M2M',
ownIdKey: 'change_recommendations_id',
@ -171,6 +165,11 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
*/
protected sortProperty: SortProperty;
/**
* Line length of a motion
*/
private motionLineLength: number;
/**
* Creates a MotionRepository
*
@ -206,10 +205,15 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
this.sortProperty = conf;
this.setConfigSortFn();
});
config.get<number>('motions_line_length').subscribe(lineLength => {
this.motionLineLength = lineLength;
});
}
/**
* Adds the personal note custom relation to the relation definitions.
* Also adds the parent relation here to get access to methods in this repo.
*/
protected groupRelationsByCollections(): void {
this.relationDefinitions.push({
@ -228,6 +232,22 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return true;
}
});
this.relationDefinitions.push({
type: 'M2O',
ownIdKey: 'parent_id',
ownKey: 'parent',
foreignViewModel: ViewMotion,
afterSetRelation: (motion: ViewMotion, foreignViewModel: ViewMotion | null) => {
if (foreignViewModel) {
motion.diffLines = this.getAmendmentParagraphs(motion, this.motionLineLength, false);
}
},
afterDependencyChange: (motion: ViewMotion, parent: ViewMotion) => {
if (motion.parent) {
motion.diffLines = this.getAmendmentParagraphs(motion, this.motionLineLength, false);
}
}
});
super.groupRelationsByCollections();
}
@ -284,8 +304,10 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
protected createViewModelWithTitles(model: Motion, initialLoading: boolean): ViewMotion {
const viewModel = super.createViewModelWithTitles(model, initialLoading);
viewModel.getIdentifierOrTitle = () => this.getIdentifierOrTitle(viewModel);
viewModel.getProjectorTitle = () => this.getAgendaSlideTitle(viewModel);
return viewModel;
}
@ -639,16 +661,6 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return range.to;
}
/**
* Given an amendment, this returns the motion affected by this amendments
*
* @param {ViewMotion} amendment
* @returns {ViewMotion}
*/
public getAmendmentBaseMotion(amendment: ViewMotion): ViewMotion {
return this.getViewModel(amendment.parent_id);
}
/**
* Splits a motion into paragraphs, optionally adding line numbers
*
@ -700,7 +712,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
lineLength: number,
includeUnchanged: boolean
): DiffLinesInParagraph[] {
const motion = this.getAmendmentBaseMotion(amendment);
const motion = amendment.parent;
const baseParagraphs = this.getTextParagraphs(motion, true, lineLength);
return amendment.amendment_paragraphs
@ -744,7 +756,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
* @returns {ViewMotionAmendedParagraph[]}
*/
public getAmendmentAmendedParagraphs(amendment: ViewMotion, lineLength: number): ViewMotionAmendedParagraph[] {
const motion = this.getAmendmentBaseMotion(amendment);
const motion = amendment.parent;
const baseParagraphs = this.getTextParagraphs(motion, true, lineLength);
return amendment.amendment_paragraphs

View File

@ -243,8 +243,6 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
if (storedFilter && storedFilter.length && newDefinitions && newDefinitions.length) {
for (const newDef of newDefinitions) {
console.log('set filter');
// for some weird angular bugs, newDef can actually be undefined
if (newDef) {
let count = 0;

View File

@ -55,6 +55,11 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
*/
private sortDefinition: OsSortingDefinition<V>;
/**
* The key to access stored valued
*/
protected abstract readonly storageKey: string;
/**
* The sorting function according to current settings.
*/
@ -105,13 +110,15 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
* @returns wether sorting is active or not
*/
public get isActive(): boolean {
return this.sortDefinition && this.sortOptions.length > 0;
return this.sortOptions && this.sortOptions.length > 0;
}
/**
* Enforce children to implement sortOptions
*/
public abstract sortOptions: OsSortingOption<V>[];
public get sortOptions(): OsSortingOption<V>[] {
const sortOptions = this.getSortOptions();
if (sortOptions && sortOptions.length) {
return sortOptions;
}
}
/**
* Constructor.
@ -121,12 +128,16 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
* @param store to save and load sorting preferences
*/
public constructor(
protected name: string,
protected translate: TranslateService,
private store: StorageService,
private OSStatus: OpenSlidesStatusService
) {}
/**
* Enforce children to implement a function that returns their sorting options
*/
protected abstract getSortOptions(): OsSortingOption<V>[];
/**
* Enforce children to implement a method that returns the fault sorting
*/
@ -148,7 +159,7 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
if (this.OSStatus.isInHistoryMode) {
this.sortDefinition = null;
} else {
this.sortDefinition = await this.store.get<OsSortingDefinition<V> | null>('sorting_' + this.name);
this.sortDefinition = await this.store.get<OsSortingDefinition<V> | null>('sorting_' + this.storageKey);
}
if (this.sortDefinition && this.sortDefinition.sortProperty) {
@ -183,11 +194,15 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
* @param option
* @returns the name of the sorting icon, fit to material icon ligatures
*/
public getSortIcon(option: OsSortingOption<V>): string {
if (this.sortProperty !== option.property) {
return '';
public getSortIcon(option: OsSortingOption<V>): string | null {
if (this.sortDefinition) {
if (this.sortProperty && this.sortProperty !== option.property) {
return '';
}
return this.ascending ? 'arrow_upward' : 'arrow_downward';
} else {
return null;
}
return this.ascending ? 'arrow_upward' : 'arrow_downward';
}
/**
@ -210,7 +225,7 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
private updateSortDefinitions(): void {
this.updateSortedData();
if (!this.OSStatus.isInHistoryMode) {
this.store.set('sorting_' + this.name, this.sortDefinition);
this.store.set('sorting_' + this.storageKey, this.sortDefinition);
}
}
@ -227,7 +242,7 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
* every time the sorting (property, ascending/descending) or the language changes
*/
protected updateSortedData(): void {
if (this.inputData) {
if (this.inputData && this.sortDefinition) {
const property = this.sortProperty as string;
const intl = new Intl.Collator(this.translate.currentLang, {

View File

@ -208,8 +208,9 @@ export class SortFilterBarComponent<V extends BaseViewModel> {
* Retrieves the currently active icon for an option.
* @param option
*/
public getSortIcon(option: OsSortingOption<V>): string {
return this.sortService.getSortIcon(option);
public getSortIcon(option: OsSortingOption<V>): string | null {
const icon = this.sortService.getSortIcon(option);
return icon ? icon : null;
}
/**

View File

@ -14,10 +14,15 @@ import { ViewAssignment } from '../models/view-assignment';
providedIn: 'root'
})
export class AssignmentSortListService extends BaseSortListService<ViewAssignment> {
/**
* set the storage key name
*/
protected storageKey = 'AssignmentList';
/**
* Define the sort options
*/
public sortOptions: OsSortingOption<ViewAssignment>[] = [
private assignmentSortOptions: OsSortingOption<ViewAssignment>[] = [
{ property: 'title', label: 'Name' },
{ property: 'phase', label: 'Phase' },
{ property: 'candidateAmount', label: 'Number of candidates' },
@ -31,7 +36,14 @@ export class AssignmentSortListService extends BaseSortListService<ViewAssignmen
* @param storage required by parent
*/
public constructor(translate: TranslateService, storage: StorageService, OSStatus: OpenSlidesStatusService) {
super('Assignment', translate, storage, OSStatus);
super(translate, storage, OSStatus);
}
/**
* @override
*/
protected getSortOptions(): OsSortingOption<ViewAssignment>[] {
return this.assignmentSortOptions;
}
/**

View File

@ -14,7 +14,12 @@ import { ViewMediafile } from '../models/view-mediafile';
providedIn: 'root'
})
export class MediafilesSortListService extends BaseSortListService<ViewMediafile> {
public sortOptions: OsSortingOption<ViewMediafile>[] = [
/**
* set the storage key name
*/
protected storageKey = 'MediafileList';
private mediafilesSortOptions: OsSortingOption<ViewMediafile>[] = [
{ property: 'title' },
{
property: 'type',
@ -33,7 +38,14 @@ export class MediafilesSortListService extends BaseSortListService<ViewMediafile
* @param store required by parent
*/
public constructor(translate: TranslateService, store: StorageService, OSStatus: OpenSlidesStatusService) {
super('Mediafiles', translate, store, OSStatus);
super(translate, store, OSStatus);
}
/**
* @override
*/
protected getSortOptions(): OsSortingOption<ViewMediafile>[] {
return this.mediafilesSortOptions;
}
/**

View File

@ -1,5 +1,6 @@
import { _ } from 'app/core/translate/translation-marker';
import { ConfigService } from 'app/core/ui-services/config.service';
import { DiffLinesInParagraph } from 'app/core/ui-services/diff.service';
import { SearchProperty, SearchRepresentation } from 'app/core/ui-services/search.service';
import { Motion, MotionComment } from 'app/shared/models/motions/motion';
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
@ -76,6 +77,7 @@ export class ViewMotion extends BaseViewModelWithAgendaItemAndListOfSpeakers<Mot
protected _parent?: ViewMotion;
protected _amendments?: ViewMotion[];
protected _changeRecommendations?: ViewMotionChangeRecommendation[];
protected _diffLines?: DiffLinesInParagraph[];
public personalNote?: PersonalNoteContent;
public get motion(): Motion {
@ -342,6 +344,31 @@ export class ViewMotion extends BaseViewModelWithAgendaItemAndListOfSpeakers<Mot
return this.state ? this.state.css_class : '';
}
/**
* getter to access diff lines
*/
public get diffLines(): DiffLinesInParagraph[] {
if (!this.parent_id) {
throw new Error('No parent No diff');
}
return this._diffLines;
}
public set diffLines(value: DiffLinesInParagraph[]) {
this._diffLines = value;
}
/**
* Get the number of the first diff line, in case a motion is an amendment
*/
public get parentAndLineNumber(): string | null {
if (this.isParagraphBasedAmendment() && this.parent && this.diffLines && this.diffLines.length) {
return `${this.parent.identifier} ${this.diffLines[0].diffLineFrom}`;
} else {
return null;
}
}
// This is set by the repository
public getIdentifierOrTitle: () => string;

View File

@ -18,7 +18,7 @@
<os-list-view-table
[repo]="motionRepo"
[sortService]="motionSortService"
[sortService]="amendmentSortService"
[filterService]="amendmentFilterService"
[columns]="tableColumnDefinition"
[filterProps]="filterProps"
@ -70,6 +70,7 @@
<!-- Summary -->
<div *pblNgridCellDef="'summary'; row as motion" class="cell-slot fill">
<a class="detail-link" [routerLink]="motion.getDetailStateURL()"></a>
<div class="innerTable">
<div class="motion-text" [innerHtml]="sanitizeText(getAmendmentSummary(motion))"></div>
</div>

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatDialog, MatSnackBar } from '@angular/material';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
@ -7,10 +7,9 @@ import { TranslateService } from '@ngx-translate/core';
import { PblColumnDefinition } from '@pebula/ngrid';
import { AmendmentFilterListService } from '../../services/amendment-filter-list.service';
import { AmendmentSortListService } from '../../services/amendment-sort-list.service';
import { StorageService } from 'app/core/core-services/storage.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { DiffLinesInParagraph } from 'app/core/ui-services/diff.service';
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
import { ItemVisibilityChoices } from 'app/shared/models/agenda/item';
import { largeDialogSettings } from 'app/shared/utils/dialog-settings';
@ -27,7 +26,8 @@ import { ViewMotion } from '../../models/view-motion';
selector: 'os-amendment-list',
templateUrl: './amendment-list.component.html',
styleUrls: ['./amendment-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> implements OnInit {
/**
@ -40,11 +40,6 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
*/
public itemVisibility = ItemVisibilityChoices;
/**
* To hold the motions line length
*/
private motionLineLength: number;
/**
* Column defintiion
*/
@ -88,9 +83,9 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
route: ActivatedRoute,
public motionRepo: MotionRepositoryService,
public motionSortService: MotionSortListService,
public amendmentSortService: AmendmentSortListService,
public amendmentFilterService: AmendmentFilterListService,
private sanitizer: DomSanitizer,
private configService: ConfigService,
private dialog: MatDialog,
private motionExport: MotionExportService,
private linenumberingService: LinenumberingService
@ -106,32 +101,7 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
}
}
/**
* Observe the line length
*/
public ngOnInit(): void {
this.configService.get<number>('motions_line_length').subscribe(lineLength => {
this.motionLineLength = lineLength;
});
if (!!this.parentMotionId) {
// this.amendmentFilterService.clearAllFilters();
}
}
/**
* Helper function to get amendment paragraphs of a given motion
*
* @param amendment the get the paragraphs from
* @returns DiffLinesInParagraph-List
*/
private getDiffLines(amendment: ViewMotion): DiffLinesInParagraph[] {
if (amendment.isParagraphBasedAmendment()) {
return this.motionRepo.getAmendmentParagraphs(amendment, this.motionLineLength, false);
} else {
return null;
}
}
public ngOnInit(): void {}
/**
* Extract the lines of the amendments
@ -141,7 +111,7 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
* @return The lines of the amendment
*/
public getChangeLines(amendment: ViewMotion): string {
const diffLines = this.getDiffLines(amendment);
const diffLines = amendment.diffLines;
if (!!diffLines) {
return diffLines
@ -163,7 +133,7 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
* @returns the amendments as string, if they are multiple they gonna be separated by `[...]`
*/
public getAmendmentSummary(amendment: ViewMotion): string {
const diffLines = this.getDiffLines(amendment);
const diffLines = amendment.diffLines;
if (!!diffLines) {
return diffLines
.map(diffLine => {

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { AmendmentSortListService } from './amendment-sort-list.service';
describe('AmendmentSortListService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: AmendmentSortListService = TestBed.get(AmendmentSortListService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,47 @@
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OpenSlidesStatusService } from 'app/core/core-services/openslides-status.service';
import { StorageService } from 'app/core/core-services/storage.service';
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { MotionSortListService } from './motion-sort-list.service';
import { ViewMotion } from '../models/view-motion';
@Injectable({
providedIn: 'root'
})
export class AmendmentSortListService extends MotionSortListService {
/**
* set the storage key name
*/
protected storageKey = 'AmendmentList';
private amendmentSortOptions: OsSortingOption<ViewMotion>[] = [
{
property: 'parentAndLineNumber',
label: 'Main motion and line number'
}
];
public constructor(
translate: TranslateService,
store: StorageService,
OSStatus: OpenSlidesStatusService,
config: ConfigService
) {
super(translate, store, OSStatus, config);
}
protected getSortOptions(): OsSortingOption<ViewMotion>[] {
return this.amendmentSortOptions.concat(super.getSortOptions());
}
protected async getDefaultDefinition(): Promise<OsSortingDefinition<ViewMotion>> {
return {
sortProperty: 'parentAndLineNumber',
sortAscending: true
};
}
}

View File

@ -11,7 +11,12 @@ import { ViewMotionBlock } from '../models/view-motion-block';
providedIn: 'root'
})
export class MotionBlockSortService extends BaseSortListService<ViewMotionBlock> {
public sortOptions: OsSortingOption<ViewMotionBlock>[] = [
/**
* set the storage key name
*/
protected storageKey = 'MotionBlockList';
private MotionBlockSortOptions: OsSortingOption<ViewMotionBlock>[] = [
{ property: 'title' },
{
property: 'motions',
@ -25,7 +30,14 @@ export class MotionBlockSortService extends BaseSortListService<ViewMotionBlock>
];
public constructor(translate: TranslateService, store: StorageService, OSStatus: OpenSlidesStatusService) {
super('Motion block', translate, store, OSStatus);
super(translate, store, OSStatus);
}
/**
* @override
*/
protected getSortOptions(): OsSortingOption<ViewMotionBlock>[] {
return this.MotionBlockSortOptions;
}
protected async getDefaultDefinition(): Promise<OsSortingDefinition<ViewMotionBlock>> {

View File

@ -17,6 +17,11 @@ import { ViewMotion } from '../models/view-motion';
providedIn: 'root'
})
export class MotionSortListService extends BaseSortListService<ViewMotion> {
/**
* set the storage key name
*/
protected storageKey = 'MotionList';
/**
* Hold the default motion sorting
*/
@ -30,7 +35,7 @@ export class MotionSortListService extends BaseSortListService<ViewMotion> {
/**
* Define the sort options
*/
public sortOptions: OsSortingOption<ViewMotion>[] = [
protected motionSortOptions: OsSortingOption<ViewMotion>[] = [
{ property: 'weight', label: 'Call list' },
{ property: 'identifier' },
{ property: 'title' },
@ -53,11 +58,11 @@ export class MotionSortListService extends BaseSortListService<ViewMotion> {
translate: TranslateService,
store: StorageService,
OSStatus: OpenSlidesStatusService,
private config: ConfigService
config: ConfigService
) {
super('Motion', translate, store, OSStatus);
super(translate, store, OSStatus);
this.config.get<string>('motions_motions_sorting').subscribe(defSortProp => {
config.get<string>('motions_motions_sorting').subscribe(defSortProp => {
if (defSortProp) {
this.defaultMotionSorting = defSortProp;
this.defaultSortingLoaded.resolve();
@ -65,6 +70,10 @@ export class MotionSortListService extends BaseSortListService<ViewMotion> {
});
}
protected getSortOptions(): OsSortingOption<ViewMotion>[] {
return this.motionSortOptions;
}
/**
* Required by parent
*

View File

@ -14,10 +14,15 @@ import { ViewUser } from '../models/view-user';
providedIn: 'root'
})
export class UserSortListService extends BaseSortListService<ViewUser> {
/**
* set the storage key name
*/
protected storageKey = 'UserList';
/**
* Define the sort options
*/
public sortOptions: OsSortingOption<ViewUser>[] = [
private userSortOptions: OsSortingOption<ViewUser>[] = [
{ property: 'first_name', label: 'Given name' },
{ property: 'last_name', label: 'Surname' },
{ property: 'is_present', label: 'Presence' },
@ -36,7 +41,14 @@ export class UserSortListService extends BaseSortListService<ViewUser> {
* @param store requires by parent
*/
public constructor(translate: TranslateService, store: StorageService, OSStatus: OpenSlidesStatusService) {
super('User', translate, store, OSStatus);
super(translate, store, OSStatus);
}
/**
* @override
*/
protected getSortOptions(): OsSortingOption<ViewUser>[] {
return this.userSortOptions;
}
/**