@@ -45,10 +45,11 @@ import TestForm from './test-form'
4545
4646const m = defineMessages ( {
4747 repository : 'Use Device Repository formatters' ,
48- customJavascipt : 'Custom Javascript formatter' ,
48+ customJavascript : 'Custom Javascript formatter' ,
4949 formatterType : 'Formatter type' ,
5050 formatterCode : 'Formatter code' ,
51- formatterCodeReadOnly : 'Formatter code (read only)' ,
51+ encoderReadOnly : 'Encoder code (read only)' ,
52+ decoderReadOnly : 'Decoder code (read only)' ,
5253 grpcHost : 'GRPC host' ,
5354 grpcFieldDescription : 'The address of the service to connect to' ,
5455 appFormatter : 'Use application payload formatter' ,
@@ -74,12 +75,16 @@ const FIELD_NAMES = {
7475const formatterOptions = [
7576 { label : m . appFormatter , value : TYPES . DEFAULT } ,
7677 { label : m . repository , value : TYPES . REPOSITORY } ,
77- { label : m . customJavascipt , value : TYPES . JAVASCRIPT } ,
78+ { label : m . customJavascript , value : TYPES . JAVASCRIPT } ,
7879 { label : sharedMessages . grpcService , value : TYPES . GRPC } ,
7980 { label : 'CayenneLPP' , value : TYPES . CAYENNELPP } ,
8081 { label : sharedMessages . none , value : TYPES . NONE } ,
8182]
8283
84+ const hasRepositoryFormatter = repoFormatters =>
85+ repoFormatters !== undefined &&
86+ ( Boolean ( repoFormatters ?. decoder ) || Boolean ( repoFormatters ?. encoder ) )
87+
8388const validationSchema = Yup . object ( ) . shape ( {
8489 [ FIELD_NAMES . SELECT ] : Yup . string ( )
8590 . oneOf ( Object . values ( TYPES ) )
@@ -89,7 +94,7 @@ const validationSchema = Yup.object().shape({
8994 then : schema =>
9095 schema
9196 . required ( sharedMessages . validateRequired )
92- // See https://github.com/TheThingsNetwork/lorawan-stack/blob/v3.14/api/messages.proto#L380
97+ // See https://github.com/TheThingsNetwork/lorawan-stack/blob/v3.14/api/messages.proto#L748
9398 // for validation requirements.
9499 . max ( 40960 , Yup . passValues ( sharedMessages . validateTooLong ) ) ,
95100 } ) ,
@@ -112,8 +117,7 @@ const Formatter = ({
112117 pasteRepoPayloadFormatters,
113118 darkTheme,
114119} ) => {
115- const hasRepoFormatter = repoFormatters !== undefined && Object . keys ( repoFormatters ) . length !== 0
116- const repositoryPayloadFormatters = repoFormatters ?. formatter_parameter
120+ const hasRepoFormatter = hasRepositoryFormatter ( repoFormatters )
117121 const showParameter =
118122 type === TYPES . JAVASCRIPT || ( type === TYPES . DEFAULT && defaultType === 'FORMATTER_JAVASCRIPT' )
119123 const showRepositoryParameter =
@@ -180,18 +184,36 @@ const Formatter = ({
180184 }
181185 return (
182186 < >
183- < Form . Field
184- readOnly
185- component = { CodeEditor }
186- title = { m . formatterCodeReadOnly }
187- name = { FIELD_NAMES . REPOSITORY }
188- type = "text"
189- height = "10rem"
190- minLines = { 25 }
191- maxLines = { 25 }
192- value = { repositoryPayloadFormatters }
193- darkTheme = { darkTheme }
194- />
187+ < div className = "d-flex gap-cs-xxl" >
188+ { repoFormatters ?. decoder && (
189+ < Form . Field
190+ readOnly
191+ component = { CodeEditor }
192+ title = { m . decoderReadOnly }
193+ name = { FIELD_NAMES . REPOSITORY }
194+ type = "text"
195+ height = "10rem"
196+ minLines = { 25 }
197+ maxLines = { 25 }
198+ value = { repoFormatters ?. decoder ?. formatter_parameter }
199+ darkTheme = { darkTheme }
200+ />
201+ ) }
202+ { repoFormatters ?. encoder && (
203+ < Form . Field
204+ readOnly
205+ component = { CodeEditor }
206+ title = { m . encoderReadOnly }
207+ name = { FIELD_NAMES . REPOSITORY }
208+ type = "text"
209+ height = "10rem"
210+ minLines = { 25 }
211+ maxLines = { 25 }
212+ value = { repoFormatters ?. encoder ?. formatter_parameter }
213+ darkTheme = { darkTheme }
214+ />
215+ ) }
216+ </ div >
195217 < Link . DocLink path = "/integrations/payload-formatters/device-repo/" secondary >
196218 < Message content = { m . learnMoreAboutDeviceRepo } />
197219 </ Link . DocLink >
@@ -208,7 +230,12 @@ Formatter.propTypes = {
208230 pasteAppPayloadFormatter : PropTypes . func . isRequired ,
209231 pasteRepoPayloadFormatters : PropTypes . func . isRequired ,
210232 repoFormatters : PropTypes . shape ( {
211- formatter_parameter : PropTypes . string ,
233+ decoder : PropTypes . shape ( {
234+ formatter_parameter : PropTypes . string ,
235+ } ) ,
236+ encoder : PropTypes . shape ( {
237+ formatter_parameter : PropTypes . string ,
238+ } ) ,
212239 } ) ,
213240 type : PropTypes . string . isRequired ,
214241}
@@ -242,7 +269,8 @@ const PayloadFormattersForm = ({
242269 const [ error , setError ] = useState ( undefined )
243270 const [ testResult , setTestResult ] = useState ( { } )
244271 const formRef = useRef ( null )
245- const repositoryPayloadFormatters = repoFormatters ?. formatter_parameter
272+ const repositoryDecoder = repoFormatters ?. decoder ?. formatter_parameter
273+ const repositoryEncoder = repoFormatters ?. encoder ?. formatter_parameter
246274
247275 // Using the unstable version of useBlocker because `useBlocker` and `usePrompt` were removes from react-router v6.
248276 // Reference: https://github.com/remix-run/react-router/issues/8139#issuecomment-1396078490
@@ -374,8 +402,11 @@ const PayloadFormattersForm = ({
374402 } , [ defaultParameter , uplink ] )
375403
376404 const pasteRepoPayloadFormatters = useCallback ( ( ) => {
405+ const repositoryPayloadFormatters = uplink
406+ ? repositoryDecoder
407+ : `${ repositoryEncoder ?? '' } \n${ repositoryDecoder ?? '' } `
377408 formRef ?. current ?. setFieldValue ( FIELD_NAMES . JAVASCRIPT , repositoryPayloadFormatters )
378- } , [ repositoryPayloadFormatters ] )
409+ } , [ repositoryDecoder , repositoryEncoder , uplink ] )
379410
380411 const _showTestSection = useCallback ( ( ) => {
381412 // Show the testing section if:
@@ -398,7 +429,8 @@ const PayloadFormattersForm = ({
398429 [ FIELD_NAMES . GRPC ] :
399430 initialType === TYPES . GRPC ? initialParameter : getDefaultGrpcServiceFormatter ( uplink ) ,
400431 }
401- const hasRepoFormatter = repoFormatters !== undefined && Object . keys ( repoFormatters ) . length !== 0
432+
433+ const hasRepoFormatter = hasRepositoryFormatter ( repoFormatters )
402434 let options = allowReset
403435 ? formatterOptions
404436 : formatterOptions . filter ( o => o . value !== TYPES . DEFAULT )
@@ -513,7 +545,12 @@ PayloadFormattersForm.propTypes = {
513545 onTestSubmit : PropTypes . func ,
514546 onTypeChange : PropTypes . func ,
515547 repoFormatters : PropTypes . shape ( {
516- formatter_parameter : PropTypes . string ,
548+ decoder : PropTypes . shape ( {
549+ formatter_parameter : PropTypes . string ,
550+ } ) ,
551+ encoder : PropTypes . shape ( {
552+ formatter_parameter : PropTypes . string ,
553+ } ) ,
517554 } ) ,
518555 uplink : PropTypes . bool . isRequired ,
519556}
0 commit comments