Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"filament/filament": "^4.0",
"filament/spatie-laravel-settings-plugin": "^4.0",
"guzzlehttp/guzzle": "^7.8",
"hirethunk/verbs": "^0.7.0",
"illuminate/cache": "^11.35.0",
"illuminate/console": "^11.35.0",
"illuminate/database": "^11.35.0",
Expand Down
154 changes: 154 additions & 0 deletions database/migrations/2026_01_12_000000_initialize_verbs_events.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php

use Cachet\Enums\ComponentGroupVisibilityEnum;
use Cachet\Enums\ComponentStatusEnum;
use Cachet\Enums\IncidentStatusEnum;
use Cachet\Enums\ResourceVisibilityEnum;
use Cachet\Models\Component;
use Cachet\Models\ComponentGroup;
use Cachet\Models\Incident;
use Cachet\Models\Schedule;
use Cachet\Verbs\Events\ComponentGroups\ComponentGroupCreated;
use Cachet\Verbs\Events\ComponentGroups\ComponentGroupDeleted;
use Cachet\Verbs\Events\Components\ComponentCreated;
use Cachet\Verbs\Events\Components\ComponentDeleted;
use Cachet\Verbs\Events\Incidents\IncidentCreated;
use Cachet\Verbs\Events\Incidents\IncidentDeleted;
use Cachet\Verbs\Events\Incidents\IncidentUpdateRecorded;
use Cachet\Verbs\Events\Schedules\ScheduleCreated;
use Cachet\Verbs\Events\Schedules\ScheduleDeleted;
use Cachet\Verbs\Events\Schedules\ScheduleUpdateRecorded;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Thunk\Verbs\Facades\Verbs;

return new class extends Migration
{
public function up(): void
{
// Skip if events already exist
if (DB::table('verb_events')->exists()) {
return;
}

$this->migrateComponentGroups();
$this->migrateComponents();
$this->migrateIncidents();
$this->migrateSchedules();

Verbs::commit();
}

public function down(): void
{
// Truncate Verbs tables to remove migrated events
DB::table('verb_state_events')->truncate();
DB::table('verb_snapshots')->truncate();
DB::table('verb_events')->truncate();
}

private function migrateComponentGroups(): void
{
ComponentGroup::each(function (ComponentGroup $group) {
ComponentGroupCreated::fire(
component_group_id: $group->id,
name: $group->name,
order: $group->order ?? 0,
collapsed: $group->collapsed ?? ComponentGroupVisibilityEnum::expanded,
visible: $group->visible ?? ResourceVisibilityEnum::guest,
);
});
}

private function migrateComponents(): void
{
Component::withTrashed()->each(function (Component $component) {
ComponentCreated::fire(
component_id: $component->id,
name: $component->name,
status: $component->status ?? ComponentStatusEnum::operational,
description: $component->description,
link: $component->link,
order: $component->order ?? 0,
component_group_id: $component->component_group_id,
enabled: $component->enabled ?? true,
meta: $component->meta ?? [],
);

if ($component->deleted_at) {
ComponentDeleted::fire(component_id: $component->id);
}
});
}

private function migrateIncidents(): void
{
Incident::withTrashed()->with(['components', 'updates'])->each(function (Incident $incident) {
$components = $incident->components->map(fn ($c) => [
'id' => $c->id,
'status' => $c->pivot->component_status ?? ComponentStatusEnum::operational,
])->all();

IncidentCreated::fire(
incident_id: $incident->id,
name: $incident->name,
status: $incident->status ?? IncidentStatusEnum::investigating,
message: $incident->message ?? '',
visible: $incident->visible ?? ResourceVisibilityEnum::guest,
stickied: $incident->stickied ?? false,
notifications: boolval($incident->notifications) ?? false,
occurred_at: $incident->occurred_at?->toIso8601String(),
user_id: $incident->user_id,
external_provider: $incident->external_provider,
external_id: $incident->external_id,
components: $components,
guid: $incident->guid,
);

foreach ($incident->updates as $update) {
IncidentUpdateRecorded::fire(
incident_id: $incident->id,
status: $update->status ?? IncidentStatusEnum::investigating,
message: $update->message ?? '',
user_id: $update->user_id,
);
}

if ($incident->deleted_at) {
IncidentDeleted::fire(incident_id: $incident->id);
}
});
}

private function migrateSchedules(): void
{
Schedule::withTrashed()->with(['components', 'updates'])->each(function (Schedule $schedule) {
$components = $schedule->components->map(fn ($c) => [
'id' => $c->id,
'status' => $c->pivot->component_status ?? ComponentStatusEnum::operational,
])->all();

ScheduleCreated::fire(
schedule_id: $schedule->id,
name: $schedule->name,
message: $schedule->message,
scheduled_at: $schedule->scheduled_at?->toIso8601String(),
completed_at: $schedule->completed_at?->toIso8601String(),
components: $components,
);

foreach ($schedule->updates as $update) {
ScheduleUpdateRecorded::fire(
schedule_id: $schedule->id,
message: $update->message ?? '',
status: $update->status,
user_id: $update->user_id,
);
}

if ($schedule->deleted_at) {
ScheduleDeleted::fire(schedule_id: $schedule->id);
}
});
}
};
15 changes: 13 additions & 2 deletions src/Actions/Component/CreateComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,26 @@
namespace Cachet\Actions\Component;

use Cachet\Data\Requests\Component\CreateComponentRequestData;
use Cachet\Enums\ComponentStatusEnum;
use Cachet\Models\Component;
use Cachet\Verbs\Events\Components\ComponentCreated;

class CreateComponent
{
/**
* Handle the action.
*/
public function handle(CreateComponentRequestData $component): Component
public function handle(CreateComponentRequestData $data): Component
{
return Component::create($component->toArray());
return ComponentCreated::commit(
name: $data->name,
status: $data->status ?? ComponentStatusEnum::operational,
description: $data->description,
link: $data->link,
order: $data->order ?? 0,
component_group_id: $data->componentGroupId,
enabled: $data->enabled,
meta: [],
);
}
}
5 changes: 2 additions & 3 deletions src/Actions/Component/DeleteComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Cachet\Actions\Component;

use Cachet\Models\Component;
use Cachet\Verbs\Events\Components\ComponentDeleted;

class DeleteComponent
{
Expand All @@ -11,8 +12,6 @@ class DeleteComponent
*/
public function handle(Component $component): void
{
$component->subscribers()->detach();

$component->delete();
ComponentDeleted::commit(component_id: $component->id);
}
}
34 changes: 25 additions & 9 deletions src/Actions/Component/UpdateComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Cachet\Actions\Component;

use Cachet\Data\Requests\Component\UpdateComponentRequestData;
use Cachet\Events\Components\ComponentStatusWasChanged;
use Cachet\Models\Component;
use Cachet\Verbs\Events\Components\ComponentStatusChanged;
use Cachet\Verbs\Events\Components\ComponentUpdated;

class UpdateComponent
{
Expand All @@ -14,17 +15,32 @@ class UpdateComponent
public function handle(Component $component, UpdateComponentRequestData $data): Component
{
$oldStatus = $component->status;
$hasStatusChange = $data->status !== null && $data->status !== $oldStatus;

$component->update($data->toArray());

if ($component->wasChanged('status')) {
ComponentStatusWasChanged::dispatch(
$component,
$oldStatus,
$component->status
// Fire status change event if status is changing
if ($hasStatusChange) {
ComponentStatusChanged::commit(
component_id: $component->id,
old_status: $oldStatus,
new_status: $data->status,
);
}

return $component->fresh();
// Fire general update event for other changes
ComponentUpdated::commit(
component_id: $component->id,
name: $data->name,
status: $hasStatusChange ? null : $data->status, // Skip status if already handled
description: $data->description,
link: $data->link,
order: $data->order,
component_group_id: $data->componentGroupId,
enabled: $data->enabled,
);

// Refresh the original model with updated data
$component->refresh();

return $component;
}
}
33 changes: 20 additions & 13 deletions src/Actions/ComponentGroup/CreateComponentGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,36 @@
namespace Cachet\Actions\ComponentGroup;

use Cachet\Data\Requests\ComponentGroup\CreateComponentGroupRequestData;
use Cachet\Models\Component;
use Cachet\Enums\ComponentGroupVisibilityEnum;
use Cachet\Enums\ResourceVisibilityEnum;
use Cachet\Models\ComponentGroup;
use Cachet\Verbs\Events\ComponentGroups\ComponentGroupCreated;
use Cachet\Verbs\Events\Components\ComponentUpdated;

class CreateComponentGroup
{
/**
* Handle the action.
*/
/**
* Handle the action.
*/
public function handle(CreateComponentGroupRequestData $data): ComponentGroup
{
return tap(ComponentGroup::create(
$data->except('components')->toArray(),
), function (ComponentGroup $componentGroup) use ($data) {
if (! $data->components) {
return;
$componentGroup = ComponentGroupCreated::commit(
name: $data->name,
order: $data->order ?? 0,
collapsed: ComponentGroupVisibilityEnum::expanded,
visible: $data->visible ?? ResourceVisibilityEnum::guest,
);

// Assign components to the group via update events
if ($data->components) {
foreach ($data->components as $componentId) {
ComponentUpdated::commit(
component_id: $componentId,
component_group_id: $componentGroup->id,
);
}
}

Component::query()->whereIn('id', $data->components)->update([
'component_group_id' => $componentGroup->id,
]);
});
return $componentGroup;
}
}
12 changes: 10 additions & 2 deletions src/Actions/ComponentGroup/DeleteComponentGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Cachet\Actions\ComponentGroup;

use Cachet\Models\ComponentGroup;
use Cachet\Verbs\Events\ComponentGroups\ComponentGroupDeleted;
use Cachet\Verbs\Events\Components\ComponentUpdated;

class DeleteComponentGroup
{
Expand All @@ -11,8 +13,14 @@ class DeleteComponentGroup
*/
public function handle(ComponentGroup $componentGroup): void
{
$componentGroup->components()->update(['component_group_id' => null]);
// First, unassign all components from this group
foreach ($componentGroup->components as $component) {
ComponentUpdated::commit(
component_id: $component->id,
clear_component_group: true,
);
}

$componentGroup->delete();
ComponentGroupDeleted::commit(component_group_id: $componentGroup->id);
}
}
23 changes: 17 additions & 6 deletions src/Actions/ComponentGroup/UpdateComponentGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Cachet\Actions\ComponentGroup;

use Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData;
use Cachet\Models\Component;
use Cachet\Models\ComponentGroup;
use Cachet\Verbs\Events\ComponentGroups\ComponentGroupUpdated;
use Cachet\Verbs\Events\Components\ComponentUpdated;

class UpdateComponentGroup
{
Expand All @@ -13,14 +14,24 @@
*/
public function handle(ComponentGroup $componentGroup, UpdateComponentGroupRequestData $data): ComponentGroup
{
$componentGroup->update($data->except('components')->toArray());
$result = ComponentGroupUpdated::commit(
component_group_id: $componentGroup->id,
name: $data->name,
order: $data->order,
collapsed: $data->collapsed ?? null,

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.2 - L11.x - prefer-lowest

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.4 - L11.x - prefer-lowest

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.3 - L11.x - prefer-stable

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.4 - L11.x - prefer-stable

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.3 - L11.x - prefer-lowest

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.

Check failure on line 21 in src/Actions/ComponentGroup/UpdateComponentGroup.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.2 - L11.x - prefer-stable

Access to an undefined property Cachet\Data\Requests\ComponentGroup\UpdateComponentGroupRequestData::$collapsed.
visible: $data->visible,
);

// Assign components to the group via update events
if ($data->components) {
Component::query()->whereIn('id', $data->components)->update([
'component_group_id' => $componentGroup->id,
]);
foreach ($data->components as $componentId) {
ComponentUpdated::commit(
component_id: $componentId,
component_group_id: $componentGroup->id,
);
}
}

return $componentGroup->fresh();
return $result;
}
}
Loading
Loading