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": {
|
||||
"builder": "@angular-builders/custom-webpack:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": ["chart.js"],
|
||||
"aot": true,
|
||||
"sourceMap": {
|
||||
"scripts": true
|
||||
|
|
|
@ -14,6 +14,6 @@ module.exports = {
|
|||
// coverageReporters: ['html', 'text'],
|
||||
coverageDirectory: 'coverage/taskana-web',
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
|
||||
prefix: '<rootDir>/'
|
||||
prefix: `<rootDir>/${compilerOptions.baseUrl}/`
|
||||
})
|
||||
};
|
||||
|
|
|
@ -22,18 +22,19 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "13.3.1",
|
||||
"@angular/cdk": "13.3.2",
|
||||
"@angular/common": "13.3.1",
|
||||
"@angular/core": "13.3.1",
|
||||
"@angular/forms": "13.3.1",
|
||||
"@angular/material": "13.3.2",
|
||||
"@angular/platform-browser": "13.3.1",
|
||||
"@angular/platform-browser-dynamic": "13.3.1",
|
||||
"@angular/router": "13.3.1",
|
||||
"@angular/animations": "13.3.4",
|
||||
"@angular/cdk": "13.3.4",
|
||||
"@angular/common": "13.3.4",
|
||||
"@angular/core": "13.3.4",
|
||||
"@angular/forms": "13.3.4",
|
||||
"@angular/material": "13.3.4",
|
||||
"@angular/platform-browser": "13.3.4",
|
||||
"@angular/platform-browser-dynamic": "13.3.4",
|
||||
"@angular/router": "13.3.4",
|
||||
"@circlon/angular-tree-component": "11.0.4",
|
||||
"@ngneat/hot-toast": "4.1.0",
|
||||
"@ngneat/overview": "3.0.4",
|
||||
"@ngxs/router-plugin": "3.7.3",
|
||||
"@ngxs/store": "3.7.3",
|
||||
"angular-svg-icon": "13.0.0",
|
||||
"chart.js": "2.9.4",
|
||||
|
@ -49,10 +50,10 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/custom-webpack": "13.1.0",
|
||||
"@angular-devkit/build-angular": "13.3.1",
|
||||
"@angular/cli": "13.3.1",
|
||||
"@angular/compiler": "13.3.1",
|
||||
"@angular/compiler-cli": "13.3.1",
|
||||
"@angular-devkit/build-angular": "13.3.3",
|
||||
"@angular/cli": "13.3.3",
|
||||
"@angular/compiler": "13.3.4",
|
||||
"@angular/compiler-cli": "13.3.4",
|
||||
"@ngxs/devtools-plugin": "3.7.3",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/lodash": "4.14.181",
|
||||
|
|
|
@ -69,7 +69,7 @@ const routes: Routes = [
|
|||
{
|
||||
path: 'task-routing',
|
||||
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 { environment } from '../environments/environment';
|
||||
import { STATES } from './shared/store';
|
||||
import { NgxsRouterPluginModule } from '@ngxs/router-plugin';
|
||||
|
||||
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];
|
||||
|
||||
|
@ -87,6 +88,7 @@ const MODULES = [
|
|||
MatProgressSpinnerModule,
|
||||
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
|
||||
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }),
|
||||
NgxsRouterPluginModule.forRoot(),
|
||||
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 { RoutingUploadService } from '../routing-upload.service';
|
||||
import { NotificationService } from '../../shared/services/notifications/notification.service';
|
||||
import { RoutingUploadService } from '@task-routing/services/routing-upload.service';
|
||||
import { NotificationService } from 'app/shared/services/notifications/notification.service';
|
||||
import { HotToastService } from '@ngneat/hot-toast';
|
||||
|
||||
@Component({
|
|
@ -1,7 +1,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
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';
|
||||
|
||||
@Injectable({
|
|
@ -2,9 +2,9 @@ import { TestBed } from '@angular/core/testing';
|
|||
|
||||
import { RoutingUploadService } from './routing-upload.service';
|
||||
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 { StartupService } from 'app/shared/services/startup/startup.service';
|
||||
import { TaskanaEngineService } from 'app/shared/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from 'app/shared/services/window/window.service';
|
||||
|
||||
describe('RoutingUploadService', () => {
|
||||
let service: RoutingUploadService;
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
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({
|
||||
providedIn: 'root'
|
|
@ -1,7 +1,7 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { RoutingUploadComponent } from './routing-upload/routing-upload.component';
|
||||
import { TaskRoutingGuard } from '../shared/guards/task-routing.guard';
|
||||
import { RoutingUploadComponent } from './components/routing-upload/routing-upload.component';
|
||||
import { TaskRoutingGuard } from './guards/task-routing.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
|
@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
|
|||
import { CommonModule } from '@angular/common';
|
||||
|
||||
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';
|
||||
|
||||
@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",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"lib": ["es2018", "dom"]
|
||||
"target": "es2017",
|
||||
"typeRoots": [
|
||||
"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