@onehat/ui 0.4.101 → 0.4.103
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.
- package/package.json +1 -1
- package/src/Components/Accordion/Accordion.js +65 -6
- package/src/Components/Container/Container.js +10 -4
- package/src/Components/Form/Field/Combo/Combo.js +10 -4
- package/src/Components/Form/Field/Tag/Tag.js +6 -0
- package/src/Components/Form/Form.js +8 -3
- package/src/Components/Grid/Grid.js +232 -154
- package/src/Components/Grid/GridRow.js +7 -3
- package/src/Components/Hoc/withPresetButtons.js +18 -6
- package/src/Components/Icons/ArrowsLeftRight.js +10 -0
- package/src/Components/Icons/Bar.js +10 -0
- package/src/Components/Icons/Box.js +11 -0
- package/src/Components/Icons/BoxOpen.js +11 -0
- package/src/Components/Icons/Bucket.js +10 -0
- package/src/Components/Icons/Bump.js +21 -0
- package/src/Components/Icons/Calculator.js +12 -0
- package/src/Components/Icons/Dots.js +20 -0
- package/src/Components/Icons/Fleets.js +26 -0
- package/src/Components/Icons/Lock.js +11 -0
- package/src/Components/Icons/Microchip.js +12 -0
- package/src/Components/Icons/Num1.js +10 -0
- package/src/Components/Icons/Num2.js +10 -0
- package/src/Components/Icons/Num3.js +10 -0
- package/src/Components/Icons/Num4.js +10 -0
- package/src/Components/Icons/OilCan.js +11 -0
- package/src/Components/Icons/Operations.js +10 -0
- package/src/Components/Icons/OverduePms.js +10 -0
- package/src/Components/Icons/SackDollar.js +11 -0
- package/src/Components/Icons/ShortBar.js +15 -0
- package/src/Components/Icons/Tower.js +10 -0
- package/src/Components/Icons/UpcomingPms.js +10 -0
- package/src/Components/Layout/ScreenHeader.js +35 -3
- package/src/Components/Layout/SetupButton.js +31 -0
- package/src/Components/Layout/UserIndicator.js +35 -0
- package/src/Components/Pms/Editor/BumpPmsEditor.js +9 -0
- package/src/Components/Pms/Editor/MetersEditor.js +173 -0
- package/src/Components/Pms/Editor/PmEventsEditor.js +291 -0
- package/src/Components/Pms/Grid/UpcomingPmsGrid.js +569 -0
- package/src/Components/Pms/Layout/TreeSpecific/MakeTreeSelection.js +11 -0
- package/src/Components/Pms/Layout/TreeSpecific/TreeSpecific.js +30 -0
- package/src/Components/Pms/Modals/BulkAssignTechnician.js +104 -0
- package/src/Components/Pms/Screens/PmsManager.js +136 -0
- package/src/Components/Pms/Window/BumpPmsEditorWindow.js +25 -0
- package/src/Components/Screens/Manager.js +3 -0
- package/src/Components/Screens/ReportsManager.js +51 -26
- package/src/Components/Tree/Tree.js +15 -6
- package/src/Components/Viewer/PmCalcDebugViewer.js +164 -146
- package/src/Components/Viewer/TextWithLinks.js +9 -1
- package/src/Components/Viewer/Viewer.js +38 -30
- package/src/Functions/flatten.js +39 -0
- package/src/Functions/verifyCanCrudPmEvents.js +33 -0
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
METER_TYPES__MILES_UNITS,
|
|
30
30
|
METER_TYPES__MILES_TEXT,
|
|
31
31
|
} from '../../Constants/MeterTypes.js';
|
|
32
|
+
import flatten from '../../Functions/flatten.js';
|
|
32
33
|
import Button from '../Buttons/Button.js';
|
|
33
34
|
import Json from '../Form/Field/Json.js';
|
|
34
35
|
import Panel from '../Panel/Panel.js';
|
|
@@ -38,6 +39,7 @@ import testProps from '../../Functions/testProps.js';
|
|
|
38
39
|
import moment from 'moment';
|
|
39
40
|
import _ from 'lodash';
|
|
40
41
|
|
|
42
|
+
|
|
41
43
|
export default function PmCalcDebugViewer(props) {
|
|
42
44
|
|
|
43
45
|
const {
|
|
@@ -45,34 +47,7 @@ export default function PmCalcDebugViewer(props) {
|
|
|
45
47
|
onClose,
|
|
46
48
|
} = props,
|
|
47
49
|
json = metersPmSchedule?.properties.meters_pm_schedules__debug_json.json,
|
|
48
|
-
|
|
49
|
-
for (const key in obj) {
|
|
50
|
-
if (obj.hasOwnProperty(key)) {
|
|
51
|
-
const
|
|
52
|
-
newKey = prefix ? `${prefix}.${key}` : key,
|
|
53
|
-
value = obj[key];
|
|
54
|
-
|
|
55
|
-
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
56
|
-
// Recursively flatten nested objects
|
|
57
|
-
flatten(value, newKey, result);
|
|
58
|
-
} else if (Array.isArray(value)) {
|
|
59
|
-
// Flatten arrays using index as key
|
|
60
|
-
value.forEach((item, index) => {
|
|
61
|
-
const arrayKey = `${newKey}.${index}`;
|
|
62
|
-
if (item !== null && typeof item === 'object') {
|
|
63
|
-
flatten(item, arrayKey, result);
|
|
64
|
-
} else {
|
|
65
|
-
result[arrayKey] = item;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
} else {
|
|
69
|
-
// Assign primitive values and null
|
|
70
|
-
result[newKey] = value;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return result;
|
|
75
|
-
},
|
|
50
|
+
record = flatten(json),
|
|
76
51
|
ucfirst = (string) => {
|
|
77
52
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
78
53
|
},
|
|
@@ -90,37 +65,85 @@ export default function PmCalcDebugViewer(props) {
|
|
|
90
65
|
return 'Unknown Mode';
|
|
91
66
|
}
|
|
92
67
|
},
|
|
93
|
-
|
|
68
|
+
formatBooleanValue = (value, record, self) => {
|
|
69
|
+
if (value === null || value === undefined) {
|
|
70
|
+
return 'N/A';
|
|
71
|
+
}
|
|
72
|
+
return value ? 'Yes' : 'No';
|
|
73
|
+
},
|
|
94
74
|
formatDaysValue = (value, record, self) => {
|
|
95
75
|
if (value === null || value === undefined) {
|
|
96
|
-
return
|
|
76
|
+
return 'N/A';
|
|
97
77
|
}
|
|
98
78
|
return parseInt(_.round(value), 10);
|
|
99
79
|
},
|
|
100
80
|
formatMeterValue = (value, record, self) => {
|
|
101
81
|
if (value === null || value === undefined) {
|
|
102
|
-
return
|
|
82
|
+
return 'N/A';
|
|
103
83
|
}
|
|
104
84
|
let ret;
|
|
105
85
|
const meterType = parseInt(record?.meter_type, 10);
|
|
86
|
+
let units = meterType === METER_TYPES__HOURS ? METER_TYPES__HOURS_UNITS : meterType === METER_TYPES__MILES ? METER_TYPES__MILES_UNITS : '';
|
|
87
|
+
if (value === 1) {
|
|
88
|
+
units = units.replace(/s$/, ''); // remove plural 's' if value is 1
|
|
89
|
+
}
|
|
106
90
|
switch(meterType) {
|
|
107
91
|
case METER_TYPES__HOURS:
|
|
108
|
-
ret = `${value} ${
|
|
92
|
+
ret = `${value} ${units}`;
|
|
109
93
|
break;
|
|
110
94
|
case METER_TYPES__MILES:
|
|
111
|
-
ret = `${value} ${
|
|
95
|
+
ret = `${value} ${units}`;
|
|
112
96
|
break;
|
|
113
97
|
}
|
|
114
98
|
return ret;
|
|
115
99
|
},
|
|
116
100
|
formatDateValue = (value, record, self) => {
|
|
117
101
|
if (value === null || value === undefined) {
|
|
118
|
-
return
|
|
102
|
+
return 'N/A';
|
|
119
103
|
}
|
|
120
104
|
|
|
121
105
|
// convert from datetime to pretty-printed date
|
|
122
106
|
return moment(value).format(MOMENT_DATE_FORMAT_6);
|
|
123
107
|
},
|
|
108
|
+
formatStatusValue = (value, record, self) => {
|
|
109
|
+
let ret = value,
|
|
110
|
+
classNames = null;
|
|
111
|
+
|
|
112
|
+
switch(record['pm_status_id']) {
|
|
113
|
+
case PM_STATUSES__OVERDUE:
|
|
114
|
+
classNames = [
|
|
115
|
+
'text-red-500',
|
|
116
|
+
'font-bold',
|
|
117
|
+
];
|
|
118
|
+
break;
|
|
119
|
+
case PM_STATUSES__PM_DUE:
|
|
120
|
+
classNames = [
|
|
121
|
+
'text-[#c89903]',
|
|
122
|
+
];
|
|
123
|
+
break;
|
|
124
|
+
case PM_STATUSES__DELAYED:
|
|
125
|
+
classNames = [
|
|
126
|
+
'text-green-500',
|
|
127
|
+
];
|
|
128
|
+
break;
|
|
129
|
+
case PM_STATUSES__WILL_CALL:
|
|
130
|
+
classNames = [
|
|
131
|
+
'text-blue-500',
|
|
132
|
+
];
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
if (classNames) {
|
|
136
|
+
// special formatting
|
|
137
|
+
ret = <Text
|
|
138
|
+
className={clsx(
|
|
139
|
+
classNames,
|
|
140
|
+
'px-3',
|
|
141
|
+
'py-2',
|
|
142
|
+
)}
|
|
143
|
+
>{value}</Text>;
|
|
144
|
+
}
|
|
145
|
+
return ret;
|
|
146
|
+
},
|
|
124
147
|
items = [
|
|
125
148
|
{
|
|
126
149
|
"type": "Column",
|
|
@@ -131,133 +154,138 @@ export default function PmCalcDebugViewer(props) {
|
|
|
131
154
|
"items": [
|
|
132
155
|
{
|
|
133
156
|
"type": "FieldSet",
|
|
134
|
-
"title": "
|
|
135
|
-
"reference": "
|
|
157
|
+
"title": "Overview",
|
|
158
|
+
"reference": "overview",
|
|
136
159
|
"defaults": {},
|
|
137
160
|
"items": [
|
|
138
|
-
{
|
|
161
|
+
record['pmSchedule.name'] && {
|
|
139
162
|
label: 'PM Schedule',
|
|
140
163
|
name: 'pmSchedule.name',
|
|
141
164
|
},
|
|
142
|
-
{
|
|
165
|
+
record['pm_status_name'] && {
|
|
143
166
|
label: 'Status',
|
|
144
167
|
name: 'pm_status_name',
|
|
168
|
+
viewerFormatter: formatStatusValue,
|
|
145
169
|
},
|
|
146
|
-
{
|
|
170
|
+
record['nextPmDate'] && {
|
|
147
171
|
label: 'Next PM Date',
|
|
148
172
|
name: 'nextPmDate',
|
|
149
173
|
viewerFormatter: formatDateValue,
|
|
150
174
|
},
|
|
151
|
-
|
|
152
|
-
label: '
|
|
153
|
-
name: 'overduePms',
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"type": "FieldSet",
|
|
159
|
-
"title": "Calculation Details",
|
|
160
|
-
"reference": "calcDetails",
|
|
161
|
-
"defaults": {},
|
|
162
|
-
"items": [
|
|
163
|
-
{
|
|
164
|
-
label: 'Controlling Method',
|
|
165
|
-
name: 'controllingMethod',
|
|
166
|
-
tooltip: 'Indicates whether the calculation was based on days or usage (meter). ' +
|
|
167
|
-
'If both methods are applicable, the one resulting in the earlier PM date is chosen.',
|
|
168
|
-
},
|
|
169
|
-
(json?.pm_status_id === PM_STATUSES__OVERDUE || json?.pm_status_id === PM_STATUSES__PM_DUE) && {
|
|
170
|
-
label: 'Grace Period End Date',
|
|
175
|
+
record['pm_status_id'] && record['pm_status_id'] === PM_STATUSES__OVERDUE && {
|
|
176
|
+
label: 'Grace Period Ends',
|
|
171
177
|
name: 'maxGracePeriodDateTime',
|
|
172
178
|
viewerFormatter: formatDateValue,
|
|
173
179
|
},
|
|
174
|
-
{
|
|
175
|
-
label: '
|
|
176
|
-
name: '
|
|
177
|
-
tooltip: 'Indicates whether the calculation was based on days or usage (meter). ' +
|
|
178
|
-
'If both methods are applicable, the one resulting in the earlier PM date is chosen.',
|
|
179
|
-
viewerFormatter: formatDateValue,
|
|
180
|
-
},
|
|
181
|
-
json?.workOrder?.title && {
|
|
182
|
-
label: 'Work Order',
|
|
183
|
-
name: 'workOrder.title',
|
|
184
|
-
},
|
|
185
|
-
json?.workOrder?.service_order && {
|
|
186
|
-
label: 'Work Order',
|
|
187
|
-
name: 'workOrder.service_order',
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
label: 'Meter Accrued Since Last PM',
|
|
191
|
-
name: 'meterAccruedSinceLatestPm',
|
|
192
|
-
viewerFormatter: formatMeterValue,
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
label: 'Meter Remaining Until Next PM',
|
|
196
|
-
name: 'meterRemainingUntilNextPm',
|
|
197
|
-
viewerFormatter: formatMeterValue,
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
label: 'Days Since Last PM',
|
|
201
|
-
name: 'daysSinceLatestPm',
|
|
202
|
-
viewerFormatter: formatDaysValue,
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
label: 'Days Left Until Next PM',
|
|
206
|
-
name: 'daysLeft',
|
|
207
|
-
viewerFormatter: formatDaysValue,
|
|
180
|
+
record['pm_status_id'] && record['pm_status_id'] === PM_STATUSES__OVERDUE && {
|
|
181
|
+
label: 'Overdue by # Cycles',
|
|
182
|
+
name: 'overduePms',
|
|
208
183
|
},
|
|
209
|
-
|
|
210
|
-
// label: 'Is Delayed',
|
|
211
|
-
// name: 'isDelayed',
|
|
212
|
-
// },
|
|
213
|
-
// json?.isOverride && {
|
|
214
|
-
// label: 'Is Override',
|
|
215
|
-
// name: 'isOverride',
|
|
216
|
-
// },
|
|
217
|
-
]
|
|
184
|
+
],
|
|
218
185
|
},
|
|
219
|
-
{
|
|
186
|
+
record['calculationMode'] && {
|
|
220
187
|
"type": "FieldSet",
|
|
221
|
-
"title": "
|
|
222
|
-
"reference": "
|
|
188
|
+
"title": "How it was calculated",
|
|
189
|
+
"reference": "calcDetails",
|
|
223
190
|
"defaults": {},
|
|
224
191
|
"items": [
|
|
225
|
-
json?.pmSchedule?.interval_days && {
|
|
226
|
-
label: 'Interval Days',
|
|
227
|
-
name: 'pmSchedule.interval_days',
|
|
228
|
-
},
|
|
229
|
-
json?.pmSchedule?.interval_meter && {
|
|
230
|
-
label: 'Interval Meter',
|
|
231
|
-
name: 'pmSchedule.interval_meter',
|
|
232
|
-
viewerFormatter: formatMeterValue,
|
|
233
|
-
},
|
|
234
192
|
{
|
|
235
|
-
label: 'Mode',
|
|
236
|
-
name: '
|
|
193
|
+
label: 'Calculation Mode',
|
|
194
|
+
name: 'calculationMode',
|
|
237
195
|
},
|
|
238
|
-
]
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
"type": "FieldSet",
|
|
242
|
-
"title": "Equipment",
|
|
243
|
-
"reference": "equipment",
|
|
244
|
-
"defaults": {},
|
|
245
|
-
"items": [
|
|
246
196
|
{
|
|
247
197
|
label: 'In Service Date',
|
|
248
198
|
name: 'inServiceDate',
|
|
249
199
|
viewerFormatter: formatDateValue,
|
|
250
200
|
},
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
201
|
+
...(record['isOverride'] ? [
|
|
202
|
+
// these items are only for overrides
|
|
203
|
+
{
|
|
204
|
+
label: 'Is Override',
|
|
205
|
+
name: 'isOverride',
|
|
206
|
+
viewerFormatter: formatBooleanValue,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
label: 'Override Event Date',
|
|
210
|
+
name: 'overrideEventDate',
|
|
211
|
+
viewerFormatter: formatDateValue,
|
|
212
|
+
},
|
|
213
|
+
] : []),
|
|
214
|
+
...(!record['isOverride'] ? [
|
|
215
|
+
// these items are only for non-overrides
|
|
216
|
+
{
|
|
217
|
+
label: 'Last Reset Date',
|
|
218
|
+
name: 'resetDate',
|
|
219
|
+
viewerFormatter: formatDateValue,
|
|
220
|
+
},
|
|
221
|
+
record['workOrder.title'] && { // Gingerich
|
|
222
|
+
label: 'Work Order',
|
|
223
|
+
name: 'workOrder.title',
|
|
224
|
+
},
|
|
225
|
+
record['workOrder.service_order'] && { // MH
|
|
226
|
+
label: 'Service Order',
|
|
227
|
+
name: 'workOrder.service_order',
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
label: 'Interval Days',
|
|
231
|
+
name: 'intervalDays',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
label: 'Days Left Until Next PM',
|
|
235
|
+
name: 'daysLeft',
|
|
236
|
+
viewerFormatter: formatDaysValue,
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: 'Interval Meter',
|
|
240
|
+
name: 'intervalMeter',
|
|
241
|
+
viewerFormatter: formatMeterValue,
|
|
242
|
+
},
|
|
243
|
+
typeof record['latestMeterReading.value'] !== 'undefined' && { // typeof so it allows 0
|
|
244
|
+
label: 'Latest Meter Reading',
|
|
245
|
+
name: 'latestMeterReading',
|
|
246
|
+
viewerFormatter: (value, record) => {
|
|
247
|
+
const
|
|
248
|
+
meterValue = formatMeterValue(record['latestMeterReading.value'], record),
|
|
249
|
+
meterDate = formatDateValue(record['latestMeterReading.date'], record);
|
|
250
|
+
return `${meterValue} on ${meterDate}`;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
label: 'Meter Accrued Since Latest PM',
|
|
255
|
+
name: 'meterAccruedSinceLatestPm',
|
|
256
|
+
viewerFormatter: formatMeterValue,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
label: 'Avg Daily Meter',
|
|
260
|
+
name: 'avgDailyMeter',
|
|
261
|
+
viewerFormatter: formatMeterValue,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
label: 'Meter Until Next PM',
|
|
265
|
+
name: 'meterRemainingUntilNextPm',
|
|
266
|
+
viewerFormatter: formatMeterValue,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
label: 'Controlling Method',
|
|
270
|
+
name: 'controllingMethod',
|
|
271
|
+
tooltip: 'Indicates whether the calculation was based on days or usage (meter). ' +
|
|
272
|
+
'If both methods are applicable, the one resulting in the earlier PM date is chosen.',
|
|
273
|
+
},
|
|
274
|
+
] : []),
|
|
275
|
+
|
|
276
|
+
...(record['isOverride'] ? [
|
|
277
|
+
// these items are only for delays
|
|
278
|
+
{
|
|
279
|
+
label: 'Is Delayed',
|
|
280
|
+
name: 'isDelayed',
|
|
281
|
+
viewerFormatter: formatBooleanValue,
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
label: 'Delay Threshold Date',
|
|
285
|
+
name: 'delayThresholdDate',
|
|
286
|
+
viewerFormatter: formatDateValue,
|
|
287
|
+
},
|
|
288
|
+
] : []),
|
|
261
289
|
]
|
|
262
290
|
},
|
|
263
291
|
|
|
@@ -265,7 +293,7 @@ export default function PmCalcDebugViewer(props) {
|
|
|
265
293
|
}
|
|
266
294
|
];
|
|
267
295
|
|
|
268
|
-
|
|
296
|
+
record.pmScheduleMode = getPmScheduleMode(json?.pmSchedule.pm_schedule_mode_id);
|
|
269
297
|
|
|
270
298
|
return <Panel
|
|
271
299
|
title="PM Calculation Info"
|
|
@@ -282,18 +310,8 @@ export default function PmCalcDebugViewer(props) {
|
|
|
282
310
|
</Footer>}
|
|
283
311
|
>
|
|
284
312
|
<Viewer
|
|
285
|
-
record={
|
|
313
|
+
record={record}
|
|
286
314
|
items={items}
|
|
287
315
|
/>
|
|
288
|
-
{/* <VStack className="PmCalcDebugViewer-VStack p-4">
|
|
289
|
-
|
|
290
|
-
<Text>Equipment: {metersPmSchedule.meters__nickname}</Text>
|
|
291
|
-
<Json
|
|
292
|
-
value={metersPmSchedule.meters_pm_schedules__debug_json}
|
|
293
|
-
displaySize="expanded"
|
|
294
|
-
editable={false}
|
|
295
|
-
collapsed={2}
|
|
296
|
-
/>
|
|
297
|
-
</VStack> */}
|
|
298
316
|
</Panel>;
|
|
299
317
|
}
|
|
@@ -49,13 +49,21 @@ function TextWithLinksElement(props) {
|
|
|
49
49
|
modifiedText = modifiedText.replace(link, key);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
let
|
|
53
53
|
textClassName = clsx(
|
|
54
54
|
'TextWithLinks-Text',
|
|
55
55
|
'text-base',
|
|
56
56
|
'overflow-hidden',
|
|
57
|
+
styles.FORM_TEXT_CLASSNAME,
|
|
57
58
|
),
|
|
58
59
|
textSegments = modifiedText.split(/(link_\d+)/);
|
|
60
|
+
if (props.className) {
|
|
61
|
+
const
|
|
62
|
+
classes = props.className.split(' '),
|
|
63
|
+
newClasses = _.reject(classes, (c) => c === 'overflow-auto'),
|
|
64
|
+
className = newClasses.join(' ');
|
|
65
|
+
textClassName += ' ' + className;
|
|
66
|
+
}
|
|
59
67
|
if (textSegments.length === 1) {
|
|
60
68
|
return <Text className={textClassName}>{modifiedText}</Text>;
|
|
61
69
|
}
|
|
@@ -278,39 +278,47 @@ function Viewer(props) {
|
|
|
278
278
|
value = record.properties[fkDisplayField].displayValue;
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
|
+
let element = null,
|
|
282
|
+
viewerFormatterReturnedReactComponent = false;
|
|
281
283
|
if (viewerFormatter) {
|
|
282
|
-
value = viewerFormatter(value, record, self);
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
'grow',
|
|
289
|
-
'shrink',
|
|
290
|
-
);
|
|
291
|
-
const defaultsClassName = defaults.className;
|
|
292
|
-
if (defaultsClassName) {
|
|
293
|
-
elementClassName += ' ' + defaultsClassName;
|
|
294
|
-
}
|
|
295
|
-
const itemPropsToPassClassName = itemPropsToPass.className;
|
|
296
|
-
if (itemPropsToPassClassName) {
|
|
297
|
-
elementClassName += ' ' + itemPropsToPassClassName;
|
|
284
|
+
value = viewerFormatter(value, record, self); // viewerFormatter can return either a primitive value or a React component.
|
|
285
|
+
if (isValidElement(value)) {
|
|
286
|
+
// if it's a React component, render it directly
|
|
287
|
+
element = value;
|
|
288
|
+
viewerFormatterReturnedReactComponent = true;
|
|
289
|
+
}
|
|
298
290
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
291
|
+
if (!viewerFormatterReturnedReactComponent) {
|
|
292
|
+
let elementClassName = clsx(
|
|
293
|
+
'Viewer-field',
|
|
294
|
+
'basis-auto',
|
|
295
|
+
'grow',
|
|
296
|
+
'shrink',
|
|
297
|
+
);
|
|
298
|
+
const defaultsClassName = defaults.className;
|
|
299
|
+
if (defaultsClassName) {
|
|
300
|
+
elementClassName += ' ' + defaultsClassName;
|
|
301
|
+
}
|
|
302
|
+
const itemPropsToPassClassName = itemPropsToPass.className;
|
|
303
|
+
if (itemPropsToPassClassName) {
|
|
304
|
+
elementClassName += ' ' + itemPropsToPassClassName;
|
|
305
|
+
}
|
|
306
|
+
const viewerTypeClassName = viewerTypeProps.className;
|
|
307
|
+
if (viewerTypeClassName) {
|
|
308
|
+
elementClassName += ' ' + viewerTypeClassName;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
element = <Element
|
|
312
|
+
{...testProps('field-' + name)}
|
|
313
|
+
value={value}
|
|
314
|
+
isEditable={false}
|
|
315
|
+
parent={self}
|
|
316
|
+
reference={name}
|
|
317
|
+
{...itemPropsToPass}
|
|
318
|
+
{...viewerTypeProps}
|
|
319
|
+
className={elementClassName}
|
|
320
|
+
/>;
|
|
302
321
|
}
|
|
303
|
-
|
|
304
|
-
let element = <Element
|
|
305
|
-
{...testProps('field-' + name)}
|
|
306
|
-
value={value}
|
|
307
|
-
isEditable={false}
|
|
308
|
-
parent={self}
|
|
309
|
-
reference={name}
|
|
310
|
-
{...itemPropsToPass}
|
|
311
|
-
{...viewerTypeProps}
|
|
312
|
-
className={elementClassName}
|
|
313
|
-
/>;
|
|
314
322
|
|
|
315
323
|
if (item.additionalViewButtons) {
|
|
316
324
|
element = <HStack className="Viewer-HStack1 flex-wrap">
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// This function takes a nested JSON object and flattens it into a single-level object with dot notation keys.
|
|
2
|
+
// For example, { a: { b: 1 } } becomes { 'a.b': 1 }
|
|
3
|
+
// or { a: [ { b: 1 }, { c: 2 } ] } becomes { 'a.0.b': 1, 'a.1.c': 2 }
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
if (value === null || typeof value !== 'object') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10
|
+
return prototype === Object.prototype || prototype === null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default function flatten(obj, prefix = '', result = {}) {
|
|
14
|
+
if (obj === null || typeof obj !== 'object') {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for (const key of Object.keys(obj)) {
|
|
19
|
+
const
|
|
20
|
+
newKey = prefix ? `${prefix}.${key}` : key,
|
|
21
|
+
value = obj[key];
|
|
22
|
+
|
|
23
|
+
if (isPlainObject(value)) {
|
|
24
|
+
flatten(value, newKey, result);
|
|
25
|
+
} else if (Array.isArray(value)) {
|
|
26
|
+
value.forEach((item, index) => {
|
|
27
|
+
const arrayKey = `${newKey}.${index}`;
|
|
28
|
+
if (isPlainObject(item) || Array.isArray(item)) {
|
|
29
|
+
flatten(item, arrayKey, result);
|
|
30
|
+
} else {
|
|
31
|
+
result[arrayKey] = item;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
result[newKey] = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PM_EVENT_TYPES__COMPLETE,
|
|
3
|
+
PM_EVENT_TYPES__RESET,
|
|
4
|
+
PM_EVENT_TYPES__DELAY_BY_DAYS,
|
|
5
|
+
PM_EVENT_TYPES__DELAY_BY_METER,
|
|
6
|
+
PM_EVENT_TYPES__SCHEDULE_PM,
|
|
7
|
+
PM_EVENT_TYPES__WILL_CALL,
|
|
8
|
+
PM_EVENT_TYPES__ASSIGN_TECHNICIAN,
|
|
9
|
+
PM_EVENT_TYPES__COMMENT,
|
|
10
|
+
} from '../Constants/PmEventTypes.js';
|
|
11
|
+
import inArray from './inArray.js';
|
|
12
|
+
import _ from 'lodash';
|
|
13
|
+
|
|
14
|
+
export default function verifyCanCrudPmEvents(selection) {
|
|
15
|
+
let canCrud = true;
|
|
16
|
+
_.each(selection, (entity) => {
|
|
17
|
+
if (!inArray(entity.pm_events__pm_event_type_id, [
|
|
18
|
+
// manual types
|
|
19
|
+
PM_EVENT_TYPES__COMPLETE,
|
|
20
|
+
PM_EVENT_TYPES__RESET,
|
|
21
|
+
PM_EVENT_TYPES__DELAY_BY_DAYS,
|
|
22
|
+
PM_EVENT_TYPES__DELAY_BY_METER,
|
|
23
|
+
PM_EVENT_TYPES__SCHEDULE_PM,
|
|
24
|
+
PM_EVENT_TYPES__WILL_CALL,
|
|
25
|
+
PM_EVENT_TYPES__ASSIGN_TECHNICIAN,
|
|
26
|
+
PM_EVENT_TYPES__COMMENT,
|
|
27
|
+
])) {
|
|
28
|
+
canCrud = false;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return canCrud;
|
|
33
|
+
};
|