added import/export functionality
This commit is contained in:
Lars Leo Grätz 2018-03-27 12:15:54 +02:00 committed by Martin Rojas Miguel Angel
parent 95d614c2d7
commit ead7b9a3a0
26 changed files with 487 additions and 37 deletions

View File

@ -1,3 +1,4 @@
taskana.roles.user = group1 | group2|teamlead_1 |teamlead_2 |user_1_1| user_1_1| user_1_2| user_2_1| user_2_2| max|elena|simone
taskana.roles.Admin=name=konrad,Organisation=novatec|admin
taskana.roles.businessadmin=max|Moritz|businessadmin
taskana.domains=DOMAIN_A,DOMAIN_B,DOMAIN_C

View File

@ -10,6 +10,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -62,22 +63,33 @@ public class ClassificationDefinitionController {
@PostMapping(path = "/import")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<String> importClassifications(
@RequestBody List<ClassificationResource> classificationResources) throws NotAuthorizedException,
ClassificationNotFoundException, ConcurrencyException, ClassificationAlreadyExistException,
DomainNotFoundException {
@RequestBody List<ClassificationResource> classificationResources) {
Map<String, String> systemIds = classificationService.createClassificationQuery()
.list()
.stream()
.collect(Collectors.toMap(i -> i.getKey() + "|||" + i.getDomain(), ClassificationSummary::getId));
for (ClassificationResource classificationResource : classificationResources) {
Classification classification = classificationMapper.toModel(classificationResource);
if (systemIds.containsKey(classificationResource.key + "|||" + classificationResource.domain)) {
classificationService.updateClassification(classification);
try {
for (ClassificationResource classificationResource : classificationResources) {
if (systemIds.containsKey(classificationResource.key + "|||" + classificationResource.domain)) {
classificationService.updateClassification(classificationMapper.toModel(classificationResource));
} else {
classificationService.createClassification(classification);
} else {
classificationResource.classificationId = null;
classificationService.createClassification(classificationMapper.toModel(classificationResource));
}
}
} catch (NotAuthorizedException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
} catch (ClassificationNotFoundException | DomainNotFoundException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
} catch (ClassificationAlreadyExistException e) {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
return new ResponseEntity<>(HttpStatus.CONFLICT);
//TODO why is this occuring???
} catch (ConcurrencyException e) {
}
return new ResponseEntity<>(HttpStatus.OK);

View File

@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pro.taskana.Workbasket;
import pro.taskana.WorkbasketAccessItem;
import pro.taskana.WorkbasketQuery;
import pro.taskana.WorkbasketService;
import pro.taskana.WorkbasketSummary;
@ -83,10 +84,9 @@ public class WorkbasketDefinitionController {
* we want to have an option to import all settings at once. When a logical equal (key and domain are equal)
* workbasket already exists an update will be executed. Otherwise a new workbasket will be created.
*
* @param definitions
* the list of workbasket definitions which will be imported to the current system.
* @param definitions the list of workbasket definitions which will be imported to the current system.
* @return Return answer is determined by the status code: 200 - all good 400 - list state error (referring to non
* existing id's) 401 - not authorized
* existing id's) 401 - not authorized
*/
@PostMapping(path = "/import")
@Transactional(rollbackFor = Exception.class)
@ -107,16 +107,23 @@ public class WorkbasketDefinitionController {
for (WorkbasketDefinition definition : definitions) {
WorkbasketResource res = definition.workbasketResource;
Workbasket workbasket;
String oldId = res.workbasketId;
if (systemIds.containsKey(logicalId(res))) {
String oldId = res.workbasketId;
res.workbasketId = systemIds.get(logicalId(res));
workbasket = workbasketService.updateWorkbasket(
workbasketMapper.toModel(res));
res.workbasketId = oldId;
} else {
res.workbasketId = null;
workbasket = workbasketService.createWorkbasket(
workbasketMapper.toModel(res));
}
res.workbasketId = oldId;
// Since we would have a n² runtime when doing a lookup and updating the access items we decided to
// simply delete all existing accessItems and create new ones.
for (WorkbasketAccessItem accessItem : workbasketService.getWorkbasketAccessItems(workbasket.getId())) {
workbasketService.deleteWorkbasketAccessItem(accessItem.getId());
}
for (WorkbasketAccessItemResource authorization : definition.authorizations) {
workbasketService.createWorkbasketAccessItem(
workbasketAccessItemMapper.toModel(authorization));
@ -132,8 +139,7 @@ public class WorkbasketDefinitionController {
if (idConversion.containsKey(oldId)) {
distributionTargets.add(idConversion.get(oldId));
} else {
throw new WorkbasketNotFoundException(
oldId,
throw new InvalidWorkbasketException(
String.format(
"invalid import state: Workbasket '%s' does not exist in the given import list",
oldId));

8
web/package-lock.json generated
View File

@ -3557,6 +3557,11 @@
"schema-utils": "0.4.5"
}
},
"file-saver": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz",
"integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@ -4192,7 +4197,8 @@
"jsbn": {
"version": "0.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"json-schema": {
"version": "0.2.3",

View File

@ -23,6 +23,7 @@
"@angular/platform-browser": "5.2.1",
"@angular/platform-browser-dynamic": "5.2.1",
"@angular/router": "5.2.1",
"file-saver": "1.3.3",
"angular-svg-icon": "5.0.0",
"angular-tree-component": "7.0.1",
"bootstrap": "3.3.7",

View File

@ -0,0 +1,40 @@
<div class="classification-list-full-height">
<ul id="cl-list-container" class="list-group footer-space">
<li id="cl-action-toolbar" class="list-group-item tab-align">
<div class="row">
<div class="col-xs-9">
<taskana-import-export-component [currentSelection]="'classifications'"></taskana-import-export-component>
</div>
</div>
</li>
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
</ul>
<ul id="wb-pagination" class="pagination vertical-center">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li>
<a href="">1</a>
</li>
<li>
<a href="">2</a>
</li>
<li>
<a href="">3</a>
</li>
<li>
<a href="">4</a>
</li>
<li>
<a href="">5</a>
</li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</div>

View File

@ -0,0 +1,22 @@
.classification-list-full-height {
height: calc(100vh - 55px);
}
.row.list-group {
margin-left: 2px;
}
.list-group > li {
border-left: none;
border-right: none;
}
a > label {
height: 2em;
width: 100%;
}
.tab-align {
border-bottom: 1px solid #ddd;
padding-bottom: 12px;
}

View File

@ -0,0 +1,34 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClassificationListComponent } from './classification-list.component';
import {ImportExportComponent} from '../../../import-export/import-export.component';
import {SpinnerComponent} from '../../../../shared/spinner/spinner.component';
import {WorkbasketService} from '../../../../services/workbasket/workbasket.service';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {WorkbasketDefinitionService} from '../../../../services/workbasket/workbasketDefinition.service';
import {AlertService} from '../../../../services/alert/alert.service';
import {ClassificationService} from '../../../../services/classification/classification.service';
describe('ClassificationListComponent', () => {
let component: ClassificationListComponent;
let fixture: ComponentFixture<ClassificationListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ClassificationListComponent, ImportExportComponent, SpinnerComponent],
imports: [HttpClientModule],
providers: [WorkbasketService, HttpClient, WorkbasketDefinitionService, AlertService, ClassificationService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ClassificationListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'taskana-classification-list',
templateUrl: './classification-list.component.html',
styleUrls: ['./classification-list.component.scss']
})
export class ClassificationListComponent implements OnInit {
requestInProgress = false;
constructor() {
}
ngOnInit() {
}
}

View File

@ -0,0 +1,23 @@
<input #selectedFile type="file" (change)="onSelectFile($event)"
style="position:absolute;display:none;"/>
<button class="btn btn-default glyphicon glyphicon-upload" type="button" title="Import" style="top: -0.5px;"
(click)="selectedFile.click()"></button>
<div class="dropdown" style="display: inline">
<button type="button" title="Export" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"
(click)="updateDomains()">
<span class="glyphicon glyphicon-download"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" (click)="exportAll()"><label>All Domains</label></a>
</li>
<div role="separator" class="divider"></div>
<li *ngFor="let domain of (this.currentSelection === 'workbaskets' ? workbasketDomains : classificationDomains)">
<a class="dropdown-item"
(click)="exportByDomain(domain)"><label>{{domain === '' ? 'Master' : domain}}</label></a>
</li>
</ul>
</div>

View File

@ -0,0 +1,32 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ImportExportComponent } from './import-export.component';
import {WorkbasketService} from '../../services/workbasket/workbasket.service';
import {ClassificationService} from '../../services/classification/classification.service';
import {WorkbasketDefinitionService} from '../../services/workbasket/workbasketDefinition.service';
import {AlertService} from '../../services/alert/alert.service';
import {HttpClient, HttpClientModule} from '@angular/common/http';
describe('ImportExportComponent', () => {
let component: ImportExportComponent;
let fixture: ComponentFixture<ImportExportComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ImportExportComponent],
imports: [HttpClientModule],
providers: [WorkbasketService, ClassificationService, WorkbasketDefinitionService, AlertService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ImportExportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,61 @@
import {Component, Input, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {ActivatedRoute, Router} from '@angular/router';
import {WorkbasketService} from '../../services/workbasket/workbasket.service';
import {ClassificationService} from '../../services/classification/classification.service';
import {WorkbasketDefinitionService} from '../../services/workbasket/workbasketDefinition.service';
@Component({
selector: 'taskana-import-export-component',
templateUrl: './import-export.component.html',
styleUrls: ['./import-export.component.scss']
})
export class ImportExportComponent implements OnInit {
@Input() currentSelection: string;
workbasketDomains: string[];
classificationDomains: string[];
constructor(private workbasketService: WorkbasketService, private workbasketDefinitionService: WorkbasketDefinitionService,
private classificationService: ClassificationService) {
}
ngOnInit() {
}
updateDomains() {
this.workbasketService.getWorkbasketDomains().subscribe(
data => this.workbasketDomains = data
);
this.classificationService.getClassificationDomains().subscribe(
data => this.classificationDomains = data
);
}
onSelectFile(event) {
const file = event.srcElement.files[0];
const reader = new FileReader();
if (this.currentSelection === 'workbaskets') {
reader.onload = <Event>(e) => this.workbasketDefinitionService.importWorkbasketDefinitions(e.target.result);
} else {
reader.onload = <Event>(e) => this.classificationService.importClassifications(e.target.result);
}
reader.readAsText(file);
}
exportAll() {
if (this.currentSelection === 'workbaskets') {
this.workbasketDefinitionService.exportAllWorkbaskets();
} else {
this.classificationService.exportAllClassifications();
}
}
exportByDomain(domain: string) {
if (this.currentSelection === 'workbaskets') {
this.workbasketDefinitionService.exportWorkbasketsByDomain(domain);
} else {
this.classificationService.exportClassificationsByDomain(domain);
}
}
}

View File

@ -22,6 +22,20 @@ import { RemoveNoneTypePipe } from 'app/pipes/removeNoneType/remove-none-type.pi
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { SavingWorkbasketService, SavingInformation } from 'app/services/saving-workbaskets/saving-workbaskets.service';
import { AlertService } from 'app/services/alert/alert.service';
import {Component} from '@angular/core';
import {Routes} from '@angular/router';
@Component({
selector: 'taskana-dummy-detail',
template: 'dummydetail'
})
export class DummyDetailComponent {
}
const routes: Routes = [
{ path: ':id', component: DummyDetailComponent, outlet: 'detail' },
{ path: 'someNewId', component: DummyDetailComponent }
];
describe('InformationComponent', () => {
let component: WorkbasketInformationComponent;
@ -31,8 +45,8 @@ describe('InformationComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [WorkbasketInformationComponent, IconTypeComponent, MapValuesPipe,
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule],
RemoveNoneTypePipe, SpinnerComponent, GeneralMessageModalComponent, DummyDetailComponent],
imports: [FormsModule, AngularSvgIconModule, HttpClientModule, HttpModule, RouterTestingModule.withRoutes(routes)],
providers: [WorkbasketService, AlertService, SavingWorkbasketService, ErrorModalService]
})

View File

@ -1,6 +1,7 @@
<li id="wb-action-toolbar" class="list-group-item tab-align">
<div class="row">
<div class="col-xs-9">
<taskana-import-export-component [currentSelection]="'workbaskets'"></taskana-import-export-component>
<button type="button" (click)="addWorkbasket()" data-toggle="tooltip" title="Add" class="btn btn-default">
<span class="glyphicon glyphicon-plus green" aria-hidden="true"></span>
</button>
@ -30,4 +31,4 @@
<div class="row">
<taskana-filter target="wb-filter-bar" (performFilter)="filtering($event)"></taskana-filter>
</div>
</li>
</li>

View File

@ -25,6 +25,9 @@ import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
import { AlertService } from 'app/services/alert/alert.service';
import {ImportExportComponent} from '../../../../import-export/import-export.component';
import {ClassificationService} from '../../../../../services/classification/classification.service';
import {WorkbasketDefinitionService} from '../../../../../services/workbasket/workbasketDefinition.service';
@Component({
selector: 'taskana-dummy-detail',
@ -48,8 +51,9 @@ describe('WorkbasketListToolbarComponent', () => {
imports: [FormsModule, ReactiveFormsModule, AngularSvgIconModule, HttpModule,
HttpClientModule, RouterTestingModule.withRoutes(routes)],
declarations: [WorkbasketListToolbarComponent, SortComponent,
FilterComponent, IconTypeComponent, DummyDetailComponent, MapValuesPipe],
providers: [ErrorModalService, WorkbasketService, RequestInProgressService, AlertService]
FilterComponent, IconTypeComponent, DummyDetailComponent, MapValuesPipe, ImportExportComponent],
providers: [ErrorModalService, WorkbasketService, RequestInProgressService, AlertService,
ClassificationService, WorkbasketDefinitionService]
})
.compileComponents();
}));

View File

@ -27,6 +27,9 @@ import { SortComponent } from 'app/shared/sort/sort.component';
import { RemoveNoneTypePipe } from 'app/pipes/removeNoneType/remove-none-type.pipe';
import { MapValuesPipe } from 'app/pipes/mapValues/map-values.pipe';
import {ClassificationService} from '../../../../services/classification/classification.service';
import {WorkbasketDefinitionService} from '../../../../services/workbasket/workbasketDefinition.service';
import {ImportExportComponent} from '../../../import-export/import-export.component';
@Component({
@ -66,14 +69,15 @@ describe('WorkbasketListComponent', () => {
TestBed.configureTestingModule({
declarations: [WorkbasketListComponent, DummyDetailComponent, SpinnerComponent, FilterComponent, WorkbasketListToolbarComponent,
RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe],
RemoveNoneTypePipe, IconTypeComponent, SortComponent, MapValuesPipe, ImportExportComponent],
imports: [
AngularSvgIconModule,
HttpModule,
HttpClientModule,
RouterTestingModule.withRoutes(routes)
],
providers: [WorkbasketService, ErrorModalService, RequestInProgressService, AlertService]
providers: [WorkbasketService, ErrorModalService, RequestInProgressService, AlertService,
ClassificationService, WorkbasketDefinitionService]
})
.compileComponents();

View File

@ -5,6 +5,7 @@ import { WorkbasketListComponent } from './administration/workbasket/master/list
import { WorkbasketDetailsComponent } from './administration/workbasket/details/workbasket-details.component';
import { MasterAndDetailComponent } from './shared/masterAndDetail/master-and-detail.component';
import { NoAccessComponent } from './administration/workbasket/details/noAccess/no-access.component';
import {ClassificationListComponent} from './administration/classification/master/list/classification-list.component';
const appRoutes: Routes = [
{
@ -29,15 +30,15 @@ const appRoutes: Routes = [
]
},
{
path: 'clasifications',
component: MasterAndDetailComponent,
children: [
{
path: '',
component: WorkbasketListComponent,
outlet: 'detail'
}
]
path: 'classifications',
component: MasterAndDetailComponent,
children: [
{
path: '',
component: ClassificationListComponent,
outlet: 'master'
}
]
},
{
path: '',

View File

@ -15,7 +15,7 @@
<a routerLink="/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a>
</li>
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab">
<a routerLink="/clasifications" aria-controls="Clasifications" routerLinkActive="active">Clasifications</a>
<a routerLink="/classifications" aria-controls="Classifications" routerLinkActive="active">Classifications</a>
</li>
</ul>
</div>
@ -48,4 +48,4 @@
<taskana-spinner [isRunning]="requestInProgress" isModal="true"></taskana-spinner>
<taskana-alert></taskana-alert>
</div>
</div>
</div>

View File

@ -56,6 +56,10 @@ import { SavingWorkbasketService } from './services/saving-workbaskets/saving-wo
import { MapValuesPipe } from './pipes/mapValues/map-values.pipe';
import { RemoveNoneTypePipe } from './pipes/removeNoneType/remove-none-type.pipe';
import { SelectWorkBasketPipe } from './pipes/selectedWorkbasket/seleted-workbasket.pipe';
import {ClassificationListComponent} from './administration/classification/master/list/classification-list.component';
import {ClassificationService} from './services/classification/classification.service';
import {WorkbasketDefinitionService} from './services/workbasket/workbasketDefinition.service';
import {ImportExportComponent} from './administration/import-export/import-export.component';
const MODULES = [
BrowserModule,
@ -89,7 +93,9 @@ const DECLARATIONS = [
DualListComponent,
MapValuesPipe,
RemoveNoneTypePipe,
SelectWorkBasketPipe
SelectWorkBasketPipe,
ClassificationListComponent,
ImportExportComponent
];
@NgModule({
@ -99,6 +105,8 @@ const DECLARATIONS = [
WorkbasketService,
MasterAndDetailService,
PermissionService,
ClassificationService,
WorkbasketDefinitionService,
{
provide: HTTP_INTERCEPTORS,
useClass: HttpClientInterceptor,

View File

@ -0,0 +1,24 @@
export class Classification {
constructor(public classificationId: string,
public key: string,
public parentId: string,
public category: string,
public domain: string,
public isValidInDomain: boolean,
public created: string,
public modifies: string,
public name: string,
public description: string,
public priority: number,
public serviceLevel: string,
public applicationEntryPoint: string,
public custom1: string,
public custom2: string,
public custom3: string,
public custom4: string,
public custom5: string,
public custom6: string,
public custom7: string,
public custom8: string) {
}
}

View File

@ -0,0 +1,9 @@
import {WorkbasketAccessItems} from './workbasket-access-items';
import {Workbasket} from './workbasket';
export class WorkbasketDefinition {
constructor(distributionTargets: string[],
workbasketAccessItems: WorkbasketAccessItems[],
workbasket: Workbasket) {
}
}

View File

@ -0,0 +1,63 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {environment} from '../../../environments/environment';
import {DatePipe} from '@angular/common';
import {AlertService} from '../alert/alert.service';
import {Classification} from '../../models/classification';
import {AlertModel, AlertType} from '../../models/alert';
import {saveAs} from 'file-saver/FileSaver';
@Injectable()
export class ClassificationService {
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
})
};
constructor(private httpClient: HttpClient, private alertService: AlertService) {
}
// GET
getClassificationDomains(): Observable<string[]> {
return this.httpClient.get<string[]>(environment.taskanaRestUrl + '/v1/classifications/domains', this.httpOptions);
}
// GET
exportAllClassifications() {
this.httpClient.get<Classification[]>(environment.taskanaRestUrl + '/v1/classificationdefinitions', this.httpOptions)
.subscribe(
response => saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}), this.generateName())
);
}
// GET
exportClassificationsByDomain(domain: string) {
this.httpClient.get<Classification[]>(environment.taskanaRestUrl + '/v1/classificationdefinitions?domain=' + domain, this.httpOptions)
.subscribe(
response => saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}), this.generateName(domain))
);
}
// POST
// TODO handle error
importClassifications(classifications: any) {
console.log('importing classifications');
this.httpClient.post(environment.taskanaRestUrl + '/v1/classificationdefinitions/import',
JSON.parse(classifications), this.httpOptions).subscribe(
classificationsUpdated => this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful')),
error => this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Import was not successful'))
);
}
private generateName(domain = ''): string {
const dateFormat = 'yyyy-MM-ddTHH:mm:ss';
const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale);
const date = datePipe.transform(Date.now(), dateFormat) + 'Z';
return 'Classifications_' + date + '.json';
}
}

View File

@ -113,6 +113,11 @@ export class WorkbasketService {
return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds, this.httpOptions);
}
// GET
getWorkbasketDomains() {
return this.httpClient.get<string[]>(environment.taskanaRestUrl + '/v1/workbaskets/domains', this.httpOptions);
}
// #endregion
// #region "Service extras"
selectWorkBasket(id: string) {

View File

@ -0,0 +1,62 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {saveAs} from 'file-saver/FileSaver';
import {DatePipe} from '@angular/common';
import {AlertService} from '../alert/alert.service';
import {WorkbasketDefinition} from '../../models/workbasket-definition';
import {AlertModel, AlertType} from '../../models/alert';
@Injectable()
export class WorkbasketDefinitionService {
url: string = environment.taskanaRestUrl + '/v1/workbasketdefinitions';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
})
};
constructor(private httpClient: HttpClient, private alertService: AlertService) {
}
// GET
exportAllWorkbaskets() {
this.httpClient.get<WorkbasketDefinition[]>(this.url, this.httpOptions).subscribe(
response => saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}), this.generateName())
);
}
// GET
exportWorkbasketsByDomain(domain: string) {
this.httpClient.get<WorkbasketDefinition[]>(this.url + '?' + 'domain=' + domain, this.httpOptions).subscribe(
response => {
saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}), this.generateName(domain));
console.log(response);
}
);
}
// POST
// TODO handle error
importWorkbasketDefinitions(workbasketDefinitions: any) {
console.log('importing workbaskets');
this.httpClient.post(environment.taskanaRestUrl + '/v1/workbasketdefinitions/import',
JSON.parse(workbasketDefinitions), this.httpOptions).subscribe(
workbasketsUpdated => this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful')),
error => this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Import was not successful'))
);
}
private generateName(domain = ''): string {
const dateFormat = 'yyyy-MM-ddTHH:mm:ss';
const dateLocale = 'en-US';
const datePipe = new DatePipe(dateLocale);
const date = datePipe.transform(Date.now(), dateFormat) + 'Z';
return 'Workbaskets_' + date + '.json';
}
}

View File

@ -9,7 +9,7 @@ import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-
})
export class MasterAndDetailComponent implements OnInit {
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'clasifications'];
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'classifications'];
private sub: any;
showDetail: Boolean = false;