abstracted out the commonalities of attribute editing modals into a common component

pull/33/head
Chris Veilleux 2019-01-08 15:46:45 -06:00
parent 602622ff73
commit 7c2e1964fb
17 changed files with 191 additions and 228 deletions

View File

@ -0,0 +1,39 @@
<div mat-dialog-title class="mat-h2-primary">{{dialogTitle}}</div>
<div mat-dialog-content>
<div class="mat-body">{{dialogInstructions}}</div>
<mat-radio-group fxLayout="column" [(ngModel)]="dialogData">
<ng-container *ngFor="let possibleValue of possibleValues">
<!-- Radio buttons for pre-defined placements -->
<mat-radio-button *ngIf="possibleValue.preDefined" class="predefined-group" [value]="possibleValue.name">
{{possibleValue.name}}
</mat-radio-button>
<!-- Radio buttons for user-defined placements -->
<div *ngIf="!possibleValue.preDefined" fxLayout="row" fxLayoutAlign="space-between center">
<mat-radio-button [value]="possibleValue.name">
<mat-form-field [floatLabel]="'never'">
<input matInput class="user-defined-group" value="{{possibleValue.name}}">
</mat-form-field>
</mat-radio-button>
<button mat-icon-button [disableRipple]="true">
<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>
</button>
</div>
</ng-container>
<!-- Radio button to add a new user-defined group -->
<mat-radio-button>
<mat-form-field [floatLabel]="'never'">
<input matInput placeholder="Add {{dialogTitle}}">
</mat-form-field>
</mat-radio-button>
</mat-radio-group>
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onCancelClick()">CANCEL</button>
<button mat-button [mat-dialog-close]="dialogData" class="action-button">SAVE</button>
</div>

View File

@ -0,0 +1,13 @@
.predefined-group {
margin-bottom: 12px;
margin-top: 12px;
}
.mat-body{
margin-bottom: 16px;
width: 250px;
}
fa-icon {
margin-left: 16px;
}

View File

@ -0,0 +1,34 @@
import {Component, Input, OnInit} from '@angular/core';
import { MatDialogRef } from '@angular/material';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { DeviceAttribute } from '../device.service';
import { GeographyEditComponent } from './geography/geography-edit.component';
import { GroupEditComponent } from './group/group-edit.component';
import { PlacementEditComponent } from './placement/placement-edit.component';
@Component({
selector: 'account-device-attribute-edit',
templateUrl: './attr-edit.component.html',
styleUrls: ['./attr-edit.component.scss']
})
export class AttrEditComponent implements OnInit {
@Input() dialogData: string;
@Input() dialogInstructions: string;
@Input() dialogRef: MatDialogRef<GeographyEditComponent | GroupEditComponent | PlacementEditComponent>;
@Input() dialogTitle: string;
@Input() possibleValues: DeviceAttribute[];
public deleteIcon = faTrashAlt;
constructor() {
}
ngOnInit() {
}
onCancelClick(): void {
this.dialogRef.close();
}
}

View File

@ -1,35 +1,43 @@
<div mat-dialog-title class="mat-h2-primary">Geography</div> <account-device-attribute-edit
[dialogData]="data"
[dialogInstructions]="dialogInstructions"
[dialogRef]="dialogRef"
[dialogTitle]="'Geography'"
[possibleValues]="deviceGeographies"
>
</account-device-attribute-edit>
<!--<div mat-dialog-title class="mat-h2-primary">Geography</div>-->
<div mat-dialog-content> <!--<div mat-dialog-content>-->
<div class="mat-body"> <!--<div class="mat-body">-->
Groups are useful to organize multiple devices. You can reuse device names if they are in different groups. <!--Groups are useful to organize multiple devices. You can reuse device names if they are in different groups.-->
</div> <!--</div>-->
<mat-radio-group fxLayout="column" [(ngModel)]="data"> <!--<mat-radio-group fxLayout="column" [(ngModel)]="data">-->
<ng-container *ngFor="let geo of deviceGeographies"> <!--<ng-container *ngFor="let geo of deviceGeographies">-->
<!-- Radio buttons for user-defined groups --> <!--&lt;!&ndash; Radio buttons for user-defined groups &ndash;&gt;-->
<div fxLayout="row" fxLayoutAlign="space-between center"> <!--<div fxLayout="row" fxLayoutAlign="space-between center">-->
<mat-radio-button [value]="geo.name"> <!--<mat-radio-button [value]="geo.name">-->
<mat-form-field [floatLabel]="'never'"> <!--<mat-form-field [floatLabel]="'never'">-->
<input matInput value="{{geo.name}}"> <!--<input matInput value="{{geo.name}}">-->
</mat-form-field> <!--</mat-form-field>-->
</mat-radio-button> <!--</mat-radio-button>-->
<button mat-icon-button [disableRipple]="true"> <!--<button mat-icon-button [disableRipple]="true">-->
<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon> <!--<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>-->
</button> <!--</button>-->
</div> <!--</div>-->
</ng-container> <!--</ng-container>-->
<!-- Radio button to add a new user-defined group --> <!--&lt;!&ndash; Radio button to add a new user-defined group &ndash;&gt;-->
<mat-radio-button> <!--<mat-radio-button>-->
<mat-form-field [floatLabel]="'never'"> <!--<mat-form-field [floatLabel]="'never'">-->
<input matInput placeholder="Add Geographic Location"> <!--<input matInput placeholder="Add Geographic Location">-->
</mat-form-field> <!--</mat-form-field>-->
</mat-radio-button> <!--</mat-radio-button>-->
</mat-radio-group> <!--</mat-radio-group>-->
</div> <!--</div>-->
<div mat-dialog-actions align="end"> <!--<div mat-dialog-actions align="end">-->
<button mat-button (click)="onCancelClick()">CANCEL</button> <!--<button mat-button (click)="onCancelClick()">CANCEL</button>-->
<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button> <!--<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button>-->
</div> <!--</div>-->

View File

@ -1,13 +0,0 @@
.mat-body{
margin-bottom: 16px;
width: 250px;
}
.predefined-group {
margin-bottom: 12px;
margin-top: 12px;
}
fa-icon {
margin-left: 16px;
}

View File

@ -1,9 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { DeviceAttribute, DeviceService} from '../../device.service';
import { DevicePlacement, DeviceService} from '../../device.service';
@Component({ @Component({
selector: 'account-device-geography', selector: 'account-device-geography',
@ -11,8 +9,8 @@ import { DevicePlacement, DeviceService} from '../../device.service';
styleUrls: ['./geography-edit.component.scss'] styleUrls: ['./geography-edit.component.scss']
}) })
export class GeographyEditComponent implements OnInit { export class GeographyEditComponent implements OnInit {
public deleteIcon = faTrashAlt; public deviceGeographies: DeviceAttribute[];
public deviceGeographies; public dialogInstructions = '';
constructor( constructor(
private deviceService: DeviceService, private deviceService: DeviceService,
@ -24,8 +22,4 @@ export class GeographyEditComponent implements OnInit {
this.deviceGeographies = this.deviceService.deviceGeographies; this.deviceGeographies = this.deviceService.deviceGeographies;
} }
onCancelClick(): void {
this.dialogRef.close();
}
} }

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Device, DeviceGeography, DeviceService } from '../../device.service'; import { Device, DeviceAttribute, DeviceService } from '../../device.service';
import { GeographyEditComponent } from './geography-edit.component'; import { GeographyEditComponent } from './geography-edit.component';
@Component({ @Component({
@ -10,7 +10,7 @@ import { GeographyEditComponent } from './geography-edit.component';
}) })
export class GeographyViewComponent implements OnInit { export class GeographyViewComponent implements OnInit {
@Input() device: Device; @Input() device: Device;
public deviceGeographies: DeviceGeography[]; public deviceGeographies: DeviceAttribute[];
public dialog = GeographyEditComponent; public dialog = GeographyEditComponent;
constructor( private service: DeviceService) { constructor( private service: DeviceService) {

View File

@ -1,41 +1,8 @@
<div mat-dialog-title class="mat-h2-primary">Group</div> <account-device-attribute-edit
[dialogData]="data"
<div mat-dialog-content> [dialogInstructions]="dialogInstructions"
<div class="mat-body"> [dialogRef]="dialogRef"
Groups are useful to organize multiple devices. You can reuse device names if they are in different groups. [dialogTitle]="'Group'"
</div> [possibleValues]="deviceGroups"
<mat-radio-group fxLayout="column" [(ngModel)]="data"> >
<ng-container *ngFor="let group of deviceGroups"> </account-device-attribute-edit>
<!-- Radio buttons for pre-defined groups -->
<mat-radio-button *ngIf="!group.userDefined" class="predefined-group" [value]="group.name">
{{group.name}}
</mat-radio-button>
<!-- Radio buttons for user-defined groups -->
<div *ngIf="group.userDefined" fxLayout="row" fxLayoutAlign="space-between center">
<mat-radio-button [value]="group.name">
<mat-form-field [floatLabel]="'never'">
<input matInput value="{{group.name}}">
</mat-form-field>
</mat-radio-button>
<button mat-icon-button [disableRipple]="true">
<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>
</button>
</div>
</ng-container>
<!-- Radio button to add a new user-defined group -->
<mat-radio-button>
<mat-form-field [floatLabel]="'never'">
<input matInput placeholder="Add Custom Placement">
</mat-form-field>
</mat-radio-button>
</mat-radio-group>
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onCancelClick()">CANCEL</button>
<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button>
</div>

View File

@ -1,13 +0,0 @@
.mat-body{
margin-bottom: 16px;
width: 250px;
}
.predefined-group {
margin-bottom: 12px;
margin-top: 12px;
}
fa-icon {
margin-left: 16px;
}

View File

@ -1,9 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { DeviceAttribute, DeviceService} from '../../device.service';
import { DeviceGroup, DeviceService} from '../../device.service';
@Component({ @Component({
selector: 'account-device-group', selector: 'account-device-group',
@ -11,20 +9,17 @@ import { DeviceGroup, DeviceService} from '../../device.service';
styleUrls: ['./group-edit.component.scss'] styleUrls: ['./group-edit.component.scss']
}) })
export class GroupEditComponent implements OnInit { export class GroupEditComponent implements OnInit {
public deleteIcon = faTrashAlt; public deviceGroups: DeviceAttribute[];
public deviceGroups: DeviceGroup[]; public dialogInstructions = 'Groups are useful to organize multiple ' +
'devices. You can reuse device names if they are in different groups.';
constructor( constructor(
private deviceService: DeviceService, private deviceService: DeviceService,
public dialogRef: MatDialogRef<GroupEditComponent>, public dialogRef: MatDialogRef<GroupEditComponent>,
@Inject(MAT_DIALOG_DATA) public data: DeviceGroup) { @Inject(MAT_DIALOG_DATA) public data: DeviceAttribute) {
} }
ngOnInit() { ngOnInit() {
this.deviceGroups = this.deviceService.deviceGroups; this.deviceGroups = this.deviceService.deviceGroups;
} }
onCancelClick(): void {
this.dialogRef.close();
}
} }

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Device, DeviceGroup, DeviceService } from '../../device.service'; import { Device, DeviceAttribute, DeviceService } from '../../device.service';
import { GroupEditComponent } from './group-edit.component'; import { GroupEditComponent } from './group-edit.component';
@Component({ @Component({
@ -10,7 +10,7 @@ import { GroupEditComponent } from './group-edit.component';
}) })
export class GroupViewComponent implements OnInit { export class GroupViewComponent implements OnInit {
@Input() device: Device; @Input() device: Device;
public deviceGroups: DeviceGroup[]; public deviceGroups: DeviceAttribute[];
public dialog = GroupEditComponent; public dialog = GroupEditComponent;
constructor( private service: DeviceService) { constructor( private service: DeviceService) {

View File

@ -1,41 +1,8 @@
<div mat-dialog-title class="mat-h2-primary">Placement</div> <account-device-attribute-edit
[dialogData]="data"
<div mat-dialog-content> [dialogInstructions]="dialogInstructions"
<div class="mat-body"> [dialogRef]="dialogRef"
You can optionally indicate where a device is placed within a location. Field is informational only. [dialogTitle]="'Placement'"
</div> [possibleValues]="devicePlacements"
<mat-radio-group fxLayout="column" [(ngModel)]="data"> >
<ng-container *ngFor="let placement of devicePlacements"> </account-device-attribute-edit>
<!-- Radio buttons for pre-defined placements -->
<mat-radio-button *ngIf="!placement.userDefined" class="predefined-group" [value]="placement.name">
{{placement.name}}
</mat-radio-button>
<!-- Radio buttons for user-defined placements -->
<div *ngIf="placement.userDefined" fxLayout="row" fxLayoutAlign="space-between center">
<mat-radio-button [value]="placement.name">
<mat-form-field [floatLabel]="'never'">
<input matInput class="user-defined-group" value="{{placement.name}}">
</mat-form-field>
</mat-radio-button>
<button mat-icon-button [disableRipple]="true">
<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>
</button>
</div>
</ng-container>
<!-- Radio button to add a new user-defined group -->
<mat-radio-button>
<mat-form-field [floatLabel]="'never'">
<input matInput placeholder="Add Custom Placement">
</mat-form-field>
</mat-radio-button>
</mat-radio-group>
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onCancelClick()">CANCEL</button>
<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button>
</div>

View File

@ -1,13 +0,0 @@
.predefined-group {
margin-bottom: 12px;
margin-top: 12px;
}
.mat-body{
margin-bottom: 16px;
width: 250px;
}
fa-icon {
margin-left: 16px;
}

View File

@ -1,9 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core'; import { Component, Inject, OnInit } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { DeviceAttribute, DeviceService} from '../../device.service';
import { DevicePlacement, DeviceService} from '../../device.service';
@Component({ @Component({
@ -12,9 +10,9 @@ import { DevicePlacement, DeviceService} from '../../device.service';
styleUrls: ['./placement-edit.component.scss'] styleUrls: ['./placement-edit.component.scss']
}) })
export class PlacementEditComponent implements OnInit { export class PlacementEditComponent implements OnInit {
public devicePlacements: DeviceAttribute[];
public deleteIcon = faTrashAlt; public dialogInstructions = 'You can optionally indicate where a device is ' +
public devicePlacements: DevicePlacement[]; 'placed within a location. Field is informational only.';
constructor( constructor(
private deviceService: DeviceService, private deviceService: DeviceService,
@ -25,8 +23,4 @@ export class PlacementEditComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.devicePlacements = this.deviceService.devicePlacements; this.devicePlacements = this.deviceService.devicePlacements;
} }
onCancelClick(): void {
this.dialogRef.close();
}
} }

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import {Device, DevicePlacement, DeviceService} from '../../device.service'; import {Device, DeviceAttribute, DeviceService} from '../../device.service';
import { PlacementEditComponent } from './placement-edit.component'; import { PlacementEditComponent } from './placement-edit.component';
@Component({ @Component({
@ -10,7 +10,7 @@ import { PlacementEditComponent } from './placement-edit.component';
}) })
export class PlacementViewComponent implements OnInit { export class PlacementViewComponent implements OnInit {
@Input() device: Device; @Input() device: Device;
public devicePlacements: DevicePlacement[]; public devicePlacements: DeviceAttribute[];
public dialog = PlacementEditComponent; public dialog = PlacementEditComponent;
constructor( private service: DeviceService) { constructor( private service: DeviceService) {

View File

@ -17,6 +17,7 @@ import {
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { AttrEditComponent } from './attribute/attr-edit.component';
import { AttrViewComponent } from './attribute/attr-view.component'; import { AttrViewComponent } from './attribute/attr-view.component';
import { DeviceComponent } from './device.component'; import { DeviceComponent } from './device.component';
import { DeviceService } from './device.service'; import { DeviceService } from './device.service';
@ -30,6 +31,7 @@ import { RemoveComponent } from './remove/remove.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AttrEditComponent,
AttrViewComponent, AttrViewComponent,
DeviceComponent, DeviceComponent,
GeographyEditComponent, GeographyEditComponent,

View File

@ -1,30 +1,19 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
export interface DeviceGroup { export interface DeviceAttribute {
id?: string; id?: string;
name: string; name: string;
userDefined: boolean; preDefined: boolean;
}
export interface DeviceGeography {
id: string;
name: string;
}
export interface DevicePlacement {
id?: string;
name: string;
userDefined: boolean;
} }
export interface Device { export interface Device {
coreVersion: string; coreVersion: string;
enclosureVersion: string; enclosureVersion: string;
group: DeviceGroup; group: DeviceAttribute;
id: string; id: string;
location: DeviceGeography; location: DeviceAttribute;
name: string; name: string;
placement: DevicePlacement; placement: DeviceAttribute;
platform: string; platform: string;
} }
@ -36,62 +25,62 @@ export class DeviceService {
{ {
coreVersion: '18.08', coreVersion: '18.08',
enclosureVersion: '1.2.3', enclosureVersion: '1.2.3',
group: {id: '1', name: 'None', userDefined: false}, group: {id: '1', name: 'None', preDefined: true},
id: 'abc-def-ghi', id: 'abc-def-ghi',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST'}, location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Mark', name: 'Mark',
placement: {id: 'bbb-bbb-bbb', name: 'Living Room', userDefined: true}, placement: {id: 'bbb-bbb-bbb', name: 'Living Room', preDefined: false},
platform: 'mark-one' platform: 'mark-one'
}, },
{ {
coreVersion: '18.08', coreVersion: '18.08',
enclosureVersion: '1.2.3', enclosureVersion: '1.2.3',
group: {id: '1', name: 'None', userDefined: false}, group: {id: '1', name: 'None', preDefined: true},
id: 'bcd-efg-hij', id: 'bcd-efg-hij',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST'}, location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Marky Mark', name: 'Marky Mark',
placement: {id: 'bbb-bbb-bbb', name: 'Kitchen', userDefined: false}, placement: {id: 'bbb-bbb-bbb', name: 'Kitchen', preDefined: true},
platform: 'mark-two' platform: 'mark-two'
}, },
{ {
coreVersion: '18.08', coreVersion: '18.08',
enclosureVersion: '1.2.3', enclosureVersion: '1.2.3',
group: {id: '2', name: 'Parent House', userDefined: true}, group: {id: '2', name: 'Parent House', preDefined: false},
id: 'cde-fgh-ijk', id: 'cde-fgh-ijk',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST'}, location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'American Pie', name: 'American Pie',
placement: {id: 'ddd-ddd-ddd', name: 'Bedroom', userDefined: false}, placement: {id: 'ddd-ddd-ddd', name: 'Bedroom', preDefined: true},
platform: 'picroft' platform: 'picroft'
}, },
{ {
coreVersion: '18.08', coreVersion: '18.08',
enclosureVersion: '1.2.3', enclosureVersion: '1.2.3',
group: {id: '2', name: 'Parent House', userDefined: true}, group: {id: '2', name: 'Parent House', preDefined: false},
id: 'def-ghi-jkl', id: 'def-ghi-jkl',
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST'}, location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
name: 'Kappa Delta Epsilon', name: 'Kappa Delta Epsilon',
placement: {id: 'fff-fff-fff', name: 'Kitchen', userDefined: false}, placement: {id: 'fff-fff-fff', name: 'Kitchen', preDefined: true},
platform: 'kde' platform: 'kde'
} }
]; ];
public deviceGroups: DeviceGroup[] = [ public deviceGroups: DeviceAttribute[] = [
{ id: '1', name: 'None', userDefined: false}, { id: '1', name: 'None', preDefined: true},
{ id: null, name: 'Home', userDefined: false}, { id: null, name: 'Home', preDefined: true},
{ id: null, name: 'Office', userDefined: false}, { id: null, name: 'Office', preDefined: true},
{ id: '2', name: 'Parent House', userDefined: true} { id: '2', name: 'Parent House', preDefined: false}
]; ];
public devicePlacements: DevicePlacement[] = [ public devicePlacements: DeviceAttribute[] = [
{ id: '1', name: 'None', userDefined: false}, { id: '1', name: 'None', preDefined: true},
{ id: null, name: 'Bedroom', userDefined: false}, { id: null, name: 'Bedroom', preDefined: true},
{ id: null, name: 'Kitchen', userDefined: false}, { id: null, name: 'Kitchen', preDefined: true},
{ id: '2', name: 'Living Room', userDefined: true} { id: '2', name: 'Living Room', preDefined: false}
]; ];
public deviceGeographies: DeviceGeography[] = [ public deviceGeographies: DeviceAttribute[] = [
{id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST'}, {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
{id: 'a1b2-c3d4-e5f6', name: 'United Kingdom, ABCDE, BST'} {id: 'a1b2-c3d4-e5f6', name: 'United Kingdom, ABCDE, BST', preDefined: false}
]; ];
constructor() { } constructor() { }