rework category list and sorting
This commit is contained in:
parent
841d80a35b
commit
66f9c81564
@ -11,7 +11,6 @@ import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { HttpService } from '../../core-services/http.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { Motion } from 'app/shared/models/motions/motion';
|
||||
import { ViewCategory } from 'app/site/motions/models/view-category';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
|
||||
@ -81,22 +80,6 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
|
||||
await this.dataSend.deleteModel(category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all motions belonging to a category
|
||||
* @param category category
|
||||
*/
|
||||
public getMotionsOfCategory(category: Category): Motion[] {
|
||||
const motList = this.DS.getAll(Motion);
|
||||
const retList: Array<Motion> = [];
|
||||
motList.forEach(motion => {
|
||||
if (motion.category_id && motion.category_id === category.id) {
|
||||
retList.push(motion);
|
||||
}
|
||||
});
|
||||
// TODO: Sorting the return List?!
|
||||
return retList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the category for the ID
|
||||
* @param category_id category ID
|
||||
|
@ -1,13 +1,16 @@
|
||||
<div cdkDropList class="list" (cdkDropListDropped)="drop($event)">
|
||||
<div cdkDropList class="os-card" (cdkDropListDropped)="drop($event)">
|
||||
<div class= "box line" *ngIf="!array.length">
|
||||
<span translate>No data</span>
|
||||
</div>
|
||||
<div class="box line" *ngFor="let item of array; let i = index" cdkDrag>
|
||||
<div class="section-one" cdkDragHandle>
|
||||
<!-- TODO: drag_indicator after icon update -->
|
||||
<mat-icon>unfold_more</mat-icon>
|
||||
</div>
|
||||
<div class="section-two">
|
||||
<!-- {number}. {item.toString()} -->
|
||||
<span *ngIf="count">{{ i+1 }}. </span>
|
||||
<span>{{ item }}</span>
|
||||
<!-- {number}. {item.getTitle()} -->
|
||||
<span *ngIf="count">{{ i + 1 }}. </span>
|
||||
<span>{{ item.getTitle() }}</span>
|
||||
</div>
|
||||
<div class="section-three">
|
||||
<!-- Extra controls slot using implicit template references -->
|
||||
|
@ -1,9 +1,3 @@
|
||||
.list {
|
||||
width: 100%;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 100%;
|
||||
border-bottom: solid 1px #ccc;
|
||||
|
@ -5,7 +5,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { Selectable } from '../selectable';
|
||||
import { EmptySelectable } from '../empty-selectable';
|
||||
|
||||
/**
|
||||
* Reusable Sorting List
|
||||
@ -133,8 +132,8 @@ export class SortingListComponent implements OnInit, OnDestroy {
|
||||
if (this.array.length !== newValues.length || this.live) {
|
||||
this.array = [];
|
||||
this.array = newValues.map(val => val);
|
||||
} else if (this.array.length === 0) {
|
||||
this.array.push(new EmptySelectable(this.translate));
|
||||
} else {
|
||||
this.array = this.array.map(arrayValue => newValues.find(val => val.id === arrayValue.id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,27 +4,28 @@
|
||||
<h2 translate>Categories</h2>
|
||||
</div>
|
||||
</os-head-bar>
|
||||
<div class="custom-table-header"></div>
|
||||
|
||||
<!-- Creating a new category -->
|
||||
<mat-card *ngIf="categoryToCreate">
|
||||
<div class="spacer-top-20"></div>
|
||||
<mat-card class="os-card" *ngIf="categoryToCreate">
|
||||
<mat-card-title translate>Create new category</mat-card-title>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="createForm" (keydown)="keyDownFunction($event)">
|
||||
<p>
|
||||
<!-- Prefix field -->
|
||||
<mat-form-field>
|
||||
<input formControlName="prefix" matInput placeholder="{{'Prefix' | translate}}">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Name field -->
|
||||
<mat-form-field>
|
||||
<input formControlName="name" matInput placeholder="{{'Name' | translate}}" required>
|
||||
<mat-hint *ngIf="!createForm.controls.name.valid">
|
||||
<span translate>Required</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</p>
|
||||
<form
|
||||
class="full-width-form flex-spaced"
|
||||
id="createForm"
|
||||
[formGroup]="createForm"
|
||||
(keydown)="keyDownFunction($event)"
|
||||
>
|
||||
<!-- prefix input -->
|
||||
<mat-form-field class="short-input">
|
||||
<input formControlName="prefix" matInput placeholder="{{ 'Prefix' | translate }}" />
|
||||
</mat-form-field>
|
||||
<!-- name input -->
|
||||
<mat-form-field class="long-input">
|
||||
<input formControlName="name" matInput placeholder="{{ 'Name' | translate }}" required />
|
||||
<mat-hint *ngIf="!updateForm.controls.name.valid">
|
||||
<span translate>Required</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
|
||||
@ -39,80 +40,94 @@
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
<mat-accordion class="os-form-card">
|
||||
<mat-expansion-panel *ngFor="let category of categories" (opened)="openId = category.id" (closed)="panelClosed(category)"
|
||||
[expanded]="openId === category.id" multiple="false">
|
||||
<mat-card class="os-card">
|
||||
<mat-accordion displayMode="flat">
|
||||
<ng-container *ngFor="let category of categories">
|
||||
<mat-expansion-panel
|
||||
class="os-card-expandion-panel"
|
||||
(opened)="setValues(category)"
|
||||
[expanded]="editId === category.id"
|
||||
(closed)="onCancelButton()"
|
||||
>
|
||||
<!-- Header shows Prefix and name -->
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<div class="header-container">
|
||||
<div class="header-name">
|
||||
<div>
|
||||
{{ category.prefixedName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-size os-amount-chip">
|
||||
{{ motionsInCategory(category).length }}
|
||||
</div>
|
||||
</div>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<!-- Header shows Prefix and name -->
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<div class="header-container">
|
||||
<div class="header-prefix">
|
||||
<div *ngIf="editId !== category.id">
|
||||
{{ category.prefix }}
|
||||
<!-- Edit form shows during the edit event -->
|
||||
<div class="full-width-form">
|
||||
<form
|
||||
class="full-width-form"
|
||||
id="updateForm"
|
||||
[formGroup]="updateForm"
|
||||
*ngIf="editId === category.id"
|
||||
(keydown)="keyDownFunction($event, category)"
|
||||
>
|
||||
<div class="flex-spaced">
|
||||
<mat-form-field class="short-input">
|
||||
<input formControlName="prefix" matInput placeholder="{{ 'Prefix' | translate }}" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="long-input">
|
||||
<input
|
||||
formControlName="name"
|
||||
matInput
|
||||
placeholder="{{ 'Name' | translate }}"
|
||||
required
|
||||
/>
|
||||
<mat-hint *ngIf="!updateForm.controls.name.valid">
|
||||
<span translate>Required</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="editId === category.id">
|
||||
{{ updateForm.get('prefix').value }}
|
||||
<div class="inline-form-submit" *osPerms="'motions.can_manage'">
|
||||
<button
|
||||
[disabled]="!updateForm.dirty"
|
||||
mat-button
|
||||
class="on-transition-fade"
|
||||
(click)="onSaveButton(category)"
|
||||
>
|
||||
<span translate>Save</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
mat-button
|
||||
class="on-transition-fade"
|
||||
[routerLink]="getSortUrl(category)"
|
||||
>
|
||||
<span translate>Sort motions</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
mat-button
|
||||
class="on-transition-fade"
|
||||
(click)="onDeleteButton(category)"
|
||||
>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-name">
|
||||
<div *ngIf="editId !== category.id">
|
||||
{{ category.name }}
|
||||
</div>
|
||||
<div *ngIf="editId === category.id">
|
||||
{{ updateForm.get('name').value }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-size os-amount-chip">
|
||||
{{ motionsInCategory(category).length }}
|
||||
</form>
|
||||
</div>
|
||||
<!-- Show and sort corresponding motions-->
|
||||
<div *ngIf="motionsInCategory(category).length > 0">
|
||||
<span translate>Motions</span>:
|
||||
<div>
|
||||
<ul *ngFor="let motion of motionsInCategory(category)">
|
||||
<li class="ellipsis-overflow">{{ motion.getListTitle() }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<!-- Edit form shows during the edit event -->
|
||||
<form id="updateForm" [formGroup]='updateForm' *ngIf="editId === category.id" (keydown)="keyDownFunction($event, category)">
|
||||
<span translate>Edit category</span>:<br>
|
||||
|
||||
<mat-form-field>
|
||||
<input formControlName="prefix" matInput placeholder="{{'Prefix' | translate}}">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input formControlName="name" matInput placeholder="{{'Name' | translate}}" required>
|
||||
<mat-hint *ngIf="!updateForm.controls.name.valid">
|
||||
<span translate>Required</span>
|
||||
</mat-hint>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<!-- Show and sort corresponding motions-->
|
||||
<div *ngIf="motionsInCategory(category).length > 0">
|
||||
<span translate>Motions</span>:
|
||||
<div *ngIf="editId !== category.id">
|
||||
<ul *ngFor="let motion of motionsInCategory(category)">
|
||||
<li>{{ motion }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="editId === category.id" class="half-width">
|
||||
<os-sorting-list [input]="motionsInCategory(category)" #sorter></os-sorting-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons to edit, delete, save ... -->
|
||||
<mat-action-row>
|
||||
<button mat-icon-button *ngIf="editId !== category.id" class='on-transition-fade' (click)=onEditButton(category)>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button *ngIf="editId === category.id" class='on-transition-fade' (click)=onCancelButton()>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button *ngIf="editId === category.id" class='on-transition-fade' (click)=onSaveButton(category)>
|
||||
<mat-icon>save</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button mat-button class='on-transition-fade' (click)=onDeleteButton(category)>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</mat-action-row>
|
||||
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
</mat-accordion>
|
||||
</mat-card>
|
||||
|
@ -1,33 +1,50 @@
|
||||
.header-container {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-template-columns: 33.333% 33.333% 33.333%;
|
||||
grid-template-columns: 75% 25%;
|
||||
width: 100%;
|
||||
|
||||
> div {
|
||||
grid-row-start: 1;
|
||||
grid-row-end: span 1;
|
||||
grid-column-end: span 3;
|
||||
}
|
||||
|
||||
.header-prefix {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 2;
|
||||
}
|
||||
|
||||
.header-name {
|
||||
grid-column-start: 2;
|
||||
grid-column-start: 1;
|
||||
color: lightslategray;
|
||||
}
|
||||
|
||||
.header-size {
|
||||
grid-column-start: 3;
|
||||
grid-column-start: 2;
|
||||
}
|
||||
}
|
||||
|
||||
#updateForm {
|
||||
margin-bottom: 20px;
|
||||
mat-expansion-panel {
|
||||
max-width: 770px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.half-width {
|
||||
width: 50%;
|
||||
.flex-spaced {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.full-width-form {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-content: space-between;
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.short-input {
|
||||
width: 20%;
|
||||
}
|
||||
.long-input {
|
||||
width: 75%;
|
||||
}
|
||||
.inline-form-submit {
|
||||
justify-content: end;
|
||||
display: block;
|
||||
flex: 1;
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { Category } from 'app/shared/models/motions/category';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { ViewCategory } from '../../models/view-category';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { Motion } from 'app/shared/models/motions/motion';
|
||||
import { SortingListComponent } from 'app/shared/components/sorting-list/sorting-list.component';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { ViewCategory } from '../../models/view-category';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
|
||||
/**
|
||||
* List view for the categories.
|
||||
@ -28,15 +28,10 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
public categoryToCreate: Category | null;
|
||||
|
||||
/**
|
||||
* Determine which category to edit
|
||||
* Determine which category is opened
|
||||
*/
|
||||
public editId: number | null;
|
||||
|
||||
/**
|
||||
* Determine which category is opened.
|
||||
*/
|
||||
public openId: number | null;
|
||||
|
||||
/**
|
||||
* Source of the data
|
||||
*/
|
||||
@ -52,12 +47,6 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public updateForm: FormGroup;
|
||||
|
||||
/**
|
||||
* The MultiSelect Component
|
||||
*/
|
||||
@ViewChild('sorter')
|
||||
public sortSelector: SortingListComponent;
|
||||
|
||||
/**
|
||||
* The usual component constructor
|
||||
* @param titleService
|
||||
@ -72,6 +61,7 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
translate: TranslateService,
|
||||
matSnackBar: MatSnackBar,
|
||||
private repo: CategoryRepositoryService,
|
||||
private motionRepo: MotionRepositoryService,
|
||||
private formBuilder: FormBuilder,
|
||||
private promptService: PromptService
|
||||
) {
|
||||
@ -89,7 +79,8 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event on key-down in form
|
||||
* Event on key-down in form. Submits the current form if the 'enter' button is pressed
|
||||
*
|
||||
* @param event
|
||||
* @param viewCategory
|
||||
*/
|
||||
@ -154,47 +145,33 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the category
|
||||
*
|
||||
* TODO: Do not number the motions. This needs to be a separate button (maybe with propting for confirmation), because
|
||||
* not every body uses this and this would destroy their own order in motion identifiers.
|
||||
* See issue #3969
|
||||
* Saves a category
|
||||
* TODO: Some feedback
|
||||
*
|
||||
* @param viewCategory
|
||||
*/
|
||||
public async onSaveButton(viewCategory: ViewCategory): Promise<void> {
|
||||
// get the sorted motions. Save them before updating the category.
|
||||
let sortedMotionIds;
|
||||
if (this.sortSelector) {
|
||||
sortedMotionIds = this.sortSelector.array.map(selectable => selectable.id);
|
||||
this.repo.numberMotionsInCategory(viewCategory.category, sortedMotionIds);
|
||||
}
|
||||
|
||||
if (this.updateForm.valid) {
|
||||
if (this.updateForm.dirty && this.updateForm.valid) {
|
||||
const cat: Partial<Category> = { name: this.updateForm.get('name').value };
|
||||
if (this.updateForm.get('prefix').value) {
|
||||
cat.prefix = this.updateForm.get('prefix').value;
|
||||
}
|
||||
// wait for the category to update; then the (maybe) changed prefix can be applied to the motions
|
||||
await this.repo.update(cat, viewCategory);
|
||||
this.onCancelButton();
|
||||
|
||||
if (this.sortSelector) {
|
||||
this.repo.numberMotionsInCategory(viewCategory.category, sortedMotionIds);
|
||||
}
|
||||
this.updateForm.markAsPristine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* executed on cancel button
|
||||
* @param viewCategory
|
||||
* Trigger after cancelling an edit. The updateForm is reset to an original
|
||||
* value, which might belong to a different category
|
||||
*/
|
||||
public onCancelButton(): void {
|
||||
this.editId = null;
|
||||
this.updateForm.markAsPristine();
|
||||
}
|
||||
|
||||
/**
|
||||
* is executed, when the delete button is pressed
|
||||
*
|
||||
* @param viewCategory The category to delete
|
||||
*/
|
||||
public async onDeleteButton(viewCategory: ViewCategory): Promise<void> {
|
||||
@ -206,23 +183,36 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Returns the motions corresponding to a category
|
||||
*
|
||||
* @param category target
|
||||
* @returns all motions in the category
|
||||
*/
|
||||
public motionsInCategory(category: Category): Motion[] {
|
||||
const motions = this.repo.getMotionsOfCategory(category);
|
||||
motions.sort((motion1, motion2) => (motion1 > motion2 ? 1 : -1));
|
||||
return motions;
|
||||
public motionsInCategory(category: Category): ViewMotion[] {
|
||||
return this.motionRepo
|
||||
.getViewModelList()
|
||||
.filter(m => m.category_id === category.id)
|
||||
.sort((motion1, motion2) => motion1.identifier.localeCompare(motion2.identifier));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is executed when a mat-extension-panel is closed
|
||||
* @param viewCategory the category in the panel
|
||||
* Fetch the correct URL for a detail sort view
|
||||
*
|
||||
* @param viewCategory
|
||||
*/
|
||||
public panelClosed(viewCategory: ViewCategory): void {
|
||||
this.openId = null;
|
||||
if (this.editId) {
|
||||
this.onSaveButton(viewCategory);
|
||||
}
|
||||
public getSortUrl(viewCategory: ViewCategory): string {
|
||||
return `/motions/category/${viewCategory.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/reset the initial values and the referenced category of the update form
|
||||
*
|
||||
* @param category
|
||||
*/
|
||||
public setValues(category: ViewCategory): void {
|
||||
this.editId = category.id;
|
||||
this.updateForm.setValue({
|
||||
prefix: category.prefix,
|
||||
name: category.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
<!-- TODO permission -->
|
||||
<os-head-bar [nav]="false">
|
||||
<!-- Title -->
|
||||
<div class="title-slot"><h2 translate>Sort motions</h2></div>
|
||||
</os-head-bar>
|
||||
|
||||
<mat-card class="os-form-card">
|
||||
<h3>{{ categoryName }}</h3>
|
||||
<br />
|
||||
<span translate>
|
||||
Drag and drop motions to reorder the category. Then click the button to renumber.
|
||||
</span>
|
||||
<br />
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="onNumberMotions()"
|
||||
class="spacer-top-10"
|
||||
[disabled]="!motionsCount"
|
||||
>
|
||||
<span translate>Number motions</span>
|
||||
</button>
|
||||
<os-sorting-list [input]="motionObservable" #sorter></os-sorting-list>
|
||||
</mat-card>
|
@ -0,0 +1,26 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CategorySortComponent } from './category-sort.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('CategorySortComponent', () => {
|
||||
let component: CategorySortComponent;
|
||||
let fixture: ComponentFixture<CategorySortComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [CategorySortComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CategorySortComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,119 @@
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { SortingListComponent } from 'app/shared/components/sorting-list/sorting-list.component';
|
||||
import { ViewCategory } from '../../models/view-category';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
|
||||
/**
|
||||
* View for rearranging and renumbering the motions of a category. The {@link onNumberMotions}
|
||||
* method sends a request to the server to re-number the given motions in the order
|
||||
* as displayed in this view
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-category-sort',
|
||||
templateUrl: './category-sort.component.html',
|
||||
styleUrls: ['./category-sort.component.scss']
|
||||
})
|
||||
export class CategorySortComponent extends BaseViewComponent implements OnInit {
|
||||
/**
|
||||
* The current category. Determined by the route
|
||||
*/
|
||||
public category: ViewCategory;
|
||||
|
||||
/**
|
||||
* A behaviorSubject emitting the currently asigned motions on change
|
||||
*/
|
||||
public motionsSubject = new BehaviorSubject<ViewMotion[]>([]);
|
||||
|
||||
/**
|
||||
* Counter indicating the amount of motions currently in the category
|
||||
*/
|
||||
public motionsCount = 0;
|
||||
|
||||
/**
|
||||
* @returns an observable for the {@link motionsSubject}
|
||||
*/
|
||||
public get motionObservable(): Observable<ViewMotion[]> {
|
||||
return this.motionsSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the name and (if present) prefix of the category
|
||||
*/
|
||||
public get categoryName(): string {
|
||||
if (!this.category) {
|
||||
return '';
|
||||
}
|
||||
return this.category.prefix ? `${this.category.name} (${this.category.prefix})` : this.category.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Sort Component
|
||||
*/
|
||||
@ViewChild('sorter')
|
||||
public sortSelector: SortingListComponent;
|
||||
|
||||
/**
|
||||
* Constructor. Calls parents
|
||||
*
|
||||
* @param title
|
||||
* @param translate
|
||||
* @param matSnackBar
|
||||
* @param promptService
|
||||
* @param repo
|
||||
* @param route
|
||||
* @param motionRepo
|
||||
*/
|
||||
public constructor(
|
||||
title: Title,
|
||||
translate: TranslateService,
|
||||
matSnackBar: MatSnackBar,
|
||||
private promptService: PromptService,
|
||||
private repo: CategoryRepositoryService,
|
||||
private route: ActivatedRoute,
|
||||
private motionRepo: MotionRepositoryService
|
||||
) {
|
||||
super(title, translate, matSnackBar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to the category and motions of this category.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
const category_id: number = +this.route.snapshot.params.id;
|
||||
this.repo.getViewModelObservable(category_id).subscribe(cat => {
|
||||
this.category = cat;
|
||||
});
|
||||
this.motionRepo.getViewModelListObservable().subscribe(motions => {
|
||||
const filtered = motions.filter(m => m.category_id === category_id);
|
||||
this.motionsCount = filtered.length;
|
||||
this.motionsSubject.next(filtered);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a (re-)numbering of the motions after a configmarion dialog
|
||||
*
|
||||
* @param category
|
||||
*/
|
||||
public async onNumberMotions(): Promise<void> {
|
||||
if (this.sortSelector) {
|
||||
const content = this.translate.instant('This will change the identifier for the motions of this category.');
|
||||
if (await this.promptService.open('Are you sure?', content)) {
|
||||
const sortedMotionIds = this.sortSelector.array.map(selectable => selectable.id);
|
||||
await this.repo
|
||||
.numberMotionsInCategory(this.category.category, sortedMotionIds)
|
||||
.then(null, this.raiseError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -72,7 +72,7 @@
|
||||
</div>
|
||||
<!-- submitters line -->
|
||||
<div class="motion-list">
|
||||
<span class="motion-list-from" *ngIf="motion.submitters.length">
|
||||
<span class="motion-list-from ellipsis-overflow" *ngIf="motion.submitters.length">
|
||||
<span translate>by</span> {{ motion.submitters }}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ import { Routes, RouterModule } from '@angular/router';
|
||||
import { AmendmentCreateWizardComponent } from './components/amendment-create-wizard/amendment-create-wizard.component';
|
||||
import { CallListComponent } from './components/call-list/call-list.component';
|
||||
import { CategoryListComponent } from './components/category-list/category-list.component';
|
||||
import { CategorySortComponent } from './components/category-sort/category-sort.component';
|
||||
import { MotionBlockListComponent } from './components/motion-block-list/motion-block-list.component';
|
||||
import { MotionBlockDetailComponent } from './components/motion-block-detail/motion-block-detail.component';
|
||||
import { MotionCommentSectionListComponent } from './components/motion-comment-section-list/motion-comment-section-list.component';
|
||||
@ -19,6 +20,7 @@ import { WorkflowDetailComponent } from './components/workflow-detail/workflow-d
|
||||
const routes: Routes = [
|
||||
{ path: '', component: MotionListComponent },
|
||||
{ path: 'category', component: CategoryListComponent },
|
||||
{ path: 'category/:id', component: CategorySortComponent },
|
||||
{ path: 'comment-section', component: MotionCommentSectionListComponent },
|
||||
{ path: 'statute-paragraphs', component: StatuteParagraphListComponent },
|
||||
{ path: 'statute-paragraphs/import', component: StatuteImportListComponent },
|
||||
|
@ -25,6 +25,7 @@ import { MotionExportDialogComponent } from './components/motion-export-dialog/m
|
||||
import { StatuteImportListComponent } from './components/statute-paragraph-list/statute-import-list/statute-import-list.component';
|
||||
import { WorkflowListComponent } from './components/workflow-list/workflow-list.component';
|
||||
import { WorkflowDetailComponent } from './components/workflow-detail/workflow-detail.component';
|
||||
import { CategorySortComponent } from './components/category-sort/category-sort.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MotionsRoutingModule, SharedModule],
|
||||
@ -50,7 +51,8 @@ import { WorkflowDetailComponent } from './components/workflow-detail/workflow-d
|
||||
MotionExportDialogComponent,
|
||||
StatuteImportListComponent,
|
||||
WorkflowListComponent,
|
||||
WorkflowDetailComponent
|
||||
WorkflowDetailComponent,
|
||||
CategorySortComponent
|
||||
],
|
||||
entryComponents: [
|
||||
MotionChangeRecommendationComponent,
|
||||
|
@ -639,3 +639,9 @@ button.mat-menu-item.selected {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ellipsis-overflow {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user