From a49554193a28c91cba7870cddbb49acb3838233b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Agust=C3=ADn=20Busso?=
<90727999+agustinbusso@users.noreply.github.com>
Date: Wed, 7 Jan 2026 11:18:19 -0300
Subject: [PATCH 1/5] Move logs logic from email start event package. Add base
logs ui for Agents
---
.../Http/Controllers/Admin/LogsController.php | 20 ++
.../Http/Middleware/GenerateMenus.php | 8 +
.../components/Logs/BaseTable/BaseTable.vue | 61 ++++++
.../logs/components/Logs/BaseTable/index.js | 3 +
.../components/Logs/HeaderBar/HeaderBar.vue | 122 ++++++++++++
.../logs/components/Logs/HeaderBar/index.js | 3 +
.../Logs/LogContainer/LogContainer.vue | 104 +++++++++++
.../components/Logs/LogContainer/index.js | 3 +
.../components/Logs/LogTable/LogTable.vue | 176 ++++++++++++++++++
.../logs/components/Logs/LogTable/index.js | 3 +
.../components/Logs/Pagination/Pagination.vue | 89 +++++++++
.../logs/components/Logs/Pagination/index.js | 3 +
.../logs/components/Logs/Sidebar/Sidebar.vue | 173 +++++++++++++++++
.../logs/components/Logs/Sidebar/index.js | 3 +
.../js/admin/logs/components/Logs/routes.js | 41 ++++
resources/js/admin/logs/index.js | 26 +++
resources/js/admin/logs/utils/date.js | 74 ++++++++
resources/views/admin/logs/index.blade.php | 28 +++
routes/web.php | 7 +
webpack.mix.js | 1 +
20 files changed, 948 insertions(+)
create mode 100644 ProcessMaker/Http/Controllers/Admin/LogsController.php
create mode 100644 resources/js/admin/logs/components/Logs/BaseTable/BaseTable.vue
create mode 100644 resources/js/admin/logs/components/Logs/BaseTable/index.js
create mode 100644 resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
create mode 100644 resources/js/admin/logs/components/Logs/HeaderBar/index.js
create mode 100644 resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
create mode 100644 resources/js/admin/logs/components/Logs/LogContainer/index.js
create mode 100644 resources/js/admin/logs/components/Logs/LogTable/LogTable.vue
create mode 100644 resources/js/admin/logs/components/Logs/LogTable/index.js
create mode 100644 resources/js/admin/logs/components/Logs/Pagination/Pagination.vue
create mode 100644 resources/js/admin/logs/components/Logs/Pagination/index.js
create mode 100644 resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
create mode 100644 resources/js/admin/logs/components/Logs/Sidebar/index.js
create mode 100644 resources/js/admin/logs/components/Logs/routes.js
create mode 100644 resources/js/admin/logs/index.js
create mode 100644 resources/js/admin/logs/utils/date.js
create mode 100644 resources/views/admin/logs/index.blade.php
diff --git a/ProcessMaker/Http/Controllers/Admin/LogsController.php b/ProcessMaker/Http/Controllers/Admin/LogsController.php
new file mode 100644
index 0000000000..37ef170c8c
--- /dev/null
+++ b/ProcessMaker/Http/Controllers/Admin/LogsController.php
@@ -0,0 +1,20 @@
+ "data:image/svg+xml;base64,{$devlinkIcon}",
]);
}
+ if (\Auth::user()->canAny('view-settings|edit-settings') &&
+ (hasPackage('package-email-start-event') || hasPackage('package-ai'))) {
+ $submenu->add(__('Logs'), [
+ 'route' => 'admin.logs',
+ 'icon' => 'fa-bars',
+ 'id' => 'admin-logs',
+ ]);
+ }
});
Menu::make('sidebar_task', function ($menu) {
$submenu = $menu->add(__('Tasks'));
diff --git a/resources/js/admin/logs/components/Logs/BaseTable/BaseTable.vue b/resources/js/admin/logs/components/Logs/BaseTable/BaseTable.vue
new file mode 100644
index 0000000000..120ae42de4
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/BaseTable/BaseTable.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+ |
+ {{ column.label }}
+ |
+
+
+
+
+ |
+ {{ getItemValue(item, column) }}
+ |
+
+
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/BaseTable/index.js b/resources/js/admin/logs/components/Logs/BaseTable/index.js
new file mode 100644
index 0000000000..f8430fb194
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/BaseTable/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as BaseTable } from './BaseTable.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue b/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
new file mode 100644
index 0000000000..d33b721828
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
@@ -0,0 +1,122 @@
+
+
+
+
+
+ Error Logs
+
+
+ Matched Logs
+
+
+ Total Logs
+
+
+
+
+
+
+ Design Mode Logs
+
+
+ Execution Logs
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/HeaderBar/index.js b/resources/js/admin/logs/components/Logs/HeaderBar/index.js
new file mode 100644
index 0000000000..c2176bf01c
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/HeaderBar/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as HeaderBar } from './HeaderBar.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue b/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
new file mode 100644
index 0000000000..1fd434353c
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/LogContainer/index.js b/resources/js/admin/logs/components/Logs/LogContainer/index.js
new file mode 100644
index 0000000000..d0ad929b7e
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/LogContainer/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as LogContainer } from './LogContainer.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/LogTable/LogTable.vue b/resources/js/admin/logs/components/Logs/LogTable/LogTable.vue
new file mode 100644
index 0000000000..dc688bbbd7
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/LogTable/LogTable.vue
@@ -0,0 +1,176 @@
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/LogTable/index.js b/resources/js/admin/logs/components/Logs/LogTable/index.js
new file mode 100644
index 0000000000..d07b1072e7
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/LogTable/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as LogTable } from './LogTable.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/Pagination/Pagination.vue b/resources/js/admin/logs/components/Logs/Pagination/Pagination.vue
new file mode 100644
index 0000000000..33b47377b4
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/Pagination/Pagination.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/Pagination/index.js b/resources/js/admin/logs/components/Logs/Pagination/index.js
new file mode 100644
index 0000000000..d2d0ae6aa6
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/Pagination/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as Pagination } from './Pagination.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
new file mode 100644
index 0000000000..b47e9561f2
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
@@ -0,0 +1,173 @@
+
+
+
+
+
+
diff --git a/resources/js/admin/logs/components/Logs/Sidebar/index.js b/resources/js/admin/logs/components/Logs/Sidebar/index.js
new file mode 100644
index 0000000000..a4f8b5ce94
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/Sidebar/index.js
@@ -0,0 +1,3 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as Sidebar } from './Sidebar.vue';
+
diff --git a/resources/js/admin/logs/components/Logs/routes.js b/resources/js/admin/logs/components/Logs/routes.js
new file mode 100644
index 0000000000..cee148dcc5
--- /dev/null
+++ b/resources/js/admin/logs/components/Logs/routes.js
@@ -0,0 +1,41 @@
+import { LogTable } from './LogTable';
+
+export default {};
+
+export const routes = [
+ {
+ name: 'logs.index',
+ path: '/',
+ redirect: '/email/errors',
+ },
+ // Email logs routes
+ {
+ name: 'logs.email',
+ path: '/email/:logType',
+ component: LogTable,
+ props(route) {
+ return {
+ category: 'email',
+ logType: route.params.logType,
+ };
+ },
+ },
+ // FlowGenie Agents logs routes
+ {
+ name: 'logs.agents.redirect',
+ path: '/agents',
+ redirect: '/agents/design',
+ },
+ {
+ name: 'logs.agents',
+ path: '/agents/:logType',
+ component: LogTable,
+ props(route) {
+ return {
+ category: 'agents',
+ logType: route.params.logType,
+ };
+ },
+ },
+];
+
diff --git a/resources/js/admin/logs/index.js b/resources/js/admin/logs/index.js
new file mode 100644
index 0000000000..bdf9dc220b
--- /dev/null
+++ b/resources/js/admin/logs/index.js
@@ -0,0 +1,26 @@
+import { LogContainer } from './components/Logs/LogContainer';
+import { routes } from './components/Logs/routes';
+
+// eslint-disable-next-line no-undef
+Vue.use(VueRouter);
+
+// eslint-disable-next-line no-undef
+const router = new VueRouter({
+ mode: 'history',
+ base: '/admin/logs',
+ routes,
+});
+
+window.Vue.component('admin-logs', LogContainer);
+
+document.addEventListener('DOMContentLoaded', () => {
+ new window.Vue({
+ el: '#admin-logs-main',
+ router,
+ components: {
+ LogContainer,
+ },
+ render: (h) => h(LogContainer),
+ });
+});
+
diff --git a/resources/js/admin/logs/utils/date.js b/resources/js/admin/logs/utils/date.js
new file mode 100644
index 0000000000..491fa1a8d8
--- /dev/null
+++ b/resources/js/admin/logs/utils/date.js
@@ -0,0 +1,74 @@
+/* eslint-disable import/prefer-default-export */
+import { DateTime } from 'luxon';
+
+/**
+ * Convert PHP/moment date format to Luxon format
+ * @param {string} format - PHP/moment format string
+ * @returns {string} - Luxon format string
+ */
+const convertToLuxonFormat = (format) => {
+ // Common conversions from PHP/moment to Luxon
+ const replacements = {
+ YYYY: 'yyyy',
+ YY: 'yy',
+ MM: 'LL',
+ M: 'L',
+ DD: 'dd',
+ D: 'd',
+ HH: 'HH',
+ hh: 'hh',
+ H: 'H',
+ h: 'h',
+ mm: 'mm',
+ m: 'm',
+ ss: 'ss',
+ s: 's',
+ A: 'a',
+ a: 'a',
+ };
+
+ let luxonFormat = format;
+ Object.entries(replacements).forEach(([from, to]) => {
+ luxonFormat = luxonFormat.replace(new RegExp(from, 'g'), to);
+ });
+
+ return luxonFormat;
+};
+
+/**
+ * Format date to user's date format
+ * @param {string} value - The date to format
+ * @returns {string} - The formatted date
+ */
+export const dateFormatter = (value) => {
+ let datetimeConfig = 'dd/LL/yyyy hh:mm';
+ let timezoneConfig = 'UTC';
+
+ if (
+ typeof ProcessMaker !== 'undefined'
+ && ProcessMaker.user
+ && ProcessMaker.user.datetime_format
+ ) {
+ timezoneConfig = ProcessMaker.user.timezone;
+ datetimeConfig = convertToLuxonFormat(ProcessMaker.user.datetime_format);
+ }
+
+ if (value) {
+ const date = DateTime.fromISO(value, { zone: 'utc' }).setZone(timezoneConfig);
+
+ if (date.isValid) {
+ return date.toFormat(datetimeConfig);
+ }
+
+ // Try parsing as SQL format
+ const sqlDate = DateTime.fromSQL(value, { zone: 'utc' }).setZone(timezoneConfig);
+ if (sqlDate.isValid) {
+ return sqlDate.toFormat(datetimeConfig);
+ }
+
+ return value;
+ }
+
+ return '-';
+};
+
diff --git a/resources/views/admin/logs/index.blade.php b/resources/views/admin/logs/index.blade.php
new file mode 100644
index 0000000000..9a7ca90a61
--- /dev/null
+++ b/resources/views/admin/logs/index.blade.php
@@ -0,0 +1,28 @@
+@extends('layouts.layout')
+
+@section('title')
+ {{__('Logs')}}
+@endsection
+
+@section('sidebar')
+ @include('layouts.sidebar', ['sidebar'=> Menu::get('sidebar_admin')])
+@endsection
+
+@section('breadcrumbs')
+ @include('shared.breadcrumbs', ['routes' => [
+ __('Admin') => route('admin.index'),
+ __('Logs') => null,
+ ]])
+@endsection
+
+@section('content')
+
+@endsection
+
+@section('js')
+
+
+@endsection
+
diff --git a/routes/web.php b/routes/web.php
index 30f1cdaa35..589cb3995f 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -8,6 +8,7 @@
use ProcessMaker\Http\Controllers\Admin\DevLinkController;
use ProcessMaker\Http\Controllers\Admin\GroupController;
use ProcessMaker\Http\Controllers\Admin\LdapLogsController;
+use ProcessMaker\Http\Controllers\Admin\LogsController;
use ProcessMaker\Http\Controllers\Admin\QueuesController;
use ProcessMaker\Http\Controllers\Admin\ScriptExecutorController;
use ProcessMaker\Http\Controllers\Admin\SettingsController;
@@ -81,6 +82,12 @@
// temporary, should be removed
Route::get('security-logs/download/all', [ProcessMaker\Http\Controllers\Api\SecurityLogController::class, 'downloadForAllUsers'])->middleware('can:view-security-logs');
Route::get('security-logs/download/{user}', [ProcessMaker\Http\Controllers\Api\SecurityLogController::class, 'downloadForUser'])->middleware('can:view-security-logs');
+
+ // Logs - available when package-email-start-event or package-ai is installed
+ if (hasPackage('package-email-start-event') || hasPackage('package-ai')) {
+ Route::get('logs', [LogsController::class, 'index'])->name('admin.logs')->middleware('can:view-settings');
+ Route::get('logs/{any}', [LogsController::class, 'index'])->name('admin.logs-any')->middleware('can:view-settings')->where('any', '.*');
+ }
});
Route::get('admin', [AdminController::class, 'index'])->name('admin.index');
diff --git a/webpack.mix.js b/webpack.mix.js
index 01253ace95..c93f125c10 100644
--- a/webpack.mix.js
+++ b/webpack.mix.js
@@ -104,6 +104,7 @@ mix
.js("resources/js/admin/cssOverride/edit.js", "public/js/admin/cssOverride/edit.js")
.js("resources/js/admin/script-executors/index.js", "public/js/admin/script-executors/index.js")
.js("resources/js/admin/tenant-queues/index.js", "public/js/admin/tenant-queues/index.js")
+ .js("resources/js/admin/logs/index.js", "public/js/admin/logs/index.js")
.js("resources/js/processes/index.js", "public/js/processes")
.js("resources/js/processes/edit.js", "public/js/processes")
From 7be12fb221750302c5e203b5b1580a1b36f80dc5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Agust=C3=ADn=20Busso?=
<90727999+agustinbusso@users.noreply.github.com>
Date: Wed, 7 Jan 2026 11:27:17 -0300
Subject: [PATCH 2/5] Add translation strings
---
.../logs/components/Logs/HeaderBar/HeaderBar.vue | 12 ++++++------
.../components/Logs/LogContainer/LogContainer.vue | 2 +-
resources/lang/en.json | 6 ++++++
3 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue b/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
index d33b721828..4085475684 100644
--- a/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
+++ b/resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
@@ -10,21 +10,21 @@
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('errors')"
>
- Error Logs
+ {{ $t('Error Logs') }}
- Matched Logs
+ {{ $t('Matched Logs') }}
- Total Logs
+ {{ $t('Total Logs') }}
@@ -38,14 +38,14 @@
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('design')"
>
- Design Mode Logs
+ {{ $t('Design Mode Logs') }}
- Execution Logs
+ {{ $t('Execution Logs') }}
@@ -68,7 +68,7 @@
tw-ring-0
placeholder:tw-text-zinc-400
"
- placeholder="Search here"
+ :placeholder="$t('Search here')"
:value="value"
@input="onInput"
@keypress="onKeypress"
diff --git a/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue b/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
index 1fd434353c..3aa08d07ca 100644
--- a/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
+++ b/resources/js/admin/logs/components/Logs/LogContainer/LogContainer.vue
@@ -12,7 +12,7 @@
- {{ title }}
+ {{ $t(title) }}
Date: Wed, 7 Jan 2026 12:50:14 -0300
Subject: [PATCH 3/5] Fix routes issue
---
routes/web.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/routes/web.php b/routes/web.php
index 589cb3995f..11287a4a62 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -86,6 +86,12 @@
// Logs - available when package-email-start-event or package-ai is installed
if (hasPackage('package-email-start-event') || hasPackage('package-ai')) {
Route::get('logs', [LogsController::class, 'index'])->name('admin.logs')->middleware('can:view-settings');
+ // Export route must be before the wildcard route
+ if (hasPackage('package-email-start-event')) {
+ Route::get('logs/export/csv', [ProcessMaker\Package\PackageEmailStartEvent\Http\Controllers\EmailListenerLogController::class, 'exportToCsv'])
+ ->name('admin.logs.export.csv')
+ ->middleware('can:view-settings');
+ }
Route::get('logs/{any}', [LogsController::class, 'index'])->name('admin.logs-any')->middleware('can:view-settings')->where('any', '.*');
}
});
From d43dc69dc80a1c7a44fd61ee1c701e03ef652a9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Agust=C3=ADn=20Busso?=
<90727999+agustinbusso@users.noreply.github.com>
Date: Wed, 7 Jan 2026 13:28:59 -0300
Subject: [PATCH 4/5] Add validation to check if packages are installed
---
.../logs/components/Logs/Sidebar/Sidebar.vue | 65 ++++++++++-----
.../js/admin/logs/components/Logs/routes.js | 79 +++++++++++++++----
2 files changed, 109 insertions(+), 35 deletions(-)
diff --git a/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
index b47e9561f2..9b93c63759 100644
--- a/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
+++ b/resources/js/admin/logs/components/Logs/Sidebar/Sidebar.vue
@@ -5,8 +5,11 @@
Logs