TSK-196 Add accessItems saving feature.
This commit is contained in:
parent
e984773b02
commit
a7885a0830
|
@ -24,7 +24,7 @@ import { CategoriesadministrationComponent } from './categoriesadministration/ca
|
||||||
import { WorkbasketDistributiontargetsComponent } from './workbasket-distributiontargets/workbasket-distributiontargets.component';
|
import { WorkbasketDistributiontargetsComponent } from './workbasket-distributiontargets/workbasket-distributiontargets.component';
|
||||||
import { WorkbasketDetailsComponent } from './workbasket/details/workbasket-details.component';
|
import { WorkbasketDetailsComponent } from './workbasket/details/workbasket-details.component';
|
||||||
import { WorkbasketInformationComponent } from './workbasket/details/information/workbasket-information.component';
|
import { WorkbasketInformationComponent } from './workbasket/details/information/workbasket-information.component';
|
||||||
import { AuthorizationsComponent } from './workbasket/details/authorizations/authorizations.component';
|
import { AccessItemsComponent } from './workbasket/details/access-items/access-items.component';
|
||||||
import { NoAccessComponent } from './workbasket/noAccess/no-access.component';
|
import { NoAccessComponent } from './workbasket/noAccess/no-access.component';
|
||||||
import { SpinnerComponent } from './shared/spinner/spinner.component';
|
import { SpinnerComponent } from './shared/spinner/spinner.component';
|
||||||
import { FilterComponent } from './shared/filter/filter.component';
|
import { FilterComponent } from './shared/filter/filter.component';
|
||||||
|
@ -70,7 +70,7 @@ const DECLARATIONS = [
|
||||||
CategoriestreeComponent,
|
CategoriestreeComponent,
|
||||||
CategoryeditorComponent,
|
CategoryeditorComponent,
|
||||||
CategoriesadministrationComponent,
|
CategoriesadministrationComponent,
|
||||||
AuthorizationsComponent,
|
AccessItemsComponent,
|
||||||
WorkbasketDetailsComponent,
|
WorkbasketDetailsComponent,
|
||||||
WorkbasketDistributiontargetsComponent,
|
WorkbasketDistributiontargetsComponent,
|
||||||
MasterAndDetailComponent,
|
MasterAndDetailComponent,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Links } from "./links";
|
import { Links } from "./links";
|
||||||
|
|
||||||
export class WorkbasketAuthorization {
|
export class WorkbasketAccessItems {
|
||||||
constructor(
|
constructor(
|
||||||
public accessItemId: string = '',
|
public accessItemId: string = '',
|
||||||
public workbasketId: string = '',
|
public workbasketId: string = '',
|
|
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { HttpClientModule, HttpClient, HttpHeaders, HttpResponse, HttpErrorResponse } from '@angular/common/http';
|
import { HttpClientModule, HttpClient, HttpHeaders, HttpResponse, HttpErrorResponse } from '@angular/common/http';
|
||||||
import { WorkbasketSummary } from '../model/workbasketSummary';
|
import { WorkbasketSummary } from '../model/workbasketSummary';
|
||||||
import { Workbasket } from '../model/workbasket';
|
import { Workbasket } from '../model/workbasket';
|
||||||
import { WorkbasketAuthorization } from '../model/workbasket-authorization';
|
import { WorkbasketAccessItems } from '../model/workbasket-access-items';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
@ -51,7 +51,7 @@ export class WorkbasketService {
|
||||||
|
|
||||||
//#region "REST calls"
|
//#region "REST calls"
|
||||||
// GET
|
// GET
|
||||||
getWorkBasketsSummary( forceRequest: boolean = false,
|
getWorkBasketsSummary(forceRequest: boolean = false,
|
||||||
sortBy: string = this.KEY,
|
sortBy: string = this.KEY,
|
||||||
order: string = Direction.ASC,
|
order: string = Direction.ASC,
|
||||||
name: string = undefined,
|
name: string = undefined,
|
||||||
|
@ -63,22 +63,17 @@ export class WorkbasketService {
|
||||||
key: string = undefined,
|
key: string = undefined,
|
||||||
keyLike: string = undefined,
|
keyLike: string = undefined,
|
||||||
requiredPermission: string = undefined): Observable<WorkbasketSummary[]> {
|
requiredPermission: string = undefined): Observable<WorkbasketSummary[]> {
|
||||||
if(this.workbasketSummaryRef && !forceRequest){
|
if (this.workbasketSummaryRef && !forceRequest) {
|
||||||
return this.workbasketSummaryRef;
|
return this.workbasketSummaryRef;
|
||||||
}
|
}
|
||||||
return this.httpClient.get<WorkbasketSummary[]>(`${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(sortBy, order, name,
|
return this.httpClient.get<WorkbasketSummary[]>(`${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(sortBy, order, name,
|
||||||
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission)}`, this.httpOptions);
|
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission)}`, this.httpOptions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
getWorkBasket(url: string): Observable<Workbasket> {
|
getWorkBasket(url: string): Observable<Workbasket> {
|
||||||
return this.httpClient.get<Workbasket>(url, this.httpOptions);
|
return this.httpClient.get<Workbasket>(url, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getWorkBasket1(id: string): Observable<Workbasket> {
|
|
||||||
return this.httpClient.get<Workbasket>(environment.taskanaRestUrl + '/v1/workbaskets/' + id, this.httpOptions);
|
|
||||||
}
|
|
||||||
// POST
|
// POST
|
||||||
createWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
createWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
|
@ -95,22 +90,19 @@ export class WorkbasketService {
|
||||||
return this.httpClient.delete(environment.taskanaRestUrl + '/v1/workbaskets/' + id, this.httpOptions);
|
return this.httpClient.delete(environment.taskanaRestUrl + '/v1/workbaskets/' + id, this.httpOptions);
|
||||||
}
|
}
|
||||||
// GET
|
// GET
|
||||||
getWorkBasketAuthorizations(id: String): Observable<WorkbasketAuthorization[]> {
|
getWorkBasketAccessItems(id: String): Observable<WorkbasketAccessItems[]> {
|
||||||
return this.httpClient.get<WorkbasketAuthorization[]>(environment.taskanaRestUrl + '/v1/workbaskets/' + id + '/authorizations', this.httpOptions);
|
return this.httpClient.get<WorkbasketAccessItems[]>(environment.taskanaRestUrl + '/v1/workbaskets/' + id + '/workbasketAccessItems', this.httpOptions);
|
||||||
}
|
}
|
||||||
// POST
|
// POST
|
||||||
createWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization): Observable<WorkbasketAuthorization> {
|
createWorkBasketAccessItem(workbasketAccessItem: WorkbasketAccessItems): Observable<WorkbasketAccessItems> {
|
||||||
return this.httpClient.post<WorkbasketAuthorization>(environment.taskanaRestUrl + '/v1/workbaskets/authorizations', workbasketAuthorization, this.httpOptions);
|
return this.httpClient.post<WorkbasketAccessItems>(environment.taskanaRestUrl + '/v1/workbaskets/workbasketAccessItems', workbasketAccessItem, this.httpOptions);
|
||||||
}
|
}
|
||||||
// PUT
|
// PUT
|
||||||
updateWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization): Observable<WorkbasketAuthorization> {
|
updateWorkBasketAccessItem(url: string, workbasketAccessItem: Array<WorkbasketAccessItems>): Observable<string> {
|
||||||
return this.httpClient.put<WorkbasketAuthorization>(environment.taskanaRestUrl + '/v1/workbaskets/authorizations/' + workbasketAuthorization.accessId, workbasketAuthorization, this.httpOptions)
|
return this.httpClient.put<string>(url,
|
||||||
|
workbasketAccessItem,
|
||||||
|
this.httpOptions);
|
||||||
}
|
}
|
||||||
// DELETE
|
|
||||||
deleteWorkBasketAuthorization(workbasketAuthorization: WorkbasketAuthorization) {
|
|
||||||
return this.httpClient.delete(environment.taskanaRestUrl + '/v1/workbaskets/authorizations/' + workbasketAuthorization.accessId, this.httpOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region "Service extras"
|
//#region "Service extras"
|
||||||
|
@ -162,7 +154,7 @@ export class WorkbasketService {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError (error: Response | any) {
|
private handleError(error: Response | any) {
|
||||||
// In a real world app, you might use a remote logging infrastructure
|
// In a real world app, you might use a remote logging infrastructure
|
||||||
let errMsg: string;
|
let errMsg: string;
|
||||||
if (error instanceof Response) {
|
if (error instanceof Response) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
.footer{
|
.footer{
|
||||||
position: fixed;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="modal fade" #generalModal tabindex="-1" data-backdrop="static" data-keyboard="false" role="dialog" aria-labelledby="generalModalLabel">
|
<div class="modal fade" #generalModal tabindex="-1" data-backdrop="static" data-keyboard="false" role="dialog" aria-labelledby="generalModalLabel">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content word-break">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title" id="generalModalLabel">{{title}}</h4>
|
<h4 class="modal-title" id="generalModalLabel">{{title}}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
.word-break{word-break: break-all; }
|
|
@ -4,4 +4,8 @@ export class Utils {
|
||||||
static getSelfRef(links: Array<Links>) {
|
static getSelfRef(links: Array<Links>) {
|
||||||
return links.find(l => l.rel === 'self');
|
return links.find(l => l.rel === 'self');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getTagLinkRef(links: Array<Links>, tag: string) {
|
||||||
|
return links.find(l => l.rel === tag );
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
||||||
|
<taskana-general-message-modal *ngIf="modalErrorMessage" [message]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
||||||
|
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<button type="button" (click)="onSave()" class="btn btn-default btn-primary">Save</button>
|
||||||
|
<button type="button" (click)="clear()" class="btn btn-default">Undo changes</button>
|
||||||
|
</div>
|
||||||
|
<h4 class="panel-header">{{workbasket.name}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped table-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th class="text-align required-header">AccessID</th>
|
||||||
|
<th>Read</th>
|
||||||
|
<th>Open</th>
|
||||||
|
<th>Append</th>
|
||||||
|
<th>Transfer</th>
|
||||||
|
<th>Distribute</th>
|
||||||
|
<th>Custom1</th>
|
||||||
|
<th>Custom2</th>
|
||||||
|
<th>Custom3</th>
|
||||||
|
<th>Custom4</th>
|
||||||
|
<th>Custom5</th>
|
||||||
|
<th>Custom6</th>
|
||||||
|
<th>Custom7</th>
|
||||||
|
<th>Custom8</th>
|
||||||
|
<th>Custom9</th>
|
||||||
|
<th>Custom10</th>
|
||||||
|
<th>Custom11</th>
|
||||||
|
<th>Custom12</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let authorization of accessItems; let index = index;">
|
||||||
|
<td>
|
||||||
|
<button type="button" (click)="remove(index)" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
||||||
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td class="text-align text-width ">
|
||||||
|
<div class ="input-group"
|
||||||
|
[ngClass]="{
|
||||||
|
'has-warning': (accessItemsClone[index].accessId !== authorization.accessId),
|
||||||
|
'has-error': !authorization.accessId }">
|
||||||
|
<input type="text" class="form-control" [(ngModel)]="authorization.accessId">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permRead !== authorization.permRead)}">
|
||||||
|
<input type="checkbox" disabled="disabled" [(ngModel)]="authorization.permRead">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permOpen !== authorization.permOpen)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permOpen">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permAppend !== authorization.permAppend)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permAppend">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permTransfer !== authorization.permTransfer)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permTransfer">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permDistribute !== authorization.permDistribute)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permDistribute">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom1 !== authorization.permCustom1)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom1">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom2 !== authorization.permCustom2)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom2">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom3 !== authorization.permCustom3)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom3">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom4 !== authorization.permCustom4)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom4">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom5 !== authorization.permCustom5)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom5">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom6 !== authorization.permCustom6)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom6">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom7 !== authorization.permCustom7)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom7">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom8 !== authorization.permCustom8)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom8">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom9 !== authorization.permCustom9)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom9">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom10 !== authorization.permCustom10)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom10">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom11 !== authorization.permCustom11)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom11">
|
||||||
|
</td>
|
||||||
|
<td [ngClass]="{'has-changes': (accessItemsClone[index].permCustom12 !== authorization.permCustom12)}">
|
||||||
|
<input type="checkbox" [(ngModel)]="authorization.permCustom12">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<button type="button" (click)="addAccessItem()" class="btn btn-default">
|
||||||
|
<span><svg-icon class="green small" src="./assets/icons/wb-add.svg"></svg-icon></span>
|
||||||
|
Add new access
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -7,6 +7,10 @@ td > input[type="checkbox"] {
|
||||||
.text-width{
|
.text-width{
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
|
.required-header:after {
|
||||||
|
content:" *";
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
&.has-changes {
|
&.has-changes {
|
|
@ -10,17 +10,17 @@ import { AlertService } from '../../../services/alert.service';
|
||||||
import { GeneralMessageModalComponent } from '../../../shared/general-message-modal/general-message-modal.component';
|
import { GeneralMessageModalComponent } from '../../../shared/general-message-modal/general-message-modal.component';
|
||||||
import { Links } from '../../../model/links';
|
import { Links } from '../../../model/links';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { AuthorizationsComponent } from './authorizations.component';
|
import { AccessItemsComponent } from './access-items.component';
|
||||||
import { WorkbasketAuthorization } from '../../../model/workbasket-authorization';
|
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
|
||||||
|
|
||||||
describe('AuthorizationsComponent', () => {
|
describe('AccessItemsComponent', () => {
|
||||||
let component: AuthorizationsComponent;
|
let component: AccessItemsComponent;
|
||||||
let fixture: ComponentFixture<AuthorizationsComponent>;
|
let fixture: ComponentFixture<AccessItemsComponent>;
|
||||||
let workbasketService;
|
let workbasketService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [SpinnerComponent, AuthorizationsComponent, GeneralMessageModalComponent],
|
declarations: [SpinnerComponent, AccessItemsComponent, GeneralMessageModalComponent],
|
||||||
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
||||||
providers: [WorkbasketService, AlertService]
|
providers: [WorkbasketService, AlertService]
|
||||||
|
|
||||||
|
@ -29,11 +29,11 @@ describe('AuthorizationsComponent', () => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(AuthorizationsComponent);
|
fixture = TestBed.createComponent(AccessItemsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
component.workbasket = new Workbasket('1')
|
component.workbasket = new Workbasket('1')
|
||||||
workbasketService = TestBed.get(WorkbasketService);
|
workbasketService = TestBed.get(WorkbasketService);
|
||||||
spyOn(workbasketService, 'getWorkBasketAuthorizations').and.returnValue(Observable.of(new Array<WorkbasketAuthorization>(new WorkbasketAuthorization())));
|
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(Observable.of(new Array<WorkbasketAccessItems>(new WorkbasketAccessItems())));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { Component, OnInit, Input, AfterViewInit } from '@angular/core';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
import { Utils } from '../../../shared/utils/utils';
|
||||||
|
|
||||||
|
import { Workbasket } from '../../../model/workbasket';
|
||||||
|
import { WorkbasketAccessItems } from '../../../model/workbasket-access-items';
|
||||||
|
|
||||||
|
import { WorkbasketService } from '../../../services/workbasket.service';
|
||||||
|
import { AlertService, AlertModel, AlertType } from '../../../services/alert.service';
|
||||||
|
|
||||||
|
declare var $: any;
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-workbasket-access-items',
|
||||||
|
templateUrl: './access-items.component.html',
|
||||||
|
styleUrls: ['./access-items.component.scss']
|
||||||
|
})
|
||||||
|
export class AccessItemsComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
workbasket: Workbasket;
|
||||||
|
|
||||||
|
accessItems: Array<WorkbasketAccessItems>;
|
||||||
|
accessItemsClone: Array<WorkbasketAccessItems>;
|
||||||
|
accessItemsResetClone: Array<WorkbasketAccessItems>;
|
||||||
|
requestInProgress: boolean = false;
|
||||||
|
modalSpinner: boolean = true;
|
||||||
|
modalTitle: string;
|
||||||
|
modalErrorMessage: string;
|
||||||
|
accessItemsubscription: Subscription;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private workbasketService: WorkbasketService, private alertService: AlertService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.accessItemsubscription = this.workbasketService.getWorkBasketAccessItems(this.workbasket.workbasketId).subscribe( (accessItems: Array<WorkbasketAccessItems>) =>{
|
||||||
|
this.accessItems = accessItems;
|
||||||
|
this.accessItemsClone = this.cloneaccessItems(this.accessItems);
|
||||||
|
this.accessItemsResetClone = this.cloneaccessItems(this.accessItems);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
addAccessItem() {
|
||||||
|
this.accessItems.push(new WorkbasketAccessItems(undefined,this.workbasket.workbasketId, undefined, true));
|
||||||
|
this.accessItemsClone.push(new WorkbasketAccessItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.accessItems = this.cloneaccessItems(this.accessItemsResetClone);
|
||||||
|
this.accessItemsClone = this.cloneaccessItems(this.accessItemsResetClone);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(index: number) {
|
||||||
|
this.accessItems.splice(index,1);
|
||||||
|
this.accessItemsClone.splice(index,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
if(this.validateAccessItems()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.workbasketService.updateWorkBasketAccessItem(Utils.getTagLinkRef(this.accessItems[0].links, 'setWorkbasketAccessItems').href, this.accessItems).subscribe(response =>{
|
||||||
|
this.accessItemsClone = this.cloneaccessItems(this.accessItems);
|
||||||
|
this.accessItemsResetClone = this.cloneaccessItems(this.accessItems);
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Workbasket ${this.workbasket.key} Access items were saved successfully`))
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
this.modalErrorMessage = error.message;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateAccessItems(): boolean {
|
||||||
|
return this.accessItems.some(element => {
|
||||||
|
if(!element.accessId || element.accessId === '') {
|
||||||
|
this.showValidationError();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private showValidationError() {
|
||||||
|
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, "AccessId must not be empty", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private cloneaccessItems(inputAuthorization): Array<WorkbasketAccessItems>{
|
||||||
|
let authorizationClone = new Array<WorkbasketAccessItems>();
|
||||||
|
inputAuthorization.forEach(authorization => {
|
||||||
|
authorizationClone.push({... authorization});
|
||||||
|
});
|
||||||
|
return authorizationClone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ngOnDestroy(): void {
|
||||||
|
if (this.accessItemsubscription) { this.accessItemsubscription.unsubscribe(); }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,171 +0,0 @@
|
||||||
<taskana-spinner [isRunning]="requestInProgress" [isModal]="modalSpinner" class="centered-horizontally floating"></taskana-spinner>
|
|
||||||
<taskana-general-message-modal *ngIf="modalErrorMessage" [message]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
|
|
||||||
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<div class="btn-group pull-right">
|
|
||||||
<button type="button" (click)="clear()" class="btn btn-default">Undo changes</button>
|
|
||||||
</div>
|
|
||||||
<h4 class="panel-header">{{workbasket.name}}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<table class="table table-striped table-center">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th class="text-align">AccessID</th>
|
|
||||||
<th>Read</th>
|
|
||||||
<th>Open</th>
|
|
||||||
<th>Append</th>
|
|
||||||
<th>Transfer</th>
|
|
||||||
<th>Distribute</th>
|
|
||||||
<th>Custom1</th>
|
|
||||||
<th>Custom2</th>
|
|
||||||
<th>Custom3</th>
|
|
||||||
<th>Custom4</th>
|
|
||||||
<th>Custom5</th>
|
|
||||||
<th>Custom6</th>
|
|
||||||
<th>Custom7</th>
|
|
||||||
<th>Custom8</th>
|
|
||||||
<th>Custom9</th>
|
|
||||||
<th>Custom10</th>
|
|
||||||
<th>Custom11</th>
|
|
||||||
<th>Custom12</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<span class="input-group-btn">
|
|
||||||
<button type="button" (click)="addAuthorization()" class="btn btn-default">
|
|
||||||
<svg-icon class="green small" src="./assets/icons/wb-add.svg"></svg-icon>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td class="text-align">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" id="au-add-work-basket" [(ngModel)]="newAuthorization.accessId" placeholder="Add authorization">
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permRead">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permOpen">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permAppend">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permTransfer">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permDistribute">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom1">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom2">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom3">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom4">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom5">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom6">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom7">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom8">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom9">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom10">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom11">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" [(ngModel)]="newAuthorization.permCustom12">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr *ngFor="let authorization of authorizations; let index = index;">
|
|
||||||
<td>
|
|
||||||
<button type="button" *ngIf="!authorizationState[index]" (click)="remove(index)" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
|
||||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
<button type="button" *ngIf="authorizationState[index]" (click)="save(index)" data-toggle="tooltip" title="Save" class="btn btn-default brown">
|
|
||||||
<span class="glyphicon glyphicon-floppy-remove" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
<td class="text-align text-width">
|
|
||||||
<div class="input-group {{(authorizationsClone[index].accessId !== authorization.accessId)? 'has-warning': ''}}">
|
|
||||||
<input type="text" class="form-control"
|
|
||||||
(change)="checkAuthorizationState(index);" [(ngModel)]="authorization.accessId">
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permRead !== authorization.permRead)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permRead">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permOpen !== authorization.permOpen)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permOpen">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permAppend !== authorization.permAppend)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permAppend">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permTransfer !== authorization.permTransfer)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permTransfer">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permDistribute !== authorization.permDistribute)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permDistribute">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom1 !== authorization.permCustom1)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom1">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom2 !== authorization.permCustom2)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom2">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom3 !== authorization.permCustom3)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom3">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom4 !== authorization.permCustom4)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom4">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom5 !== authorization.permCustom5)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom5">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom6 !== authorization.permCustom6)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom6">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom7 !== authorization.permCustom7)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom7">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom8 !== authorization.permCustom8)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom8">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom9 !== authorization.permCustom9)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom9">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom10 !== authorization.permCustom10)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom10">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom11 !== authorization.permCustom11)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom11">
|
|
||||||
</td>
|
|
||||||
<td class ="{{(authorizationsClone[index].permCustom12 !== authorization.permCustom12)? 'has-changes': ''}}">
|
|
||||||
<input type="checkbox" (change)="checkAuthorizationState(index)" [(ngModel)]="authorization.permCustom12">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,91 +0,0 @@
|
||||||
import { Component, OnInit, Input } from '@angular/core';
|
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
|
|
||||||
import { Workbasket } from '../../../model/workbasket';
|
|
||||||
import { WorkbasketAuthorization } from '../../../model/workbasket-authorization';
|
|
||||||
|
|
||||||
import { WorkbasketService } from '../../../services/workbasket.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'taskana-workbasket-authorizations',
|
|
||||||
templateUrl: './authorizations.component.html',
|
|
||||||
styleUrls: ['./authorizations.component.scss']
|
|
||||||
})
|
|
||||||
export class AuthorizationsComponent implements OnInit {
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
workbasket: Workbasket;
|
|
||||||
|
|
||||||
authorizations: Array<WorkbasketAuthorization>;
|
|
||||||
authorizationsClone: Array<WorkbasketAuthorization>;
|
|
||||||
authorizationsResetClone: Array<WorkbasketAuthorization>;
|
|
||||||
newAuthorization: WorkbasketAuthorization = new WorkbasketAuthorization();
|
|
||||||
authorizationState: Array<boolean>;
|
|
||||||
requestInProgress: boolean = false;
|
|
||||||
modalSpinner: boolean = true;
|
|
||||||
modalTitle: string;
|
|
||||||
modalErrorMessage: string;
|
|
||||||
authorizationSubscription: Subscription;
|
|
||||||
|
|
||||||
constructor(private workbasketService: WorkbasketService) { }
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.authorizationSubscription = this.workbasketService.getWorkBasketAuthorizations(this.workbasket.workbasketId).subscribe( (authorizations: Array<WorkbasketAuthorization>) =>{
|
|
||||||
this.authorizations = authorizations;
|
|
||||||
this.authorizationsClone = this.cloneAuthorizations(this.authorizations);
|
|
||||||
this.authorizationsResetClone = this.cloneAuthorizations(this.authorizations);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
addAuthorization(){
|
|
||||||
this.authorizations.push({...this.newAuthorization});
|
|
||||||
this.authorizationsClone.push({...this.newAuthorization});
|
|
||||||
this.authorizationState.push(false);
|
|
||||||
this.newAuthorization = new WorkbasketAuthorization();
|
|
||||||
}
|
|
||||||
|
|
||||||
authorizationToggle(index: number) {
|
|
||||||
this.checkAuthorizationState(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.authorizations = this.cloneAuthorizations(this.authorizationsResetClone);
|
|
||||||
this.authorizationsClone = this.cloneAuthorizations(this.authorizationsResetClone);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(index: number) {
|
|
||||||
this.authorizations.splice(index,1);
|
|
||||||
this.authorizationsClone.splice(index,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(index: number) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private resetAuthorizationsState() {
|
|
||||||
this.authorizationState = new Array<boolean>(this.authorizations.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private checkAuthorizationState(index: number) {
|
|
||||||
this.authorizationState[index] = false;
|
|
||||||
Object.keys(this.authorizations[index]).forEach(key =>{
|
|
||||||
if(this.authorizations[index][key]!== this.authorizationsClone[index][key]){
|
|
||||||
this.authorizationState[index] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private cloneAuthorizations(inputAuthorization): Array<WorkbasketAuthorization>{
|
|
||||||
let authorizationClone = new Array<WorkbasketAuthorization>();
|
|
||||||
inputAuthorization.forEach(authorization => {
|
|
||||||
authorizationClone.push({... authorization});
|
|
||||||
});
|
|
||||||
this.resetAuthorizationsState();
|
|
||||||
return authorizationClone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ngOnDestroy(): void {
|
|
||||||
if (this.authorizationSubscription) { this.authorizationSubscription.unsubscribe(); }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@
|
||||||
<a href="#work-baskets" aria-controls="work baskets" role="tab" data-toggle="tab" aria-expanded="true">Information</a>
|
<a href="#work-baskets" aria-controls="work baskets" role="tab" data-toggle="tab" aria-expanded="true">Information</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="inactive">
|
<li role="presentation" class="inactive">
|
||||||
<a href="#authorizations" aria-controls="Authorizations" role="tab" data-toggle="tab" aria-expanded="true">Authorizations</a>
|
<a href="#access-items" aria-controls="Acccess" role="tab" data-toggle="tab" aria-expanded="true">Access</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="inactive">
|
<li role="presentation" class="inactive">
|
||||||
<a href="#distribution-targets" aria-controls="distribution targets" role="tab" data-toggle="tab" aria-expanded="true">Distribution targets</a>
|
<a href="#distribution-targets" aria-controls="distribution targets" role="tab" data-toggle="tab" aria-expanded="true">Distribution targets</a>
|
||||||
|
@ -20,8 +20,8 @@
|
||||||
<div role="tabpanel" class="tab-pane active" id="work-baskets">
|
<div role="tabpanel" class="tab-pane active" id="work-baskets">
|
||||||
<workbasket-information [workbasket]="workbasket"></workbasket-information>
|
<workbasket-information [workbasket]="workbasket"></workbasket-information>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane inactive" id="authorizations">
|
<div role="tabpanel" class="tab-pane inactive" id="access-items">
|
||||||
<taskana-workbasket-authorizations [workbasket]="workbasket"></taskana-workbasket-authorizations>
|
<taskana-workbasket-access-items [workbasket]="workbasket"></taskana-workbasket-access-items>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane inactive" id="distribution-targets">
|
<div role="tabpanel" class="tab-pane inactive" id="distribution-targets">
|
||||||
<!-- <taskana-workbasket-distributiontargets [workbasket]="workbasket"></taskana-workbasket-distributiontargets>-->
|
<!-- <taskana-workbasket-distributiontargets [workbasket]="workbasket"></taskana-workbasket-distributiontargets>-->
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { WorkbasketDetailsComponent } from './workbasket-details.component';
|
import { WorkbasketDetailsComponent } from './workbasket-details.component';
|
||||||
import { NoAccessComponent } from '../noAccess/no-access.component';
|
import { NoAccessComponent } from '../noAccess/no-access.component';
|
||||||
import { WorkbasketInformationComponent } from './information/workbasket-information.component';
|
import { WorkbasketInformationComponent } from './information/workbasket-information.component';
|
||||||
import { AuthorizationsComponent } from './authorizations/authorizations.component';
|
import { AccessItemsComponent } from './access-items/access-items.component';
|
||||||
import { Workbasket } from 'app/model/workbasket';
|
import { Workbasket } from 'app/model/workbasket';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { SpinnerComponent } from '../../shared/spinner/spinner.component';
|
import { SpinnerComponent } from '../../shared/spinner/spinner.component';
|
||||||
|
@ -35,7 +35,7 @@ describe('WorkbasketDetailsComponent', () => {
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports:[RouterTestingModule, FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
imports:[RouterTestingModule, FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule],
|
||||||
declarations: [ WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent, IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AuthorizationsComponent ],
|
declarations: [ WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent, IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent ],
|
||||||
providers:[WorkbasketService, MasterAndDetailService, PermissionService, AlertService]
|
providers:[WorkbasketService, MasterAndDetailService, PermissionService, AlertService]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
|
@ -190,10 +190,6 @@ li > div.row > dl {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-center > tbody >tr:first-child >td {
|
|
||||||
border-bottom: 2px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.remove {
|
.btn.remove {
|
||||||
color: crimson;
|
color: crimson;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,5 @@
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue