diff --git a/app/Bots/BashScript.php b/app/Bots/BashScript.php
new file mode 100644
index 0000000..c71fcf6
--- /dev/null
+++ b/app/Bots/BashScript.php
@@ -0,0 +1,46 @@
+config = $config;
+ }
+
+ public function run(): void
+ {
+ if (!empty($this->config['script'])) {
+ // Execute the bash script
+ $script = $this->config['script'];
+ $output = [];
+ $returnVar = null;
+ exec($script, $output, $returnVar);
+
+ if ($returnVar !== 0) {
+ // Log error if the script failed
+ \Illuminate\Support\Facades\Log::error("Bash script execution failed: " . implode("\n", $output));
+ } else {
+ Log::info("Bash script executed successfully: " . implode("\n", $output));
+ }
+ }
+ }
+
+ public static function configSchema(): array
+ {
+ return [
+ 'script' => [
+ 'type' => 'textarea',
+ 'label' => 'Bash Script',
+ 'rules' => [
+ 'required',
+ ]
+ ],
+ ];
+ }
+}
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index f908a28..d9d2f89 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -3,12 +3,13 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
class DashboardController extends Controller
{
public function index()
{
- $bots = \App\Models\Bot::all();
+ $bots = Auth::user()->bots;
return view('dashboard', compact('bots'));
}
diff --git a/app/Jobs/RunBot.php b/app/Jobs/RunBot.php
index 674a25b..59dc610 100644
--- a/app/Jobs/RunBot.php
+++ b/app/Jobs/RunBot.php
@@ -3,6 +3,7 @@
namespace App\Jobs;
use App\Models\Bot;
+use App\Models\BotLog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
@@ -13,9 +14,7 @@ class RunBot implements ShouldQueue
/**
* Create a new job instance.
*/
- public function __construct(private Bot $bot)
- {
- }
+ public function __construct(private Bot $bot, private BotLog $log) {}
/**
* Execute the job.
@@ -24,6 +23,22 @@ class RunBot implements ShouldQueue
{
$class = new $this->bot->class($this->bot->config ?? []);
- $class->run();
+ try {
+ $class->run();
+
+ // Update the log entry on success
+ $this->log->update([
+ 'finished_at' => now(),
+ 'status' => 'success',
+ // 'output' => is_string($result) ? $result : json_encode($result, JSON_PRETTY_PRINT),
+ ]);
+ } catch (\Throwable $e) {
+ // Log the error in the bot log
+ $this->log->update([
+ 'finished_at' => now(),
+ 'status' => 'failed',
+ 'error' => $e->getMessage(),
+ ]);
+ }
}
}
diff --git a/app/Livewire/BotLogs.php b/app/Livewire/BotLogs.php
new file mode 100644
index 0000000..f199c8e
--- /dev/null
+++ b/app/Livewire/BotLogs.php
@@ -0,0 +1,35 @@
+getLogs();
+ // }
+
+ // public function getLogs(): void
+ // {
+ // $this->logs = Auth::user()->bots->pluck('logs')->flatten()->sortByDesc('created_at');
+ // }
+
+ public function render()
+ {
+ return view('livewire.bot-logs', [
+ 'logs' => BotLog::whereHas('bot', fn($q) => $q->where('user_id', Auth::id()))
+ ->orderBy('created_at', 'desc')
+ ->latest()
+ ->paginate(10),
+ ]);
+ }
+}
diff --git a/app/Livewire/BotsList.php b/app/Livewire/BotsList.php
index 1a2cdc4..cc13936 100644
--- a/app/Livewire/BotsList.php
+++ b/app/Livewire/BotsList.php
@@ -12,11 +12,21 @@ class BotsList extends Component
{
public $bots;
+ public string $query = '';
+
public function mount()
{
$this->bots = Auth::user()->bots;
}
+ public function search()
+ {
+ $this->bots = Auth::user()->bots()
+ ->where('name', 'like', '%' . $this->query . '%')
+ ->orWhere('class', 'like', '%' . $this->query . '%')
+ ->get();
+ }
+
public function toggleBot($botId)
{
$bot = \App\Models\Bot::find($botId);
@@ -62,8 +72,13 @@ class BotsList extends Component
public function confirmRunBot(Bot $bot): void
{
+ $log = $bot->logs()->create([
+ 'status' => 'pending',
+ 'started_at' => now(),
+ ]);
+
// Dispatch the job to run the bot
- dispatch(new RunBot($bot));
+ dispatch(new RunBot($bot, $log));
flash()->success("Bot '{$bot->name}' is being executed.");
}
diff --git a/app/Livewire/ViewBot.php b/app/Livewire/ViewBot.php
new file mode 100644
index 0000000..e2c239b
--- /dev/null
+++ b/app/Livewire/ViewBot.php
@@ -0,0 +1,38 @@
+bot->name . '?')
+ ->asConfirm()
+ ->onConfirm('confirmRunBot')
+ ->show();
+ }
+
+ public function confirmRunBot(): void
+ {
+ $log = $this->bot->logs()->create([
+ 'status' => 'pending',
+ ]);
+
+ // Dispatch the job to run the bot
+ dispatch(new RunBot($this->bot, $log));
+
+ flash()->success("Bot '{$this->bot->name}' is being executed.");
+ }
+
+ public function render()
+ {
+ return view('livewire.view-bot');
+ }
+}
diff --git a/app/Models/Bot.php b/app/Models/Bot.php
index 1af2e7d..80b8a5d 100644
--- a/app/Models/Bot.php
+++ b/app/Models/Bot.php
@@ -51,4 +51,19 @@ class Bot extends Model
{
return $this->belongsTo(User::class);
}
+
+ public function logs()
+ {
+ return $this->hasMany(BotLog::class);
+ }
+
+ public function latestLog()
+ {
+ return $this->hasOne(BotLog::class)->latestOfMany();
+ }
+
+ public function failedLogs()
+ {
+ return $this->hasMany(BotLog::class)->where('status', 'failed');
+ }
}
diff --git a/app/Models/BotLog.php b/app/Models/BotLog.php
new file mode 100644
index 0000000..ea20660
--- /dev/null
+++ b/app/Models/BotLog.php
@@ -0,0 +1,30 @@
+ 'datetime',
+ 'finished_at' => 'datetime',
+ ];
+ }
+
+ public function bot()
+ {
+ return $this->belongsTo(Bot::class);
+ }
+}
diff --git a/app/Services/BotService.php b/app/Services/BotService.php
index 62a4279..8074e98 100644
--- a/app/Services/BotService.php
+++ b/app/Services/BotService.php
@@ -4,6 +4,7 @@ namespace App\Services;
use App\Models\Bot;
use App\Bots\BotContract;
+use App\Jobs\RunBot;
use Cron\CronExpression;
use Illuminate\Support\Facades\Log;
@@ -16,14 +17,29 @@ class BotService
foreach ($bots as $bot) {
$cron = new CronExpression($bot->schedule);
if ($cron->isDue()) {
+ $log = $bot->logs()->create([
+ 'status' => 'pending',
+ 'started_at' => now(),
+ ]);
+
try {
$instance = app($bot->class, ['config' => $bot->config]);
if ($instance instanceof BotContract) {
- $instance->run();
+ dispatch(RunBot::class, $bot, $log);
+ $log->update([
+ 'started_at' => now(),
+ 'status' => 'running'
+ ]);
}
} catch (\Throwable $e) {
Log::error("Bot [{$bot->name}] failed: " . $e->getMessage());
+
+ $log->update([
+ 'finished_at' => now(),
+ 'status' => 'failed',
+ 'error' => $e->getMessage(),
+ ]);
}
Log::info("Bot [{$bot->name}] executed successfully.");
diff --git a/database/migrations/2025_08_31_170246_create_bot_logs_table.php b/database/migrations/2025_08_31_170246_create_bot_logs_table.php
new file mode 100644
index 0000000..530b1e6
--- /dev/null
+++ b/database/migrations/2025_08_31_170246_create_bot_logs_table.php
@@ -0,0 +1,33 @@
+id();
+ $table->foreignId('bot_id');
+ $table->timestamp('started_at')->nullable();
+ $table->timestamp('finished_at')->nullable();
+ $table->string('status')->default('pending'); // pending, running, success, failed
+ $table->text('output')->nullable(); // store raw response/log text
+ $table->text('error')->nullable(); // store error message/trace if failed
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('bot_logs');
+ }
+};
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php
index 2f30e47..383d42c 100644
--- a/resources/views/dashboard.blade.php
+++ b/resources/views/dashboard.blade.php
@@ -28,13 +28,16 @@
-
+
Logs
+
+ @livewire('bot-logs')
+
All Bots
diff --git a/resources/views/livewire/bot-logs.blade.php b/resources/views/livewire/bot-logs.blade.php
new file mode 100644
index 0000000..28b59cb
--- /dev/null
+++ b/resources/views/livewire/bot-logs.blade.php
@@ -0,0 +1,40 @@
+
+
+
+
+ | Bot |
+ Status |
+ Started At |
+ Finished At |
+
+
+
+ @foreach ($logs as $log)
+
+ |
+ {{ $log->bot->name }}
+ |
+ $log->status === 'failed',
+ 'text-green-400' => $log->status === 'success',
+ 'text-yellow-400' => $log->status === 'pending',
+ ]),
+ class="px-4 py-2"
+ >
+ {{ $log->status }}
+ |
+
+ {{ $log->started_at ?? '' }}
+ |
+
+ {{ $log->finished_at ?? '' }}
+ |
+
+ @endforeach
+
+
+
+ {{ $logs->links() }}
+
+
diff --git a/resources/views/livewire/bots-list.blade.php b/resources/views/livewire/bots-list.blade.php
index e66fa49..c11409d 100644
--- a/resources/views/livewire/bots-list.blade.php
+++ b/resources/views/livewire/bots-list.blade.php
@@ -1,13 +1,27 @@
-
+
+
+
+
+ Searching
+
+
+
- | Name |
- Schema |
- Schedule |
- Next due |
- Enabled |
- Actions |
+ Name |
+ Schema |
+ Schedule |
+ Next due |
+ Enabled |
+ Actions |
@@ -16,7 +30,7 @@
{{ $bot->name }}
@@ -37,7 +51,7 @@
wire:click="toggleBot({{ $bot->id }})"
/>
|
-
+ |
|