mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:21:10 +02:00
feat(ai-missions): inline AiProposalInbox in mission detail (cross-module)
Mission detail now renders all pending proposals for that mission, across every module, directly above the iteration list. No more jumping between /todo, /news, /calendar to approve what the agent staged. AiProposalInbox.module is now optional; when omitted, every card grows a small lowercase module badge (e.g. "news", "todo") so the user knows where each proposal will land on approve. The existing per-module inboxes on /todo, /news, /calendar still work — proposals show in both places via the same live query, so approving in one auto-clears the other. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
988c17a678
commit
f06ca2c7c3
2 changed files with 31 additions and 4 deletions
|
|
@ -23,13 +23,22 @@
|
|||
import type { Proposal } from '$lib/data/ai/proposals/types';
|
||||
|
||||
interface Props {
|
||||
/** Filter proposals to tools belonging to this module (e.g. 'todo'). */
|
||||
module: string;
|
||||
/** Filter proposals to tools belonging to this module (e.g. 'todo').
|
||||
* Omit when filtering by mission only — the inbox will then render
|
||||
* every pending proposal across modules and add a module badge to
|
||||
* each card so the user knows where it'll land on approve. */
|
||||
module?: string;
|
||||
/** Filter to proposals from a specific mission. Combine with `module`
|
||||
* to scope to that mission's proposals for a single module. */
|
||||
missionId?: string;
|
||||
}
|
||||
|
||||
let { module }: Props = $props();
|
||||
let { module, missionId }: Props = $props();
|
||||
|
||||
const proposals = $derived(useAiProposals({ status: 'pending', module }));
|
||||
const proposals = $derived(useAiProposals({ status: 'pending', module, missionId }));
|
||||
/** Show module badge whenever the inbox is cross-module (i.e. the
|
||||
* caller didn't pin it to a single module). */
|
||||
const showModuleBadge = $derived(!module);
|
||||
|
||||
let busyId = $state<string | null>(null);
|
||||
/** Proposal whose reject-feedback textarea is currently open. */
|
||||
|
|
@ -92,6 +101,10 @@
|
|||
<header class="header">
|
||||
<Sparkle size={16} weight="fill" />
|
||||
<span class="label">KI schlägt vor</span>
|
||||
{#if showModuleBadge && p.intent.kind === 'toolCall'}
|
||||
{@const mod = getTool(p.intent.toolName)?.module ?? '?'}
|
||||
<span class="module-badge">{mod}</span>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
<p class="intent">{formatIntent(p)}</p>
|
||||
|
|
@ -181,6 +194,16 @@
|
|||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.module-badge {
|
||||
margin-left: auto;
|
||||
padding: 0.0625rem 0.375rem;
|
||||
border-radius: 0.25rem;
|
||||
background: color-mix(in oklab, var(--color-primary, #6b5bff) 18%, transparent);
|
||||
color: color-mix(in oklab, var(--color-primary, #6b5bff) 90%, var(--color-fg, #000));
|
||||
font-size: 0.6875rem;
|
||||
letter-spacing: 0.02em;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.intent {
|
||||
margin: 0.375rem 0 0;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
import MissionInputPicker from '$lib/components/ai/MissionInputPicker.svelte';
|
||||
import MissionGrantDialog from '$lib/components/ai/MissionGrantDialog.svelte';
|
||||
import AiDebugBlock from '$lib/components/ai/AiDebugBlock.svelte';
|
||||
import AiProposalInbox from '$lib/components/ai/AiProposalInbox.svelte';
|
||||
import { isAiDebugEnabled, setAiDebugEnabled } from '$lib/data/ai/missions/debug';
|
||||
import { isMissionGrantsEnabled } from '$lib/api/config';
|
||||
import type { Mission, MissionCadence, MissionInputRef } from '$lib/data/ai/missions/types';
|
||||
|
|
@ -392,6 +393,9 @@
|
|||
<MissionGrantDialog mission={selected} bind:open={grantDialogOpen} />
|
||||
{/if}
|
||||
|
||||
<h3 class="section-title">Vorschläge zur Review</h3>
|
||||
<AiProposalInbox missionId={selected.id} />
|
||||
|
||||
<h3 class="section-title">Iterationen</h3>
|
||||
{#if selected.iterations.length === 0}
|
||||
<p class="empty">Noch keine Iteration gelaufen.</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue