Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m45s
Implemented the first version of review output resolve actions. Included a ReviewOutputResolveActionMapper, commands to seed browser fixtures, updated CustomerReviewWorkspace, EnvironmentReviewResource, UI enforcement, and related views. Also added extensive unit, feature, and browser tests, and updated the design coverage matrix.
214 lines
7.5 KiB
PHP
214 lines
7.5 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\ReviewOutputResolveActionMapper;
|
|
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,
|
|
* action_name:?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,
|
|
* action_name:?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 $context = [],
|
|
): 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 !== '');
|
|
|
|
$mappedActions = ReviewOutputResolveActionMapper::map(
|
|
review: $review,
|
|
guidance: $guidance,
|
|
sourceSurface: $sourceSurface,
|
|
urls: is_array($context['urls'] ?? null) ? $context['urls'] : [],
|
|
execution: is_array($context['execution'] ?? null) ? $context['execution'] : [],
|
|
);
|
|
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: $mappedActions['primary_action'],
|
|
secondaryActions: $mappedActions['secondary_actions'],
|
|
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,
|
|
* action_name:?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',
|
|
};
|
|
}
|
|
}
|