With the core services and components in place, we'll now interface with the ProcessMaker API.
Completed code: live example / download example
Ensure you have the subsequent details ready for this section:
Client ID
Client Secret
FQDN for your ProcessMaker installation
OAuth Token URL
OAuth Redirect URI
OAuth Authorization URL
You can see what a sample environment.ts
file looks like below. This is where you will add the above information.
environment.ts
export const environment = {
production: false,
apiDomain: 'localhost',
apiPath: '/api/1.0',
apiProtocol: 'http://',
clientId: '19',
clientSecret: 'Psn9cxcGFKO1GO4ZZ9TgOhQtAjt0Wmzjc58vw8Lq',
oauthUrl: 'http://localhost/oauth/token',
redirectUri: 'http://localhost:4200/#/oauth/callback',
oauthAuthorizeUrl: 'http://localhost/oauth/authorize',
customCss: false,
calcProps: true,
};
The TasksComponent
relies on the ScreenComponent
, which we'll address in the subsequent section. We'll omit it for now and reintroduce it when we're set to render the form.
app-tasks.component.html
<div class="container-fluid">
<div class="table-container mt-4">
<div class="mb-2">
<h2>Your pending tasks</h2>
<h5 class="text-secondary">View your assigned tasks.</h5>
</div>
<table id="mytable" class="table align-middle mb-0 bg-white">
<thead class="bg-light">
<tr class="header-row">
<th>ID #</th>
<th>Task Name</th>
<th>Status</th>
<th>Assignee</th>
<th>Process</th>
<th>Due</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngIf="!userTasks.length">
<td colspan="6">
<p>Loading...</p>
</td>
</tr>
<tr *ngFor="let task of userTasks">
<td>
<p class="fw-bold fw-normal mb-1">{{ task.process_request_id }}</p>
</td>
<td>
<p class="fw-bold fw-normal mb-1">{{ task.element_name }}</p>
</td>
<td>
<div [ngSwitch]="task.advanceStatus">
<span
*ngSwitchCase="'overdue'"
class="badge badge-danger rounded-pill d-inline"
style="text-transform: capitalize"
>{{ task.advanceStatus }}</span
>
<span
*ngSwitchCase="'completed'"
class="badge badge-primary rounded-pill d-inline"
style="text-transform: capitalize"
>{{ task.advanceStatus }}</span
>
<span
*ngSwitchCase="'open'"
class="badge badge-success rounded-pill d-inline"
style="text-transform: capitalize"
>{{ task.advanceStatus }}</span
>
</div>
</td>
<td>{{ task.user.firstname }} {{ task.user.lastname }}</td>
<td>{{ task.process_request.name }}</td>
<td>
<div>
<span>{{ task.due_at }}</span>
</div>
</td>
<td>
<button
(click)="openScreen(task.process_request_id, task.id)"
type="button"
class="btn btn-link btn-sm btn-rounded text-primary">
<i class="me-1 bi-window-sidebar text-primary"></i>
View Task
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
app-tasks.component.ts
// Import necessary Angular core modules
import { Component, OnInit } from '@angular/core';
// Import Angular routing modules
import { ActivatedRoute, Router } from '@angular/router';
// Import services related to ProcessRequests and Tasks
import { ProcessRequestsService, TasksService } from 'api';
// Import local database service
import { DbService } from 'src/app/services/db.service';
// Define the Task interface to represent the structure of a task
interface Task {
process_request_id: string; // ID of the associated process request
element_name: string; // Name of the element
advanceStatus: string; // Status of the task advancement
user: { firstname: string; lastname: string }; // User information
process_request: { name: string }; // Process request information
due_at: string; // Due date for the task
id: string; // Unique ID for the task
}
// Component metadata
@Component({
selector: 'app-tasks', // Selector used in templates
templateUrl: './app-tasks.component.html', // Path to the HTML template
})
// TasksComponent class definition
export class TasksComponent implements OnInit {
// Pagination properties
pagination = {
currentPage: 1, // Current page number
itemsPerPage: 10, // Number of items per page
lastPage: null, // Last page number
totalItems: null, // Total number of items
};
// Selected request and task properties
selectedRequest: Request | null = null;
selectedTask: Task | null = null;
userTasks: Task[] = []; // Array to hold user tasks
color = 'green'; // Color property (usage not shown in provided code)
// Constructor with dependency injection
constructor(
private requestApi: ProcessRequestsService, // Process request service
private tasksApi: TasksService, // Task service
private route: ActivatedRoute, // Activated route information
private router: Router, // Router service for navigation
private db: DbService // Database service
) {}
// ngOnInit lifecycle hook
ngOnInit() {
// Load access token from the database
const accessToken = this.db.load('access_token') as string | undefined;
// If access token exists, set it in the task API configuration
if (accessToken) {
this.tasksApi.configuration.credentials['pm_api_bearer'] = accessToken;
}
// Call getTasks method from tasksApi with parameters null and 'ACTIVE'
this.tasksApi.getTasks(undefined, 'ACTIVE').subscribe(
(response: any) => {
// Handle successful response
this.userTasks = response.data; // Assign user tasks from response data
// Create a new ScreenComponent instance
console.log(this.userTasks);
},
(error) => {
// Handle error response
console.log(error); // Log the error to the console
}
);
}
// Method to open a form with given processRequestId and taskId
openScreen(processRequestId: string, taskId: string) {
// Navigate to the 'form' route with parameters
this.router.navigate([
'screen',
{
processRequestId: processRequestId,
taskId: taskId,
},
]);
}
// Placeholder method for getting a user task by ID
getUserTask(id: string) {}
// Placeholder method for getting user tasks by ID
getUserTasks(id: string) {}
}
Integrate the new components and their respective paths into the router. The following code demonstrates how to import these components and establish a route for the inbox view.
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from '../components/login/login.component';
import { TasksComponent } from '../components/tasks/app-tasks.component';
import { AuthGuard } from '../guards/auth.guard';
const routes: Routes = [
{
path: 'login',
component: LoginComponent,
runGuardsAndResolvers: 'always',
title: 'Login',
},
{
path: 'oauth/callback',
component: LoginComponent,
runGuardsAndResolvers: 'always',
},
{
path: 'tasks',
component: TasksComponent,
canActivate: [AuthGuard],
runGuardsAndResolvers: 'always',
title: 'Inbox',
},
{
path: '',
redirectTo: 'tasks',
pathMatch: 'full',
runGuardsAndResolvers: 'always',
},
{
path: '**',
redirectTo: 'tasks',
runGuardsAndResolvers: 'always',
},
];
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule],
})
export class AppRoutingModule {}
Now we just need to incorporate the TasksComponent
into the AppModule
declaration.
app.module.ts
import { NgModule } from '@angular/core';
import '@angular/compiler';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { AppRoutingModule } from './routing/app-routing.module';
import { RootComponent } from './components/root/app-root.component';
import { LoginComponent } from './components/login/login.component';
import { NavigationComponent } from './components/nav/navigation.component';
import { AppBreadcrumbsComponent } from './components/breadcrumbs/app-breadcrumbs.component';
import { TasksComponent } from './components/tasks/app-tasks.component';
@NgModule({
declarations: [
RootComponent,
LoginComponent,
NavigationComponent,
AppBreadcrumbsComponent,
TasksComponent,
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
CommonModule,
AppRoutingModule,
],
providers: [],
bootstrap: [RootComponent],
})
export class AppModule {}
If you are following along with the tutorial, you should now be able to see your tasks, in your new Angular Inbox!