Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3be46ef
created a new web route to see files by media id
gustavobascope Aug 14, 2025
2a82dfd
Merge branch 'epic/FOUR-25679' of github.com:ProcessMaker/processmake…
gustavobascope Aug 14, 2025
c5fcbfb
Merge pull request #8445 from ProcessMaker/task/FOUR-25712
gustavobascope Aug 19, 2025
d701049
Merge branch 'develop' into epic/FOUR-25679
agustinbusso Dec 2, 2025
3ce7927
Merge
agustinbusso Dec 12, 2025
0dd55fb
Php cs fixer fixes
agustinbusso Dec 12, 2025
72d3190
Add microserviceHost to layout
agustinbusso Dec 17, 2025
00d2352
Merge pull request #8656 from ProcessMaker/task/FOUR-28467
agustinbusso Dec 17, 2025
a495541
Move logs logic from email start event package. Add base logs ui for …
agustinbusso Jan 7, 2026
c76e941
Merge branch 'develop' into epic/FOUR-25679
agustinbusso Jan 7, 2026
7be12fb
Add translation strings
agustinbusso Jan 7, 2026
1022975
Fix routes issue
agustinbusso Jan 7, 2026
d43dc69
Add validation to check if packages are installed
agustinbusso Jan 7, 2026
5f65a78
Fix issue with nested properties
agustinbusso Jan 7, 2026
1f6187e
Merge pull request #8671 from ProcessMaker/task/FOUR-28659
agustinbusso Jan 7, 2026
40875ec
Add session logs UI improvements and new fields
agustinbusso Jan 12, 2026
7ea2dc3
Merge pull request #8674 from ProcessMaker/task/FOUR-28707
agustinbusso Jan 12, 2026
14c79eb
Add translation strings
agustinbusso Jan 15, 2026
ebd7ade
Add detail panel in log container
agustinbusso Jan 15, 2026
41e54a0
Change titles for tab in agent logs. Add debounce for search
agustinbusso Jan 15, 2026
8b3993e
Add and show details panel
agustinbusso Jan 15, 2026
8a864df
Merge pull request #8684 from ProcessMaker/task/FOUR-28750
agustinbusso Jan 15, 2026
7173eba
Enhance MediaExporter to update FlowGenie media configuration upon me…
marcoAntonioNina Jan 19, 2026
f44c728
Merge pull request #8691 from ProcessMaker/bugfix/FOUR-25701
marcoAntonioNina Jan 20, 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
20 changes: 20 additions & 0 deletions ProcessMaker/Http/Controllers/Admin/LogsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace ProcessMaker\Http\Controllers\Admin;

use Illuminate\Http\Request;
use ProcessMaker\Http\Controllers\Controller;

class LogsController extends Controller
{
/**
* Display the logs index page.
* This view loads log components from installed packages (package-email-start-event, package-ai).
*
* @return \Illuminate\Contracts\View\View
*/
public function index()
{
return view('admin.logs.index');
}
}
14 changes: 13 additions & 1 deletion ProcessMaker/Http/Controllers/Api/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,19 @@ public function download(Media $file)
{
$path = Storage::disk('public')->path($file->id . '/' . $file->file_name);

// Register the Event
// Inline preview when requested
if (request()->boolean('inline', false)) {
if (!empty($file->file_name)) {
FilesDownloaded::dispatch($file);
}

return response()->file($path, [
'Content-Type' => $file->mime_type,
'Content-Disposition' => 'inline; filename="' . addslashes($file->file_name) . '"',
]);
}

// Default: force download
if (!empty($file->file_name)) {
FilesDownloaded::dispatch($file);
}
Expand Down
8 changes: 8 additions & 0 deletions ProcessMaker/Http/Middleware/GenerateMenus.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ public function handle(Request $request, Closure $next)
'file' => "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'));
Expand Down
14 changes: 13 additions & 1 deletion ProcessMaker/ImportExport/Exporters/MediaExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,22 @@ public function import(): bool

$ref = $this->getReference(DependentType::MEDIA);
if ($ref && isset($ref['base64'])) {
$this->model->model->addMediaFromBase64($ref['base64'])
$newMedia = $this->model->model->addMediaFromBase64($ref['base64'])
->usingFileName($this->model->file_name)
->withCustomProperties($this->model->custom_properties)
->toMediaCollection($this->model->collection_name);

if (hasPackage('package-ai')) {
$updaterClass = 'ProcessMaker\\Package\\PackageAi\\Services\\FlowGenieMediaConfigUpdater';
if (class_exists($updaterClass)) {
$updaterClass::updateForMediaImport(
(string) $this->model->model_type,
(int) $this->model->model_id,
(int) $this->model->id,
(int) $newMedia->id
);
}
}
}

// We should delete the model, because the Spatie library recreates it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
return new class extends Migration {
/**
* Run the migrations.
*/
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AgentSessionDetail from "./AgentSessionDetail.vue";

export { AgentSessionDetail };
export default AgentSessionDetail;

87 changes: 87 additions & 0 deletions resources/js/admin/logs/components/Logs/BaseTable/BaseTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<template>
<div
class="
tw-flex-1 tw-overflow-auto tw-rounded-xl tw-border tw-border-gray-200 tw-shadow-zinc-200
"
>
<table class="tw-w-full tw-text-left tw-text-sm">
<thead class="tw-bg-gray-50 tw-text-zinc-400">
<tr>
<th
v-for="column in columns"
:key="column.key"
class="tw-px-6 tw-py-4 tw-font-medium tw-whitespace-nowrap"
>
{{ column.label }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, idx) in data"
:key="idx"
class="tw-border-t tw-border-zinc-200 tw-transition-colors"
:class="[
clickable ? 'tw-cursor-pointer hover:tw-bg-blue-50' : '',
isSelected(item) ? 'tw-bg-blue-50' : ''
]"
@click="handleRowClick(item, idx)"
>
<td
v-for="column in columns"
:key="column.key"
class="tw-px-6 tw-py-4 tw-text-gray-600 tw-border-b tw-border-gray-200 tw-whitespace-nowrap"
>
<slot
:name="`cell-${column.key}`"
:value="getRawValue(item, column)"
:item="item"
:column="column"
>
{{ getItemValue(item, column) }}
</slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>

<script>
export default {
props: {
columns: { type: Array, required: true },
data: { type: Array, required: true },
clickable: { type: Boolean, default: false },
selectedItem: { type: Object, default: null },
itemKey: { type: String, default: 'id' },
},
methods: {
getRawValue(item, column) {
// Get raw value - handle dot-separated keys for nested properties
return column.key.includes(".")
? column.key.split(".").reduce((val, part) => (val == null ? undefined : val[part]), item)
: item[column.key];
},
getItemValue(item, column) {
const value = this.getRawValue(item, column);

// Apply format function if provided
if (typeof column.format === "function") {
return column.format(value);
}

return value;
},
handleRowClick(item, index) {
if (this.clickable) {
this.$emit('row-click', item, index);
}
},
isSelected(item) {
if (!this.selectedItem) return false;
return item[this.itemKey] === this.selectedItem[this.itemKey];
},
},
};
</script>
3 changes: 3 additions & 0 deletions resources/js/admin/logs/components/Logs/BaseTable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line import/prefer-default-export
export { default as BaseTable } from './BaseTable.vue';

148 changes: 148 additions & 0 deletions resources/js/admin/logs/components/Logs/HeaderBar/HeaderBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<template>
<div class="tw-flex tw-flex-row tw-gap-x-8 tw-justify-between tw-w-full sm:tw-flex-row">
<!-- Email log type tabs - only shown for email category -->
<div
v-if="isEmailCategory"
class="tw-flex tw-items-center tw-gap-2 tw-bg-gray-100 tw-rounded-lg tw-p-1"
>
<RouterLink
to="/email/errors"
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('errors')"
>
{{ $t('Error Logs') }}
</RouterLink>
<RouterLink
to="/email/matched"
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('matched')"
>
{{ $t('Matched Logs') }}
</RouterLink>
<RouterLink
to="/email/total"
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('total')"
>
{{ $t('Total Logs') }}
</RouterLink>
</div>

<!-- Agents category tabs -->
<div
v-else-if="isAgentsCategory"
class="tw-flex tw-items-center tw-gap-2 tw-bg-gray-100 tw-rounded-lg tw-p-1"
>
<RouterLink
to="/agents/design"
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('design')"
>
{{ $t('FlowGenie Studio Logs') }}
</RouterLink>
<RouterLink
to="/agents/execution"
class="tw-rounded-lg tw-px-3 tw-py-2 tw-text-base"
:class="tabClasses('execution')"
>
{{ $t('Runtime Logs') }}
</RouterLink>
</div>

<!-- Empty placeholder for other categories -->
<div v-else />

<div class="tw-flex tw-flex-1 tw-items-center tw-gap-1 tw-w-auto tw-border tw-border-zinc-200 tw-rounded-lg tw-p-1 tw-px-3">
<div class="tw-relative tw-w-full tw-flex tw-items-center tw-gap-1">
<i class="fas fa-search" />
<input
ref="searchInput"
type="text"
class="
tw-h-8
tw-w-full
tw-pl-3
tw-pr-3
tw-text-sm
tw-outline-none
tw-ring-0
placeholder:tw-text-zinc-400
"
:placeholder="$t('Search here')"
:value="value"
@input="onInput"
@keypress="onKeypress"
>
</div>
</div>
</div>
</template>

<script>
export default {
props: {
value: { type: String, default: '' },
},
data() {
return {
debounceTimer: null,
};
},
computed: {
isEmailCategory() {
return this.$route.path.startsWith('/email');
},
isAgentsCategory() {
return this.$route.path.startsWith('/agents');
},
},
watch: {
'$route.path': {
handler() {
// reset input value in search when route changes
this.$emit('input', '');
},
immediate: true,
},
},
beforeDestroy() {
// Clear debounce timer when component is destroyed
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
},
methods: {
tabClasses(tab) {
const currentRoute = this.$route.params.logType;

return currentRoute === tab
? 'tw-bg-white tw-font-semibold tw-text-zinc-900'
: 'tw-text-zinc-700 hover:tw-bg-zinc-50';
},
onInput(event) {
this.$emit('input', event.target.value);
this.debouncedSearch();
},
debouncedSearch() {
// Clear existing timer
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
// Set new timer - wait 300ms after user stops typing
this.debounceTimer = setTimeout(() => {
this.$emit('search');
}, 300);
},
onKeypress(event) {
// Allow immediate search on Enter key
if (event.charCode === 13) {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.$emit('search');
}
},
},
};
</script>

3 changes: 3 additions & 0 deletions resources/js/admin/logs/components/Logs/HeaderBar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line import/prefer-default-export
export { default as HeaderBar } from './HeaderBar.vue';

Loading
Loading