## Summary - add the Evidence Snapshot domain with immutable tenant-scoped snapshots, per-dimension items, queued generation, audit actions, badge mappings, and Filament list/detail surfaces - add the workspace evidence overview, capability and policy wiring, Livewire update-path hardening, and review-pack integration through explicit evidence snapshot resolution - add spec 153 artifacts, migrations, factories, and focused Pest coverage for evidence, review-pack reuse, authorization, action-surface regressions, and audit behavior ## Testing - `vendor/bin/sail artisan test --compact --stop-on-failure` - `CI=1 vendor/bin/sail artisan test --compact` - `vendor/bin/sail bin pint --dirty --format agent` ## Notes - branch: `153-evidence-domain-foundation` - commit: `b7dfa279` - spec: `specs/153-evidence-domain-foundation/` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #183
103 lines
3.8 KiB
PHP
103 lines
3.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Resources\EvidenceSnapshotResource\Pages;
|
|
|
|
use App\Filament\Resources\EvidenceSnapshotResource;
|
|
use App\Filament\Resources\ReviewPackResource;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\User;
|
|
use App\Services\Evidence\EvidenceSnapshotService;
|
|
use App\Support\Auth\Capabilities;
|
|
use App\Support\OperationRunLinks;
|
|
use App\Support\Rbac\UiEnforcement;
|
|
use Filament\Actions;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Resources\Pages\ViewRecord;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class ViewEvidenceSnapshot extends ViewRecord
|
|
{
|
|
protected static string $resource = EvidenceSnapshotResource::class;
|
|
|
|
protected function resolveRecord(int|string $key): Model
|
|
{
|
|
return EvidenceSnapshotResource::resolveScopedRecordOrFail($key);
|
|
}
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Actions\Action::make('view_run')
|
|
->label('View run')
|
|
->icon('heroicon-o-eye')
|
|
->color('gray')
|
|
->url(fn (): ?string => $this->record->operation_run_id ? OperationRunLinks::tenantlessView((int) $this->record->operation_run_id) : null)
|
|
->hidden(fn (): bool => ! is_numeric($this->record->operation_run_id)),
|
|
Actions\Action::make('view_review_pack')
|
|
->label('View review pack')
|
|
->icon('heroicon-o-document-text')
|
|
->color('gray')
|
|
->url(function (): ?string {
|
|
$pack = $this->latestReviewPack();
|
|
|
|
if (! $pack instanceof ReviewPack || ! $pack->tenant) {
|
|
return null;
|
|
}
|
|
|
|
return ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $pack->tenant);
|
|
})
|
|
->hidden(fn (): bool => ! $this->latestReviewPack() instanceof ReviewPack),
|
|
UiEnforcement::forAction(
|
|
Actions\Action::make('refresh_snapshot')
|
|
->label('Refresh evidence')
|
|
->icon('heroicon-o-arrow-path')
|
|
->requiresConfirmation()
|
|
->action(function (): void {
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
app(EvidenceSnapshotService::class)->refresh($this->record, $user);
|
|
|
|
Notification::make()->success()->title('Refresh evidence queued')->send();
|
|
}),
|
|
)
|
|
->requireCapability(Capabilities::EVIDENCE_MANAGE)
|
|
->apply(),
|
|
UiEnforcement::forAction(
|
|
Actions\Action::make('expire_snapshot')
|
|
->label('Expire snapshot')
|
|
->icon('heroicon-o-x-circle')
|
|
->color('danger')
|
|
->hidden(fn (): bool => ! EvidenceSnapshotResource::canExpireRecord($this->record))
|
|
->requiresConfirmation()
|
|
->action(function (): void {
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
app(EvidenceSnapshotService::class)->expire($this->record, $user);
|
|
$this->refreshFormData(['status', 'expires_at']);
|
|
|
|
Notification::make()->success()->title('Snapshot expired')->send();
|
|
}),
|
|
)
|
|
->requireCapability(Capabilities::EVIDENCE_MANAGE)
|
|
->apply(),
|
|
];
|
|
}
|
|
|
|
private function latestReviewPack(): ?ReviewPack
|
|
{
|
|
return $this->record->reviewPacks()
|
|
->latest('created_at')
|
|
->first();
|
|
}
|
|
}
|