@@ -17,7 +17,12 @@ import {
1717 type SmartColumnDisplay ,
1818 type SmartColumnSource ,
1919} from "./runColumns" ;
20- import { extractSmartValue , labelFromPath , parseSource } from "./smartColumnData" ;
20+ import {
21+ extractSmartValue ,
22+ labelFromPath ,
23+ parseSource ,
24+ type ParsedSource ,
25+ } from "./smartColumnData" ;
2126import { SmartColumnSample } from "./SmartColumnSample" ;
2227import type { loader as sampleLoader } from "~/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.smart-column-sample" ;
2328
@@ -84,29 +89,43 @@ export function AddSmartColumnDialog({
8489 // eslint-disable-next-line react-hooks/exhaustive-deps
8590 } , [ open , sampleUrl ] ) ;
8691
92+ useEffect ( ( ) => {
93+ setSampleIndex ( 0 ) ;
94+ } , [ source ] ) ;
95+
8796 const effectiveLabel = labelEdited ? label : labelFromPath ( path ) ;
8897
8998 const sampleLoaded = sample . data !== undefined && sample . state === "idle" ;
90- const sampleRuns = sample . data ?. runs ?? [ ] ;
91- const clampedIndex = sampleRuns . length > 0 ? Math . min ( sampleIndex , sampleRuns . length - 1 ) : 0 ;
92- const sampleRun = sampleRuns [ clampedIndex ] ?? null ;
99+ const sampleData = sample . data ;
93100
94- const parsed = useMemo ( ( ) => {
95- if ( ! sampleRun ) return undefined ;
96- switch ( source ) {
97- case "payload" :
98- return parseSource ( { data : sampleRun . payload , dataType : sampleRun . payloadType } ) ;
99- case "metadata" :
100- return parseSource ( { data : sampleRun . metadata , dataType : sampleRun . metadataType } ) ;
101- case "output" :
102- return parseSource ( { data : sampleRun . output , dataType : sampleRun . outputType } ) ;
103- }
104- } , [ sampleRun , source ] ) ;
101+ const { usable, anyOffloaded, runCount } = useMemo ( ( ) => {
102+ const runs = sampleData ?. runs ?? [ ] ;
103+ const parsed = runs . map ( ( run ) => {
104+ switch ( source ) {
105+ case "payload" :
106+ return parseSource ( { data : run . payload , dataType : run . payloadType } ) ;
107+ case "metadata" :
108+ return parseSource ( { data : run . metadata , dataType : run . metadataType } ) ;
109+ case "output" :
110+ return parseSource ( { data : run . output , dataType : run . outputType } ) ;
111+ }
112+ } ) ;
113+ return {
114+ runCount : runs . length ,
115+ anyOffloaded : parsed . some ( ( p ) => p . state === "offloaded" ) ,
116+ usable : parsed . filter (
117+ ( p ) : p is Extract < ParsedSource , { state : "parsed" } > => p . state === "parsed"
118+ ) ,
119+ } ;
120+ } , [ sampleData , source ] ) ;
121+
122+ const activeIndex = usable . length > 0 ? Math . min ( sampleIndex , usable . length - 1 ) : 0 ;
123+ const activeSample = usable [ activeIndex ] ;
105124
106125 const resolved = useMemo ( ( ) => {
107- if ( ! parsed || path . trim ( ) . length === 0 ) return undefined ;
108- return extractSmartValue ( parsed , path ) ;
109- } , [ parsed , path ] ) ;
126+ if ( ! activeSample || path . trim ( ) . length === 0 ) return undefined ;
127+ return extractSmartValue ( activeSample , path ) ;
128+ } , [ activeSample , path ] ) ;
110129
111130 const canSubmit = path . trim ( ) . length > 0 ;
112131
@@ -202,37 +221,37 @@ export function AddSmartColumnDialog({
202221 < div className = "flex flex-col gap-1.5 self-start rounded-lg border border-grid-dimmed bg-background-dimmed p-3" >
203222 < div className = "flex items-center justify-between gap-2" >
204223 < Paragraph variant = "extra-extra-small/dimmed/caps" > Sample — { source } </ Paragraph >
205- { sampleRuns . length > 0 && (
224+ { usable . length > 1 && (
206225 < SampleRunPicker
207- index = { clampedIndex }
208- total = { sampleRuns . length }
226+ index = { activeIndex }
227+ total = { usable . length }
209228 onPrev = { ( ) => setSampleIndex ( ( i ) => Math . max ( 0 , i - 1 ) ) }
210- onNext = { ( ) => setSampleIndex ( ( i ) => Math . min ( sampleRuns . length - 1 , i + 1 ) ) }
229+ onNext = { ( ) => setSampleIndex ( ( i ) => Math . min ( usable . length - 1 , i + 1 ) ) }
211230 />
212231 ) }
213232 </ div >
214233 { ! sampleLoaded ? (
215234 < Paragraph variant = "extra-small" className = "text-text-dimmed" >
216235 Loading…
217236 </ Paragraph >
218- ) : ! parsed ? (
237+ ) : activeSample ? (
238+ < SmartColumnSample
239+ value = { activeSample . value }
240+ activePath = { path . trim ( ) }
241+ onSelectPath = { setPath }
242+ />
243+ ) : runCount === 0 ? (
219244 < Paragraph variant = "extra-small" className = "text-text-dimmed" >
220245 No runs to sample.
221246 </ Paragraph >
222- ) : parsed . state === "offloaded" ? (
247+ ) : anyOffloaded ? (
223248 < Paragraph variant = "extra-small" className = "text-text-dimmed" >
224- This { source } is offloaded to object storage, too large to sample here.
249+ Recent { source } s are offloaded to object storage, too large to sample here.
225250 </ Paragraph >
226- ) : parsed . state === "empty" ? (
251+ ) : (
227252 < Paragraph variant = "extra-small" className = "text-text-dimmed" >
228- No { source } value for this run .
253+ No recent run has a { source } value to sample .
229254 </ Paragraph >
230- ) : (
231- < SmartColumnSample
232- value = { parsed . value }
233- activePath = { path . trim ( ) }
234- onSelectPath = { setPath }
235- />
236255 ) }
237256 < Paragraph variant = "extra-extra-small/dimmed/caps" className = "mt-2" >
238257 Resolves to
0 commit comments