96 lines
3.4 KiB
PHP
96 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\OpsUx;
|
|
|
|
use App\Services\Providers\ProviderOperationStartResult;
|
|
use App\Support\OperationRunLinks;
|
|
use App\Support\ReasonTranslation\NextStepOption;
|
|
use App\Support\ReasonTranslation\ReasonPresenter;
|
|
use Filament\Actions\Action;
|
|
use Filament\Notifications\Notification as FilamentNotification;
|
|
|
|
final class ProviderOperationStartResultPresenter
|
|
{
|
|
public function __construct(
|
|
private readonly ReasonPresenter $reasonPresenter,
|
|
) {}
|
|
|
|
/**
|
|
* @param array<int, Action> $extraActions
|
|
*/
|
|
public function notification(
|
|
ProviderOperationStartResult $result,
|
|
string $blockedTitle,
|
|
string $runUrl,
|
|
array $extraActions = [],
|
|
string $scopeBusyTitle = 'Scope busy',
|
|
string $scopeBusyBody = 'Another provider-backed operation is already running for this scope. Open the active operation for progress and next steps.',
|
|
): FilamentNotification {
|
|
$notification = match ($result->status) {
|
|
'started' => OperationUxPresenter::queuedToast((string) $result->run->type),
|
|
'deduped' => OperationUxPresenter::alreadyRunningToast((string) $result->run->type),
|
|
'scope_busy' => OperationUxPresenter::scopeBusyToast($scopeBusyTitle, $scopeBusyBody),
|
|
'blocked' => FilamentNotification::make()
|
|
->title($blockedTitle)
|
|
->body(implode("\n", $this->blockedBodyLines($result)))
|
|
->warning(),
|
|
default => OperationUxPresenter::queuedToast((string) $result->run->type),
|
|
};
|
|
|
|
return $notification->actions($this->actionsFor($result, $runUrl, $extraActions));
|
|
}
|
|
|
|
/**
|
|
* @param array<int, Action> $extraActions
|
|
* @return array<int, Action>
|
|
*/
|
|
private function actionsFor(ProviderOperationStartResult $result, string $runUrl, array $extraActions): array
|
|
{
|
|
$actions = [
|
|
Action::make('view_run')
|
|
->label(OperationRunLinks::openLabel())
|
|
->url($runUrl),
|
|
];
|
|
|
|
if ($result->status === 'blocked') {
|
|
$nextStep = $this->firstNextStep($result);
|
|
|
|
if ($nextStep instanceof NextStepOption && $nextStep->kind === 'link' && is_string($nextStep->destination) && trim($nextStep->destination) !== '') {
|
|
$actions[] = Action::make('next_step_0')
|
|
->label($nextStep->label)
|
|
->url($nextStep->destination);
|
|
}
|
|
}
|
|
|
|
return [...$actions, ...$extraActions];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, string>
|
|
*/
|
|
private function blockedBodyLines(ProviderOperationStartResult $result): array
|
|
{
|
|
$reasonEnvelope = $this->reasonPresenter->forOperationRun($result->run, 'notification');
|
|
|
|
return $reasonEnvelope?->toBodyLines() ?? ['Blocked by provider configuration.'];
|
|
}
|
|
|
|
private function firstNextStep(ProviderOperationStartResult $result): ?NextStepOption
|
|
{
|
|
$nextSteps = is_array($result->run->context['next_steps'] ?? null)
|
|
? $result->run->context['next_steps']
|
|
: [];
|
|
|
|
$storedNextStep = NextStepOption::collect($nextSteps)[0] ?? null;
|
|
|
|
if ($storedNextStep instanceof NextStepOption) {
|
|
return $storedNextStep;
|
|
}
|
|
|
|
$reasonEnvelope = $this->reasonPresenter->forOperationRun($result->run, 'notification');
|
|
|
|
return $reasonEnvelope?->firstNextStep();
|
|
}
|
|
} |