Fixes and preparation for history detail

This commit is contained in:
Jonatan Rek 2024-08-08 10:33:21 +02:00
parent 6ad2ddeb4a
commit 17616bad17
19 changed files with 213 additions and 17 deletions

View File

@ -8,4 +8,6 @@
class AuthController class AuthController
{ {
use Authentication; use Authentication;
protected string $redirectTo = "dashboard";
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\MaintenanceHistory; use App\Models\MaintenanceHistory;
use Carbon\Carbon;
use Illuminate\Http\Request; use Illuminate\Http\Request;
class MaintenanceController extends BaseController class MaintenanceController extends BaseController
@ -19,6 +20,10 @@ public function planned()
public function plannedDetail(MaintenanceHistory $maintenance_history) public function plannedDetail(MaintenanceHistory $maintenance_history)
{ {
if (!empty($maintenance_history->finished_at)){
abort(404);
}
return view('maintenance.planned-detail', [ return view('maintenance.planned-detail', [
'maintenance_history' => $maintenance_history, 'maintenance_history' => $maintenance_history,
]); ]);
@ -26,9 +31,26 @@ public function plannedDetail(MaintenanceHistory $maintenance_history)
public function plannedDetailPut(Request $request, MaintenanceHistory $maintenance_history) public function plannedDetailPut(Request $request, MaintenanceHistory $maintenance_history)
{ {
if (!empty($maintenance_history->finished_at)){
abort(404);
}
$maintenance_history->finished_at = Carbon::now();
$maintenance_history->save();
return view('maintenance.planned-detail-done', [ return view('maintenance.planned-detail-done', [
'maintenance_history' => $maintenance_history, 'maintenance_history' => $maintenance_history,
'maintenance_state' => $request->input('test'), 'maintenance_task_status' => $request->input('maintenance_task_status'),
]); ]);
} }
public function plannedDetailFinishPost(Request $request, MaintenanceHistory $maintenance_history)
{
dd();
}
public function history(Request $request, MaintenanceHistory $maintenance_history)
{
return view('maintenance.history');
}
} }

View File

@ -26,8 +26,9 @@ public function handle(Request $request, Closure $next): Response
Menu::make('main-menu', function ($menu) { Menu::make('main-menu', function ($menu) {
$systemRoutes = [ $systemRoutes = [
'boilerplate::ui.home' => [' fas fa-home', 'dashboard'], 'ui.dashboard' => [' fas fa-home', 'dashboard'],
'boilerplate::ui.planned' => [' fas fa-home', 'maintenance.planned'], 'ui.planned' => [' fas fa-home', 'maintenance.planned'],
'ui.history' => [' fas fa-home', 'maintenance.history'],
]; ];
foreach ($systemRoutes as $title => $route_data) { foreach ($systemRoutes as $title => $route_data) {

View File

@ -36,6 +36,7 @@ public function handle(): void
$cron = new CronCronExpression($maintenance->schedule); $cron = new CronCronExpression($maintenance->schedule);
$maintenancePlanned = $maintenance->history()->create([ $maintenancePlanned = $maintenance->history()->create([
'start_at' => Carbon::createFromTimestamp($cron->getNext()), 'start_at' => Carbon::createFromTimestamp($cron->getNext()),
'guestor_id' => $maintenance->guestor_id,
]); ]);
$maintenancePlanned->refresh(); $maintenancePlanned->refresh();

View File

@ -22,10 +22,20 @@ public function headers(): array
return [ return [
'name' => 'name', 'name' => 'name',
'description' => 'description', 'description' => 'description',
'schedule' => 'schedule', 'schedule' => 'schedule/offset',
]; ];
} }
public function renderColumnSchedule($value, $row)
{
return e(!empty($value) ? $value : $row['blocking_maintenance_offset']);
}
public function renderColumnDescription($value, $row)
{
return e(!empty($value) ? mb_strimwidth(strip_tags($value), 0, 50, "...") : "");
}
public function remove($maintenance_id){ public function remove($maintenance_id){
Maintenance::find($maintenance_id)->delete(); Maintenance::find($maintenance_id)->delete();
} }

View File

@ -7,6 +7,7 @@
use App\Models\Maintenance; use App\Models\Maintenance;
use App\Models\MaintenanceTask; use App\Models\MaintenanceTask;
use App\Models\Task; use App\Models\Task;
use App\Models\User;
class Form extends Component class Form extends Component
{ {
@ -23,12 +24,26 @@ class Form extends Component
public $hosts_tasks = []; public $hosts_tasks = [];
public $hosts_tasks_available = []; public $hosts_tasks_available = [];
public int $guestor_id;
public $guestor_available = [];
public $blocking_maintenance_id = null;
public $maintenances_available = [];
public $blocking_maintenance_offset = null;
public int $duration = 0;
protected function rules() protected function rules()
{ {
return [ return [
'name' => 'required', 'name' => 'required',
'guestor_id' => 'required|exists:users,id',
'blocking_maintenance_id' => 'exists:maintenances,id|nullable',
'blocking_maintenance_offset' => 'nullable',
'description' => 'required', 'description' => 'required',
'schedule' => 'required', 'schedule' => 'nullable',
'duration' => 'required|max:24',
]; ];
} }
@ -36,6 +51,10 @@ public function mount($model = null)
{ {
$this->hosts_available = Host::all()->pluck('hostname', 'id')->toArray(); $this->hosts_available = Host::all()->pluck('hostname', 'id')->toArray();
$this->hosts_tasks_available = Task::all()->pluck('name', 'id')->toArray(); $this->hosts_tasks_available = Task::all()->pluck('name', 'id')->toArray();
$this->guestor_available = User::all()->pluck('name', 'id')->toArray();
$this->maintenances_available = Maintenance::where('id', '!=', $model)->pluck('name', 'id')->toArray();
$this->maintenances_available = [null => 'Select blocking maintenance...'] + $this->maintenances_available;
if (!empty($model)) { if (!empty($model)) {
$maintenance = Maintenance::find($model); $maintenance = Maintenance::find($model);
@ -45,6 +64,11 @@ public function mount($model = null)
$this->name = $maintenance->name; $this->name = $maintenance->name;
$this->description = $maintenance->description; $this->description = $maintenance->description;
$this->schedule = $maintenance->schedule; $this->schedule = $maintenance->schedule;
$this->guestor_id = $maintenance->guestor_id;
$this->blocking_maintenance_id = $maintenance->blocking_maintenance_id ?? null;
$this->blocking_maintenance_offset = $maintenance->blocking_maintenance_offset ?? null;
$this->duration = $maintenance->duration ;
$this->hosts = $maintenance->hosts()->pluck('hosts.id')->toArray(); $this->hosts = $maintenance->hosts()->pluck('hosts.id')->toArray();
foreach ($maintenance->tasks as $task) { foreach ($maintenance->tasks as $task) {
@ -71,6 +95,7 @@ public function store()
$validatedData = $this->validate(); $validatedData = $this->validate();
$maintenance = Maintenance::create($validatedData); $maintenance = Maintenance::create($validatedData);
$hosts = Host::whereIn('id', $this->hosts)->get(); $hosts = Host::whereIn('id', $this->hosts)->get();
foreach ($hosts as $key => $host) { foreach ($hosts as $key => $host) {
$maintenance->hosts()->attach($host); $maintenance->hosts()->attach($host);
$tasks = Task::whereIn('id', $this->hosts_tasks[$host->id])->get(); $tasks = Task::whereIn('id', $this->hosts_tasks[$host->id])->get();

View File

@ -20,6 +20,9 @@ class ProgressForm extends Component
public function mount(int $maintenanceHistory) public function mount(int $maintenanceHistory)
{ {
$this->maintenanceHistory = self::getMaintenanceHistory($maintenanceHistory); $this->maintenanceHistory = self::getMaintenanceHistory($maintenanceHistory);
if (!empty($this->maintenanceHistory->finished_at)){
abort(404);
}
foreach ($this->maintenanceHistory->historyHosts as $maintenanceHost) { foreach ($this->maintenanceHistory->historyHosts as $maintenanceHost) {
foreach ($maintenanceHost->historyTasks as $maintenanceTask) { foreach ($maintenanceHost->historyTasks as $maintenanceTask) {

View File

@ -8,6 +8,8 @@
class DataTable extends DataTableComponent class DataTable extends DataTableComponent
{ {
public string $type = "planned";
public $listeners = [ public $listeners = [
'maintenanceHistoryAdded' => '$refresh', 'maintenanceHistoryAdded' => '$refresh',
'closeModal' => '$refresh', 'closeModal' => '$refresh',
@ -15,16 +17,31 @@ class DataTable extends DataTableComponent
public function query(): Builder public function query(): Builder
{ {
return MaintenanceHistory::query(); $query = MaintenanceHistory::query();
if ($this->type == "planned") {
$query->whereNull('finished_at');
} elseif ($this->type == "history") {
$query->whereNotNull('finished_at');
}
return $query;
} }
public function headers(): array public function headers(): array
{ {
return [ $headers = [
'maintenance.name' => 'maintenance.name', 'maintenance.name' => 'maintenance.name',
'start_at' => 'start_at', 'start_at' => 'start_at',
'finished_at' => 'finished_at',
]; ];
if ($this->type == "planned") {
$headers['guestor.name'] = 'guestor';
} else {
$headers['finished_at'] = 'finished_at';
}
return $headers;
} }
public function remove($maintenancehistory_id) public function remove($maintenancehistory_id)
@ -34,7 +51,12 @@ public function remove($maintenancehistory_id)
public function renderColumnMaintenanceName($val, $row) public function renderColumnMaintenanceName($val, $row)
{ {
if ($this->type == "planned") {
$ret = '<a href="' . route('maintenance.planned.detail', $row['id']) . '">' . e($val) . '</a>'; $ret = '<a href="' . route('maintenance.planned.detail', $row['id']) . '">' . e($val) . '</a>';
} else {
$ret = '<a href="' . route('maintenance.history.detail', $row['id']) . '">' . e($val) . '</a>';
}
return $ret; return $ret;
} }

View File

@ -25,6 +25,11 @@ public function headers(): array
]; ];
} }
public function renderColumnDescription($value, $row)
{
return e(!empty($value) ? mb_strimwidth(strip_tags($value), 0, 50, "...") : "");
}
public function remove($task_id){ public function remove($task_id){
Task::find($task_id)->delete(); Task::find($task_id)->delete();
} }

View File

@ -13,6 +13,10 @@ class Maintenance extends Model
'name', 'name',
'description', 'description',
'schedule', 'schedule',
'guestor_id',
'blocking_maintenance_id',
'duration',
'blocking_maintenance_offset',
]; ];
public function hosts() public function hosts()
@ -29,4 +33,9 @@ public function tasks()
{ {
return $this->hasMany(MaintenanceTask::class,); return $this->hasMany(MaintenanceTask::class,);
} }
public function guestor()
{
return $this->BelongsTo(User::class, 'guestor_id');
}
} }

View File

@ -13,6 +13,7 @@ class MaintenanceHistory extends Model
'maintenance_id', 'maintenance_id',
'start_at', 'start_at',
'finished_at', 'finished_at',
'guestor_id',
]; ];
public function maintenance() public function maintenance()
@ -24,4 +25,9 @@ public function historyHosts()
{ {
return $this->hasMany(MaintenanceHostHistory::class); return $this->hasMany(MaintenanceHostHistory::class);
} }
public function guestor()
{
return $this->BelongsTo(User::class, 'guestor_id');
}
} }

View File

@ -0,0 +1,33 @@
<?php
use App\Models\Maintenance;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('maintenances', function (Blueprint $table) {
$table->foreignIdFor(User::class, 'guestor_id');
$table->foreignIdFor(Maintenance::class, 'blocking_maintenance_id')->nullable();
$table->string('blocking_maintenance_offset')->nullable();
$table->integer('duration');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('maintenances', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('maintenance_histories', function (Blueprint $table) {
$table->foreignIdFor(User::class, 'guestor_id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('maintenance_histories', function (Blueprint $table) {
});
}
};

7
lang/en/ui.php Normal file
View File

@ -0,0 +1,7 @@
<?php
return [
'dashboard' => 'Dashboard',
'planned' => 'Planned',
'history' => 'History',
];

View File

@ -1,8 +1,17 @@
<div> <div>
<x-form::form wire:submit.prevent="{{ $action }}"> <x-form::form wire:submit.prevent="{{ $action }}">
<x-form::input group-class="mb-3" type="text" wire:model="name" id="name" label="name" /> <x-form::input group-class="mb-3" type="text" wire:model="name" id="name" label="name" />
<x-form::select group-class="mb-3" wire:model="guestor_id" label="Livewire Select" :options="$guestor_available" placeholder="Select guestor..." />
<x-form::select group-class="mb-3" wire:model.live="blocking_maintenance_id" label="Livewire Select" :options="$maintenances_available" placeholder="Select blocking maintenance..." />
<x-form::quill group-class="mb-3" type="text" wire:model="description" id="description" label="description" /> <x-form::quill group-class="mb-3" type="text" wire:model="description" id="description" label="description" />
@if(empty($blocking_maintenance_id))
<x-form::input group-class="mb-3" type="text" wire:model="schedule" id="schedule" label="schedule" /> <x-form::input group-class="mb-3" type="text" wire:model="schedule" id="schedule" label="schedule" />
@else
<x-form::input group-class="mb-3" type="text" wire:model="blocking_maintenance_offset" id="blocking_maintenance_offset" label="blocking_maintenance_offset" help="you can use foloving shortcodes (w - weeks, m - months, d - days)" />
@endif
<x-form::input group-class="mb-3" type="text" wire:model="duration" id="duration" label="duration" help="in hours (60 minutes) maximum 24h" />
<x-form::select group-class="mb-3" wire:model.live="hosts" label="Livewire Select" :options="$hosts_available" placeholder="Select value..." multiple /> <x-form::select group-class="mb-3" wire:model.live="hosts" label="Livewire Select" :options="$hosts_available" placeholder="Select value..." multiple />
@foreach($hosts as $key => $host_id) @foreach($hosts as $key => $host_id)

View File

@ -8,7 +8,7 @@
<div class="collapse" id="collapse{{ $historyHost->id }}" wire:ignore.self> <div class="collapse" id="collapse{{ $historyHost->id }}" wire:ignore.self>
<div class="card card-body mt-2"> <div class="card card-body mt-2">
@foreach ($historyHost->historyTasks as $historyTasks) @foreach ($historyHost->historyTasks as $historyTasks)
<x-form::checkbox wire:key="{{ $historyHost->id . $historyTasks->id }}" wire:model.live.debounce.250ms="maintenance_task_status.{{ $historyHost->id }}.{{ $historyTasks->id }}" name="test[{{ $historyHost->id }}][{{ $historyTasks->id }}]" id="test-{{ $historyHost->id }}-{{ $historyTasks->id }}" label="{{ $historyTasks->maintenanceTask->task->name }}" /> <x-form::checkbox wire:key="{{ $historyHost->id . $historyTasks->id }}" wire:model.live.debounce.250ms="maintenance_task_status.{{ $historyHost->id }}.{{ $historyTasks->id }}" name="maintenance_task_status[{{ $historyHost->id }}][{{ $historyTasks->id }}]" id="maintenance_task_status-{{ $historyHost->id }}-{{ $historyTasks->id }}" label="{{ $historyTasks->maintenanceTask->task->name }}" />
<p>{!! $historyTasks->maintenanceTask->task->description !!}</p> <p>{!! $historyTasks->maintenanceTask->task->description !!}</p>
@endforeach @endforeach
</div> </div>

View File

@ -0,0 +1,9 @@
<x-layout-app>
<div class="container-xl">
<div class="page-header">
<h1>{{ __('History') }}</h1>
</div>
@livewire('maintenance-history.data-table', ['type' => 'history'], key('data-table'))
</div>
</x-layout-app>

View File

@ -7,7 +7,10 @@
@foreach ($maintenance_history->historyHosts as $historyHost) @foreach ($maintenance_history->historyHosts as $historyHost)
<b>{{ $historyHost->host->hostname }}</b> <b>{{ $historyHost->host->hostname }}</b>
@foreach ($historyHost->historyTasks as $historyTasks) @foreach ($historyHost->historyTasks as $historyTasks)
<x-form::checkbox onclick="return false" checked="{{ isset($maintenance_state[$historyHost->id][$historyTasks->id]) ? 'checked' : '' }}" label="{{ $historyTasks->maintenanceTask->task->name }}" name="test-{{ $historyHost->id }}-{{ $historyTasks->id }}" /> <x-form::checkbox onclick="return false" checked="{{ isset($maintenance_task_status[$historyHost->id][$historyTasks->id]) ? 'checked' : '' }}" label="{{ $historyTasks->maintenanceTask->task->name }}" name="test-{{ $historyHost->id }}-{{ $historyTasks->id }}" />
@if(!isset($maintenance_task_status[$historyHost->id][$historyTasks->id]))
<x-form::quill />
@endif
@endforeach @endforeach
@endforeach @endforeach
</div> </div>

View File

@ -11,6 +11,7 @@
Route::get('/maintenance/planned', [App\Http\Controllers\MaintenanceController::class, 'planned'])->name('maintenance.planned'); Route::get('/maintenance/planned', [App\Http\Controllers\MaintenanceController::class, 'planned'])->name('maintenance.planned');
Route::get('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetail'])->name('maintenance.planned.detail'); Route::get('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetail'])->name('maintenance.planned.detail');
Route::put('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailPut'])->name('maintenance.planned.detail.put'); Route::put('/maintenance/planned/{maintenance_history}', [App\Http\Controllers\MaintenanceController::class, 'plannedDetailPut'])->name('maintenance.planned.detail.put');
Route::get('/maintenance/history/', [App\Http\Controllers\MaintenanceController::class, 'history'])->name('maintenance.history');
Route::get('/host', [App\Http\Controllers\HostController::class, 'index'])->name('host'); Route::get('/host', [App\Http\Controllers\HostController::class, 'index'])->name('host');