Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show an overlay and deleting message when deleting from a card or table action. #2415

Merged
merged 11 commits into from
Jun 18, 2018
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CardNumberMetricComponent } from '../../../shared/components/cards/card-number-metric/card-number-metric.component';
import {
ServiceBrokerCardComponent,
} from '../../../shared/components/cards/service-broker-card/service-broker-card.component';
import {
ServiceRecentInstancesCardComponent,
} from '../../../shared/components/cards/service-recent-instances-card/service-recent-instances-card.component';
import {
ServiceSummaryCardComponent,
} from '../../../shared/components/cards/service-summary-card/service-summary-card.component';
import { TileGridComponent } from '../../../shared/components/tile/tile-grid/tile-grid.component';
import { TileGroupComponent } from '../../../shared/components/tile/tile-group/tile-group.component';
import { TileComponent } from '../../../shared/components/tile/tile/tile.component';
import { BaseTestModulesNoShared, BaseTestModules } from '../../../test-framework/cloud-foundry-endpoint-service.helper';
import { BaseTestModules } from '../../../test-framework/cloud-foundry-endpoint-service.helper';
import { ServicesService } from '../services.service';
import { ServicesServiceMock } from '../services.service.mock';
import { ServiceSummaryComponent } from './service-summary.component';
import { ServiceIconComponent } from '../../../shared/components/service-icon/service-icon.component';


describe('ServiceSummaryComponent', () => {
let component: ServiceSummaryComponent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '../../../../test-framework/cloud-foundry-endpoint-service.helper';
import { CloudFoundrySpaceServiceMock } from '../../../../test-framework/cloud-foundry-space.service.mock';
import { CardCfSpaceDetailsComponent } from './card-cf-space-details.component';
import { EntityMonitorFactory } from '../../../monitors/entity-monitor.factory.service';

describe('CardCfSpaceDetailsComponent', () => {
let component: CardCfSpaceDetailsComponent;
Expand All @@ -17,7 +18,8 @@ describe('CardCfSpaceDetailsComponent', () => {
declarations: [CardCfSpaceDetailsComponent, MetadataCardTestComponents],
imports: [...BaseTestModulesNoShared],
providers: [
{ provide: CloudFoundrySpaceService, useClass: CloudFoundrySpaceServiceMock }
{ provide: CloudFoundrySpaceService, useClass: CloudFoundrySpaceServiceMock },
EntityMonitorFactory
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { ServiceSummaryCardComponent } from './service-summary-card.component';
import { ServicesService } from '../../../../features/service-catalog/services.service';
import { ServicesServiceMock } from '../../../../features/service-catalog/services.service.mock';
import { BaseTestModulesNoShared, MetadataCardTestComponents } from '../../../../test-framework/cloud-foundry-endpoint-service.helper';
import { ServiceIconComponent } from '../../service-icon/service-icon.component';
import { BooleanIndicatorComponent } from '../../boolean-indicator/boolean-indicator.component';
import { AppChipsComponent } from '../../chips/chips.component';
import { ServicesService } from '../../../../features/service-catalog/services.service';
import { ServicesServiceMock } from '../../../../features/service-catalog/services.service.mock';
import { ServiceIconComponent } from '../../service-icon/service-icon.component';
import { ServiceSummaryCardComponent } from './service-summary-card.component';
import { EntityMonitorFactory } from '../../../monitors/entity-monitor.factory.service';


describe('ServiceSummaryCardComponent', () => {
let component: ServiceSummaryCardComponent;
Expand All @@ -24,6 +25,7 @@ describe('ServiceSummaryCardComponent', () => {
imports: [BaseTestModulesNoShared],
providers: [
{ provide: ServicesService, useClass: ServicesServiceMock },
EntityMonitorFactory
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class ListActionConfig<T> {

interface ICoreListDataSource<T> extends DataSource<T> {
rowsState?: Observable<RowsState>;
getRowState?(row: T): Observable<RowsState>;
getRowState?(row: T): Observable<RowState>;
trackBy(index: number, item: T);
}

Expand Down Expand Up @@ -88,12 +88,14 @@ export interface RowState {
message?: string;
blocked?: boolean;
highlighted?: boolean;
deleting?: boolean;
[customState: string]: any;
}

export const getDefaultRowState = (): RowState => ({
busy: false,
error: false,
blocked: false,
deleting: false,
message: null
});
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,7 @@ export abstract class ListDataSource<T, A = T> extends DataSource<T> implements
this.transformEntity = config.transformEntity;
this.isLocal = config.isLocal || false;
this.transformEntities = config.transformEntities;
this.rowsState = config.rowsState ? config.rowsState.pipe(
publishReplay(1), refCount()
) : observableOf({}).pipe(first());
this.rowsState = config.rowsState;
this.externalDestroy = config.destroy || (() => { });
this.addItem = this.getEmptyType();
this.entityKey = this.sourceScheme.key;
Expand All @@ -180,17 +178,6 @@ export abstract class ListDataSource<T, A = T> extends DataSource<T> implements
this.store.dispatch(this.action);
};
}
/**
* Will return the row state with default values filled in.
* @param row The data for the current row
*/
getRowState(row: T) {
return this.rowsState.pipe(
map(state => ({ ...getDefaultRowState(), ...(state[this.getRowUniqueId(row)] || {}) })),
distinctUntilChanged(),
publishReplay(1), refCount()
);
}

disconnect() {
this.pageSubscription.unsubscribe();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
<mat-card class="meta-card" [ngClass]="clickAction ? 'meta-card-pointer' : ''" (click)="clickAction ? clickAction() : null">
<div *ngIf="isDeleting$ | async" class="meta-card__deleting-overlay">
<div class="meta-card__deleting-overlay-inner">
<div class="meta-card__deleting-text">Deleting</div>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
</div>
<app-card-status *ngIf="status$" [status$]="status$">
</app-card-status>
<mat-card-header class="meta-card__header" *ngIf="title">
<ng-container *ngTemplateOutlet="title.content"></ng-container>
<div *ngIf="_actionMenu && (showMenu$ | async)" appClickStopPropagation>
<button mat-icon-button class="meta-card__header__button" color="basic" [matMenuTriggerFor]="menu">
<button mat-icon-button class="meta-card__header__button" color="basic" [matMenuTriggerFor]="menu" [disabled]="isDeleting$ | async">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu class="meta-card__header__popup" #menu="matMenu">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
flex-direction: column;
height: 100%;
width: 100%;
&__deleting-overlay {
align-items: center;
bottom: 0;
display: flex;
justify-content: center;
left: 0;
position: absolute;
right: 0;
top: 0;
&-inner {
width: 50%;
}
}
&__deleting-text {
margin-bottom: 5px;
text-align: center;
}
&__header {
align-content: center;
display: flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MetaCardComponent } from './meta-card.component';
import { SharedModule } from '../../../../../shared.module';
import { createBasicStoreModule } from '../../../../../../test-framework/store-test-helper';

describe('MetaCardComponent', () => {
let component: MetaCardComponent;
Expand All @@ -10,7 +11,8 @@ describe('MetaCardComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
SharedModule
SharedModule,
createBasicStoreModule()
]
})
.compileComponents();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import '~@angular/material/theming';
@mixin meta-card-component($theme, $app-theme) {
$background: map-get($theme, background);
.meta-card__deleting-overlay {
background: transparentize(mat-color($background, card), .2);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@

import {of as observableOf, Observable , combineLatest } from 'rxjs';
import { Component, ContentChild, ContentChildren, Input, QueryList } from '@angular/core';

import { combineLatest, Observable, of as observableOf } from 'rxjs';
import { map } from 'rxjs/operators';
import { EntityMonitorFactory } from '../../../../../monitors/entity-monitor.factory.service';
import { ComponentEntityMonitorConfig } from '../../../../../shared.types';
import { CardStatus } from '../../../../application-state/application-state.service';
import { MetaCardItemComponent } from '../meta-card-item/meta-card-item.component';
import { MetaCardTitleComponent } from '../meta-card-title/meta-card-title.component';
import { IPermissionConfigs } from '../../../../../../core/current-user-permissions.config';
import { map, tap } from 'rxjs/operators';


export interface MetaCardMenuItem {
icon?: string;
Expand All @@ -31,6 +32,20 @@ export class MetaCardComponent {
@Input('status$')
status$: Observable<CardStatus>;

@Input('entityConfig')
set entityConfig(entityConfig: ComponentEntityMonitorConfig) {
if (entityConfig) {
const entityMonitor = this.entityMonitorFactory.create(
entityConfig.guid,
entityConfig.schema.key,
entityConfig.schema
);
this.isDeleting$ = entityMonitor.isDeletingEntity$;
}
}

public isDeleting$: Observable<boolean> = observableOf(false);

@Input('actionMenu')
set actionMenu(actionMenu: MetaCardMenuItem[]) {
this._actionMenu = actionMenu.map(menuItem => {
Expand All @@ -50,7 +65,7 @@ export class MetaCardComponent {
@Input('clickAction')
clickAction: Function = null;

constructor() {
constructor(private entityMonitorFactory: EntityMonitorFactory) {
if (this.actionMenu) {
this.actionMenu = this.actionMenu.map(element => {
if (!element.disabled) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<div class="table-row-wrapper" [ngClass]="{'table-row-wrapper__blocked': isBlocked$ | async, 'table-row-wrapper__errored': inErrorState$ | async,'table-row-wrapper__highlighted': isHighlighted$ | async }">
<div *ngIf="isDeleting$ | async" class="table-row__deletion-bar-wrapper">
<div class="table-row__deletion-bar-inner">
<div class="table-row__deletion-bar-text">Deleting</div>
<mat-progress-bar class="table-row__deletion-bar" mode="indeterminate"></mat-progress-bar>
</div>
</div>
<div role="row" class="table-row">
<div class="mat-row table-row__inner">
<ng-container cdkCellOutlet></ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
cursor: not-allowed;
&__inner {
* {
opacity: .8;
opacity: .65;
}
}
}
Expand Down Expand Up @@ -32,6 +32,30 @@
border-width: 0 0 1px;
display: flex;
transition: opacity .25s;
&-wrapper {
position: relative;
}
&__deletion-bar {
&-inner {
flex: .5;
max-width: 200px;
}
&-text {
padding-bottom: 5px;
text-align: center;
}
&-wrapper {
align-items: center;
bottom: 0;
display: flex;
justify-content: center;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: 999;
}
}
&__error {
display: none;
justify-content: middle;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { TableRowComponent } from './table-row.component';
import { Observable, of as observableOf } from 'rxjs';
import { CoreModule } from '../../../../../core/core.module';
import { SharedModule } from '../../../../shared.module';
import { CdkTableModule } from '@angular/cdk/table';
import { setTimeout } from 'timers';
import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { of as observableOf } from 'rxjs';
import { CoreModule } from '../../../../../core/core.module';
import { TableRowComponent } from './table-row.component';


describe('TableRowComponent', () => {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ export class TableRowComponent extends CdkRow implements OnInit {
@Input('rowState')
rowState: Observable<RowState>;

private inErrorState$: Observable<boolean>;
private errorMessage$: Observable<string>;
private isBlocked$: Observable<boolean>;
private isHighlighted$: Observable<boolean>;
public inErrorState$: Observable<boolean>;
public errorMessage$: Observable<string>;
public isBlocked$: Observable<boolean>;
public isHighlighted$: Observable<boolean>;
public isDeleting$: Observable<boolean>;

ngOnInit() {
if (this.rowState) {
Expand All @@ -33,11 +34,14 @@ export class TableRowComponent extends CdkRow implements OnInit {
map(state => state.message)
);
this.isBlocked$ = this.rowState.pipe(
map(state => state.blocked)
map(state => state.blocked || state.deleting)
);
this.isHighlighted$ = this.rowState.pipe(
map(state => state.highlighted)
);
this.isDeleting$ = this.rowState.pipe(
map(state => state.deleting)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<app-meta-card class="app-service-card" [actionMenu]="cardMenu">
<app-meta-card class="app-service-card" [actionMenu]="cardMenu" [entityConfig]="entityConfig">
<app-meta-card-title>
<div class="app-service-card__title">
{{ (serviceInstance$ | async)?.entity.entity.name}}
Expand Down
Loading