fix: make execution names unique, move approval bar above input
- Execution entity name now includes UUID suffix: 'pct_create on host:strong (abc12345)' so the (type,name) UNIQUE constraint doesn't block subsequent executions for the same target+action. Dedup now uses JOIN + LIKE prefix match to find only pending_approval executions. - Move persistent approval bar from top of messages area to just above the chat input box (bottom-fixed position, above the textarea form).
This commit is contained in:
@@ -130,38 +130,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex min-w-0 flex-1 flex-col">
|
||||
{#if pendingApprovals.length > 0}
|
||||
<div class="shrink-0 border-b border-warning/30 bg-warning/5 px-4 py-2">
|
||||
{#each pendingApprovals as a (a.executionId)}
|
||||
<div class="flex items-center gap-2">
|
||||
<ShieldCheckIcon class="size-4 shrink-0 text-warning" />
|
||||
<span class="flex-1 text-xs font-medium">
|
||||
{a.action} on {a.target}
|
||||
</span>
|
||||
{#if approving === a.executionId}
|
||||
<LoaderCircleIcon class="size-4 animate-spin text-muted-foreground" />
|
||||
{:else}
|
||||
<Button size="sm" variant="default" class="h-7 px-2.5 text-xs" disabled={approving !== null} onclick={() => approveOne(a)}>
|
||||
<CheckIcon class="size-3" />
|
||||
<span class="ml-1">Approve</span>
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" class="h-7 px-2.5 text-xs" disabled={approving !== null} onclick={() => denyOne(a)}>
|
||||
<XIcon class="size-3" />
|
||||
<span class="ml-1">Deny</span>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if pendingApprovals.length > 1}
|
||||
<div class="mt-1">
|
||||
<Button size="sm" variant="default" class="h-6 px-2 text-xs" disabled={approving !== null} onclick={approveAll}>
|
||||
<CheckIcon class="size-3" />
|
||||
<span class="ml-1">Approve all</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="min-h-0 flex-1 overflow-y-auto">
|
||||
<div class="mx-auto flex max-w-3xl flex-col gap-5 p-4">
|
||||
{#if $messages.length === 0}
|
||||
@@ -215,6 +183,37 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if pendingApprovals.length > 0}
|
||||
<div class="shrink-0 border-t border-warning/30 bg-warning/5 px-4 py-2">
|
||||
{#each pendingApprovals as a (a.executionId)}
|
||||
<div class="flex items-center gap-2">
|
||||
<ShieldCheckIcon class="size-4 shrink-0 text-warning" />
|
||||
<span class="flex-1 text-xs font-medium">
|
||||
{a.action} on {a.target}
|
||||
</span>
|
||||
{#if approving === a.executionId}
|
||||
<LoaderCircleIcon class="size-4 animate-spin text-muted-foreground" />
|
||||
{:else}
|
||||
<Button size="sm" variant="default" class="h-7 px-2.5 text-xs" disabled={approving !== null} onclick={() => approveOne(a)}>
|
||||
<CheckIcon class="size-3" />
|
||||
<span class="ml-1">Approve</span>
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" class="h-7 px-2.5 text-xs" disabled={approving !== null} onclick={() => denyOne(a)}>
|
||||
<XIcon class="size-3" />
|
||||
<span class="ml-1">Deny</span>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if pendingApprovals.length > 1}
|
||||
<Button size="sm" variant="default" class="mt-1 h-6 px-2 text-xs" disabled={approving !== null} onclick={approveAll}>
|
||||
<CheckIcon class="size-3" />
|
||||
<span class="ml-1">Approve all</span>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="border-t bg-card/50 p-3">
|
||||
<form
|
||||
class="mx-auto flex max-w-3xl items-end gap-2"
|
||||
|
||||
Reference in New Issue
Block a user