TSK-1475: Hide mechanism workbasket list (#1369)
* TSK-1475: implement toggle button that resizes the width of workbasket list * TSK-1475: update pagination component view when workbasket list is collapsed * TSK-1475: optimize workbasket list toolbar when workbasket list is collapsed * TSK-1475: fix broken jest tests
This commit is contained in:
parent
5ac12037bc
commit
3c067c55e3
|
@ -10,7 +10,7 @@
|
|||
</button>
|
||||
|
||||
<!-- IMPORT EXPORT -->
|
||||
<taskana-administration-import-export [currentSelection]="selectionToImport" [parentComponent]="'workbaskets'"></taskana-administration-import-export>
|
||||
<taskana-administration-import-export *ngIf="workbasketListExpanded" [currentSelection]="selectionToImport" [parentComponent]="'workbaskets'"></taskana-administration-import-export>
|
||||
|
||||
<span class="workbasket-details__spacer" style="flex: 1 1 auto"> </span>
|
||||
|
||||
|
@ -29,9 +29,10 @@
|
|||
</button>
|
||||
|
||||
<div class="filter__filter-component-wrapper">
|
||||
<taskana-shared-filter [isExpanded]="isExpanded" (performFilter)="filtering($event)"></taskana-shared-filter>
|
||||
<taskana-shared-filter [isExpanded]="isExpanded"
|
||||
(performFilter)="filtering($event)"
|
||||
component="workbasket-list"
|
||||
(inputComponent)="setComponent($event)"></taskana-shared-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<taskana-shared-filter *ngIf="showFilter" (performFilter)="filtering($event)" component="workbasket-list" (inputComponent)="setComponent($event)"></taskana-shared-filter>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
padding: 16px 16px 20px;
|
||||
flex-wrap: wrap;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.workbasket-list-toolbar__action-toolbar {
|
||||
|
|
|
@ -19,6 +19,7 @@ import { WorkbasketService } from '../../../shared/services/workbasket/workbaske
|
|||
styleUrls: ['./workbasket-list-toolbar.component.scss']
|
||||
})
|
||||
export class WorkbasketListToolbarComponent implements OnInit {
|
||||
@Input() workbasketListExpanded: boolean = true;
|
||||
@Input() workbaskets: Array<WorkbasketSummary>;
|
||||
@Input() workbasketDefaultSortBy: string;
|
||||
@Output() performSorting = new EventEmitter<Sorting>();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<!-- TOOLBAR -->
|
||||
<section #wbToolbar class="workbasket-list__toolbar">
|
||||
<taskana-administration-workbasket-list-toolbar [workbaskets]="workbasketsSummary$ | async" (performFilter)="performFilter($event)"
|
||||
(performSorting)="performSorting($event)" [workbasketDefaultSortBy]="workbasketDefaultSortBy">
|
||||
(performSorting)="performSorting($event)" [workbasketDefaultSortBy]="workbasketDefaultSortBy" [workbasketListExpanded]="expanded">
|
||||
</taskana-administration-workbasket-list-toolbar>
|
||||
</section>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
[value]="workbasket.workbasketId">
|
||||
<div class="workbaskets-item__wrapper">
|
||||
|
||||
<div class="workbaskets-item__icon">
|
||||
<div class="workbaskets-item__icon" *ngIf="expanded">
|
||||
<taskana-administration-icon-type [type]="workbasket.type" size="large" tooltip="true" [selected]="workbasket.workbasketId === selectedId"></taskana-administration-icon-type>
|
||||
</div>
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
<p>
|
||||
<b>{{workbasket.name}}</b>, <i>{{workbasket.key}} </i>
|
||||
</p>
|
||||
<p>{{workbasket.description}} </p>
|
||||
<p style="max-height: 20px; overflow: hidden; text-overflow: ellipsis">{{workbasket.description}} </p>
|
||||
<p>{{workbasket.owner}} </p>
|
||||
</div>
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
|||
<taskana-shared-pagination
|
||||
[page]="(workbasketsSummaryRepresentation$ | async) ? (workbasketsSummaryRepresentation$ | async)?.page : (workbasketsSummaryRepresentation$ | async)"
|
||||
[type]="type"
|
||||
[expanded]="expanded"
|
||||
[numberOfItems]="(workbasketsSummary$ | async)?.length"
|
||||
(changePage)="changePage($event)">
|
||||
</taskana-shared-pagination>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
}
|
||||
.mat-list-item {
|
||||
height: 90px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.mat-list-single-selected-option {
|
||||
background-color: $green !important;
|
||||
|
@ -25,6 +26,7 @@
|
|||
}
|
||||
.workbaskets-item__info {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding: 8px 0;
|
||||
}
|
||||
p {
|
||||
|
|
|
@ -73,6 +73,7 @@ const requestInProgressServiceSpy = jest.fn().mockImplementation(
|
|||
class WorkbasketListToolbarStub {
|
||||
@Input() workbaskets: Array<WorkbasketSummary>;
|
||||
@Input() workbasketDefaultSortBy: string;
|
||||
@Input() workbasketListExpanded: boolean;
|
||||
@Output() performSorting = new EventEmitter<Sorting>();
|
||||
@Output() performFilter = new EventEmitter<Filter>();
|
||||
}
|
||||
|
@ -87,6 +88,7 @@ class IconTypeStub {
|
|||
class PaginationStub {
|
||||
@Input() page: Page;
|
||||
@Input() type: String;
|
||||
@Input() expanded: boolean;
|
||||
@Output() changePage = new EventEmitter<number>();
|
||||
@Input() numberOfItems: number;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
import { WorkbasketSummaryRepresentation } from 'app/shared/models/workbasket-summary-representation';
|
||||
|
@ -40,6 +40,7 @@ export class WorkbasketListComponent implements OnInit, OnDestroy {
|
|||
filterBy: Filter = new Filter({ name: '', owner: '', type: '', description: '', key: '' });
|
||||
requestInProgress: boolean;
|
||||
requestInProgressLocal = false;
|
||||
@Input() expanded: boolean;
|
||||
|
||||
@ViewChild('wbToolbar', { static: true })
|
||||
private toolbarElement: ElementRef;
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
<div class="workbasket-overview">
|
||||
<taskana-administration-workbasket-list></taskana-administration-workbasket-list>
|
||||
<div class="vertical-right-divider"></div>
|
||||
<taskana-administration-workbasket-details
|
||||
*ngIf="showDetail; else showEmptyPage"></taskana-administration-workbasket-details>
|
||||
|
||||
<div class="workbasket-overview__list" #workbasketList>
|
||||
<taskana-administration-workbasket-list [expanded]="expanded"></taskana-administration-workbasket-list>
|
||||
</div>
|
||||
|
||||
<div class="vertical-right-divider">
|
||||
<span class="workbasket-overview__toggle-view-button" (click)="toggleWidth()" #toggleButton>
|
||||
<mat-icon class="md-36" *ngIf="expanded">chevron_left</mat-icon>
|
||||
<mat-icon class="md-36" *ngIf="!expanded">chevron_right</mat-icon>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="workbasket-overview__details" *ngIf="showDetail; else showEmptyPage">
|
||||
<taskana-administration-workbasket-details></taskana-administration-workbasket-details>
|
||||
</div>
|
||||
|
||||
<ng-template #showEmptyPage>
|
||||
<div class="hidden-xs hidden-sm col-md-8 container-no-items">
|
||||
<div class="workbasket-overview__empty-page">
|
||||
<div class="center-block no-detail">
|
||||
<h3 class="grey">Select a workbasket</h3>
|
||||
<svg-icon class="img-responsive empty-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
|
||||
|
|
|
@ -4,10 +4,33 @@
|
|||
height: 100%;
|
||||
overflow: hidden;
|
||||
align-items: stretch;
|
||||
}
|
||||
taskana-administration-workbasket-list {
|
||||
min-width: 500px;
|
||||
}
|
||||
taskana-administration-workbasket-details {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
|
||||
&__toggle-view-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #cecece;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 50%;
|
||||
left: 480px;
|
||||
z-index: 10;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
&__list {
|
||||
min-width: 500px;
|
||||
width: 500px;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
&__details {
|
||||
flex-grow: 1;
|
||||
}
|
||||
&__empty-page {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { WorkbasketOverviewComponent } from './workbasket-overview.component';
|
||||
import { Component, DebugElement } from '@angular/core';
|
||||
import { Component, DebugElement, Input } from '@angular/core';
|
||||
import { Actions, NgxsModule, ofActionDispatched, Store } from '@ngxs/store';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { WorkbasketState } from '../../../shared/store/workbasket-store/workbasket.state';
|
||||
|
@ -17,6 +17,7 @@ import { StartupService } from '../../../shared/services/startup/startup.service
|
|||
import { TaskanaEngineService } from '../../../shared/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from '../../../shared/services/window/window.service';
|
||||
import { workbasketReadStateMock } from '../../../shared/store/mock-data/mock-store';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
const showDialogFn = jest.fn().mockReturnValue(true);
|
||||
const NotificationServiceSpy = jest.fn().mockImplementation(
|
||||
|
@ -47,7 +48,9 @@ const mockActivatedRouteNoParams = {
|
|||
};
|
||||
|
||||
@Component({ selector: 'taskana-administration-workbasket-list', template: '' })
|
||||
class WorkbasketListStub {}
|
||||
class WorkbasketListStub {
|
||||
@Input() expanded: boolean;
|
||||
}
|
||||
|
||||
@Component({ selector: 'taskana-administration-workbasket-details', template: '' })
|
||||
class WorkbasketDetailsStub {}
|
||||
|
@ -64,7 +67,12 @@ describe('WorkbasketOverviewComponent', () => {
|
|||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), NgxsModule.forRoot([WorkbasketState])],
|
||||
imports: [
|
||||
MatIconModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
|
||||
providers: [
|
||||
WorkbasketService,
|
||||
|
@ -124,7 +132,12 @@ describe('WorkbasketOverviewComponent Alternative Params ID', () => {
|
|||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), NgxsModule.forRoot([WorkbasketState])],
|
||||
imports: [
|
||||
MatIconModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
|
||||
providers: [
|
||||
WorkbasketService,
|
||||
|
@ -162,7 +175,12 @@ describe('WorkbasketOverviewComponent No Params', () => {
|
|||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), NgxsModule.forRoot([WorkbasketState])],
|
||||
imports: [
|
||||
MatIconModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([WorkbasketState])
|
||||
],
|
||||
declarations: [WorkbasketOverviewComponent, WorkbasketListStub, WorkbasketDetailsStub, SvgIconStub],
|
||||
providers: [
|
||||
WorkbasketService,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
@ -19,6 +19,10 @@ export class WorkbasketOverviewComponent implements OnInit {
|
|||
@Select(WorkbasketSelectors.selectedWorkbasket) selectedWorkbasket$: Observable<Workbasket>;
|
||||
destroy$ = new Subject<void>();
|
||||
routerParams: any;
|
||||
expanded = true;
|
||||
|
||||
@ViewChild('workbasketList') workbasketList: ElementRef;
|
||||
@ViewChild('toggleButton') toggleButton: ElementRef;
|
||||
|
||||
constructor(private route: ActivatedRoute, private store: Store) {}
|
||||
|
||||
|
@ -52,6 +56,20 @@ export class WorkbasketOverviewComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
toggleWidth() {
|
||||
if (this.workbasketList.nativeElement.offsetWidth === 250) {
|
||||
this.expanded = true;
|
||||
this.workbasketList.nativeElement.style.width = '500px';
|
||||
this.workbasketList.nativeElement.style.minWidth = '500px';
|
||||
this.toggleButton.nativeElement.style.left = '480px';
|
||||
} else {
|
||||
this.expanded = false;
|
||||
this.workbasketList.nativeElement.style.width = '250px';
|
||||
this.workbasketList.nativeElement.style.minWidth = '250px';
|
||||
this.toggleButton.nativeElement.style.left = '230px';
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
<div class="pagination">
|
||||
<mat-paginator [length]="page?.totalElements" [pageIndex]="pageSelected - 1 " hidePageSize="true" [pageSize]="page?.size" (page)="changeToPage($event)" showFirstLastButtons="true"></mat-paginator>
|
||||
<div class="pagination__go-to">
|
||||
<div class="pagination__go-to-label">Page: </div>
|
||||
<div class="pagination" #pagination>
|
||||
<mat-paginator class="pagination__mat-paginator" [length]="page?.totalElements" [pageIndex]="pageSelected - 1 "
|
||||
hidePageSize="true" [pageSize]="page?.size" (page)="changeToPage($event)" [showFirstLastButtons]="true"
|
||||
[ngClass]="
|
||||
{'pagination__mat-paginator--expanded': expanded,
|
||||
'pagination__mat-paginator--collapsed': !expanded }"></mat-paginator>
|
||||
<div class="pagination__go-to" *ngIf="expanded">
|
||||
<div class="pagination__go-to-label">Page:</div>
|
||||
<mat-form-field>
|
||||
<input #inputTypeAhead matInput type="text" [matAutocomplete]="auto" [(ngModel)]="value" name="accessId"
|
||||
(ngModelChange)="filter(value)"/>
|
||||
(ngModelChange)="filter(value)"/>
|
||||
<mat-autocomplete #autoComplete autoActiveFirstOption (optionSelected)="goToPage($event.option.value)"
|
||||
#auto="matAutocomplete">
|
||||
#auto="matAutocomplete">
|
||||
<mat-option *ngFor="let pageNumber of filteredPages" [value]="pageNumber">{{ pageNumber }}</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,26 +2,34 @@
|
|||
display: flex;
|
||||
max-width: 100%;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
mat-paginator {
|
||||
background-color: #fafafa;
|
||||
width: 70%;
|
||||
font-feature-settings: 'tnum';
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
//Original
|
||||
.pagination__go-to {
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
mat-form-field {
|
||||
width: 56px;
|
||||
margin: 6px 4px 0 4px;
|
||||
font-size: 12px;
|
||||
&__mat-paginator {
|
||||
background-color: #fafafa;
|
||||
font-feature-settings: 'tnum';
|
||||
font-variant-numeric: tabular-nums;
|
||||
&--expanded {
|
||||
width: 70%;
|
||||
}
|
||||
&--collapsed {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.pagination__go-to-label {
|
||||
margin: 0 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
&__go-to {
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
mat-form-field {
|
||||
width: 56px;
|
||||
margin: 6px 4px 0 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.pagination__go-to-label {
|
||||
margin: 0 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
}
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { Page } from 'app/shared/models/page';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
|
||||
|
@ -17,12 +27,17 @@ export class PaginationComponent implements OnInit, OnChanges {
|
|||
@Input()
|
||||
numberOfItems: number;
|
||||
|
||||
@Input()
|
||||
expanded: boolean = true;
|
||||
|
||||
@Output()
|
||||
changePage = new EventEmitter<number>();
|
||||
|
||||
@ViewChild(MatPaginator, { static: true })
|
||||
paginator: MatPaginator;
|
||||
|
||||
@ViewChild('pagination') paginationWrapper: ElementRef;
|
||||
|
||||
hasItems = true;
|
||||
pageSelected = 1;
|
||||
pageNumbers: number[];
|
||||
|
@ -30,6 +45,32 @@ export class PaginationComponent implements OnInit, OnChanges {
|
|||
value: number;
|
||||
|
||||
ngOnInit() {
|
||||
this.changeLabel();
|
||||
this.value = 1;
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const rangeLabel = this.paginationWrapper?.nativeElement?.querySelector('.mat-paginator-range-label');
|
||||
const container = this.paginationWrapper?.nativeElement?.querySelector('.mat-paginator-container');
|
||||
if (rangeLabel && container) {
|
||||
if (!this.expanded) {
|
||||
container.style.justifyContent = 'center';
|
||||
rangeLabel.style.display = 'none';
|
||||
} else {
|
||||
container.style.justifyContent = 'flex-end';
|
||||
rangeLabel.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.page && changes.page.currentValue) {
|
||||
this.pageSelected = changes.page.currentValue.number;
|
||||
}
|
||||
this.hasItems = this.numberOfItems > 0;
|
||||
if (changes.page) {
|
||||
this.updateGoto();
|
||||
}
|
||||
}
|
||||
|
||||
changeLabel() {
|
||||
// Custom label: EG. "1-7 of 21 workbaskets"
|
||||
// return `${start} - ${end} of ${length} workbaskets`;
|
||||
|
||||
|
@ -44,16 +85,6 @@ export class PaginationComponent implements OnInit, OnChanges {
|
|||
return `${start} - ${end} of ${length}`;
|
||||
}
|
||||
};
|
||||
this.value = 1;
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.page && changes.page.currentValue) {
|
||||
this.pageSelected = changes.page.currentValue.number;
|
||||
}
|
||||
this.hasItems = this.numberOfItems > 0;
|
||||
if (changes.page) {
|
||||
this.updateGoto();
|
||||
}
|
||||
}
|
||||
|
||||
changeToPage(event) {
|
||||
|
|
Loading…
Reference in New Issue