Part 4: The Inbox

Overview

With the core services and components in place, we'll now interface with the ProcessMaker API.

Completed code: live example / download example

Step 1: Environment Details

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

Step 2: TasksComponent

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.

Template

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>

Typescript

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

Step 3: Update the Router

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

Step 4: Update AppModule

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

Review

If you are following along with the tutorial, you should now be able to see your tasks, in your new Angular Inbox!

Next Steps

pagePart 5: The Screen & Form Elements

Last updated