add new Motion form

This commit is contained in:
Sean Engelhardt 2018-08-21 14:56:26 +02:00
parent b808228b42
commit 133ecb4724
9 changed files with 136 additions and 69 deletions

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable, of, BehaviorSubject } from 'rxjs'; import { Observable, BehaviorSubject } from 'rxjs';
import { tap, map } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { ImproperlyConfiguredError } from 'app/core/exceptions'; import { ImproperlyConfiguredError } from 'app/core/exceptions';
import { BaseModel, ModelId } from 'app/shared/models/base.model'; import { BaseModel, ModelId } from 'app/shared/models/base.model';

View File

@ -26,10 +26,10 @@ export class MotionVersion implements Deserializable {
this.id = id; this.id = id;
this.version_number = version_number; this.version_number = version_number;
this.creation_time = creation_time; this.creation_time = creation_time;
this.title = title; this.title = title || '';
this.text = text; this.text = text || '';
this.amendment_paragraphs = amendment_paragraphs; this.amendment_paragraphs = amendment_paragraphs || '';
this.reason = reason; this.reason = reason || '';
} }
deserialize(input: any): this { deserialize(input: any): this {

View File

@ -66,24 +66,24 @@ export class Motion extends BaseModel {
super(); super();
this._collectionString = 'motions/motion'; this._collectionString = 'motions/motion';
this.id = id; this.id = id;
this.identifier = identifier; this.identifier = identifier || '';
this.versions = versions; this.versions = versions || [new MotionVersion()];
this.active_version = active_version; this.active_version = active_version;
this.parent_id = parent_id; this.parent_id = parent_id;
this.category_id = category_id; this.category_id = category_id;
this.motion_block_id = motion_block_id; this.motion_block_id = motion_block_id;
this.origin = origin; this.origin = origin || '';
this.submitters = submitters; this.submitters = submitters || [new MotionSubmitter()];
this.supporters_id = supporters_id; this.supporters_id = supporters_id;
this.comments = comments; this.comments = comments;
this.state_id = state_id; this.state_id = state_id;
this.state_required_permission_to_see = state_required_permission_to_see; this.state_required_permission_to_see = state_required_permission_to_see || '';
this.recommendation_id = recommendation_id; this.recommendation_id = recommendation_id;
this.tags_id = tags_id; this.tags_id = tags_id;
this.attachments_id = attachments_id; this.attachments_id = attachments_id;
this.polls = polls; this.polls = polls;
this.agenda_item_id = agenda_item_id; this.agenda_item_id = agenda_item_id;
this.log_messages = log_messages; this.log_messages = log_messages || [new MotionLog()];
this.initDataStoreValues(); this.initDataStoreValues();
} }
@ -124,7 +124,7 @@ export class Motion extends BaseModel {
* returns the most current title from versions * returns the most current title from versions
*/ */
get currentTitle(): string { get currentTitle(): string {
if (this.versions[0]) { if (this.versions && this.versions[0]) {
return this.versions[0].title; return this.versions[0].title;
} else { } else {
return ''; return '';
@ -141,7 +141,11 @@ export class Motion extends BaseModel {
* returns the most current motion text from versions * returns the most current motion text from versions
*/ */
get currentText() { get currentText() {
if (this.versions) {
return this.versions[0].text; return this.versions[0].text;
} else {
return null;
}
} }
set currentText(newText: string) { set currentText(newText: string) {
@ -152,9 +156,17 @@ export class Motion extends BaseModel {
* returns the most current motion reason text from versions * returns the most current motion reason text from versions
*/ */
get currentReason() { get currentReason() {
if (this.versions) {
return this.versions[0].reason; return this.versions[0].reason;
} else {
return null;
}
} }
/**
* Update the current reason.
* TODO: ignores motion versions. Should make a new one.
*/
set currentReason(newReason: string) { set currentReason(newReason: string) {
this.versions[0].reason = newReason; this.versions[0].reason = newReason;
} }
@ -164,20 +176,24 @@ export class Motion extends BaseModel {
*/ */
get submitterAsUser() { get submitterAsUser() {
const submitterIds = []; const submitterIds = [];
if (this.submitters) {
this.submitters.forEach(submitter => { this.submitters.forEach(submitter => {
submitterIds.push(submitter.user_id); submitterIds.push(submitter.user_id);
}); });
const users = this.DS.get(User, ...submitterIds); const users = this.DS.get(User, ...submitterIds);
return users; return users;
} else {
return null;
}
} }
/** /**
* returns the name of the first submitter * returns the name of the first submitter
*/ */
get submitterName() { get submitterName() {
const mainSubmitter = this.DS.get(User, this.submitters[0].user_id) as User; const submitters = this.submitterAsUser;
if (mainSubmitter) { if (submitters) {
return mainSubmitter; return submitters[0];
} else { } else {
return ''; return '';
} }
@ -191,7 +207,7 @@ export class Motion extends BaseModel {
const motionCategory = this.DS.get(Category, this.category_id); const motionCategory = this.DS.get(Category, this.category_id);
return motionCategory as Category; return motionCategory as Category;
} else { } else {
return 'none'; return '';
} }
} }
@ -205,12 +221,12 @@ export class Motion extends BaseModel {
/** /**
* return the workflow state * return the workflow state
*/ */
get state() { get state(): any {
if (this.workflow && this.workflow.id) { if (this.state_id && this.workflow && this.workflow.id) {
const state = this.workflow.state_by_id(this.state_id); const state = this.workflow.state_by_id(this.state_id);
return state; return state;
} else { } else {
return null; return '';
} }
} }
@ -226,12 +242,12 @@ export class Motion extends BaseModel {
* *
* TODO: Motion workflow needs to be specific on the server * TODO: Motion workflow needs to be specific on the server
*/ */
get recommendation() { get recommendation(): any {
if (this.workflow && this.workflow.id) { if (this.recommendation_id && this.workflow && this.workflow.id) {
const state = this.workflow.state_by_id(this.recommendation_id); const state = this.workflow.state_by_id(this.recommendation_id);
return state; return state;
} else { } else {
return null; return '';
} }
} }
@ -243,8 +259,13 @@ export class Motion extends BaseModel {
Config, Config,
config => config.key === 'motions_recommendations_by' config => config.key === 'motions_recommendations_by'
)[0] as Config; )[0] as Config;
if (motionsRecommendationsByConfig) {
const recomByString = motionsRecommendationsByConfig.value; const recomByString = motionsRecommendationsByConfig.value;
return recomByString; return recomByString;
} else {
return null;
}
} }
deserialize(input: any): this { deserialize(input: any): this {

View File

@ -1,14 +1,16 @@
<mat-toolbar color='primary'> <mat-toolbar color='primary'>
<button (click)='editMotionButton()' [ngClass]="{'save-button': editMotion}" class='generic-mini-button on-transition-fade save-button' mat-mini-fab> <button (click)='editMotionButton()' [ngClass]="{'save-button': editMotion}" class='generic-mini-button on-transition-fade'
mat-mini-fab>
<fa-icon *ngIf="!editMotion" icon='pen'></fa-icon> <fa-icon *ngIf="!editMotion" icon='pen'></fa-icon>
<fa-icon *ngIf="editMotion" icon='check'></fa-icon> <fa-icon *ngIf="editMotion" icon='check'></fa-icon>
</button> </button>
<div class='motion-title on-transition-fade'> <div class='motion-title on-transition-fade'>
<span *ngIf="newMotion">New </span>
<span translate>Motion</span> <span translate>Motion</span>
<span *ngIf="!editMotion"> {{motion.identifier}}</span> <span *ngIf="!editMotion"> {{motion.identifier}}</span>
<span *ngIf="editMotion"> {{metaInfoForm.get('identifier').value}}</span> <span *ngIf="editMotion && !newMotion"> {{metaInfoForm.get('identifier').value}}</span>
<span>:</span> <span>:</span>
<span *ngIf="!editMotion"> {{motion.currentTitle}}</span> <span *ngIf="!editMotion"> {{motion.currentTitle}}</span>
<span *ngIf="editMotion"> {{contentForm.get('currentTitle').value}}</span> <span *ngIf="editMotion"> {{contentForm.get('currentTitle').value}}</span>
@ -23,7 +25,7 @@
<!-- MetaInfo --> <!-- MetaInfo -->
<!-- <mat-expansion-panel #metaInfoPanel [expanded]='true' class='meta-info-panel'> --> <!-- <mat-expansion-panel #metaInfoPanel [expanded]='true' class='meta-info-panel'> -->
<mat-expansion-panel #metaInfoPanel class='meta-info-panel'> <mat-expansion-panel #metaInfoPanel [expanded]='this.editMotion && this.newMotion' class='meta-info-panel'>
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<fa-icon icon='info-circle' [fixedWidth]="true"></fa-icon> <fa-icon icon='info-circle' [fixedWidth]="true"></fa-icon>
@ -35,7 +37,8 @@
<form [formGroup]='metaInfoForm' class='expansion-panel-custom-body' (ngSubmit)='saveMotion()'> <form [formGroup]='metaInfoForm' class='expansion-panel-custom-body' (ngSubmit)='saveMotion()'>
<!-- Identifier --> <!-- Identifier -->
<div *ngIf="editMotion"> <div *ngIf="editMotion && !newMotion">
<!-- <div *ngIf="editMotion"> -->
<div *ngIf='!editMotion'> <div *ngIf='!editMotion'>
<h3 translate>Identifier</h3> <h3 translate>Identifier</h3>
{{motion.identifier}} {{motion.identifier}}
@ -92,12 +95,6 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<!-- <h3>
<a [matMenuTriggerFor]="stateMenu">
<span>{{motion.recomBy}}</span>
</a>
</h3> -->
<!-- {{motion.recommendation}} -->
</div> </div>
<!-- Category --> <!-- Category -->
@ -185,7 +182,7 @@
<textarea matInput placeholder="Reason" formControlName='currentReason' [value]='motion.currentReason'></textarea> <textarea matInput placeholder="Reason" formControlName='currentReason' [value]='motion.currentReason'></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
</form>
</form>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>

View File

@ -19,11 +19,28 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
metaInfoForm: FormGroup; metaInfoForm: FormGroup;
contentForm: FormGroup; contentForm: FormGroup;
editMotion = false; editMotion = false;
newMotion = false;
/**
*
* @param route determine if this is a new or an existing motion
* @param formBuilder For reactive forms. Form Group and Form Control
*/
constructor(private route: ActivatedRoute, private formBuilder: FormBuilder) { constructor(private route: ActivatedRoute, private formBuilder: FormBuilder) {
super(); super();
this.createForm(); this.createForm();
console.log('route: ', route.snapshot.url[0].path);
if (route.snapshot.url[0].path === 'new') {
this.newMotion = true;
this.editMotion = true;
this.motion = new Motion();
} else {
// load existing motion
this.route.params.subscribe(params => { this.route.params.subscribe(params => {
console.log('params ', params);
// has the motion of the DataStore was initialized before. // has the motion of the DataStore was initialized before.
this.motion = this.DS.get(Motion, params.id) as Motion; this.motion = this.DS.get(Motion, params.id) as Motion;
@ -37,8 +54,11 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
}); });
}); });
} }
}
/** Parches the Form with content from the dataStore */ /**
* Async load the values of the motion in the Form.
*/
patchForm() { patchForm() {
this.metaInfoForm.patchValue({ this.metaInfoForm.patchValue({
category_id: this.motion.category.id, category_id: this.motion.category.id,
@ -54,7 +74,11 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
}); });
} }
/** Create the whole Form with empty or default values */ /**
* Creates the forms for the Motion and the MotionVersion
*
* TODO: Build a custom form validator
*/
createForm() { createForm() {
this.metaInfoForm = this.formBuilder.group({ this.metaInfoForm = this.formBuilder.group({
identifier: [''], identifier: [''],
@ -70,35 +94,57 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
}); });
} }
/**
* Save a motion. Calls the "patchValues" function in the MotionObject
*
* http:post the motion to the server.
* The AutoUpdate-Service should see a change once it arrives and show it
* in the list view automatically
*/
saveMotion() { saveMotion() {
const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value }; const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value };
this.motion.patchValues(newMotionValues); this.motion.patchValues(newMotionValues);
console.log('save motion: this: ', this);
this.DS.save(this.motion).subscribe(answer => {
console.log(answer);
});
} }
/**
* return all Categories.
*/
getMotionCategories(): Category[] { getMotionCategories(): Category[] {
const categories = this.DS.get(Category); const categories = this.DS.get(Category);
return categories as Category[]; return categories as Category[];
} }
/**
* Click on the edit button (pen-symbol)
*/
editMotionButton() { editMotionButton() {
this.editMotion ? (this.editMotion = false) : (this.editMotion = true); this.editMotion ? (this.editMotion = false) : (this.editMotion = true);
if (this.editMotion) { if (this.editMotion) {
// switch to edit mode
this.patchForm(); this.patchForm();
this.metaInfoPanel.open(); this.metaInfoPanel.open();
this.contentPanel.open(); this.contentPanel.open();
} else { } else {
// save button
this.saveMotion(); this.saveMotion();
} }
} }
ngOnInit() { /**
console.log('(init)the motion: ', this.motion); * Init. Does nothing here.
console.log('motion state name: ', this.motion.state); */
} ngOnInit() {}
/**
* Function to download a motion.
*
* TODO: does nothing yet.
*/
downloadSingleMotionButton() { downloadSingleMotionButton() {
console.log('Download this motion'); console.log('Download this motion');
} }

View File

@ -1,6 +1,6 @@
<mat-toolbar color='primary'> <mat-toolbar color='primary'>
<button class='generic-plus-button on-transition-fade' mat-fab> <button class='generic-plus-button on-transition-fade' routerLink='new' mat-fab>
<fa-icon icon='plus'></fa-icon> <fa-icon icon='plus'></fa-icon>
</button> </button>
@ -43,7 +43,7 @@
<br> <br>
<span class='motion-list-from'> <span class='motion-list-from'>
<span translate>by</span> <span translate>by</span>
{{motion.submitterAsUser.username}} {{motion.submitterAsUser}}
</span> </span>
</div> </div>
</mat-cell> </mat-cell>

View File

@ -70,9 +70,11 @@ export class MotionListComponent extends BaseComponent implements OnInit {
// The alternative approach is to put the observable as DataSource to the table // The alternative approach is to put the observable as DataSource to the table
this.DS.getObservable().subscribe(newModel => { this.DS.getObservable().subscribe(newModel => {
if (newModel instanceof Motion) { if (newModel instanceof Motion) {
if (!this.motionArray.includes(newModel)) {
this.motionArray.push(newModel as Motion); this.motionArray.push(newModel as Motion);
this.dataSource.data = this.motionArray; this.dataSource.data = this.motionArray;
} }
}
}); });
} }

View File

@ -5,7 +5,7 @@ import { MotionDetailComponent } from './motion-detail/motion-detail.component';
const routes: Routes = [ const routes: Routes = [
{ path: '', component: MotionListComponent }, { path: '', component: MotionListComponent },
{ path: 'dummy', component: MotionDetailComponent }, { path: 'new', component: MotionDetailComponent },
{ path: ':id', component: MotionDetailComponent } { path: ':id', component: MotionDetailComponent }
]; ];

View File

@ -111,7 +111,8 @@ export class StartComponent extends BaseComponent implements OnInit {
* function to print datastore * function to print datastore
*/ */
giveDataStore() { giveDataStore() {
this.DS.printWhole(); // this.DS.printWhole();
console.log('only the motions: \n', this.DS.get(Motion) as Motion[]);
} }
/** /**