AI & workflows
Ai Change Set code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/ai-change-set.blade.php
@props([
'files' => [],
'title' => 'Changes this run',
'embedded' => false,
'navigate' => false,
'selectedPath' => null,
])
@php
/*
| Files changed during an agent iteration.
|
| status per file: added, modified, deleted
|
| Set `navigate` to link each row via the file `href` key.
|
| Usage:
| <x-ui.ai-change-set :files="[
| ['path' => 'tests/Feature/WorkflowComponentsTest.php', 'status' => 'modified', 'additions' => 24, 'deletions' => 3],
| ]" />
*/
$statusLabels = [
'added' => 'Added',
'modified' => 'Modified',
'deleted' => 'Deleted',
];
$statusVariants = [
'added' => 'green',
'modified' => 'brand',
'deleted' => 'red',
];
$itemClass = fn (bool $isSelected): string => \Illuminate\Support\Arr::toCssClasses([
'flex flex-col gap-2 px-4 py-3 transition sm:flex-row sm:items-center sm:justify-between sm:px-5',
'bg-brand-50/70 dark:bg-brand-950/20' => $isSelected,
'hover:bg-gray-50 dark:hover:bg-gray-950/60' => $navigate && ! $isSelected,
]);
$normalizedFiles = collect($files)
->map(function ($file) {
return [
'path' => $file['path'] ?? '',
'status' => $file['status'] ?? 'modified',
'additions' => isset($file['additions']) ? (int) $file['additions'] : null,
'deletions' => isset($file['deletions']) ? (int) $file['deletions'] : null,
'href' => $file['href'] ?? null,
];
})
->filter(fn (array $file) => $file['path'] !== '')
->values()
->all();
@endphp
<div {{ $attributes->merge(['class' => $embedded ? 'min-w-0' : 'min-w-0 overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900']) }}>
@unless ($embedded)
<div class="border-b border-gray-200 px-4 py-4 dark:border-gray-800 sm:px-5">
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $title }}</p>
<p class="text-xs text-gray-500 dark:text-gray-400">{{ count($normalizedFiles) }} files</p>
</div>
@endunless
<ul @class(['divide-y divide-gray-200 dark:divide-gray-800', 'border-t border-gray-200 dark:border-gray-800' => $embedded]) role="list">
@forelse ($normalizedFiles as $file)
@php
$isSelected = $selectedPath === $file['path'];
@endphp
<li>
@if ($navigate && $file['href'])
<a href="{{ $file['href'] }}" @class([$itemClass($isSelected), 'block'])>
<p class="min-w-0 break-all font-mono text-sm text-gray-800 sm:truncate dark:text-gray-200">{{ $file['path'] }}</p>
<div class="flex shrink-0 flex-wrap items-center gap-2">
<x-ui.badge :variant="$statusVariants[$file['status']] ?? 'gray'" size="sm">
{{ $statusLabels[$file['status']] ?? ucfirst($file['status']) }}
</x-ui.badge>
@if ($file['additions'] !== null || $file['deletions'] !== null)
<span class="text-xs tabular-nums text-gray-500 dark:text-gray-400">
@if ($file['additions'] !== null)
<span class="text-green-600 dark:text-green-400">+{{ $file['additions'] }}</span>
@endif
@if ($file['deletions'] !== null)
<span class="ms-1 text-red-600 dark:text-red-400">-{{ $file['deletions'] }}</span>
@endif
</span>
@endif
</div>
</a>
@else
<div @class($itemClass($isSelected))>
<p class="min-w-0 break-all font-mono text-sm text-gray-800 sm:truncate dark:text-gray-200">{{ $file['path'] }}</p>
<div class="flex shrink-0 flex-wrap items-center gap-2">
<x-ui.badge :variant="$statusVariants[$file['status']] ?? 'gray'" size="sm">
{{ $statusLabels[$file['status']] ?? ucfirst($file['status']) }}
</x-ui.badge>
@if ($file['additions'] !== null || $file['deletions'] !== null)
<span class="text-xs tabular-nums text-gray-500 dark:text-gray-400">
@if ($file['additions'] !== null)
<span class="text-green-600 dark:text-green-400">+{{ $file['additions'] }}</span>
@endif
@if ($file['deletions'] !== null)
<span class="ms-1 text-red-600 dark:text-red-400">-{{ $file['deletions'] }}</span>
@endif
</span>
@endif
</div>
</div>
@endif
</li>
@empty
<li class="px-4 py-6 text-sm text-gray-500 dark:text-gray-400 sm:px-5">No file changes recorded.</li>
@endforelse
</ul>
@if (trim($slot) !== '')
<div class="border-t border-gray-200 px-4 py-3 dark:border-gray-800 sm:px-5">{{ $slot }}</div>
@endif
</div>