TenantAtlas/apps/platform/app/Support/OpsUx/ProviderOperationStartResultPresenter.php
Ahmed Darrazi 34230be79d
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 4m21s
feat: unify provider-backed action dispatch gating
2026-04-20 08:47:08 +02:00

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();
}
}