@@ -180,28 +180,39 @@ export const Intents = observer(({ handleTabChange }: { handleTabChange: any })
180180 const [ intentValue , setIntentValue ] = useState < ListenerOptionType | null > ( null ) ;
181181 const [ raiseIntentError , setRaiseIntentError ] = useState < string | false > ( false ) ;
182182 const [ intentListener , setIntentListener ] = useState < ListenerOptionType | null > ( null ) ;
183+ const [ intentListenerWithContext , setIntentListenerWithContext ] = useState < ListenerOptionType | null > ( null ) ;
183184 const [ intentsForContext , setIntentsForContext ] = useState < ListenerOptionType [ ] | null > ( null ) ;
184185 const [ targetApp , setTargetApp ] = useState < string > ( 'None' ) ;
185186 const [ contextTargetApp , setContextTargetApp ] = useState < string > ( 'None' ) ;
186187 const [ raiseIntentContext , setRaiseIntentContext ] = useState < ContextType | null > ( null ) ;
187188 const [ raiseIntentWithContextContext , setRaiseIntentWithContextContext ] = useState < ContextType | null > ( null ) ;
188189 const [ intentError , setIntentError ] = useState < string | false > ( false ) ;
190+ const [ intentWithContextError , setIntentWithContextError ] = useState < string | false > ( false ) ;
189191 const [ intentResolution , setIntentResolution ] = useState < IntentResolution | undefined | null > ( null ) ;
190192 const [ intentForContextResolution , setIntentForContextResolution ] = useState < IntentResolution | undefined | null > (
191193 null
192194 ) ;
193195 const intentListenersOptions : ListenerOptionType [ ] = intentStore . intentsList ;
194196 const [ contextFields , setContextFields ] = useState < any [ ] > ( [ ] ) ;
197+ const [ contextFieldsWithContext , setContextFieldsWithContext ] = useState < any [ ] > ( [ ] ) ;
195198 const [ resultTypeContext , setResultTypeContext ] = useState < ContextType | null > ( null ) ;
199+ const [ resultTypeListenerWithContextContext , setResultTypeListenerWithContextContext ] = useState < ContextType | null > (
200+ null
201+ ) ;
196202 const [ resultOverChannelContextList , setResultOverChannelContextList ] = useState < any > ( { } ) ;
197203 const [ resultOverChannelContextDelays , setResultOverChannelContextDelays ] = useState < any > ( { } ) ;
198204 const [ sendIntentResult , setSendIntentResult ] = useState < boolean | undefined > ( false ) ;
205+ const [ sendIntentWithIntentResult , setSendIntentWithIntentResult ] = useState < boolean | undefined > ( false ) ;
199206 const [ resultType , setResultType ] = useState < string | null > ( null ) ;
207+ const [ listenerWithContextResultType , setListenerWithContextResultType ] = useState < string | null > ( null ) ;
200208 const [ useTargets , setUseTargets ] = useState < boolean > ( false ) ;
201209 const [ useContextTargets , setUseContextTargets ] = useState < boolean > ( false ) ;
202210 const [ channelType , setChannelType ] = useState < string | null > ( 'app-channel' ) ;
211+ const [ channelTypeWithContext , setChannelTypeWithContext ] = useState < string | null > ( 'app-channel' ) ;
203212 const [ sendResultOverChannel , setSendResultOverChannel ] = useState < boolean | undefined > ( false ) ;
213+ const [ sendResultOverChannelWithContext , setSendResultOverChannelWithContext ] = useState < boolean | undefined > ( false ) ;
204214 const [ currentAppChannelId , setCurrentAppChannelId ] = useState < string > ( '' ) ;
215+ const [ currentAppChannelIdWithContext , setCurrentAppChannelIdWithContext ] = useState < string > ( '' ) ;
205216 const [ targetOptions , setTargetOptions ] = useState < ReactElement [ ] > ( [ ] ) ;
206217 const [ targetOptionsforContext , setTargetOptionsforContext ] = useState < ReactElement [ ] > ( [ ] ) ;
207218
@@ -466,10 +477,32 @@ export const Intents = observer(({ handleTabChange }: { handleTabChange: any })
466477 setSendIntentResult ( false ) ;
467478 } ;
468479
480+ const handleAddIntentListenerWithContext = ( ) => {
481+ if ( ! intentListener ) {
482+ setIntentError ( 'Enter intent' ) ;
483+ return ;
484+ } else {
485+ intentStore . addIntentListener (
486+ intentListener . value ,
487+ sendIntentResult && resultType === 'context-result' ? toJS ( resultTypeListenerWithContextContext ) : null ,
488+ sendIntentResult && resultType === 'channel-result' ? currentAppChannelId : undefined ,
489+ sendIntentResult && resultType === 'channel-result' ? channelType === 'private-channel' : undefined ,
490+ sendIntentResult && resultType === 'channel-result' ? resultOverChannelContextList : undefined ,
491+ sendIntentResult && resultType === 'channel-result' ? resultOverChannelContextDelays : undefined
492+ ) ;
493+ setIntentListener ( null ) ;
494+ }
495+ setSendIntentResult ( false ) ;
496+ } ;
497+
469498 const handleChannelTypeChange = ( event : React . MouseEvent < HTMLElement > , nextView : string ) => {
470499 setChannelType ( nextView ) ;
471500 } ;
472501
502+ const handleChannelTypeWithContextChange = ( event : React . MouseEvent < HTMLElement > , nextView : string ) => {
503+ setChannelTypeWithContext ( nextView ) ;
504+ } ;
505+
473506 const handleTargetToggle = ( event : ChangeEvent < HTMLInputElement > , checked : boolean ) => {
474507 setUseTargets ( checked ) ;
475508 if ( ! checked ) {
@@ -520,6 +553,29 @@ export const Intents = observer(({ handleTabChange }: { handleTabChange: any })
520553 ] ) ;
521554 } ;
522555
556+ const handleAddContextWithContextField = ( ) => {
557+ setContextFieldsWithContext ( current => [
558+ ...current ,
559+ < Grid container direction = "row" key = { contextFieldsWithContext . length } >
560+ < Grid item className = { classes . indentLeft } >
561+ < TextField
562+ variant = "outlined"
563+ label = "Delay (ms)"
564+ type = "number"
565+ size = "small"
566+ onChange = { e => setChannelContextDelay ( e . target . value , contextFieldsWithContext . length ) }
567+ />
568+ </ Grid >
569+ < Grid item className = { `${ classes . indentLeft } ${ classes . field } ` } >
570+ < ContextTemplates
571+ handleTabChange = { handleTabChange }
572+ contextStateSetter = { ( context : any ) => setChannelContextList ( context , contextFieldsWithContext . length ) }
573+ />
574+ </ Grid >
575+ </ Grid > ,
576+ ] ) ;
577+ } ;
578+
523579 useEffect ( ( ) => {
524580 setIntentValue ( null ) ;
525581 const fetchIntents = async ( ) => {
@@ -996,6 +1052,205 @@ export const Intents = observer(({ handleTabChange }: { handleTabChange: any })
9961052 </ RadioGroup >
9971053 </ Grid >
9981054 ) }
1055+
1056+ < Grid container item spacing = { 2 } justifyContent = "flex-end" className = { classes . spread } >
1057+ < Grid item xs = { 12 } >
1058+ < Typography className = { classes . bottomMargin } variant = "h5" >
1059+ Add intent listener with context
1060+ </ Typography >
1061+ </ Grid >
1062+ < Grid item className = { `${ classes . field } ${ classes . removeSidePadding } ` } >
1063+ < Autocomplete
1064+ id = "intent-listener-with-context"
1065+ size = "small"
1066+ selectOnFocus
1067+ blurOnSelect
1068+ clearOnBlur
1069+ handleHomeEndKeys
1070+ value = { intentListenerWithContext }
1071+ onChange = { handleChangeListener ( setIntentListenerWithContext , setIntentWithContextError ) }
1072+ filterOptions = { filterOptions }
1073+ options = { intentListenersOptions }
1074+ getOptionLabel = { getOptionLabel }
1075+ renderOption = { option => option . title }
1076+ renderInput = { params => (
1077+ < TemplateTextField
1078+ label = "INTENT LISTENER"
1079+ placeholder = "Enter Intent Type"
1080+ variant = "outlined"
1081+ { ...params }
1082+ error = { ! ! intentWithContextError }
1083+ helperText = { intentWithContextError }
1084+ />
1085+ ) }
1086+ />
1087+ </ Grid >
1088+
1089+ < Grid item className = { classes . controls } >
1090+ < Button
1091+ variant = "contained"
1092+ color = "primary"
1093+ onClick = { handleAddIntentListenerWithContext }
1094+ disabled = { intentListenerWithContext === null }
1095+ >
1096+ Add listener
1097+ </ Button >
1098+
1099+ < Tooltip title = "Copy code example" aria-label = "Copy code example" >
1100+ < IconButton
1101+ size = "small"
1102+ aria-label = "Copy code example"
1103+ color = "primary"
1104+ onClick = { ( ) => {
1105+ let exampleToUse = codeExamples . intentListenerWithContext ;
1106+ if ( listenerWithContextResultType === 'context-result' ) {
1107+ exampleToUse = codeExamples . intentListenerWithContextContextResult ;
1108+ } else if ( listenerWithContextResultType === 'channel-result' ) {
1109+ if ( channelType === 'app-channel' ) {
1110+ exampleToUse = codeExamples . intentListenerWithContextAppChannel ;
1111+ } else {
1112+ exampleToUse = codeExamples . intentListenerWithContextPrivateChannel ;
1113+ }
1114+ }
1115+ copyToClipboard ( exampleToUse , 'addIntentListener' ) ( ) ;
1116+ } }
1117+ >
1118+ < FileCopyIcon />
1119+ </ IconButton >
1120+ </ Tooltip >
1121+
1122+ < Link
1123+ onClick = { openApiDocsLink }
1124+ target = "FDC3APIDocs"
1125+ href = "https://fdc3.finos.org/docs/api/ref/DesktopAgent#addintentlistenerWithContext"
1126+ >
1127+ < InfoOutlinedIcon />
1128+ </ Link >
1129+ </ Grid >
1130+ </ Grid >
1131+ { window . fdc3Version === '2.0' && (
1132+ < Grid item xs = { 12 } >
1133+ < FormGroup >
1134+ < FormControlLabel
1135+ control = {
1136+ < Checkbox
1137+ className = { classes . input }
1138+ color = "default"
1139+ checked = { sendIntentWithIntentResult }
1140+ onChange = { e => setSendIntentWithIntentResult ( e . target . checked ) }
1141+ />
1142+ }
1143+ label = "Send intent result"
1144+ />
1145+ </ FormGroup >
1146+ </ Grid >
1147+ ) }
1148+ { sendIntentWithIntentResult && (
1149+ < Grid item xs = { 12 } className = { classes . indentLeft } >
1150+ < RadioGroup
1151+ name = "intent-result-type"
1152+ value = { listenerWithContextResultType }
1153+ onChange = { e => setListenerWithContextResultType ( e . target . value ) }
1154+ >
1155+ < FormControlLabel
1156+ value = "context-result"
1157+ control = { < Radio className = { classes . input } /> }
1158+ label = "Context result"
1159+ />
1160+ { listenerWithContextResultType === 'context-result' && (
1161+ < Grid item className = { classes . indentLeft } >
1162+ < ContextTemplates
1163+ handleTabChange = { handleTabChange }
1164+ contextStateSetter = { setResultTypeListenerWithContextContext }
1165+ />
1166+ </ Grid >
1167+ ) }
1168+ < FormControlLabel
1169+ value = "channel-result"
1170+ control = { < Radio className = { classes . input } /> }
1171+ label = "Channel result"
1172+ />
1173+ { listenerWithContextResultType === 'channel-result' && (
1174+ < Grid item className = { classes . indentLeft } >
1175+ < ToggleButtonGroup
1176+ value = { channelTypeWithContext }
1177+ exclusive
1178+ onChange = { handleChannelTypeWithContextChange }
1179+ aria-label = "result channel type"
1180+ >
1181+ < ToggleButton className = { classes . toggle } value = "app-channel" aria-label = "left aligned" >
1182+ App channel
1183+ </ ToggleButton >
1184+ < ToggleButton className = { classes . toggle } value = "private-channel" aria-label = "left aligned" >
1185+ Private channel
1186+ </ ToggleButton >
1187+ </ ToggleButtonGroup >
1188+
1189+ { channelType === 'app-channel' && (
1190+ < Grid item className = { classes . field } >
1191+ < TextField
1192+ fullWidth
1193+ variant = "outlined"
1194+ label = "Channel Name"
1195+ type = "text"
1196+ size = "small"
1197+ onChange = { ( e : any ) => setCurrentAppChannelIdWithContext ( e . target . value ) }
1198+ value = { currentAppChannelIdWithContext }
1199+ />
1200+ </ Grid >
1201+ ) }
1202+ < FormGroup >
1203+ { channelType === 'private-channel' && (
1204+ < Typography variant = "caption" className = { classes . caption } >
1205+ Context streaming will start AFTER a context listener is added to the channel
1206+ </ Typography >
1207+ ) }
1208+ < FormControlLabel
1209+ control = {
1210+ < Checkbox
1211+ className = { classes . input }
1212+ color = "default"
1213+ checked = { sendResultOverChannelWithContext }
1214+ onChange = { e => setSendResultOverChannelWithContext ( e . target . checked ) }
1215+ />
1216+ }
1217+ label = "Send context result over channel"
1218+ />
1219+ </ FormGroup >
1220+ { sendResultOverChannelWithContext && (
1221+ < >
1222+ { contextFieldsWithContext . map ( ( field , index ) => (
1223+ < React . Fragment key = { index } > { field } </ React . Fragment >
1224+ ) ) }
1225+ < Grid item className = { `${ classes . indentLeft } ${ classes . controls } ` } >
1226+ < Tooltip
1227+ title = "Add context result (delays will trigger sequentially)"
1228+ aria-label = "Add context result (delays will trigger sequentially)"
1229+ >
1230+ < IconButton
1231+ size = "small"
1232+ aria-label = "Add context result (delays will trigger sequentially)"
1233+ color = "primary"
1234+ onClick = { handleAddContextWithContextField }
1235+ >
1236+ < AddCircleOutlineIcon />
1237+ </ IconButton >
1238+ </ Tooltip >
1239+
1240+ < Link
1241+ target = "FDC3APIDocs"
1242+ href = "https://fdc3.finos.org/docs/api/ref/DesktopAgent#addintentlistener"
1243+ >
1244+ < InfoOutlinedIcon />
1245+ </ Link >
1246+ </ Grid >
1247+ </ >
1248+ ) }
1249+ </ Grid >
1250+ ) }
1251+ </ RadioGroup >
1252+ </ Grid >
1253+ ) }
9991254 < Grid item xs = { 12 } >
10001255 < Alert severity = "info" >
10011256 Desktop Agents often require apps that listen for intents to include the intent in their appD record.
0 commit comments