Skip to main content

AI & workflows

Ai Loop List code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/ai-loop-list.blade.php

@props([
    'loops' => [],
    'selectedId' => null,
    'name' => 'loop_id',
    'title' => 'Agent loops',
    'navigate' => false,
    'embedded' => false,
])

@php
    /*
    | Dashboard list of active and recent agent loops.
    |
    | Usage:
    |   <x-ui.ai-loop-list :loops="[
    |       ['id' => '550e8400-e29b-41d4-a716-446655440000', 'goal' => 'Keep CI green', 'status' => 'running', 'iteration' => 4, 'maxIterations' => 10, 'model' => '5.5 High', 'updatedAt' => '2m ago'],
    |   ]" selected-id="550e8400-e29b-41d4-a716-446655440000" />
    |
    | Set `navigate` to render each row as a link instead of a radio control.
    */
    $itemClass = fn (bool $isSelected): string => \Illuminate\Support\Arr::toCssClasses([
        'flex flex-col gap-2 px-4 py-3 transition sm:px-5',
        'bg-brand-50/70 dark:bg-brand-950/20' => $isSelected,
        'hover:bg-gray-50 dark:hover:bg-gray-950/60' => ! $isSelected,
    ]);
    $normalizedLoops = collect($loops)
        ->map(function ($loop) {
            return [
                'id' => $loop['id'] ?? '',
                'goal' => $loop['goal'] ?? 'Untitled loop',
                'status' => $loop['status'] ?? 'idle',
                'iteration' => (int) ($loop['iteration'] ?? 1),
                'maxIterations' => isset($loop['maxIterations']) ? (int) $loop['maxIterations'] : null,
                'model' => $loop['model'] ?? null,
                'updatedAt' => $loop['updatedAt'] ?? null,
                'href' => $loop['href'] ?? null,
            ];
        })
        ->filter(fn (array $loop) => $loop['id'] !== '')
        ->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($normalizedLoops) }} loops</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 ($normalizedLoops as $agentLoop)
            @php
                $isSelected = $selectedId === $agentLoop['id'];
                $iterationLabel = $agentLoop['maxIterations']
                    ? 'Loop '.$agentLoop['iteration'].' / '.$agentLoop['maxIterations']
                    : 'Loop '.$agentLoop['iteration'];
            @endphp
            <li>
                @if ($navigate)
                    <a href="{{ $agentLoop['href'] ?? '#' }}" @class([$itemClass($isSelected), 'block'])>
                        <div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-3">
                            <p class="min-w-0 break-words text-sm font-medium text-gray-900 dark:text-white">{{ $agentLoop['goal'] }}</p>
                            <x-ui.ai-loop-status-badge :status="$agentLoop['status']" class="self-start shrink-0" />
                        </div>

                        <div class="flex flex-col gap-1 text-xs text-gray-500 sm:flex-row sm:flex-wrap sm:items-center sm:gap-2 dark:text-gray-400">
                            <span class="break-all font-mono sm:max-w-[12rem] sm:truncate">{{ $agentLoop['id'] }}</span>
                            <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                            <span>{{ $iterationLabel }}</span>
                            @if ($agentLoop['model'])
                                <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                                <span>{{ $agentLoop['model'] }}</span>
                            @endif
                            @if ($agentLoop['updatedAt'])
                                <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                                <span>{{ $agentLoop['updatedAt'] }}</span>
                            @endif
                        </div>
                    </a>
                @else
                    <label @class([$itemClass($isSelected), 'cursor-pointer'])>
                        <span class="sr-only">Select loop</span>
                        <input type="radio" name="{{ $name }}" value="{{ $agentLoop['id'] }}" @checked($isSelected) class="sr-only">

                        <div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-3">
                            <p class="min-w-0 break-words text-sm font-medium text-gray-900 dark:text-white">{{ $agentLoop['goal'] }}</p>
                            <x-ui.ai-loop-status-badge :status="$agentLoop['status']" class="self-start shrink-0" />
                        </div>

                        <div class="flex flex-col gap-1 text-xs text-gray-500 sm:flex-row sm:flex-wrap sm:items-center sm:gap-2 dark:text-gray-400">
                            <span class="break-all font-mono sm:max-w-[12rem] sm:truncate">{{ $agentLoop['id'] }}</span>
                            <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                            <span>{{ $iterationLabel }}</span>
                            @if ($agentLoop['model'])
                                <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                                <span>{{ $agentLoop['model'] }}</span>
                            @endif
                            @if ($agentLoop['updatedAt'])
                                <span class="hidden text-gray-300 sm:inline dark:text-gray-600">·</span>
                                <span>{{ $agentLoop['updatedAt'] }}</span>
                            @endif
                        </div>
                    </label>
                @endif
            </li>
        @empty
            <li class="px-4 py-8 text-center text-sm text-gray-500 dark:text-gray-400 sm:px-5">
                No loops yet.
            </li>
        @endforelse
    </ul>
</div>