Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 59s
Implemented the first version of the operator resolution guidance framework. Added new foundation classes (ResolutionCase, ResolutionAction) and a ReviewPackOutputResolutionAdapter. Updated the Customer Review Workspace and Environment Review Resource to use the new adapter. Added extensive test coverage for the framework and UI integrations.
204 lines
7.2 KiB
PHP
204 lines
7.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\ResolutionGuidance\Adapters;
|
|
|
|
use App\Models\EnvironmentReview;
|
|
use App\Models\EvidenceSnapshot;
|
|
use App\Models\ReviewPack;
|
|
use App\Support\ResolutionGuidance\ResolutionAction;
|
|
use App\Support\ResolutionGuidance\ResolutionCase;
|
|
use App\Support\ReviewPacks\ReviewPackOutputResolutionGuidance;
|
|
|
|
final class ReviewPackOutputResolutionAdapter
|
|
{
|
|
/**
|
|
* @param array<string, mixed> $guidance
|
|
* @return array{
|
|
* key:string,
|
|
* scope:array<string, int|string>,
|
|
* severity:string,
|
|
* status:string,
|
|
* title:string,
|
|
* reason:string,
|
|
* impact:string,
|
|
* primary_action:array{
|
|
* key:string,
|
|
* label:string,
|
|
* type:string,
|
|
* url:?string,
|
|
* icon:string,
|
|
* kind:string,
|
|
* capability:?string,
|
|
* requires_confirmation:bool,
|
|
* audit_event:?string,
|
|
* operation_run_type:?string,
|
|
* disabled_reason:?string
|
|
* },
|
|
* secondary_actions:list<array{
|
|
* key:string,
|
|
* label:string,
|
|
* type:string,
|
|
* url:?string,
|
|
* icon:string,
|
|
* kind:string,
|
|
* capability:?string,
|
|
* requires_confirmation:bool,
|
|
* audit_event:?string,
|
|
* operation_run_type:?string,
|
|
* disabled_reason:?string
|
|
* }>,
|
|
* source_refs:list<array{type:string,id:int|string}>,
|
|
* evidence_refs:list<array{type:string,id:int|string}>,
|
|
* technical_details:array<string, string>
|
|
* }
|
|
*/
|
|
public static function fromGuidance(EnvironmentReview $review, array $guidance, string $sourceSurface): array
|
|
{
|
|
$scope = array_filter([
|
|
'type' => 'review_pack',
|
|
'workspace_id' => (int) $review->workspace_id,
|
|
'managed_environment_id' => (int) $review->managed_environment_id,
|
|
'environment_review_id' => (int) $review->getKey(),
|
|
'review_pack_id' => $review->currentExportReviewPack instanceof ReviewPack
|
|
? (int) $review->currentExportReviewPack->getKey()
|
|
: '',
|
|
'source_surface' => $sourceSurface,
|
|
], static fn (mixed $value): bool => $value !== null && $value !== '');
|
|
|
|
$primaryAction = ResolutionAction::fromArray(
|
|
is_array($guidance['primary_action'] ?? null) ? $guidance['primary_action'] : null,
|
|
self::caseKey((string) ($guidance['state'] ?? ReviewPackOutputResolutionGuidance::STATE_UNKNOWN)).'.primary_action',
|
|
__('localization.review.review_output_limitations'),
|
|
);
|
|
|
|
return ResolutionCase::make(
|
|
key: self::caseKey((string) ($guidance['state'] ?? ReviewPackOutputResolutionGuidance::STATE_UNKNOWN)),
|
|
scope: $scope,
|
|
severity: self::severity((string) ($guidance['state'] ?? ReviewPackOutputResolutionGuidance::STATE_UNKNOWN)),
|
|
status: self::status((string) ($guidance['state'] ?? ReviewPackOutputResolutionGuidance::STATE_UNKNOWN)),
|
|
title: (string) ($guidance['label'] ?? __('localization.review.requires_review')),
|
|
reason: (string) ($guidance['primary_reason'] ?? __('localization.review.review_pack_with_limitations_description')),
|
|
impact: (string) ($guidance['impact'] ?? __('localization.review.published_with_limitations_impact')),
|
|
primaryAction: $primaryAction,
|
|
secondaryActions: self::secondaryActions($guidance),
|
|
sourceRefs: self::sourceRefs($review),
|
|
evidenceRefs: self::evidenceRefs($review),
|
|
technicalDetails: self::technicalDetails($guidance),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $guidance
|
|
* @return list<array{
|
|
* key:string,
|
|
* label:string,
|
|
* type:string,
|
|
* url:?string,
|
|
* icon:string,
|
|
* kind:string,
|
|
* capability:?string,
|
|
* requires_confirmation:bool,
|
|
* audit_event:?string,
|
|
* operation_run_type:?string,
|
|
* disabled_reason:?string
|
|
* }>
|
|
*/
|
|
private static function secondaryActions(array $guidance): array
|
|
{
|
|
$secondaryActions = is_array($guidance['secondary_actions'] ?? null) ? $guidance['secondary_actions'] : [];
|
|
|
|
return array_values(array_map(
|
|
static fn (array $action, int $index): array => ResolutionAction::fromArray(
|
|
$action,
|
|
self::caseKey((string) ($guidance['state'] ?? ReviewPackOutputResolutionGuidance::STATE_UNKNOWN)).'.secondary_action_'.$index,
|
|
__('localization.review.review_output_limitations'),
|
|
),
|
|
array_values(array_filter($secondaryActions, static fn (mixed $action): bool => is_array($action))),
|
|
array_keys(array_values(array_filter($secondaryActions, static fn (mixed $action): bool => is_array($action)))),
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @return list<array{type:string,id:int|string}>
|
|
*/
|
|
private static function sourceRefs(EnvironmentReview $review): array
|
|
{
|
|
$refs = [
|
|
[
|
|
'type' => 'environment_review',
|
|
'id' => (int) $review->getKey(),
|
|
],
|
|
];
|
|
|
|
if ($review->currentExportReviewPack instanceof ReviewPack) {
|
|
$refs[] = [
|
|
'type' => 'review_pack',
|
|
'id' => (int) $review->currentExportReviewPack->getKey(),
|
|
];
|
|
}
|
|
|
|
if ($review->operationRun !== null) {
|
|
$refs[] = [
|
|
'type' => 'operation_run',
|
|
'id' => (int) $review->operationRun->getKey(),
|
|
];
|
|
}
|
|
|
|
return $refs;
|
|
}
|
|
|
|
/**
|
|
* @return list<array{type:string,id:int|string}>
|
|
*/
|
|
private static function evidenceRefs(EnvironmentReview $review): array
|
|
{
|
|
if (! $review->evidenceSnapshot instanceof EvidenceSnapshot) {
|
|
return [];
|
|
}
|
|
|
|
return [[
|
|
'type' => 'evidence_snapshot',
|
|
'id' => (int) $review->evidenceSnapshot->getKey(),
|
|
]];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $guidance
|
|
* @return array<string, string>
|
|
*/
|
|
private static function technicalDetails(array $guidance): array
|
|
{
|
|
return array_filter(
|
|
is_array($guidance['technical_details'] ?? null) ? $guidance['technical_details'] : [],
|
|
static fn (mixed $value): bool => is_string($value) && $value !== '',
|
|
);
|
|
}
|
|
|
|
private static function caseKey(string $state): string
|
|
{
|
|
return 'review_output.'.$state;
|
|
}
|
|
|
|
private static function severity(string $state): string
|
|
{
|
|
return match ($state) {
|
|
ReviewPackOutputResolutionGuidance::STATE_CUSTOMER_SAFE_READY => 'success',
|
|
ReviewPackOutputResolutionGuidance::STATE_PUBLICATION_BLOCKED => 'critical',
|
|
default => 'warning',
|
|
};
|
|
}
|
|
|
|
private static function status(string $state): string
|
|
{
|
|
return match ($state) {
|
|
ReviewPackOutputResolutionGuidance::STATE_CUSTOMER_SAFE_READY => 'ready',
|
|
ReviewPackOutputResolutionGuidance::STATE_PUBLICATION_BLOCKED,
|
|
ReviewPackOutputResolutionGuidance::STATE_EXPORT_NOT_READY => 'blocked',
|
|
ReviewPackOutputResolutionGuidance::STATE_UNKNOWN => 'unknown',
|
|
default => 'action_required',
|
|
};
|
|
}
|
|
}
|