TSK-203 Add classification tree view
This commit is contained in:
parent
88eca3d326
commit
2efa1c6b30
|
@ -19,9 +19,7 @@
|
|||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss",
|
||||
"./assets/_site.scss",
|
||||
"./assets/_forms.scss"
|
||||
"./assets/_styles.scss"
|
||||
],
|
||||
"scripts": [
|
||||
"../node_modules/jquery/dist/jquery.min.js",
|
||||
|
|
|
@ -571,13 +571,20 @@
|
|||
"integrity": "sha512-wIRpoQ3PwytxA4MRe9cgmdytXrHgTGUuTdmIFtAQvCcftUSWWkzkVaXF1QSlFip6ipHf/YacdJHFYXpnW2lWPQ=="
|
||||
},
|
||||
"angular-tree-component": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-7.0.1.tgz",
|
||||
"integrity": "sha1-/I0OctjDS4cTGjuivTKtIJRWiaw=",
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-7.1.0.tgz",
|
||||
"integrity": "sha512-i0Kk4gnuU+i6p5ZsIcDcGrtHPnDLOyHk8Vqez6IpSuOLvVPZ3Y7/Y1MEOoj7Nx6qRU5NuuVaPLy2idOEB7ClRw==",
|
||||
"requires": {
|
||||
"lodash": "4.17.4",
|
||||
"mobx": "3.4.1",
|
||||
"lodash": "4.17.5",
|
||||
"mobx": "3.6.2",
|
||||
"mobx-angular": "2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.17.5",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ansi-html": {
|
||||
|
@ -7259,9 +7266,9 @@
|
|||
}
|
||||
},
|
||||
"mobx": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/mobx/-/mobx-3.4.1.tgz",
|
||||
"integrity": "sha1-N6vl7ogtQBgo2fJsbBovR2FLu+8="
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/mobx/-/mobx-3.6.2.tgz",
|
||||
"integrity": "sha512-Dq3boJFLpZEvuh5a/MbHLUIyN9XobKWIb0dBfkNOJffNkE3vtuY0C9kSDVpfH8BB0BPkVw8g22qCv7d05LEhKg=="
|
||||
},
|
||||
"mobx-angular": {
|
||||
"version": "2.1.1",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"@angular/router": "5.2.1",
|
||||
"file-saver": "1.3.3",
|
||||
"angular-svg-icon": "5.0.0",
|
||||
"angular-tree-component": "7.0.1",
|
||||
"angular-tree-component": "7.1.0",
|
||||
"bootstrap": "3.3.7",
|
||||
"bootstrap-sass": "3.3.7",
|
||||
"core-js": "2.5.3",
|
||||
|
|
|
@ -1,40 +1,20 @@
|
|||
<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]="selectionToImport"></taskana-import-export-component>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
|
||||
<li id="wb-action-toolbar" class="list-group-item tab-align">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" (click)="addClassification()" data-toggle="tooltip" title="Add" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-plus green" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button type="button" (click)="removeClassification()" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
||||
</button>
|
||||
<taskana-import-export-component [currentSelection]="selectionToImport"></taskana-import-export-component>
|
||||
<taskana-classification-types-selector class="pull-right" [classificationTypes]="classificationsTypes" [(classificationTypeSelected)]="classificationTypeSelected"
|
||||
(classificationTypeChanged)=selectClassificationType($event)></taskana-classification-types-selector>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
|
||||
<taskana-tree [treeNodes]="classifications"></taskana-tree>
|
||||
|
||||
</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>
|
||||
</div>
|
|
@ -2,21 +2,15 @@
|
|||
height: calc(100vh - 55px);
|
||||
}
|
||||
|
||||
.row.list-group {
|
||||
margin-left: 2px;
|
||||
.list-group-item {
|
||||
padding: 5px 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.list-group > li {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
.tab-align{
|
||||
margin-bottom: 0px;
|
||||
|
||||
a > label {
|
||||
height: 2em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tab-align {
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-bottom: 12px;
|
||||
&>div{
|
||||
margin: 6px 0px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,46 @@
|
|||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import {ClassificationListComponent} from './classification-list.component';
|
||||
import {ImportExportComponent} from 'app/shared/import-export/import-export.component';
|
||||
import {SpinnerComponent} from 'app/shared/spinner/spinner.component';
|
||||
import {WorkbasketService} from 'app/services/workbasket/workbasket.service';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {WorkbasketDefinitionService} from 'app/services/workbasket/workbasketDefinition.service';
|
||||
import {AlertService} from 'app/services/alert/alert.service';
|
||||
import {ClassificationService} from 'app/services/classification/classification.service';
|
||||
import {DomainService} from 'app/services/domains/domain.service';
|
||||
import { TreeNode } from 'app/models/tree-node';
|
||||
|
||||
import { ClassificationListComponent } from './classification-list.component';
|
||||
import { ImportExportComponent } from 'app/shared/import-export/import-export.component';
|
||||
import { SpinnerComponent } from 'app/shared/spinner/spinner.component';
|
||||
import { ClassificationTypesSelectorComponent } from 'app/shared/classification-types-selector/classification-types-selector.component';
|
||||
import { MapValuesPipe } from 'app/pipes/mapValues/map-values.pipe';
|
||||
|
||||
import { WorkbasketService } from 'app/services/workbasket/workbasket.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket-definition/workbasket-definition.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { ClassificationsService } from 'app/services/classifications/classifications.service';
|
||||
import { ClassificationDefinitionService } from 'app/services/classification-definition/classification-definition.service';
|
||||
import { DomainService } from 'app/services/domains/domain.service';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-tree',
|
||||
template: ''
|
||||
})
|
||||
class TreeComponent {
|
||||
@Input() treeNodes;
|
||||
}
|
||||
|
||||
describe('ClassificationListComponent', () => {
|
||||
let component: ClassificationListComponent;
|
||||
let fixture: ComponentFixture<ClassificationListComponent>;
|
||||
const treeNodes: Array<TreeNode> = new Array(new TreeNode());
|
||||
const classificationTypes: Map<string, string> = new Map<string, string>([['type1', 'type1'], ['type2', 'type2']])
|
||||
let classificationsSpy, classificationsTypesSpy;
|
||||
let classificationsService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ClassificationListComponent, ImportExportComponent, SpinnerComponent],
|
||||
declarations: [ClassificationListComponent, ImportExportComponent, SpinnerComponent, ClassificationTypesSelectorComponent,
|
||||
TreeComponent, MapValuesPipe],
|
||||
imports: [HttpClientModule],
|
||||
providers: [
|
||||
WorkbasketService, HttpClient, WorkbasketDefinitionService, AlertService, ClassificationService, DomainService
|
||||
HttpClient, WorkbasketDefinitionService, AlertService, ClassificationsService, DomainService, ClassificationDefinitionService
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -28,6 +49,9 @@ describe('ClassificationListComponent', () => {
|
|||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClassificationListComponent);
|
||||
component = fixture.componentInstance;
|
||||
classificationsService = TestBed.get(ClassificationsService);
|
||||
classificationsSpy = spyOn(classificationsService, 'getClassifications').and.returnValue(Observable.of(treeNodes));
|
||||
classificationsTypesSpy = spyOn(classificationsService, 'getClassificationTypes').and.returnValue(Observable.of(classificationTypes));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,19 +1,55 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { ImportType } from 'app/models/import-type';
|
||||
import { Classification } from 'app/models/classification';
|
||||
import { TreeNode } from 'app/models/tree-node';
|
||||
|
||||
import { ClassificationsService } from 'app/services/classifications/classifications.service';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-classification-list',
|
||||
templateUrl: './classification-list.component.html',
|
||||
styleUrls: ['./classification-list.component.scss']
|
||||
selector: 'taskana-classification-list',
|
||||
templateUrl: './classification-list.component.html',
|
||||
styleUrls: ['./classification-list.component.scss']
|
||||
})
|
||||
export class ClassificationListComponent implements OnInit {
|
||||
export class ClassificationListComponent implements OnInit, OnDestroy {
|
||||
|
||||
selectionToImport = ImportType.CLASSIFICATIONS;
|
||||
requestInProgress = false;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
selectionToImport = ImportType.CLASSIFICATIONS;
|
||||
requestInProgress = false;
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
classifications: Array<Classification> = [];
|
||||
classificationsTypes: Map<string, string> = new Map();
|
||||
classificationTypeSelected: string;
|
||||
classificationServiceSubscription: Subscription;
|
||||
classificationTypeServiceSubscription: Subscription;
|
||||
constructor(private classificationService: ClassificationsService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.classificationServiceSubscription = this.classificationService.getClassifications()
|
||||
.subscribe((classifications: Array<TreeNode>) => {
|
||||
this.classifications = classifications;
|
||||
this.classificationTypeServiceSubscription = this.classificationService.getClassificationTypes()
|
||||
.subscribe((classificationsTypes: Map<string, string>) => {
|
||||
this.classificationsTypes = classificationsTypes;
|
||||
this.classificationTypeSelected = this.classifications[0].type;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectClassificationType(classificationTypeSelected: string) {
|
||||
this.classificationService.getClassifications(true, classificationTypeSelected)
|
||||
.subscribe((classifications: Array<TreeNode>) => {
|
||||
this.classifications = classifications;
|
||||
});
|
||||
}
|
||||
|
||||
addClassification() { }
|
||||
removeClassification() { }
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.classificationServiceSubscription) { this.classificationServiceSubscription.unsubscribe(); }
|
||||
if (this.classificationTypeServiceSubscription) { this.classificationTypeServiceSubscription.unsubscribe(); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
<button *ngIf="workbasketIdSelected" type="button" (click)="copyWorkbasket()" data-toggle="tooltip" title="copy" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-copy" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button *ngIf="workbasketIdSelected" type="button" data-toggle="tooltip" title="Remove distibution target" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-erase" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button *ngIf="workbasketIdSelected" type="button" (click)="removeWorkbasket()" data-toggle="tooltip" title="Remove" class="btn btn-default remove">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
.list-group-item {
|
||||
padding: 0px 15px;
|
||||
padding: 5px 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tab-align{
|
||||
margin-bottom: 0px;
|
||||
padding: 0px;
|
||||
|
||||
&>div{
|
||||
margin: 6px 0px;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ 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 { ClassificationService } from 'app/services/classification/classification.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket/workbasketDefinition.service';
|
||||
import { ClassificationDefinitionService } from 'app/services/classification-definition/classification-definition.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket-definition/workbasket-definition.service';
|
||||
import { DomainService } from 'app/services/domains/domain.service';
|
||||
|
||||
@Component({
|
||||
|
@ -54,7 +54,7 @@ describe('WorkbasketListToolbarComponent', () => {
|
|||
declarations: [WorkbasketListToolbarComponent, SortComponent,
|
||||
FilterComponent, IconTypeComponent, DummyDetailComponent, MapValuesPipe, ImportExportComponent],
|
||||
providers: [ErrorModalService, WorkbasketService, RequestInProgressService, AlertService,
|
||||
ClassificationService, WorkbasketDefinitionService, DomainService]
|
||||
ClassificationDefinitionService, WorkbasketDefinitionService, DomainService]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<taskana-spinner [isRunning]="requestInProgress" class="centered-horizontally"></taskana-spinner>
|
||||
<div>
|
||||
<ul #wbList id="wb-list-container" class="list-group">
|
||||
<li class="list-group-item no-border">
|
||||
<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"
|
||||
|
|
|
@ -35,6 +35,7 @@ li > div.row > dl:first-child {
|
|||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
.no-space {
|
||||
border-top: none;
|
||||
padding: 0px
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ import { ImportExportComponent } from 'app/shared/import-export/import-export.co
|
|||
|
||||
import { RemoveNoneTypePipe } from 'app/pipes/removeNoneType/remove-none-type.pipe';
|
||||
import { MapValuesPipe } from 'app/pipes/mapValues/map-values.pipe';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket/workbasketDefinition.service';
|
||||
import { ClassificationService } from 'app/services/classification/classification.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket-definition/workbasket-definition.service';
|
||||
import { ClassificationDefinitionService } from 'app/services/classification-definition/classification-definition.service';
|
||||
import { DomainService } from 'app/services/domains/domain.service';
|
||||
|
||||
@Component({
|
||||
|
@ -91,7 +91,7 @@ describe('WorkbasketListComponent', () => {
|
|||
RouterTestingModule.withRoutes(routes)
|
||||
],
|
||||
providers: [WorkbasketService, ErrorModalService, RequestInProgressService, AlertService,
|
||||
WorkbasketDefinitionService, OrientationService, DomainService, ClassificationService]
|
||||
WorkbasketDefinitionService, OrientationService, DomainService, ClassificationDefinitionService]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ import { RouterModule, Routes } from '@angular/router';
|
|||
import { AppComponent } from './app.component';
|
||||
import { WorkbasketListComponent } from './administration/workbasket/master/list/workbasket-list.component';
|
||||
import { WorkbasketDetailsComponent } from './administration/workbasket/details/workbasket-details.component';
|
||||
import { MasterAndDetailComponent } from './shared/masterAndDetail/master-and-detail.component';
|
||||
import { MasterAndDetailComponent } from './shared/master-and-detail/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 = [
|
||||
{
|
||||
path: 'workbaskets',
|
||||
path: 'administration/workbaskets',
|
||||
component: MasterAndDetailComponent,
|
||||
children: [
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ const appRoutes: Routes = [
|
|||
]
|
||||
},
|
||||
{
|
||||
path: 'classifications',
|
||||
path: 'administration/classifications',
|
||||
component: MasterAndDetailComponent,
|
||||
children: [
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ const appRoutes: Routes = [
|
|||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'workbaskets',
|
||||
redirectTo: 'administration/workbaskets',
|
||||
pathMatch: 'full'
|
||||
}
|
||||
];
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
<div class="col-xs-8 col-md-7 logo-container">
|
||||
<ul class="nav nav-tabs no-border-bottom" id="myTabs" role="tablist">
|
||||
<li role="presentation" class="{{workbasketsRoute? 'active' : 'inactive'}}" role="tab" data-toggle="tab">
|
||||
<a routerLink="/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a>
|
||||
<a routerLink="administration/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a>
|
||||
</li>
|
||||
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab">
|
||||
<a routerLink="/classifications" aria-controls="Classifications" routerLinkActive="active">Classifications</a>
|
||||
<a routerLink="administration/classifications" aria-controls="Classifications" routerLinkActive="active">Classifications</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,7 @@ import { ErrorModalService } from './services/errorModal/error-modal.service';
|
|||
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
|
||||
import { AlertService } from './services/alert/alert.service';
|
||||
import { OrientationService } from './services/orientation/orientation.service';
|
||||
import { SelectedRouteService } from './services/selected-route/selected-route';
|
||||
|
||||
import { GeneralMessageModalComponent } from './shared/general-message-modal/general-message-modal.component'
|
||||
import { SpinnerComponent } from './shared/spinner/spinner.component'
|
||||
|
@ -20,7 +21,7 @@ describe('AppComponent', () => {
|
|||
let app, fixture, debugElement;
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'categories', component: AppComponent }
|
||||
{ path: 'classifications', component: AppComponent }
|
||||
];
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
@ -33,7 +34,7 @@ describe('AppComponent', () => {
|
|||
RouterTestingModule.withRoutes(routes),
|
||||
HttpClientModule
|
||||
],
|
||||
providers: [ErrorModalService, RequestInProgressService, AlertService, OrientationService]
|
||||
providers: [ErrorModalService, RequestInProgressService, AlertService, OrientationService, SelectedRouteService]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AppComponent);
|
||||
|
@ -59,11 +60,11 @@ describe('AppComponent', () => {
|
|||
expect(debugElement.querySelector('ul p a').textContent).toContain('Taskana administration');
|
||||
}));
|
||||
|
||||
it('should call Router.navigateByUrl("categories") and workbasketRoute should be false', (inject([Router], (router: Router) => {
|
||||
it('should call Router.navigateByUrl("classifications") and workbasketRoute should be false', (inject([Router], (router: Router) => {
|
||||
|
||||
expect(app.workbasketsRoute).toBe(true);
|
||||
fixture.detectChanges();
|
||||
router.navigateByUrl(`/categories`);
|
||||
router.navigateByUrl(`/classifications`);
|
||||
expect(app.workbasketsRoute).toBe(false);
|
||||
|
||||
})));
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
import { Component, OnInit, HostListener } from '@angular/core';
|
||||
import { Component, OnInit, HostListener, OnDestroy } from '@angular/core';
|
||||
import { environment } from '../environments/environment';
|
||||
import { Router, NavigationStart } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { ErrorModel } from './models/modal-error';
|
||||
|
||||
import { ErrorModalService } from './services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
|
||||
import { OrientationService } from './services/orientation/orientation.service';
|
||||
import { SelectedRouteService } from './services/selected-route/selected-route';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
title = 'Taskana administration';
|
||||
|
||||
adminUrl: string = environment.taskanaAdminUrl;
|
||||
|
@ -23,9 +25,15 @@ export class AppComponent implements OnInit {
|
|||
|
||||
modalErrorMessage = '';
|
||||
modalTitle = '';
|
||||
selectedRoute = '';
|
||||
|
||||
requestInProgress = false;
|
||||
|
||||
errorModalSubscription: Subscription;
|
||||
requestInProgressSubscription: Subscription;
|
||||
selectedRouteSubscription: Subscription;
|
||||
routerSubscription: Subscription;
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event) {
|
||||
this.orientationService.onResize();
|
||||
|
@ -35,25 +43,38 @@ export class AppComponent implements OnInit {
|
|||
private router: Router,
|
||||
private errorModalService: ErrorModalService,
|
||||
private requestInProgressService: RequestInProgressService,
|
||||
private orientationService: OrientationService) {
|
||||
private orientationService: OrientationService,
|
||||
private selectedRouteService: SelectedRouteService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.router.events.subscribe(event => {
|
||||
|
||||
this.routerSubscription = this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationStart) {
|
||||
if (event.url.indexOf('categories') !== -1) {
|
||||
this.workbasketsRoute = false;
|
||||
}
|
||||
this.selectedRouteService.selectRoute(event);
|
||||
}
|
||||
});
|
||||
|
||||
this.errorModalService.getError().subscribe((error: ErrorModel) => {
|
||||
this.errorModalSubscription = this.errorModalService.getError().subscribe((error: ErrorModel) => {
|
||||
this.modalErrorMessage = error.message;
|
||||
this.modalTitle = error.title;
|
||||
})
|
||||
|
||||
this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => {
|
||||
this.requestInProgressSubscription = this.requestInProgressService.getRequestInProgress().subscribe((value: boolean) => {
|
||||
this.requestInProgress = value;
|
||||
})
|
||||
|
||||
this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => {
|
||||
if (value.indexOf('classifications') !== -1) {
|
||||
this.workbasketsRoute = false;
|
||||
}
|
||||
this.selectedRoute = value;
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.routerSubscription) { this.routerSubscription.unsubscribe(); }
|
||||
if (this.errorModalSubscription) { this.errorModalSubscription.unsubscribe(); }
|
||||
if (this.requestInProgressSubscription) { this.requestInProgressSubscription.unsubscribe(); }
|
||||
if (this.selectedRouteSubscription) { this.selectedRouteSubscription.unsubscribe(); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,61 +2,66 @@
|
|||
/**
|
||||
* Modules
|
||||
*/
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
|
||||
import {AppRoutingModule} from './app-routing.module';
|
||||
import {AlertModule} from 'ngx-bootstrap';
|
||||
import {AngularSvgIconModule} from 'angular-svg-icon';
|
||||
import {TabsModule} from 'ngx-bootstrap/tabs';
|
||||
import {TreeModule} from 'angular-tree-component';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { TreeModule } from 'angular-tree-component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import {AppComponent} from './app.component';
|
||||
import {WorkbasketListComponent} from './administration/workbasket/master/list/workbasket-list.component';
|
||||
import {WorkbasketListToolbarComponent} from './administration/workbasket/master/list/workbasket-list-toolbar/workbasket-list-toolbar.component'
|
||||
import {WorkbasketDetailsComponent} from './administration/workbasket/details/workbasket-details.component';
|
||||
import {WorkbasketInformationComponent} from './administration/workbasket/details/information/workbasket-information.component';
|
||||
import {DistributionTargetsComponent} from './administration/workbasket/details/distribution-targets/distribution-targets.component';
|
||||
import {DualListComponent} from './administration/workbasket/details/distribution-targets/dual-list/dual-list.component';
|
||||
import {AccessItemsComponent} from './administration/workbasket/details/access-items/access-items.component';
|
||||
import {NoAccessComponent} from './administration/workbasket/details/noAccess/no-access.component';
|
||||
import {SpinnerComponent} from './shared/spinner/spinner.component';
|
||||
import {FilterComponent} from './shared/filter/filter.component';
|
||||
import {IconTypeComponent} from './shared/type-icon/icon-type.component';
|
||||
import {AlertComponent} from './shared/alert/alert.component';
|
||||
import {SortComponent} from './shared/sort/sort.component';
|
||||
import {GeneralMessageModalComponent} from './shared/general-message-modal/general-message-modal.component';
|
||||
import {PaginationComponent} from './administration/workbasket/master/list/pagination/pagination.component';
|
||||
import {ClassificationListComponent} from './administration/classification/master/list/classification-list.component';
|
||||
import {ImportExportComponent} from './shared/import-export/import-export.component';
|
||||
// Shared
|
||||
import {MasterAndDetailComponent} from './shared/masterAndDetail/master-and-detail.component';
|
||||
import { AppComponent } from './app.component';
|
||||
import { WorkbasketListComponent } from './administration/workbasket/master/list/workbasket-list.component';
|
||||
import { WorkbasketListToolbarComponent } from './administration/workbasket/master/list/workbasket-list-toolbar/workbasket-list-toolbar.component'
|
||||
import { WorkbasketDetailsComponent } from './administration/workbasket/details/workbasket-details.component';
|
||||
import { WorkbasketInformationComponent } from './administration/workbasket/details/information/workbasket-information.component';
|
||||
import { DistributionTargetsComponent } from './administration/workbasket/details/distribution-targets/distribution-targets.component';
|
||||
import { DualListComponent } from './administration/workbasket/details/distribution-targets/dual-list/dual-list.component';
|
||||
import { AccessItemsComponent } from './administration/workbasket/details/access-items/access-items.component';
|
||||
import { NoAccessComponent } from './administration/workbasket/details/noAccess/no-access.component';
|
||||
import { SpinnerComponent } from './shared/spinner/spinner.component';
|
||||
import { FilterComponent } from './shared/filter/filter.component';
|
||||
import { IconTypeComponent } from './shared/type-icon/icon-type.component';
|
||||
import { AlertComponent } from './shared/alert/alert.component';
|
||||
import { SortComponent } from './shared/sort/sort.component';
|
||||
import { GeneralMessageModalComponent } from './shared/general-message-modal/general-message-modal.component';
|
||||
import { PaginationComponent } from './administration/workbasket/master/list/pagination/pagination.component';
|
||||
import { ClassificationListComponent } from './administration/classification/master/list/classification-list.component';
|
||||
import { ImportExportComponent } from './shared/import-export/import-export.component';
|
||||
import { MasterAndDetailComponent } from './shared/master-and-detail/master-and-detail.component';
|
||||
import { ClassificationTypesSelectorComponent } from './shared/classification-types-selector/classification-types-selector.component';
|
||||
import { TreeComponent } from './shared/tree/tree.component';
|
||||
|
||||
/**
|
||||
* Services
|
||||
*/
|
||||
import {WorkbasketService} from './services/workbasket/workbasket.service';
|
||||
import {MasterAndDetailService} from './services/masterAndDetail/master-and-detail.service';
|
||||
import {HttpClientInterceptor} from './services/httpClientInterceptor/http-client-interceptor.service';
|
||||
import {PermissionService} from './services/permission/permission.service';
|
||||
import {AlertService} from './services/alert/alert.service';
|
||||
import {ErrorModalService} from './services/errorModal/error-modal.service';
|
||||
import {RequestInProgressService} from './services/requestInProgress/request-in-progress.service';
|
||||
import {SavingWorkbasketService} from './services/saving-workbaskets/saving-workbaskets.service';
|
||||
import {OrientationService} from './services/orientation/orientation.service';
|
||||
import {ClassificationService} from './services/classification/classification.service';
|
||||
import {WorkbasketDefinitionService} from './services/workbasket/workbasketDefinition.service';
|
||||
import { WorkbasketService } from './services/workbasket/workbasket.service';
|
||||
import { MasterAndDetailService } from './services/masterAndDetail/master-and-detail.service';
|
||||
import { HttpClientInterceptor } from './services/httpClientInterceptor/http-client-interceptor.service';
|
||||
import { PermissionService } from './services/permission/permission.service';
|
||||
import { AlertService } from './services/alert/alert.service';
|
||||
import { ErrorModalService } from './services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from './services/requestInProgress/request-in-progress.service';
|
||||
import { SavingWorkbasketService } from './services/saving-workbaskets/saving-workbaskets.service';
|
||||
import { OrientationService } from './services/orientation/orientation.service';
|
||||
import { ClassificationDefinitionService } from './services/classification-definition/classification-definition.service';
|
||||
import { WorkbasketDefinitionService } from './services/workbasket-definition/workbasket-definition.service';
|
||||
import { SelectedRouteService } from './services/selected-route/selected-route';
|
||||
import { ClassificationsService } from './services/classifications/classifications.service';
|
||||
|
||||
/**
|
||||
* Pipes
|
||||
*/
|
||||
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 {SpreadNumberPipe} from './pipes/spreadNumber/spread-number';
|
||||
import {DomainService} from './services/domains/domain.service';
|
||||
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 { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
|
||||
import { DomainService } from './services/domains/domain.service';
|
||||
|
||||
const MODULES = [
|
||||
BrowserModule,
|
||||
|
@ -91,6 +96,8 @@ const DECLARATIONS = [
|
|||
PaginationComponent,
|
||||
ClassificationListComponent,
|
||||
ImportExportComponent,
|
||||
TreeComponent,
|
||||
ClassificationTypesSelectorComponent,
|
||||
MapValuesPipe,
|
||||
RemoveNoneTypePipe,
|
||||
SelectWorkBasketPipe,
|
||||
|
@ -104,7 +111,7 @@ const DECLARATIONS = [
|
|||
WorkbasketService,
|
||||
MasterAndDetailService,
|
||||
PermissionService,
|
||||
ClassificationService,
|
||||
ClassificationDefinitionService,
|
||||
WorkbasketDefinitionService,
|
||||
DomainService,
|
||||
{
|
||||
|
@ -116,7 +123,9 @@ const DECLARATIONS = [
|
|||
ErrorModalService,
|
||||
RequestInProgressService,
|
||||
SavingWorkbasketService,
|
||||
OrientationService
|
||||
OrientationService,
|
||||
SelectedRouteService,
|
||||
ClassificationsService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
export class ClassificationDefinition {
|
||||
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) {
|
||||
}
|
||||
}
|
|
@ -1,24 +1,12 @@
|
|||
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) {
|
||||
constructor(public id: string,
|
||||
public key: string,
|
||||
public category: string,
|
||||
public type: string,
|
||||
public domain: string,
|
||||
public name: string,
|
||||
public parentId: string,
|
||||
public priority: number,
|
||||
public serviceLevel: string) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { Classification } from 'app/models/classification';
|
||||
|
||||
export class TreeNode extends Classification {
|
||||
constructor(public id: string = '',
|
||||
public key: string = '',
|
||||
public category: string = '',
|
||||
public type: string = '',
|
||||
public domain: string = '',
|
||||
public name: string = '',
|
||||
public parentId: string = '',
|
||||
public priority: number = 0,
|
||||
public serviceLevel: string = '',
|
||||
public children: Array<TreeNode> = undefined) {
|
||||
super(id, key, category, type, domain, name, parentId, priority, serviceLevel);
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@ import {Injectable} from '@angular/core';
|
|||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import {environment} from '../../../environments/environment';
|
||||
import {AlertService} from '../alert/alert.service';
|
||||
import {Classification} from '../../models/classification';
|
||||
import {ClassificationDefinition} from '../../models/classification-definition';
|
||||
import {AlertModel, AlertType} from '../../models/alert';
|
||||
import {saveAs} from 'file-saver/FileSaver';
|
||||
import {TaskanaDate} from '../../shared/util/taskana.date';
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationService {
|
||||
export class ClassificationDefinitionService {
|
||||
|
||||
url = environment.taskanaRestUrl + '/v1/classificationdefinitions';
|
||||
|
||||
|
@ -25,7 +25,7 @@ export class ClassificationService {
|
|||
// GET
|
||||
exportClassifications(domain: string) {
|
||||
domain = (domain === '' ? '' : '?domain=' + domain);
|
||||
this.httpClient.get<Classification[]>(this.url + domain, this.httpOptions)
|
||||
this.httpClient.get<ClassificationDefinition[]>(this.url + domain, this.httpOptions)
|
||||
.subscribe(
|
||||
response => saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}),
|
||||
'Classifications_' + TaskanaDate.getDate() + '.json')
|
|
@ -0,0 +1,84 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
import { Classification } from 'app/models/classification';
|
||||
import { TreeNode } from 'app/models/tree-node';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationsService {
|
||||
|
||||
url = environment.taskanaRestUrl + '/v1/classifications';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
private classificationRef: Observable<Array<Classification>>;
|
||||
private classificationTypes: Array<string>;
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
// GET
|
||||
getClassifications(forceRequest = false, type = 'TASK', domain = ''): Observable<Array<TreeNode>> {
|
||||
if (!forceRequest && this.classificationRef) {
|
||||
return this.classificationRef.map((response: Array<Classification>) => {
|
||||
return this.buildHierarchy(response, type, domain);
|
||||
});
|
||||
}
|
||||
this.classificationRef = this.httpClient.get<Array<Classification>>(`${environment.taskanaRestUrl}/v1/classifications`,
|
||||
this.httpOptions);
|
||||
|
||||
return this.classificationRef.map((response: Array<Classification>) => {
|
||||
return this.buildHierarchy(response, type, domain);
|
||||
});
|
||||
}
|
||||
|
||||
getClassificationTypes(): Observable<Map<string, string>> {
|
||||
const typesSubject = new Subject<Map<string, string>>();
|
||||
this.classificationRef.subscribe((classifications: Array<Classification>) => {
|
||||
const types = new Map<string, string>();
|
||||
classifications.forEach(element => {
|
||||
types.set(element.type, element.type);
|
||||
});
|
||||
typesSubject.next(types);
|
||||
});
|
||||
return typesSubject.asObservable();
|
||||
}
|
||||
|
||||
private buildHierarchy(classifications: Array<Classification>, type: string, domain: string) {
|
||||
const roots = []
|
||||
const children = new Array<any>();
|
||||
|
||||
for (let index = 0, len = classifications.length; index < len; ++index) {
|
||||
const item = classifications[index];
|
||||
if (item.type === type) {
|
||||
const parent = item.parentId,
|
||||
target = !parent ? roots : (children[parent] || (children[parent] = []));
|
||||
|
||||
target.push(item);
|
||||
}
|
||||
}
|
||||
for (let index = 0, len = roots.length; index < len; ++index) {
|
||||
this.findChildren(roots[index], children);
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
|
||||
private findChildren(parent: any, children: Array<any>) {
|
||||
if (children[parent.id]) {
|
||||
parent.children = children[parent.id];
|
||||
for (let index = 0, len = parent.children.length; index < len; ++index) {
|
||||
this.findChildren(parent.children[index], children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { Injectable, OnInit } from '@angular/core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class SelectedRouteService {
|
||||
|
||||
public selectedRouteTriggered = new Subject<string>();
|
||||
|
||||
private detailRoutes: Array<string> = ['workbaskets', 'classifications'];
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router) { }
|
||||
|
||||
|
||||
selectRoute(value) {
|
||||
this.selectedRouteTriggered.next(this.getRoute(value));
|
||||
}
|
||||
|
||||
getSelectedRoute(): Observable<string> {
|
||||
return this.selectedRouteTriggered.asObservable();
|
||||
}
|
||||
|
||||
private getRoute(event): string {
|
||||
if (event === undefined) {
|
||||
return this.checkUrl(this.router.url);
|
||||
}
|
||||
return this.checkUrl(event.url)
|
||||
}
|
||||
|
||||
private checkUrl(url: string): string {
|
||||
for (const routeDetail of this.detailRoutes) {
|
||||
if (url.indexOf(routeDetail) !== -1) {
|
||||
return routeDetail;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<div class="dropdown clearfix btn-group">
|
||||
|
||||
<button type="button" class="btn btn-default"> {{classificationTypeSelected}}</button>
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right sortby-dropdown popup" aria-labelledby="sortingDropdown">
|
||||
<li *ngFor="let classificationType of classificationTypes | mapValues">
|
||||
<a (click)="select(classificationType.key)">
|
||||
<label>
|
||||
<span class="glyphicon {{classificationTypeSelected === classificationType.key? 'glyphicon-check': 'glyphicon-unchecked'}} blue"
|
||||
aria-hidden="true"></span>
|
||||
{{classificationType.key}}
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ClassificationTypesSelectorComponent } from './classification-types-selector.component';
|
||||
import { MapValuesPipe } from 'app/pipes/mapValues/map-values.pipe';
|
||||
|
||||
describe('ClassificationTypesSelectorComponent', () => {
|
||||
let component: ClassificationTypesSelectorComponent;
|
||||
let fixture: ComponentFixture<ClassificationTypesSelectorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ClassificationTypesSelectorComponent, MapValuesPipe ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClassificationTypesSelectorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-classification-types-selector',
|
||||
templateUrl: './classification-types-selector.component.html',
|
||||
styleUrls: ['./classification-types-selector.component.scss']
|
||||
})
|
||||
export class ClassificationTypesSelectorComponent implements OnInit {
|
||||
|
||||
@Input() classificationTypes: Map<string, string> = new Map<string, string>();
|
||||
@Input()
|
||||
classificationTypeSelected: string = undefined;
|
||||
@Output()
|
||||
classificationTypeSelectedChange = new EventEmitter<string>();
|
||||
@Output()
|
||||
classificationTypeChanged = new EventEmitter<string>();
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
select(value: string) {
|
||||
this.classificationTypeSelected = value;
|
||||
this.classificationTypeChanged.emit(value);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@ 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 {ClassificationDefinitionService} from '../../services/classification-definition/classification-definition.service';
|
||||
import {WorkbasketDefinitionService} from '../../services/workbasket-definition/workbasket-definition.service';
|
||||
import {AlertService} from '../../services/alert/alert.service';
|
||||
import {HttpClientModule} from '@angular/common/http';
|
||||
import {DomainService} from '../../services/domains/domain.service';
|
||||
|
@ -17,7 +17,7 @@ describe('ImportExportComponent', () => {
|
|||
TestBed.configureTestingModule({
|
||||
declarations: [ImportExportComponent],
|
||||
imports: [HttpClientModule],
|
||||
providers: [WorkbasketService, ClassificationService, WorkbasketDefinitionService, AlertService, DomainService]
|
||||
providers: [WorkbasketService, ClassificationDefinitionService, WorkbasketDefinitionService, AlertService, DomainService]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { ClassificationService } from 'app/services/classification/classification.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket/workbasketDefinition.service';
|
||||
import { ClassificationDefinitionService } from 'app/services/classification-definition/classification-definition.service';
|
||||
import { WorkbasketDefinitionService } from 'app/services/workbasket-definition/workbasket-definition.service';
|
||||
import { DomainService } from 'app/services/domains/domain.service';
|
||||
import { ImportType } from 'app/models/import-type';
|
||||
|
||||
|
@ -15,7 +15,7 @@ export class ImportExportComponent implements OnInit {
|
|||
domains: string[] = [];
|
||||
|
||||
constructor(private domainService: DomainService, private workbasketDefinitionService: WorkbasketDefinitionService,
|
||||
private classificationService: ClassificationService) {
|
||||
private classificationDefinitionService: ClassificationDefinitionService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -33,7 +33,7 @@ export class ImportExportComponent implements OnInit {
|
|||
if (this.currentSelection === ImportType.WORKBASKETS) {
|
||||
reader.onload = <Event>(e) => this.workbasketDefinitionService.importWorkbasketDefinitions(e.target.result);
|
||||
} else {
|
||||
reader.onload = <Event>(e) => this.classificationService.importClassifications(e.target.result);
|
||||
reader.onload = <Event>(e) => this.classificationDefinitionService.importClassifications(e.target.result);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export class ImportExportComponent implements OnInit {
|
|||
if (this.currentSelection === ImportType.WORKBASKETS) {
|
||||
this.workbasketDefinitionService.exportWorkbaskets(domain);
|
||||
} else {
|
||||
this.classificationService.exportClassifications(domain);
|
||||
this.classificationDefinitionService.exportClassifications(domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-
|
|||
|
||||
})
|
||||
export class MasterAndDetailComponent implements OnInit {
|
||||
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'classifications'];
|
||||
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'classifications/(detail'];
|
||||
private sub: any;
|
||||
|
||||
showDetail: Boolean = false;
|
|
@ -0,0 +1,14 @@
|
|||
<tree-root [nodes]="treeNodes" [state]="state" [options]="options">
|
||||
<ng-template #treeNodeTemplate let-node let-index="index">
|
||||
<span class="text-top">
|
||||
<svg-icon class="blue small fa-fw" src="./assets/icons/{{node.data.category === 'EXTERN'? 'external':
|
||||
node.data.category === 'AUTOMATIC'? 'automatic':
|
||||
node.data.category === 'MANUAL'? 'manual':
|
||||
'closed'}}.svg"></svg-icon>
|
||||
</span>
|
||||
<span>
|
||||
<strong>{{ node.data.key }}</strong>
|
||||
</span>
|
||||
<span> - {{ node.data.name }}</span>
|
||||
</ng-template>
|
||||
</tree-root>
|
|
@ -0,0 +1,3 @@
|
|||
.text-top{
|
||||
vertical-align: text-top;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import { Input, Component } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TreeComponent } from './tree.component';
|
||||
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
// tslint:disable:component-selector
|
||||
@Component({
|
||||
selector: 'tree-root',
|
||||
template: ''
|
||||
})
|
||||
class TreeVendorComponent {
|
||||
@Input() options;
|
||||
@Input() state;
|
||||
@Input() nodes;
|
||||
}
|
||||
|
||||
// tslint:enable:component-selector
|
||||
fdescribe('TreeComponent', () => {
|
||||
let component: TreeComponent;
|
||||
let fixture: ComponentFixture<TreeComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AngularSvgIconModule, HttpClientModule, HttpModule],
|
||||
declarations: [TreeComponent, TreeVendorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TreeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { TreeNode } from 'app/models/tree-node';
|
||||
import { TREE_ACTIONS, KEYS, IActionMapping, ITreeOptions, ITreeState } from 'angular-tree-component';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-tree',
|
||||
templateUrl: './tree.component.html',
|
||||
styleUrls: ['./tree.component.scss']
|
||||
})
|
||||
export class TreeComponent implements OnInit {
|
||||
|
||||
@Input() treeNodes: TreeNode;
|
||||
@Output() treeNodesChange = new EventEmitter<Array<TreeNode>>();
|
||||
|
||||
options: ITreeOptions = {
|
||||
displayField: 'name',
|
||||
idField: 'id',
|
||||
actionMapping: {
|
||||
keys: {
|
||||
[KEYS.ENTER]: (tree, node, $event) => {
|
||||
node.toggleExpanded();
|
||||
}
|
||||
}
|
||||
},
|
||||
animateExpand: true,
|
||||
animateSpeed: 20,
|
||||
levelPadding: 20
|
||||
}
|
||||
|
||||
state: ITreeState = {
|
||||
activeNodeIds: { ['']: true },
|
||||
}
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
$blue-green: #479ea9;
|
||||
$blue: #337ab7;
|
||||
$green: green;
|
||||
$grey: grey;
|
||||
$brown: #f0ad4e;
|
||||
$invalid: #a94442;
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
.ng-invalid:not(form) {
|
||||
border-color: #a94442;
|
||||
border-color: $invalid;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.required-text {
|
||||
padding-left: 15px;
|
||||
color: #a94442;
|
||||
color: $invalid;
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.placeholder {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
@ -70,38 +69,58 @@
|
|||
}
|
||||
|
||||
.blue{
|
||||
color: #337ab7;
|
||||
color: $blue;
|
||||
& svg {
|
||||
fill: #337ab7;
|
||||
fill: $blue;
|
||||
}
|
||||
}
|
||||
|
||||
.green {
|
||||
color: green;
|
||||
color: $green;
|
||||
& svg {
|
||||
fill: green;
|
||||
fill: $green;
|
||||
}
|
||||
}
|
||||
|
||||
.grey {
|
||||
color:grey;
|
||||
color:$grey;
|
||||
& svg {
|
||||
fill: grey;
|
||||
fill: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
.brown {
|
||||
color: #f0ad4e;
|
||||
color: $brown;
|
||||
& svg {
|
||||
fill: #f0ad4e;
|
||||
fill: $brown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.panel-default > .panel-heading .badge.warning {
|
||||
background-color: #f0ad4e;
|
||||
.red {
|
||||
color: crimson;
|
||||
& svg {
|
||||
fill: crimson;
|
||||
}
|
||||
}
|
||||
|
||||
.green-blue {
|
||||
color: $blue-green;
|
||||
& svg {
|
||||
fill: $blue-green;
|
||||
}
|
||||
}
|
||||
|
||||
svg-icon.fa-fw > svg {
|
||||
text-align: center;
|
||||
width: 1.25em;
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading .badge.warning {
|
||||
background-color: $brown;
|
||||
}
|
||||
.badge.priority {
|
||||
background-color: #e1e1e1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -247,3 +266,8 @@ taskana-workbasket-information, taskana-workbasket-access-items, taskana-workbas
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
tree-viewport {
|
||||
border-top: 1px solid #ddd;
|
||||
height: calc(100vh - 110px);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@import 'variables';
|
||||
@import '../../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap';
|
||||
@import '../../node_modules/angular-tree-component/dist/angular-tree-component.css';
|
||||
@import 'site';
|
||||
@import 'forms';
|
||||
@import 'tree';
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
tree-node-expander {
|
||||
|
||||
& .toggle-children {
|
||||
top: 2px;
|
||||
@extend .glyphicon;
|
||||
@extend .glyphicon-plus;
|
||||
@extend .blue;
|
||||
background: white;
|
||||
background-image: none;
|
||||
color: $blue-green;
|
||||
padding-left:3px;
|
||||
}
|
||||
}
|
||||
.toggle-children-wrapper {
|
||||
padding: 0px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
tree-node-expander .toggle-children-wrapper-expanded {
|
||||
& .toggle-children {
|
||||
@extend .glyphicon-minus ;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
tree-node-collection > div > tree-node > .tree-node {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.node-content-wrapper {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
margin: 0px 10px;
|
||||
}
|
||||
|
||||
.node-wrapper {
|
||||
padding: 4px 0px;
|
||||
}
|
||||
|
||||
.node-drop-slot {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.node-content-wrapper, .tree-children {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.node-content-wrapper::before, .tree-children::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.node-content-wrapper-active, .node-content-wrapper.node-content-wrapper-active:hover, .node-content-wrapper-active.node-content-wrapper-focused {
|
||||
background-color: $blue;
|
||||
& >tree-node-content{
|
||||
color:white;
|
||||
& >span >svg-icon{
|
||||
@extend .white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* START Children branch lines*/
|
||||
.node-content-wrapper::before {
|
||||
border-bottom: 1px dotted $blue-green;
|
||||
border-left: 1px dotted $blue-green;
|
||||
height: 28px;
|
||||
top: -17px;
|
||||
width: 20px;
|
||||
left: -28px;
|
||||
}
|
||||
|
||||
.tree-node-level-1 > tree-node-wrapper > .node-wrapper > .node-content-wrapper::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree-node-leaf > .node-wrapper > .node-content-wrapper::before {
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
.tree-children::after {
|
||||
border-left: 1px dotted $blue-green;
|
||||
|
||||
height: 100%;
|
||||
top: -15px;
|
||||
left: -15px;
|
||||
}
|
||||
|
||||
tree-node:last-child > .tree-node > .tree-children::after {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.toggle-children {
|
||||
z-index: 1;
|
||||
}
|
||||
/* END children branch lines */
|
|
@ -0,0 +1,2 @@
|
|||
@import '_colors';
|
||||
$icon-font-path: '../../node_modules/bootstrap-sass/assets/fonts/bootstrap/';
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M6.108 15.89c-.088-.086-.15-.406-.193-.984l-.062-.856-.664-.327a9.303 9.303 0 0 1-1.013-.576l-.348-.248-.769.325c-.923.39-1.128.404-1.349.091-.442-.627-1.679-2.822-1.679-2.98 0-.128.207-.323.72-.678l.72-.498.048-1.144.049-1.143-.223-.193a8.167 8.167 0 0 0-.72-.51c-.273-.175-.52-.372-.548-.437-.047-.112 1.473-2.84 1.77-3.177.187-.212.379-.187 1.044.138.901.44.91.441 1.395.102.235-.164.684-.416.997-.56l.57-.259.062-.823c.034-.453.1-.892.145-.976.077-.139.245-.152 1.946-.152 1.39 0 1.885.027 1.953.107.05.059.12.482.154.94l.063.834.663.327c.365.18.82.439 1.012.575l.348.249.769-.325c.923-.39 1.128-.405 1.349-.092.443.628 1.679 2.823 1.679 2.981 0 .128-.207.323-.72.678l-.72.499-.024 1.16-.024 1.16.658.483c.38.28.68.567.709.681.038.148-.153.548-.757 1.584-.899 1.543-1 1.683-1.225 1.683-.086 0-.504-.147-.928-.326l-.771-.326-.39.295a6.852 6.852 0 0 1-1.01.586l-.621.29-.062.847c-.041.571-.104.889-.191.974-.193.188-3.62.188-3.812 0zM9.19 11.79c3.02-.797 3.91-4.723 1.544-6.797-.764-.67-1.612-.985-2.664-.99C5.713 3.995 3.945 5.7 3.95 7.979c.004 2.735 2.486 4.541 5.241 3.813zm-2.18-1.65c-.895-.395-1.395-1.172-1.394-2.163.003-1.388.976-2.338 2.397-2.338 1.42 0 2.393.95 2.396 2.338.002 1.384-.973 2.335-2.396 2.335-.428 0-.729-.052-1.004-.173z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M.517 15.83c-.144-.104-.292-.32-.377-.549-.133-.357-.14-.55-.12-3.638.019-3.142.025-3.27.167-3.495.311-.494.488-.582 1.233-.611l.691-.027 2.592-3.068 2.592-3.068-.043-.31c-.05-.356.09-.75.34-.957.208-.173.694-.17.905.006.224.187.38.655.33.99-.04.262.04.37 2.55 3.339L13.97 7.51l.692.027c.745.03.922.117 1.233.61.142.226.148.355.168 3.471.024 3.663.01 3.784-.473 4.174l-.26.21H8.042c-7.19 0-7.291-.003-7.525-.172zm14.885-.63l.176-.208v-6.38l-.209-.249-.209-.248H.921l-.208.248-.209.248v6.38l.175.21.176.207h14.372zM1.72 13.564a1.386 1.386 0 0 1-.41-.437c-.147-.26-.163-.388-.163-1.315 0-1.237.09-1.51.593-1.818.265-.162.383-.188.634-.138.412.083.866.6.832.947-.036.367-.242.348-.553-.051-.293-.377-.407-.412-.715-.223-.27.166-.29.255-.29 1.286 0 .829.01.901.174 1.095.111.132.257.209.397.209.212 0 .571-.312.571-.496 0-.132.226-.193.33-.09.233.23-.002.801-.429 1.042a.933.933 0 0 1-.971-.011zm1.975.092c-.09-.108-.055-3.633.038-3.743.113-.134.168-.128.302.032.094.11.113.384.113 1.65v1.517l.617.025c.647.025.817.129.718.436-.038.118-.174.14-.893.14-.466 0-.869-.026-.895-.057zm2.468-.085c-.459-.268-.548-.537-.574-1.724-.022-.994-.013-1.079.143-1.35.263-.458.512-.633.9-.633.38 0 .689.179.909.527.122.194.146.384.166 1.328.021 1.039.013 1.12-.145 1.4-.308.546-.907.74-1.399.452zm.881-.66c.165-.196.175-.263.173-1.124-.002-.959-.04-1.098-.344-1.29-.208-.132-.462-.062-.652.18-.127.161-.145.297-.145 1.105 0 .864.011.933.176 1.128.11.132.257.209.396.209.14 0 .286-.077.396-.209zm1.526.62c-.263-.18-.493-.546-.493-.783 0-.073.063-.173.14-.222.113-.071.172-.054.287.082.08.094.144.203.144.243 0 .107.337.268.562.268.233 0 .51-.278.51-.512 0-.255-.256-.506-.518-.508-.353-.002-.818-.29-.98-.608-.594-1.155.837-2.214 1.718-1.273.252.27.31.665.117.811-.108.082-.164.045-.366-.24-.207-.291-.28-.338-.528-.338-.496 0-.767.497-.453.834.073.078.312.177.531.22.646.124.979.502.979 1.109 0 .854-.964 1.39-1.65.917zm2.057.127c-.092-.109-.058-3.633.036-3.745.056-.066.35-.102.848-.102.803 0 .964.07.91.4-.02.13-.115.155-.684.176l-.66.024V11.5l.518.025c.485.023.52.038.542.227.033.276-.09.346-.613.348h-.447v1.018l.59.001c.666.002.79.06.756.348-.024.199-.039.203-.885.226-.474.013-.884-.003-.911-.035zm2.208-.08c-.024-.074-.043-.909-.043-1.855 0-2.003-.012-1.967.613-1.88.935.131 1.532.888 1.528 1.937-.004 1.094-.727 1.932-1.667 1.932-.288 0-.399-.034-.431-.134zm1.019-.635c.382-.258.534-.55.566-1.093.023-.387-.002-.521-.14-.762a1.391 1.391 0 0 0-.792-.644l-.196-.057v1.366c0 1.334.003 1.366.15 1.366.084 0 .269-.08.412-.176zM10.845 4.66l-2.41-2.862h-.788L5.237 4.66l-2.41 2.862h10.428zM8.303 1.037c.099-.257-.02-.469-.262-.469a.345.345 0 0 0-.252.13c-.14.2.02.549.252.549.124 0 .207-.067.262-.21z"/></svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M.056 8.794V1.611h10.202L8.68 3.294 7.105 4.978H2.933v8.082h8.19V9.113l1.402-1.675c.771-.92 1.419-1.674 1.44-1.674.02 0 .036 2.298.036 5.107v5.107H.056zm9.96-2.862l-.936-.955 1.63-1.656 1.63-1.657-.8-.812-.802-.813h5.255v5.326l-.83-.837-.831-.837-1.578 1.598c-.868.878-1.628 1.597-1.69 1.597-.061 0-.533-.43-1.048-.954z"/></svg>
|
After Width: | Height: | Size: 400 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M5.622 15.86c-.279-.151-.432-.49-.482-1.069l-.044-.504-1.554-2.058C1.9 10.052 1.777 9.835 1.88 9.27c.102-.56.59-1.024 1.161-1.103.403-.055.773.072 1.117.383l.274.249.002-2.41c.001-2.717.012-2.783.533-3.214.442-.365 1.218-.435 1.576-.142.066.055.089.029.089-.103 0-.224.245-.587.575-.854.582-.47 1.5-.297 1.916.36.113.178.205.386.205.46 0 .11.033.128.16.089.622-.19.884-.19 1.266.003.417.21.772.807.773 1.3 0 .132.027.157.125.117.365-.15.599-.18.857-.11.42.113.74.363.916.713.156.309.16.374.16 2.598 0 2.41-.085 3.537-.35 4.634-.154.637-.452 1.473-.613 1.72-.058.088-.14.425-.185.748-.095.7-.202.938-.505 1.123-.216.132-.374.14-3.172.137-2.466-.002-2.976-.02-3.139-.109zm5.932-.624c.068-.052.136-.307.185-.688.05-.388.142-.725.256-.942.273-.515.517-1.29.678-2.154.124-.667.15-1.167.182-3.389.027-1.936.014-2.646-.048-2.764-.047-.087-.194-.204-.327-.26-.21-.088-.275-.088-.485 0-.134.056-.278.167-.32.246-.046.087-.076.64-.076 1.414 0 1.034-.02 1.299-.11 1.428-.125.177-.464.215-.588.065-.05-.06-.084-.819-.098-2.169l-.02-2.077-.186-.186c-.333-.333-.966-.206-1.13.227-.037.099-.068 1.073-.068 2.166v1.986l-.177.117c-.165.108-.19.108-.355 0l-.178-.117V5.73c0-1.324-.02-2.508-.044-2.63-.108-.542-.727-.763-1.14-.407l-.2.171-.02 2.618c-.012 1.603-.047 2.65-.09 2.703-.142.171-.36.168-.536-.007l-.17-.17V6.006c0-1.297-.026-2.051-.076-2.145-.1-.188-.476-.341-.722-.294-.108.02-.276.132-.373.248l-.176.21v2.811c0 1.801-.027 2.86-.074 2.948-.143.269-.428.174-.886-.294-.667-.681-.982-.784-1.376-.451-.18.151-.219.237-.219.48 0 .24.058.37.305.688.167.215.886 1.161 1.596 2.103l1.292 1.712.046.554c.029.334.088.594.15.657.088.088.522.103 2.787.095 1.916-.007 2.714-.033 2.791-.092zM.118 4.356c-.12-.12-.106-.774.027-1.292C.59 1.34 2.276-.042 3.936-.042c.427 0 .567.08.567.325 0 .233-.157.321-.695.39C2.164.878.896 2.137.763 3.693c-.02.235-.082.5-.137.587-.108.174-.37.213-.508.075zm1.475-.023c-.134-.162-.045-.881.167-1.345.365-.8 1.25-1.44 2.1-1.516.479-.044.643.035.643.308 0 .216-.226.355-.668.411-.854.109-1.602.947-1.602 1.795 0 .128-.05.282-.112.344-.142.142-.412.144-.528.003zm12.354.043c-.055-.035-.124-.244-.154-.464-.126-.93-.762-1.614-1.597-1.72-.442-.057-.668-.196-.668-.412 0-.273.164-.352.643-.308.85.077 1.696.685 2.076 1.491.225.477.327 1.206.191 1.37-.1.12-.337.14-.491.043zm1.458-.095c-.055-.088-.119-.356-.142-.597-.15-1.57-1.397-2.805-3.04-3.012-.538-.068-.695-.156-.695-.389 0-.245.14-.325.567-.325.793 0 1.694.353 2.429.954.481.393 1.044 1.214 1.256 1.831.194.567.275 1.436.148 1.59-.133.16-.408.134-.523-.052z"/></svg>
|
After Width: | Height: | Size: 2.5 KiB |
Loading…
Reference in New Issue