fix(frontend/library): Transition from empty tasks view on task init (#11600)

- Resolves #11599

### Changes 🏗️

- Manually update item counts when initiating a task from `EmptyTasks`
view
- Other improvements made while debugging

### Checklist 📋

#### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
- [x] `NewAgentLibraryView` transitions to full layout when a first task
is created
- [x] `NewAgentLibraryView` transitions to full layout when a first
trigger is set up
This commit is contained in:
Reinier van der Leer
2025-12-11 12:13:53 +01:00
committed by GitHub
parent bd37fe946d
commit 4d4741d558
5 changed files with 90 additions and 41 deletions

View File

@@ -1,6 +1,5 @@
"use client";
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
import { Button } from "@/components/atoms/Button/Button";
import { Breadcrumbs } from "@/components/molecules/Breadcrumbs/Breadcrumbs";
import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard";
@@ -39,14 +38,11 @@ export function NewAgentLibraryView() {
handleSelectRun,
handleCountsChange,
handleClearSelectedRun,
onRunInitiated,
onTriggerSetup,
onScheduleCreated,
} = useNewAgentLibraryView();
function onTriggerSetup(newTrigger: LibraryAgentPreset) {
if (!agent) return;
handleSelectRun(newTrigger.id, "triggers");
}
if (error) {
return (
<ErrorCard
@@ -74,7 +70,12 @@ export function NewAgentLibraryView() {
/>
</div>
<div className="flex min-h-0 flex-1">
<EmptyTasks agent={agent} onTriggerSetup={onTriggerSetup} />
<EmptyTasks
agent={agent}
onRun={onRunInitiated}
onTriggerSetup={onTriggerSetup}
onScheduleCreated={onScheduleCreated}
/>
</div>
</div>
);
@@ -101,10 +102,8 @@ export function NewAgentLibraryView() {
</Button>
}
agent={agent}
onRunCreated={(execution) => handleSelectRun(execution.id, "runs")}
onScheduleCreated={(schedule) =>
handleSelectRun(schedule.id, "scheduled")
}
onRunCreated={onRunInitiated}
onScheduleCreated={onScheduleCreated}
onTriggerSetup={onTriggerSetup}
initialInputValues={activeTemplate?.inputs}
initialInputCredentials={activeTemplate?.credentials}
@@ -167,7 +166,12 @@ export function NewAgentLibraryView() {
</SelectedViewLayout>
) : (
<SelectedViewLayout agentName={agent.name} agentId={agent.id}>
<EmptyTasks agent={agent} onTriggerSetup={onTriggerSetup} />
<EmptyTasks
agent={agent}
onRun={onRunInitiated}
onTriggerSetup={onTriggerSetup}
onScheduleCreated={onScheduleCreated}
/>
</SelectedViewLayout>
)}
</div>

View File

@@ -1,5 +1,5 @@
import {
getGetV1ListGraphExecutionsInfiniteQueryOptions,
getGetV1ListGraphExecutionsQueryKey,
usePostV1ExecuteGraphAgent,
} from "@/app/api/__generated__/endpoints/graphs/graphs";
import {
@@ -66,13 +66,11 @@ export function useAgentRunModal(
toast({
title: "Agent execution started",
});
callbacks?.onRun?.(response.data as unknown as GraphExecutionMeta);
// Invalidate runs list for this graph
queryClient.invalidateQueries({
queryKey: getGetV1ListGraphExecutionsInfiniteQueryOptions(
agent.graph_id,
).queryKey,
queryKey: getGetV1ListGraphExecutionsQueryKey(agent.graph_id),
});
callbacks?.onRun?.(response.data);
analytics.sendDatafastEvent("run_agent", {
name: agent.name,
id: agent.graph_id,
@@ -91,17 +89,15 @@ export function useAgentRunModal(
const setupTriggerMutation = usePostV2SetupTrigger({
mutation: {
onSuccess: (response: any) => {
onSuccess: (response) => {
if (response.status === 200) {
toast({
title: "Trigger setup complete",
});
callbacks?.onSetupTrigger?.(response.data);
queryClient.invalidateQueries({
queryKey: getGetV2ListPresetsQueryKey({
graph_id: agent.graph_id,
}),
queryKey: getGetV2ListPresetsQueryKey({ graph_id: agent.graph_id }),
});
callbacks?.onSetupTrigger?.(response.data);
setIsOpen(false);
}
},

View File

@@ -1,6 +1,8 @@
"use client";
import { getV1GetGraphVersion } from "@/app/api/__generated__/endpoints/graphs/graphs";
import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo";
import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta";
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
import { Button } from "@/components/atoms/Button/Button";
@@ -16,10 +18,17 @@ import { EmptyTasksIllustration } from "./EmptyTasksIllustration";
type Props = {
agent: LibraryAgent;
onRun?: (run: GraphExecutionMeta) => void;
onTriggerSetup?: (preset: LibraryAgentPreset) => void;
onScheduleCreated?: (schedule: GraphExecutionJobInfo) => void;
};
export function EmptyTasks({ agent, onTriggerSetup }: Props) {
export function EmptyTasks({
agent,
onRun,
onTriggerSetup,
onScheduleCreated,
}: Props) {
const { toast } = useToast();
async function handleExport() {
@@ -77,7 +86,9 @@ export function EmptyTasks({ agent, onTriggerSetup }: Props) {
</Button>
}
agent={agent}
onRunCreated={onRun}
onTriggerSetup={onTriggerSetup}
onScheduleCreated={onScheduleCreated}
/>
</div>
</div>

View File

@@ -32,7 +32,7 @@ function parseTab(
}
type Args = {
graphId?: string;
graphId: string;
onSelectRun: (
runId: string,
tab?: "runs" | "scheduled" | "templates" | "triggers",
@@ -60,7 +60,7 @@ export function useSidebarRunsList({
const queryClient = useQueryClient();
const runsQuery = useGetV1ListGraphExecutionsInfinite(
graphId || "",
graphId,
{ page: 1, page_size: 20 },
{
query: {
@@ -71,22 +71,19 @@ export function useSidebarRunsList({
},
);
const schedulesQuery = useGetV1ListExecutionSchedulesForAGraph(
graphId || "",
{
query: {
enabled: !!graphId,
select: (r) => okData<GraphExecutionJobInfo[]>(r) ?? [],
},
const schedulesQuery = useGetV1ListExecutionSchedulesForAGraph(graphId, {
query: {
enabled: !!graphId,
select: (r) => okData<GraphExecutionJobInfo[]>(r),
},
);
});
const presetsQuery = useGetV2ListPresets(
{ graph_id: graphId || null, page: 1, page_size: 100 },
{ graph_id: graphId, page: 1, page_size: 100 },
{
query: {
enabled: !!graphId,
select: (r) => okData<LibraryAgentPresetResponse>(r)?.presets ?? [],
select: (r) => okData<LibraryAgentPresetResponse>(r)?.presets,
},
},
);
@@ -99,11 +96,11 @@ export function useSidebarRunsList({
const schedules = schedulesQuery.data || [];
const allPresets = presetsQuery.data || [];
const triggers = useMemo(
() => allPresets.filter((preset) => preset.webhook_id && preset.webhook),
() => allPresets.filter((preset) => preset.webhook_id),
[allPresets],
);
const templates = useMemo(
() => allPresets.filter((preset) => !preset.webhook_id || !preset.webhook),
() => allPresets.filter((preset) => !preset.webhook_id),
[allPresets],
);
@@ -112,9 +109,11 @@ export function useSidebarRunsList({
const templatesCount = templates.length;
const triggersCount = triggers.length;
const loading =
!schedulesQuery.isSuccess ||
!runsQuery.isSuccess ||
!schedulesQuery.isSuccess ||
!presetsQuery.isSuccess;
const stale =
runsQuery.isStale || schedulesQuery.isStale || presetsQuery.isStale;
// Update query cache when execution events arrive via websocket
useExecutionEvents({
@@ -131,7 +130,7 @@ export function useSidebarRunsList({
// Notify parent about counts and loading state
useEffect(() => {
if (onCountsChange) {
if (onCountsChange && !stale) {
onCountsChange({
runsCount,
schedulesCount,
@@ -141,12 +140,13 @@ export function useSidebarRunsList({
});
}
}, [
onCountsChange,
runsCount,
schedulesCount,
templatesCount,
triggersCount,
loading,
onCountsChange,
stale,
]);
useEffect(() => {

View File

@@ -1,5 +1,7 @@
import { useGetV2GetLibraryAgent } from "@/app/api/__generated__/endpoints/library/library";
import { useGetV2GetASpecificPreset } from "@/app/api/__generated__/endpoints/presets/presets";
import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo";
import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta";
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset";
import { okData } from "@/app/api/helpers";
@@ -153,6 +155,39 @@ export function useNewAgentLibraryView() {
[],
);
function onItemCreated(
createEvent:
| { type: "runs"; item: GraphExecutionMeta }
| { type: "triggers"; item: LibraryAgentPreset }
| { type: "scheduled"; item: GraphExecutionJobInfo },
) {
if (!hasAnyItems) {
// Manually increment item count to flip hasAnyItems and showSidebarLayout
const counts = {
runsCount: createEvent.type === "runs" ? 1 : 0,
triggersCount: createEvent.type === "triggers" ? 1 : 0,
schedulesCount: createEvent.type === "scheduled" ? 1 : 0,
templatesCount: 0,
};
handleCountsChange(counts);
}
}
function onRunInitiated(newRun: GraphExecutionMeta) {
if (!agent) return;
onItemCreated({ item: newRun, type: "runs" });
}
function onTriggerSetup(newTrigger: LibraryAgentPreset) {
if (!agent) return;
onItemCreated({ item: newTrigger, type: "triggers" });
}
function onScheduleCreated(newSchedule: GraphExecutionJobInfo) {
if (!agent) return;
onItemCreated({ item: newSchedule, type: "scheduled" });
}
return {
agentId: id,
agent,
@@ -169,5 +204,8 @@ export function useNewAgentLibraryView() {
handleClearSelectedRun,
handleCountsChange,
handleSelectRun,
onRunInitiated,
onTriggerSetup,
onScheduleCreated,
};
}