Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
33ebad6
feat: add saved_search_advanced_configuration to filesystem configura…
devmiguelangel Sep 10, 2025
9c3618e
Merge pull request #8514 from ProcessMaker/FOUR-26188
caleeli Sep 11, 2025
2ae98d8
Merge branch 'develop' into feature/FOUR-26166
devmiguelangel Sep 16, 2025
bf587d1
Add job validation and new scheduling method `scheduleDateJob`
caleeli Sep 16, 2025
ce8757c
Merge pull request #8528 from ProcessMaker/FOUR-26192
caleeli Sep 16, 2025
5546f2a
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166
caleeli Sep 18, 2025
5c3e708
Merge branch 'develop' into feature/FOUR-26166
devmiguelangel Oct 2, 2025
818399b
Merge branch 'develop' into feature/FOUR-26166
devmiguelangel Oct 7, 2025
7e03f40
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166-b
caleeli Apr 28, 2026
b6d3d52
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166-b
Apr 30, 2026
2b3db57
feat: update configuration structure for scheduled jobs
May 6, 2026
841421e
Merge pull request #8812 from ProcessMaker/FOUR-26194
caleeli May 8, 2026
93cae59
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166-b
caleeli May 20, 2026
58d774f
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166-b
caleeli May 26, 2026
46dd5a3
Merge remote-tracking branch 'origin/develop' into feature/FOUR-26166-b
caleeli Jun 1, 2026
8d15b57
Update dependency
nolanpro Jun 10, 2026
1444838
Version 2026.9.4-RC1
nolanpro Jun 10, 2026
e04999c
feat: implement ETag middleware for Tasks page caching
devmiguelangel Jun 10, 2026
f6f6d04
feat: update inbox and tasks routes to use ETag middleware for improv…
devmiguelangel Jun 10, 2026
df83b96
feat: enhance BrowserCache middleware to return response if ETag head…
devmiguelangel Jun 10, 2026
7576098
test: add ETag handling tests for Tasks page to ensure proper caching…
devmiguelangel Jun 10, 2026
8b3959f
feat: optimize TasksPageEtag for permission handling and user configu…
devmiguelangel Jun 11, 2026
6da1dec
fix: update inbox route to use no-cache middleware for improved respo…
devmiguelangel Jun 11, 2026
127f020
docs: add Tasks Page ETag Sequence documentation
devmiguelangel Jun 11, 2026
fda4b93
Merge pull request #8863 from ProcessMaker/feature/FOUR-31736
caleeli Jun 12, 2026
8e368ab
Merge remote-tracking branch 'origin/develop' into feature/FOUR-30918
devmiguelangel Jun 18, 2026
5c9d5b6
feat: add api client caching functionality
devmiguelangel Jun 18, 2026
913769f
feat: add debug logging to api client cache for improved diagnostics
devmiguelangel Jun 18, 2026
6cf268b
feat(FOUR-31831): review Improve Task page loading
rodriquelca Jun 19, 2026
b986b4b
fix: code style
rodriquelca Jun 19, 2026
9eb2fa3
feat(FOUR-31695): add support for Laravel Octane in core
rodriquelca Jun 19, 2026
359fcc9
feat: enhance api client cache with additional utility functions and …
devmiguelangel Jun 19, 2026
48d1b21
feat: return original request in api client cache to maintain promise…
devmiguelangel Jun 19, 2026
5c222b6
test: add comprehensive tests for api client cache functionality
devmiguelangel Jun 19, 2026
85a1a25
Adding indexOptimized method to taskController api-1.1
AugustoLopezProcess Jun 19, 2026
7c3e722
Adding optimization parameter to nonSystem
AugustoLopezProcess Jun 19, 2026
28faf03
Adding taskOptimized route to api.php v1.1
AugustoLopezProcess Jun 19, 2026
2264b6b
Adding indexOptimizedBaseQuery method
AugustoLopezProcess Jun 19, 2026
5f0485a
Merge pull request #8877 from ProcessMaker/FOUR-31921
caleeli Jun 23, 2026
2d02f75
Merge pull request #8875 from ProcessMaker/feature/FOUR-31831
caleeli Jun 23, 2026
e751416
Merge pull request #8876 from ProcessMaker/laravel_octane_C
caleeli Jun 23, 2026
b01d2e3
Merge remote-tracking branch 'origin/develop' into feature/FOUR-30918
devmiguelangel Jun 23, 2026
da7445e
Adding config value from env, to activate the optimized endpoint on 1.1
AugustoLopezProcess Jun 23, 2026
5a5013f
fix merge conflicts
rodriquelca Jun 25, 2026
8c5f71f
Merge pull request #8884 from ProcessMaker/feature/FOUR-31979
caleeli Jun 25, 2026
d0b19cf
feat(FOUR-32024): review and fix the calculation of DB timing when lo…
rodriquelca Jun 26, 2026
a419c75
fix merge conflicts
rodriquelca Jun 26, 2026
c2eb21d
Merge remote-tracking branch 'origin/develop' into feature/FOUR-30918
devmiguelangel Jun 29, 2026
fccb869
Merge pull request #8881 from ProcessMaker/feature/FOUR-31892
caleeli Jun 30, 2026
d0ea1fa
Merge pull request #8885 from ProcessMaker/feature/FOUR-32024
caleeli Jun 30, 2026
80e42d3
feat: fix sonarqube notes
rodriquelca Jul 2, 2026
e95cb23
chore: update package dependencies for screen-builder and vue-form-el…
devmiguelangel Jul 6, 2026
d00fb84
Merge remote-tracking branch 'origin/develop' into feature/FOUR-30918
devmiguelangel Jul 6, 2026
8bf7e1f
chore: update @processmaker/vue-form-elements dependency to version v…
devmiguelangel Jul 6, 2026
e21f0ad
Update JS dependencies
nolanpro Jul 7, 2026
a855647
Version 2026.12.0-performance.2
nolanpro Jul 7, 2026
f163d5a
chore: update version format in composer.json to 2026.12.0+performance.2
devmiguelangel Jul 7, 2026
c04b68f
Merge remote-tracking branch 'origin/develop' into feature/FOUR-30918
devmiguelangel Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ storage/ssl
storage/api/*
storage/data-sources/logs/*
storage/decision-tables/*
storage/saved_search_advanced_configuration/*
npm.sh
laravel-echo-server.lock
public/.htaccess
Expand All @@ -51,4 +52,7 @@ devhub/pm-font/dist
test-db-snapshot.db
snapshot_*.db
storage/transitions
.envrc
.envrc
**/caddy
frankenphp
frankenphp-worker.php
4 changes: 4 additions & 0 deletions ProcessMaker/Http/Controllers/Api/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ProcessMaker\Events\ActivityReassignment;
use ProcessMaker\Facades\WorkflowManager;
use ProcessMaker\Filters\Filter;
use ProcessMaker\Http\Controllers\Api\V1_1\TaskController as V1_1TaskController;
use ProcessMaker\Http\Controllers\Controller;
use ProcessMaker\Http\Resources\ApiResource;
use ProcessMaker\Http\Resources\Task as Resource;
Expand Down Expand Up @@ -126,6 +127,9 @@ class TaskController extends Controller
*/
public function index(Request $request, $getTotal = false, User $user = null)
{
if (config('app.processmaker_optimized_tasks_enabled')) {
return (new V1_1TaskController())->indexOptimized($request, $getTotal, $user);
}
// If a specific user is specified, use it; otherwise use the authorized user
// This is necessary to produce accurate counts for Saved Searches
if (!$user) {
Expand Down
82 changes: 82 additions & 0 deletions ProcessMaker/Http/Controllers/Api/V1_1/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,33 @@

namespace ProcessMaker\Http\Controllers\Api\V1_1;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use ProcessMaker\Cache\Screens\ScreenCacheFactory;
use ProcessMaker\Http\Controllers\Controller;
use ProcessMaker\Http\Resources\TaskCollection;
use ProcessMaker\Http\Resources\V1_1\TaskInterstitialResource;
use ProcessMaker\Http\Resources\V1_1\TaskResource;
use ProcessMaker\Http\Resources\V1_1\TaskScreen;
use ProcessMaker\Models\ProcessRequest;
use ProcessMaker\Models\ProcessRequestToken;
use ProcessMaker\Models\User;
use ProcessMaker\ProcessTranslations\TranslationManager;
use ProcessMaker\Traits\TaskControllerIndexMethods;

class TaskController extends Controller
{
use TaskControllerIndexMethods;

public $doNotSanitize = [
'data',
'pmql',
];

protected $defaultFields = [
'id',
'element_id',
Expand All @@ -29,6 +42,56 @@ class TaskController extends Controller
'process_request_id',
];

public function indexOptimized(Request $request, $getTotal = false, ?User $user = null)
{
if (!$user) {
$user = Auth::user();
}

$request->merge(['optimized' => true]);

$query = $this->indexOptimizedBaseQuery($request);
$this->applyIndexFieldSelection($query, $request);
$this->applyFilters($query, $request);
$this->excludeNonVisibleTasks($query, $request);
$this->applyColumnOrdering($query, $request);
$this->applyStatusFilter($query, $request);

if ($request->input('processesIManage') === 'true') {
$this->applyProcessManager($query, $user, $request);
} else {
$this->applyForCurrentUser($query, $user);
}

$this->applyPmql($query, $request, $user);
$this->applyAdvancedFilter($query, $request);
$query->overdue($request->input('overdue'));

if ($getTotal === true) {
return $query->count();
}

try {
$response = $query->paginate($request->input('per_page', 10));
} catch (QueryException $e) {
return $this->handleQueryException($e);
}

$response = $this->applyUserFilter($response, $request, $user);

if ($response->total() > 0 && $request->input('processesIManage') === 'true') {
$this->enableUserManager($user);
}

$inOverdueQuery = ProcessRequestToken::query()
->whereIn('id', $response->pluck('id'))
->where('due_at', '<', Carbon::now());

$response->inOverdue = $inOverdueQuery->count();

return new TaskCollection($response);
}

/**
* Display a listing of the resource.
*/
Expand Down Expand Up @@ -151,4 +214,23 @@ public function showInterstitial($taskId)

return $response;
}

private function handleQueryException(QueryException $e)
{
$regex = '~Column not found: 1054 Unknown column \'(.*?)\' in \'where clause\'~';

preg_match($regex, $e->getMessage(), $m);

$message = __('PMQL Is Invalid.');

if (count($m) > 1) {
$message .= ' ' . __('Column not found: ') . '"' . $m[1] . '"';
}

\Log::error($e->getMessage());

return response([
'message' => $message,
], 422);
}
}
24 changes: 16 additions & 8 deletions ProcessMaker/Http/Controllers/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,16 @@ public function edit(ProcessRequestToken $task, string $preview = '')
{
$task = $task->loadTokenInstance();
$dataManager = new DataManager();
$userHasComments = Comment::where('commentable_type', ProcessRequestToken::class)
->where('commentable_id', $task->id)
->where('body', 'like', '%{{' . \Auth::user()->id . '}}%')
->count() > 0;

if (!\Auth::user()->can('update', $task) && !$userHasComments) {
$this->authorize('update', $task);
if (!\Auth::user()->can('update', $task)) {
$userHasComments = Comment::where('commentable_type', ProcessRequestToken::class)
->where('commentable_id', $task->id)
->where('body', 'like', '%{{' . \Auth::user()->id . '}}%')
->count() > 0;

if (!$userHasComments) {
$this->authorize('update', $task);
}
}

//Mark notification as read
Expand Down Expand Up @@ -178,7 +181,9 @@ public function edit(ProcessRequestToken $task, string $preview = '')
]);
}

UserResourceView::setViewed(Auth::user(), $task);
dispatch(function () use ($task) {
UserResourceView::setViewed(Auth::user(), $task);
})->afterResponse();
$currentUser = Auth::user()->only([
'id',
'username',
Expand All @@ -189,7 +194,8 @@ public function edit(ProcessRequestToken $task, string $preview = '')
'timezone',
'datetime_format',
]);
$userConfiguration = (new UserConfigurationController())->index();
//$userConfiguration = (new UserConfigurationController())->index();
$userConfiguration = app(UserConfigurationController::class)->index();
$hitlEnabled = config('smart-extract.hitl_enabled', false) && $isSmartExtractTask;

// Build the iframe source
Expand All @@ -209,9 +215,11 @@ public function edit(ProcessRequestToken $task, string $preview = '')
$iframeSrc = $dashboardUrl . '?' . $queryParams;
}
}
$canUpdateTask = Auth::user()->can('update', $task);

return view('tasks.edit', [
'task' => $task,
'canUpdateTask' => $canUpdateTask,
'dueLabels' => self::$dueLabels,
'manager' => $manager,
'submitUrl' => $submitUrl,
Expand Down
4 changes: 4 additions & 0 deletions ProcessMaker/Http/Middleware/BrowserCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public function handle($request, Closure $next)
return $response;
}

if ($response->headers->has('ETag')) {
return $response;
}

$response->header('pragma', 'no-cache');
$response->header('Cache-Control', 'no-store');

Expand Down
77 changes: 77 additions & 0 deletions ProcessMaker/Http/Middleware/Etag/TasksPageEtag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace ProcessMaker\Http\Middleware\Etag;

use Closure;
use Illuminate\Http\Request;
use ProcessMaker\Http\Resources\Caching\TasksPageEtag as TasksPageEtagResource;
use Symfony\Component\HttpFoundation\Response;

class TasksPageEtag
{
public function __construct(
private TasksPageEtagResource $tasksPageEtag
) {
}

/**
* Handle Tasks page validation before rendering the full page shell.
*
* The ETag is computed from stable page context before controller execution, so a
* matching conditional request can return 304 without paying the render cost.
*/
public function handle(Request $request, Closure $next): Response
{
if (!config('etag.enabled') || (!$request->isMethod('GET') && !$request->isMethod('HEAD'))) {
return $next($request);
}

$etag = $this->tasksPageEtag->getEtag($request);

if ($this->buildResponseWithEtag($etag)->isNotModified($request)) {
return $this->withPrivateCacheHeaders($this->buildNotModifiedResponse($etag, $request));
}

$response = $next($request);
$response->setEtag($etag);

return $this->withPrivateCacheHeaders($response);
}

/**
* Build a framework-compatible 304 response for a matched Tasks page ETag.
*/
private function buildNotModifiedResponse(string $etag, Request $request): Response
{
$response = $this->buildResponseWithEtag($etag);
$response->isNotModified($request);

return $response;
}

/**
* Create a response carrying the Tasks page validator.
*
* Weak ETags are used because the HTML may be transformed by gzip while the
* rendered representation remains equivalent for browser revalidation.
*/
private function buildResponseWithEtag(string $etag): Response
{
$response = new Response();
$response->setEtag($etag, true);

return $response;
}

/**
* Apply browser-cache headers that allow private conditional revalidation.
*/
private function withPrivateCacheHeaders(Response $response): Response
{
$response->headers->set('Cache-Control', 'private, must-revalidate');
$response->headers->remove('Pragma');
$response->headers->remove('Expires');

return $response;
}
}
2 changes: 2 additions & 0 deletions ProcessMaker/Http/Middleware/ServerTimingMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public function handle(Request $request, Closure $next): Response
return $next($request);
}

ProcessMakerServiceProvider::beginRequestTiming();

// Start time for controller execution
$startController = microtime(true);

Expand Down
Loading
Loading