Merge pull request #4653 from GabrielInTheWorld/sorting
Save motion category weight, handle auto update in categories
This commit is contained in:
commit
addc0cc3cc
@ -2,10 +2,11 @@ import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { CategoryListComponent } from './components/category-list/category-list.component';
|
||||
import { CategorySortComponent } from './components/category-sort/category-sort.component';
|
||||
import { WatchSortingTreeGuard } from 'app/shared/utils/watch-sorting-tree.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: CategoryListComponent, pathMatch: 'full' },
|
||||
{ path: ':id', component: CategorySortComponent }
|
||||
{ path: ':id', component: CategorySortComponent, canDeactivate: [WatchSortingTreeGuard] }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -1,5 +1,9 @@
|
||||
<!-- TODO permission -->
|
||||
<os-head-bar [nav]="false">
|
||||
<os-head-bar
|
||||
[editMode]="hasChanged"
|
||||
(saveEvent)="sendUpdate()"
|
||||
(mainEvent)="onCancel()"
|
||||
[nav]="false">
|
||||
<!-- Title -->
|
||||
<div class="title-slot"><h2 translate>Sort motions</h2></div>
|
||||
</os-head-bar>
|
||||
@ -15,20 +19,26 @@
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="onNumberMotions()"
|
||||
class="spacer-top-10"
|
||||
[disabled]="!motionsCount"
|
||||
class="spacer-top-10 spacer-bottom-10"
|
||||
[disabled]="!motionsCount || hasChanged"
|
||||
>
|
||||
<span translate>Number motions</span>
|
||||
</button>
|
||||
<os-sorting-list [input]="motionObservable" #sorter>
|
||||
|
||||
<os-sorting-list
|
||||
(sortEvent)="onListUpdate($event)"
|
||||
[input]="motionObservable"
|
||||
#sorter
|
||||
>
|
||||
<!-- implicit motion references into the component using ng-template slot -->
|
||||
<ng-template let-motion>
|
||||
<div class="ellipsis-overflow small" *ngIf="motion.tags && motion.tags.length">
|
||||
<span class="ellipsis-overflow small" *ngIf="motion.tags && motion.tags.length">
|
||||
<span *ngFor="let tag of motion.tags">
|
||||
<mat-icon inline>local_offer</mat-icon>
|
||||
{{ tag.getTitle() }}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<mat-chip matTooltip="{{ 'Sequential number' | translate }}">{{ motion.id }}</mat-chip>
|
||||
</ng-template>
|
||||
</os-sorting-list>
|
||||
</mat-card>
|
||||
|
@ -12,6 +12,7 @@ import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { SortingListComponent } from 'app/shared/components/sorting-list/sorting-list.component';
|
||||
import { ViewCategory } from 'app/site/motions/models/view-category';
|
||||
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
import { CanComponentDeactivate } from 'app/shared/utils/watch-sorting-tree.guard';
|
||||
|
||||
/**
|
||||
* View for rearranging and renumbering the motions of a category. The {@link onNumberMotions}
|
||||
@ -23,7 +24,7 @@ import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
templateUrl: './category-sort.component.html',
|
||||
styleUrls: ['./category-sort.component.scss']
|
||||
})
|
||||
export class CategorySortComponent extends BaseViewComponent implements OnInit {
|
||||
export class CategorySortComponent extends BaseViewComponent implements OnInit, CanComponentDeactivate {
|
||||
/**
|
||||
* The current category. Determined by the route
|
||||
*/
|
||||
@ -39,6 +40,22 @@ export class CategorySortComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public motionsCount = 0;
|
||||
|
||||
/**
|
||||
* Flag to define if the list has changed.
|
||||
*/
|
||||
public hasChanged = false;
|
||||
|
||||
/**
|
||||
* Copied array of the motions in this category
|
||||
*/
|
||||
private motionsCopy: ViewMotion[] = [];
|
||||
|
||||
/**
|
||||
* Array that contains the initial list of motions.
|
||||
* Necessary to reset the list.
|
||||
*/
|
||||
private motionsBackup: ViewMotion[] = [];
|
||||
|
||||
/**
|
||||
* @returns an observable for the {@link motionsSubject}
|
||||
*/
|
||||
@ -95,11 +112,27 @@ export class CategorySortComponent extends BaseViewComponent implements OnInit {
|
||||
});
|
||||
this.motionRepo.getViewModelListObservable().subscribe(motions => {
|
||||
const filtered = motions.filter(m => m.category_id === category_id);
|
||||
this.motionsBackup = [...filtered];
|
||||
this.motionsCount = filtered.length;
|
||||
this.motionsSubject.next(filtered);
|
||||
if (this.motionsCopy.length === 0) {
|
||||
this.initializeList(filtered);
|
||||
} else {
|
||||
this.motionsSubject.next(this.handleMotionUpdates(filtered));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to (re-)set the current list of motions.
|
||||
*
|
||||
* @param motions An array containing the new motions.
|
||||
*/
|
||||
private initializeList(motions: ViewMotion[]): void {
|
||||
motions.sort((a, b) => (a.category_weight < b.category_weight ? -1 : 1));
|
||||
this.motionsSubject.next(motions);
|
||||
this.motionsCopy = motions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a (re-)numbering of the motions after a configmarion dialog
|
||||
*
|
||||
@ -117,4 +150,86 @@ export class CategorySortComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for the sorting event in the `sorting-list`.
|
||||
*
|
||||
* @param motions ViewMotion[]: The sorted array of motions.
|
||||
*/
|
||||
public onListUpdate(motions: ViewMotion[]): void {
|
||||
this.hasChanged = true;
|
||||
this.motionsCopy = motions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current list.
|
||||
*/
|
||||
public async onCancel(): Promise<void> {
|
||||
if (await this.canDeactivate()) {
|
||||
this.motionsSubject.next([]);
|
||||
this.initializeList(this.motionsBackup);
|
||||
this.hasChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function sends the changed list.
|
||||
* Only an array containing ids from the motions will be sent.
|
||||
*/
|
||||
public async sendUpdate(): Promise<void> {
|
||||
const title = this.translate.instant('Save changes');
|
||||
const content = this.translate.instant('Do you really want to save your changes?');
|
||||
if (await this.promptService.open(title, content)) {
|
||||
const ids = this.motionsCopy.map(motion => motion.id);
|
||||
this.repo.sortMotionsInCategory(this.category.category, ids);
|
||||
this.hasChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles the incoming motions after the user sorted them previously.
|
||||
*
|
||||
* @param nextMotions are the motions that are received from the server.
|
||||
*
|
||||
* @returns An array containing the new motions or not the removed motions.
|
||||
*/
|
||||
private handleMotionUpdates(nextMotions: ViewMotion[]): ViewMotion[] {
|
||||
const copy = this.motionsCopy;
|
||||
if (nextMotions.length > copy.length) {
|
||||
for (const motion of nextMotions) {
|
||||
if (!this.motionsCopy.includes(motion)) {
|
||||
copy.push(motion);
|
||||
}
|
||||
}
|
||||
} else if (nextMotions.length < copy.length) {
|
||||
for (const motion of copy) {
|
||||
if (!nextMotions.includes(motion)) {
|
||||
copy.splice(copy.indexOf(motion), 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const motion of copy) {
|
||||
if (!nextMotions.includes(motion)) {
|
||||
const updatedMotion = nextMotions.find(theMotion => theMotion.id === motion.id);
|
||||
copy.splice(copy.indexOf(motion), 1, updatedMotion);
|
||||
}
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to open a prompt dialog,
|
||||
* so the user will be warned if he has made changes and not saved them.
|
||||
*
|
||||
* @returns The result from the prompt dialog.
|
||||
*/
|
||||
public async canDeactivate(): Promise<boolean> {
|
||||
if (this.hasChanged) {
|
||||
const title = this.translate.instant('You made changes.');
|
||||
const content = this.translate.instant('Do you really want to exit?');
|
||||
return await this.promptService.open(title, content);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user