Merge pull request #3809 from tsiegleauq/MotionStates

Read the Workflow by state_id in Motion
This commit is contained in:
Finn Stutzenstein 2018-08-23 15:11:03 +02:00 committed by GitHub
commit 95c6628732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 35 deletions

View File

@ -37,9 +37,7 @@ export class Motion extends BaseModel {
agenda_item_id: number; agenda_item_id: number;
log_messages: MotionLog[]; log_messages: MotionLog[];
// read from config // dynamic values
workflow_id: number;
// by the config above
workflow: Workflow; workflow: Workflow;
// for request // for request
@ -100,31 +98,31 @@ export class Motion extends BaseModel {
} }
/** /**
* sets the workflow_id and the workflow * sets the and the workflow from either dataStore or WebSocket
*/ */
initDataStoreValues() { initDataStoreValues() {
const motionsWorkflowConfig = this.DS.filter(Config, config => config.key === 'motions_workflow')[0] as Config; // check the containing Workflows in DataStore
if (motionsWorkflowConfig) { const allWorkflows = this.DS.get(Workflow) as Workflow[];
this.workflow_id = +motionsWorkflowConfig.value; allWorkflows.forEach(localWorkflow => {
} else { if (localWorkflow.isStateContained(this.state_id)) {
this.DS.getObservable().subscribe(newConfig => { this.workflow = localWorkflow as Workflow;
if (newConfig instanceof Config && newConfig.key === 'motions_workflow') {
this.workflow_id = +newConfig.value;
} }
}); });
}
this.workflow = this.DS.get(Workflow, this.workflow_id) as Workflow; // observe for new models
if (!this.workflow.id) {
this.DS.getObservable().subscribe(newModel => { this.DS.getObservable().subscribe(newModel => {
if (newModel instanceof Workflow && newModel.id === this.workflow_id) { if (newModel instanceof Workflow) {
this.workflow = newModel; if (newModel.isStateContained(this.state_id)) {
this.workflow = newModel as Workflow;
}
} }
}); });
} }
}
/** add a new motionSubmitter from user-object */ /**
* add a new motionSubmitter from user-object
* @param user the user
*/
addSubmitter(user: User) { addSubmitter(user: User) {
const newSubmitter = new MotionSubmitter(null, user.id); const newSubmitter = new MotionSubmitter(null, user.id);
this.submitters.push(newSubmitter); this.submitters.push(newSubmitter);
@ -142,6 +140,11 @@ export class Motion extends BaseModel {
} }
} }
/**
* Patch the current version
*
* TODO: Altering the current version should be avoided.
*/
set currentTitle(newTitle: string) { set currentTitle(newTitle: string) {
if (this.versions[0]) { if (this.versions[0]) {
this.versions[0].title = newTitle; this.versions[0].title = newTitle;
@ -221,9 +224,8 @@ export class Motion extends BaseModel {
* return the workflow state * return the workflow state
*/ */
get state(): any { get state(): any {
if (this.state_id && this.workflow && this.workflow.id) { if (this.workflow) {
const state = this.workflow.state_by_id(this.state_id); return this.workflow.state_by_id(this.state_id);
return state;
} else { } else {
return ''; return '';
} }
@ -232,8 +234,12 @@ export class Motion extends BaseModel {
/** /**
* returns possible states for the motion * returns possible states for the motion
*/ */
get possible_states(): WorkflowState[] { get nextStates(): WorkflowState[] {
return this.workflow.states; if (this.workflow && this.state) {
return this.state.getNextStates(this.workflow);
} else {
return null;
}
} }
/** /**

View File

@ -1,4 +1,6 @@
import { Deserializable } from '../deserializable.model'; import { Deserializable } from '../deserializable.model';
import { Workflow } from './workflow';
import { MotionLog } from './motion-log';
/** /**
* Representation of a workflow state * Representation of a workflow state
@ -79,6 +81,20 @@ export class WorkflowState implements Deserializable {
this.workflow_id = workflow_id; this.workflow_id = workflow_id;
} }
/**
* return a list of the next possible states.
* Also adds the current state.
*/
getNextStates(workflow: Workflow): WorkflowState[] {
const nextStates = [];
workflow.states.forEach(state => {
if (this.next_states_id.includes(state.id)) {
nextStates.push(state as WorkflowState);
}
});
return nextStates;
}
deserialize(input: any): this { deserialize(input: any): this {
Object.assign(this, input); Object.assign(this, input);
return this; return this;

View File

@ -21,6 +21,25 @@ export class Workflow extends BaseModel {
this.first_state = first_state; this.first_state = first_state;
} }
/**
* Check if the containing @link{WorkflowState}s contain a given ID
* @param id The State ID
*/
isStateContained(obj: number | WorkflowState): boolean {
let id: number;
if (obj instanceof WorkflowState) {
id = obj.id;
} else {
id = obj;
}
return this.states.some(state => {
if (state.id === id) {
return true;
}
});
}
state_by_id(id: number): WorkflowState { state_by_id(id: number): WorkflowState {
let targetState; let targetState;
this.states.forEach(state => { this.states.forEach(state => {

View File

@ -73,18 +73,19 @@
</div> </div>
<!-- State --> <!-- State -->
<div *ngIf='motion && motion.state_id || editMotion'> <div *ngIf='!newMotion && motion && motion.workflow && motion.state_id || editMotion'>
<div *ngIf='!editMotion'> <div *ngIf='!editMotion'>
<h3 translate>State</h3> <h3 translate>State</h3>
{{motion.state.name}} {{motion.state}}
</div> </div>
<mat-form-field *ngIf="editMotion"> <mat-form-field *ngIf="editMotion && !newMotion">
<mat-select placeholder='State' formControlName='state_id'> <mat-select placeholder='State' formControlName='state_id'>
<mat-option *ngFor="let state of motion.possible_states" [value]="state.id">{{state}}</mat-option> <mat-option [value]="motion.state.id">{{motion.state}}</mat-option>
<mat-divider></mat-divider>
<mat-option *ngFor="let state of motion.nextStates" [value]="state.id">{{state}}</mat-option>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-option> <mat-option>
<fa-icon icon='exclamation-triangle'></fa-icon> <fa-icon icon='exclamation-triangle'></fa-icon> <span translate>Reset State</span>
<span translate>Reset State</span>
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -99,7 +100,7 @@
</div> </div>
<mat-form-field *ngIf="motion && editMotion"> <mat-form-field *ngIf="motion && editMotion">
<mat-select placeholder='Recommendation' formControlName='recommendation_id'> <mat-select placeholder='Recommendation' formControlName='recommendation_id'>
<mat-option *ngFor="let state of motion.possible_states" [value]="state.id">{{state}}</mat-option> <mat-option *ngFor="let state of motion.nextStates" [value]="state.id">{{state}}</mat-option>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-option> <mat-option>
<fa-icon icon='exclamation-triangle'></fa-icon> <fa-icon icon='exclamation-triangle'></fa-icon>

View File

@ -133,6 +133,8 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
* http:post the motion to the server. * http:post the motion to the server.
* The AutoUpdate-Service should see a change once it arrives and show it * The AutoUpdate-Service should see a change once it arrives and show it
* in the list view automatically * in the list view automatically
*
* TODO: state is not yet saved. Need a special "put" command
*/ */
saveMotion() { saveMotion() {
const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value }; const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value };

View File

@ -53,7 +53,7 @@
<ng-container matColumnDef="state"> <ng-container matColumnDef="state">
<mat-header-cell *matHeaderCellDef mat-sort-header> State </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header> State </mat-header-cell>
<mat-cell *matCellDef="let motion"> <mat-cell *matCellDef="let motion">
<div *ngIf='motion.state && motion.state.name !== "submitted"' class='innerTable'> <div *ngIf='isDisplayIcon(motion.state) && motion.state' class='innerTable'>
<fa-icon icon={{getStateIcon(motion.state)}}></fa-icon> <fa-icon icon={{getStateIcon(motion.state)}}></fa-icon>
</div> </div>
</mat-cell> </mat-cell>

View File

@ -121,6 +121,10 @@ export class MotionListComponent extends BaseComponent implements OnInit {
} }
} }
isDisplayIcon(state): boolean {
return state.name === 'accepted' || state.name === 'rejected' || state.name === 'not decided';
}
/** /**
* Download all motions As PDF and DocX * Download all motions As PDF and DocX
* *