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:
Kaan Holat 2022-04-28 14:08:44 +02:00 committed by Mustapha Zorgati
parent a8f7f5e96a
commit 8f38f82ee2
58 changed files with 1214 additions and 444 deletions

View File

@ -11,6 +11,7 @@
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"allowedCommonJsDependencies": ["chart.js"],
"aot": true,
"sourceMap": {
"scripts": true

View File

@ -14,6 +14,6 @@ module.exports = {
// coverageReporters: ['html', 'text'],
coverageDirectory: 'coverage/taskana-web',
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths || {}, {
prefix: '<rootDir>/'
prefix: `<rootDir>/${compilerOptions.baseUrl}/`
})
};

View File

@ -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",

View File

@ -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)
}
]
},

View File

@ -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
];

View File

@ -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();
});
});

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -0,0 +1,8 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [CommonModule]
})
export class SharedModule {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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({

View File

@ -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({

View File

@ -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;

View File

@ -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'

View File

@ -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 = [
{

View File

@ -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({

View File

@ -0,0 +1,4 @@
<div class="task-list-container">
<taskana-task-list></taskana-task-list>
<router-outlet></router-outlet>
</div>

View File

@ -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;
}

View File

@ -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();
});
});

View File

@ -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();
}
}

View File

@ -0,0 +1,2 @@
<p>TASK DETAILS CONTAINER</p>
<taskana-task-details></taskana-task-details>

View File

@ -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();
});
});

View File

@ -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);
});
}
}

View File

@ -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>

View File

@ -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();
});
});

View File

@ -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 {}
}

View File

@ -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>

View File

@ -0,0 +1,3 @@
.task--selected {
color: blue;
}

View File

@ -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();
});
});

View File

@ -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;
}
}

View File

@ -0,0 +1 @@
<p>task-overview works!</p>

View File

@ -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();
});
});

View File

@ -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 {}
}

View File

@ -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 */;
}

View File

@ -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[];
}

View File

@ -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();
});
});

View File

@ -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
*/
}

View File

@ -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();
});
});

View File

@ -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}`);
}
}

View File

@ -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) {}
}

View File

@ -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;
}
}

View File

@ -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 });
})
);
}
}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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 {}

View File

@ -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/*"
]
}
}
}

File diff suppressed because it is too large Load Diff