$diff * @return array */ public static function build(array $diff, string $hostKind): array { $summary = is_array($diff['summary'] ?? null) ? $diff['summary'] : []; $added = is_array($diff['added'] ?? null) ? $diff['added'] : []; $removed = is_array($diff['removed'] ?? null) ? $diff['removed'] : []; $changed = is_array($diff['changed'] ?? null) ? $diff['changed'] : []; $message = is_string($summary['message'] ?? null) && trim((string) $summary['message']) !== '' ? trim((string) $summary['message']) : null; $addedCount = is_numeric($summary['added'] ?? null) ? (int) $summary['added'] : count($added); $removedCount = is_numeric($summary['removed'] ?? null) ? (int) $summary['removed'] : count($removed); $changedCount = is_numeric($summary['changed'] ?? null) ? (int) $summary['changed'] : count($changed); $availabilityState = self::availabilityState($message, $addedCount, $removedCount, $changedCount); return [ 'hostKind' => $hostKind, 'availabilityState' => $availabilityState, 'summary' => [ 'added' => $addedCount, 'removed' => $removedCount, 'changed' => $changedCount, 'message' => $message, ], 'viewModes' => [ ['key' => 'grouped', 'label' => 'Grouped diff', 'default' => true], ], 'sectionBehavior' => [ 'preservesGroupOrder' => true, 'supportsExpansion' => true, 'supportsFullscreen' => true, ], 'renderExpectations' => [ 'ownsAvailabilityState' => true, 'ownsZeroDiffMessaging' => true, 'keepsHostFramingOutsideCore' => true, ], 'groups' => [ self::group('changed', 'Changed', $changed, false), self::group('added', 'Added', $added, true), self::group('removed', 'Removed', $removed, true), ], 'scriptRendering' => [ 'policyType' => $diff['policy_type'] ?? null, 'showScriptContent' => (bool) config('tenantpilot.display.show_script_content', false), ], 'emptyState' => self::emptyState($availabilityState, $message, $addedCount, $removedCount, $changedCount), 'raw' => [ 'added' => $added, 'removed' => $removed, 'changed' => $changed, ], ]; } /** * @param array $items * @return array */ private static function group(string $key, string $label, array $items, bool $collapsed): array { return [ 'key' => $key, 'label' => $label, 'collapsed' => $collapsed, 'count' => count($items), 'items' => self::groupByBlock($items), ]; } /** * @param array $items * @return array> */ private static function groupByBlock(array $items): array { $groups = []; foreach ($items as $path => $value) { if (! is_string($path) || $path === '') { continue; } $parts = explode(' > ', $path, 2); $group = count($parts) === 2 ? $parts[0] : 'Other'; $label = count($parts) === 2 ? $parts[1] : $path; $groups[$group][$label] = $value; } ksort($groups); return $groups; } private static function availabilityState(?string $message, int $addedCount, int $removedCount, int $changedCount): string { if ($message !== null && str_contains(strtolower($message), 'unavailable')) { return 'unavailable'; } if ($message !== null && str_contains(strtolower($message), 'partial')) { return 'partial'; } return 'available'; } /** * @return array{title: string, message: string}|null */ private static function emptyState( string $availabilityState, ?string $message, int $addedCount, int $removedCount, int $changedCount, ): ?array { if ($availabilityState === 'unavailable' && $message !== null) { return [ 'title' => 'Diff unavailable', 'message' => $message, ]; } if ($availabilityState === 'partial' && $message !== null) { return [ 'title' => 'Diff partially available', 'message' => $message, ]; } if ($availabilityState === 'available' && ($addedCount + $removedCount + $changedCount) === 0) { return [ 'title' => 'No normalized changes', 'message' => $message ?? 'No normalized changes were found.', ]; } return null; } }