1- import { Suspense , useMemo , useState } from "react" ;
1+ import { Suspense , useCallback , useEffect , useRef , useState } from "react" ;
22import type { ModalOverlayProps } from "react-aria-components" ;
33import { graphql , useLazyLoadQuery , useMutation } from "react-relay" ;
44import invariant from "tiny-invariant" ;
@@ -9,11 +9,11 @@ import { Modal, ModalOverlay } from "@phoenix/components/core/overlay/Modal";
99import type { CreateCodeDatasetEvaluatorSlideover_createCodeEvaluatorMutation } from "@phoenix/components/dataset/__generated__/CreateCodeDatasetEvaluatorSlideover_createCodeEvaluatorMutation.graphql" ;
1010import type { CreateCodeDatasetEvaluatorSlideover_createDatasetCodeEvaluatorMutation } from "@phoenix/components/dataset/__generated__/CreateCodeDatasetEvaluatorSlideover_createDatasetCodeEvaluatorMutation.graphql" ;
1111import type { CreateCodeDatasetEvaluatorSlideoverQuery } from "@phoenix/components/dataset/__generated__/CreateCodeDatasetEvaluatorSlideoverQuery.graphql" ;
12+ import { mapSandboxConfigOptions } from "@phoenix/components/evaluators/CodeEvaluatorLanguageSandboxFields" ;
1213import { DEFAULT_CODE_EVALUATOR_SOURCE } from "@phoenix/components/evaluators/codeEvaluatorUtils" ;
1314import {
14- EditCodeEvaluatorDialogContent ,
15- mapSandboxConfigOptions ,
1615 createDefaultContinuousOutputConfig ,
16+ EditCodeEvaluatorDialogContent ,
1717} from "@phoenix/components/evaluators/EditCodeEvaluatorDialogContent" ;
1818import { buildOutputConfigsInput } from "@phoenix/components/evaluators/utils" ;
1919import { EvaluatorStoreProvider } from "@phoenix/contexts/EvaluatorContext" ;
@@ -29,20 +29,49 @@ export const CreateCodeDatasetEvaluatorSlideover = ({
2929 datasetId,
3030 updateConnectionIds,
3131 onEvaluatorCreated,
32+ onOpenChange,
33+ isOpen,
3234 ...props
3335} : {
3436 datasetId : string ;
3537 updateConnectionIds ?: string [ ] ;
3638 onEvaluatorCreated ?: ( datasetEvaluatorId : string ) => void ;
3739} & ModalOverlayProps ) => {
40+ const isDirtyRef = useRef ( false ) ;
41+
42+ // Reset dirty state when slideover opens
43+ useEffect ( ( ) => {
44+ if ( isOpen ) {
45+ isDirtyRef . current = false ;
46+ }
47+ } , [ isOpen ] ) ;
48+
49+ const handleOpenChange = useCallback (
50+ ( nextIsOpen : boolean ) => {
51+ if ( ! nextIsOpen && isDirtyRef . current ) {
52+ const confirmed = window . confirm (
53+ "You have unsaved changes. Are you sure you want to close?"
54+ ) ;
55+ if ( ! confirmed ) return ;
56+ }
57+ onOpenChange ?.( nextIsOpen ) ;
58+ } ,
59+ [ onOpenChange ]
60+ ) ;
61+
62+ const handleDirtyChange = useCallback ( ( isDirty : boolean ) => {
63+ isDirtyRef . current = isDirty ;
64+ } , [ ] ) ;
65+
3866 return (
39- < ModalOverlay { ...props } >
67+ < ModalOverlay { ...props } isOpen = { isOpen } onOpenChange = { handleOpenChange } >
4068 < Modal variant = "slideover" size = "fullscreen" >
4169 < Dialog >
4270 { ( { close } ) => (
4371 < Suspense fallback = { < Loading /> } >
4472 < CreateCodeEvaluatorDialog
4573 onClose = { close }
74+ onDirtyChange = { handleDirtyChange }
4675 datasetId = { datasetId }
4776 updateConnectionIds = { updateConnectionIds }
4877 onEvaluatorCreated = { onEvaluatorCreated }
@@ -57,11 +86,13 @@ export const CreateCodeDatasetEvaluatorSlideover = ({
5786
5887const CreateCodeEvaluatorDialog = ( {
5988 onClose,
89+ onDirtyChange,
6090 datasetId,
6191 updateConnectionIds,
6292 onEvaluatorCreated,
6393} : {
6494 onClose : ( ) => void ;
95+ onDirtyChange ?: ( isDirty : boolean ) => void ;
6596 datasetId : string ;
6697 updateConnectionIds ?: string [ ] ;
6798 onEvaluatorCreated ?: ( datasetEvaluatorId : string ) => void ;
@@ -74,19 +105,24 @@ const CreateCodeEvaluatorDialog = ({
74105 sandboxProviders {
75106 backendType
76107 language
108+ enabled
77109 configs {
78110 id
79111 name
80112 description
81113 }
82114 }
115+ sandboxBackends {
116+ backendType
117+ status
118+ }
83119 }
84120 ` ,
85121 { }
86122 ) ;
87- const sandboxConfigs = useMemo (
88- ( ) => mapSandboxConfigOptions ( data . sandboxProviders ) ,
89- [ data . sandboxProviders ]
123+ const sandboxConfigs = mapSandboxConfigOptions (
124+ data . sandboxProviders ,
125+ data . sandboxBackends
90126 ) ;
91127 const [ createCodeEvaluator , isCreatingCodeEvaluator ] =
92128 useMutation < CreateCodeDatasetEvaluatorSlideover_createCodeEvaluatorMutation > ( graphql `
@@ -119,40 +155,36 @@ const CreateCodeEvaluatorDialog = ({
119155 }
120156 }
121157 ` ) ;
122- const initialState = useMemo (
123- ( ) =>
124- ( {
125- evaluator : {
126- globalName : "" ,
127- name : "" ,
128- description : "" ,
129- inputMapping : {
130- literalMapping : { } ,
131- pathMapping : { } ,
132- } ,
133- kind : "CODE" ,
134- isBuiltin : false ,
135- includeExplanation : false ,
136- } ,
137- outputConfigs : [ createDefaultContinuousOutputConfig ( "" ) ] ,
138- dataset : {
139- readonly : true ,
140- id : datasetId ,
141- selectedExampleId : null ,
142- selectedSplitIds : [ ] ,
143- } ,
144- evaluatorMappingSource : EVALUATOR_MAPPING_SOURCE_DEFAULT ,
145- showPromptPreview : false ,
146- } ) satisfies EvaluatorStoreProps ,
147- [ datasetId ]
148- ) ;
158+ const initialState : EvaluatorStoreProps = {
159+ evaluator : {
160+ globalName : "" ,
161+ name : "" ,
162+ description : "" ,
163+ inputMapping : {
164+ literalMapping : { } ,
165+ pathMapping : { } ,
166+ } ,
167+ kind : "CODE" ,
168+ isBuiltin : false ,
169+ includeExplanation : false ,
170+ } ,
171+ outputConfigs : [ createDefaultContinuousOutputConfig ( "" ) ] ,
172+ dataset : {
173+ readonly : true ,
174+ id : datasetId ,
175+ selectedExampleId : null ,
176+ selectedSplitIds : [ ] ,
177+ } ,
178+ evaluatorMappingSource : EVALUATOR_MAPPING_SOURCE_DEFAULT ,
179+ showPromptPreview : false ,
180+ } ;
149181
150182 const onSubmit = (
151183 store : EvaluatorStoreInstance ,
152184 payload : {
153185 language : "PYTHON" | "TYPESCRIPT" ;
154186 sourceCode : string ;
155- sandboxConfigId : number | null ;
187+ sandboxConfigId ?: string | null ;
156188 }
157189 ) => {
158190 setError ( undefined ) ;
@@ -198,6 +230,7 @@ const CreateCodeEvaluatorDialog = ({
198230 title : "Evaluator created" ,
199231 message : "The code evaluator has been added to the dataset." ,
200232 } ) ;
233+ onDirtyChange ?.( false ) ;
201234 onClose ( ) ;
202235 } ,
203236 onError : ( mutationError ) => {
@@ -223,6 +256,8 @@ const CreateCodeEvaluatorDialog = ({
223256 { ( { store } ) => (
224257 < EditCodeEvaluatorDialogContent
225258 onSubmit = { ( payload ) => onSubmit ( store , payload ) }
259+ onCancel = { onClose }
260+ onDirtyChange = { onDirtyChange }
226261 isSubmitting = {
227262 isCreatingCodeEvaluator || isCreatingDatasetCodeEvaluator
228263 }
0 commit comments