@@ -23,6 +23,7 @@ import browserStyles from 'dashboard/Data/Browser/Browser.scss';
2323import { CurrentApp } from 'context/currentApp' ;
2424import Modal from 'components/Modal/Modal.react' ;
2525import equal from 'fast-deep-equal' ;
26+ import Notification from 'dashboard/Data/Browser/Notification.react' ;
2627
2728@subscribeTo ( 'Config' , 'config' )
2829class Config extends TableView {
@@ -41,7 +42,10 @@ class Config extends TableView {
4142 modalMasterKeyOnly : false ,
4243 loading : false ,
4344 confirmModalOpen : false ,
45+ lastError : null ,
46+ lastNote : null ,
4447 } ;
48+ this . noteTimeout = null ;
4549 }
4650
4751 componentWillMount ( ) {
@@ -127,12 +131,24 @@ class Config extends TableView {
127131 } }
128132 >
129133 < div className = { [ browserStyles . confirmConfig ] } >
130- This parameter changed while you were editing it. If you continue, the latest changes will be lost and replaced with your version. Do you want to proceed?
134+ This parameter changed while you were editing it. If you continue, the latest changes
135+ will be lost and replaced with your version. Do you want to proceed?
131136 </ div >
132137 </ Modal >
133138 ) ;
134139 }
135- return extras ;
140+ let notification = null ;
141+ if ( this . state . lastError ) {
142+ notification = < Notification note = { this . state . lastError } isErrorNote = { true } /> ;
143+ } else if ( this . state . lastNote ) {
144+ notification = < Notification note = { this . state . lastNote } isErrorNote = { false } /> ;
145+ }
146+ return (
147+ < >
148+ { extras }
149+ { notification }
150+ </ >
151+ ) ;
136152 }
137153
138154 parseValueForModal ( dataValue ) {
@@ -186,7 +202,6 @@ class Config extends TableView {
186202 * Opens the modal dialog to edit the Config parameter.
187203 */
188204 const openModal = async ( ) => {
189-
190205 // Show dialog
191206 this . setState ( {
192207 loading : true ,
@@ -203,7 +218,8 @@ class Config extends TableView {
203218 // Get latest param values
204219 const fetchedParams = this . props . config . data . get ( 'params' ) ;
205220 const fetchedValue = fetchedParams . get ( this . state . modalParam ) ;
206- const fetchedMasterKeyOnly = this . props . config . data . get ( 'masterKeyOnly' ) ?. get ( this . state . modalParam ) || false ;
221+ const fetchedMasterKeyOnly =
222+ this . props . config . data . get ( 'masterKeyOnly' ) ?. get ( this . state . modalParam ) || false ;
207223
208224 // Parse fetched data
209225 const { modalValue : fetchedModalValue } = this . parseValueForModal ( fetchedValue ) ;
@@ -219,6 +235,7 @@ class Config extends TableView {
219235 // Define column styles
220236 const columnStyleLarge = { width : '30%' , cursor : 'pointer' } ;
221237 const columnStyleSmall = { width : '15%' , cursor : 'pointer' } ;
238+ const columnStyleAction = { width : '10%' , textAlign : 'center' } ;
222239
223240 const openModalValueColumn = ( ) => {
224241 if ( data . value instanceof Parse . File ) {
@@ -244,6 +261,13 @@ class Config extends TableView {
244261 < td style = { columnStyleLarge } onClick = { openModalValueColumn } >
245262 { value }
246263 </ td >
264+ < td style = { columnStyleAction } >
265+ { type === 'Array' && (
266+ < a onClick = { ( ) => this . addArrayEntry ( data . param ) } >
267+ < Icon width = { 16 } height = { 16 } name = "plus-solid" />
268+ </ a >
269+ ) }
270+ </ td >
247271 < td style = { columnStyleSmall } onClick = { openModal } >
248272 { data . masterKeyOnly . toString ( ) }
249273 </ td >
@@ -264,9 +288,12 @@ class Config extends TableView {
264288 < TableHeader key = "type" width = { 15 } >
265289 Type
266290 </ TableHeader > ,
267- < TableHeader key = "value" width = { 30 } >
291+ < TableHeader key = "value" width = { 25 } >
268292 Value
269293 </ TableHeader > ,
294+ < TableHeader key = "action" width = { 10 } >
295+ Action
296+ </ TableHeader > ,
270297 < TableHeader key = "masterKeyOnly" width = { 15 } >
271298 Master key only
272299 </ TableHeader > ,
@@ -430,6 +457,53 @@ class Config extends TableView {
430457 modalMasterKeyOnly : false ,
431458 } ) ;
432459 }
460+
461+ showNote ( message , isError ) {
462+ if ( ! message ) {
463+ return ;
464+ }
465+ clearTimeout ( this . noteTimeout ) ;
466+ if ( isError ) {
467+ this . setState ( { lastError : message , lastNote : null } ) ;
468+ } else {
469+ this . setState ( { lastNote : message , lastError : null } ) ;
470+ }
471+ this . noteTimeout = setTimeout ( ( ) => {
472+ this . setState ( { lastError : null , lastNote : null } ) ;
473+ } , 3500 ) ;
474+ }
475+
476+ async addArrayEntry ( param ) {
477+ const input = window . prompt ( 'New array entry (JSON supported)' ) ;
478+ if ( input === null ) {
479+ return ;
480+ }
481+ let value ;
482+ try {
483+ value = JSON . parse ( input ) ;
484+ } catch ( e ) {
485+ value = input ;
486+ }
487+ try {
488+ this . setState ( { loading : true } ) ;
489+ await Parse . _request (
490+ 'PUT' ,
491+ 'config' ,
492+ {
493+ params : {
494+ [ param ] : { __op : 'AddUnique' , objects : [ Parse . _encode ( value ) ] } ,
495+ } ,
496+ } ,
497+ { useMasterKey : true }
498+ ) ;
499+ await this . props . config . dispatch ( ActionTypes . FETCH ) ;
500+ this . showNote ( 'Entry added' ) ;
501+ } catch ( e ) {
502+ this . showNote ( `Failed to add entry: ${ e . message } ` , true ) ;
503+ } finally {
504+ this . setState ( { loading : false } ) ;
505+ }
506+ }
433507}
434508
435509export default Config ;
0 commit comments