*/ public static function knownValues(): array { return array_map( static fn (self $case): string => $case->value, self::cases(), ); } public static function labelFor(string|self $action): string { $value = $action instanceof self ? $action->value : trim($action); return self::labels()[$value] ?? self::humanize($value); } /** * @param array $context */ public static function summaryFor( string|self $action, ?string $targetLabel = null, ?string $targetType = null, array $context = [], ): string { $value = $action instanceof self ? $action->value : trim($action); $summary = self::summaries()[$value] ?? self::labelFor($value); if ($targetLabel !== null && $targetLabel !== '' && ! str_contains($summary, $targetLabel)) { $summary .= ' for '.$targetLabel; } elseif (($targetLabel === null || $targetLabel === '') && filled($targetType)) { $summary .= ' for '.self::humanize((string) $targetType); } if (($context['after_status'] ?? null) !== null && ($context['before_status'] ?? null) !== null && ! str_contains($summary, 'status')) { return sprintf( '%s (%s -> %s)', $summary, (string) $context['before_status'], (string) $context['after_status'], ); } return $summary; } /** * @return array */ private static function labels(): array { return [ self::WorkspaceMembershipAdd->value => 'Workspace member add', self::WorkspaceMembershipRoleChange->value => 'Workspace member role change', self::WorkspaceMembershipRemove->value => 'Workspace member removal', self::WorkspaceMembershipLastOwnerBlocked->value => 'Workspace last-owner protection', self::TenantArchived->value => 'Tenant archived', self::TenantRestored->value => 'Tenant restored', self::TenantReturnedToDraft->value => 'Tenant returned to draft', self::TenantMembershipAdd->value => 'Tenant member add', self::TenantMembershipRoleChange->value => 'Tenant member role change', self::TenantMembershipRemove->value => 'Tenant member removal', self::TenantMembershipLastOwnerBlocked->value => 'Tenant last-owner protection', self::ManagedTenantOnboardingStart->value => 'Managed tenant onboarding start', self::ManagedTenantOnboardingResume->value => 'Managed tenant onboarding resume', self::ManagedTenantOnboardingDraftSelected->value => 'Managed tenant onboarding draft selected', self::ManagedTenantOnboardingDraftUpdated->value => 'Managed tenant onboarding draft updated', self::ManagedTenantOnboardingProviderConnectionChanged->value => 'Managed tenant onboarding provider connection changed', self::ManagedTenantOnboardingVerificationStart->value => 'Managed tenant onboarding verification start', self::ManagedTenantOnboardingVerificationPersisted->value => 'Managed tenant onboarding verification persisted', self::ManagedTenantOnboardingBootstrapStarted->value => 'Managed tenant onboarding bootstrap started', self::ManagedTenantOnboardingCancelled->value => 'Managed tenant onboarding cancelled', self::ManagedTenantOnboardingDeleted->value => 'Managed tenant onboarding deleted', self::ManagedTenantOnboardingActivationOverrideUsed->value => 'Managed tenant onboarding activation override used', self::ManagedTenantOnboardingActivation->value => 'Managed tenant onboarding activation', self::VerificationCompleted->value => 'Verification completed', self::VerificationCheckAcknowledged->value => 'Verification check acknowledged', self::AlertDestinationCreated->value => 'Alert destination created', self::AlertDestinationUpdated->value => 'Alert destination updated', self::AlertDestinationDeleted->value => 'Alert destination deleted', self::AlertDestinationEnabled->value => 'Alert destination enabled', self::AlertDestinationDisabled->value => 'Alert destination disabled', self::AlertDestinationTestRequested->value => 'Alert destination test requested', self::AlertRuleCreated->value => 'Alert rule created', self::AlertRuleUpdated->value => 'Alert rule updated', self::AlertRuleDeleted->value => 'Alert rule deleted', self::AlertRuleEnabled->value => 'Alert rule enabled', self::AlertRuleDisabled->value => 'Alert rule disabled', self::WorkspaceSettingUpdated->value => 'Workspace setting updated', self::WorkspaceSettingReset->value => 'Workspace setting reset', self::BaselineProfileCreated->value => 'Baseline profile created', self::BaselineProfileUpdated->value => 'Baseline profile updated', self::BaselineProfileArchived->value => 'Baseline profile archived', self::BaselineCaptureStarted->value => 'Baseline capture started', self::BaselineCaptureCompleted->value => 'Baseline capture completed', self::BaselineCaptureFailed->value => 'Baseline capture failed', self::BaselineCompareStarted->value => 'Baseline compare started', self::BaselineCompareCompleted->value => 'Baseline compare completed', self::BaselineCompareFailed->value => 'Baseline compare failed', self::BaselineAssignmentCreated->value => 'Baseline assignment created', self::BaselineAssignmentUpdated->value => 'Baseline assignment updated', self::BaselineAssignmentDeleted->value => 'Baseline assignment deleted', self::WorkspaceAutoSelected->value => 'Workspace auto-selected', self::WorkspaceSelected->value => 'Workspace selected', self::FindingTriaged->value => 'Finding triaged', self::FindingInProgress->value => 'Finding moved to in progress', self::FindingAssigned->value => 'Finding assignment updated', self::FindingResolved->value => 'Finding resolved', self::FindingClosed->value => 'Finding closed', self::FindingRiskAccepted->value => 'Finding risk accepted', self::FindingReopened->value => 'Finding reopened', self::FindingExceptionRequested->value => 'Finding exception requested', self::FindingExceptionApproved->value => 'Finding exception approved', self::FindingExceptionRejected->value => 'Finding exception rejected', self::FindingExceptionRenewalRequested->value => 'Finding exception renewal requested', self::FindingExceptionRenewed->value => 'Finding exception renewed', self::FindingExceptionRevoked->value => 'Finding exception revoked', self::EvidenceSnapshotCreated->value => 'Evidence snapshot created', self::EvidenceSnapshotRefreshed->value => 'Evidence snapshot refreshed', self::EvidenceSnapshotExpired->value => 'Evidence snapshot expired', self::TenantReviewCreated->value => 'Tenant review created', self::TenantReviewRefreshed->value => 'Tenant review refreshed', self::TenantReviewPublished->value => 'Tenant review published', self::TenantReviewArchived->value => 'Tenant review archived', self::TenantReviewExported->value => 'Tenant review exported', self::TenantReviewSuccessorCreated->value => 'Tenant review next cycle created', 'baseline.capture.started' => 'Baseline capture started', 'baseline.capture.completed' => 'Baseline capture completed', 'baseline.capture.failed' => 'Baseline capture failed', 'baseline.compare.started' => 'Baseline compare started', 'baseline.compare.completed' => 'Baseline compare completed', 'baseline.compare.failed' => 'Baseline compare failed', 'baseline.evidence.resume.started' => 'Baseline evidence capture resumed', 'backup.created' => 'Backup set created', 'backup.updated' => 'Backup set updated', 'backup.archived' => 'Backup set archived', 'backup.items_added' => 'Backup set items added', 'backup.assignments.included' => 'Backup set assignments included', 'backup_schedule.run_started' => 'Backup schedule run started', 'backup_schedule.run_finished' => 'Backup schedule run finished', 'backup_schedule.run_failed' => 'Backup schedule run failed', 'backup_schedule.run_skipped' => 'Backup schedule run skipped', 'backup_schedule.retention_applied' => 'Backup schedule retention applied', 'restore.started' => 'Restore started', 'restore.previewed' => 'Restore preview completed', 'restore.executed' => 'Restore executed', 'restore.failed' => 'Restore failed', 'restore.assignments.summary' => 'Restore assignment summary recorded', 'restore.group_mapping.applied' => 'Restore group mapping applied', 'operation.completed' => 'Operation completed', 'operation.failed' => 'Operation failed', 'operation.partial' => 'Operation partially completed', 'operation.blocked' => 'Operation blocked', ]; } /** * @return array */ private static function summaries(): array { return [ self::WorkspaceMembershipAdd->value => 'Workspace member added', self::WorkspaceMembershipRoleChange->value => 'Workspace member role changed', self::WorkspaceMembershipRemove->value => 'Workspace member removed', self::WorkspaceMembershipLastOwnerBlocked->value => 'Workspace last-owner protection triggered', self::TenantArchived->value => 'Tenant archived', self::TenantRestored->value => 'Tenant restored', self::TenantReturnedToDraft->value => 'Tenant returned to draft', self::TenantMembershipAdd->value => 'Tenant member added', self::TenantMembershipRoleChange->value => 'Tenant member role changed', self::TenantMembershipRemove->value => 'Tenant member removed', self::TenantMembershipLastOwnerBlocked->value => 'Tenant last-owner protection triggered', self::WorkspaceSettingUpdated->value => 'Workspace setting updated', self::WorkspaceSettingReset->value => 'Workspace setting reset', self::BaselineProfileCreated->value => 'Baseline profile created', self::BaselineProfileUpdated->value => 'Baseline profile updated', self::BaselineProfileArchived->value => 'Baseline profile archived', self::AlertDestinationCreated->value => 'Alert destination created', self::AlertDestinationUpdated->value => 'Alert destination updated', self::AlertDestinationDeleted->value => 'Alert destination deleted', self::AlertRuleCreated->value => 'Alert rule created', self::AlertRuleUpdated->value => 'Alert rule updated', self::AlertRuleDeleted->value => 'Alert rule deleted', self::FindingTriaged->value => 'Finding triaged', self::FindingInProgress->value => 'Finding moved to in progress', self::FindingAssigned->value => 'Finding assignment updated', self::FindingResolved->value => 'Finding resolved', self::FindingClosed->value => 'Finding closed', self::FindingRiskAccepted->value => 'Finding risk accepted', self::FindingReopened->value => 'Finding reopened', self::FindingExceptionRequested->value => 'Finding exception requested', self::FindingExceptionApproved->value => 'Finding exception approved', self::FindingExceptionRejected->value => 'Finding exception rejected', self::FindingExceptionRenewalRequested->value => 'Finding exception renewal requested', self::FindingExceptionRenewed->value => 'Finding exception renewed', self::FindingExceptionRevoked->value => 'Finding exception revoked', self::EvidenceSnapshotCreated->value => 'Evidence snapshot created', self::EvidenceSnapshotRefreshed->value => 'Evidence snapshot refreshed', self::EvidenceSnapshotExpired->value => 'Evidence snapshot expired', self::TenantReviewCreated->value => 'Tenant review created', self::TenantReviewRefreshed->value => 'Tenant review refreshed', self::TenantReviewPublished->value => 'Tenant review published', self::TenantReviewArchived->value => 'Tenant review archived', self::TenantReviewExported->value => 'Tenant review exported', self::TenantReviewSuccessorCreated->value => 'Tenant review next cycle created', ]; } private static function humanize(string $value): string { $normalized = str_replace(['.', '_', '-'], ' ', trim($value)); $normalized = preg_replace('/\s+/', ' ', $normalized) ?? $normalized; return ucfirst($normalized); } }