Merge pull request #4606 from GabrielInTheWorld/motion-quick-dialog
Implements a dialog to edit meta information of one motion
This commit is contained in:
commit
d4ac7441fa
@ -103,22 +103,24 @@
|
||||
<!-- state column -->
|
||||
<ng-container matColumnDef="state">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>State</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable state-column">
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
{{ motion.category }}
|
||||
</div>
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.motion_block">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
{{ motion.motion_block.title }}
|
||||
</div>
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.tags && motion.tags.length">
|
||||
<mat-icon>local_offer</mat-icon>
|
||||
<span *ngFor="let tag of motion.tags; let last = last">
|
||||
{{ tag.getTitle() }}
|
||||
<span *ngIf="!last">, </span>
|
||||
</span>
|
||||
<mat-cell (click)="openEditInfo(motion, $event)" *matCellDef="let motion">
|
||||
<div class="fill">
|
||||
<div class="innerTable state-column">
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.category">
|
||||
<mat-icon>device_hub</mat-icon>
|
||||
{{ motion.category }}
|
||||
</div>
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.motion_block">
|
||||
<mat-icon>widgets</mat-icon>
|
||||
{{ motion.motion_block.title }}
|
||||
</div>
|
||||
<div class="small ellipsis-overflow" *ngIf="motion.tags && motion.tags.length">
|
||||
<mat-icon>local_offer</mat-icon>
|
||||
<span *ngFor="let tag of motion.tags; let last = last">
|
||||
{{ tag.getTitle() }}
|
||||
<span *ngIf="!last">, </span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
@ -245,7 +247,7 @@
|
||||
<span translate>Set status</span>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="recomendationEnabled"
|
||||
*ngIf="recommendationEnabled"
|
||||
[disabled]="!selectedRows.length"
|
||||
mat-menu-item
|
||||
(click)="multiselectWrapper(multiselectService.setRecommendation(selectedRows))"
|
||||
@ -329,3 +331,47 @@
|
||||
</div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
|
||||
<!-- Template for dialog for quick editing -->
|
||||
<ng-template #motionInfoDialog>
|
||||
<h1 mat-dialog-title>
|
||||
<span>{{ 'Edit details for' | translate }} {{ infoDialog.title }}</span>
|
||||
</h1>
|
||||
<div class="os-form-card-mobile" mat-dialog-content>
|
||||
<!-- Category -->
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{ 'Category' | translate }}" [(ngModel)]="infoDialog.category">
|
||||
<mat-option [value]="null">-</mat-option>
|
||||
<mat-option *ngFor="let category of categories" [value]="category.id">
|
||||
{{ category.getTitle() | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<!-- Motion block -->
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{ 'Motion block' | translate }}" [(ngModel)]="infoDialog.motionBlock">
|
||||
<mat-option [value]="null">-</mat-option>
|
||||
<mat-option *ngFor="let block of motionBlocks" [value]="block.id">
|
||||
{{ block.getTitle() | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<!-- Tag -->
|
||||
<mat-form-field>
|
||||
<mat-select multiple placeholder="{{ 'Tags' | translate }}" [(ngModel)]="infoDialog.tags">
|
||||
<mat-option *ngFor="let tag of tags" [value]="tag.id">
|
||||
{{ tag.getTitle() | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button type="submit" mat-button color="primary" [mat-dialog-close]="infoDialog">
|
||||
<span translate>Save</span>
|
||||
</button>
|
||||
<button type="button" mat-button [mat-dialog-close]="null">
|
||||
<span translate>Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewChild, TemplateRef } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { MatSnackBar, MatDialog } from '@angular/material';
|
||||
@ -31,6 +31,32 @@ import { MotionXlsxExportService } from 'app/site/motions/services/motion-xlsx-e
|
||||
import { LocalPermissionsService } from 'app/site/motions/services/local-permissions.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
|
||||
/**
|
||||
* Interface to describe possible values and changes for
|
||||
* meta information dialog.
|
||||
*/
|
||||
interface InfoDialog {
|
||||
/**
|
||||
* The title of the motion
|
||||
*/
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* The motion block id
|
||||
*/
|
||||
motionBlock: number;
|
||||
|
||||
/**
|
||||
* The category id
|
||||
*/
|
||||
category: number;
|
||||
|
||||
/**
|
||||
* The motions tag ids
|
||||
*/
|
||||
tags: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that displays all the motions in a Table using DataSource.
|
||||
*/
|
||||
@ -40,6 +66,17 @@ import { StorageService } from 'app/core/core-services/storage.service';
|
||||
styleUrls: ['./motion-list.component.scss']
|
||||
})
|
||||
export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motion> implements OnInit {
|
||||
/**
|
||||
* Reference to the dialog for quick editing meta information.
|
||||
*/
|
||||
@ViewChild('motionInfoDialog')
|
||||
private motionInfoDialog: TemplateRef<string>;
|
||||
|
||||
/**
|
||||
* Interface to hold meta information.
|
||||
*/
|
||||
public infoDialog: InfoDialog;
|
||||
|
||||
/**
|
||||
* Columns to display in table when desktop view is available
|
||||
*/
|
||||
@ -55,7 +92,7 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motio
|
||||
* @TODO replace by direct access to config variable, once it's available from the templates
|
||||
*/
|
||||
public statutesEnabled: boolean;
|
||||
public recomendationEnabled: boolean;
|
||||
public recommendationEnabled: boolean;
|
||||
|
||||
public tags: ViewTag[] = [];
|
||||
public workflows: ViewWorkflow[] = [];
|
||||
@ -128,9 +165,9 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motio
|
||||
this.configService
|
||||
.get<boolean>('motions_statutes_enabled')
|
||||
.subscribe(enabled => (this.statutesEnabled = enabled));
|
||||
this.configService
|
||||
.get<string>('motions_recommendations_by')
|
||||
.subscribe(recommender => (this.recomendationEnabled = !!recommender));
|
||||
this.configService.get<string>('motions_recommendations_by').subscribe(recommender => {
|
||||
this.recommendationEnabled = !!recommender;
|
||||
});
|
||||
this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => (this.motionBlocks = mBs));
|
||||
this.categoryRepo.getViewModelListObservable().subscribe(cats => (this.categories = cats));
|
||||
this.tagRepo.getViewModelListObservable().subscribe(tags => (this.tags = tags));
|
||||
@ -341,4 +378,54 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motio
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a dialog to edit some meta information about a motion.
|
||||
*
|
||||
* @param motion the ViewMotion whose content is edited.
|
||||
* @param ev a MouseEvent.
|
||||
*/
|
||||
public async openEditInfo(motion: ViewMotion, ev: MouseEvent): Promise<void> {
|
||||
ev.stopPropagation();
|
||||
|
||||
// The interface holding the current information from motion.
|
||||
this.infoDialog = {
|
||||
title: motion.title,
|
||||
motionBlock: motion.motion_block_id,
|
||||
category: motion.category_id,
|
||||
tags: motion.tags_id
|
||||
};
|
||||
|
||||
// Copies the interface to check, if changes were made.
|
||||
const copyDialog = { ...this.infoDialog };
|
||||
|
||||
const dialogRef = this.dialog.open(this.motionInfoDialog, {
|
||||
width: '400px',
|
||||
maxWidth: '90vw',
|
||||
maxHeight: '90vh',
|
||||
disableClose: true
|
||||
});
|
||||
|
||||
dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
|
||||
if (event.key === 'Enter' && event.shiftKey) {
|
||||
dialogRef.close(this.infoDialog);
|
||||
}
|
||||
});
|
||||
|
||||
// After closing the dialog: Goes through the fields and check if they are changed
|
||||
// TODO: Logic like this should be handled in a service
|
||||
dialogRef.afterClosed().subscribe(async (result: InfoDialog) => {
|
||||
if (result) {
|
||||
const partialUpdate = {
|
||||
category_id: result.category !== copyDialog.category ? result.category : undefined,
|
||||
motion_block_id: result.motionBlock !== copyDialog.motionBlock ? result.motionBlock : undefined,
|
||||
tags_id: JSON.stringify(result.tags) !== JSON.stringify(copyDialog.tags) ? result.tags : undefined
|
||||
};
|
||||
// TODO: "only update if different" was another repo-todo
|
||||
if (!Object.keys(partialUpdate).every(key => partialUpdate[key] === undefined)) {
|
||||
await this.motionRepo.update(partialUpdate, motion).then(null, this.raiseError);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -61,10 +61,7 @@
|
||||
</span>
|
||||
</span>
|
||||
<br *ngIf="user.groups && user.structure_level" />
|
||||
<span *ngIf="user.structure_level">
|
||||
<mat-icon>flag</mat-icon>
|
||||
{{ user.structure_level }}
|
||||
</span>
|
||||
<span *ngIf="user.structure_level"> <mat-icon>flag</mat-icon>{{ user.structure_level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
|
@ -84,4 +84,8 @@
|
||||
background-color: mat-color($background, hover);
|
||||
color: mat-color($foreground, text) !important;
|
||||
}
|
||||
|
||||
input[readonly] {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user