TSK-736 Reimplement workplace module according to taskana UI

This commit is contained in:
Martin Rojas Miguel Angel 2018-10-31 16:41:58 +01:00 committed by Holger Hagen
parent 9c1fa6dfe2
commit cc675e324b
50 changed files with 1003 additions and 808 deletions

View File

@ -1,14 +1,13 @@
<div class="container-scrollable"> <div class="container-scrollable">
<taskana-spinner [isRunning]="requestInProgress" class="floating" (spinnerIsRunning)="spinnerRunning($event)"></taskana-spinner> <taskana-spinner [isRunning]="requestInProgress" class="floating" (spinnerIsRunning)="spinnerRunning($event)"></taskana-spinner>
<div id="classification-details" *ngIf="classification && !spinnerIsRunning"> <div id="classification-details" *ngIf="classification && !spinnerIsRunning">
<ul class="nav nav-tabs" role="tablist">
<li *ngIf="showDetail" class="visible-xs visible-sm hidden">
<a (click)="backClicked()">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back</a>
</li>
</ul>
<div id="classification" class="panel panel-default classification"> <div id="classification" class="panel panel-default classification">
<div class="panel-heading"> <div class="panel-heading">
<div *ngIf="showDetail" class="pull-left btn-group align-header">
<button (click)="backClicked()" class="btn btn-default no-style blue visible-xs visible-sm hidden">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back
</button>
</div>
<div class="pull-right btn-group"> <div class="pull-right btn-group">
<button type="button" (click)="onSubmit()" class="btn btn-default btn-primary" data-toggle="tooltip" title="Save"> <button type="button" (click)="onSubmit()" class="btn btn-default btn-primary" data-toggle="tooltip" title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span> <span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
@ -18,6 +17,7 @@
</button> </button>
<button type="button" (click)="removeClassification()" data-toggle="tooltip" title="Remove" class="btn btn-default remove"> <button type="button" (click)="removeClassification()" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button> </button>
</div> </div>
<h4 class="panel-header">{{classification.name}}&nbsp; [{{classification.type}}] <h4 class="panel-header">{{classification.name}}&nbsp; [{{classification.type}}]
@ -29,54 +29,62 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group required"> <div class="form-group required">
<label for="classification-key" class="control-label">Key</label> <label for="classification-key" class="control-label">Key</label>
<input type="text" required #key="ngModel" [disabled]="action!== 'CREATE'? true : false" class="form-control" id="classification-key" <input type="text" required #key="ngModel" [disabled]="action!== 'CREATE'? true : false" class="form-control"
placeholder="Key" [(ngModel)]="classification.key" name="classification.key"> id="classification-key" placeholder="Key" [(ngModel)]="classification.key" name="classification.key">
<taskana-field-error-display *ngIf="action === 'CREATE'" [displayError]="!isFieldValid('classification.key')" [validationTrigger]="this.toogleValidationMap.get('classification.key')" <taskana-field-error-display *ngIf="action === 'CREATE'" [displayError]="!isFieldValid('classification.key')"
errorMessage="* Key is required"> [validationTrigger]="this.toogleValidationMap.get('classification.key')" errorMessage="* Key is required">
</taskana-field-error-display> </taskana-field-error-display>
</div> </div>
<div class="form-group required"> <div class="form-group required">
<label for="classification-name" class="control-label">Name</label> <label for="classification-name" class="control-label">Name</label>
<input type="text" required #name="ngModel" class="form-control" id="classification-name" placeholder="Name" [(ngModel)]="classification.name" <input type="text" required #name="ngModel" class="form-control" id="classification-name" placeholder="Name"
name="classification.name"> [(ngModel)]="classification.name" name="classification.name">
<taskana-field-error-display [displayError]="!isFieldValid('classification.name')" [validationTrigger]="this.toogleValidationMap.get('classification.name')" <taskana-field-error-display [displayError]="!isFieldValid('classification.name')" [validationTrigger]="this.toogleValidationMap.get('classification.name')"
errorMessage="* Name is required"> errorMessage="* Name is required">
</taskana-field-error-display> </taskana-field-error-display>
</div> </div>
<div class="form-group"> <div class="row">
<label for="classification-domain" class="control-label">Domain</label>
<input type="text" disabled #domain="ngModel" class="form-control" id="classification-domain" placeholder="Domain" [(ngModel)]="classification.domain" <div class="form-group col-xs-6 required">
name="classification.domain"> <label for="classification-category" class="control-label">Category</label>
<div class="input-group">
<div class="input-group-btn">
<button class="btn btn-default vertical-align" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
<span class="text-top ">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(classification.category).name}}"
data-toggle="tooltip" [title]="getCategoryIcon(classification.category).text"></svg-icon>
</span>
{{classification.category}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu " aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let category of categories" (click)="selectCategory(category)">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(category).name}}" data-toggle="tooltip"
[title]="getCategoryIcon(category).text"></svg-icon>
</span>
{{category}}
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="form-group col-xs-6">
<label for="classification-domain" class="control-label">Domain</label>
<input type="text" disabled #domain="ngModel" class="form-control" id="classification-domain"
placeholder="Domain" [(ngModel)]="classification.domain" name="classification.domain">
<a *ngIf="!masterDomainSelected()" (click)="validChanged()"> <a *ngIf="!masterDomainSelected()" (click)="validChanged()">
<label> <label>
<b>Valid in Domain:</b> <b>Valid in Domain:</b>
<span class="glyphicon {{classification.isValidInDomain ? 'glyphicon-check': 'glyphicon-unchecked'}} blue" <span class="glyphicon {{classification.isValidInDomain ? 'glyphicon-check': 'glyphicon-unchecked'}} blue"
aria-hidden="true"></span> aria-hidden="true"></span>
</label> </label>
</a> </a>
</div>
<div class="form-group required">
<label for="classification-category" class="control-label">Category</label>
<div class="dropdown clearfix btn-group">
<button class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(classification.category).name}}" data-toggle="tooltip" [title]="getCategoryIcon(classification.category).text"></svg-icon>
</span>
{{classification.category}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let category of categories" (click)="selectCategory(category)">
<span class="text-top">
<svg-icon class="blue fa-fw" src="{{getCategoryIcon(category).name}}" data-toggle="tooltip" [title]="getCategoryIcon(category).text"></svg-icon>
</span>
{{category}}
</a>
</li>
</ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -86,8 +94,8 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="classification-service-level" class="control-label">Service Level</label> <label for="classification-service-level" class="control-label">Service Level</label>
<input type="text" class="form-control" id="classification-service-level" placeholder="Service Level" [(ngModel)]="classification.serviceLevel" <input type="text" class="form-control" id="classification-service-level" placeholder="Service Level"
name="classification.serviceLevel"> [(ngModel)]="classification.serviceLevel" name="classification.serviceLevel">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="classification-application-entry-point" class="control-label">Application entry point</label> <label for="classification-application-entry-point" class="control-label">Application entry point</label>
@ -96,50 +104,50 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="classification-description" class="control-label">Description</label> <label for="classification-description" class="control-label">Description</label>
<textarea class="form-control" rows="5" id="classification-description" placeholder="Description" [(ngModel)]="classification.description" <textarea class="form-control" rows="5" id="classification-description" placeholder="Description"
name="classification.description"></textarea> [(ngModel)]="classification.description" name="classification.description"></textarea>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div *ngIf="custom1Field.visible" class="form-group"> <div *ngIf="custom1Field.visible" class="form-group">
<label for="classification-custom-1" class="control-label">{{custom1Field.field}}</label> <label for="classification-custom-1" class="control-label">{{custom1Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-1" placeholder="{{custom1Field.field}}" [(ngModel)]="classification.custom1" <input type="text" class="form-control" id="classification-custom-1" placeholder="{{custom1Field.field}}"
name="classification.custom1"> [(ngModel)]="classification.custom1" name="classification.custom1">
</div> </div>
<div *ngIf="custom2Field.visible" class="form-group"> <div *ngIf="custom2Field.visible" class="form-group">
<label for="classification-custom-2" class="control-label">{{custom2Field.field}}</label> <label for="classification-custom-2" class="control-label">{{custom2Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-2" placeholder="{{custom2Field.field}}" [(ngModel)]="classification.custom2" <input type="text" class="form-control" id="classification-custom-2" placeholder="{{custom2Field.field}}"
name="classification.custom2"> [(ngModel)]="classification.custom2" name="classification.custom2">
</div> </div>
<div *ngIf="custom3Field.visible" class="form-group"> <div *ngIf="custom3Field.visible" class="form-group">
<label for="classification-custom-3" class="control-label">{{custom3Field.field}}</label> <label for="classification-custom-3" class="control-label">{{custom3Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-3" placeholder="{{custom3Field.field}}" [(ngModel)]="classification.custom3" <input type="text" class="form-control" id="classification-custom-3" placeholder="{{custom3Field.field}}"
name="classification.custom3"> [(ngModel)]="classification.custom3" name="classification.custom3">
</div> </div>
<div *ngIf="custom4Field.visible" class="form-group"> <div *ngIf="custom4Field.visible" class="form-group">
<label for="classification-custom-4" class="control-label">{{custom4Field.field}}</label> <label for="classification-custom-4" class="control-label">{{custom4Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-4" placeholder="{{custom4Field.field}}" [(ngModel)]="classification.custom4" <input type="text" class="form-control" id="classification-custom-4" placeholder="{{custom4Field.field}}"
name="classification.custom4"> [(ngModel)]="classification.custom4" name="classification.custom4">
</div> </div>
<div *ngIf="custom5Field.visible" class="form-group"> <div *ngIf="custom5Field.visible" class="form-group">
<label for="classification-custom-5" class="control-label">{{custom5Field.field}}</label> <label for="classification-custom-5" class="control-label">{{custom5Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-5" placeholder="{{custom5Field.field}}" [(ngModel)]="classification.custom5" <input type="text" class="form-control" id="classification-custom-5" placeholder="{{custom5Field.field}}"
name="classification.custom5"> [(ngModel)]="classification.custom5" name="classification.custom5">
</div> </div>
<div *ngIf="custom6Field.visible" class="form-group"> <div *ngIf="custom6Field.visible" class="form-group">
<label for="classification-custom-6" class="control-label">{{custom6Field.field}}</label> <label for="classification-custom-6" class="control-label">{{custom6Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-6" placeholder="{{custom6Field.field}}" [(ngModel)]="classification.custom6" <input type="text" class="form-control" id="classification-custom-6" placeholder="{{custom6Field.field}}"
name="classification.custom6"> [(ngModel)]="classification.custom6" name="classification.custom6">
</div> </div>
<div *ngIf="custom7Field.visible" class="form-group"> <div *ngIf="custom7Field.visible" class="form-group">
<label for="classification-custom-7" class="control-label">{{custom7Field.field}}</label> <label for="classification-custom-7" class="control-label">{{custom7Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-7" placeholder="{{custom7Field.field}}" [(ngModel)]="classification.custom7" <input type="text" class="form-control" id="classification-custom-7" placeholder="{{custom7Field.field}}"
name="classification.custom7"> [(ngModel)]="classification.custom7" name="classification.custom7">
</div> </div>
<div *ngIf="custom8Field.visible" class="form-group"> <div *ngIf="custom8Field.visible" class="form-group">
<label for="classification-custom-8" class="control-label">{{custom8Field.field}}</label> <label for="classification-custom-8" class="control-label">{{custom8Field.field}}</label>
<input type="text" class="form-control" id="classification-custom-8" placeholder="{{custom8Field.field}}" [(ngModel)]="classification.custom8" <input type="text" class="form-control" id="classification-custom-8" placeholder="{{custom8Field.field}}"
name="classification.custom8"> [(ngModel)]="classification.custom8" name="classification.custom8">
</div> </div>
</div> </div>
</form> </form>

View File

@ -34,7 +34,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-xs-9"> <div class="col-xs-8">
<input class="filter-input" [ngModel]="inputValue" (ngModelChange)="inputValue = $event" placeholder="Filter classifications"> <input class="filter-input" [ngModel]="inputValue" (ngModelChange)="inputValue = $event" placeholder="Filter classifications">
</div> </div>
<div class="col-xs-12 horizontal-bottom-divider"> <div class="col-xs-12 horizontal-bottom-divider">

View File

@ -10,6 +10,7 @@
.tab-align{ .tab-align{
margin-bottom: 0px; margin-bottom: 0px;
border-bottom: 1px dotted #ddd; border-bottom: 1px dotted #ddd;
padding: 8px 12px 8px 4px;
&>div{ &>div{
margin: 6px 0px; margin: 6px 0px;
} }

View File

@ -55,32 +55,36 @@
</taskana-field-error-display> </taskana-field-error-display>
</ng-template> </ng-template>
</div> </div>
<div class="form-group "> <div class="row">
<label for="wb-domain" class="control-label">Domain</label> <div class="form-group col-xs-6">
<input type="text" #domain="ngModel" class="form-control" disabled id="wb-domain" placeholder="Domain" <label for="wb-type" class="control-label">Type</label>
[(ngModel)]="workbasket.domain" name="workbasket.domain"> <div class="input-group">
</div> <div class="input-group-btn">
<div class="form-group"> <button class="btn btn-default" type="button" id="dropdownMenu24" data-toggle="dropdown"
<label for="wb-type" class="control-label">Type</label> aria-haspopup="true" aria-expanded="true">
<div class="dropdown clearfix btn-group"> <taskana-icon-type class="vertical-align" [type]='workbasket.type'></taskana-icon-type>
<button class="btn btn-default" type="button" id="dropdownMenu24" data-toggle="dropdown" {{allTypes.get(workbasket.type)}}
aria-haspopup="true" aria-expanded="true"> <span class="caret"></span>
<taskana-icon-type class="vertical-align" [type]='workbasket.type'></taskana-icon-type> </button>
{{allTypes.get(workbasket.type)}} <ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu">
<span class="caret"></span> <li>
</button> <a *ngFor="let type of allTypes | mapValues | removeEmptyType" (click)="selectType(type.key)">
<ul class="dropdown-menu dropdown-menu" aria-labelledby="dropdownMenu"> <taskana-icon-type class="vertical-align" [type]='type.key' [text]="type.value"></taskana-icon-type>
<li> </a>
<a *ngFor="let type of allTypes | mapValues | removeEmptyType" (click)="selectType(type.key)"> </li>
<taskana-icon-type class="vertical-align" [type]='type.key' [text]="type.value"></taskana-icon-type> </ul>
</a> </div>
</li> </div>
</ul> </div>
<div class="form-group col-xs-6">
<label for="wb-domain" class="control-label">Domain</label>
<input type="text" #domain="ngModel" class="form-control" disabled id="wb-domain" placeholder="Domain"
[(ngModel)]="workbasket.domain" name="workbasket.domain">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="wb-description" class="control-label">Description</label> <label for="wb-description" class="control-label">Description</label>
<textarea class="form-control" rows="5" id="wb-description" placeholder="Description" [(ngModel)]="workbasket.description" <textarea class="form-control" rows="7" id="wb-description" placeholder="Description" [(ngModel)]="workbasket.description"
name="workbasket.description"></textarea> name="workbasket.description"></textarea>
</div> </div>
</div> </div>

View File

@ -96,7 +96,7 @@ export class WorkbasketInformationComponent
]); ]);
} }
ngOnInit(): void {} ngOnInit(): void { }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
this.workbasketClone = { ...this.workbasket }; this.workbasketClone = { ...this.workbasket };
@ -138,7 +138,7 @@ export class WorkbasketInformationComponent
this.removeConfirmationService.setRemoveConfirmation( this.removeConfirmationService.setRemoveConfirmation(
this.onRemoveConfirmed.bind(this), this.onRemoveConfirmed.bind(this),
`You are going to delete workbasket: ${ `You are going to delete workbasket: ${
this.workbasket.key this.workbasket.key
}. Can you confirm this action?` }. Can you confirm this action?`
); );
} }
@ -162,7 +162,7 @@ export class WorkbasketInformationComponent
new AlertModel( new AlertModel(
AlertType.SUCCESS, AlertType.SUCCESS,
`DistributionTarget for workbasketID: ${ `DistributionTarget for workbasketID: ${
this.workbasket.workbasketId this.workbasket.workbasketId
} was removed successfully` } was removed successfully`
) )
); );
@ -171,7 +171,7 @@ export class WorkbasketInformationComponent
this.errorModalService.triggerError( this.errorModalService.triggerError(
new ErrorModel( new ErrorModel(
`There was an error removing distribution target for ${ `There was an error removing distribution target for ${
this.workbasket.workbasketId this.workbasket.workbasketId
}.`, }.`,
error error
) )
@ -281,7 +281,7 @@ export class WorkbasketInformationComponent
if (response) { if (response) {
this.errorModalService.triggerError( this.errorModalService.triggerError(
new ErrorModel('There was an error marking workbasket for deletion', new ErrorModel('There was an error marking workbasket for deletion',
'It not possible to mark the workbasket for deletion, It has been deleted.') 'It not possible to mark the workbasket for deletion, It has been deleted.')
); );
} else { } else {
this.alertService.triggerAlert( this.alertService.triggerAlert(

View File

@ -1,12 +1,12 @@
<li id="wb-action-toolbar" class="list-group-item tab-align"> <li id="wb-action-toolbar" class="list-group-item tab-align">
<div class="row"> <div class="row">
<div class="col-xs-9"> <div class="col-xs-8">
<button type="button" (click)="addWorkbasket()" data-toggle="tooltip" title="Add" class="btn btn-default"> <button type="button" (click)="addWorkbasket()" data-toggle="tooltip" title="Add" class="btn btn-default">
<span class="glyphicon glyphicon-plus green-blue" aria-hidden="true"></span> <span class="glyphicon glyphicon-plus green-blue" aria-hidden="true"></span>
</button> </button>
<taskana-import-export-component (importSucessful)="importEvent()" [currentSelection]="selectionToImport"></taskana-import-export-component> <taskana-import-export-component (importSucessful)="importEvent()" [currentSelection]="selectionToImport"></taskana-import-export-component>
</div> </div>
<div class="margin-right pull-right "> <div class="margin-right pull-right ">
<button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" aria-expanded="false" (click)="toolbarState=!toolbarState" <button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" aria-expanded="false" (click)="toolbarState=!toolbarState"
data-toggle="tooltip" title="Filter"> data-toggle="tooltip" title="Filter">
<span class="glyphicon glyphicon-filter blue"></span> <span class="glyphicon glyphicon-filter blue"></span>

View File

@ -4,7 +4,8 @@
} }
.tab-align{ .tab-align{
margin-bottom: 0px; padding: 8px 12px 8px 4px;
margin-bottom: 0px;
&>div{ &>div{
margin: 6px 0px; margin: 6px 0px;

View File

@ -1,42 +1,41 @@
<div class="workbasket-list-full-height"> <div class="footer-space-pagination-list">
<div class="footer-space-workbasket"> <div #wbToolbar>
<div #wbToolbar> <taskana-workbasket-list-toolbar [workbaskets]="workbaskets" (performFilter)="performFilter($event)"
<taskana-workbasket-list-toolbar [workbaskets]="workbaskets" (performFilter)="performFilter($event)" (performSorting)="performSorting($event)" (importSucessful)="refreshWorkbasketList()"></taskana-workbasket-list-toolbar>
(performSorting)="performSorting($event)" (importSucessful)="refreshWorkbasketList()"></taskana-workbasket-list-toolbar>
</div>
<div *ngIf="(workbaskets && workbaskets.length > 0) else empty_workbaskets">
<ul #wbList id="wb-list-container" class="list-group">
<li class="list-group-item no-space">
<div class="row"></div>
</li>
<li class="list-group-item" *ngFor="let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId"
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
<div class="row">
<dl class="col-xs-1">
<taskana-icon-type class="vertical-align" [type]="workbasket.type" tooltip="true" [selected]="workbasket.workbasketId === selectedId"></taskana-icon-type>
</dl>
<dl class="col-xs-10">
<dt data-toggle="tooltip" title="{{workbasket.name}}">{{workbasket.name}},
<i data-toggle="tooltip" title="{{workbasket.key}}">{{workbasket.key}} </i>
</dt>
<dd data-toggle="tooltip" title="{{workbasket.description}}">{{workbasket.description}} &nbsp;</dd>
<dd data-toggle="tooltip" title="{{workbasket.owner}}">{{workbasket.owner}} &nbsp;</dd>
</dl>
<dl *ngIf="workbasket.markedForDeletion">
<span class="{{workbasket.workbasketId === selectedId ? 'white': 'red' }} glyphicon glyphicon-exclamation-sign"
aria-hidden="true" data-toggle="tooltip" title="Marked for deletion"></span>
</dl>
</div>
</li>
</ul>
</div>
<taskana-spinner [isRunning]="requestInProgress"></taskana-spinner>
<ng-template #empty_workbaskets>
<div *ngIf="!requestInProgress" class="col-xs-12 container-no-items center-block">
<h3 class="grey">There are no workbaskets</h3>
<svg-icon class="img-responsive empty-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
</div>
</ng-template>
</div> </div>
<taskana-pagination [(page)]="workbasketsResource !== undefined ? workbasketsResource.page : workbasketsResource" [type]="type" (changePage)="changePage($event)"></taskana-pagination> <div *ngIf="(workbaskets && workbaskets.length > 0) else empty_workbaskets">
<ul #wbList id="wb-list-container" class="list-group">
<li class="list-group-item no-space">
<div class="row"></div>
</li>
<li class="list-group-item" *ngFor="let workbasket of workbaskets" [class.active]="workbasket.workbasketId == selectedId"
type="text" (click)="selectWorkbasket(workbasket.workbasketId)">
<div class="row">
<dl class="col-xs-1">
<taskana-icon-type class="vertical-align" [type]="workbasket.type" tooltip="true" [selected]="workbasket.workbasketId === selectedId"></taskana-icon-type>
</dl>
<dl class="col-xs-10">
<dt data-toggle="tooltip" title="{{workbasket.name}}">{{workbasket.name}},
<i data-toggle="tooltip" title="{{workbasket.key}}">{{workbasket.key}} </i>
</dt>
<dd data-toggle="tooltip" title="{{workbasket.description}}">{{workbasket.description}} &nbsp;</dd>
<dd data-toggle="tooltip" title="{{workbasket.owner}}">{{workbasket.owner}} &nbsp;</dd>
</dl>
<dl *ngIf="workbasket.markedForDeletion">
<span class="{{workbasket.workbasketId === selectedId ? 'white': 'red' }} glyphicon glyphicon-exclamation-sign"
aria-hidden="true" data-toggle="tooltip" title="Marked for deletion"></span>
</dl>
</div>
</li>
</ul>
</div>
<taskana-spinner [isRunning]="requestInProgress"></taskana-spinner>
<ng-template #empty_workbaskets>
<div *ngIf="!requestInProgress" class="col-xs-12 container-no-items center-block">
<h3 class="grey">There are no workbaskets</h3>
<svg-icon class="img-responsive empty-icon" src="./assets/icons/wb-empty.svg"></svg-icon>
</div>
</ng-template>
</div> </div>
<taskana-pagination [(page)]="workbasketsResource !== undefined ? workbasketsResource.page : workbasketsResource"
[type]="type" (changePage)="changePage($event)"></taskana-pagination>

View File

@ -28,7 +28,7 @@ li > div.row > dl {
margin-bottom: 0px; margin-bottom: 0px;
} }
li > div.row > dl:first-child { li > div.row > dl:first-child {
margin-left: 10px; margin-left: 15px;
} }
.no-space { .no-space {

View File

@ -3,7 +3,7 @@
<div class="row "> <div class="row ">
<router-outlet></router-outlet> <router-outlet></router-outlet>
<taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal> <taskana-general-message-modal *ngIf="modalErrorMessage" [(message)]="modalErrorMessage" [title]="modalTitle" error="true"></taskana-general-message-modal>
<taskana-spinner [isRunning]="requestInProgress" isModal="true"></taskana-spinner> <taskana-spinner [isRunning]="requestInProgress" isModal=true></taskana-spinner>
<taskana-alert></taskana-alert> <taskana-alert></taskana-alert>
<taskana-remove-confirmation></taskana-remove-confirmation> <taskana-remove-confirmation></taskana-remove-confirmation>
</div> </div>

View File

@ -35,8 +35,6 @@ import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine
import { RemoveConfirmationService } from './services/remove-confirmation/remove-confirmation.service'; import { RemoveConfirmationService } from './services/remove-confirmation/remove-confirmation.service';
import { FormsValidatorService } from './shared/services/forms/forms-validator.service'; import { FormsValidatorService } from './shared/services/forms/forms-validator.service';
/** /**
* Components * Components
*/ */

View File

@ -2,16 +2,16 @@ import { trigger, style, transition, animate, keyframes, state } from '@angular/
export const expandDown = export const expandDown =
trigger('toggleDown', [ trigger('toggleDown', [
state('true', style({ opacity: '1', display: 'initial' })), state('true', style({ opacity: '1', display: 'initial' })),
state('false', style({ opacity: '0', display: 'none' })), state('false', style({ opacity: '0', display: 'none' })),
transition('false => true', animate('300ms ease-in', keyframes([ transition('false => true', animate('300ms ease-in', keyframes([
style({ opacity: 0, height: '0px' }), style({ opacity: 0, height: '0px' }),
style({ opacity: 0.5, height: '50px' }), style({ opacity: 0.5, height: '50px' }),
style({ opacity: 1, height: '*' })]))), style({ opacity: 1, height: '*' })]))),
transition('true => false', animate('300ms ease-out', keyframes([ transition('true => false', animate('300ms ease-out', keyframes([
style({ opacity: 1, height: '*' }), style({ opacity: 1, height: '*' }),
style({ opacity: 0.5, height: '50px' }), style({ opacity: 0.5, height: '50px' }),
style({ opacity: 0, height: '0px' })]))) style({ opacity: 0, height: '0px' })])))
]); ]);
export const expandRight = trigger('toggleRight', [ export const expandRight = trigger('toggleRight', [

View File

@ -1,66 +1,74 @@
<div class="list-group-search"> <div class="list-group-search">
<div class="row"> <div *ngIf="filterTypeIsWorkbasket(); else tasktype">
<div *ngIf="filterTypeIsWorkbasket(); else tasktype"> <div class="row">
<div class="dropdown col-xs-2"> <div class="dropdown col-xs-2">
<button class="btn btn-default" data-toggle="dropdown" type="button" id="dropdownMenufilter" data-toggle="dropdown" aria-haspopup="true" <button class="btn btn-default" data-toggle="dropdown" type="button" id="dropdownMenufilter" data-toggle="dropdown"
aria-expanded="true"> aria-haspopup="true" aria-expanded="true">
<taskana-icon-type [type]="filter.filterParams?.type" class="vertical-align"></taskana-icon-type> <taskana-icon-type [type]="filter.filterParams?.type" class="vertical-align"></taskana-icon-type>
</button> </button>
<ul class="dropdown-menu dropdown-menu-users" role="menu"> <ul class="dropdown-menu dropdown-menu-users" role="menu">
<li> <li>
<a *ngFor="let type of allTypes | mapValues" type="button" (click)="selectType(type.key); search()" data-toggle="tooltip" <a *ngFor="let type of allTypes | mapValues" type="button" (click)="selectType(type.key); search()"
[title]="type.value"> data-toggle="tooltip" [title]="type.value">
<taskana-icon-type class="vertical-align" [type]='type.key' [text]="type.value"></taskana-icon-type> <taskana-icon-type class="vertical-align" [type]='type.key' [text]="type.value"></taskana-icon-type>
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control" id="display-name-filter" <input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control" id="display-name-filter"
placeholder="Filter name"> placeholder="Filter name">
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control" id="display-key-filter" <input type="text" [(ngModel)]="filter.filterParams.key" (keyup.enter)="search()" class="form-control" id="display-key-filter"
placeholder="Filter key"> placeholder="Filter key">
</div> </div>
<button (click)="clear(); search()" type="button" class="btn btn-default glyphicon glyphicon-ban-circle blue pull-right margin-right"
data-toggle="tooltip" title="Clear">
</button>
</div> </div>
<ng-template #tasktype> <div class="row">
<div class="col-xs-2"> <div class="col-xs-8 col-xs-offset-2">
<input type="text" [(ngModel)]="filter.filterParams.description" (keyup.enter)="search()" class="form-control"
id="display-name-description" placeholder="Filter description">
</div> </div>
<div class="col-xs-8"> </div>
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<input type="text" [(ngModel)]="filter.filterParams.owner" (keyup.enter)="search()" class="form-control" id="display-name-owner"
placeholder="Filter owner">
</div>
<button (click)="search()" type="button" class="btn btn-default glyphicon glyphicon-search blue pull-right margin-right"
data-toggle="tooltip" title="Search">
</button>
</div>
</div>
<ng-template #tasktype>
<div class="row">
<div class="col-xs-2">
<input type="text" [(ngModel)]="filter.filterParams.priority" (keyup.enter)="search()" data-toggle="tooltip" title="priority" class="form-control" id="display-priority-filter">
</div>
<div class="col-xs-4">
<input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control" id="display-name-filter" <input type="text" [(ngModel)]="filter.filterParams.name" (keyup.enter)="search()" class="form-control" id="display-name-filter"
placeholder="Filter name"> placeholder="Filter name">
</div> </div>
</ng-template> <div class="col-xs-4">
<button (click)="clear(); search()" type="button" class="btn btn-default glyphicon glyphicon-ban-circle blue pull-right margin-right" <input type="text" [(ngModel)]="filter.filterParams.owner" (keyup.enter)="search()" class="form-control" id="display-owner-filter"
data-toggle="tooltip" title="Clear"> placeholder="Filter owner">
</button>
</div>
<div class="filter-list">
<li class="" *ngFor="let filterType of getUnusedKeys()">
<div class="row padding">
<div class="col-xs-2">
</div>
<div class="col-xs-8">
<div *ngIf="checkUppercaseFilterType(filterType); else normalFilter">
<input type="text" [(ngModel)]="filter.filterParams[filterType]" (ngModelChange)="filter.filterParams[filterType] = $event.toLocaleUpperCase()"
(keyup.enter)="search()" class="form-control" id="display-{{filterType}}-filter" placeholder="Filter {{filterType}}">
</div>
<ng-template #normalFilter>
<input type="text" [(ngModel)]="filter.filterParams[filterType]" (keyup.enter)="search()" class="form-control" id="display-{{filterType}}-filter"
placeholder="Filter {{filterType}}">
</ng-template>
</div>
<div *ngIf="filterType === lastFilterKey" class="pull-right">
<button (click)="search()" type="button" class="btn btn-default glyphicon glyphicon-search blue pull-right margin-right"
data-toggle="tooltip" title="Search">
</button>
</div>
</div> </div>
</li> <button (click)="clear(); search()" type="button" class="btn btn-default glyphicon glyphicon-ban-circle blue pull-right margin-right"
</div> data-toggle="tooltip" title="Clear">
</button>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-2">
<input type="text" [(ngModel)]="filter.filterParams.state" (keyup.enter)="search()" class="form-control" id="display-owner-state"
placeholder="Filter status">
</div>
<button (click)="search()" type="button" class="btn btn-default glyphicon glyphicon-search blue pull-right margin-right"
data-toggle="tooltip" title="Search">
</button>
</div>
</ng-template>
</div> </div>

View File

@ -36,7 +36,7 @@ export class FilterComponent implements OnInit {
} }
selectType(type: ICONTYPES) { selectType(type: ICONTYPES) {
this.filter.filterParams.type = type; this.filter.filterParams.type = (type === ICONTYPES.ALL) ? '' : type;
} }
clear() { clear() {

View File

@ -17,7 +17,7 @@
</div> </div>
<div *ngIf="currentRoute === 'tasks'" class="center-block no-detail"> <div *ngIf="currentRoute === 'tasks'" class="center-block no-detail">
<h3 class="grey">Select a Task</h3> <h3 class="grey">Select a Task</h3>
<span class="glyphicon glyphicon-object-align-bottom"></span> <span class="glyphicon glyphicon-object-align-bottom empty-icon"></span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,9 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'numberToArray' })
export class NumberToArray implements PipeTransform {
transform(index: number): Array<number> {
return Array.from(Array(index), (x, i) => i)
};
}

View File

@ -7,99 +7,99 @@ import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.serv
@Injectable() @Injectable()
export class FormsValidatorService { export class FormsValidatorService {
public formSubmitAttempt = false; public formSubmitAttempt = false;
private workbasketOwner = 'workbasket.owner'; private workbasketOwner = 'workbasket.owner';
constructor( constructor(
private alertService: AlertService, private alertService: AlertService,
private accessIdsService: AccessIdsService) { private accessIdsService: AccessIdsService) {
}
public validateFormInformation(form: NgForm, toogleValidationMap: Map<any, boolean>): Promise<any> {
let validSync = true;
const forFieldsPromise = new Promise((resolve, reject) => {
for (const control in form.form.controls) {
if (control.indexOf('owner') === -1 && form.form.controls[control].invalid) {
const validationState = toogleValidationMap.get(control);
validationState ? toogleValidationMap.set(control, !validationState) : toogleValidationMap.set(control, true);
validSync = false;
}
}
resolve(validSync);
});
const ownerPromise = new Promise((resolve, reject) => {
const ownerString = 'owner';
if (form.form.controls[this.workbasketOwner]) {
this.accessIdsService.getAccessItemsInformation(form.form.controls[this.workbasketOwner].value).subscribe(items => {
const validationState = toogleValidationMap.get(this.workbasketOwner);
validationState ? toogleValidationMap.set(this.workbasketOwner, !validationState) :
toogleValidationMap.set(this.workbasketOwner, true);
items.find(item => item.accessId === form.form.controls[this.workbasketOwner].value) ?
resolve(new ResponseOwner({valid: true, field: ownerString})) :
resolve(new ResponseOwner({valid: false, field: ownerString}));
});
} else {
const validationState = toogleValidationMap.get(form.form.controls[this.workbasketOwner]);
validationState ? toogleValidationMap.set(this.workbasketOwner, !validationState) :
toogleValidationMap.set(this.workbasketOwner, true);
resolve(new ResponseOwner({valid: true, field: ownerString}));
}
});
return Promise.all([forFieldsPromise, ownerPromise]).then(values => {
const responseOwner = new ResponseOwner(values[1]);
if (!(values[0] && responseOwner.valid)) {
if (!responseOwner.valid) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'The ' + responseOwner.field + ' introduced is not valid.'))
} else {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'There are some empty fields which are required.'))
}
}
return values[0] && responseOwner.valid;
});
} }
public validateFormAccess(form: FormArray, toogleValidationAccessIdMap: Map<any, boolean>): Promise<boolean> { public async validateFormInformation(form: NgForm, toogleValidationMap: Map<any, boolean>): Promise<any> {
let validSync = true;
if (!form) {
return;
}
const forFieldsPromise = new Promise((resolve, reject) => {
for (const control in form.form.controls) {
if (control.indexOf('owner') === -1 && form.form.controls[control].invalid) {
const validationState = toogleValidationMap.get(control);
validationState ? toogleValidationMap.set(control, !validationState) : toogleValidationMap.set(control, true);
validSync = false;
}
}
resolve(validSync);
});
const ownerPromise = new Promise((resolve, reject) => {
const ownerString = 'owner';
if (form.form.controls[this.workbasketOwner]) {
this.accessIdsService.getAccessItemsInformation(form.form.controls[this.workbasketOwner].value).subscribe(items => {
const validationState = toogleValidationMap.get(this.workbasketOwner);
validationState ? toogleValidationMap.set(this.workbasketOwner, !validationState) :
toogleValidationMap.set(this.workbasketOwner, true);
items.find(item => item.accessId === form.form.controls[this.workbasketOwner].value) ?
resolve(new ResponseOwner({ valid: true, field: ownerString })) :
resolve(new ResponseOwner({ valid: false, field: ownerString }));
});
} else {
const validationState = toogleValidationMap.get(form.form.controls[this.workbasketOwner]);
validationState ? toogleValidationMap.set(this.workbasketOwner, !validationState) :
toogleValidationMap.set(this.workbasketOwner, true);
resolve(new ResponseOwner({ valid: true, field: ownerString }));
}
});
const values = await Promise.all([forFieldsPromise, ownerPromise]);
const responseOwner = new ResponseOwner(values[1]);
if (!(values[0] && responseOwner.valid)) {
if (!responseOwner.valid) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'The ' + responseOwner.field + ' introduced is not valid.'));
} else {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'There are some empty fields which are required.'));
}
}
return values[0] && responseOwner.valid;
}
public async validateFormAccess(form: FormArray, toogleValidationAccessIdMap: Map<any, boolean>): Promise<boolean> {
const ownerPromise: Array<Promise<boolean>> = new Array<Promise<boolean>>(); const ownerPromise: Array<Promise<boolean>> = new Array<Promise<boolean>>();
for (let i = 0; i < form.length; i++) { for (let i = 0; i < form.length; i++) {
ownerPromise.push(new Promise((resolve, reject) => { ownerPromise.push(new Promise((resolve, reject) => {
const validationState = toogleValidationAccessIdMap.get(i); const validationState = toogleValidationAccessIdMap.get(i);
validationState ? toogleValidationAccessIdMap.set(i, !validationState) : validationState ? toogleValidationAccessIdMap.set(i, !validationState) :
toogleValidationAccessIdMap.set(i, true); toogleValidationAccessIdMap.set(i, true);
this.accessIdsService.getAccessItemsInformation(form.controls[i].value['accessId']).subscribe(items => { this.accessIdsService.getAccessItemsInformation(form.controls[i].value['accessId']).subscribe(items => {
items.length > 0 ? items.length > 0 ?
resolve(new ResponseOwner({valid: true, field: 'access id'})) : resolve(new ResponseOwner({ valid: true, field: 'access id' })) :
resolve(new ResponseOwner({valid: false, field: 'access id'})); resolve(new ResponseOwner({ valid: false, field: 'access id' }));
}) })
})); }));
} }
let result = true; let result = true;
return Promise.all(ownerPromise).then(values => { const values = await Promise.all(ownerPromise);
let responseOwner; let responseOwner;
for (let i = 0; i < values.length; i++) { for (let i_1 = 0; i_1 < values.length; i_1++) {
responseOwner = new ResponseOwner(values[i]); responseOwner = new ResponseOwner(values[i_1]);
result = result && responseOwner.valid; result = result && responseOwner.valid;
} }
if (!result) { if (!result) {
this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'The ' + responseOwner.field + ' introduced is not valid.')) this.alertService.triggerAlert(new AlertModel(AlertType.WARNING, 'The ' + responseOwner.field + ' introduced is not valid.'));
} }
return result; return result;
});
} }
public isFieldValid(ngForm: NgForm, field: string) { public isFieldValid(ngForm: NgForm, field: string) {
if (!ngForm || !ngForm.form.controls || !ngForm.form.controls[field]) { if (!ngForm || !ngForm.form.controls || !ngForm.form.controls[field]) {
return false; return false;
} }
if (!this.formSubmitAttempt) { if (!this.formSubmitAttempt) {
return true; return true;
} }
return (this.formSubmitAttempt && ngForm.form.controls[field].valid) || return (this.formSubmitAttempt && ngForm.form.controls[field].valid) ||
(ngForm.form.controls[field].touched && ngForm.form.controls[field].valid); (ngForm.form.controls[field].touched && ngForm.form.controls[field].valid);
} }
} }

View File

@ -3,10 +3,10 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon'; import { AngularSvgIconModule } from 'angular-svg-icon';
import { AlertModule } from 'ngx-bootstrap';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { TreeModule } from 'angular-tree-component'; import { TreeModule } from 'angular-tree-component';
import { TypeaheadModule } from 'ngx-bootstrap'; import { AlertModule, TypeaheadModule } from 'ngx-bootstrap';
import { AccordionModule } from 'ngx-bootstrap/accordion';
/** /**
* Components * Components
@ -33,6 +33,7 @@ import { SelectWorkBasketPipe } from './pipes/selectedWorkbasket/seleted-workbas
import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number'; import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
import { OrderBy } from './pipes/orderBy/orderBy'; import { OrderBy } from './pipes/orderBy/orderBy';
import { MapToIterable } from './pipes/mapToIterable/mapToIterable'; import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
import { NumberToArray } from './pipes/numberToArray/numberToArray';
/** /**
* Services * Services
@ -45,6 +46,7 @@ const MODULES = [
FormsModule, FormsModule,
AlertModule.forRoot(), AlertModule.forRoot(),
TypeaheadModule.forRoot(), TypeaheadModule.forRoot(),
AccordionModule.forRoot(),
AngularSvgIconModule, AngularSvgIconModule,
HttpClientModule, HttpClientModule,
RouterModule, RouterModule,
@ -62,6 +64,7 @@ const DECLARATIONS = [
RemoveNoneTypePipe, RemoveNoneTypePipe,
SelectWorkBasketPipe, SelectWorkBasketPipe,
SpreadNumberPipe, SpreadNumberPipe,
NumberToArray,
OrderBy, OrderBy,
MapToIterable, MapToIterable,
SortComponent, SortComponent,
@ -69,7 +72,7 @@ const DECLARATIONS = [
IconTypeComponent, IconTypeComponent,
RemoveConfirmationComponent, RemoveConfirmationComponent,
FieldErrorDisplayComponent, FieldErrorDisplayComponent,
PaginationComponent PaginationComponent,
]; ];
@NgModule({ @NgModule({

View File

@ -1,5 +1,5 @@
<div [ngClass]="{'no-display':!showSpinner}"> <div [ngClass]="{'no-display':!showSpinner}">
<div *ngIf ="!isModal" class="sk-circle {{positionClass? positionClass: 'spinner-centered'}}"> <div *ngIf="!isModal" class="sk-circle {{positionClass? positionClass: 'spinner-centered'}}">
<div class="sk-circle1 sk-child"></div> <div class="sk-circle1 sk-child"></div>
<div class="sk-circle2 sk-child"></div> <div class="sk-circle2 sk-child"></div>
<div class="sk-circle3 sk-child"></div> <div class="sk-circle3 sk-child"></div>
@ -13,23 +13,21 @@
<div class="sk-circle11 sk-child"></div> <div class="sk-circle11 sk-child"></div>
<div class="sk-circle12 sk-child"></div> <div class="sk-circle12 sk-child"></div>
</div> </div>
<div #spinnerModal class="modal fade" id="spinner-modal" data-backdrop="static" data-keyboard="false" role="dialog"> <div #spinnerModal class="modal" id="spinner-modal" data-backdrop="static" data-keyboard="false" role="dialog">
<div class="modal-dialog"> <div class="modal-dialog {{positionClass? positionClass: 'spinner-centered'}}">
<div class="modal-dialog {{positionClass? positionClass: 'spinner-centered'}}"> <div class="sk-circle">
<div class="sk-circle"> <div class="sk-circle1 sk-child"></div>
<div class="sk-circle1 sk-child"></div> <div class="sk-circle2 sk-child"></div>
<div class="sk-circle2 sk-child"></div> <div class="sk-circle3 sk-child"></div>
<div class="sk-circle3 sk-child"></div> <div class="sk-circle4 sk-child"></div>
<div class="sk-circle4 sk-child"></div> <div class="sk-circle5 sk-child"></div>
<div class="sk-circle5 sk-child"></div> <div class="sk-circle6 sk-child"></div>
<div class="sk-circle6 sk-child"></div> <div class="sk-circle7 sk-child"></div>
<div class="sk-circle7 sk-child"></div> <div class="sk-circle8 sk-child"></div>
<div class="sk-circle8 sk-child"></div> <div class="sk-circle9 sk-child"></div>
<div class="sk-circle9 sk-child"></div> <div class="sk-circle10 sk-child"></div>
<div class="sk-circle10 sk-child"></div> <div class="sk-circle11 sk-child"></div>
<div class="sk-circle11 sk-child"></div> <div class="sk-circle12 sk-child"></div>
<div class="sk-circle12 sk-child"></div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -59,7 +59,7 @@ export class SpinnerComponent implements OnDestroy {
private runSpinner(value) { private runSpinner(value) {
this.currentTimeout = setTimeout(() => { this.currentTimeout = setTimeout(() => {
if (this.isModal) { $(this.modal.nativeElement).modal('toggle'); } if (this.isModal) { $(this.modal.nativeElement).modal('show'); }
this.isDelayedRunning = value; this.isDelayedRunning = value;
this.cancelTimeout(); this.cancelTimeout();
this.requestTimeout = setTimeout(() => { this.requestTimeout = setTimeout(() => {
@ -73,7 +73,7 @@ export class SpinnerComponent implements OnDestroy {
} }
private closeModal() { private closeModal() {
if (this.showSpinner) { if (this.showSpinner) {
$(this.modal.nativeElement).modal('toggle'); $(this.modal.nativeElement).modal('hide');
} }
} }

View File

@ -12,7 +12,8 @@
</div> </div>
</ng-template> </ng-template>
<div [ngClass]="{'hidden': !dataSource.selected || typing, <div [ngClass]="{'hidden': !dataSource.selected || typing,
'disable': disable}" class="wrapper-text" (click)="setTyping(true)"> 'disable': disable}" class="wrapper-text"
(click)="setTyping(true)">
<span> <span>
<label> <label>
{{dataSource.selected?.name}} {{dataSource.selected?.name}}
@ -29,11 +30,13 @@
</label> </label>
</span> </span>
<div class="input-group"> <div class="input-group">
<input #inputTypeAhead class=" form-control input-text" [ngClass]="{'invalid': dataSource.length == null}" (blur)="typeaheadOnSelect({'item':dataSource.selected})" name="accessItem-{{index}}" <input #inputTypeAhead class="form-control input-text" [ngClass]="{'invalid': !dataSource.length && isRequired}" (blur)="typeaheadOnSelect({'item':dataSource.selected})"
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate" name="accessItem-{{index}}" [required]="isRequired ? 'required' : null" #accessItemName="ngModel" [(ngModel)]="value"
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)" (typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true"
placeholder="{{displayError? placeHolderMessage: ''}}" [@validation]="validationValue" > [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView" [typeaheadMinLength]="typeaheadMinLength"
[typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)" placeholder="{{displayError? placeHolderMessage: ''}}"
[@validation]="validationValue">
<button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue"> <button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span> <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button> </button>
@ -42,4 +45,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,8 +11,8 @@
} }
&> div{ &> div{
&> div { &> div {
border-bottom: 1px solid $light-grey; border-bottom: 1px solid $pallete-blue;
margin-top:3px; margin-top: 2px;
padding-left: 12px; padding-left: 12px;
min-width: 175px; min-width: 175px;
} }
@ -26,7 +26,8 @@
} }
.custom-form-control { .custom-form-control {
height: 50px; margin-top: -5px;
height: 40px;
& .input-group{ & .input-group{
width: 100%; width: 100%;
} }
@ -40,7 +41,7 @@
border-radius: 0px; border-radius: 0px;
min-width: 150px; min-width: 150px;
height: 28px; height: 28px;
border-bottom: 1px solid $light-grey; border-bottom: 1px solid $pallete-blue;
&:focus{ &:focus{
border-bottom: 1px solid $aquamarine; border-bottom: 1px solid $aquamarine;
} }
@ -56,6 +57,9 @@
box-sizing: content-box; box-sizing: content-box;
overflow: hidden; overflow: hidden;
pointer-events: none; pointer-events: none;
label{
margin-bottom: 1px;
}
} }
.form-control:focus { .form-control:focus {
@ -93,5 +97,5 @@
} }
.invalid { .invalid {
color: $invalid; border-bottom: 1px solid $invalid;
} }

View File

@ -41,6 +41,9 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
@Input() @Input()
disable; disable;
@Input()
isRequired = true;
@Output() @Output()
onSelect = new EventEmitter<AccessIdDefinition>(); onSelect = new EventEmitter<AccessIdDefinition>();

View File

@ -1,5 +1,3 @@
import { Direction } from 'app/models/sorting';
export class TaskanaQueryParameters { export class TaskanaQueryParameters {
// Sorting // Sorting
static SORTBY = 'sort-by'; static SORTBY = 'sort-by';
@ -16,7 +14,7 @@ export class TaskanaQueryParameters {
static WORKBASKET_KEY = 'workbasket-key'; static WORKBASKET_KEY = 'workbasket-key';
static KEYLIKE = 'key-like'; static KEYLIKE = 'key-like';
static PRIORITY = 'priority'; static PRIORITY = 'priority';
static STATE = 'state'; static STATELIKE = 'state-like';
static WORKBASKET_ID = 'workbasket-id'; static WORKBASKET_ID = 'workbasket-id';
// Access // Access
@ -54,7 +52,7 @@ export class TaskanaQueryParameters {
workbasketKeyLike: string = undefined, workbasketKeyLike: string = undefined,
basketId: string = undefined, basketId: string = undefined,
priority: string = undefined, priority: string = undefined,
state: string = undefined, stateLike: string = undefined,
): string { ): string {
let query = '?'; let query = '?';
query += sortBy ? `${this.SORTBY}=${sortBy}&` : ''; query += sortBy ? `${this.SORTBY}=${sortBy}&` : '';
@ -66,7 +64,7 @@ export class TaskanaQueryParameters {
query += ownerLike ? `${this.OWNERLIKE}=${ownerLike}&` : ''; query += ownerLike ? `${this.OWNERLIKE}=${ownerLike}&` : '';
query += basketId ? `${this.WORKBASKET_ID}=${basketId}&` : ''; query += basketId ? `${this.WORKBASKET_ID}=${basketId}&` : '';
query += priority ? `${this.PRIORITY}=${priority}&` : ''; query += priority ? `${this.PRIORITY}=${priority}&` : '';
query += state ? `${this.STATE}=${state}&` : ''; query += stateLike ? `${this.STATELIKE}=${stateLike}&` : '';
query += type ? `${this.TYPE}=${type}&` : ''; query += type ? `${this.TYPE}=${type}&` : '';
query += key ? `${this.KEY}=${key}&` : ''; query += key ? `${this.KEY}=${key}&` : '';
query += keyLike ? `${this.KEYLIKE}=${keyLike}&` : ''; query += keyLike ? `${this.KEYLIKE}=${keyLike}&` : '';

View File

@ -1,10 +1,11 @@
import {DatePipe} from '@angular/common'; import { DatePipe } from '@angular/common';
export class TaskanaDate { export class TaskanaDate {
public static getDate(): string { public static getDate(): string {
const dateFormat = 'yyyy-MM-ddTHH:mm:ss.sss'; const dateFormat = 'yyyy-MM-ddTHH:mm:ss.sss';
const dateLocale = 'en-US'; const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale); const datePipe = new DatePipe(dateLocale);
return datePipe.transform(Date.now(), dateFormat) + 'Z'; return datePipe.transform(Date.now(), dateFormat) + 'Z';
} }
@ -14,4 +15,16 @@ export class TaskanaDate {
const datePipe = new DatePipe(dateLocale); const datePipe = new DatePipe(dateLocale);
return datePipe.transform(date, dateFormat); return datePipe.transform(date, dateFormat);
} }
public static getDateToDisplay(date: string): string {
const dateFormat = 'yyyy-MM-dd HH:mm:ss';
const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale);
return datePipe.transform(date, dateFormat);
}
public static convertToBrowserTimeZone(date: Date): string {
return date.toLocaleString('en-US', { timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })
}
} }

View File

@ -53,21 +53,21 @@ export class TaskService {
* @param {string} basketId the id of workbasket * @param {string} basketId the id of workbasket
* @param {string} sortBy name of field, that the tasks should be sorted by, default is priority * @param {string} sortBy name of field, that the tasks should be sorted by, default is priority
* @param {string} sortDirection ASC or DESC * @param {string} sortDirection ASC or DESC
* @param {string} name the name of the task * @param {string} nameLike the name of the task
* @param {string} owner the owner of the task * @param {string} ownerLike the owner of the task
* @param {string} priority the priority of the task * @param {string} priority the priority of the task
* @param {string} statethe state of the task * @param {string} state the state of the task
*/ */
findTasksWithWorkbasket(basketId: string, findTasksWithWorkbasket(basketId: string,
sortBy = 'priority', sortBy = 'priority',
sortDirection: string = Direction.ASC, sortDirection: string = Direction.ASC,
name: string, nameLike: string,
owner: string, ownerLike: string,
priority: string, priority: string,
state: string, state: string,
allPages: boolean = false): Observable<TaskResource> { allPages: boolean = false): Observable<TaskResource> {
const url = `${this.url}${TaskanaQueryParameters.getQueryParameters( const url = `${this.url}${TaskanaQueryParameters.getQueryParameters(
sortBy, sortDirection, name, undefined, undefined, owner, undefined, undefined, undefined, undefined, undefined, sortBy, sortDirection, undefined, nameLike, undefined, undefined, ownerLike, undefined, undefined, undefined, undefined,
!allPages ? TaskanaQueryParameters.page : undefined, !allPages ? TaskanaQueryParameters.pageSize : undefined, !allPages ? TaskanaQueryParameters.page : undefined, !allPages ? TaskanaQueryParameters.pageSize : undefined,
undefined, undefined, undefined, undefined, basketId, priority, state)}`; undefined, undefined, undefined, undefined, basketId, priority, state)}`;
return this.httpClient.get<TaskResource>(url); return this.httpClient.get<TaskResource>(url);

View File

@ -1,18 +1,16 @@
<taskana-spinner [isRunning]="requestInProgress"></taskana-spinner> <taskana-spinner [isRunning]="requestInProgress"></taskana-spinner>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right"> <div class="pull-left btn-group align-header">
<button type="button" (click)="navigateBack()" class="btn btn-default"><span title="Cancel and return to task detail" <button (click)="navigateBack()" class="btn btn-default no-style blue " title="Cancel and return to task detail">
class="glyphicon glyphicon-arrow-left text-muted"></span> <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back
</button> </button>
</div>
<div class="pull-right">
<div class="dropdown" style="display: inline"> <div class="dropdown" style="display: inline">
<button type="button" data-toggle="dropdown" aria-expanded="true" class="btn btn-default dropdown-toggle"> <button type="button" data-toggle="dropdown" aria-expanded="true" class="btn btn-default dropdown-toggle">
<span <span title="Transfer task to another workbasket" class="glyphicon glyphicon-transfer text-muted"></span>
title="Transfer task to another workbasket"
class="glyphicon glyphicon-transfer text-muted"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right"> <ul class="dropdown-menu dropdown-menu-right">
<li *ngFor="let workbasket of workbaskets"> <li *ngFor="let workbasket of workbaskets">
<a class="dropdown-item" (click)="transferTask(workbasket)"> <a class="dropdown-item" (click)="transferTask(workbasket)">
@ -21,42 +19,42 @@
</li> </li>
</ul> </ul>
</div> </div>
<button type="button" (click)="completeTask()" class="btn btn-default"><span <button type="button" (click)="completeTask()" class="btn btn-default"><span title="Complete task and return to task list"
title="Complete task and return to task list" class="glyphicon glyphicon-ok blue text-success"></span>
class="glyphicon glyphicon-ok blue text-success"></span>
</button> </button>
</div> </div>
<div class="panel-header"><h4><b>{{task?.name}}</b></h4></div> <div class="panel-header">
<h4><b>{{task?.name}}</b></h4>
</div>
</div> </div>
<div class="panel-body" *ngIf="task"> <div class="panel-body" *ngIf="task">
<form #TaskForm="ngForm"> <div class="row">
<div class="col-md-6"> <form #TaskForm="ngForm">
<div class="form-group"> <div class="col-md-6">
<label for="task-description" class="control-label">Description</label> <div class="form-group">
<textarea class="form-control" disabled rows="5" id="task-description" placeholder="Description" <label for="task-description" class="control-label">Description</label>
[(ngModel)]="task.description" <textarea class="form-control" disabled rows="5" id="task-description" placeholder="Description"
name="task.description"></textarea> [(ngModel)]="task.description" name="task.description"></textarea>
</div>
</div> </div>
</div> <div class="col-md-6">
<div class="col-md-6"> <div class="form-group">
<div class="form-group"> <label for="task-note" class="control-label">Note</label>
<label for="task-note" class="control-label">Note</label> <input type="text" disabled class="form-control" id="task-note" placeholder="Task has no Note" [(ngModel)]="task.note"
<input type="text" disabled class="form-control" id="task-note" placeholder="Task has no Note" name="task.note">
[(ngModel)]="task.note" </div>
name="task.note"> <div class="form-group">
<label for="task-due" class="control-label">Due Date</label>
<input type="text" disabled class="form-control" id="task-due" placeholder="No deadline set" [(ngModel)]="task.due"
name="task.due">
</div>
</div> </div>
<div class="form-group"> </form>
<label for="task-due" class="control-label">Due Date</label> </div>
<input type="text" disabled class="form-control" id="task-due" placeholder="No deadline set" <div class="row">
[(ngModel)]="task.due" <iframe class="col-xs-12" [src]="link"></iframe>
name="task.due"> </div>
</div>
</div>
</form>
</div> </div>
</div> </div>
<iframe [src]="link"></iframe>

View File

@ -1,9 +1,4 @@
iframe { iframe {
position: absolute; height: calc(100vh - 290px);
margin: 0;
padding: 0;
height: 600px;
width: 98%;
overflow: auto;
} }

View File

@ -0,0 +1,45 @@
<ng-container *ngIf="task">
<div class="col-md-6">
<div *ngIf="task.taskId" class="form-group">
<label for="task-modified" class="control-label">Modification date</label>
<input type="text" disabled class="form-control" id="task-modified" placeholder="Modified" [(ngModel)]="task.modified"
name="task.modified">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-completed" class="control-label">Completion date</label>
<input type="text" disabled class="form-control" id="task-completed" placeholder="Complete date" [(ngModel)]="task.completed"
name="task.completed">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-state" class="control-label">State</label>
<input type="text" disabled class="form-control" id="task-state" placeholder="State" [(ngModel)]="task.state"
name="task.state">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-read" class="control-label">Task read</label>
<input type="text" disabled class="form-control" id="task-read" placeholder="Read" [(ngModel)]="task.read" name="task.read">
</div>
</div>
<div class="col-md-6">
<div *ngIf="task.taskId" class="form-group">
<label for="task-claimed" class="control-label">Claim date</label>
<input type="text" disabled class="form-control" id="task-claimed" placeholder="Claimed date" [(ngModel)]="task.claimed"
name="task.claimed">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-planned" class="control-label">Planned date</label>
<input type="text" disabled class="form-control" id="task-planned" placeholder="Planned date" [(ngModel)]="task.planned"
name="task.planned">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-created" class="control-label">Creation date</label>
<input type="text" disabled class="form-control" id="task-created" placeholder="Created" [(ngModel)]="task.created"
name="task.created">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-transferred" class="control-label">Transferred</label>
<input type="text" disabled class="form-control" id="task-transferred" placeholder="Transferred" [(ngModel)]="task.transferred"
name="task.transferred">
</div>
</div>
</ng-container>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GeneralFieldsExtensionComponent } from './general-fields-extension.component';
xdescribe('GeneralFieldsExtensionComponent', () => {
let component: GeneralFieldsExtensionComponent;
let fixture: ComponentFixture<GeneralFieldsExtensionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GeneralFieldsExtensionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GeneralFieldsExtensionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Task } from 'app/workplace/models/task';
@Component({
selector: 'taskana-general-fields-extension',
templateUrl: './general-fields-extension.component.html',
styleUrls: ['./general-fields-extension.component.scss']
})
export class GeneralFieldsExtensionComponent implements OnInit {
@Input() task: Task;
@Output() taskChange: EventEmitter<Task> = new EventEmitter<Task>();
constructor() { }
ngOnInit() {
}
}

View File

@ -1,167 +1,117 @@
<ng-container *ngIf="task && !requestInProgress"> <ng-container *ngIf="task && !requestInProgress">
<div class="col-md-12"> <form #TaskForm="ngForm">
<div class="form-group"> <div class="col-md-6">
<label for="task-description" class="control-label">Description</label> <div class="row">
<textarea class="form-control" id="task-description" <div class="form-group col-xs-6 required">
placeholder="Task has no description" <label for="task-name" class="control-label">Name</label>
[(ngModel)]="task.description" <input type="text" class="form-control" id="task-name" placeholder="Name" [(ngModel)]="task.name" name="task.name">
name="task.description"></textarea> <taskana-field-error-display [displayError]="!isFieldValid('task.name')" [validationTrigger]="this.toogleValidationMap.get('task.name')"
</div> errorMessage="* Name is required">
</div> </taskana-field-error-display>
</div>
<div class="form-group col-xs-6 required">
<label for="task.primaryObjRef.company" class="control-label">Company</label>
<input type="text" class="form-control" id="task.primaryObjRef.company" required placeholder="Company description"
[(ngModel)]="task.primaryObjRef.company" name="task.primaryObjRef.company">
<taskana-field-error-display [displayError]="!isFieldValid('task.primaryObjRef.company')" [validationTrigger]="this.toogleValidationMap.get('task.primaryObjRef.company')"
errorMessage="* Company is required">
</taskana-field-error-display>
</div>
<div class="col-md-6"> </div>
<div class="form-group required"> <div class="row">
<label for="task-objectRef-company" class="control-label">Reference Company</label> <div class="form-group col-xs-6 required">
<input type="text" class="form-control" id="task-objectRef-company" required <label for="task.primaryObjRef.system" class="control-label">System</label>
placeholder="Company description not provided" <input type="text" class="form-control" id="task.primaryObjRef.system" required placeholder="System description"
[(ngModel)]="task.primaryObjRef.company" [(ngModel)]="task.primaryObjRef.system" name="task.primaryObjRef.system">
name="task-objectRef-company"> <taskana-field-error-display [displayError]="!isFieldValid('task.primaryObjRef.system')" [validationTrigger]="this.toogleValidationMap.get('task.primaryObjRef.system')"
</div> errorMessage="* System is required">
<div class="form-group required"> </taskana-field-error-display>
<label for="task-objectRef-system" class="control-label">Reference System</label> </div>
<input type="text" class="form-control" id="task-objectRef-system" required <div class="form-group col-xs-6 required">
placeholder="System description not provided" <label for="task.primaryObjRef.systemInstance" class="control-label">System instance</label>
[(ngModel)]="task.primaryObjRef.system" <input type="text" class="form-control" id="task.primaryObjRef.systemInstance" required placeholder="System Instance description"
name="task-objectRef-system"> [(ngModel)]="task.primaryObjRef.systemInstance" name="task.primaryObjRef.systemInstance">
</div> <taskana-field-error-display [displayError]="!isFieldValid('task.primaryObjRef.systemInstance')"
<div class="form-group required"> [validationTrigger]="this.toogleValidationMap.get('task.primaryObjRef.systemInstance')" errorMessage="* System instance is required">
<label for="task-objectRef-system-instance" class="control-label">Reference System Instance</label> </taskana-field-error-display>
<input type="text" class="form-control" id="task-objectRef-system-instance" required </div>
placeholder="System Instance description not provided" </div>
[(ngModel)]="task.primaryObjRef.systemInstance" <div class="row">
name="task-objectRef-system-instance"> <div class="form-group col-xs-6 required">
</div> <label for="task.primaryObjRef.type" class="control-label">Reference type</label>
<div class="form-group"> <input type="text" class="form-control" id="task.primaryObjRef.type" required placeholder="Reference type"
<label for="task-owner" class="control-label">Owner</label> [(ngModel)]="task.primaryObjRef.type" name="task.primaryObjRef.type">
<input type="text" class="form-control" id="task-owner" <taskana-field-error-display [displayError]="!isFieldValid('task.primaryObjRef.type')" [validationTrigger]="this.toogleValidationMap.get('task.primaryObjRef.type')"
placeholder="Task has no owner" errorMessage="* Reference type is required">
[(ngModel)]="task.owner" </taskana-field-error-display>
name="task.owner"> </div>
</div> <div class="form-group col-xs-6 required">
<div class="form-group"> <label for="task.primaryObjRef.value" class="control-label">Reference value</label>
<label for="task-priority" disabled class="control-label">Priority</label> <input type="text" class="form-control" id="task.primaryObjRef.value" required placeholder="Reference value"
<input type="text" class="form-control" id="task-priority" [(ngModel)]="task.primaryObjRef.value" name="task.primaryObjRef.value">
placeholder="Task has no priority" <taskana-field-error-display [displayError]="!isFieldValid('task.primaryObjRef.value')" [validationTrigger]="this.toogleValidationMap.get('task.primaryObjRef.value')"
[(ngModel)]="task.priority" errorMessage="* Reference value is required">
name="task.priority"> </taskana-field-error-display>
</div> </div>
<div class="form-group"> </div>
<label for="task-note" class="control-label">Note</label> <div class="row">
<input type="text" class="form-control" id="task-note" <div class="form-group col-xs-6 required">
placeholder="Task has no Note" <label for="wb-type" class="control-label">Classification</label>
[(ngModel)]="task.note" <div class="input-group" dropdown>
name="task.note"> <button class="btn btn-default" type="button" dropdownToggle id="task.classificationSummaryResource"
</div> data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" name="">
<div *ngIf="task.taskId" class="form-group"> {{task.classificationSummaryResource?.name }}
<label for="task-modified" class="control-label">Modification Date</label> <span class="caret"></span>
<input type="text" disabled class="form-control" id="task-modified" </button>
placeholder="Task has not been modified" <ul class="dropdown-menu" *dropdownMenu>
[(ngModel)]="task.modified" <li>
name="task.modified"> <a *ngFor="let classification of classifications" (click)="selectClassification(classification)">
</div> {{classification.name}}
<div *ngIf="task.taskId" class="form-group"> </a>
<label for="task-completed" class="control-label">Completion Date</label> </li>
<input type="text" disabled class="form-control" id="task-completed" </ul>
placeholder="Task has not been completed" </div>
[(ngModel)]="task.completed" </div>
name="task.completed"> <div class="form-group col-xs-6">
</div> <label for="task-priority" disabled class="control-label">Priority</label>
<div *ngIf="task.taskId" class="form-group"> <input type="text" class="form-control" id="task-priority" placeholder="Priority" [(ngModel)]="task.priority"
<label for="task-state" class="control-label">State</label> name="task.priority">
<input type="text" disabled class="form-control" id="task-state" </div>
placeholder="Task has no State" </div>
[(ngModel)]="task.state" <div class="row">
name="task.state"> <div class="form-group col-xs-12">
</div> <div class="form-group">
<div *ngIf="task.taskId" class="form-group"> <label for="task-note" class="control-label">Note</label>
<label for="task-read" class="control-label">Task Read?</label> <textarea class="form-control" rows="2" id="task-note" placeholder="Note" [(ngModel)]="task.note" name="task.note"></textarea>
<input type="text" disabled class="form-control" id="task-read" </div>
placeholder="Task not been read" </div>
[(ngModel)]="task.read"
name="task.read">
</div>
</div>
<div class="col-md-6">
<div class="form-group required">
<label for="task-objectRef-type" class="control-label">Reference Type</label>
<input type="text" class="form-control" id="task-objectRef-type" required
placeholder="Reference Type is not provided"
[(ngModel)]="task.primaryObjRef.type"
name="task-objectRef-type">
</div>
<div class="form-group required">
<label for="task-objectRef-value" class="control-label">Reference Value</label>
<input type="text" class="form-control" id="task-objectRef-value" required
placeholder="Reference Value is not provided"
[(ngModel)]="task.primaryObjRef.value"
name="task-objectRef-value">
</div>
<div class="form-group required">
<div class="dropdown clearfix btn-group">
<label for="classificationDropdownMenu" class="control-label">Classification</label><br>
<button class="btn btn-default" type="button" id="classificationDropdownMenu" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
{{task.classificationSummaryResource ? selectedClassification.name :
'Task does not belong to a Classification'}}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu">
<li>
<a *ngFor="let classification of classifications" (click)="selectClassification(classification)">
{{classification.name}}
</a>
</li>
</ul>
</div> </div>
</div> </div>
<div class="form-group"> <div class="col-md-6">
<label for="task-parent-business-p-id" class="control-label">Parent Business Process ID</label> <div class="form-group">
<input type="text" class="form-control" id="task-parent-business-p-id" <label for="task-due" class="control-label">Due date</label>
placeholder="Task has no Parent Business Process ID" <input type="text" class="form-control" id="task-due" placeholder="Due date" [(ngModel)]="task.due" name="task.due">
[(ngModel)]="task.parentBusinessProcessId" </div>
name="task.parentBusinessProcessId"> <div class="input-group form-group col-xs-12">
<label for="wb-owner" class="control-label ">Owner</label>
<taskana-type-ahead *ngIf="ownerField?.lookupField else ownerInput" #owner="ngModel" name="task.owner"
[(ngModel)]="task.owner" width="100%" [isRequired]="false"></taskana-type-ahead>
<ng-template #ownerInput>
<input type="text" #task.owner="ngModel" class="form-control" id="ts-owner" placeholder="Owner" [(ngModel)]="task.owner"
name="task.owner">
</ng-template>
</div>
<div class="form-group">
<label for="task-parent-business-p-id" class="control-label">Parent business process id</label>
<input type="text" class="form-control" id="task-parent-business-p-id" placeholder="Parent business process iD"
[(ngModel)]="task.parentBusinessProcessId" name="task.parentBusinessProcessId">
</div>
<div class="form-group">
<label for="task-business-p-id" class="control-label">Business process iD</label>
<input type="text" class="form-control" id="task-business-p-id" placeholder="Business process id" [(ngModel)]="task.businessProcessId"
name="task.businessProcessId">
</div>
</div> </div>
<div class="form-group"> </form>
<label for="task-business-p-id" class="control-label">Business Process ID</label> </ng-container>
<input type="text" class="form-control" id="task-business-p-id"
placeholder="Task has no Business Process ID"
[(ngModel)]="task.businessProcessId"
name="task.businessProcessId">
</div>
<div class="form-group">
<label for="task-due" class="control-label">Due Date</label>
<input type="text" class="form-control" id="task-due"
placeholder="Task has no deadline"
[(ngModel)]="task.due"
name="task.due">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-claimed" class="control-label">Claim Date</label>
<input type="text" disabled class="form-control" id="task-claimed"
placeholder="Task has not been claimed"
[(ngModel)]="task.claimed"
name="task.claimed">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-planned" class="control-label">Planned Date</label>
<input type="text" disabled class="form-control" id="task-planned"
placeholder="Task has no planned date set"
[(ngModel)]="task.planned"
name="task.planned">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-created" class="control-label">Creation Date</label>
<input type="text" disabled class="form-control" id="task-created"
placeholder="Task has not been created"
[(ngModel)]="task.created"
name="task.created">
</div>
<div *ngIf="task.taskId" class="form-group">
<label for="task-transferred" class="control-label">Task Transferred?</label>
<input type="text" disabled class="form-control" id="task-transferred"
placeholder="Task not been transferred"
[(ngModel)]="task.transferred"
name="task.transferred">
</div>
</div>
</ng-container>

View File

@ -1,25 +1,50 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild, SimpleChanges, OnChanges } from '@angular/core';
import {Task} from 'app/workplace/models/task'; import { Task } from 'app/workplace/models/task';
import {Classification} from '../../../models/classification'; import { Classification } from '../../../models/classification';
import {ClassificationsService} from '../../../services/classifications/classifications.service'; import { ClassificationsService } from '../../../services/classifications/classifications.service';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { NgForm } from '@angular/forms';
@Component({ @Component({
selector: 'taskana-task-details-general-fields', selector: 'taskana-task-details-general-fields',
templateUrl: './general-fields.component.html', templateUrl: './general-fields.component.html',
styleUrls: ['./general-fields.component.scss'] styleUrls: ['./general-fields.component.scss']
}) })
export class TaskdetailsGeneralFieldsComponent implements OnInit { export class TaskdetailsGeneralFieldsComponent implements OnInit, OnChanges {
@Input()
task: Task; task: Task;
@Output() taskChange: EventEmitter<Task> = new EventEmitter<Task>(); @Output() taskChange: EventEmitter<Task> = new EventEmitter<Task>();
@Input()
saveToggleTriggered: boolean;
@Output() formValid: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() classificationsReceived: EventEmitter<Classification[]> = new EventEmitter<Classification[]>(); @Output() classificationsReceived: EventEmitter<Classification[]> = new EventEmitter<Classification[]>();
@ViewChild('TaskForm')
taskForm: NgForm;
toogleValidationMap = new Map<string, boolean>();
requestInProgress = false; requestInProgress = false;
selectedClassification: Classification = new Classification();
classifications: Classification[] = undefined; classifications: Classification[] = undefined;
constructor(private classificationService: ClassificationsService) { ownerField = this.customFieldsService.getCustomField(
'Owner',
'tasks.information.owner'
);
constructor(
private classificationService: ClassificationsService,
private customFieldsService: CustomFieldsService,
private formsValidatorService: FormsValidatorService) {
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.saveToggleTriggered && changes.saveToggleTriggered.currentValue !== changes.saveToggleTriggered.previousValue) {
this.validate();
}
} }
ngOnInit() { ngOnInit() {
@ -27,18 +52,28 @@ export class TaskdetailsGeneralFieldsComponent implements OnInit {
this.classificationService.getClassifications().subscribe(classificationList => { this.classificationService.getClassifications().subscribe(classificationList => {
this.requestInProgress = false; this.requestInProgress = false;
this.classifications = classificationList; this.classifications = classificationList;
if (classificationList.length > 0) { this.task.classificationSummaryResource = classificationList[0]; }
this.classificationsReceived.emit(this.classifications); this.classificationsReceived.emit(this.classifications);
}); });
} }
@Input()
set _task(task: Task) {
this.task = task;
this.selectedClassification = task.classificationSummaryResource;
}
selectClassification(classification: Classification) { selectClassification(classification: Classification) {
this.selectedClassification = classification;
this.task.classificationSummaryResource = classification; this.task.classificationSummaryResource = classification;
} }
validate() {
this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService
.validateFormInformation(this.taskForm, this.toogleValidationMap)
.then(value => {
if (value) {
this.formValid.emit(true);
}
});
}
isFieldValid(field: string): boolean {
return this.formsValidatorService.isFieldValid(this.taskForm, field);
}
} }

View File

@ -1,50 +1,25 @@
<taskana-spinner [isRunning]="requestInProgress"></taskana-spinner> <taskana-spinner [isRunning]="requestInProgress"></taskana-spinner>
<ul class="nav nav-tabs" role="tablist" *ngIf="task && !requestInProgress">
<li class="visible-xs visible-sm hidden">
<a (click)="backClicked()">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back</a>
</li>
<li role="presentation" (click)="selectTab('general')" [ngClass]="{'active':tabSelected === 'general'}">
<a role="tab" aria-expanded="true">
General Fields
</a>
</li>
<li role="presentation" (click)="selectTab('custom')" [ngClass]="{'active':tabSelected === 'custom'}">
<a role="tab" aria-expanded="true">
Custom Fields
</a>
</li>
<li role="presentation" (click)="selectTab('custom-attributes')"
[ngClass]="{'active':tabSelected === 'custom-attributes'}">
<a role="tab" aria-expanded="true">
Custom Attributes
</a>
</li>
<li role="presentation" (click)="selectTab('callback-info')"
[ngClass]="{'active':tabSelected === 'callback-info'}">
<a role="tab" aria-expanded="true">
Callback Information
</a>
</li>
</ul>
<div class="panel panel-default" *ngIf="task && !requestInProgress"> <div class="panel panel-default" *ngIf="task && !requestInProgress">
<div class="panel-heading"> <div class="panel-heading">
<div *ngIf="showDetail" class="pull-left btn-group align-header">
<button (click)="backClicked()" class="btn btn-default no-style blue visible-xs visible-sm hidden">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>Back
</button>
</div>
<div class="pull-right btn-group"> <div class="pull-right btn-group">
<button type="button" (click)="onSave()" class="btn btn-default btn-primary" data-toggle="tooltip" <button type="button" (click)="toggleFormValidation = !toggleFormValidation" class="btn btn-default btn-primary"
title="Save"> data-toggle="tooltip" title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span> <span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</button> </button>
<ng-container *ngIf="currentId != 'new-task'"> <ng-container *ngIf="currentId != 'new-task'">
<button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align" <button type="button" title="Open task to work on it" class="btn btn-default" aria-label="Left Align"
[disabled]="workOnTaskDisabled()" (click)="openTask()"> [disabled]="workOnTaskDisabled()" (click)="openTask()">
<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> <span class="glyphicon glyphicon-new-window blue" aria-hidden="true"></span>
</button> </button>
<button type="button" (click)="resetTask()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes"> <button type="button" (click)="resetTask()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
<span class="glyphicon glyphicon-repeat blue" aria-hidden="true"></span> <span class="glyphicon glyphicon-repeat blue" aria-hidden="true"></span>
</button> </button>
<button type="button" title="Delete Task" class="btn btn-default remove" <button type="button" title="Delete Task" class="btn btn-default remove" (click)="deleteTask()">
(click)="deleteTask()">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</button> </button>
</ng-container> </ng-container>
@ -53,25 +28,53 @@
<span *ngIf="!task.taskId" class="badge warning"> {{'Creating Task'}}</span> <span *ngIf="!task.taskId" class="badge warning"> {{'Creating Task'}}</span>
</h4> </h4>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form #TaskForm="ngForm"> <accordion *ngIf="task && !requestInProgress">
<div class="tab-content"> <accordion-group panelClass="customClass" isOpen="true" (isOpenChange)="accordion1State = $event" >
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'general'}"> <button class="btn btn-block clearfix" accordion-heading>
<taskana-task-details-general-fields [_task]="task"></taskana-task-details-general-fields> <div class="pull-left float-left">1 - Information</div>
</div> <span class="float-right pull-right glyphicon blue" [ngClass]="{
'glyphicon-chevron-up': !accordion1State,
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'custom'}"> 'glyphicon-chevron-down': accordion1State}"></span>
<taskana-task-details-custom-fields [task]="task"></taskana-task-details-custom-fields> </button>
</div> <taskana-task-details-general-fields [task]="task" [saveToggleTriggered]="toggleFormValidation" (formValid)="onSubmit()"></taskana-task-details-general-fields>
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'custom-attributes'}"> </accordion-group>
<taskana-task-details-attributes [attributes]="task.customAttributes"></taskana-task-details-attributes> <accordion-group panelClass="customClass" (isOpenChange)="accordion2State = $event">
</div> <button class="btn btn-block clearfix" accordion-heading>
<div role="tabpanel" class="tab-pane" [ngClass]="{'active':tabSelected === 'callback-info'}"> <div class="pull-left float-left">2 - Status details</div>
<taskana-task-details-attributes [attributes]="task.callbackInfo" <span class="float-right pull-right glyphicon blue" [ngClass]="{
[callbackInfo]="true"></taskana-task-details-attributes> 'glyphicon-chevron-up': !accordion2State,
</div> 'glyphicon-chevron-down': accordion2State}"></span>
</div> </button>
</form> <taskana-general-fields-extension [task]="task"></taskana-general-fields-extension>
</accordion-group>
<accordion-group panelClass="customClass" (isOpenChange)="accordion3State = $event">
<button class="btn btn-block clearfix" accordion-heading>
<div class="pull-left float-left">3 - Custom fields</div>
<span class="float-right pull-right glyphicon blue" [ngClass]="{
'glyphicon-chevron-up': !accordion3State,
'glyphicon-chevron-down': accordion3State}"></span>
</button>
<taskana-task-details-custom-fields [task]="task"></taskana-task-details-custom-fields>
</accordion-group>
<accordion-group panelClass="customClass" (isOpenChange)="accordion4State = $event">
<button class="btn btn-block clearfix" accordion-heading>
<div class="pull-left float-left">4 - Custom attributes</div>
<span class="float-right pull-right glyphicon blue" [ngClass]="{
'glyphicon-chevron-up': !accordion4State,
'glyphicon-chevron-down': accordion4State}"></span>
</button>
<taskana-task-details-attributes [attributes]="task.customAttributes"></taskana-task-details-attributes>
</accordion-group>
<accordion-group panelClass="customClass" (isOpenChange)="accordion5State = $event">
<button class="btn btn-block clearfix" accordion-heading>
<div class="pull-left float-left">5 - Callback information</div>
<span class="float-right pull-right glyphicon blue" [ngClass]="{
'glyphicon-chevron-up': !accordion5State,
'glyphicon-chevron-down': accordion5State}"></span>
</button>
<taskana-task-details-attributes [attributes]="task.callbackInfo" [callbackInfo]="true"></taskana-task-details-attributes>
</accordion-group>
</accordion>
</div> </div>
</div> </div>

View File

@ -1,3 +1,29 @@
.panel > .panel-body { @import './src/assets/_colors';
max-height: calc(100vh - 150px);
::ng-deep .btn-block {
background-color: whitesmoke;
font-size: 16px;
font-weight: 700;
} }
::ng-deep .panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group {
border: none;
}
::ng-deep .collapse {
-webkit-transition: max-height 0.5s ease;
-moz-transition: max-height 0.5s ease;
-o-transition: max-height 0.5s ease;
-ms-transition: max-height 0.5s ease;
transition: max-height 0.5s ease;
display: block!important;
overflow: hidden!important;
visibility: visible!important;
max-height: 0;
&.in {
max-height: 2000px;
overflow: visible!important;
}
}

View File

@ -1,20 +1,21 @@
import {Component, OnDestroy, OnInit} from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import {Subscription} from 'rxjs'; import { Subscription } from 'rxjs';
import {ActivatedRoute, Router} from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import {TaskService} from 'app/workplace/services/task.service'; import { TaskService } from 'app/workplace/services/task.service';
import {RemoveConfirmationService} from 'app/services/remove-confirmation/remove-confirmation.service'; import { RemoveConfirmationService } from 'app/services/remove-confirmation/remove-confirmation.service';
import {Task} from 'app/workplace/models/task'; import { Task } from 'app/workplace/models/task';
import {ErrorModel} from 'app/models/modal-error'; import { ErrorModel } from 'app/models/modal-error';
import {ErrorModalService} from 'app/services/errorModal/error-modal.service'; import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import {RequestInProgressService} from 'app/services/requestInProgress/request-in-progress.service'; import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import {AlertService} from 'app/services/alert/alert.service'; import { AlertService } from 'app/services/alert/alert.service';
import {AlertModel, AlertType} from 'app/models/alert'; import { AlertModel, AlertType } from 'app/models/alert';
import {TaskanaDate} from 'app/shared/util/taskana.date'; import { TaskanaDate } from 'app/shared/util/taskana.date';
import {ObjectReference} from 'app/workplace/models/object-reference'; import { ObjectReference } from 'app/workplace/models/object-reference';
import {Workbasket} from 'app/models/workbasket'; import { Workbasket } from 'app/models/workbasket';
import {WorkplaceService} from 'app/workplace/services/workplace.service'; import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
@Component({ @Component({
selector: 'taskana-task-details', selector: 'taskana-task-details',
@ -28,18 +29,21 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
tabSelected = 'general'; tabSelected = 'general';
currentWorkbasket: Workbasket = undefined; currentWorkbasket: Workbasket = undefined;
currentId: string = undefined; currentId: string = undefined;
showDetail = false;
private routeSubscription: Subscription; private routeSubscription: Subscription;
private workbasketSubscription: Subscription; private workbasketSubscription: Subscription;
private masterAndDetailSubscription: Subscription;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private taskService: TaskService, private taskService: TaskService,
private workplaceService: WorkplaceService, private workplaceService: WorkplaceService,
private router: Router, private router: Router,
private removeConfirmationService: RemoveConfirmationService, private removeConfirmationService: RemoveConfirmationService,
private requestInProgressService: RequestInProgressService, private requestInProgressService: RequestInProgressService,
private alertService: AlertService, private alertService: AlertService,
private errorModalService: ErrorModalService) { private errorModalService: ErrorModalService,
private masterAndDetailService: MasterAndDetailService) {
} }
ngOnInit() { ngOnInit() {
@ -55,13 +59,16 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
} }
this.getTask(); this.getTask();
}); });
this.masterAndDetailSubscription = this.masterAndDetailService.getShowDetail().subscribe(showDetail => {
this.showDetail = showDetail;
});
} }
resetTask(): void { resetTask(): void {
this.task = {...this.taskClone}; this.task = { ...this.taskClone };
this.task.customAttributes = this.taskClone.customAttributes.slice(0); this.task.customAttributes = this.taskClone.customAttributes.slice(0);
this.task.callbackInfo = this.taskClone.callbackInfo.slice(0); this.task.callbackInfo = this.taskClone.callbackInfo.slice(0);
this.task.primaryObjRef = {...this.taskClone.primaryObjRef}; this.task.primaryObjRef = { ...this.taskClone.primaryObjRef };
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields')); this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'Reset edited fields'));
} }
@ -83,43 +90,13 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
} }
} }
onSave() { onSubmit() {
this.requestInProgressService.setRequestInProgress(true); this.onSave();
this.currentId === 'new-task' ? this.createTask() : this.updateTask();
} }
updateTask() {
this.taskService.updateTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.task = task;
this.cloneTask();
this.taskService.publishUpdatedTask(task);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Update successful!'))
}, err => {
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Update not successful!'))
});
}
createTask() {
this.addDateToTask();
this.taskService.createTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Task ${this.currentId} was created successfully`));
this.task = task;
this.taskService.selectTask(this.task);
this.taskService.publishAddedTask(task);
this.router.navigate(['../' + task.taskId], {relativeTo: this.route});
});
}
private addDateToTask() {
const date = TaskanaDate.getDate();
this.task.created = date;
this.task.modified = date;
}
openTask() { openTask() {
this.router.navigate([{outlets: {detail: `task/${this.currentId}`}}], {relativeTo: this.route.parent}); this.router.navigate([{ outlets: { detail: `task/${this.currentId}` } }], { relativeTo: this.route.parent });
} }
workOnTaskDisabled(): boolean { workOnTaskDisabled(): boolean {
@ -142,22 +119,69 @@ export class TaskdetailsComponent implements OnInit, OnDestroy {
this.tabSelected = tab; this.tabSelected = tab;
} }
backClicked(): void { backClicked(): void {
this.task = undefined; this.task = undefined;
this.taskService.selectTask(this.task); this.taskService.selectTask(this.task);
this.router.navigate(['./'], {relativeTo: this.route.parent}); this.router.navigate(['./'], { relativeTo: this.route.parent });
}
private onSave() {
this.currentId === 'new-task' ? this.createTask() : this.updateTask();
}
private updateTask() {
this.requestInProgressService.setRequestInProgress(true);
this.taskService.updateTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.task = task;
this.cloneTask();
this.taskService.publishUpdatedTask(task);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Updating was successful.'))
}, err => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'There was an error while updating.'))
});
}
private createTask() {
this.requestInProgressService.setRequestInProgress(true);
this.addDateToTask();
this.taskService.createTask(this.task).subscribe(task => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, `Task ${this.currentId} was created successfully.`));
this.task = task;
this.taskService.selectTask(this.task);
this.taskService.publishAddedTask(task);
this.router.navigate(['../' + task.taskId], { relativeTo: this.route });
}, err => {
this.requestInProgressService.setRequestInProgress(false);
this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'There was an error while creating a new task.'))
});
}
private addDateToTask() {
const date = TaskanaDate.getDate();
this.task.created = date;
this.task.modified = date;
}
private cloneTask() {
this.taskClone = { ...this.task };
this.taskClone.customAttributes = this.task.customAttributes.slice(0);
this.taskClone.callbackInfo = this.task.callbackInfo.slice(0);
this.taskClone.primaryObjRef = { ...this.task.primaryObjRef };
} }
ngOnDestroy(): void { ngOnDestroy(): void {
if (this.routeSubscription) { if (this.routeSubscription) {
this.routeSubscription.unsubscribe(); this.routeSubscription.unsubscribe();
if (this.workbasketSubscription) {
this.workbasketSubscription.unsubscribe();
}
if (this.masterAndDetailSubscription) {
this.masterAndDetailSubscription.unsubscribe();
}
} }
} }
private cloneTask() {
this.taskClone = {...this.task};
this.taskClone.customAttributes = this.task.customAttributes.slice(0);
this.taskClone.callbackInfo = this.task.callbackInfo.slice(0);
this.taskClone.primaryObjRef = {...this.task.primaryObjRef};
}
} }

View File

@ -1,35 +1,23 @@
<li id="tasklist-action-toolbar" class="list-group-item tab-align"> <li id="tasklist-action-toolbar" class="list-group-item tab-align">
<div class="row"> <div class="row">
<div *ngIf="currentBasket" class="col-xs-2"> <div *ngIf="currentBasket" class="col-xs-2">
<button (click)="createTask()" type="button" <button (click)="createTask()" type="button" class="btn btn-default pull-left green-blue" title="Add Task to current Workbasket">
class="btn btn-default pull-left green-blue"
title="Add Task to current Workbasket">
<span class="glyphicon glyphicon-plus"></span> <span class="glyphicon glyphicon-plus"></span>
</button> </button>
</div> </div>
<div class="col-xs-7"> <div class="col-xs-6">
<input [(ngModel)]="resultName" [typeahead]="workbasketNames" class="form-control" <input [(ngModel)]="resultName" [typeahead]="workbasketNames" class="form-control" (typeaheadOnSelect)="searchBasket()"
(typeaheadOnSelect)="searchBasket()" (typeaheadNoResults)="workbasketSelected = false" (typeaheadNoResults)="workbasketSelected = false" placeholder="Search for Workbasket ..." />
placeholder="Search for Workbasket ..."/>
</div> </div>
<div *ngIf="currentBasket" class="pull-right margin-right">
<div class="pull-right margin-right"> <button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" aria-expanded="false" (click)="toolbarState=!toolbarState">
<taskana-sort
[sortingFields]="sortingFields"
(performSorting)="sorting($event)"></taskana-sort>
<button class="btn btn-default collapsed" type="button"
id="collapsedMenufilterWb" aria-expanded="false"
(click)="toolbarState=!toolbarState">
<span class="glyphicon glyphicon-filter blue"></span> <span class="glyphicon glyphicon-filter blue"></span>
</button> </button>
<taskana-sort [sortingFields]="sortingFields" (performSorting)="sorting($event)" class="btn-group"></taskana-sort>
</div> </div>
</div> </div>
<div [@toggleDown]="toolbarState" class="row no-overflow"> <div [@toggleDown]="toolbarState" class="row no-overflow">
<taskana-filter <taskana-filter [filterParams]="filterParams" [filterType]="filterType" (performFilter)="filtering($event)">
[filterParams]="filterParams"
[filterType]="filterType"
(performFilter)="filtering($event)">
</taskana-filter> </taskana-filter>
</div> </div>
</li> </li>

View File

@ -4,6 +4,7 @@
} }
.tab-align{ .tab-align{
padding: 8px 12px 8px 0px;
margin-bottom: 0px; margin-bottom: 0px;
&>div{ &>div{

View File

@ -1,14 +1,14 @@
import {Component, EventEmitter, OnInit, Output} from '@angular/core'; import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import {Task} from 'app/workplace/models/task'; import { Task } from 'app/workplace/models/task';
import {Workbasket} from 'app/models/workbasket'; import { Workbasket } from 'app/models/workbasket';
import {TaskService} from 'app/workplace/services/task.service'; import { TaskService } from 'app/workplace/services/task.service';
import {WorkbasketService} from 'app/services/workbasket/workbasket.service'; import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import {SortingModel} from 'app/models/sorting'; import { SortingModel } from 'app/models/sorting';
import {FilterModel} from 'app/models/filter'; import { FilterModel } from 'app/models/filter';
import {TaskanaType} from 'app/models/taskana-type'; import { TaskanaType } from 'app/models/taskana-type';
import {expandDown} from 'app/shared/animations/expand.animation'; import { expandDown } from 'app/shared/animations/expand.animation';
import {ActivatedRoute, Router} from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import {WorkplaceService} from 'app/workplace/services/workplace.service'; import { WorkplaceService } from 'app/workplace/services/workplace.service';
@Component({ @Component({
selector: 'taskana-tasklist-toolbar', selector: 'taskana-tasklist-toolbar',
@ -23,7 +23,7 @@ export class TaskListToolbarComponent implements OnInit {
sortingFields = new Map([['name', 'Name'], ['priority', 'Priority'], ['due', 'Due'], ['planned', 'Planned']]); sortingFields = new Map([['name', 'Name'], ['priority', 'Priority'], ['due', 'Due'], ['planned', 'Planned']]);
filterParams = {name: '', key: '', owner: '', priority: '', state: ''}; filterParams = { name: '', key: '', owner: '', priority: '', state: '' };
tasks: Task[] = []; tasks: Task[] = [];
workbasketNames: string[] = []; workbasketNames: string[] = [];
@ -36,10 +36,10 @@ export class TaskListToolbarComponent implements OnInit {
filterType = TaskanaType.TASKS; filterType = TaskanaType.TASKS;
constructor(private taskService: TaskService, constructor(private taskService: TaskService,
private workbasketService: WorkbasketService, private workbasketService: WorkbasketService,
private workplaceService: WorkplaceService, private workplaceService: WorkplaceService,
private router: Router, private router: Router,
private route: ActivatedRoute) { private route: ActivatedRoute) {
} }
ngOnInit() { ngOnInit() {
@ -91,6 +91,6 @@ export class TaskListToolbarComponent implements OnInit {
createTask() { createTask() {
this.taskService.selectTask(undefined); this.taskService.selectTask(undefined);
this.router.navigate([{outlets: {detail: 'taskdetail/new-task'}}], {relativeTo: this.route}); this.router.navigate([{ outlets: { detail: 'taskdetail/new-task' } }], { relativeTo: this.route });
} }
} }

View File

@ -1,20 +1,37 @@
<div class="taskana-task-list"> <div class="footer-space-pagination-list">
<div #wbToolbar> <div #wbToolbar>
<taskana-tasklist-toolbar (performSorting)="performSorting($event)" (performFilter)="performFilter($event)" (importSucessful)="refreshWorkbasketList()"> <taskana-tasklist-toolbar (performSorting)="performSorting($event)" (performFilter)="performFilter($event)"
(importSucessful)="refreshWorkbasketList()">
</taskana-tasklist-toolbar> </taskana-tasklist-toolbar>
</div> </div>
<div *ngIf="!requestInProgress" class="footer-space-task"> <div *ngIf="!requestInProgress">
<div *ngIf="(tasks && tasks.length > 0); else empty_list"> <div *ngIf="(tasks && tasks.length > 0); else empty_list">
<ul #taskList id="task-list-container" class="list-group"> <ul #taskList id="task-list-container" class="list-group">
<li class="list-group-item" *ngFor="let task of tasks" [class.active]="task.taskId == selectedId" type="text" <li class="list-group-item" *ngFor="let task of tasks" [class.active]="task.taskId == selectedId" type="text"
(click)="selectTask(task.taskId)"> (click)="selectTask(task.taskId)">
<div class="row"> <div class="row">
<dl class="col-xs-10"> <dl class="col-xs-2">
<dt data-toggle="tooltip" title="{{task.name}}">{{task.name}}</dt> <span data-toggle="tooltip" class="badge" [ngClass]="{
<dd data-toggle="tooltip" title="{{task.owner}}">Owner: {{task.owner}} &nbsp;</dd> 'badge-red': task.priority <=5,
<dd data-toggle="tooltip" title="{{task.priority}}">Priority: {{task.priority}} &nbsp;</dd> 'badge-orange': (task.priority > 5 && task.priority <=15),
<dd data-toggle="tooltip" title="{{task.state}}">State: {{task.state}} &nbsp;</dd> 'badge-green': task.priority > 15}"
title="{{task.priority}}">{{task.priority}}</span>
</dl> </dl>
<dl class="col-xs-8">
<dt>
<span data-toggle="tooltip" title="{{task.name}}">{{task.name}}</span>
<i *ngIf="task.owner" data-toggle="tooltip" title="{{task.owner}}">, {{task.owner}}</i>
</dt>
</dl>
</div>
<div class="row">
<dl class="col-xs-3 col-xs-offset-2">
<dd data-toggle="tooltip" title="{{task.state}}">{{task.state}}</dd>
</dl>
<dl class="pull-right padding-right">
<i data-toggle="tooltip" title="{{task.due}}">Due: {{displayDate(task.due)}}</i>
</dl>
</div> </div>
</li> </li>
</ul> </ul>
@ -26,6 +43,6 @@
</div> </div>
</ng-template> </ng-template>
</div> </div>
<taskana-pagination *ngIf="tasks && tasks.length > 0" [(page)]="page" [type]="type" (changePage)="changePage($event)"></taskana-pagination>
</div> </div>
<taskana-code></taskana-code> <taskana-pagination *ngIf="tasks && tasks.length > 0" [(page)]="tasksPageInformation" [type]="type" (changePage)="changePage($event)"></taskana-pagination>
<taskana-code></taskana-code>

View File

@ -2,44 +2,15 @@
cursor: pointer; cursor: pointer;
} }
.row.list-group {
margin-left: 2px;
}
.list-group > li { .list-group > li {
border-left: none; border-left: none;
border-right: none; border-right: none;
} }
ul {
max-height: 90vh;
margin-bottom: 10px;
overflow-y: auto;
}
a > label {
height: 2em;
width: 100%;
}
dd, dt {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
dt > i {
font-weight: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
li > div.row > dl { li > div.row > dl {
margin-bottom: 0px; margin-bottom: 0px;
} }
.no-space { .list-group-item>div>dl>span.badge{
border-top: none; margin-left: 8px;
padding: 0px
} }

View File

@ -1,18 +1,19 @@
import {Component, OnDestroy, OnInit, ViewChild, ElementRef} from '@angular/core'; import { Component, OnDestroy, OnInit, ViewChild, ElementRef } from '@angular/core';
import {Task} from 'app/workplace/models/task'; import { Task } from 'app/workplace/models/task';
import {ActivatedRoute, Router} from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import {TaskService} from 'app/workplace/services/task.service'; import { TaskService } from 'app/workplace/services/task.service';
import {Subscription} from 'rxjs'; import { Subscription } from 'rxjs';
import {SortingModel} from 'app/models/sorting'; import { SortingModel } from 'app/models/sorting';
import {Workbasket} from 'app/models/workbasket'; import { Workbasket } from 'app/models/workbasket';
import {FilterModel} from 'app/models/filter'; import { FilterModel } from 'app/models/filter';
import {AlertService} from 'app/services/alert/alert.service'; import { AlertService } from 'app/services/alert/alert.service';
import {AlertModel, AlertType} from 'app/models/alert'; import { AlertModel, AlertType } from 'app/models/alert';
import {WorkplaceService} from 'app/workplace/services/workplace.service'; import { WorkplaceService } from 'app/workplace/services/workplace.service';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters'; import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { Page } from 'app/models/page';
import { OrientationService } from 'app/services/orientation/orientation.service'; import { OrientationService } from 'app/services/orientation/orientation.service';
import { Orientation } from 'app/models/orientation'; import { Orientation } from 'app/models/orientation';
import { Page } from 'app/models/page';
import { TaskanaDate } from 'app/shared/util/taskana.date';
@Component({ @Component({
selector: 'taskana-task-list', selector: 'taskana-task-list',
@ -22,10 +23,7 @@ import { Orientation } from 'app/models/orientation';
export class TasklistComponent implements OnInit, OnDestroy { export class TasklistComponent implements OnInit, OnDestroy {
tasks: Task[]; tasks: Task[];
tasksPageInformation: Page;
page: Page;
pageSelected = 1;
pageSize = 6;
type = 'tasks'; type = 'tasks';
currentBasket: Workbasket; currentBasket: Workbasket;
selectedId = ''; selectedId = '';
@ -50,11 +48,11 @@ export class TasklistComponent implements OnInit, OnDestroy {
private orientationSubscription: Subscription; private orientationSubscription: Subscription;
constructor(private router: Router, constructor(private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private taskService: TaskService, private taskService: TaskService,
private workplaceService: WorkplaceService, private workplaceService: WorkplaceService,
private alertService: AlertService, private alertService: AlertService,
private orientationService: OrientationService) { private orientationService: OrientationService) {
this.taskChangeSubscription = this.taskService.taskChangedStream.subscribe(task => { this.taskChangeSubscription = this.taskService.taskChangedStream.subscribe(task => {
for (let i = 0; i < this.tasks.length; i++) { for (let i = 0; i < this.tasks.length; i++) {
if (this.tasks[i].taskId === task.taskId) { if (this.tasks[i].taskId === task.taskId) {
@ -90,9 +88,7 @@ export class TasklistComponent implements OnInit, OnDestroy {
if (!task) { if (!task) {
this.selectedId = undefined; this.selectedId = undefined;
} }
}); });
TaskanaQueryParameters.page = this.pageSelected;
TaskanaQueryParameters.pageSize = this.pageSize;
this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => { this.orientationSubscription = this.orientationService.getOrientation().subscribe((orientation: Orientation) => {
this.refreshWorkbasketList(); this.refreshWorkbasketList();
}) })
@ -100,7 +96,7 @@ export class TasklistComponent implements OnInit, OnDestroy {
selectTask(taskId: string) { selectTask(taskId: string) {
this.selectedId = taskId; this.selectedId = taskId;
this.router.navigate([{outlets: {detail: `taskdetail/${this.selectedId}`}}], {relativeTo: this.route}); this.router.navigate([{ outlets: { detail: `taskdetail/${this.selectedId}` } }], { relativeTo: this.route });
} }
performSorting(sort: SortingModel) { performSorting(sort: SortingModel) {
@ -126,7 +122,7 @@ export class TasklistComponent implements OnInit, OnDestroy {
calculateHeightCard() { calculateHeightCard() {
if (this.toolbarElement && this.currentBasket) { if (this.toolbarElement && this.currentBasket) {
const toolbarSize = this.toolbarElement.nativeElement.offsetHeight; const toolbarSize = this.toolbarElement.nativeElement.offsetHeight;
const cardHeight = 95; const cardHeight = 53;
const unusedHeight = 140; const unusedHeight = 140;
const totalHeight = window.innerHeight; const totalHeight = window.innerHeight;
const cards = Math.round((totalHeight - (unusedHeight + toolbarSize)) / cardHeight); const cards = Math.round((totalHeight - (unusedHeight + toolbarSize)) / cardHeight);
@ -152,13 +148,15 @@ export class TasklistComponent implements OnInit, OnDestroy {
this.tasks = []; this.tasks = [];
this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'The selected Workbasket is empty!')); this.alertService.triggerAlert(new AlertModel(AlertType.INFO, 'The selected Workbasket is empty!'));
} }
if (tasks.page) { this.tasksPageInformation = tasks.page;
this.page = tasks.page;
}
}); });
} }
} }
displayDate(date: string): string {
return TaskanaDate.getDateToDisplay(date);
}
ngOnDestroy(): void { ngOnDestroy(): void {
this.taskChangeSubscription.unsubscribe(); this.taskChangeSubscription.unsubscribe();
this.taskDeletedSubscription.unsubscribe(); this.taskDeletedSubscription.unsubscribe();

View File

@ -1,34 +1,38 @@
import {CommonModule} from '@angular/common'; import { CommonModule } from '@angular/common';
import {NgModule} from '@angular/core'; import { NgModule } from '@angular/core';
import {FormsModule} from '@angular/forms'; import { FormsModule } from '@angular/forms';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import {AngularSvgIconModule} from 'angular-svg-icon'; import { AngularSvgIconModule } from 'angular-svg-icon';
import {WorkplaceRoutingModule} from './workplace-routing.module'; import { WorkplaceRoutingModule } from './workplace-routing.module';
import {AlertModule, TypeaheadModule} from 'ngx-bootstrap'; import { AlertModule, TypeaheadModule } from 'ngx-bootstrap';
import {TaskListToolbarComponent} from './tasklist/tasklist-toolbar/tasklist-toolbar.component'; import { TaskListToolbarComponent } from './tasklist/tasklist-toolbar/tasklist-toolbar.component';
import {TasklistComponent} from './tasklist/tasklist.component'; import { TasklistComponent } from './tasklist/tasklist.component';
import {TaskdetailsComponent} from './taskdetails/taskdetails.component'; import { TaskdetailsComponent } from './taskdetails/taskdetails.component';
import {TaskdetailsGeneralFieldsComponent} from './taskdetails/general/general-fields.component'; import { TaskdetailsGeneralFieldsComponent } from './taskdetails/general/general-fields.component';
import {TaskdetailsCustomFieldsComponent} from './taskdetails/custom/custom-fields.component'; import { TaskdetailsCustomFieldsComponent } from './taskdetails/custom/custom-fields.component';
import {TaskdetailsAttributeComponent} from './taskdetails/attribute/attribute.component'; import { TaskdetailsAttributeComponent } from './taskdetails/attribute/attribute.component';
import {TaskComponent} from './task/task.component'; import { TaskComponent } from './task/task.component';
import {CodeComponent} from './components/code/code.component'; import { CodeComponent } from './components/code/code.component';
import { GeneralFieldsExtensionComponent } from './taskdetails/general-fields-extension/general-fields-extension.component';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { OrderTasksByPipe } from './util/orderTasksBy.pipe';
import {OrderTasksByPipe} from './util/orderTasksBy.pipe'; import { TaskService } from './services/task.service';
import { ClassificationsService } from 'app/services/classifications/classifications.service';
import {TaskService} from './services/task.service'; import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import {ClassificationsService} from 'app/services/classifications/classifications.service'; import { SharedModule } from 'app/shared/shared.module';
import {WorkbasketService} from 'app/services/workbasket/workbasket.service'; import { CustomHttpClientInterceptor } from './services/custom-http-interceptor/custom-http-interceptor.service';
import {SharedModule} from 'app/shared/shared.module'; import { ClassificationCategoriesService } from 'app/services/classifications/classification-categories.service';
import {CustomHttpClientInterceptor} from './services/custom-http-interceptor/custom-http-interceptor.service'; import { WorkplaceService } from './services/workplace.service';
import {ClassificationCategoriesService} from 'app/services/classifications/classification-categories.service';
import {WorkplaceService} from './services/workplace.service';
const MODULES = [ const MODULES = [
TypeaheadModule.forRoot(), TypeaheadModule.forRoot(),
AccordionModule.forRoot(),
BsDropdownModule.forRoot(),
CommonModule, CommonModule,
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
@ -47,6 +51,7 @@ const DECLARATIONS = [
TaskdetailsAttributeComponent, TaskdetailsAttributeComponent,
TaskComponent, TaskComponent,
CodeComponent, CodeComponent,
GeneralFieldsExtensionComponent,
OrderTasksByPipe OrderTasksByPipe
]; ];

View File

@ -3,10 +3,12 @@ $blue: #2e9eca;
$green: #246972; $green: #246972;
$dark-green: #175263; $dark-green: #175263;
$grey: grey; $grey: grey;
$light-grey: #ddd; $light-grey: #f5f5f5;
$brown: #f0ad4e; $brown: #f0ad4e;
$invalid: #d82626; $invalid: #d82626;
$aquamarine: #22a39f; $aquamarine: #22a39f;
$pallete-blue: #36bcee; $pallete-blue: #36bcee;
$pallete-green: #5fbca1; $pallete-green: #5fbca1;
$transparent-grey: rgba(192, 192, 192, 0.65); $transparent-grey: rgba(192, 192, 192, 0.65);

View File

@ -8,3 +8,4 @@
@import 'checkboxes'; @import 'checkboxes';
@import 'tabs'; @import 'tabs';
@import 'bootstrap-3-backward-compatibility'; @import 'bootstrap-3-backward-compatibility';
@import 'mixin/colors';

View File

@ -17,7 +17,6 @@
border-radius: 0px; border-radius: 0px;
} }
/* /*
* Base structure * Base structure
*/ */
@ -154,20 +153,13 @@ svg-icon.fa-fw > svg {
min-width: 0px; min-width: 0px;
} }
.footer-space-workbasket { .footer-space-pagination-list {
max-height: calc(100vh - 140px); max-height: calc(100vh - 130px);
height: calc(100vh - 140px); height: calc(100vh - 130px);
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.footer-space-task {
max-height: calc(100vh - 182px);
height: calc(100vh - 150px);
overflow-y: auto;
overflow-x: hidden;
}
.margin-right { .margin-right {
margin-right: 2px; margin-right: 2px;
} }
@ -286,8 +278,8 @@ body{
} }
} }
taskana-workbasket-information,taskana-task-details, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-monitor-tasks, taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-workbasket-details, taskana-monitor-tasks,
taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management, taskana-classification-details,taskana-workbasket-details { taskana-monitor-workbaskets, taskana-monitor-classification-tasks {
& .panel{ & .panel{
border: none; border: none;
box-shadow: none; box-shadow: none;
@ -300,8 +292,17 @@ taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-acces
} }
} }
.taskana-workbasket-list, .taskana-task-list { taskana-task-details, taskana-classification-details, taskana-access-items-management, taskana-task {
height: calc(100vh - 55px); & .panel{
border: none;
box-shadow: none;
margin-bottom: 0px;
&> .panel-body {
height: calc(100vh - 100px);
max-height: calc(100vh - 100px);
overflow-y: auto;
}
}
} }
taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management { taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management {
@ -330,6 +331,7 @@ li.list-group-item:hover {
.vertical-right-divider { .vertical-right-divider {
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
height: calc(100vh - 55px);
} }
.horizontal-bottom-divider { .horizontal-bottom-divider {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
@ -340,12 +342,21 @@ li.list-group-item:hover {
width: 150px; width: 150px;
height: 150px; height: 150px;
fill: grey; fill: grey;
color: grey;
margin: 20px auto; margin: 20px auto;
font-size: 100px;
} }
.btn.no-style{
border: none;
background-color: transparent;
}
.align-header{
margin-top: 3px;
}
.container-no-items { .container-no-items {
top: 20vh; top: 20vh;
height: 60vh; height: 40vh;
} }
.center-block { .center-block {
@ -367,3 +378,6 @@ li.list-group-item:hover {
.modal-backdrop.show { .modal-backdrop.show {
background-color: $transparent-grey; background-color: $transparent-grey;
} }
.padding-right.pull-right {
padding-right: 15px;
}

View File

@ -1,5 +1,9 @@
.dropdown-menu.show { .dropdown-menu.show, .modal-backdrop.show, .fade.show {
display: block; display: block;
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
.modal.fade .modal-dialog {
transform: translate(0,0);
}

View File

@ -0,0 +1,17 @@
@mixin colors {
&-red {
background-color: $invalid;
}
&-green {
background-color: $pallete-green;
}
&-orange {
background-color: $brown;
}
}
.badge{
@include colors;
}

View File

@ -57,6 +57,13 @@
"AUTOMATIC": "assets/icons/categories/automatic.svg", "AUTOMATIC": "assets/icons/categories/automatic.svg",
"PROCESS": "assets/icons/categories/process.svg" "PROCESS": "assets/icons/categories/process.svg"
} }
},
"tasks": {
"information": {
"owner": {
"lookupField": true
}
}
} }
} }
} }