Merge pull request #4927 from tsiegleauq/better-motion-detail-ui

Overwork motion detail UI
This commit is contained in:
Sean 2019-08-20 13:52:44 +02:00 committed by GitHub
commit 1d1ddbd6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 107 additions and 80 deletions

View File

@ -1,3 +1,4 @@
import { Location } from '@angular/common';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router'; import { Router, RoutesRecognized } from '@angular/router';
@ -14,7 +15,7 @@ export class RoutingStateService {
/** /**
* Hold the previous URL * Hold the previous URL
*/ */
private _previousUrl: string; private previousUrl: string;
/** /**
* Unsafe paths that the user should not go "back" to * Unsafe paths that the user should not go "back" to
@ -23,14 +24,11 @@ export class RoutingStateService {
private unsafeUrls: string[] = ['/login', '/privacypolicy', '/legalnotice']; private unsafeUrls: string[] = ['/login', '/privacypolicy', '/legalnotice'];
/** /**
* @return Get the previous URL * Checks if the previous URL is safe to navigate to.
* If this fails, the open nav button should be shown
*/ */
public get previousUrl(): string {
return this._previousUrl ? this._previousUrl : null;
}
public get isSafePrevUrl(): boolean { public get isSafePrevUrl(): boolean {
return !!this.previousUrl && !this.unsafeUrls.includes(this.previousUrl); return !this.previousUrl || !this.unsafeUrls.includes(this.previousUrl);
} }
/** /**
@ -38,14 +36,18 @@ export class RoutingStateService {
* *
* @param router Angular Router * @param router Angular Router
*/ */
public constructor(private router: Router) { public constructor(private router: Router, private location: Location) {
this.router.events this.router.events
.pipe( .pipe(
filter(e => e instanceof RoutesRecognized), filter(e => e instanceof RoutesRecognized),
pairwise() pairwise()
) )
.subscribe((event: any[]) => { .subscribe((event: any[]) => {
this._previousUrl = event[0].urlAfterRedirects; this.previousUrl = event[0].urlAfterRedirects;
}); });
} }
public goBack(): void {
this.location.back();
}
} }

View File

@ -11,7 +11,7 @@
</button> </button>
<!-- Cancel edit button --> <!-- Cancel edit button -->
<button mat-icon-button *ngIf="editMode" (click)="sendMainEvent()"> <button mat-icon-button *ngIf="editMode" (click)="cancelEditEvent ? sendCancelEditEvent() : sendMainEvent()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
@ -35,21 +35,17 @@
<!-- Main action button - desktop --> <!-- Main action button - desktop -->
<button <button
mat-icon-button mat-icon-button
*ngIf="mainButtonIcon == 'add' && mainButton && !editMode && !vp.isMobile && !multiSelectMode" *ngIf="mainButton && !editMode && !vp.isMobile && !multiSelectMode"
(click)="sendMainEvent()" (click)="sendMainEvent()"
matTooltip="{{ mainActionTooltip | translate }}"
> >
<mat-icon>add_circle</mat-icon> <mat-icon>{{ mainButtonIcon }}</mat-icon>
</button>
<button
mat-icon-button
*ngIf="mainButtonIcon == 'edit' && mainButton && !editMode && !vp.isMobile && !multiSelectMode"
(click)="sendMainEvent()"
>
<mat-icon>edit</mat-icon>
</button> </button>
<!-- Save button --> <!-- Save button -->
<button mat-button *ngIf="editMode" [disabled]="!isSaveButtonEnabled" (click)="save()"><strong translate class="upper">Save</strong></button> <button mat-button *ngIf="editMode" [disabled]="!isSaveButtonEnabled" (click)="save()">
<strong translate class="upper">Save</strong>
</button>
<!-- Menu button slot --> <!-- Menu button slot -->
<ng-content *ngIf="!editMode" select=".menu-slot"></ng-content> <ng-content *ngIf="!editMode" select=".menu-slot"></ng-content>
@ -60,9 +56,10 @@
<button <button
mat-fab mat-fab
class="head-button " class="head-button"
*ngIf="mainButton && !editMode && vp.isMobile && !multiSelectMode" *ngIf="mainButton && !editMode && vp.isMobile && !multiSelectMode"
(click)="sendMainEvent()" (click)="sendMainEvent()"
matTooltip="{{ mainActionTooltip | translate }}"
> >
<mat-icon>{{ mainButtonIcon }}</mat-icon> <mat-icon>{{ mainButtonIcon }}</mat-icon>
</button> </button>

View File

@ -63,7 +63,7 @@ export class HeadBarComponent {
* Custom icon if necessary * Custom icon if necessary
*/ */
@Input() @Input()
public mainButtonIcon = 'add'; public mainButtonIcon = 'add_circle';
/** /**
* Determine edit mode * Determine edit mode
@ -105,12 +105,24 @@ export class HeadBarComponent {
@Input() @Input()
public prevUrl = '../'; public prevUrl = '../';
/**
* Optional tooltip for the main action
*/
@Input()
public mainActionTooltip: string;
/** /**
* Emit a signal to the parent component if the main button was clicked * Emit a signal to the parent component if the main button was clicked
*/ */
@Output() @Output()
public mainEvent = new EventEmitter<void>(); public mainEvent = new EventEmitter<void>();
/**
* Optional custom event for cancel the edit
*/
@Output()
public cancelEditEvent = new EventEmitter<void>();
/** /**
* Sends a signal if a detail view should be saved * Sends a signal if a detail view should be saved
*/ */
@ -139,6 +151,13 @@ export class HeadBarComponent {
this.mainEvent.next(); this.mainEvent.next();
} }
/**
* Emits a signal to for custom cancel edits
*/
public sendCancelEditEvent(): void {
this.cancelEditEvent.next();
}
/** /**
* Clicking the burger-menu-icon should toggle the menu * Clicking the burger-menu-icon should toggle the menu
*/ */
@ -159,7 +178,7 @@ export class HeadBarComponent {
*/ */
public onBackButton(): void { public onBackButton(): void {
if (this.goBack) { if (this.goBack) {
this.router.navigateByUrl(this.routingState.previousUrl); this.routingState.goBack();
} else { } else {
this.router.navigate([this.prevUrl], { relativeTo: this.route }); this.router.navigate([this.prevUrl], { relativeTo: this.route });
} }

View File

@ -14,6 +14,10 @@
<button type="button" *ngIf="menuItem" mat-menu-item [routerLink]="listOfSpeakers.listOfSpeakersUrl"> <button type="button" *ngIf="menuItem" mat-menu-item [routerLink]="listOfSpeakers.listOfSpeakersUrl">
<mat-icon>{{ icon }}</mat-icon> <mat-icon>{{ icon }}</mat-icon>
<span translate>List of speakers</span> <span translate>List of speakers</span>
<span>&nbsp;</span>
<mat-basic-chip disableRipple class="lightblue" *ngIf="listOfSpeakers.waitingSpeakerAmount > 0">
<span>{{ listOfSpeakers.waitingSpeakerAmount }}</span>
</mat-basic-chip>
</button> </button>
</ng-container> </ng-container>
</ng-container> </ng-container>

View File

@ -1,4 +1,4 @@
<os-head-bar [nav]="false"> <os-head-bar [nav]="false" [goBack]="false">
<!-- Title --> <!-- Title -->
<div class="title-slot"><h2 translate>New amendment</h2></div> <div class="title-slot"><h2 translate>New amendment</h2></div>
<div class="menu-slot"> <div class="menu-slot">

View File

@ -14,7 +14,7 @@
<div *ngIf="!isEditMode || !perms.isAllowed('change_metadata')"> <div *ngIf="!isEditMode || !perms.isAllowed('change_metadata')">
<mat-chip-list *ngFor="let user of motion.submittersAsUsers" class="user"> <mat-chip-list *ngFor="let user of motion.submittersAsUsers" class="user">
<mat-chip disableRipple *ngIf="user">{{ user.getTitle() }}</mat-chip> <mat-basic-chip disableRipple *ngIf="user">{{ user.getTitle() }}</mat-basic-chip>
</mat-chip-list> </mat-chip-list>
</div> </div>

View File

@ -19,3 +19,11 @@ h4 {
font-size: 100%; font-size: 100%;
} }
} }
.user .mat-chip {
border-radius: 16px !important;
padding: 5px 15px !important;
margin: 5px 0;
border: 1px solid #dddddd;
height: auto;
}

View File

@ -1,11 +1,13 @@
<os-head-bar <os-head-bar
[mainButton]="perms.isAllowed('update', motion)" [mainButton]="perms.isAllowed('can_create_amendments', motion)"
mainButtonIcon="edit" mainActionTooltip="New amendment"
[prevUrl]="getPrevUrl()" prevUrl="../.."
[goBack]="motion && !!motion.parent_id"
[nav]="false" [nav]="false"
[editMode]="editMotion" [editMode]="editMotion"
[isSaveButtonEnabled]="contentForm.valid" [isSaveButtonEnabled]="contentForm.valid"
(mainEvent)="setEditMode(!editMotion)" (mainEvent)="createAmendment()"
(cancelEditEvent)="setEditMode(false)"
(saveEvent)="saveMotion()" (saveEvent)="saveMotion()"
> >
<!-- Title --> <!-- Title -->
@ -24,15 +26,6 @@
<div *ngIf="!editMotion && !vp.isMobile" class="extra-controls-slot"> <div *ngIf="!editMotion && !vp.isMobile" class="extra-controls-slot">
<div *ngIf="previousMotion"> <div *ngIf="previousMotion">
<button mat-button (click)="navigateToMotion(previousMotion)"> <button mat-button (click)="navigateToMotion(previousMotion)">
<!-- possible icons:
arrow_left
chevron_left
first_page
arrow_back
arrow_back_ios
navigate_before
fast_rewind
-->
<mat-icon>chevron_left</mat-icon> <mat-icon>chevron_left</mat-icon>
<span>{{ previousMotion.identifier }}</span> <span>{{ previousMotion.identifier }}</span>
</button> </button>
@ -40,15 +33,6 @@
<div *ngIf="nextMotion"> <div *ngIf="nextMotion">
<button mat-button (click)="navigateToMotion(nextMotion)"> <button mat-button (click)="navigateToMotion(nextMotion)">
<span>{{ nextMotion.identifier }}</span> <span>{{ nextMotion.identifier }}</span>
<!-- possible icons:
arrow_right
chevron_right
last_page
arrow_forward
arrow_forward_ios
navigate_next
fast_forward
-->
<mat-icon>chevron_right</mat-icon> <mat-icon>chevron_right</mat-icon>
</button> </button>
</div> </div>
@ -63,13 +47,25 @@
<mat-menu #motionExtraMenu="matMenu"> <mat-menu #motionExtraMenu="matMenu">
<div *ngIf="motion"> <div *ngIf="motion">
<div *ngIf="vp.isMobile">
<button mat-menu-item (click)="navigateToMotion(previousMotion)" *ngIf="previousMotion">
<mat-icon>chevron_left</mat-icon>
<span>{{ 'Motion' | translate }} {{ previousMotion.identifier }}</span>
</button>
<button mat-menu-item (click)="navigateToMotion(nextMotion)" *ngIf="nextMotion">
<mat-icon>chevron_right</mat-icon>
<span>{{ 'Motion' | translate }} {{ nextMotion.identifier }}</span>
</button>
<mat-divider *ngIf="previousMotion || nextMotion"></mat-divider>
</div>
<!-- List of speakers -->
<os-speaker-button [object]="motion" [menuItem]="true"></os-speaker-button>
<!-- PDF --> <!-- PDF -->
<button mat-menu-item (click)="onDownloadPdf()"> <button mat-menu-item (click)="onDownloadPdf()">
<mat-icon>picture_as_pdf</mat-icon> <mat-icon>picture_as_pdf</mat-icon>
<span translate>PDF</span> <span translate>PDF</span>
</button> </button>
<!-- List of speakers --> <mat-divider></mat-divider>
<os-speaker-button [object]="motion" [menuItem]="true"></os-speaker-button>
<!-- Project --> <!-- Project -->
<os-projector-button <os-projector-button
[object]="motion" [object]="motion"
@ -87,21 +83,6 @@
<span translate>Remove from agenda</span> <span translate>Remove from agenda</span>
</button> </button>
</div> </div>
<!-- New amendment -->
<button mat-menu-item (click)="createAmendment()" *ngIf="perms.isAllowed('can_create_amendments', motion)">
<mat-icon>add</mat-icon>
<span translate>New amendment</span>
</button>
<!-- Show entire motion text -->
<button
mat-menu-item
(click)="showAmendmentContext = !showAmendmentContext"
*ngIf="motion && motion.isParagraphBasedAmendment()"
>
<mat-icon>{{ !showAmendmentContext ? 'check_box_outline_blank' : 'check_box' }}</mat-icon>
<span translate>Show entire motion text</span>
</button>
<button <button
mat-menu-item mat-menu-item
*osPerms="'core.can_see_history'" *osPerms="'core.can_see_history'"
@ -113,16 +94,23 @@
History History
</span> </span>
</button> </button>
<div *ngIf="perms.isAllowed('manage')">
<mat-divider></mat-divider> <mat-divider></mat-divider>
<!-- Edit-->
<button mat-menu-item (click)="setEditMode(true)" *ngIf="perms.isAllowed('update', motion)">
<mat-icon>edit</mat-icon>
<span translate>Edit</span>
</button>
<!-- Delete --> <!-- Delete -->
<button mat-menu-item class="red-warning-text" (click)="deleteMotionButton()"> <button
mat-menu-item
class="red-warning-text"
(click)="deleteMotionButton()"
*ngIf="perms.isAllowed('manage')"
>
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
<span translate>Delete</span> <span translate>Delete</span>
</button> </button>
</div> </div>
</div>
</mat-menu> </mat-menu>
</os-head-bar> </os-head-bar>
@ -901,6 +889,17 @@
<div class="paragraphcontext" [innerHtml]="sanitizedText(paragraph.textPost)"></div> <div class="paragraphcontext" [innerHtml]="sanitizedText(paragraph.textPost)"></div>
</div> </div>
</section> </section>
<!-- Show entire motion text -->
<div>
<mat-checkbox
(change)="showAmendmentContext = !showAmendmentContext"
*ngIf="motion && motion.isParagraphBasedAmendment()"
class="show-entire-text-check"
>
<span translate>Show entire motion text</span>
</mat-checkbox>
</div>
</ng-template> </ng-template>
<!-- Line number Menu --> <!-- Line number Menu -->

View File

@ -231,3 +231,8 @@ span {
font-size: 12px; font-size: 12px;
margin-top: 4px; margin-top: 4px;
} }
.show-entire-text-check {
font-size: 70%;
float: right;
}

View File

@ -520,13 +520,6 @@ mat-expansion-panel {
display: inline-flex; display: inline-flex;
} }
.mat-chip-list.user .mat-chip {
border-radius: 16px !important;
padding: 5px 15px !important;
border: 1px solid;
height: auto;
}
// to display quantities. Use in span or div // to display quantities. Use in span or div
.os-amount-chip { .os-amount-chip {
border-radius: 50%; border-radius: 50%;