Skip to content

Commit

Permalink
feat: Time-controlled status for Planned Maintenances / Schedules (#119)
Browse files Browse the repository at this point in the history
Co-authored-by: swoga <[email protected]>
Co-authored-by: James Brooks <[email protected]>
  • Loading branch information
3 people authored Nov 24, 2024
1 parent 9b9a186 commit 53964c5
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 130 deletions.
18 changes: 2 additions & 16 deletions database/factories/ScheduleFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Cachet\Database\Factories;

use Cachet\Enums\ScheduleStatusEnum;
use Cachet\Models\Schedule;
use Illuminate\Database\Eloquent\Factories\Factory;

Expand All @@ -22,24 +21,22 @@ public function definition(): array
{
return [
'name' => 'Incident Schedule',
'status' => ScheduleStatusEnum::upcoming,
'scheduled_at' => now()->addDays(7),
'completed_at' => null,
'completed_at' => now()->addDays(14),
];
}

public function completed(): self
{
return $this->state([
'status' => ScheduleStatusEnum::complete,
'scheduled_at' => now()->subMinutes(45),
'completed_at' => now()->subMinutes(30),
]);
}

public function inProgress(): self
{
return $this->state([
'status' => ScheduleStatusEnum::in_progress,
'scheduled_at' => now()->subMinutes(30),
'completed_at' => null,
]);
Expand All @@ -48,7 +45,6 @@ public function inProgress(): self
public function inTheFuture(): self
{
return $this->state([
'status' => ScheduleStatusEnum::upcoming->value,
'scheduled_at' => now()->addDays(30),
'completed_at' => null,
]);
Expand All @@ -57,17 +53,7 @@ public function inTheFuture(): self
public function inThePast(): self
{
return $this->state([
'status' => ScheduleStatusEnum::upcoming,
'scheduled_at' => now()->subDays(30)->subHours(2),
'completed_at' => null,
]);
}

public function completedInThePast(): self
{
return $this->state([
'status' => ScheduleStatusEnum::complete,
'scheduled_at' => now()->addDays(30)->subHours(2),
'completed_at' => now()->subDays(30),
]);
}
Expand Down
32 changes: 32 additions & 0 deletions database/migrations/2024_10_13_214300_drop_schedule_status.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('schedules', function (Blueprint $table) {
$table->dropColumn('status');
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('incidents', function (Blueprint $table) {
$table->tinyInteger('status')->unsigned()->default(0);
});
}
};
11 changes: 9 additions & 2 deletions database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@ public function run(): void
'email_verified_at' => now(),
]);

Schedule::create([
'name' => 'Documentation Maintenance',
'message' => 'We will be conducting maintenance on our documentation servers. Documentation may not be available during this time.',
'scheduled_at' => now()->subHours(12)->subMinutes(45),
'completed_at' => now()->subHours(12),
]);

Schedule::create([
'name' => 'Database Maintenance',
'message' => 'We will be conducting maintenance on our database servers. You may experience degraded performance during this time.',
'scheduled_at' => now()->addHours(6),
'status' => ScheduleStatusEnum::upcoming,
'scheduled_at' => now()->addHours(24),
'completed_at' => null,
]);

$componentGroup = ComponentGroup::create([
Expand Down
17 changes: 2 additions & 15 deletions src/Filament/Resources/ScheduleResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@ public static function form(Form $form): Form
Forms\Components\TextInput::make('name')
->label(__('Name'))
->required(),
Forms\Components\Select::make('status')
->label(__('Status'))
->required()
->options(ScheduleStatusEnum::class)
->default(ScheduleStatusEnum::upcoming)
->afterStateUpdated(function (Forms\Set $set, int|ScheduleStatusEnum $state): void {
if (ScheduleStatusEnum::parse($state) !== ScheduleStatusEnum::complete) {
$set('completed_at', null);
}
})
->live(),
Forms\Components\MarkdownEditor::make('message')
->label(__('Message'))
->columnSpanFull(),
Expand All @@ -45,9 +34,7 @@ public static function form(Form $form): Form
->label(__('Scheduled at'))
->required(),
Forms\Components\DateTimePicker::make('completed_at')
->label(__('Completed at'))
->visible(fn (Forms\Get $get): bool => ScheduleStatusEnum::parse($get('status')) === ScheduleStatusEnum::complete)
->required(fn (Forms\Get $get): bool => ScheduleStatusEnum::parse($get('status')) === ScheduleStatusEnum::complete),
->label(__('Completed at')),
])->columnSpan(1),
])->columns(4);
}
Expand Down Expand Up @@ -99,7 +86,7 @@ public static function table(Table $table): Table
->required(),
])
->color('success')
->action(fn (Schedule $record, array $data) => $record->update(['completed_at' => $data['completed_at'], 'status' => ScheduleStatusEnum::complete])),
->action(fn (Schedule $record, array $data) => $record->update(['completed_at' => $data['completed_at']])),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Expand Down
4 changes: 2 additions & 2 deletions src/Http/Controllers/Api/ScheduleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public function index()
{
$schedules = QueryBuilder::for(Schedule::class)
->allowedIncludes(['components'])
->allowedFilters(['name', 'status'])
->allowedSorts(['name', 'status', 'id', 'scheduled_at', 'completed_at'])
->allowedFilters(['name'])
->allowedSorts(['name', 'id', 'scheduled_at', 'completed_at'])
->simplePaginate(request('per_page', 15));

return ScheduleResource::collection($schedules);
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Controllers/StatusPage/StatusPageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function index(): View
->withCount('incidents')
->get(),

'schedules' => Schedule::query()->inTheFuture()->orderBy('scheduled_at')->get(),
'schedules' => Schedule::query()->incomplete()->orderBy('scheduled_at')->get(),
]);
}

Expand Down
4 changes: 4 additions & 0 deletions src/Http/Resources/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public function toAttributes(Request $request): array
'human' => optional($this->scheduled_at)->diffForHumans(),
'string' => optional($this->scheduled_at)->toDateTimeString(),
],
'completed' => [
'human' => optional($this->completed_at)->diffForHumans(),
'string' => optional($this->completed_at)->toDateTimeString(),
],
'created' => [
'human' => optional($this->created_at)->diffForHumans(),
'string' => optional($this->created_at)->toDateTimeString(),
Expand Down
44 changes: 25 additions & 19 deletions src/Models/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Cachet\Enums\ScheduleStatusEnum;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
Expand All @@ -16,19 +17,33 @@ class Schedule extends Model
use HasFactory, SoftDeletes;

protected $casts = [
'status' => ScheduleStatusEnum::class,
'scheduled_at' => 'datetime',
'completed_at' => 'datetime',
];

protected $fillable = [
'name',
'message',
'status',
'scheduled_at',
'completed_at',
];

/**
* Get the status of the schedule.
*/
public function status(): Attribute
{
return Attribute::get(function () {
$now = Carbon::now();

return match (true) {
$this->scheduled_at->gte($now) => ScheduleStatusEnum::upcoming,
$this->completed_at === null => ScheduleStatusEnum::in_progress,
default => ScheduleStatusEnum::complete,
};
});
}

/**
* Get the components affected by this schedule.
*/
Expand All @@ -53,7 +68,7 @@ public function formattedMessage(): string
*/
public function scopeIncomplete(Builder $query): Builder
{
return $query->whereIn('status', ScheduleStatusEnum::incomplete())
return $query->whereDate('scheduled_at', '>=', Carbon::now())
->whereNull('completed_at');
}

Expand All @@ -62,35 +77,26 @@ public function scopeIncomplete(Builder $query): Builder
*/
public function scopeInProgress(Builder $query): Builder
{
return $query->where('scheduled_at', '<=', Carbon::now())
->where('status', '=', ScheduleStatusEnum::in_progress)
->whereNull('completed_at');
return $query->whereDate('scheduled_at', '<=', Carbon::now())
->where(function (Builder $query) {
$query->whereDate('completed_at', '>=', Carbon::now())
->orWhereNull('completed_at');
});
}

/**
* Scopes schedules to those in the future.
*/
public function scopeInTheFuture(Builder $query): Builder
{
return $query->whereIn('status', ScheduleStatusEnum::upcoming())
->whereDate('scheduled_at', '>=', Carbon::now());
return $query->whereDate('scheduled_at', '>=', Carbon::now());
}

/**
* Scopes schedules to those scheduled in the past.
*/
public function scopeInThePast(Builder $query): Builder
{
return $query->whereIn('status', ScheduleStatusEnum::upcoming())
->where('scheduled_at', '<=', Carbon::now());
}

/**
* Scopes schedules to those completed in the past.
*/
public function scopeCompletedPreviously(Builder $query): Builder
{
return $query->where('status', '=', ScheduleStatusEnum::complete)
->where('completed_at', '<=', Carbon::now());
return $query->where('completed_at', '<=', Carbon::now());
}
}
Loading

0 comments on commit 53964c5

Please sign in to comment.