@@ -15,6 +15,7 @@ import React, { Component } from 'react';
15
15
import styles from 'components/BrowserCell/BrowserCell.scss' ;
16
16
import { unselectable } from 'stylesheets/base.scss' ;
17
17
import Tooltip from '../Tooltip/PopperTooltip.react' ;
18
+ import * as ColumnPreferences from 'lib/ColumnPreferences' ;
18
19
19
20
export default class BrowserCell extends Component {
20
21
constructor ( ) {
@@ -23,13 +24,161 @@ export default class BrowserCell extends Component {
23
24
this . cellRef = React . createRef ( ) ;
24
25
this . copyableValue = undefined ;
25
26
this . state = {
26
- showTooltip : false
27
+ showTooltip : false ,
28
+ content : null ,
29
+ classes : [ ]
30
+ } ;
31
+ }
32
+
33
+ async renderCellContent ( ) {
34
+ let content = this . props . value ;
35
+ let isNewRow = this . props . row < 0 ;
36
+ this . copyableValue = content ;
37
+ let classes = [ styles . cell , unselectable ] ;
38
+ if ( this . props . hidden ) {
39
+ content = this . props . value !== undefined || ! isNewRow ? '(hidden)' : this . props . isRequired ? '(required)' : '(undefined)' ;
40
+ classes . push ( styles . empty ) ;
41
+ } else if ( this . props . value === undefined ) {
42
+ if ( this . props . type === 'ACL' ) {
43
+ this . copyableValue = content = 'Public Read + Write' ;
44
+ } else {
45
+ this . copyableValue = content = '(undefined)' ;
46
+ classes . push ( styles . empty ) ;
47
+ }
48
+ content = isNewRow && this . props . isRequired && this . props . value === undefined ? '(required)' : content ;
49
+ } else if ( this . props . value === null ) {
50
+ this . copyableValue = content = '(null)' ;
51
+ classes . push ( styles . empty ) ;
52
+ } else if ( this . props . value === '' ) {
53
+ content = < span > </ span > ;
54
+ classes . push ( styles . empty ) ;
55
+ } else if ( this . props . type === 'Pointer' ) {
56
+ const defaultPointerKey = await ColumnPreferences . getPointerDefaultKey ( this . props . appId , this . props . value . className ) ;
57
+ let dataValue = this . props . value . id ;
58
+ if ( defaultPointerKey !== 'objectId' ) {
59
+ dataValue = this . props . value . get ( defaultPointerKey ) ;
60
+ if ( dataValue && typeof dataValue === 'object' ) {
61
+ if ( dataValue instanceof Date ) {
62
+ dataValue = dataValue . toLocaleString ( ) ;
63
+ }
64
+ else {
65
+ if ( ! this . props . value . id ) {
66
+ dataValue = this . props . value . id ;
67
+ } else {
68
+ dataValue = '(undefined)' ;
69
+ }
70
+ }
71
+ }
72
+ if ( ! dataValue ) {
73
+ if ( this . props . value . id ) {
74
+ dataValue = this . props . value . id ;
75
+ } else {
76
+ dataValue = '(undefined)' ;
77
+ }
78
+ }
79
+ }
80
+
81
+ if ( this . props . value && this . props . value . __type ) {
82
+ const object = new Parse . Object ( this . props . value . className ) ;
83
+ object . id = this . props . value . objectId ;
84
+ this . props . value = object ;
85
+ }
86
+
87
+ content = this . props . onPointerClick ? (
88
+ < Pill value = { dataValue } onClick = { this . props . onPointerClick . bind ( undefined , this . props . value ) } followClick = { true } />
89
+ ) : (
90
+ dataValue
91
+ ) ;
92
+
93
+ this . copyableValue = this . props . value . id ;
94
+ }
95
+ else if ( this . props . type === 'Array' ) {
96
+ if ( this . props . value [ 0 ] && typeof this . props . value [ 0 ] === 'object' && this . props . value [ 0 ] . __type === 'Pointer' ) {
97
+ const array = [ ] ;
98
+ this . props . value . map ( ( v , i ) => {
99
+ if ( typeof v !== 'object' || v . __type !== 'Pointer' ) {
100
+ throw new Error ( 'Invalid type found in pointer array' ) ;
101
+ }
102
+ const object = new Parse . Object ( v . className ) ;
103
+ object . id = v . objectId ;
104
+ array . push (
105
+ < Pill key = { i } value = { v . objectId } onClick = { this . props . onPointerClick . bind ( undefined , object ) } followClick = { true } />
106
+ ) ;
107
+ } ) ;
108
+ this . copyableValue = content = < ul >
109
+ { array . map ( a => < li > { a } </ li > ) }
110
+ </ ul >
111
+ if ( array . length > 1 ) {
112
+ classes . push ( styles . hasMore ) ;
113
+ }
114
+ }
115
+ else {
116
+ this . copyableValue = content = JSON . stringify ( this . props . value ) ;
117
+ }
118
+ }
119
+ else if ( this . props . type === 'Date' ) {
120
+ if ( typeof value === 'object' && this . props . value . __type ) {
121
+ this . props . value = new Date ( this . props . value . iso ) ;
122
+ } else if ( typeof value === 'string' ) {
123
+ this . props . value = new Date ( this . props . value ) ;
124
+ }
125
+ this . copyableValue = content = dateStringUTC ( this . props . value ) ;
126
+ } else if ( this . props . type === 'Boolean' ) {
127
+ this . copyableValue = content = this . props . value ? 'True' : 'False' ;
128
+ } else if ( this . props . type === 'Object' || this . props . type === 'Bytes' ) {
129
+ this . copyableValue = content = JSON . stringify ( this . props . value ) ;
130
+ } else if ( this . props . type === 'File' ) {
131
+ const fileName = this . props . value . url ( ) ? getFileName ( this . props . value ) : 'Uploading\u2026' ;
132
+ content = < Pill value = { fileName } fileDownloadLink = { this . props . value . url ( ) } /> ;
133
+ this . copyableValue = fileName ;
134
+ } else if ( this . props . type === 'ACL' ) {
135
+ let pieces = [ ] ;
136
+ let json = this . props . value . toJSON ( ) ;
137
+ if ( Object . prototype . hasOwnProperty . call ( json , '*' ) ) {
138
+ if ( json [ '*' ] . read && json [ '*' ] . write ) {
139
+ pieces . push ( 'Public Read + Write' ) ;
140
+ } else if ( json [ '*' ] . read ) {
141
+ pieces . push ( 'Public Read' ) ;
142
+ } else if ( json [ '*' ] . write ) {
143
+ pieces . push ( 'Public Write' ) ;
144
+ }
145
+ }
146
+ for ( let role in json ) {
147
+ if ( role !== '*' ) {
148
+ pieces . push ( role ) ;
149
+ }
150
+ }
151
+ if ( pieces . length === 0 ) {
152
+ pieces . push ( 'Master Key Only' ) ;
153
+ }
154
+ this . copyableValue = content = pieces . join ( ', ' ) ;
155
+ } else if ( this . props . type === 'GeoPoint' ) {
156
+ this . copyableValue = content = `(${ this . props . value . latitude } , ${ this . props . value . longitude } )` ;
157
+ } else if ( this . props . type === 'Polygon' ) {
158
+ this . copyableValue = content = this . props . value . coordinates . map ( coord => `(${ coord } )` )
159
+ } else if ( this . props . type === 'Relation' ) {
160
+ content = this . props . setRelation ? (
161
+ < div style = { { textAlign : 'center' } } >
162
+ < Pill onClick = { ( ) => this . props . setRelation ( this . props . value ) } value = 'View relation' followClick = { true } />
163
+ </ div >
164
+ ) : (
165
+ 'Relation'
166
+ ) ;
167
+ this . copyableValue = undefined ;
27
168
}
28
169
this . onContextMenu = this . onContextMenu . bind ( this ) ;
29
170
171
+ if ( this . props . markRequiredField && this . props . isRequired && ! this . props . value ) {
172
+ classes . push ( styles . required ) ;
173
+ }
174
+
175
+ this . setState ( { ...this . state , content, classes } )
30
176
}
31
177
32
- componentDidUpdate ( prevProps ) {
178
+ async componentDidUpdate ( prevProps ) {
179
+ if ( this . props . value !== prevProps . value ) {
180
+ await this . renderCellContent ( ) ;
181
+ }
33
182
if ( this . props . current ) {
34
183
const node = this . cellRef . current ;
35
184
const { setRelation } = this . props ;
@@ -58,7 +207,7 @@ export default class BrowserCell extends Component {
58
207
}
59
208
60
209
shouldComponentUpdate ( nextProps , nextState ) {
61
- if ( nextState . showTooltip !== this . state . showTooltip ) {
210
+ if ( nextState . showTooltip !== this . state . showTooltip || nextState . content !== this . state . content ) {
62
211
return true ;
63
212
}
64
213
const shallowVerifyProps = [ ...new Set ( Object . keys ( this . props ) . concat ( Object . keys ( nextProps ) ) ) ]
@@ -225,139 +374,27 @@ export default class BrowserCell extends Component {
225
374
} ) ) ) ;
226
375
}
227
376
377
+ componentDidMount ( ) {
378
+ this . renderCellContent ( ) ;
379
+ }
380
+
228
381
//#endregion
229
382
230
383
render ( ) {
231
- let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, onPointerCmdClick, row, col, field, onEditSelectedRow, readonly, isRequired, markRequiredFieldRow } = this . props ;
232
- let content = value ;
384
+ let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, onPointerCmdClick, row, col, field, onEditSelectedRow, readonly, isRequired, markRequiredFieldRow } = this . props ;
233
385
let isNewRow = row < 0 ;
234
- this . copyableValue = content ;
235
- let classes = [ styles . cell , unselectable ] ;
236
- if ( hidden ) {
237
- content = value !== undefined || ! isNewRow ? '(hidden)' : isRequired ? '(required)' : '(undefined)' ;
238
- classes . push ( styles . empty ) ;
239
- } else if ( value === undefined ) {
240
- if ( type === 'ACL' ) {
241
- this . copyableValue = content = 'Public Read + Write' ;
242
- } else {
243
- this . copyableValue = content = '(undefined)' ;
244
- classes . push ( styles . empty ) ;
245
- }
246
- content = isNewRow && isRequired && value === undefined ? '(required)' : content ;
247
- } else if ( value === null ) {
248
- this . copyableValue = content = '(null)' ;
249
- classes . push ( styles . empty ) ;
250
- } else if ( value === '' ) {
251
- content = < span > </ span > ;
252
- classes . push ( styles . empty ) ;
253
- } else if ( type === 'Pointer' ) {
254
- if ( value && value . __type ) {
255
- const object = new Parse . Object ( value . className ) ;
256
- object . id = value . objectId ;
257
- value = object ;
258
- }
259
- content = onPointerClick ? (
260
- < Pill
261
- value = { value . id }
262
- onClick = { onPointerClick . bind ( undefined , value ) }
263
- followClick = { true }
264
- />
265
- ) : (
266
- value . id
267
- ) ;
268
- this . copyableValue = value . id ;
269
- }
270
- else if ( type === 'Array' ) {
271
- if ( value [ 0 ] && typeof value [ 0 ] === 'object' && value [ 0 ] . __type === 'Pointer' ) {
272
- const array = [ ] ;
273
- value . map ( ( v , i ) => {
274
- if ( typeof v !== 'object' || v . __type !== 'Pointer' ) {
275
- throw new Error ( 'Invalid type found in pointer array' ) ;
276
- }
277
- const object = new Parse . Object ( v . className ) ;
278
- object . id = v . objectId ;
279
- array . push (
280
- < Pill
281
- key = { v . objectId }
282
- value = { v . objectId }
283
- onClick = { onPointerClick . bind ( undefined , object ) }
284
- followClick = { true }
285
- />
286
- ) ;
287
- } ) ;
288
- content = < ul className = { styles . hasMore } >
289
- { array . map ( a => < li > { a } </ li > ) }
290
- </ ul >
291
- this . copyableValue = JSON . stringify ( value ) ;
292
- if ( array . length > 1 ) {
293
- classes . push ( styles . removePadding ) ;
294
- }
295
- }
296
- else {
297
- this . copyableValue = content = JSON . stringify ( value ) ;
298
- }
299
- }
300
- else if ( type === 'Date' ) {
301
- if ( typeof value === 'object' && value . __type ) {
302
- value = new Date ( value . iso ) ;
303
- } else if ( typeof value === 'string' ) {
304
- value = new Date ( value ) ;
305
- }
306
- this . copyableValue = content = dateStringUTC ( value ) ;
307
- } else if ( type === 'Boolean' ) {
308
- this . copyableValue = content = value ? 'True' : 'False' ;
309
- } else if ( type === 'Object' || type === 'Bytes' ) {
310
- this . copyableValue = content = JSON . stringify ( value ) ;
311
- } else if ( type === 'File' ) {
312
- const fileName = value . url ( ) ? getFileName ( value ) : 'Uploading\u2026' ;
313
- content = < Pill value = { fileName } fileDownloadLink = { value . url ( ) } /> ;
314
- this . copyableValue = fileName ;
315
- } else if ( type === 'ACL' ) {
316
- let pieces = [ ] ;
317
- let json = value . toJSON ( ) ;
318
- if ( Object . prototype . hasOwnProperty . call ( json , '*' ) ) {
319
- if ( json [ '*' ] . read && json [ '*' ] . write ) {
320
- pieces . push ( 'Public Read + Write' ) ;
321
- } else if ( json [ '*' ] . read ) {
322
- pieces . push ( 'Public Read' ) ;
323
- } else if ( json [ '*' ] . write ) {
324
- pieces . push ( 'Public Write' ) ;
325
- }
326
- }
327
- for ( let role in json ) {
328
- if ( role !== '*' ) {
329
- pieces . push ( role ) ;
330
- }
331
- }
332
- if ( pieces . length === 0 ) {
333
- pieces . push ( 'Master Key Only' ) ;
334
- }
335
- this . copyableValue = content = pieces . join ( ', ' ) ;
336
- } else if ( type === 'GeoPoint' ) {
337
- this . copyableValue = content = `(${ value . latitude } , ${ value . longitude } )` ;
338
- } else if ( type === 'Polygon' ) {
339
- this . copyableValue = content = value . coordinates . map ( coord => `(${ coord } )` )
340
- } else if ( type === 'Relation' ) {
341
- content = setRelation ? (
342
- < div style = { { textAlign : 'center' } } >
343
- < Pill onClick = { ( ) => setRelation ( value ) } value = 'View relation' followClick = { true } />
344
- </ div >
345
- ) : (
346
- 'Relation'
347
- ) ;
348
- this . copyableValue = undefined ;
349
- }
350
386
351
- if ( current ) {
387
+ let classes = [ ...this . state . classes ] ;
388
+
389
+ if ( current ) {
352
390
classes . push ( styles . current ) ;
353
391
}
354
-
355
392
if ( markRequiredFieldRow === row && isRequired && ! value ) {
356
393
classes . push ( styles . required ) ;
357
394
}
358
395
359
396
return readonly ? (
360
- < Tooltip placement = 'bottom' tooltip = 'Read only (CTRL+C to copy)' visible = { this . state . showTooltip } >
397
+ < Tooltip placement = 'bottom' tooltip = 'Read only (CTRL+C to copy)' visible = { this . state . showTooltip } >
361
398
< span
362
399
ref = { this . cellRef }
363
400
className = { classes . join ( ' ' ) }
@@ -382,7 +419,7 @@ export default class BrowserCell extends Component {
382
419
} }
383
420
onContextMenu = { this . onContextMenu }
384
421
>
385
- { isNewRow ? '(auto)' : content }
422
+ { row < 0 || isNewRow ? '(auto)' : this . state . content }
386
423
</ span >
387
424
</ Tooltip >
388
425
) : (
@@ -413,13 +450,11 @@ export default class BrowserCell extends Component {
413
450
if ( [ 'ACL' , 'Boolean' , 'File' ] . includes ( type ) ) {
414
451
e . preventDefault ( ) ;
415
452
}
416
- onEditChange ( true ) ;
417
- }
418
- } }
419
- onContextMenu = { this . onContextMenu }
420
- >
421
- { content }
422
- </ span >
453
+ } } }
454
+ onContextMenu = { this . onContextMenu . bind ( this ) }
455
+ >
456
+ { this . state . content }
457
+ </ span >
423
458
) ;
424
459
}
425
460
}
0 commit comments