Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions apps/demo/src/lib/components/CodePanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { fade } from 'svelte/transition';
import { codeToHtml } from 'shiki';
import { FLOW_CODE, getStepFromLine, FLOW_SECTIONS } from '$lib/data/flow-code';
import type { createFlowState } from '$lib/stores/pgflow-state-improved.svelte';
import type { createFlowState } from '$lib/stores/pgflow-state.svelte';
import StatusBadge from '$lib/components/StatusBadge.svelte';
import PulseDot from '$lib/components/PulseDot.svelte';
Expand Down Expand Up @@ -61,7 +61,8 @@
// Helper to get status for a step badge
function getStepStatus(stepSlug: string): string | null {
const status = flowState.stepStatuses[stepSlug];
// Use reactive step() method from runState
const status = flowState.step(stepSlug).status;
const hasFlowStarted = flowState.status !== 'idle';
// Don't show badge if flow hasn't started yet
Expand All @@ -70,7 +71,7 @@
}
// If flow has started but this step has no status yet, don't show indicator
if (!status) {
if (!status || status === 'created') {
return null;
}
Expand Down Expand Up @@ -210,8 +211,8 @@
// Explicitly track these dependencies
const currentSelectedStep = selectedStep;
const currentHoveredStep = hoveredStep;
// Ensure reactivity to step status changes by accessing it
void flowState.stepStatuses;
// Ensure reactivity to step status changes by accessing flowState.run
void flowState.run;
Comment on lines +214 to +215
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace 'void flowState.run' with a proper $effect block or use $: to track the dependency. For example: '$: ({ run } = flowState);' or create an $effect that uses flowState.run properly.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

if (!codeContainer) return;
Expand Down
12 changes: 7 additions & 5 deletions apps/demo/src/lib/components/DAGVisualization.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { createEventDispatcher, onMount } from 'svelte';
import { SvelteFlow } from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import type { createFlowState } from '$lib/stores/pgflow-state-improved.svelte';
import type { createFlowState } from '$lib/stores/pgflow-state.svelte';
import DAGNode from './DAGNode.svelte';
interface Props {
Expand Down Expand Up @@ -163,16 +163,18 @@
]);
function isStepActive(stepSlug: string): boolean {
const status = flowState.stepStatuses[stepSlug];
return status === 'started';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'started';
Comment on lines +166 to +167
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here is redundant since the code already clearly shows we're using the step() method. Consider removing the comment to make the code cleaner.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

}
function isStepCompleted(stepSlug: string): boolean {
return flowState.stepStatuses[stepSlug] === 'completed';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'completed';
}
function isStepFailed(stepSlug: string): boolean {
return flowState.stepStatuses[stepSlug] === 'failed';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'failed';
}
function isEdgeActive(source: string, target: string): boolean {
Expand Down
44 changes: 19 additions & 25 deletions apps/demo/src/lib/components/DebugPanel.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { createFlowState } from '$lib/stores/pgflow-state-improved.svelte';
import type { createFlowState } from '$lib/stores/pgflow-state.svelte';
import { codeToHtml } from 'shiki';
import { SvelteMap } from 'svelte/reactivity';
Expand Down Expand Up @@ -45,7 +45,7 @@
// Clear cache when flow resets (events list becomes empty or significantly changes)
let lastEventCount = $state(0);
$effect(() => {
const currentEventCount = flowState.events.length;
const currentEventCount = flowState.timeline.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the timeline implementation uses SvelteDate instead of the built-in Date class for reactivity. If the timeline is created in pgflow-state.svelte, make sure all Date instances are replaced with SvelteDate there.

Spotted by Graphite Agent (based on CI logs)

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

// If events list was cleared or reduced significantly, clear the cache
if (currentEventCount === 0 || currentEventCount < lastEventCount - 5) {
highlightedEvents = new SvelteMap();
Expand All @@ -54,23 +54,11 @@
lastEventCount = currentEventCount;
});
// Get relative time from flow start
function formatRelativeTime(timestamp: Date, firstEventTimestamp: Date): string {
const diffMs = timestamp.getTime() - firstEventTimestamp.getTime();
const seconds = (diffMs / 1000).toFixed(3);
return `+${seconds}s`;
}
// Get display status from event_type (use the status part for badge coloring)
function getEventStatus(eventType: string): string {
return eventType.split(':')[1] || 'unknown';
}
// Get full event name for display
function getEventDisplayName(eventType: string): string {
return eventType;
}
// Get color class for event name based on status
function getEventColor(eventType: string): string {
const status = getEventStatus(eventType);
Expand All @@ -87,15 +75,16 @@
return 'text-muted-foreground';
}
}
</script>

<div class="flex flex-col h-full min-w-0">
{#if flowState.events.length > 0}
{#if flowState.timeline.length > 0}
<!-- Table-like headers -->
<div
class="flex items-center gap-2 px-3 py-1 border-b border-muted text-xs font-semibold text-muted-foreground"
>
<div class="w-[80px] text-left">TIME</div>
<div class="w-[120px] text-left">TIME</div>
<div class="w-[140px] text-left">EVENT</div>
<div class="flex-1 text-left">STEP</div>
<div class="w-[32px]"></div>
Expand All @@ -104,16 +93,14 @@
{/if}

<div class="flex-1 overflow-y-auto overflow-x-hidden space-y-1 min-w-0">
{#if flowState.events.length === 0}
{#if flowState.timeline.length === 0}
<p class="text-sm text-muted-foreground text-center py-8">
No events yet. Start a flow to see events.
</p>
{:else}
{@const firstEventTimestamp = flowState.events[0]?.timestamp}
{#each flowState.events as event, index (index)}
{#each flowState.timeline as event, index (index)}
{@const eventType = event.event_type}
{@const stepSlug = event.data?.step_slug}
{@const eventDisplayName = getEventDisplayName(eventType)}
{@const stepSlug = event.step_slug}
{@const eventColor = getEventColor(eventType)}
{@const isExpanded = expandedEventIndices.has(index)}
{@const isHighlighted = stepSlug && hoveredStep === stepSlug}
Expand All @@ -127,11 +114,18 @@
class="flex items-center gap-2 w-full text-left px-1 rounded transition-colors hover:bg-muted/20"
onclick={(e) => toggleEvent(index, e)}
>
<code class="w-[80px] text-base text-muted-foreground font-mono text-left"
>{formatRelativeTime(event.timestamp, firstEventTimestamp)}</code
>
<div class="w-[120px] flex flex-col text-left">
<code class="text-base text-muted-foreground font-mono"
>{event.cumulativeDisplay}</code
>
{#if event.deltaMs > 0}
<code class="text-xs text-muted-foreground/70 font-mono"
>{event.deltaDisplay}</code
>
{/if}
</div>
<code class="w-[140px] text-base font-semibold font-mono {eventColor}">
{eventDisplayName}
{eventType}
</code>
{#if stepSlug}
<code
Expand Down
38 changes: 13 additions & 25 deletions apps/demo/src/lib/components/ExplanationPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { fade } from 'svelte/transition';
import { Button } from '$lib/components/ui/button';
import { codeToHtml } from 'shiki';
import type { createFlowState } from '$lib/stores/pgflow-state-improved.svelte';
import type { createFlowState } from '$lib/stores/pgflow-state.svelte';
import StatusBadge from '$lib/components/StatusBadge.svelte';
import MiniDAG from '$lib/components/MiniDAG.svelte';
import { Clock, Workflow, Play, Hourglass } from '@lucide/svelte';
Expand Down Expand Up @@ -232,50 +232,37 @@
selectedStep && stepInfo[selectedStep] ? stepInfo[selectedStep] : null
);

// Build step outputs map from events
const stepOutputs = $derived.by(() => {
const outputs: Record<string, unknown> = {};
flowState.events.forEach((event) => {
if (
event.event_type === 'step:completed' &&
event.data?.step_slug &&
event.data?.output !== undefined
) {
outputs[event.data.step_slug as string] = event.data.output;
}
});
return outputs;
});

// Get step output
const stepOutput = $derived(selectedStep ? stepOutputs[selectedStep] : null);
// Get step output from reactive step() method
const stepOutput = $derived(selectedStep ? flowState.step(selectedStep).output : null);

// Get actual input for the selected step
const stepInput = $derived.by(() => {
if (!selectedStep || !currentStepInfo) return null;
if (!selectedStep || !currentStepInfo || !flowState.run) return null;

// Only show input if step is started or completed
const stepStatus = flowState.stepStatuses[selectedStep];
// Use reactive step() method from runState
const stepStatus = flowState.step(selectedStep).status;
if (stepStatus !== 'started' && stepStatus !== 'completed') return null;

// For steps with dependencies, check if all dependencies are completed
if (currentStepInfo.dependsOn.length > 0) {
const allDepsCompleted = currentStepInfo.dependsOn.every((dep) => {
return flowState.stepStatuses[dep] === 'completed';
// Use reactive step() method from runState
return flowState.step(dep).status === 'completed';
});
if (!allDepsCompleted) return null;
}

const input: Record<string, unknown> = {};

// Always add run input (URL) from flowState.run if available
if (flowState.run?.input) {
if (flowState.run.input) {
input.run = flowState.run.input;
}

// Add outputs from dependencies
// Add outputs from dependencies using reactive step() method
for (const dep of currentStepInfo.dependsOn) {
const depOutput = stepOutputs[dep];
const depOutput = flowState.step(dep).output;
if (depOutput !== undefined) {
input[dep] = depOutput;
}
Expand All @@ -286,7 +273,8 @@

// Get current step status
function getStepStatus(stepSlug: string): string | null {
const status = flowState.stepStatuses[stepSlug];
// Use reactive step() method from runState
const status = flowState.step(stepSlug).status;
const hasFlowStarted = flowState.status !== 'idle';

// Don't show badge if flow hasn't started yet
Expand Down
12 changes: 7 additions & 5 deletions apps/demo/src/lib/components/MiniDAG.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { createFlowState } from '$lib/stores/pgflow-state-improved.svelte';
import type { createFlowState } from '$lib/stores/pgflow-state.svelte';

/**
* Minimal DAG visualization for showing flow context
Expand All @@ -14,16 +14,18 @@
let { selectedStep, flowState }: Props = $props();

function isStepActive(stepSlug: string): boolean {
const status = flowState.stepStatuses[stepSlug];
return status === 'started';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'started';
}

function isStepCompleted(stepSlug: string): boolean {
return flowState.stepStatuses[stepSlug] === 'completed';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'completed';
}

function isStepFailed(stepSlug: string): boolean {
return flowState.stepStatuses[stepSlug] === 'failed';
// Use reactive step() method from runState
return flowState.step(stepSlug).status === 'failed';
}

// Node dimensions (smaller for mini view)
Expand Down
Loading
Loading