TSK-1871: Implement new Frontend structure
Co-authored-by: Chi Nguyen <c.nguyen.prog@gmail.com> Co-authored-by: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com>
This commit is contained in:
parent
a8f7f5e96a
commit
8f38f82ee2
|
@ -11,6 +11,7 @@
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-builders/custom-webpack:browser",
|
"builder": "@angular-builders/custom-webpack:browser",
|
||||||
"options": {
|
"options": {
|
||||||
|
"allowedCommonJsDependencies": ["chart.js"],
|
||||||
"aot": true,
|
"aot": true,
|
||||||
"sourceMap": {
|
"sourceMap": {
|
||||||
"scripts": true
|
"scripts": true
|
||||||
|
|
|
@ -14,6 +14,6 @@ module.exports = {
|
||||||
// coverageReporters: ['html', 'text'],
|
// coverageReporters: ['html', 'text'],
|
||||||
coverageDirectory: 'coverage/taskana-web',
|
coverageDirectory: 'coverage/taskana-web',
|
||||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
|
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
|
||||||
prefix: '<rootDir>/'
|
prefix: `<rootDir>/${compilerOptions.baseUrl}/`
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,18 +22,19 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "13.3.1",
|
"@angular/animations": "13.3.4",
|
||||||
"@angular/cdk": "13.3.2",
|
"@angular/cdk": "13.3.4",
|
||||||
"@angular/common": "13.3.1",
|
"@angular/common": "13.3.4",
|
||||||
"@angular/core": "13.3.1",
|
"@angular/core": "13.3.4",
|
||||||
"@angular/forms": "13.3.1",
|
"@angular/forms": "13.3.4",
|
||||||
"@angular/material": "13.3.2",
|
"@angular/material": "13.3.4",
|
||||||
"@angular/platform-browser": "13.3.1",
|
"@angular/platform-browser": "13.3.4",
|
||||||
"@angular/platform-browser-dynamic": "13.3.1",
|
"@angular/platform-browser-dynamic": "13.3.4",
|
||||||
"@angular/router": "13.3.1",
|
"@angular/router": "13.3.4",
|
||||||
"@circlon/angular-tree-component": "11.0.4",
|
"@circlon/angular-tree-component": "11.0.4",
|
||||||
"@ngneat/hot-toast": "4.1.0",
|
"@ngneat/hot-toast": "4.1.0",
|
||||||
"@ngneat/overview": "3.0.4",
|
"@ngneat/overview": "3.0.4",
|
||||||
|
"@ngxs/router-plugin": "3.7.3",
|
||||||
"@ngxs/store": "3.7.3",
|
"@ngxs/store": "3.7.3",
|
||||||
"angular-svg-icon": "13.0.0",
|
"angular-svg-icon": "13.0.0",
|
||||||
"chart.js": "2.9.4",
|
"chart.js": "2.9.4",
|
||||||
|
@ -49,10 +50,10 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-builders/custom-webpack": "13.1.0",
|
"@angular-builders/custom-webpack": "13.1.0",
|
||||||
"@angular-devkit/build-angular": "13.3.1",
|
"@angular-devkit/build-angular": "13.3.3",
|
||||||
"@angular/cli": "13.3.1",
|
"@angular/cli": "13.3.3",
|
||||||
"@angular/compiler": "13.3.1",
|
"@angular/compiler": "13.3.4",
|
||||||
"@angular/compiler-cli": "13.3.1",
|
"@angular/compiler-cli": "13.3.4",
|
||||||
"@ngxs/devtools-plugin": "3.7.3",
|
"@ngxs/devtools-plugin": "3.7.3",
|
||||||
"@types/jest": "27.4.1",
|
"@types/jest": "27.4.1",
|
||||||
"@types/lodash": "4.14.181",
|
"@types/lodash": "4.14.181",
|
||||||
|
|
|
@ -69,7 +69,7 @@ const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'task-routing',
|
path: 'task-routing',
|
||||||
canActivate: [DomainGuard],
|
canActivate: [DomainGuard],
|
||||||
loadChildren: () => import('../task-routing/task-routing.module').then((m) => m.TaskRoutingModule)
|
loadChildren: () => import('@task-routing/task-routing.module').then((m) => m.TaskRoutingModule)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -60,6 +60,7 @@ import { UserGuard } from './shared/guards/user.guard';
|
||||||
import { ClassificationCategoriesService } from './shared/services/classification-categories/classification-categories.service';
|
import { ClassificationCategoriesService } from './shared/services/classification-categories/classification-categories.service';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
import { STATES } from './shared/store';
|
import { STATES } from './shared/store';
|
||||||
|
import { NgxsRouterPluginModule } from '@ngxs/router-plugin';
|
||||||
|
|
||||||
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];
|
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ const MODULES = [
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
|
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
|
||||||
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }),
|
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }),
|
||||||
|
NgxsRouterPluginModule.forRoot(),
|
||||||
HttpClientXsrfModule
|
HttpClientXsrfModule
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { RoutingUploadComponent } from './routing-upload.component';
|
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
import { StartupService } from '../../shared/services/startup/startup.service';
|
|
||||||
import { TaskanaEngineService } from '../../shared/services/taskana-engine/taskana-engine.service';
|
|
||||||
import { WindowRefService } from '../../shared/services/window/window.service';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
|
||||||
import { DragAndDropDirective } from '../../shared/directives/drag-and-drop.directive';
|
|
||||||
|
|
||||||
describe('RoutingUploadComponent', () => {
|
|
||||||
let component: RoutingUploadComponent;
|
|
||||||
let fixture: ComponentFixture<RoutingUploadComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [RoutingUploadComponent, DragAndDropDirective],
|
|
||||||
imports: [HttpClientTestingModule, MatDialogModule],
|
|
||||||
providers: [StartupService, TaskanaEngineService, WindowRefService]
|
|
||||||
}).compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(RoutingUploadComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class ClassificationRoutingModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { ClassificationRoutingModule } from './classification-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule, ClassificationRoutingModule]
|
||||||
|
})
|
||||||
|
export class ClassificationModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class HistoryRoutingModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { HistoryRoutingModule } from './history-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule, HistoryRoutingModule]
|
||||||
|
})
|
||||||
|
export class HistoryModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class MonitorRoutingModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { MonitorRoutingModule } from './monitor-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule, MonitorRoutingModule]
|
||||||
|
})
|
||||||
|
export class MonitorModule {}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule]
|
||||||
|
})
|
||||||
|
export class SharedModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class ShellRoutingModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { ShellRoutingModule } from './shell-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule, ShellRoutingModule]
|
||||||
|
})
|
||||||
|
export class ShellModule {}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { RoutingUploadService } from '../routing-upload.service';
|
import { RoutingUploadService } from '@task-routing/services/routing-upload.service';
|
||||||
import { NotificationService } from '../../shared/services/notifications/notification.service';
|
import { NotificationService } from 'app/shared/services/notifications/notification.service';
|
||||||
import { HotToastService } from '@ngneat/hot-toast';
|
import { HotToastService } from '@ngneat/hot-toast';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
|
@ -1,7 +1,7 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { TaskanaEngineService } from '../services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
|
@ -2,9 +2,9 @@ import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { RoutingUploadService } from './routing-upload.service';
|
import { RoutingUploadService } from './routing-upload.service';
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
import { StartupService } from '../shared/services/startup/startup.service';
|
import { StartupService } from 'app/shared/services/startup/startup.service';
|
||||||
import { TaskanaEngineService } from '../shared/services/taskana-engine/taskana-engine.service';
|
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
|
||||||
import { WindowRefService } from '../shared/services/window/window.service';
|
import { WindowRefService } from 'app/shared/services/window/window.service';
|
||||||
|
|
||||||
describe('RoutingUploadService', () => {
|
describe('RoutingUploadService', () => {
|
||||||
let service: RoutingUploadService;
|
let service: RoutingUploadService;
|
|
@ -1,6 +1,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { StartupService } from '../shared/services/startup/startup.service';
|
import { StartupService } from 'app/shared/services/startup/startup.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
|
@ -1,7 +1,7 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { RoutingUploadComponent } from './routing-upload/routing-upload.component';
|
import { RoutingUploadComponent } from './components/routing-upload/routing-upload.component';
|
||||||
import { TaskRoutingGuard } from '../shared/guards/task-routing.guard';
|
import { TaskRoutingGuard } from './guards/task-routing.guard';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
import { TaskRoutingRoutingModule } from './task-routing-routing.module';
|
import { TaskRoutingRoutingModule } from './task-routing-routing.module';
|
||||||
import { RoutingUploadComponent } from './routing-upload/routing-upload.component';
|
import { RoutingUploadComponent } from './components/routing-upload/routing-upload.component';
|
||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="task-list-container">
|
||||||
|
<taskana-task-list></taskana-task-list>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
|
@ -0,0 +1,13 @@
|
||||||
|
.task-list-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
taskana-task-list {
|
||||||
|
width: 500px;
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
router-outlet {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskContainerComponent } from './task-container.component';
|
||||||
|
|
||||||
|
describe.skip('TaskContainerComponent', () => {
|
||||||
|
let component: TaskContainerComponent;
|
||||||
|
let fixture: ComponentFixture<TaskContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [TaskContainerComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TaskContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { TaskFacadeService } from '@task/services/task-facade.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-task-container',
|
||||||
|
templateUrl: './task-container.component.html',
|
||||||
|
styleUrls: ['./task-container.component.scss']
|
||||||
|
})
|
||||||
|
export class TaskContainerComponent implements OnInit {
|
||||||
|
constructor(private taskFacade: TaskFacadeService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.taskFacade.getTasks();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
<p>TASK DETAILS CONTAINER</p>
|
||||||
|
<taskana-task-details></taskana-task-details>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskDetailsContainerComponent } from './task-details-container.component';
|
||||||
|
|
||||||
|
describe.skip('TaskDetailsContainerComponent', () => {
|
||||||
|
let component: TaskDetailsContainerComponent;
|
||||||
|
let fixture: ComponentFixture<TaskDetailsContainerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [TaskDetailsContainerComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TaskDetailsContainerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { TaskFacadeService } from '@task/services/task-facade.service';
|
||||||
|
import { debounceTime } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-task-details-container',
|
||||||
|
templateUrl: './task-details-container.component.html',
|
||||||
|
styleUrls: ['./task-details-container.component.scss']
|
||||||
|
})
|
||||||
|
export class TaskDetailsContainerComponent implements OnInit {
|
||||||
|
constructor(private route: ActivatedRoute, private taskFacade: TaskFacadeService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
//TODO add takeuntil destroy, can use https://github.com/ngneat/until-destroy
|
||||||
|
this.route.params.pipe().subscribe((param) => {
|
||||||
|
const taskId = param.id;
|
||||||
|
this.taskFacade.getTask(taskId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div *ngIf="selectedTask$ | async as task">
|
||||||
|
<div>
|
||||||
|
<p>{{task.taskId}}</p>
|
||||||
|
<p>{{task.name}}</p>
|
||||||
|
<p>{{task.priority}}</p>
|
||||||
|
<p>{{task.owner}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskDetailsComponent } from './task-details.component';
|
||||||
|
|
||||||
|
describe.skip('TaskDetailsComponent', () => {
|
||||||
|
let component: TaskDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<TaskDetailsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [TaskDetailsComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TaskDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Select } from '@ngxs/store';
|
||||||
|
import { TaskSelector } from '@task/store/task.selector';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-task-details',
|
||||||
|
templateUrl: './task-details.component.html',
|
||||||
|
styleUrls: ['./task-details.component.scss']
|
||||||
|
})
|
||||||
|
export class TaskDetailsComponent implements OnInit {
|
||||||
|
@Select(TaskSelector.selectedTask) selectedTask$: Observable<Task | null>;
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<p>task-list works!</p>
|
||||||
|
<div *ngFor="let task of tasks$ | async">
|
||||||
|
<div (click)="selectTask(task.taskId)">
|
||||||
|
<span [ngClass]="{'task--selected': (selectedTask$ | async)?.taskId === task.taskId}">{{ task.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
.task--selected {
|
||||||
|
color: blue;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskListComponent } from './task-list.component';
|
||||||
|
|
||||||
|
describe.skip('TaskListComponent', () => {
|
||||||
|
let component: TaskListComponent;
|
||||||
|
let fixture: ComponentFixture<TaskListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [TaskListComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TaskListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Select } from '@ngxs/store';
|
||||||
|
import { TaskSummary } from '@task/models/task';
|
||||||
|
import { TaskFacadeService } from '@task/services/task-facade.service';
|
||||||
|
import { TaskSelector } from '@task/store/task.selector';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-task-list',
|
||||||
|
templateUrl: './task-list.component.html',
|
||||||
|
styleUrls: ['./task-list.component.scss']
|
||||||
|
})
|
||||||
|
export class TaskListComponent implements OnInit {
|
||||||
|
@Select(TaskSelector.tasks)
|
||||||
|
tasks$: Observable<TaskSummary[]>;
|
||||||
|
|
||||||
|
@Select(TaskSelector.selectedTask) selectedTask$: Observable<Task | null>;
|
||||||
|
|
||||||
|
constructor(private taskFacade: TaskFacadeService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
selectTask(taskId: string): void {
|
||||||
|
if (this.isTaskSelected(taskId)) {
|
||||||
|
/**
|
||||||
|
* @TODO Add deselectTask to facade
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
this.taskFacade.selectTask(taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isTaskSelected(taskId: string): boolean {
|
||||||
|
return this.taskFacade.selectedTask()?.taskId === taskId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
<p>task-overview works!</p>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskOverviewComponent } from './task-overview.component';
|
||||||
|
|
||||||
|
describe('TaskOverviewComponent', () => {
|
||||||
|
let component: TaskOverviewComponent;
|
||||||
|
let fixture: ComponentFixture<TaskOverviewComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [TaskOverviewComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TaskOverviewComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'taskana-task-overview',
|
||||||
|
templateUrl: './task-overview.component.html',
|
||||||
|
styleUrls: ['./task-overview.component.scss']
|
||||||
|
})
|
||||||
|
export class TaskOverviewComponent implements OnInit {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { TaskSummary } from './task';
|
||||||
|
|
||||||
|
export interface PagedTaskSummary {
|
||||||
|
tasks: TaskSummary[];
|
||||||
|
_links?: Object /* @TODO Use real object */;
|
||||||
|
page?: Object /* @TODO Use real object */;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
export interface TaskSummary {
|
||||||
|
taskId?: string;
|
||||||
|
externalId?: string;
|
||||||
|
created?: string;
|
||||||
|
claimed?: string;
|
||||||
|
completed?: string;
|
||||||
|
modified?: string;
|
||||||
|
planned?: string;
|
||||||
|
due?: string;
|
||||||
|
name?: string;
|
||||||
|
creator?: string;
|
||||||
|
note?: string;
|
||||||
|
description?: string;
|
||||||
|
priority?: number;
|
||||||
|
state?: string;
|
||||||
|
classificationSummary?: Object /* @TODO: Update to something real */;
|
||||||
|
workbasketSummary?: Object /* @TODO: Update to something real */;
|
||||||
|
businessProcessId?: string;
|
||||||
|
parentBusinessProcessId?: string;
|
||||||
|
owner?: string;
|
||||||
|
primaryObjRef?: Object /* @TODO: Update to something real */;
|
||||||
|
secondaryObjectReferences?: Object[] /* @TODO: Update to something real */;
|
||||||
|
custom1?: string;
|
||||||
|
custom2?: string;
|
||||||
|
custom3?: string;
|
||||||
|
custom4?: string;
|
||||||
|
custom5?: string;
|
||||||
|
custom6?: string;
|
||||||
|
custom7?: string;
|
||||||
|
custom8?: string;
|
||||||
|
custom9?: string;
|
||||||
|
custom10?: string;
|
||||||
|
custom11?: string;
|
||||||
|
custom12?: string;
|
||||||
|
custom13?: string;
|
||||||
|
custom14?: string;
|
||||||
|
custom15?: string;
|
||||||
|
custom16?: string;
|
||||||
|
attachmentSummaries?: any[];
|
||||||
|
read?: boolean;
|
||||||
|
transferred?: boolean;
|
||||||
|
count?: number;
|
||||||
|
// [key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Task extends TaskSummary {
|
||||||
|
customAttributes?: any[];
|
||||||
|
callbackinfo?: any[];
|
||||||
|
attachments?: any[];
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskFacadeService } from './task-facade.service';
|
||||||
|
|
||||||
|
describe.skip('TaskFacadeService', () => {
|
||||||
|
let service: TaskFacadeService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(TaskFacadeService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Navigate } from '@ngxs/router-plugin';
|
||||||
|
import { Store } from '@ngxs/store';
|
||||||
|
import { Task } from '@task/models/task';
|
||||||
|
import { GetTasks, GetTask } from '@task/store/task.actions';
|
||||||
|
import { TaskSelector } from '@task/store/task.selector';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TaskFacadeService {
|
||||||
|
constructor(private store: Store) {}
|
||||||
|
|
||||||
|
selectedTask(): Task | null {
|
||||||
|
return this.store.selectSnapshot(TaskSelector.selectedTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTasks(): void {
|
||||||
|
this.store.dispatch(new GetTasks());
|
||||||
|
}
|
||||||
|
|
||||||
|
// distinguish between select a task (what happens to UI?) and the action of getting information of a task from a taskID
|
||||||
|
selectTask(taskId: string): void {
|
||||||
|
this.store.dispatch(new Navigate([`/taskana/workplace/tasks/taskdetail/${taskId}`]));
|
||||||
|
}
|
||||||
|
|
||||||
|
getTask(taskId: string): void {
|
||||||
|
this.store.dispatch(new GetTask(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO Discuss potential method "deselectTask" if feature is present
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TaskService } from './task.service';
|
||||||
|
|
||||||
|
describe.skip('TaskService', () => {
|
||||||
|
let service: TaskService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(TaskService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { Task } from '@task/models/task';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Sorting, TaskQuerySortParameter } from 'app/shared/models/sorting';
|
||||||
|
import { StartupService } from 'app/shared/services/startup/startup.service'; /* @TODO Legacy */
|
||||||
|
import { asUrlQueryString } from 'app/shared/util/query-parameters-v2'; /* @TODO Legacy */
|
||||||
|
import { TaskQueryFilterParameter } from 'app/shared/models/task-query-filter-parameter'; /* @TODO Legacy */
|
||||||
|
import { QueryPagingParameter } from 'app/shared/models/query-paging-parameter'; /* @TODO Legacy */
|
||||||
|
import { PagedTaskSummary } from '@task/models/paged-task';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TaskService {
|
||||||
|
constructor(private httpClient: HttpClient, private startupService: StartupService) {}
|
||||||
|
|
||||||
|
get url(): string {
|
||||||
|
return this.startupService.getTaskanaRestUrl() + '/v1/tasks';
|
||||||
|
}
|
||||||
|
|
||||||
|
createTask(task: Task): Observable<Task> {
|
||||||
|
return this.httpClient.post<Task>(this.url, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTasks(
|
||||||
|
filterParameter?: TaskQueryFilterParameter,
|
||||||
|
sortParameter?: Sorting<TaskQuerySortParameter>,
|
||||||
|
pagingParameter?: QueryPagingParameter
|
||||||
|
): Observable<PagedTaskSummary> {
|
||||||
|
const url: string = `${this.url}${asUrlQueryString({ ...filterParameter, ...sortParameter, ...pagingParameter })}`;
|
||||||
|
|
||||||
|
return this.httpClient.get<PagedTaskSummary>(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTask(id: string): Observable<Task> {
|
||||||
|
return this.httpClient.get<Task>(`${this.url}/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTask(task: Task): Observable<Task> {
|
||||||
|
return this.httpClient.put<Task>(`${this.url}/${task.taskId}`, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
completeTask(id: string): Observable<Task> {
|
||||||
|
return this.httpClient.post<Task>(`${this.url}/${id}/complete`, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
claimTask(id: string): Observable<Task> {
|
||||||
|
return this.httpClient.post<Task>(`${this.url}/${id}/claim`, 'test');
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelClaimTask(id: string): Observable<Task> {
|
||||||
|
return this.httpClient.delete<Task>(`${this.url}/${id}/claim`);
|
||||||
|
}
|
||||||
|
|
||||||
|
transferTask(taskId: string, workbasketId: string): Observable<Task> {
|
||||||
|
return this.httpClient.post<Task>(`${this.url}/${taskId}/transfer/${workbasketId}`, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTask(task: Task): Observable<Task> {
|
||||||
|
return this.httpClient.delete<Task>(`${this.url}/${task.taskId}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export class GetTasks {
|
||||||
|
static readonly type = '[TaskList] Get Tasks';
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GetTask {
|
||||||
|
static readonly type = '[TaskDetails] Get Task Details from Backend by its Id';
|
||||||
|
|
||||||
|
constructor(public taskId: string) {}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Selector } from '@ngxs/store';
|
||||||
|
import { Task, TaskSummary } from '@task/models/task';
|
||||||
|
import { TaskState, TaskStateModel } from './task.state';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TaskSelector {
|
||||||
|
@Selector([TaskState])
|
||||||
|
static tasks(state: TaskStateModel): TaskSummary[] {
|
||||||
|
return state.pagedTask.tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Selector([TaskState])
|
||||||
|
static selectedTask(state: TaskStateModel): Task | null {
|
||||||
|
return state.selectedTask;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Action, State, StateContext } from '@ngxs/store';
|
||||||
|
import { PagedTaskSummary } from '@task/models/paged-task';
|
||||||
|
import { TaskService } from '@task/services/task.service';
|
||||||
|
import { take, tap } from 'rxjs';
|
||||||
|
import { GetTask, GetTasks } from './task.actions';
|
||||||
|
import { Task } from '@task/models/task';
|
||||||
|
|
||||||
|
export interface TaskStateModel {
|
||||||
|
pagedTask: PagedTaskSummary | null;
|
||||||
|
selectedTask: Task | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaults: TaskStateModel = {
|
||||||
|
pagedTask: { tasks: [], page: {} },
|
||||||
|
selectedTask: null
|
||||||
|
};
|
||||||
|
|
||||||
|
@State<TaskStateModel>({
|
||||||
|
name: 'task',
|
||||||
|
defaults
|
||||||
|
})
|
||||||
|
@Injectable()
|
||||||
|
export class TaskState {
|
||||||
|
constructor(private taskService: TaskService) {}
|
||||||
|
|
||||||
|
@Action(GetTasks)
|
||||||
|
getTasks(ctx: StateContext<TaskStateModel>) {
|
||||||
|
return this.taskService.getTasks().pipe(
|
||||||
|
take(1),
|
||||||
|
tap((pagedTask) => {
|
||||||
|
ctx.patchState({ pagedTask });
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(GetTask)
|
||||||
|
getTask(ctx: StateContext<TaskStateModel>, { taskId }: GetTask) {
|
||||||
|
return this.taskService.getTask(taskId).pipe(
|
||||||
|
take(1),
|
||||||
|
tap((selectedTask) => {
|
||||||
|
ctx.patchState({ selectedTask });
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { TaskContainerComponent } from './components/task-container/task-container.component';
|
||||||
|
import { TaskDetailsContainerComponent } from './components/task-details-container/task-details-container.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: 'tasks',
|
||||||
|
component: TaskContainerComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'taskdetail/:id',
|
||||||
|
component: TaskDetailsContainerComponent
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirectTo: 'tasks',
|
||||||
|
pathMatch: 'full'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
redirectTo: 'tasks'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class TaskRoutingModule {}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { TaskRoutingModule } from './task-routing.module';
|
||||||
|
import { TaskListComponent } from './components/task-list/task-list.component';
|
||||||
|
import { SharedModule } from '@shared/shared.module';
|
||||||
|
import { TaskOverviewComponent } from './components/task-overview/task-overview.component';
|
||||||
|
import { TaskDetailsComponent } from './components/task-details/task-details.component';
|
||||||
|
import { TaskContainerComponent } from './components/task-container/task-container.component';
|
||||||
|
import { NgxsModule } from '@ngxs/store';
|
||||||
|
import { TaskState } from './store/task.state';
|
||||||
|
import { TaskDetailsContainerComponent } from './components/task-details-container/task-details-container.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
TaskListComponent,
|
||||||
|
TaskOverviewComponent,
|
||||||
|
TaskDetailsComponent,
|
||||||
|
TaskContainerComponent,
|
||||||
|
TaskDetailsContainerComponent
|
||||||
|
],
|
||||||
|
imports: [CommonModule, TaskRoutingModule, SharedModule, NgxsModule.forFeature([TaskState])]
|
||||||
|
})
|
||||||
|
export class TaskModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class WorkbasketRoutingModule {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { WorkbasketRoutingModule } from './workbasket-routing.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [CommonModule, WorkbasketRoutingModule]
|
||||||
|
})
|
||||||
|
export class WorkbasketModule {}
|
|
@ -10,8 +10,39 @@
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es5",
|
"target": "es2017",
|
||||||
"typeRoots": ["node_modules/@types"],
|
"typeRoots": [
|
||||||
"lib": ["es2018", "dom"]
|
"node_modules/@types"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2020",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@task/*": [
|
||||||
|
"app/v2/task/*"
|
||||||
|
],
|
||||||
|
"@shared/*": [
|
||||||
|
"app/v2/shared/*"
|
||||||
|
],
|
||||||
|
"@classification/*": [
|
||||||
|
"app/v2/classification/*"
|
||||||
|
],
|
||||||
|
"@history/*": [
|
||||||
|
"app/v2/history/*"
|
||||||
|
],
|
||||||
|
"@monitor/*": [
|
||||||
|
"app/v2/monitor/*"
|
||||||
|
],
|
||||||
|
"@shell/*": [
|
||||||
|
"app/v2/shell/*"
|
||||||
|
],
|
||||||
|
"@task-routing/*": [
|
||||||
|
"app/v2/task-routing/*"
|
||||||
|
],
|
||||||
|
"@workbasket/*": [
|
||||||
|
"app/v2/workbasket/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
855
web/yarn.lock
855
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue