Joining lib, rest and web

This commit is contained in:
Jose Ignacio Recuerda Cambil 2018-08-30 12:46:53 +02:00 committed by Mustapha Zorgati
parent 3f8dc3cf87
commit ec432d122a
38 changed files with 724 additions and 175 deletions

View File

@ -379,4 +379,4 @@ public class LdapCacheTestImpl implements LdapCache {
new AccessIdResource("haftpflicht", "cn=haftpflicht,ou=groups,o=TaskanaTest"),
new AccessIdResource("bauspar", "cn=bauspar,ou=groups,o=TaskanaTest")));
}
}

View File

@ -19,6 +19,8 @@ import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.rest.resource.WorkbasketAccesItemExtendedResource;
import pro.taskana.rest.resource.assembler.WorkbasketAccessItemExtendedAssembler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -85,7 +87,7 @@ public class WorkbasketAccessItemController extends AbstractPagingController {
private WorkbasketAccessItemExtendedQuery getAccessIds(WorkbasketAccessItemExtendedQuery query,
MultiValueMap<String, String> params) throws InvalidArgumentException {
if (params.containsKey(ACCESS_IDS)) {
String[] accessIds = extractCommaSeparatedFields(params.get(ACCESS_IDS));
String[] accessIds = extractVerticalBarSeparatedFields(params.get(ACCESS_IDS));
query.accessIdIn(accessIds);
params.remove(ACCESS_IDS);
}
@ -142,4 +144,12 @@ public class WorkbasketAccessItemController extends AbstractPagingController {
return query;
}
private String[] extractVerticalBarSeparatedFields(List<String> searchFor) {
List<String> values = new ArrayList<>();
if (searchFor != null) {
searchFor.forEach(item -> values.addAll(Arrays.asList(item.split("\\|"))));
}
return values.toArray(new String[0]);
}
}

View File

@ -7,10 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
<<<<<<< HEAD
import pro.taskana.WorkbasketAccessItem;
=======
>>>>>>> a89fa20c... TSK-694 - Show list of all access items valid for a user (REST)
import pro.taskana.WorkbasketAccessItemExtended;
import pro.taskana.WorkbasketService;
import pro.taskana.impl.WorkbasketAccessItemExtendedImpl;

View File

@ -0,0 +1,169 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right btn-group">
<button *ngIf="AccessItemsForm" type="button" (click)="revokeAccess()" class="btn btn-default" data-toggle="tooltip" title="Revoke access">
<span class="glyphicon glyphicon-remove red" aria-hidden="true"></span>
</button>
</div>
<h4 class="panel-header">Acces items management</h4>
</div>
<div class="panel-body">
<div class="col-md-6 col-md-offset-3 margin">
<taskana-type-ahead #accesId="ngModel" name="accessIdSelected" [(ngModel)]="accessIdSelected" placeHolderMessage="Search for access id..."
(onSelect)="onSelectAccessId($event)" displayError=true></taskana-type-ahead>
</div>
<div *ngIf="!AccessItemsForm" class="center-block no-detail col-xs-12">
<h3 class="grey">Select an access id</h3>
<svg-icon class="empty-icon" src="./assets/icons/users.svg"></svg-icon>
</div>
<div *ngIf="AccessItemsForm" class="row col-xs-12">
<form [formGroup]="AccessItemsForm">
<table id="table-access-items" class="table table-striped table-center">
<thead>
<tr>
<th>
<taskana-sort [sortingFields]="sortingFields" (performSorting)="sorting($event)" menuPosition="left"></taskana-sort>
</th>
<th class="text-align min-width">Workbasket Key</th>
<th colspan="2" class="text-align">Access Id</th>
<th>Read</th>
<th>Open</th>
<th>Append</th>
<th>Transfer</th>
<th>Distribute</th>
<th *ngIf="custom1Field.visible">{{custom1Field.field}}</th>
<th *ngIf="custom2Field.visible">{{custom2Field.field}}</th>
<th *ngIf="custom3Field.visible">{{custom3Field.field}}</th>
<th *ngIf="custom4Field.visible">{{custom4Field.field}}</th>
<th *ngIf="custom5Field.visible">{{custom5Field.field}}</th>
<th *ngIf="custom6Field.visible">{{custom6Field.field}}</th>
<th *ngIf="custom7Field.visible">{{custom7Field.field}}</th>
<th *ngIf="custom8Field.visible">{{custom8Field.field}}</th>
<th *ngIf="custom9Field.visible">{{custom9Field.field}}</th>
<th *ngIf="custom10Field.visible">{{custom10Field.field}}</th>
<th *ngIf="custom11Field.visible">{{custom11Field.field}}</th>
<th *ngIf="custom12Field.visible">{{custom12Field.field}}</th>
</tr>
<tr>
<th colspan="2" class="text-align"><input type="text" formControlName="workbasketKeyFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
class="form-control" placeholder="Workbasket filter"></th>
<th class="text-align"><input type="text" formControlName="accessIdFilter" (keyup.enter)="searchForAccessItemsWorkbaskets()"
class="form-control" placeholder="Access id filter"></th>
<th>
<button type="button" (click)="searchForAccessItemsWorkbaskets()" class="btn btn-default" data-toggle="tooltip" title="Search">
<span class="glyphicon glyphicon-search blue" aria-hidden="true"></span>
</button>
</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody formArrayName="accessItemsGroups">
<tr *ngFor="let accessItem of accessItemsGroups.controls; let index = index;" [formGroupName]="index">
<td colspan="2">
<label class="wrap">{{accessItem.value.workbasketKey}}</label>
</td>
<td *ngIf="accessIdField.lookupField else accessIdInput" colspan="2" class="text-align text-width taskana-type-ahead">
<div>
<taskana-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required" [validationValue]="toogleValidationAccessIdMap.get(index)"
[displayError]="!isFieldValid('accessItem.value.accessId', index)" [disable]=true></taskana-type-ahead>
</div>
</td>
<ng-template #accessIdInput>
<td colspan="2" class="text-align text-width">
<div>
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
'* Access id is required': ''}}">
</div>
</td>
</ng-template>
<td>
<input id="checkbox-{{index}}-0" type="checkbox" formControlName="permRead" class="regular-checkbox">
<label for="checkbox-{{index}}-0"></label>
</td>
<td>
<input id="checkbox-{{index}}-1" type="checkbox" formControlName="permOpen">
<label for="checkbox-{{index}}-1"></label>
</td>
<td>
<input id="checkbox-{{index}}-2" type="checkbox" formControlName="permAppend">
<label for="checkbox-{{index}}-2"></label>
</td>
<td>
<input id="checkbox-{{index}}-3" type="checkbox" formControlName="permTransfer">
<label for="checkbox-{{index}}-3"></label>
</td>
<td>
<input id="checkbox-{{index}}-4" type="checkbox" formControlName="permDistribute">
<label for="checkbox-{{index}}-4"></label>
</td>
<td *ngIf="custom1Field.visible">
<input id="checkbox-{{index}}-5" type="checkbox" formControlName="permCustom1">
<label for="checkbox-{{index}}-5"></label>
</td>
<td *ngIf="custom2Field.visible">
<input id="checkbox-{{index}}-6" type="checkbox" formControlName="permCustom2">
<label for="checkbox-{{index}}-6"></label>
</td>
<td *ngIf="custom3Field.visible">
<input id="checkbox-{{index}}-7" type="checkbox" formControlName="permCustom3">
<label for="checkbox-{{index}}-7"></label>
</td>
<td *ngIf="custom4Field.visible">
<input id="checkbox-{{index}}-8" type="checkbox" formControlName="permCustom4">
<label for="checkbox-{{index}}-8"></label>
</td>
<td *ngIf="custom5Field.visible">
<input id="checkbox-{{index}}-9" type="checkbox" formControlName="permCustom5">
<label for="checkbox-{{index}}-9"></label>
</td>
<td *ngIf="custom6Field.visible">
<input id="checkbox-{{index}}-10" type="checkbox" formControlName="permCustom6">
<label for="checkbox-{{index}}-10"></label>
</td>
<td *ngIf="custom7Field.visible">
<input id="checkbox-{{index}}-11" type="checkbox" formControlName="permCustom7">
<label for="checkbox-{{index}}-11"></label>
</td>
<td *ngIf="custom8Field.visible">
<input id="checkbox-{{index}}-12" type="checkbox" formControlName="permCustom8">
<label for="checkbox-{{index}}-12"></label>
</td>
<td *ngIf="custom9Field.visible">
<input id="checkbox-{{index}}-13" type="checkbox" formControlName="permCustom9">
<label for="checkbox-{{index}}-13"></label>
</td>
<td *ngIf="custom10Field.visible">
<input id="checkbox-{{index}}-14" type="checkbox" formControlName="permCustom10">
<label for="checkbox-{{index}}-14"></label>
</td>
<td *ngIf="custom11Field.visible">
<input id="checkbox-{{index}}-15" type="checkbox" formControlName="permCustom11">
<label for="checkbox-{{index}}-15"></label>
</td>
<td *ngIf="custom12Field.visible">
<input id="checkbox-{{index}}-16" type="checkbox" formControlName="permCustom12">
<label for="checkbox-{{index}}-16"></label>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,33 @@
@import './src/assets/_colors';
.margin {
margin-top: 10px;
margin-bottom: 20px;
}
.required-header:after {
content:" *";
color: $invalid;
}
td {
&.has-changes {
border-bottom: 1px solid $brown;
}
}
.table > thead > tr > th {
max-width: 150px;
border-bottom: none;
}
.table > thead > tr:last-child > th {
max-width: 150px;
border-bottom: 2px solid $grey;
}
.wrap{
max-width: 150px;
word-wrap:break-word;
}
.min-width{ min-width: 135px;}

View File

@ -0,0 +1,41 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AccessItemsManagementComponent } from './access-items-management.component';
import { configureTests } from 'app/app.test.configuration';
import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.service';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { AccessIdDefinition } from 'app/models/access-id';
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
import { of } from 'rxjs';
describe('AccessItemsManagementComponent', () => {
let component: AccessItemsManagementComponent;
let fixture: ComponentFixture<AccessItemsManagementComponent>;
let accessIdsService;
beforeEach(done => {
const configure = (testBed: TestBed) => {
testBed.configureTestingModule({
imports: [],
declarations: [AccessItemsManagementComponent],
providers: [ AccessIdsService, FormsValidatorService]
})
};
configureTests(configure).then(testBed => {
fixture = TestBed.createComponent(AccessItemsManagementComponent);
component = fixture.componentInstance;
accessIdsService = TestBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsPermissions').and.returnValue(of(new Array<AccessIdDefinition>()));
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new AccessItemsWorkbasketResource()));
fixture.detectChanges();
done();
});
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,153 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormBuilder, FormArray, Validators, FormGroup, FormControl } from '@angular/forms';
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { Subscription } from 'rxjs';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { AccessIdDefinition } from '../../models/access-id';
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
import { AccessItemWorkbasket } from 'app/models/access-item-workbasket';
import { AccessIdsService } from '../../shared/services/access-ids/access-ids.service';
import { SortingModel } from 'app/models/sorting';
import { RequestInProgressService } from '../../services/requestInProgress/request-in-progress.service';
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { ErrorModel } from 'app/models/modal-error';
@Component({
selector: 'taskana-access-items-management',
templateUrl: './access-items-management.component.html',
styleUrls: ['./access-items-management.component.scss']
})
export class AccessItemsManagementComponent implements OnInit, OnDestroy {
accessIdSelected;
accessIdPrevious;
AccessItemsForm: FormGroup;
toogleValidationAccessIdMap = new Map<number, boolean>();
accessItemPermissionsSubscription: Subscription;
accessItemInformationsubscription: Subscription;
accessIdsWithGroups: Array<AccessIdDefinition>;
sortingFields = new Map([['workbasket-key', 'Workbasket Key'], ['access-id', 'Access id']]);
sortModel: SortingModel;
accessIdField = this.customFieldsService.getCustomField('Owner', 'workbaskets.access-items.accessId');
custom1Field = this.customFieldsService.getCustomField('Custom 1', 'workbaskets.access-items.custom1');
custom2Field = this.customFieldsService.getCustomField('Custom 2', 'workbaskets.access-items.custom2');
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.access-items.custom3');
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.access-items.custom4');
custom5Field = this.customFieldsService.getCustomField('Custom 5', 'workbaskets.access-items.custom5');
custom6Field = this.customFieldsService.getCustomField('Custom 6', 'workbaskets.access-items.custom6');
custom7Field = this.customFieldsService.getCustomField('Custom 7', 'workbaskets.access-items.custom7');
custom8Field = this.customFieldsService.getCustomField('Custom 8', 'workbaskets.access-items.custom8');
custom9Field = this.customFieldsService.getCustomField('Custom 9', 'workbaskets.access-items.custom9');
custom10Field = this.customFieldsService.getCustomField('Custom 10', 'workbaskets.access-items.custom10');
custom11Field = this.customFieldsService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
custom12Field = this.customFieldsService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
setAccessItemsGroups(accessItems: Array<AccessItemWorkbasket>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
AccessItemsFormGroups.map(accessItemGroup => {
accessItemGroup.controls['accessId'].setValidators(Validators.required);
for (const key of Object.keys(accessItemGroup.controls)) {
accessItemGroup.controls[key].disable();
}
});
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups);
if (!this.AccessItemsForm) { this.AccessItemsForm = this.formBuilder.group({}); }
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
if (!this.AccessItemsForm.value['workbasketKeyFilter']) { this.AccessItemsForm.addControl('workbasketKeyFilter', new FormControl()) }
if (!this.AccessItemsForm.value['accessIdFilter']) { this.AccessItemsForm.addControl('accessIdFilter', new FormControl()) }
};
get accessItemsGroups(): FormArray {
return this.AccessItemsForm ? this.AccessItemsForm.get('accessItemsGroups') as FormArray : null;
};
constructor(private formBuilder: FormBuilder,
private customFieldsService: CustomFieldsService,
private accessIdsService: AccessIdsService,
private formsValidatorService: FormsValidatorService,
private requestInProgressService: RequestInProgressService,
private errorModalService: ErrorModalService) { }
ngOnInit() {
}
onSelectAccessId(selected: AccessIdDefinition) {
if (!selected) {
this.AccessItemsForm = null;
return;
}
if (!this.AccessItemsForm || this.accessIdPrevious !== selected.accessId) {
this.accessIdPrevious = selected.accessId
this.unSubscribe(this.accessItemInformationsubscription)
this.accessItemInformationsubscription = this.accessIdsService.getAccessItemsInformation(selected.accessId, true)
.subscribe((accessIdsWithGroups: Array<AccessIdDefinition>) => {
this.accessIdsWithGroups = accessIdsWithGroups;
this.searchForAccessItemsWorkbaskets();
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorModalService.triggerError(
new ErrorModel(
'There was error while retrieving your access ids with groups',
error
)
)
}
)
}
}
isFieldValid(field: string, index: number): boolean {
return this.formsValidatorService.isFieldValid(this.accessItemsGroups[index], field);
}
sorting(sort: SortingModel) {
this.sortModel = sort;
this.searchForAccessItemsWorkbaskets();
}
searchForAccessItemsWorkbaskets() {
this.requestInProgressService.setRequestInProgress(true);
this.unSubscribe(this.accessItemPermissionsSubscription)
this.accessItemPermissionsSubscription = this.accessIdsService.getAccessItemsPermissions(
this.accessIdsWithGroups,
this.AccessItemsForm ? this.AccessItemsForm.value.accessIdFilter : undefined,
this.AccessItemsForm ? this.AccessItemsForm.value.workbasketKeyFilter : undefined,
this.sortModel,
true)
.subscribe((accessItemsResource: AccessItemsWorkbasketResource) => {
this.setAccessItemsGroups(accessItemsResource._embedded ? accessItemsResource._embedded.accessItems : []);
this.requestInProgressService.setRequestInProgress(false);
},
error => {
this.requestInProgressService.setRequestInProgress(false);
this.errorModalService.triggerError(
new ErrorModel(
'There was error while retrieving your access items',
error
)
);
})
}
revokeAccess() {
}
private unSubscribe(subscription: Subscription): void {
if (subscription) { subscription.unsubscribe(); }
}
ngOnDestroy(): void {
this.unSubscribe(this.accessItemPermissionsSubscription)
this.unSubscribe(this.accessItemInformationsubscription)
}
}

View File

@ -7,6 +7,7 @@ import { MasterAndDetailComponent } from 'app/shared/master-and-detail/master-an
import { ClassificationListComponent } from 'app/administration/classification/master/list/classification-list.component';
import { ClassificationDetailsComponent } from 'app/administration/classification/details/classification-details.component';
import { DomainGuard } from 'app/guards/domain-guard';
import { AccessItemsManagementComponent } from './access-items-management/access-items-management.component';
const routes: Routes = [
@ -35,7 +36,7 @@ const routes: Routes = [
{
path: 'classifications',
component: MasterAndDetailComponent,
canActivate: [DomainGuard],
canActivate: [DomainGuard],
children: [
{
path: '',
@ -49,6 +50,11 @@ const routes: Routes = [
}
]
},
{
path: 'access-items-management',
component: AccessItemsManagementComponent,
canActivate: [DomainGuard]
},
{
path: '',
redirectTo: 'workbaskets',

View File

@ -16,7 +16,6 @@ import {WorkbasketInformationComponent} from './workbasket/details/information/w
import {DistributionTargetsComponent} from './workbasket/details/distribution-targets/distribution-targets.component';
import {DualListComponent} from './workbasket/details/distribution-targets/dual-list/dual-list.component';
import {AccessItemsComponent} from './workbasket/details/access-items/access-items.component';
import {IconTypeComponent} from './components/type-icon/icon-type.component';
import {PaginationComponent} from './workbasket/master/list/pagination/pagination.component';
import {ClassificationListComponent} from './classification/master/list/classification-list.component';
import {ClassificationDetailsComponent} from './classification/details/classification-details.component';
@ -31,6 +30,7 @@ import {ClassificationDefinitionService} from './services/classification-definit
import {WorkbasketDefinitionService} from './services/workbasket-definition/workbasket-definition.service';
import {ClassificationsService} from './services/classifications/classifications.service';
import {ClassificationCategoriesService} from './services/classification-categories-service/classification-categories.service';
import { AccessItemsManagementComponent } from 'app/administration/access-items-management/access-items-management.component';
const MODULES = [
CommonModule,
@ -55,7 +55,8 @@ const DECLARATIONS = [
ClassificationListComponent,
ImportExportComponent,
ClassificationTypesSelectorComponent,
ClassificationDetailsComponent
ClassificationDetailsComponent,
AccessItemsManagementComponent
];
@NgModule({

View File

@ -9,7 +9,7 @@
</ul>
<div id="classification" class="panel panel-default classification">
<div class="panel-heading">
<div class="pull-right">
<div class="pull-right btn-group">
<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>
</button>

View File

@ -1,11 +0,0 @@
.classification.panel{
border: none;
box-shadow: none;
margin-bottom: 0px;
&> .panel-body {
height: 85vh;
max-height: 85vh;
overflow-y: auto;
}
}

View File

@ -1,6 +1,6 @@
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
<div class="pull-right btn-group">
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary" data-toggle="tooltip"
title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>

View File

@ -26,7 +26,3 @@ td {
max-width: 150px;
border-bottom: none;
}
.has-warning.taskana-type-ahead {
border-bottom: 1px solid #f0ad4e;
}

View File

@ -35,19 +35,19 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
active: string;
badgeMessage = '';
accessIdField = this.customFieldService.getCustomField('Owner', 'workbaskets.access-items.accessId');
custom1Field = this.customFieldService.getCustomField('Custom 1', 'workbaskets.access-items.custom1');
custom2Field = this.customFieldService.getCustomField('Custom 2', 'workbaskets.access-items.custom2');
custom3Field = this.customFieldService.getCustomField('Custom 3', 'workbaskets.access-items.custom3');
custom4Field = this.customFieldService.getCustomField('Custom 4', 'workbaskets.access-items.custom4');
custom5Field = this.customFieldService.getCustomField('Custom 5', 'workbaskets.access-items.custom5');
custom6Field = this.customFieldService.getCustomField('Custom 6', 'workbaskets.access-items.custom6');
custom7Field = this.customFieldService.getCustomField('Custom 7', 'workbaskets.access-items.custom7');
custom8Field = this.customFieldService.getCustomField('Custom 8', 'workbaskets.access-items.custom8');
custom9Field = this.customFieldService.getCustomField('Custom 9', 'workbaskets.access-items.custom9');
custom10Field = this.customFieldService.getCustomField('Custom 10', 'workbaskets.access-items.custom10');
custom11Field = this.customFieldService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
custom12Field = this.customFieldService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
accessIdField = this.customFieldsService.getCustomField('Owner', 'workbaskets.access-items.accessId');
custom1Field = this.customFieldsService.getCustomField('Custom 1', 'workbaskets.access-items.custom1');
custom2Field = this.customFieldsService.getCustomField('Custom 2', 'workbaskets.access-items.custom2');
custom3Field = this.customFieldsService.getCustomField('Custom 3', 'workbaskets.access-items.custom3');
custom4Field = this.customFieldsService.getCustomField('Custom 4', 'workbaskets.access-items.custom4');
custom5Field = this.customFieldsService.getCustomField('Custom 5', 'workbaskets.access-items.custom5');
custom6Field = this.customFieldsService.getCustomField('Custom 6', 'workbaskets.access-items.custom6');
custom7Field = this.customFieldsService.getCustomField('Custom 7', 'workbaskets.access-items.custom7');
custom8Field = this.customFieldsService.getCustomField('Custom 8', 'workbaskets.access-items.custom8');
custom9Field = this.customFieldsService.getCustomField('Custom 9', 'workbaskets.access-items.custom9');
custom10Field = this.customFieldsService.getCustomField('Custom 10', 'workbaskets.access-items.custom10');
custom11Field = this.customFieldsService.getCustomField('Custom 11', 'workbaskets.access-items.custom11');
custom12Field = this.customFieldsService.getCustomField('Custom 12', 'workbaskets.access-items.custom12');
accessItemsResource: WorkbasketAccessItemsResource;
accessItemsClone: Array<WorkbasketAccessItems>;
@ -83,7 +83,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
private errorModalService: ErrorModalService,
private savingWorkbaskets: SavingWorkbasketService,
private requestInProgressService: RequestInProgressService,
private customFieldService: CustomFieldsService,
private customFieldsService: CustomFieldsService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService) {
}

View File

@ -1,6 +1,6 @@
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
<div class="pull-right btn-group">
<button type="button" (click)="onSave()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary" data-toggle="tooltip"
title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>

View File

@ -1,7 +1,7 @@
<taskana-spinner [isRunning]="requestInProgress" class="floating"></taskana-spinner>
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
<div class="pull-right btn-group">
<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>
</button>
@ -30,7 +30,7 @@
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key" [(ngModel)]="workbasket.key"
name="workbasket.key">
<taskana-field-error-display [displayError]="!isFieldValid('workbasket.key')" [validationTrigger]="this.toogleValidationMap.get('workbasket.key')"
errorMessage="* Key is required">
errorMessage="* Key is required" >
</taskana-field-error-display>
</div>
<div class="form-group required">
@ -41,11 +41,11 @@
errorMessage="* Name is required">
</taskana-field-error-display>
</div>
<div class="form-group required">
<label for="wb-owner" class="control-label">Owner</label>
<div class="input-group form-group required">
<label for="wb-owner" class="control-label ">Owner</label>
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner" [(ngModel)]="workbasket.owner"
placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"
[displayError]="!isFieldValid('workbasket.owner')"></taskana-type-ahead>
[displayError]="!isFieldValid('workbasket.owner')" width="100%"></taskana-type-ahead>
<ng-template #ownerInput>
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
name="workbasket.owner">

View File

@ -4,21 +4,18 @@
<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>
</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 class="pull-right margin-right">
<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" data-toggle="tooltip" title="Filter">
<div class="margin-right pull-right ">
<button class="btn btn-default collapsed" type="button" id="collapsedMenufilterWb" aria-expanded="false" (click)="toolbarState=!toolbarState"
data-toggle="tooltip" title="Filter">
<span class="glyphicon glyphicon-filter blue"></span>
</button>
<taskana-sort [sortingFields]="sortingFields" (performSorting)="sorting($event)" class="btn-group"></taskana-sort>
</div>
</div>
<div [@toggleDown]="toolbarState" class="row no-overflow">
<taskana-filter (performFilter)="filtering($event)"></taskana-filter>
</div>
</li>
</li>

View File

@ -1,3 +1,4 @@
.workbasket-list-full-height{
height: calc(100vh - 55px);
}

View File

@ -23,7 +23,9 @@ import { SelectedRouteService } from './services/selected-route/selected-route';
import { FormsValidatorService } from './shared/services/forms/forms-validator.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SharedModule } from './shared/shared.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AngularSvgIconModule } from 'angular-svg-icon';
export const configureTests = (configure: (testBed: TestBed) => void) => {
const testBed = getTestBed();
@ -36,7 +38,7 @@ export const configureTests = (configure: (testBed: TestBed) => void) => {
configure(testBed);
testBed.configureTestingModule({
imports: [BrowserAnimationsModule, SharedModule],
imports: [BrowserAnimationsModule, SharedModule, FormsModule, ReactiveFormsModule, HttpClientModule, AngularSvgIconModule],
providers: [{ provide: TaskanaEngineService, useClass: TaskanaEngineServiceMock },
{ provide: DomainService, useClass: DomainServiceMock }, CustomFieldsService, RemoveConfirmationService,
AlertService, ErrorModalService, RequestInProgressService, OrientationService, SelectedRouteService, FormsValidatorService]

View File

@ -1,5 +1,5 @@
<nav class="navbar navbar-fixed-top">
<div class="navbar no-border-radius navbar-inverse no-gutter col-xs-12">
<nav class="navbar main navbar-fixed-top">
<div class="navbar no-border-radius navbar-inverse no-gutter col-xs-12">
<div class="pull-left col-sm-3 col-md-4">
<button type="button" *ngIf="!showNavbar" class="btn btn-default navbar-toggle show pull-left" (click)="toogleNavBar();"
aria-expanded="true" aria-controls="navbar" data-toggle="tooltip" title="Menu">
@ -53,6 +53,10 @@
<span (click)="toogleNavBar()" class="col-xs-6" routerLink="administration/classifications" aria-controls="Classifications"
routerLinkActive="active">Classifications</span>
</div>
<div class="row submenu" [ngClass]="{'selected': selectedRoute.indexOf('access-items-management') !== -1}">
<span (click)="toogleNavBar()" class="col-xs-6" routerLink="administration/access-items-management" aria-controls="Access items"
routerLinkActive="active">Access items</span>
</div>
</div>
<div *ngIf="monitorAccess" class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('monitor') !== -1}">
<span (click)="toogleNavBar()" routerLink="{{monitorUrl}}" aria-controls="Monitor" routerLinkActive="active">Monitor</span>

View File

@ -1,17 +1,17 @@
$background-color: #224562;
$background-color-sidenav: #175263;
$selected-border-color: #22a39f;
$unselected-text: #9d9d9d;
@import './src/assets/_variables';
.navbar.main:before {
@include degraded-bar(right, 100%, 5px)
}
.navbar-inverse {
border:none;
background-color: $background-color;
box-shadow: 0px 1px 10px -1px $background-color;
background-color: $dark-green;
box-shadow: 0px 1px 5px -1px black;
}
.navbar-toggle{
margin: 5px 0px;
margin: 3px 0px;
font-size: 20px;
&.logout{
font-size: 20px;
@ -19,7 +19,7 @@ $unselected-text: #9d9d9d;
}
button.navbar-toggle:hover > span{
color:$selected-border-color;
color:$aquamarine;
}
ul.nav > p {
white-space: nowrap;
@ -35,15 +35,15 @@ ul.nav > p {
svg-icon.logo {
float: left;
width: 150px;
height: 55px;
padding: 6px 5px 5px 5px;
height: 50px;
padding: 5px;
}
h2.navbar-brand{
vertical-align: middle;
text-decoration: none;
color: white;
padding: 17px 0px 0px 0px;
padding: 15px 0px 0px 0px;
font-size: 20px;
}
@ -65,10 +65,10 @@ h2.navbar-brand{
cursor: pointer;
> button {
color: white;
background-color: $background-color;
background-color: $dark-green;
border: none;
font-size: 16px;
border-bottom: 1px solid grey;
border-bottom: 1px solid $dark-green;
margin-left:5px;
}
}
@ -79,11 +79,10 @@ h2.navbar-brand{
}
.nav-version {
color: $unselected-text;
margin: 5px;
color: $grey;
position: absolute;
bottom: 5px;
font-size: 8px;
font-size: 12px;
}
/*
@ -105,22 +104,22 @@ h2.navbar-brand{
.sidenav {
position:fixed;
z-index:999;
margin-top: -1px;
box-shadow: none;
height: 100%;
background-color: $background-color-sidenav;
box-shadow: 3px 0px 10px -1px $background-color;
background-color: $dark-green;
box-shadow: 3px 0px 10px -1px $dark-green;
}
.navbar {
height: 55px;
height: 50px;
margin-bottom: 0px;
}
.menu,.submenu > span {
margin-top: 15px;
font-size: 20px;
width: 100%;
font-family: inherit;
font-weight: 500;
line-height: 1.1;
@ -128,7 +127,7 @@ h2.navbar-brand{
.menu,.submenu > span {
padding-left: 12px;
color: $unselected-text;
color: $grey;
outline: none;
}
@ -136,8 +135,7 @@ h2.navbar-brand{
background-color: transparent;
&> span{
padding-left: 10px;
border-left: $selected-border-color 5px solid;
border-left: $pallete-green 5px solid;
color: white;
}
}
@ -147,7 +145,7 @@ h2.navbar-brand{
}
a {
color: $unselected-text;
color: $grey;
&:hover{
color:white;
}

View File

@ -9,7 +9,6 @@ import { WindowRefService } from 'app/services/window/window.service';
import { UserGuard } from 'app/guards/user-guard';
import { TaskanaEngineService } from '../../services/taskana-engine/taskana-engine.service';
import { expandRight } from 'app/shared/animations/expand.animation';
import { VersionModel } from 'app/models/version';
@Component({
selector: 'taskana-nav-bar',
templateUrl: './nav-bar.component.html',
@ -25,6 +24,7 @@ export class NavBarComponent implements OnInit, OnDestroy {
titleAdministration = 'Administration';
titleWorkbaskets = 'Workbaskets';
titleClassifications = 'Classifications';
titleAccessItems = 'Access items';
titleMonitor = 'Monitor';
titleWorkplace = 'Workplace';
showNavbar = false;
@ -101,6 +101,8 @@ export class NavBarComponent implements OnInit, OnDestroy {
this.title = this.titleMonitor;
} else if (value.indexOf('workplace') === 0) {
this.title = this.titleWorkplace;
} else if (value.indexOf('access-items') === 0) {
this.title = this.titleAccessItems;
}
}

View File

@ -1,3 +1,5 @@
@import './src/assets/_variables';
.big {
width: 64px;
height: 64px;
@ -20,9 +22,9 @@
position: relative;
& > .icon-wrap {
border-radius: 50%;
border: solid 3px #22a39f;
width: 74px;
height: 74px;
border: solid 2px #22a39f;
width: 72px;
height: 72px;
overflow: hidden;
background-color: #175263;
position: absolute;
@ -42,10 +44,10 @@
.icon:before { content: '';
position: absolute;
border-bottom: solid 3px #22a39f;
@include degraded-bar(right, 100%, 4px);
width: 100%;
height: 60px;
transform: translateY(-33%);
height: 2px;
transform: translateY(33px);
-webkit-box-shadow: 0px 3px 3px #416b6a;
-moz-box-shadow: 0px 3px 3px #416b6a;
box-shadow: 0px 3px 3px #416b6a;

View File

@ -0,0 +1,9 @@
import { Links } from './links';
import { AccessItemWorkbasket } from './access-item-workbasket';
export class AccessItemsWorkbasketResource {
constructor(
public _embedded: { 'accessItems': Array<AccessItemWorkbasket> } = { 'accessItems': [] },
public _links: Links = undefined
) { }
}

View File

@ -0,0 +1,27 @@
import { Links } from './links';
export class AccessItemWorkbasket {
constructor(
public accessItemId: string = '',
public workbasketKey: string = '',
public accessId: string = '',
public permRead: boolean = false,
public permOpen: boolean = false,
public permAppend: boolean = false,
public permTransfer: boolean = false,
public permDistribute: boolean = false,
public permCustom1: boolean = false,
public permCustom2: boolean = false,
public permCustom3: boolean = false,
public permCustom4: boolean = false,
public permCustom5: boolean = false,
public permCustom6: boolean = false,
public permCustom7: boolean = false,
public permCustom8: boolean = false,
public permCustom9: boolean = false,
public permCustom10: boolean = false,
public permCustom11: boolean = false,
public permCustom12: boolean = false,
public _links: Links = undefined
) { }
}

View File

@ -7,7 +7,7 @@ export class SelectedRouteService {
public selectedRouteTriggered = new Subject<string>();
private detailRoutes: Array<string> = ['workbaskets', 'classifications', 'monitor', 'workplace'];
private detailRoutes: Array<string> = ['workbaskets', 'classifications', 'monitor', 'workplace', 'access-items-management'];
constructor(private router: Router) { }

View File

@ -15,9 +15,9 @@
<h3 class="grey">Select a classification</h3>
<svg-icon class="img-responsive empty-icon" src="./assets/icons/classification-empty.svg"></svg-icon>
</div>
<div *ngIf="currentRoute === 'tasks'" class="center-block no-detail">
<h3 class="grey">Select a Task</h3>
<span class="glyphicon glyphicon-object-align-bottom"></span>
</div>
<div *ngIf="currentRoute === 'tasks'" class="center-block no-detail">
<h3 class="grey">Select a Task</h3>
<span class="glyphicon glyphicon-object-align-bottom"></span>
</div>
</div>
</div>

View File

@ -1,24 +1,47 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from 'environments/environment';
import { AccessIdDefinition } from 'app/models/access-id';
import { Observable, of } from 'rxjs';
import { AccessItemsWorkbasketResource } from 'app/models/access-item-workbasket-resource';
import { TaskanaQueryParameters } from 'app/shared/util/query-parameters';
import { SortingModel } from 'app/models/sorting';
@Injectable()
@Injectable({
providedIn: 'root'
})
export class AccessIdsService {
private url = environment.taskanaRestUrl + '/v1/access-ids';
private accessItemsRef: Observable<AccessItemsWorkbasketResource> = new Observable();
constructor(
private httpClient: HttpClient) { }
getAccessItemsInformation(token: string): Observable<Array<AccessIdDefinition>> {
getAccessItemsInformation(token: string, searchInGroups = false): Observable<Array<AccessIdDefinition>> {
if (!token || token.length < 3) {
return of([]);
}
return this.httpClient.get<Array<AccessIdDefinition>>(`${this.url}?searchFor=${token}`);
return this.httpClient.get<Array<AccessIdDefinition>>(`${this.url}?searchFor=${token}&searchInGroups=${searchInGroups}`);
};
getAccessItemsPermissions(
accessIds: Array<AccessIdDefinition>,
accessIdLike: string = undefined,
workbasketKeyLike: string = undefined,
sortModel: SortingModel = new SortingModel('workbasket-key'),
forceRequest: boolean = false): Observable<AccessItemsWorkbasketResource> {
if (this.accessItemsRef && !forceRequest) {
return this.accessItemsRef;
}
return this.accessItemsRef = this.httpClient.get<AccessItemsWorkbasketResource>(encodeURI(
`${environment.taskanaRestUrl}/v1/workbasket-access/${TaskanaQueryParameters.getQueryParameters(sortModel.sortBy,
sortModel.sortDirection,
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
accessIds.map((values: AccessIdDefinition) => {
return values.accessId
}).join('|'),
accessIdLike, workbasketKeyLike)}`))
}
}

View File

@ -1,29 +1,28 @@
<div class="dropdown clearfix btn-group">
<button [disabled]="!enabled" class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="glyphicon {{sort.sortDirection === 'asc'? 'glyphicon-sort-by-attributes-alt' : 'glyphicon-sort-by-attributes' }} blue"
data-toggle= "tooltip" title="{{sort.sortDirection === 'asc'? 'A-Z' : 'Z-A' }}"></span>
</button>
<div class="dropdown-menu dropdown-menu-right sortby-dropdown popup" aria-labelledby="sortingDropdown">
<div>
<div class="col-xs-6">
<h5>Sort By</h5>
</div>
<button id="sort-by-direction-asc" type="button" (click)="changeOrder('asc')" data-toggle="tooltip" title="A-Z" class="btn btn-default {{sort.sortDirection === 'asc'? 'selected' : '' }}">
<div class="dropdown">
<button [disabled]="!enabled" class="btn btn-default" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="glyphicon {{sort.sortDirection === 'asc'? 'glyphicon-sort-by-attributes-alt' : 'glyphicon-sort-by-attributes' }} blue"
data-toggle="tooltip" title="{{sort.sortDirection === 'asc'? 'A-Z' : 'Z-A' }}"></span>
</button>
<div class="dropdown-menu dropdown-menu-{{menuPosition}} sortby-dropdown popup" aria-labelledby="sortingDropdown">
<div>
<div class="col-xs-6">
<h5>Sort By</h5>
</div>
<button id="sort-by-direction-asc" type="button" (click)="changeOrder('asc')" data-toggle="tooltip" title="A-Z" class="btn btn-default {{sort.sortDirection === 'asc'? 'selected' : '' }}">
<span class="glyphicon glyphicon-sort-by-attributes-alt blue" aria-hidden="true"></span>
</button>
<button id= "sort-by-direction-desc" type="button" (click)="changeOrder('desc')" data-toggle="tooltip" title="Z-A" class="btn btn-default {{sort.sortDirection === 'desc'? 'selected' : '' }}" >
<span class="glyphicon glyphicon-sort-by-attributes blue" aria-hidden="true"></span>
</button>
</button>
<button id="sort-by-direction-desc" type="button" (click)="changeOrder('desc')" data-toggle="tooltip" title="Z-A" class="btn btn-default {{sort.sortDirection === 'desc'? 'selected' : '' }}">
<span class="glyphicon glyphicon-sort-by-attributes blue" aria-hidden="true"></span>
</button>
</div>
<div role="separator" class="divider"></div>
<li id="sort-by-{{sortingField.key}}" (click)="changeSortBy(sortingField.key)" *ngFor="let sortingField of sortingFields | mapValues">
<a>
<label>
<span class="glyphicon {{sort.sortBy === sortingField.key? 'glyphicon-check': 'glyphicon-unchecked'}} blue" aria-hidden="true"></span>
{{sortingField.value}}
</label>
</a>
</li>
</div>
<div role="separator" class="divider"></div>
<li id="sort-by-{{sortingField.key}}" (click)="changeSortBy(sortingField.key)" *ngFor="let sortingField of sortingFields | mapValues">
<a>
<label>
<span class="glyphicon {{sort.sortBy === sortingField.key? 'glyphicon-check': 'glyphicon-unchecked'}} blue" aria-hidden="true"></span>
{{sortingField.value}}
</label>
</a>
</li>
</div>
</div>
</div>

View File

@ -9,6 +9,7 @@ import {Direction, SortingModel} from 'app/models/sorting';
export class SortComponent implements OnInit {
@Input() sortingFields: Map<string, string>;
@Input() enabled = true;
@Input() menuPosition = 'right';
@Output() performSorting = new EventEmitter<SortingModel>();

View File

@ -1,4 +1,4 @@
<div *ngIf="dataSource" class="custom-form-control">
<div *ngIf="dataSource" class="custom-form-control" [ngStyle]="{'width': width ? width : auto }">
<ng-template class="wrapper-text" #customItemTemplate let-model="item" let-index="indexTemplate" let-query="query">
<div (mousedown)="typeaheadOnSelect({'item':model})">
<div>
@ -11,13 +11,19 @@
</div>
</div>
</ng-template>
<div [ngClass]="{'hidden': !dataSource.selected || typing}" class="wrapper-text" (click)="setTyping(true)">
<div [ngClass]="{'hidden': !dataSource.selected || typing,
'disable': disable}" class="wrapper-text" (click)="setTyping(true)">
<span>
<label>
{{dataSource.selected?.accessId}}
</label>
</span>
<div>{{dataSource.selected?.name}}</div>
<div class="input-group">
<div>{{dataSource.selected?.name}}</div>
<button *ngIf="!disable" type="button" (click)="clear()" title="clear search" class="btn rounded remove">
<span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
</button>
</div>
</div>
<div [ngClass]="{'hidden': dataSource.selected && !typing}">
<span class="field-label-wrapper">
@ -25,13 +31,19 @@
{{dataSource.selected?.name}}
</label>
</span>
<div *ngIf="typeaheadLoading" class="loading">
<taskana-spinner [isRunning]="typeaheadLoading" positionClass="type-ahead-spinner"></taskana-spinner>
<div class="input-group">
<input #inputTypeAhead class=" form-control input-text" (blur)="typeaheadOnSelect({'item':dataSource.selected})" name="accessItem-{{index}}"
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [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">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
<div *ngIf="typeaheadLoading" class="loading">
<taskana-spinner [isRunning]="typeaheadLoading" positionClass="type-ahead-spinner"></taskana-spinner>
</div>
</div>
<input #inputTypeAhead class=" form-control input-text" (blur)="typeaheadOnSelect({'item':dataSource.selected})" name="accessItem-{{index}}"
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView"
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
placeholder="{{displayError? placeHolderMessage: ''}}" [@validation]="validationValue">
</div>
</div>
</div>

View File

@ -1,25 +1,34 @@
$blue: #2e9eca;
$grey: #ddd;
$invalid: #a94442;
@import './src/assets/_colors';
.wrapper-text {
min-width: 150px;
height: 47px;
& label {
width: 100%;
margin-bottom: 0px;
padding-left: 12px;
font-style: italic;
overflow: hidden;
}
& div {
width: 100%;
border-bottom: 1px solid $grey;
margin-top:6px;
padding-left: 12px;
&> div{
&> div {
border-bottom: 1px solid $light-grey;
margin-top:6px;
padding-left: 12px;
min-width: 175px;
}
}
> div{
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
padding-left: 12px;
padding-right: 35px;
}
}
.custom-form-control {
height: 50px;
& .input-group{
width: 100%;
}
}
@ -29,34 +38,44 @@ $invalid: #a94442;
border: none;
padding: 0px;
border-radius: 0px;
//margin-top: 18px;
height: 22px;
border-bottom: 1px solid $grey;
min-width: 150px;
height: 28px;
border-bottom: 1px solid $light-grey;
&:focus{
border-bottom: 1px solid $blue;
border-bottom: 1px solid $aquamarine;
}
padding-left: 12px;
padding-right: 35px;
}
.field-label-wrapper{
position: relative;
//left: 8px;
height: 28px;
padding-left: 12px;
box-sizing: content-box;
overflow: hidden;
pointer-events: none;
}
.form-control:focus {
border-color: none;
box-shadow: none;
}
.loading {
position: absolute;
top: 0px;
right: 0;
}
.btn.rounded {
position: absolute;
top: 0px;
right: 0px;
}
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: $invalid;
opacity: 1; /* Firefox */
@ -67,4 +86,8 @@ $invalid: #a94442;
::-ms-input-placeholder { /* Microsoft Edge */
color: $invalid;
}
.disable {
cursor: not-allowed;
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit, Input, ViewChild, forwardRef } from '@angular/core';
import { Component, OnInit, Input, ViewChild, forwardRef, Output, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs';
import { TypeaheadMatch } from 'ngx-bootstrap/typeahead';
@ -6,7 +6,7 @@ import { AccessIdsService } from 'app/shared/services/access-ids/access-ids.serv
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { highlight } from 'app/shared/animations/validation.animation';
import { mergeMap } from 'rxjs/operators';
import { AccessIdDefinition } from 'app/models/access-id';
@Component({
selector: 'taskana-type-ahead',
@ -35,6 +35,15 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
@Input()
displayError;
@Input()
width;
@Input()
disable;
@Output()
onSelect = new EventEmitter<AccessIdDefinition>();
@ViewChild('inputTypeAhead')
private inputTypeAhead;
@ -107,11 +116,13 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
if (event && event.item) {
this.value = event.item.accessId;
this.dataSource.selected = event.item;
this.onSelect.emit(this.dataSource.selected)
}
this.setTyping(false);
}
setTyping(value) {
if (this.disable) { return true; }
if (value) {
setTimeout(() => {
this.inputTypeAhead.nativeElement.focus();
@ -129,4 +140,11 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
return text.toLocaleLowerCase().split(str).join(`<strong>${str}</strong>`);
}
clear() {
this.value = null;
this.innerValue = null;
this.dataSource.selected = null
this.onSelect.emit(this.dataSource.selected)
}
}

View File

@ -12,10 +12,14 @@ export class TaskanaQueryParameters {
static OWNERLIKE = 'owner-like';
static TYPE = 'type';
static KEY = 'key';
static WORKBASKET_KEY = 'workbasket-key';
static KEYLIKE = 'key-like';
// Access
static REQUIREDPERMISSION = 'required-permission';
static ACCESSIDS = 'access-ids';
static ACCESSIDLIKE = 'access-id-like';
static WORKBASKETKEYLIKE = 'workbasket-key-like';
// Pagination
static PAGE = 'page';
@ -26,7 +30,6 @@ export class TaskanaQueryParameters {
// Domain
static DOMAIN = 'domain';
public static getQueryParameters(sortBy: string = undefined,
order: string = undefined,
name: string = undefined,
@ -40,7 +43,10 @@ export class TaskanaQueryParameters {
requiredPermission: string = undefined,
page: number = undefined,
pageSize: number = undefined,
domain: string = undefined): string {
domain: string = undefined,
accessIds: string = undefined,
accessIdLike: string = undefined,
workbasketKeyLike: string = undefined): string {
let query = '?';
query += sortBy ? `${this.SORTBY}=${sortBy}&` : '';
query += order ? `${this.ORDER}=${order}&` : '';
@ -55,7 +61,10 @@ export class TaskanaQueryParameters {
query += requiredPermission ? `${this.REQUIREDPERMISSION}=${requiredPermission}&` : '';
query += page ? `${this.PAGE}=${page}&` : '';
query += pageSize ? `${this.PAGESIZE}=${pageSize}&` : '';
query += domain !== undefined ? `${this.DOMAIN}=${domain}&` : '';
query += domain ? `${this.DOMAIN}=${domain}&` : '';
query += accessIds ? `${this.ACCESSIDS}=${accessIds}&` : '';
query += accessIdLike ? `${this.ACCESSIDLIKE}=${accessIdLike}&` : '';
query += workbasketKeyLike ? `${this.WORKBASKETKEYLIKE}=${workbasketKeyLike}&` : '';
if (query.lastIndexOf('&') === query.length - 1) {
query = query.slice(0, query.lastIndexOf('&'))

View File

@ -1,8 +1,11 @@
$blue-green: #11c584;
$blue: #2e9eca;
$green: #246972;
$dark-green: #175263;
$grey: grey;
$light-grey: #ddd;
$brown: #f0ad4e;
$invalid: #a94442;
$aquamarine: #22a39f;
$pallete-blue: #36bcee;
$pallete-green: #5fbca1;

View File

@ -1,6 +1,4 @@
.placeholder {
margin-bottom: 20px;
}
.placeholder img {
display: inline-block;
@ -201,6 +199,10 @@ svg-icon.fa-fw > svg {
vertical-align: middle;
}
body{
overflow-y: hidden;
}
.table-center > tbody > tr > td {
text-align: center;
vertical-align: middle;
@ -231,7 +233,7 @@ svg-icon.fa-fw > svg {
opacity: 1;
visibility: visible;
}
.dropdown-menu {
display: block;
opacity: 0;
@ -271,22 +273,28 @@ svg-icon.fa-fw > svg {
margin-top: 4px;
}
.container {
@media (min-width: 1200px){
width: 100%;
}
}
taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks {
&> .panel{
taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbaskets-distribution-targets, taskana-monitor-tasks,
taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management, taskana-classification-details,taskana-workbasket-details {
& .panel{
border: none;
box-shadow: none;
margin-bottom: 0px;
&> .panel-body {
height: 80vh;
max-height: 80vh;
height: calc(100vh - 108px);
max-height: calc(100vh - 108px);
overflow-y: auto;
}
}
}
taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks {
&> .panel {
taskana-monitor-tasks, taskana-monitor-workbaskets, taskana-monitor-classification-tasks, taskana-access-items-management {
& .panel {
&> .panel-heading {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
@ -336,3 +344,11 @@ li.list-group-item:hover, {
.align-center {
text-align: center;
}
.btn.rounded {
border-radius: 50%;
background-color: transparent;
&:focus, &:active:focus {
outline: none;
}
}

View File

@ -1,12 +1,13 @@
typeahead-container >ul.dropdown-menu{
width: 215px;
max-width: 600px;
& >li.active {
&>a {
background-color: $green;
background-color: $blue;
}
&>a:hover {
background-color: $green;
background-color: $blue;
}
}
}

View File

@ -1,2 +1,10 @@
@import '_colors';
$icon-font-path: '../../node_modules/bootstrap-sass/assets/fonts/bootstrap/';
@mixin degraded-bar ($direction, $width, $height) {
display: block;
width: $width;
height: $height;
background-image: linear-gradient(to $direction, $pallete-blue 30%, $pallete-green 50%);
content: ' ';
}