goblin-desktop 2.0.21 → 2.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/.editorconfig +9 -9
  2. package/.eslintrc.js +28 -28
  3. package/.zou-flow +3 -3
  4. package/README.md +108 -108
  5. package/builders/builders.js +3 -3
  6. package/builders/wizard.js +457 -457
  7. package/contexts.js +13 -13
  8. package/desktop-manager.js +10 -10
  9. package/desktop-window.js +13 -13
  10. package/desktop.js +13 -13
  11. package/lib/service.js +137 -137
  12. package/package.json +36 -36
  13. package/password-wizard.js +13 -13
  14. package/quest-run-wizard.js +13 -13
  15. package/taskbar.js +13 -13
  16. package/widgets/audio/sfx.js +177 -177
  17. package/widgets/board/view.js +37 -37
  18. package/widgets/board/widget.js +65 -65
  19. package/widgets/contexts/logic-handlers.js +36 -36
  20. package/widgets/contexts/service.js +40 -40
  21. package/widgets/contexts/view.js +22 -22
  22. package/widgets/contexts/widget.js +147 -147
  23. package/widgets/datagrid/datagrid-entity.js +82 -82
  24. package/widgets/datagrid/datagrid-headers.js +272 -272
  25. package/widgets/datagrid/styles.js +13 -13
  26. package/widgets/datagrid/widget.js +192 -192
  27. package/widgets/datagrid-cell/styles.js +52 -52
  28. package/widgets/datagrid-cell/widget.js +41 -41
  29. package/widgets/datagrid-item/styles.js +15 -15
  30. package/widgets/datagrid-item/widget.js +74 -74
  31. package/widgets/default/view.js +95 -91
  32. package/widgets/desktop/compensator.js +9 -9
  33. package/widgets/desktop/logic-handlers.js +237 -237
  34. package/widgets/desktop/reducer.js +35 -35
  35. package/widgets/desktop/service.js +828 -828
  36. package/widgets/desktop/styles.js +28 -28
  37. package/widgets/desktop/widget.js +175 -175
  38. package/widgets/desktop-clock/styles.js +69 -69
  39. package/widgets/desktop-clock/widget.js +387 -387
  40. package/widgets/desktop-clock-clock/styles.js +56 -56
  41. package/widgets/desktop-clock-clock/widget.js +96 -96
  42. package/widgets/desktop-clock-menu/styles.js +129 -129
  43. package/widgets/desktop-clock-menu/widget.js +63 -63
  44. package/widgets/desktop-connection-status/reducer.js +15 -15
  45. package/widgets/desktop-connection-status/styles.js +44 -44
  46. package/widgets/desktop-connection-status/widget.js +129 -129
  47. package/widgets/desktop-content/widget.js +68 -68
  48. package/widgets/desktop-footer/reducer.js +31 -31
  49. package/widgets/desktop-footer/styles.js +36 -36
  50. package/widgets/desktop-footer/widget.js +52 -52
  51. package/widgets/desktop-monitors/styles.js +155 -155
  52. package/widgets/desktop-monitors/widget.js +272 -272
  53. package/widgets/desktop-notebook/styles.js +155 -155
  54. package/widgets/desktop-notebook/widget.js +252 -252
  55. package/widgets/desktop-notifications/styles.js +147 -147
  56. package/widgets/desktop-notifications/widget.js +231 -231
  57. package/widgets/desktop-scale/reducer.js +15 -15
  58. package/widgets/desktop-scale/styles.js +48 -48
  59. package/widgets/desktop-scale/widget.js +172 -172
  60. package/widgets/desktop-state-monitor/styles.js +72 -72
  61. package/widgets/desktop-state-monitor/widget.js +123 -123
  62. package/widgets/desktop-taskbar/widget.js +57 -57
  63. package/widgets/desktop-themes-menu/widget.js +121 -121
  64. package/widgets/desktop-topbar/widget.js +201 -201
  65. package/widgets/desktop-window/service.js +56 -56
  66. package/widgets/desktop-window/styles.js +22 -22
  67. package/widgets/desktop-window/widget.js +70 -70
  68. package/widgets/detail/compensator.js +17 -17
  69. package/widgets/detail/view.js +40 -40
  70. package/widgets/detail/widget.js +125 -125
  71. package/widgets/editor/widget.js +84 -80
  72. package/widgets/entity-alerts/styles.js +77 -77
  73. package/widgets/entity-alerts/widget.js +328 -328
  74. package/widgets/entity-list/styles.js +66 -66
  75. package/widgets/entity-list/view.js +36 -36
  76. package/widgets/entity-list/widget.js +209 -209
  77. package/widgets/entity-list-item/widget.js +68 -68
  78. package/widgets/entity-row/styles.js +105 -105
  79. package/widgets/entity-row/widget.js +524 -524
  80. package/widgets/entity-row-button/styles.js +46 -46
  81. package/widgets/entity-row-button/widget.js +57 -57
  82. package/widgets/entity-view/reducer.js +20 -20
  83. package/widgets/entity-view/styles.js +90 -90
  84. package/widgets/entity-view/widget.js +516 -516
  85. package/widgets/facet-checkbox/styles.js +17 -17
  86. package/widgets/facet-checkbox/widget.js +43 -43
  87. package/widgets/facet-filter/widget.js +94 -94
  88. package/widgets/facet-filter-add/styles.js +30 -30
  89. package/widgets/facet-filter-add/widget.js +105 -105
  90. package/widgets/facet-filter-button/styles.js +74 -74
  91. package/widgets/facet-filter-button/widget.js +214 -214
  92. package/widgets/facet-filter-list-dialog/styles.js +59 -59
  93. package/widgets/facet-filter-list-dialog/widget.js +253 -253
  94. package/widgets/facet-filter-list-dialog-footer/styles.js +22 -22
  95. package/widgets/facet-filter-list-dialog-footer/widget.js +105 -105
  96. package/widgets/facet-filter-range-dialog/styles.js +82 -82
  97. package/widgets/facet-filter-range-dialog/widget.js +399 -399
  98. package/widgets/facet-filter-range-dialog-footer/styles.js +22 -22
  99. package/widgets/facet-filter-range-dialog-footer/widget.js +182 -182
  100. package/widgets/gamepad/widget.js +75 -75
  101. package/widgets/helpers/facet-helpers.js +105 -105
  102. package/widgets/hinter/reducer.js +35 -35
  103. package/widgets/hinter/styles.js +79 -79
  104. package/widgets/hinter/view.js +31 -31
  105. package/widgets/hinter/widget.js +291 -291
  106. package/widgets/junction/styles.js +22 -22
  107. package/widgets/junction/widget.js +50 -50
  108. package/widgets/main-tab-menu/styles.js +17 -17
  109. package/widgets/main-tab-menu/widget.js +136 -136
  110. package/widgets/map/view.js +49 -49
  111. package/widgets/map/widget.js +65 -65
  112. package/widgets/monitor/reducer.js +15 -15
  113. package/widgets/monitor/widget.js +66 -66
  114. package/widgets/navigating-layer/widget.js +25 -25
  115. package/widgets/notifications-button/widget.js +44 -44
  116. package/widgets/password-wizard/service.js +53 -53
  117. package/widgets/password-wizard/ui.js +66 -66
  118. package/widgets/plugin/reducer.js +19 -19
  119. package/widgets/plugin/styles.js +294 -294
  120. package/widgets/plugin/widget.js +637 -636
  121. package/widgets/quest-run-wizard/service.js +49 -49
  122. package/widgets/quest-run-wizard/ui.js +25 -25
  123. package/widgets/search/styles.js +80 -80
  124. package/widgets/search/widget.js +285 -285
  125. package/widgets/simple/view.js +29 -29
  126. package/widgets/status-filters/widget.js +121 -121
  127. package/widgets/tab/styles.js +16 -16
  128. package/widgets/tab/widget.js +89 -89
  129. package/widgets/tab-content/widget.js +35 -35
  130. package/widgets/tabs/widget.js +48 -48
  131. package/widgets/taskbar/service.js +99 -99
  132. package/widgets/taskbar/view.js +24 -24
  133. package/widgets/taskbar/widget.js +167 -167
  134. package/widgets/widget-doc-caller/reducer.js +15 -15
  135. package/widgets/widget-doc-caller/styles.js +20 -20
  136. package/widgets/widget-doc-caller/widget.js +55 -55
  137. package/widgets/wizard/widget.js +299 -299
  138. package/widgets/wizard-buttons/widget.js +111 -107
  139. package/widgets/workitem/styles.js +281 -281
  140. package/widgets/workitem/view.js +62 -62
  141. package/widgets/workitem/widget.js +971 -971
  142. package/widgets/workitem-dialog/widget.js +86 -86
  143. package/widgets/workitem-fields/widget.js +63 -63
@@ -1,524 +1,524 @@
1
- //T:2019-02-27
2
- import React from 'react';
3
- import Widget from 'goblin-laboratory/widgets/widget';
4
- import TableCell from 'goblin-gadgets/widgets/table-cell/widget';
5
- import Gauge from 'goblin-gadgets/widgets/gauge/widget';
6
- import Label from 'goblin-gadgets/widgets/label/widget';
7
- import Spinner from 'goblin-gadgets/widgets/spinner/widget';
8
- import ColoredContainer from 'goblin-gadgets/widgets/colored-container/widget';
9
- import EntityRowButton from 'goblin-desktop/widgets/entity-row-button/widget';
10
- import T from 't';
11
- import ListHelpers from 'goblin-workshop/lib/list-helpers.js';
12
- import RetroGear from 'goblin-gadgets/widgets/retro-gear/widget';
13
- import {ColorManipulator} from 'goblin-theme';
14
- import Shredder from 'xcraft-core-shredder';
15
- import {Unit} from 'goblin-theme';
16
-
17
- /******************************************************************************/
18
-
19
- class _Driller extends Widget {
20
- constructor() {
21
- super(...arguments);
22
- this.renewTTL = this.renewTTL.bind(this);
23
- this._loadRequested = false;
24
- this._renewInterval = null;
25
- }
26
-
27
- renewTTL(id) {
28
- if (this._renewInterval) {
29
- clearInterval(this._renewInterval);
30
- }
31
- this._renewInterval = setInterval(this.props.onDrillDown, 15000, id);
32
- }
33
-
34
- componentWillUnmount() {
35
- super.componentWillUnmount();
36
- clearInterval(this._renewInterval);
37
- }
38
-
39
- /******************************************************************************/
40
-
41
- renderSpinner() {
42
- if (this.context.theme.look.name === 'retro') {
43
- return (
44
- <div className={this.styles.classNames.busyBox}>
45
- <RetroGear
46
- color={ColorManipulator.darken(
47
- this.context.theme.palette.light,
48
- 0.2
49
- )}
50
- left="0px"
51
- top="0px"
52
- radius="20px"
53
- toothCount={12}
54
- toothThickness={6}
55
- rotationDuration="3s"
56
- rotationDirection="cw"
57
- shadow="no"
58
- />
59
- </div>
60
- );
61
- } else {
62
- <Spinner size="24px" />;
63
- }
64
- }
65
-
66
- render() {
67
- if (this._loadRequested === false && this.props.entityId) {
68
- setTimeout(this.props.onDrillDown, 0, this.props.entityId);
69
- this.renewTTL(this.props.entityId);
70
- this._loadRequested = true;
71
- }
72
-
73
- if (this.props.loaded) {
74
- return (
75
- <TableCell
76
- rowId={this.props.rowId}
77
- isLast={false}
78
- isHeader={false}
79
- text={this.props.text}
80
- {...ListHelpers.getColumnProps(
81
- this.props.column,
82
- this.props.settings
83
- )}
84
- />
85
- );
86
- } else {
87
- return (
88
- <TableCell
89
- rowId={this.props.rowId}
90
- isLast={false}
91
- isHeader={false}
92
- {...ListHelpers.getColumnProps(
93
- this.props.column,
94
- this.props.settings
95
- )}
96
- >
97
- {this.renderSpinner()}
98
- </TableCell>
99
- );
100
- }
101
- }
102
- }
103
-
104
- /******************************************************************************/
105
-
106
- const Driller = Widget.connect((state, props) => {
107
- const loaded = !!state.get(`backend.${props.entityId}.id`, null);
108
- const path = props.path || 'meta.summaries.info';
109
- return {
110
- column: props.column,
111
- entityId: props.entityId,
112
- loaded: loaded,
113
- text: loaded ? state.get(`backend.${props.entityId}.${path}`) : '',
114
- };
115
- })(_Driller);
116
-
117
- /******************************************************************************/
118
-
119
- const Score = Widget.connect((state, props) => {
120
- const highlights = state.get(`backend.${props.listId}.highlights`);
121
- let score;
122
- if (highlights.get(props.entityId, null) !== null) {
123
- score = highlights.get(`${props.entityId}.score`);
124
- }
125
- return {value: score * 100};
126
- })(Gauge);
127
-
128
- /******************************************************************************/
129
-
130
- const Colored = Widget.connect((state, props) => {
131
- const highlights = state.get(`backend.${props.listId}.highlights`);
132
- let score;
133
- if (highlights.get(props.entityId, null) !== null) {
134
- score = highlights.get(`${props.entityId}.score`);
135
- }
136
- return {value: score * 100};
137
- })(ColoredContainer);
138
-
139
- /******************************************************************************/
140
-
141
- const TableCellWithHighlight = Widget.connect((state, props) => {
142
- const highlights = state.get(`backend.${props.listId}.highlights`);
143
- let text = props.text;
144
- if (highlights.get(props.entityId, null) !== null) {
145
- const auto = highlights.get(`${props.entityId}.auto`);
146
- const phonetic = highlights.get(`${props.entityId}.phonetic`);
147
- const info = highlights.get(`${props.entityId}.info`);
148
- if (auto && !phonetic) {
149
- text = auto;
150
- } else if (!auto && phonetic) {
151
- text = phonetic;
152
- } else if (auto && phonetic) {
153
- text = auto;
154
- } else if (info) {
155
- text = highlights.get(`${props.entityId}.info`);
156
- }
157
- }
158
- return {text};
159
- })(TableCell);
160
-
161
- /******************************************************************************/
162
-
163
- class EntityRow extends Widget {
164
- constructor() {
165
- super(...arguments);
166
- this.renewTTL = this.renewTTL.bind(this);
167
- this.onEditInStash = this.onEditInStash.bind(this);
168
- this.onEditAndOpen = this.onEditAndOpen.bind(this);
169
- this._idRequested = null;
170
- this._renewInterval = null;
171
- }
172
-
173
- renewTTL(id) {
174
- if (this._renewInterval) {
175
- clearInterval(this._renewInterval);
176
- }
177
- this._renewInterval = setInterval(this.props.onDrillDown, 15000, id);
178
- }
179
-
180
- onEditInStash() {
181
- this.props.onEdit(this.props.rowIndex, false);
182
- }
183
-
184
- onEditAndOpen() {
185
- this.props.onEdit(this.props.rowIndex, true);
186
- }
187
-
188
- componentWillUnmount() {
189
- super.componentWillUnmount();
190
- clearInterval(this._renewInterval);
191
- }
192
-
193
- isFilterPath(path) {
194
- if (this.props.hasFilter && this.props.filterPaths) {
195
- return this.props.filterPaths.includes(path);
196
- }
197
- return false;
198
- }
199
-
200
- /******************************************************************************/
201
-
202
- renderButtons() {
203
- return (
204
- <div className={`buttons-hover ${this.styles.classNames.buttons}`}>
205
- <EntityRowButton
206
- place="left"
207
- glyph="solid/external-link"
208
- tooltip={T('Editer plus tard')}
209
- onClick={this.onEditInStash}
210
- />
211
- <EntityRowButton
212
- place="right"
213
- glyph="solid/pencil"
214
- tooltip={T('Editer immédiatement')}
215
- onClick={this.onEditAndOpen}
216
- />
217
- </div>
218
- );
219
- }
220
-
221
- renderCellTextBar(cell, text, isFilter, index) {
222
- const props = ListHelpers.getColumnProps(cell, this.props.settings);
223
- const {type, width, ...otherProps} = props;
224
-
225
- if (isFilter) {
226
- const w = Unit.sub(width, '15px');
227
- return (
228
- <div key={index} className={this.styles.classNames.filteredCellBarre}>
229
- <Colored
230
- entityId={this.props.id}
231
- listId={this.props.listId}
232
- gradient="red-yellow-green"
233
- width="5px"
234
- alpha={0.9}
235
- />
236
- <Label width="10px" />
237
- <TableCellWithHighlight
238
- entityId={this.props.id}
239
- listId={this.props.listId}
240
- rowId={this.props.rowIndex}
241
- index={index}
242
- isLast={false}
243
- isHeader={false}
244
- width={w}
245
- {...otherProps}
246
- maxHeight={this.props.maxHeight}
247
- cellFormat="original"
248
- text={text}
249
- />
250
- </div>
251
- );
252
- } else {
253
- return (
254
- <TableCell
255
- rowId={this.props.rowIndex}
256
- key={index}
257
- index={index}
258
- isLast={false}
259
- isHeader={false}
260
- width={width}
261
- {...otherProps}
262
- maxHeight={this.props.maxHeight}
263
- cellFormat="original"
264
- text={text}
265
- />
266
- );
267
- }
268
- }
269
-
270
- renderCellTextCarnaval(cell, text, isFilter, index) {
271
- const props = ListHelpers.getColumnProps(cell, this.props.settings);
272
- const {type, width, ...otherProps} = props;
273
-
274
- if (isFilter) {
275
- const w = Unit.sub(width, '15px');
276
- return (
277
- <Colored
278
- key={index}
279
- entityId={this.props.id}
280
- listId={this.props.listId}
281
- gradient="red-yellow-green"
282
- margin="-2px 5px -2px 0px"
283
- padding="0px 0px 0px 10px"
284
- radius="5px"
285
- alpha={this.context.theme.palette.isDarkTheme ? 0.3 : 0.8}
286
- >
287
- <TableCellWithHighlight
288
- entityId={this.props.id}
289
- listId={this.props.listId}
290
- rowId={this.props.rowIndex}
291
- index={index}
292
- isLast={false}
293
- isHeader={false}
294
- width={w}
295
- {...otherProps}
296
- maxHeight={this.props.maxHeight}
297
- cellFormat="original"
298
- text={text}
299
- />
300
- </Colored>
301
- );
302
- } else {
303
- return (
304
- <TableCell
305
- rowId={this.props.rowIndex}
306
- key={index}
307
- index={index}
308
- isLast={false}
309
- isHeader={false}
310
- width={width}
311
- {...otherProps}
312
- maxHeight={this.props.maxHeight}
313
- cellFormat="original"
314
- text={text}
315
- />
316
- );
317
- }
318
- }
319
-
320
- renderCellTextGauge(cell, text, isFilter, index) {
321
- const props = ListHelpers.getColumnProps(cell, this.props.settings);
322
- const {type, width, ...otherProps} = props;
323
-
324
- if (isFilter) {
325
- const w = Unit.sub(width, '12px');
326
- return (
327
- <div key={index} className={this.styles.classNames.filteredCellGauge}>
328
- <Score
329
- entityId={this.props.id}
330
- listId={this.props.listId}
331
- kind="simple"
332
- gradient="red-yellow-green"
333
- direction="vertical"
334
- width="6px"
335
- height="unset"
336
- />
337
- <Label width="6px" />
338
- <TableCellWithHighlight
339
- entityId={this.props.id}
340
- listId={this.props.listId}
341
- rowId={this.props.rowIndex}
342
- index={index}
343
- isLast={false}
344
- isHeader={false}
345
- width={w}
346
- {...otherProps}
347
- maxHeight={this.props.maxHeight}
348
- cellFormat="original"
349
- text={text}
350
- />
351
- </div>
352
- );
353
- } else {
354
- return (
355
- <TableCell
356
- rowId={this.props.rowIndex}
357
- key={index}
358
- index={index}
359
- isLast={false}
360
- isHeader={false}
361
- width={width}
362
- {...otherProps}
363
- maxHeight={this.props.maxHeight}
364
- cellFormat="original"
365
- text={text}
366
- />
367
- );
368
- }
369
- }
370
-
371
- renderCellText(cell, text, isFilter, index) {
372
- switch (this.props.variant) {
373
- default:
374
- case 'gauge':
375
- return this.renderCellTextGauge(cell, text, isFilter, index);
376
- case 'bar':
377
- return this.renderCellTextBar(cell, text, isFilter, index);
378
- case 'carnaval':
379
- return this.renderCellTextCarnaval(cell, text, isFilter, index);
380
- }
381
- }
382
-
383
- renderCell(cell, index) {
384
- if (!cell) {
385
- return null;
386
- }
387
- const targetPath = ListHelpers.getColumnTargetPath(cell);
388
- const columnSubPath = ListHelpers.getColumnSubPath(cell);
389
- let text = ListHelpers.getColumnDisplayText(cell, this.props.entity);
390
-
391
- const {schema} = this.props;
392
- if (schema) {
393
- const propSchema = schema.get(targetPath, null);
394
- if (propSchema) {
395
- const {type} = propSchema.pick('type');
396
- if (type === 'enum') {
397
- const valuesInfo = propSchema.get('valuesInfo');
398
- if (valuesInfo) {
399
- text = valuesInfo.get(`${text}.text`, text);
400
- }
401
- }
402
- }
403
- }
404
-
405
- if (
406
- ListHelpers.isTargetingValueOrRef(this.props.entity, targetPath) &&
407
- text !== null
408
- ) {
409
- return (
410
- <Driller
411
- entityId={text}
412
- schema={this.props.schema}
413
- rowId={this.props.rowIndex}
414
- key={index}
415
- column={cell}
416
- onDrillDown={this.props.onDrillDown}
417
- onSelect={this.props.onSelect}
418
- onEdit={this.props.onEdit}
419
- path={columnSubPath}
420
- />
421
- );
422
- } else {
423
- const isFilter = this.isFilterPath(targetPath);
424
- return this.renderCellText(cell, text, isFilter, index);
425
- }
426
- }
427
-
428
- renderSpinner() {
429
- if (this.context.theme.look.name === 'retro') {
430
- return (
431
- <div className={this.styles.classNames.spinner}>
432
- <div className={this.styles.classNames.busyBox}>
433
- <RetroGear
434
- color={ColorManipulator.darken(
435
- this.context.theme.palette.light,
436
- 0.2
437
- )}
438
- left="0px"
439
- top="0px"
440
- radius="20px"
441
- toothCount={12}
442
- toothThickness={6}
443
- rotationDuration="3s"
444
- rotationDirection="cw"
445
- shadow="no"
446
- />
447
- </div>
448
- </div>
449
- );
450
- } else {
451
- return (
452
- <div className={this.styles.classNames.spinner}>
453
- <Spinner size="24px" />
454
- </div>
455
- );
456
- }
457
- }
458
-
459
- render() {
460
- const {id, rowIndex, entity, columns, onDrillDown} = this.props;
461
- const loaded = id && entity;
462
-
463
- if (onDrillDown && id && this._idRequested !== id) {
464
- setTimeout(onDrillDown, 0, id);
465
- this.renewTTL(id);
466
- this._idRequested = id;
467
- }
468
-
469
- if (!loaded) {
470
- return (
471
- <div className={this.styles.classNames.busyEntityRow}>
472
- <TableCell isLast={false} isHeader={false}>
473
- {this.renderSpinner()}
474
- </TableCell>
475
- </div>
476
- );
477
- }
478
-
479
- const n = new Shredder({
480
- text: rowIndex + 1,
481
- weight: 'bold',
482
- });
483
-
484
- const divProps = {};
485
- if (this.props.onSelect) {
486
- divProps.onClick = () => this.props.onSelect(rowIndex);
487
- }
488
-
489
- return (
490
- <div className={this.styles.classNames.entityRow} {...divProps}>
491
- <TableCell
492
- rowId={rowIndex}
493
- index={rowIndex}
494
- isLast={false}
495
- isHeader={false}
496
- width={this.props.firstColumnWidth || '50px'}
497
- wrap="no-end"
498
- text={n}
499
- />
500
- {columns.map((c, i) => this.renderCell(c, i))}
501
- {this.renderButtons()}
502
- </div>
503
- );
504
- }
505
- }
506
-
507
- /******************************************************************************/
508
-
509
- export default Widget.connect((state, props) => {
510
- const entityId = props.useView ? `entity-view@${props.id}` : props.id;
511
- const entity = state.get(`backend.${entityId}`);
512
- if (!entity) {
513
- // TODO: !!!
514
- //? console.warn(`>>> Entity ${entityId} not found <<<`);
515
- } else if (!entity.get('meta')) {
516
- // TODO: Why some entities don't have meta ???
517
- //? console.warn(`>>> Entity ${entityId} has no meta <<<`);
518
- }
519
-
520
- return {
521
- id: props.id,
522
- entity,
523
- };
524
- })(EntityRow);
1
+ //T:2019-02-27
2
+ import React from 'react';
3
+ import Widget from 'goblin-laboratory/widgets/widget';
4
+ import TableCell from 'goblin-gadgets/widgets/table-cell/widget';
5
+ import Gauge from 'goblin-gadgets/widgets/gauge/widget';
6
+ import Label from 'goblin-gadgets/widgets/label/widget';
7
+ import Spinner from 'goblin-gadgets/widgets/spinner/widget';
8
+ import ColoredContainer from 'goblin-gadgets/widgets/colored-container/widget';
9
+ import EntityRowButton from 'goblin-desktop/widgets/entity-row-button/widget';
10
+ import T from 't';
11
+ import ListHelpers from 'goblin-workshop/lib/list-helpers.js';
12
+ import RetroGear from 'goblin-gadgets/widgets/retro-gear/widget';
13
+ import {ColorManipulator} from 'goblin-theme';
14
+ import Shredder from 'xcraft-core-shredder';
15
+ import {Unit} from 'goblin-theme';
16
+
17
+ /******************************************************************************/
18
+
19
+ class _Driller extends Widget {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.renewTTL = this.renewTTL.bind(this);
23
+ this._loadRequested = false;
24
+ this._renewInterval = null;
25
+ }
26
+
27
+ renewTTL(id) {
28
+ if (this._renewInterval) {
29
+ clearInterval(this._renewInterval);
30
+ }
31
+ this._renewInterval = setInterval(this.props.onDrillDown, 15000, id);
32
+ }
33
+
34
+ componentWillUnmount() {
35
+ super.componentWillUnmount();
36
+ clearInterval(this._renewInterval);
37
+ }
38
+
39
+ /******************************************************************************/
40
+
41
+ renderSpinner() {
42
+ if (this.context.theme.look.name === 'retro') {
43
+ return (
44
+ <div className={this.styles.classNames.busyBox}>
45
+ <RetroGear
46
+ color={ColorManipulator.darken(
47
+ this.context.theme.palette.light,
48
+ 0.2
49
+ )}
50
+ left="0px"
51
+ top="0px"
52
+ radius="20px"
53
+ toothCount={12}
54
+ toothThickness={6}
55
+ rotationDuration="3s"
56
+ rotationDirection="cw"
57
+ shadow="no"
58
+ />
59
+ </div>
60
+ );
61
+ } else {
62
+ <Spinner size="24px" />;
63
+ }
64
+ }
65
+
66
+ render() {
67
+ if (this._loadRequested === false && this.props.entityId) {
68
+ setTimeout(this.props.onDrillDown, 0, this.props.entityId);
69
+ this.renewTTL(this.props.entityId);
70
+ this._loadRequested = true;
71
+ }
72
+
73
+ if (this.props.loaded) {
74
+ return (
75
+ <TableCell
76
+ rowId={this.props.rowId}
77
+ isLast={false}
78
+ isHeader={false}
79
+ text={this.props.text}
80
+ {...ListHelpers.getColumnProps(
81
+ this.props.column,
82
+ this.props.settings
83
+ )}
84
+ />
85
+ );
86
+ } else {
87
+ return (
88
+ <TableCell
89
+ rowId={this.props.rowId}
90
+ isLast={false}
91
+ isHeader={false}
92
+ {...ListHelpers.getColumnProps(
93
+ this.props.column,
94
+ this.props.settings
95
+ )}
96
+ >
97
+ {this.renderSpinner()}
98
+ </TableCell>
99
+ );
100
+ }
101
+ }
102
+ }
103
+
104
+ /******************************************************************************/
105
+
106
+ const Driller = Widget.connect((state, props) => {
107
+ const loaded = !!state.get(`backend.${props.entityId}.id`, null);
108
+ const path = props.path || 'meta.summaries.info';
109
+ return {
110
+ column: props.column,
111
+ entityId: props.entityId,
112
+ loaded: loaded,
113
+ text: loaded ? state.get(`backend.${props.entityId}.${path}`) : '',
114
+ };
115
+ })(_Driller);
116
+
117
+ /******************************************************************************/
118
+
119
+ const Score = Widget.connect((state, props) => {
120
+ const highlights = state.get(`backend.${props.listId}.highlights`);
121
+ let score;
122
+ if (highlights.get(props.entityId, null) !== null) {
123
+ score = highlights.get(`${props.entityId}.score`);
124
+ }
125
+ return {value: score * 100};
126
+ })(Gauge);
127
+
128
+ /******************************************************************************/
129
+
130
+ const Colored = Widget.connect((state, props) => {
131
+ const highlights = state.get(`backend.${props.listId}.highlights`);
132
+ let score;
133
+ if (highlights.get(props.entityId, null) !== null) {
134
+ score = highlights.get(`${props.entityId}.score`);
135
+ }
136
+ return {value: score * 100};
137
+ })(ColoredContainer);
138
+
139
+ /******************************************************************************/
140
+
141
+ const TableCellWithHighlight = Widget.connect((state, props) => {
142
+ const highlights = state.get(`backend.${props.listId}.highlights`);
143
+ let text = props.text;
144
+ if (highlights.get(props.entityId, null) !== null) {
145
+ const auto = highlights.get(`${props.entityId}.auto`);
146
+ const phonetic = highlights.get(`${props.entityId}.phonetic`);
147
+ const info = highlights.get(`${props.entityId}.info`);
148
+ if (auto && !phonetic) {
149
+ text = auto;
150
+ } else if (!auto && phonetic) {
151
+ text = phonetic;
152
+ } else if (auto && phonetic) {
153
+ text = auto;
154
+ } else if (info) {
155
+ text = highlights.get(`${props.entityId}.info`);
156
+ }
157
+ }
158
+ return {text};
159
+ })(TableCell);
160
+
161
+ /******************************************************************************/
162
+
163
+ class EntityRow extends Widget {
164
+ constructor() {
165
+ super(...arguments);
166
+ this.renewTTL = this.renewTTL.bind(this);
167
+ this.onEditInStash = this.onEditInStash.bind(this);
168
+ this.onEditAndOpen = this.onEditAndOpen.bind(this);
169
+ this._idRequested = null;
170
+ this._renewInterval = null;
171
+ }
172
+
173
+ renewTTL(id) {
174
+ if (this._renewInterval) {
175
+ clearInterval(this._renewInterval);
176
+ }
177
+ this._renewInterval = setInterval(this.props.onDrillDown, 15000, id);
178
+ }
179
+
180
+ onEditInStash() {
181
+ this.props.onEdit(this.props.rowIndex, false);
182
+ }
183
+
184
+ onEditAndOpen() {
185
+ this.props.onEdit(this.props.rowIndex, true);
186
+ }
187
+
188
+ componentWillUnmount() {
189
+ super.componentWillUnmount();
190
+ clearInterval(this._renewInterval);
191
+ }
192
+
193
+ isFilterPath(path) {
194
+ if (this.props.hasFilter && this.props.filterPaths) {
195
+ return this.props.filterPaths.includes(path);
196
+ }
197
+ return false;
198
+ }
199
+
200
+ /******************************************************************************/
201
+
202
+ renderButtons() {
203
+ return (
204
+ <div className={`buttons-hover ${this.styles.classNames.buttons}`}>
205
+ <EntityRowButton
206
+ place="left"
207
+ glyph="solid/external-link"
208
+ tooltip={T('Editer plus tard')}
209
+ onClick={this.onEditInStash}
210
+ />
211
+ <EntityRowButton
212
+ place="right"
213
+ glyph="solid/pencil"
214
+ tooltip={T('Editer immédiatement')}
215
+ onClick={this.onEditAndOpen}
216
+ />
217
+ </div>
218
+ );
219
+ }
220
+
221
+ renderCellTextBar(cell, text, isFilter, index) {
222
+ const props = ListHelpers.getColumnProps(cell, this.props.settings);
223
+ const {type, width, ...otherProps} = props;
224
+
225
+ if (isFilter) {
226
+ const w = Unit.sub(width, '15px');
227
+ return (
228
+ <div key={index} className={this.styles.classNames.filteredCellBarre}>
229
+ <Colored
230
+ entityId={this.props.id}
231
+ listId={this.props.listId}
232
+ gradient="red-yellow-green"
233
+ width="5px"
234
+ alpha={0.9}
235
+ />
236
+ <Label width="10px" />
237
+ <TableCellWithHighlight
238
+ entityId={this.props.id}
239
+ listId={this.props.listId}
240
+ rowId={this.props.rowIndex}
241
+ index={index}
242
+ isLast={false}
243
+ isHeader={false}
244
+ width={w}
245
+ {...otherProps}
246
+ maxHeight={this.props.maxHeight}
247
+ cellFormat="original"
248
+ text={text}
249
+ />
250
+ </div>
251
+ );
252
+ } else {
253
+ return (
254
+ <TableCell
255
+ rowId={this.props.rowIndex}
256
+ key={index}
257
+ index={index}
258
+ isLast={false}
259
+ isHeader={false}
260
+ width={width}
261
+ {...otherProps}
262
+ maxHeight={this.props.maxHeight}
263
+ cellFormat="original"
264
+ text={text}
265
+ />
266
+ );
267
+ }
268
+ }
269
+
270
+ renderCellTextCarnaval(cell, text, isFilter, index) {
271
+ const props = ListHelpers.getColumnProps(cell, this.props.settings);
272
+ const {type, width, ...otherProps} = props;
273
+
274
+ if (isFilter) {
275
+ const w = Unit.sub(width, '15px');
276
+ return (
277
+ <Colored
278
+ key={index}
279
+ entityId={this.props.id}
280
+ listId={this.props.listId}
281
+ gradient="red-yellow-green"
282
+ margin="-2px 5px -2px 0px"
283
+ padding="0px 0px 0px 10px"
284
+ radius="5px"
285
+ alpha={this.context.theme.palette.isDarkTheme ? 0.3 : 0.8}
286
+ >
287
+ <TableCellWithHighlight
288
+ entityId={this.props.id}
289
+ listId={this.props.listId}
290
+ rowId={this.props.rowIndex}
291
+ index={index}
292
+ isLast={false}
293
+ isHeader={false}
294
+ width={w}
295
+ {...otherProps}
296
+ maxHeight={this.props.maxHeight}
297
+ cellFormat="original"
298
+ text={text}
299
+ />
300
+ </Colored>
301
+ );
302
+ } else {
303
+ return (
304
+ <TableCell
305
+ rowId={this.props.rowIndex}
306
+ key={index}
307
+ index={index}
308
+ isLast={false}
309
+ isHeader={false}
310
+ width={width}
311
+ {...otherProps}
312
+ maxHeight={this.props.maxHeight}
313
+ cellFormat="original"
314
+ text={text}
315
+ />
316
+ );
317
+ }
318
+ }
319
+
320
+ renderCellTextGauge(cell, text, isFilter, index) {
321
+ const props = ListHelpers.getColumnProps(cell, this.props.settings);
322
+ const {type, width, ...otherProps} = props;
323
+
324
+ if (isFilter) {
325
+ const w = Unit.sub(width, '12px');
326
+ return (
327
+ <div key={index} className={this.styles.classNames.filteredCellGauge}>
328
+ <Score
329
+ entityId={this.props.id}
330
+ listId={this.props.listId}
331
+ kind="simple"
332
+ gradient="red-yellow-green"
333
+ direction="vertical"
334
+ width="6px"
335
+ height="unset"
336
+ />
337
+ <Label width="6px" />
338
+ <TableCellWithHighlight
339
+ entityId={this.props.id}
340
+ listId={this.props.listId}
341
+ rowId={this.props.rowIndex}
342
+ index={index}
343
+ isLast={false}
344
+ isHeader={false}
345
+ width={w}
346
+ {...otherProps}
347
+ maxHeight={this.props.maxHeight}
348
+ cellFormat="original"
349
+ text={text}
350
+ />
351
+ </div>
352
+ );
353
+ } else {
354
+ return (
355
+ <TableCell
356
+ rowId={this.props.rowIndex}
357
+ key={index}
358
+ index={index}
359
+ isLast={false}
360
+ isHeader={false}
361
+ width={width}
362
+ {...otherProps}
363
+ maxHeight={this.props.maxHeight}
364
+ cellFormat="original"
365
+ text={text}
366
+ />
367
+ );
368
+ }
369
+ }
370
+
371
+ renderCellText(cell, text, isFilter, index) {
372
+ switch (this.props.variant) {
373
+ default:
374
+ case 'gauge':
375
+ return this.renderCellTextGauge(cell, text, isFilter, index);
376
+ case 'bar':
377
+ return this.renderCellTextBar(cell, text, isFilter, index);
378
+ case 'carnaval':
379
+ return this.renderCellTextCarnaval(cell, text, isFilter, index);
380
+ }
381
+ }
382
+
383
+ renderCell(cell, index) {
384
+ if (!cell) {
385
+ return null;
386
+ }
387
+ const targetPath = ListHelpers.getColumnTargetPath(cell);
388
+ const columnSubPath = ListHelpers.getColumnSubPath(cell);
389
+ let text = ListHelpers.getColumnDisplayText(cell, this.props.entity);
390
+
391
+ const {schema} = this.props;
392
+ if (schema) {
393
+ const propSchema = schema.get(targetPath, null);
394
+ if (propSchema) {
395
+ const {type} = propSchema.pick('type');
396
+ if (type === 'enum') {
397
+ const valuesInfo = propSchema.get('valuesInfo');
398
+ if (valuesInfo) {
399
+ text = valuesInfo.get(`${text}.text`, text);
400
+ }
401
+ }
402
+ }
403
+ }
404
+
405
+ if (
406
+ ListHelpers.isTargetingValueOrRef(this.props.entity, targetPath) &&
407
+ text !== null
408
+ ) {
409
+ return (
410
+ <Driller
411
+ entityId={text}
412
+ schema={this.props.schema}
413
+ rowId={this.props.rowIndex}
414
+ key={index}
415
+ column={cell}
416
+ onDrillDown={this.props.onDrillDown}
417
+ onSelect={this.props.onSelect}
418
+ onEdit={this.props.onEdit}
419
+ path={columnSubPath}
420
+ />
421
+ );
422
+ } else {
423
+ const isFilter = this.isFilterPath(targetPath);
424
+ return this.renderCellText(cell, text, isFilter, index);
425
+ }
426
+ }
427
+
428
+ renderSpinner() {
429
+ if (this.context.theme.look.name === 'retro') {
430
+ return (
431
+ <div className={this.styles.classNames.spinner}>
432
+ <div className={this.styles.classNames.busyBox}>
433
+ <RetroGear
434
+ color={ColorManipulator.darken(
435
+ this.context.theme.palette.light,
436
+ 0.2
437
+ )}
438
+ left="0px"
439
+ top="0px"
440
+ radius="20px"
441
+ toothCount={12}
442
+ toothThickness={6}
443
+ rotationDuration="3s"
444
+ rotationDirection="cw"
445
+ shadow="no"
446
+ />
447
+ </div>
448
+ </div>
449
+ );
450
+ } else {
451
+ return (
452
+ <div className={this.styles.classNames.spinner}>
453
+ <Spinner size="24px" />
454
+ </div>
455
+ );
456
+ }
457
+ }
458
+
459
+ render() {
460
+ const {id, rowIndex, entity, columns, onDrillDown} = this.props;
461
+ const loaded = id && entity;
462
+
463
+ if (onDrillDown && id && this._idRequested !== id) {
464
+ setTimeout(onDrillDown, 0, id);
465
+ this.renewTTL(id);
466
+ this._idRequested = id;
467
+ }
468
+
469
+ if (!loaded) {
470
+ return (
471
+ <div className={this.styles.classNames.busyEntityRow}>
472
+ <TableCell isLast={false} isHeader={false}>
473
+ {this.renderSpinner()}
474
+ </TableCell>
475
+ </div>
476
+ );
477
+ }
478
+
479
+ const n = new Shredder({
480
+ text: rowIndex + 1,
481
+ weight: 'bold',
482
+ });
483
+
484
+ const divProps = {};
485
+ if (this.props.onSelect) {
486
+ divProps.onClick = () => this.props.onSelect(rowIndex);
487
+ }
488
+
489
+ return (
490
+ <div className={this.styles.classNames.entityRow} {...divProps}>
491
+ <TableCell
492
+ rowId={rowIndex}
493
+ index={rowIndex}
494
+ isLast={false}
495
+ isHeader={false}
496
+ width={this.props.firstColumnWidth || '50px'}
497
+ wrap="no-end"
498
+ text={n}
499
+ />
500
+ {columns.map((c, i) => this.renderCell(c, i))}
501
+ {this.renderButtons()}
502
+ </div>
503
+ );
504
+ }
505
+ }
506
+
507
+ /******************************************************************************/
508
+
509
+ export default Widget.connect((state, props) => {
510
+ const entityId = props.useView ? `entity-view@${props.id}` : props.id;
511
+ const entity = state.get(`backend.${entityId}`);
512
+ if (!entity) {
513
+ // TODO: !!!
514
+ //? console.warn(`>>> Entity ${entityId} not found <<<`);
515
+ } else if (!entity.get('meta')) {
516
+ // TODO: Why some entities don't have meta ???
517
+ //? console.warn(`>>> Entity ${entityId} has no meta <<<`);
518
+ }
519
+
520
+ return {
521
+ id: props.id,
522
+ entity,
523
+ };
524
+ })(EntityRow);