Merge pull request #4979 from GabrielInTheWorld/sortingCallList
Implements the possibility to sort trees by a given property
This commit is contained in:
commit
11922c2a12
@ -1,32 +1,15 @@
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { BaseSortService, OsSortingDefinition, OsSortingOption } from './base-sort.service';
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { OpenSlidesStatusService } from '../core-services/openslides-status.service';
|
||||
import { StorageService } from '../core-services/storage.service';
|
||||
|
||||
/**
|
||||
* Describes the sorting columns of an associated ListView, and their state.
|
||||
*/
|
||||
export interface OsSortingDefinition<V> {
|
||||
sortProperty: keyof V;
|
||||
sortAscending: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sorting property (data may be a string, a number, a function, or an object
|
||||
* with a toString method) to sort after. Sorting will be done in {@link filterData}
|
||||
*/
|
||||
export interface OsSortingOption<V> {
|
||||
property: keyof V;
|
||||
label?: string;
|
||||
sortFn?: (itemA: V, itemB: V, ascending: boolean, intl?: Intl.Collator) => number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for generic sorting purposes
|
||||
*/
|
||||
export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
export abstract class BaseSortListService<V extends BaseViewModel> extends BaseSortService<V> {
|
||||
/**
|
||||
* The data to be sorted. See also the setter for {@link data}
|
||||
*/
|
||||
@ -60,11 +43,6 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
*/
|
||||
protected abstract readonly storageKey: string;
|
||||
|
||||
/**
|
||||
* The sorting function according to current settings.
|
||||
*/
|
||||
public sortFn?: (a: V, b: V, ascending: boolean, intl?: Intl.Collator) => number;
|
||||
|
||||
/**
|
||||
* Set the current sorting order
|
||||
*
|
||||
@ -131,7 +109,9 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
protected translate: TranslateService,
|
||||
private store: StorageService,
|
||||
private OSStatus: OpenSlidesStatusService
|
||||
) {}
|
||||
) {
|
||||
super(translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce children to implement a function that returns their sorting options
|
||||
@ -229,79 +209,14 @@ export abstract class BaseSortListService<V extends BaseViewModel> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine false-like values (if they are not boolean)
|
||||
* @param property
|
||||
*/
|
||||
private isFalsy(property: any): boolean {
|
||||
return property === null || property === undefined || property === 0 || property === '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreates the sorting function. Is supposed to be called on init and
|
||||
* every time the sorting (property, ascending/descending) or the language changes
|
||||
*/
|
||||
protected updateSortedData(): void {
|
||||
if (this.inputData && this.sortDefinition) {
|
||||
const property = this.sortProperty as string;
|
||||
|
||||
const intl = new Intl.Collator(this.translate.currentLang, {
|
||||
numeric: true,
|
||||
ignorePunctuation: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
|
||||
if (this.inputData) {
|
||||
this.inputData.sort((itemA, itemB) => {
|
||||
// always sort falsy values to the bottom
|
||||
if (this.isFalsy(itemA[property]) && this.isFalsy(itemB[property])) {
|
||||
return 0;
|
||||
} else if (this.isFalsy(itemA[property])) {
|
||||
return 1;
|
||||
} else if (this.isFalsy(itemB[property])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const firstProperty = this.ascending ? itemA[property] : itemB[property];
|
||||
const secondProperty = this.ascending ? itemB[property] : itemA[property];
|
||||
|
||||
if (this.sortFn) {
|
||||
return this.sortFn(itemA, itemB, this.ascending, intl);
|
||||
} else {
|
||||
switch (typeof firstProperty) {
|
||||
case 'boolean':
|
||||
if (!firstProperty && secondProperty) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
case 'number':
|
||||
return firstProperty > secondProperty ? 1 : -1;
|
||||
case 'string':
|
||||
if (!!firstProperty && !secondProperty) {
|
||||
return -1;
|
||||
} else if (!firstProperty && !!secondProperty) {
|
||||
return 1;
|
||||
} else if ((!secondProperty && !secondProperty) || firstProperty === secondProperty) {
|
||||
return 0;
|
||||
} else {
|
||||
return intl.compare(firstProperty, secondProperty);
|
||||
}
|
||||
case 'function':
|
||||
const a = firstProperty();
|
||||
const b = secondProperty();
|
||||
return intl.compare(a, b);
|
||||
case 'object':
|
||||
if (firstProperty instanceof Date) {
|
||||
return firstProperty > secondProperty ? 1 : -1;
|
||||
} else {
|
||||
return intl.compare(firstProperty.toString(), secondProperty.toString());
|
||||
}
|
||||
case 'undefined':
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return this.sortItems(itemA, itemB, this.sortProperty, this.ascending);
|
||||
});
|
||||
this.outputSubject.next(this.inputData);
|
||||
}
|
||||
|
19
client/src/app/core/ui-services/base-sort.service.spec.ts
Normal file
19
client/src/app/core/ui-services/base-sort.service.spec.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BaseSortService } from './base-sort.service';
|
||||
import { E2EImportsModule } from '../../../e2e-imports.module';
|
||||
|
||||
describe('BaseSortService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [BaseSortService]
|
||||
});
|
||||
});
|
||||
|
||||
// TODO testing (does not work without injecting a BaseViewComponent)
|
||||
// it('should be created', () => {
|
||||
// const service: BaseSortService = TestBed.get(BaseSortService);
|
||||
// expect(service).toBeTruthy();
|
||||
// });
|
||||
});
|
124
client/src/app/core/ui-services/base-sort.service.ts
Normal file
124
client/src/app/core/ui-services/base-sort.service.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { Displayable } from 'app/site/base/displayable';
|
||||
|
||||
export type SortDefinition<T> = keyof T | OsSortingDefinition<T>;
|
||||
|
||||
/**
|
||||
* Describes the sorting columns of an associated ListView, and their state.
|
||||
*/
|
||||
export interface OsSortingDefinition<T> {
|
||||
sortProperty: keyof T;
|
||||
sortAscending: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sorting property (data may be a string, a number, a function, or an object
|
||||
* with a toString method) to sort after. Sorting will be done in {@link filterData}
|
||||
*/
|
||||
export interface OsSortingOption<T> {
|
||||
property: keyof T;
|
||||
label?: string;
|
||||
sortFn?: (itemA: T, itemB: T, ascending: boolean, intl?: Intl.Collator) => number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base sorting service with main functionality for sorting.
|
||||
*
|
||||
* Extends sorting services to sort with a consistent function.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export abstract class BaseSortService<T extends Identifiable & Displayable> {
|
||||
/**
|
||||
* The sorting function according to current settings.
|
||||
*/
|
||||
public sortFn?: (a: T, b: T, ascending: boolean, intl?: Intl.Collator) => number;
|
||||
|
||||
/**
|
||||
* The international localisation.
|
||||
*/
|
||||
protected intl: Intl.Collator;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Pass the `TranslatorService`.
|
||||
*/
|
||||
public constructor(protected translate: TranslateService) {
|
||||
this.intl = new Intl.Collator(translate.currentLang, {
|
||||
numeric: true,
|
||||
ignorePunctuation: true,
|
||||
sensitivity: 'base'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine false-like values (if they are not boolean)
|
||||
* @param property
|
||||
*/
|
||||
private isFalsy(property: any): boolean {
|
||||
return property === null || property === undefined || property === 0 || property === '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreates the sorting function. Is supposed to be called on init and
|
||||
* every time the sorting (property, ascending/descending) or the language changes
|
||||
*/
|
||||
protected sortItems(itemA: T, itemB: T, sortProperty: keyof T, ascending: boolean = true): number {
|
||||
// always sort falsy values to the bottom
|
||||
const property = sortProperty as string;
|
||||
if (this.isFalsy(itemA[property]) && this.isFalsy(itemB[property])) {
|
||||
return 0;
|
||||
} else if (this.isFalsy(itemA[property])) {
|
||||
return 1;
|
||||
} else if (this.isFalsy(itemB[property])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const firstProperty = ascending ? itemA[property] : itemB[property];
|
||||
const secondProperty = ascending ? itemB[property] : itemA[property];
|
||||
|
||||
if (this.sortFn) {
|
||||
return this.sortFn(itemA, itemB, ascending, this.intl);
|
||||
} else {
|
||||
switch (typeof firstProperty) {
|
||||
case 'boolean':
|
||||
if (!firstProperty && secondProperty) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
case 'number':
|
||||
return firstProperty > secondProperty ? 1 : -1;
|
||||
case 'string':
|
||||
if (!!firstProperty && !secondProperty) {
|
||||
return -1;
|
||||
} else if (!firstProperty && !!secondProperty) {
|
||||
return 1;
|
||||
} else if ((!secondProperty && !secondProperty) || firstProperty === secondProperty) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.intl.compare(firstProperty, secondProperty);
|
||||
}
|
||||
case 'function':
|
||||
const a = firstProperty();
|
||||
const b = secondProperty();
|
||||
return this.intl.compare(a, b);
|
||||
case 'object':
|
||||
if (firstProperty instanceof Date) {
|
||||
return firstProperty > secondProperty ? 1 : -1;
|
||||
} else {
|
||||
return this.intl.compare(firstProperty.toString(), secondProperty.toString());
|
||||
}
|
||||
case 'undefined':
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
client/src/app/core/ui-services/tree-sort.service.spec.ts
Normal file
19
client/src/app/core/ui-services/tree-sort.service.spec.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from '../../../e2e-imports.module';
|
||||
import { TreeSortService } from './tree-sort.service';
|
||||
|
||||
describe('TreeSortService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [TreeSortService]
|
||||
})
|
||||
);
|
||||
|
||||
// TODO testing (does not work without injecting a BaseViewComponent)
|
||||
// it('should be created', () => {
|
||||
// const service: TreeSortService = TestBed.get(TreeSortService);
|
||||
// expect(service).toBeTruthy();
|
||||
// });
|
||||
});
|
53
client/src/app/core/ui-services/tree-sort.service.ts
Normal file
53
client/src/app/core/ui-services/tree-sort.service.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { Displayable } from 'app/site/base/displayable';
|
||||
import { BaseSortService } from './base-sort.service';
|
||||
import { FlatNode } from './tree.service';
|
||||
|
||||
/**
|
||||
* Sorting service for trees.
|
||||
*
|
||||
* Contains base functions to sort a tree by different properties.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TreeSortService<T extends Identifiable & Displayable> extends BaseSortService<T> {
|
||||
/**
|
||||
* Constructor.
|
||||
* Calls the `super()`-method.
|
||||
*
|
||||
* @param translate The reference to the `TranslateService`
|
||||
*/
|
||||
public constructor(protected translate: TranslateService) {
|
||||
super(translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to sort the passed source of a tree
|
||||
* and resets some properties like `level`, `expandable`, `position`.
|
||||
*
|
||||
* @param sourceData The source array of `FlatNode`s.
|
||||
* @param property The property, the array will be sorted by.
|
||||
* @param ascending Boolean, if the array should be sorted in ascending order.
|
||||
*
|
||||
* @returns {FlatNode<T>[]} The sorted array.
|
||||
*/
|
||||
public sortTree(sourceData: FlatNode<T>[], property: keyof T, ascending: boolean = true): FlatNode<T>[] {
|
||||
return sourceData
|
||||
.sort((nodeA, nodeB) => {
|
||||
const itemA = nodeA.item;
|
||||
const itemB = nodeB.item;
|
||||
return this.sortItems(itemA, itemB, property, ascending);
|
||||
})
|
||||
.map((node, index) => {
|
||||
node.level = 0;
|
||||
node.position = index;
|
||||
node.expandable = false;
|
||||
return node;
|
||||
});
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseFilterListService, OsFilterIndicator } from 'app/core/ui-services/base-filter-list.service';
|
||||
import { OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||
import { FilterMenuComponent } from './filter-menu/filter-menu.component';
|
||||
|
@ -6,6 +6,8 @@ import { Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Output
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { auditTime } from 'rxjs/operators';
|
||||
|
||||
import { SortDefinition } from 'app/core/ui-services/base-sort.service';
|
||||
import { TreeSortService } from 'app/core/ui-services/tree-sort.service';
|
||||
import { FlatNode, TreeIdNode, TreeService } from 'app/core/ui-services/tree.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { Displayable } from 'app/site/base/displayable';
|
||||
@ -175,6 +177,19 @@ export class SortingTreeComponent<T extends Identifiable & Displayable> implemen
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for sorting functions.
|
||||
*
|
||||
* @param predicate An `EventEmitter` to push to sort the tree by the passed property.
|
||||
* It should pass a `SortDefinition`.
|
||||
*/
|
||||
@Input()
|
||||
public set sortingDefinition(predicate: EventEmitter<SortDefinition<T>>) {
|
||||
predicate.subscribe((event: SortDefinition<T>) => {
|
||||
this.resolveSortingPredicate(event);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* EventEmitter to send info if changes has been made.
|
||||
*/
|
||||
@ -197,8 +212,9 @@ export class SortingTreeComponent<T extends Identifiable & Displayable> implemen
|
||||
* Constructor
|
||||
*
|
||||
* @param treeService Service to get data from store and build the tree nodes.
|
||||
* @param sortService Service to sort tree nodes by their given items.
|
||||
*/
|
||||
public constructor(private treeService: TreeService) {}
|
||||
public constructor(private treeService: TreeService, private sortService: TreeSortService<T>) {}
|
||||
|
||||
/**
|
||||
* On init method
|
||||
@ -947,6 +963,27 @@ export class SortingTreeComponent<T extends Identifiable & Displayable> implemen
|
||||
return willFiltered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to sort the given source-array by the passed property of the underlying items `<T>`.
|
||||
*
|
||||
* @param event `SortDefinition<T>` - can be only a `keyof T` or
|
||||
* an object defining the property and whether ascending order or not:
|
||||
* `{ property: keyof T, ascending: boolean }`.
|
||||
*/
|
||||
private resolveSortingPredicate(event: SortDefinition<T>): void {
|
||||
this.removeSubscription();
|
||||
const sortProperty = typeof event === 'object' ? event.sortProperty : event;
|
||||
const sortAscending = typeof event === 'object' ? event.sortAscending : true;
|
||||
|
||||
this.osTreeData = this.sortService.sortTree(this.osTreeData, sortProperty, sortAscending);
|
||||
this.checkActiveFilters();
|
||||
|
||||
this.dataSource = null;
|
||||
this.dataSource = new ArrayDataSource(this.osTreeData);
|
||||
|
||||
this.madeChanges(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if a node has children.
|
||||
*/
|
||||
|
@ -4,7 +4,8 @@ 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 { BaseSortListService, OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ViewAssignment } from '../models/view-assignment';
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { SortDefinition } from 'app/core/ui-services/base-sort.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { SortingTreeComponent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
@ -40,6 +41,11 @@ export abstract class SortTreeViewComponent<V extends BaseViewModel> extends Bas
|
||||
*/
|
||||
public readonly changeFilter: EventEmitter<(item: V) => boolean> = new EventEmitter<(item: V) => boolean>();
|
||||
|
||||
/**
|
||||
* Emitter to notice the `tree-sorting.service` for sorting the data-source.
|
||||
*/
|
||||
public readonly forceSort = new EventEmitter<SortDefinition<V>>();
|
||||
|
||||
/**
|
||||
* Boolean to check if changes has been made.
|
||||
*/
|
||||
|
@ -4,7 +4,8 @@ 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 { BaseSortListService, OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ViewMediafile } from '../models/view-mediafile';
|
||||
|
||||
/**
|
||||
|
@ -82,6 +82,7 @@
|
||||
(hasChanged)="receiveChanges($event)"
|
||||
[model]="motionsObservable"
|
||||
[filterChange]="changeFilter"
|
||||
[sortingDefinition]="forceSort"
|
||||
>
|
||||
<ng-template #innerNode let-item="item">
|
||||
<div class="line">
|
||||
@ -100,6 +101,13 @@
|
||||
</mat-card>
|
||||
|
||||
<mat-menu #mainMenu="matMenu">
|
||||
<button mat-menu-item (click)="sortMotionsByIdentifier()">
|
||||
<mat-icon>sort</mat-icon>
|
||||
<span translate>Sort by identifier</span>
|
||||
</button>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<button mat-menu-item (click)="pdfExportCallList()">
|
||||
<mat-icon>picture_as_pdf</mat-icon>
|
||||
<span translate>Export as PDF</span>
|
||||
|
@ -256,6 +256,19 @@ export class CallListComponent extends SortTreeViewComponent<ViewMotion> impleme
|
||||
this.activeCatFilters.next([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method requires a confirmation from the user
|
||||
* and starts the sorting by the property `identifier` of the motions
|
||||
* in case of `true`.
|
||||
*/
|
||||
public async sortMotionsByIdentifier(): Promise<void> {
|
||||
const title = this.translate.instant('Do you really want to go ahead?');
|
||||
const text = this.translate.instant('This will reset all made changes and sort the tree...');
|
||||
if (await this.promptService.open(title, text)) {
|
||||
this.forceSort.emit('identifier');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to trigger an update of the filter itself and the information about
|
||||
* the state of filters
|
||||
|
@ -4,7 +4,7 @@ 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 { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { MotionSortListService } from './motion-sort-list.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
@ -4,7 +4,8 @@ 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 { BaseSortListService, OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ViewMotionBlock } from '../models/view-motion-block';
|
||||
|
||||
@Injectable({
|
||||
|
@ -6,7 +6,8 @@ import { OpenSlidesStatusService } from 'app/core/core-services/openslides-statu
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { Deferred } from 'app/core/promises/deferred';
|
||||
import { _ } from 'app/core/translate/translation-marker';
|
||||
import { BaseSortListService, OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
||||
|
@ -4,7 +4,8 @@ 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 { BaseSortListService, OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
|
||||
import { OsSortingDefinition, OsSortingOption } from 'app/core/ui-services/base-sort.service';
|
||||
import { ViewUser } from '../models/view-user';
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user