@mixd-id/web-scaffold 0.1.230406001

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/package.json +71 -0
  4. package/public/images/mixd-logo2.png +0 -0
  5. package/src/App.vue +17 -0
  6. package/src/components/Ahref.vue +34 -0
  7. package/src/components/Alert.vue +160 -0
  8. package/src/components/Button.vue +253 -0
  9. package/src/components/ButtonGroup.vue +101 -0
  10. package/src/components/Carousel.vue +293 -0
  11. package/src/components/ChatTyping.vue +69 -0
  12. package/src/components/Checkbox.vue +152 -0
  13. package/src/components/ContextMenu.vue +261 -0
  14. package/src/components/CopyToClipboard.vue +59 -0
  15. package/src/components/Countdown.vue +213 -0
  16. package/src/components/Datepicker.vue +312 -0
  17. package/src/components/Dropdown.vue +198 -0
  18. package/src/components/DynamicTemplate.vue +44 -0
  19. package/src/components/ErrorText.vue +36 -0
  20. package/src/components/Feed.vue +118 -0
  21. package/src/components/Gmaps.vue +227 -0
  22. package/src/components/Grid.vue +29 -0
  23. package/src/components/GridColumn.vue +31 -0
  24. package/src/components/HTMLEditor.vue +396 -0
  25. package/src/components/Image.vue +207 -0
  26. package/src/components/Image360.vue +140 -0
  27. package/src/components/ImageFullScreen.vue +101 -0
  28. package/src/components/ImagePreview.vue +71 -0
  29. package/src/components/ImportModal.vue +247 -0
  30. package/src/components/ListItem.vue +147 -0
  31. package/src/components/ListPage1.vue +1331 -0
  32. package/src/components/ListPage1Filter.vue +170 -0
  33. package/src/components/Modal.vue +253 -0
  34. package/src/components/OTPField.vue +126 -0
  35. package/src/components/Radio.vue +134 -0
  36. package/src/components/SearchButton.vue +57 -0
  37. package/src/components/Slider.vue +285 -0
  38. package/src/components/SplitPane.vue +129 -0
  39. package/src/components/Switch.vue +89 -0
  40. package/src/components/TabView.vue +106 -0
  41. package/src/components/TableView.vue +201 -0
  42. package/src/components/TableViewHead.vue +159 -0
  43. package/src/components/Tabs.vue +74 -0
  44. package/src/components/TextEditor.vue +85 -0
  45. package/src/components/Textarea.vue +184 -0
  46. package/src/components/Textbox.vue +200 -0
  47. package/src/components/Timepicker.vue +108 -0
  48. package/src/components/Toast.vue +93 -0
  49. package/src/components/VirtualScroll.vue +215 -0
  50. package/src/components/VirtualTable.vue +497 -0
  51. package/src/entry-client.js +27 -0
  52. package/src/entry-server.js +73 -0
  53. package/src/index.css +3 -0
  54. package/src/index.js +255 -0
  55. package/src/main.js +38 -0
  56. package/src/router.js +57 -0
  57. package/src/themes/default/index.js +200 -0
  58. package/src/utils/helpers.js +185 -0
  59. package/src/utils/helpers.mjs +197 -0
  60. package/src/utils/importer.js +156 -0
  61. package/src/utils/listpage1.js +1371 -0
  62. package/src/utils/selection.js +64 -0
@@ -0,0 +1,1371 @@
1
+ const { Op } = module.parent.require('sequelize')
2
+ const Sequelize = module.parent.require('sequelize')
3
+ const dayjs = require("dayjs");
4
+ const Exceljs = require("exceljs");
5
+
6
+ let ListPage1 = {
7
+
8
+ presetName: 'listpage1',
9
+ itemsPerPage: 24,
10
+ model: '',
11
+ channel: '',
12
+
13
+ async patch(params, socket){
14
+
15
+ const { reset } = params
16
+
17
+ let currentPreset
18
+ const preset = this['loadPreset'] && !reset ? await this.loadPreset() : undefined
19
+ if(preset){
20
+ currentPreset = {
21
+ ...this.getDefaultPresets(),
22
+ ...preset
23
+ }
24
+ }
25
+ else{
26
+ currentPreset = {
27
+ ...this.getDefaultPresets()
28
+ }
29
+ }
30
+
31
+ for(let i = 0 ; i < currentPreset.presets.length ; i++){
32
+
33
+ Object.assign({
34
+ name: 'Default',
35
+ columns: [],
36
+ sorts: [],
37
+ filters: [],
38
+ summaries: [],
39
+ },
40
+ currentPreset.presets[i])
41
+
42
+ if(currentPreset.presets[i].summaries){
43
+ for(let j = 0 ; j < currentPreset.presets[i].summaries.length ; j++){
44
+
45
+ Object.assign({
46
+ map: {
47
+ mapRadius: 16,
48
+ mapType: "heatmap",
49
+ zoom: 7
50
+ }
51
+ },
52
+ currentPreset.presets[i].summaries[j])
53
+ }
54
+ }
55
+ }
56
+
57
+ /*if(this.user && this.socket && this.socket.auth){
58
+ const { userId } = this.socket.auth
59
+ const user = await this.user.withId(userId)
60
+ const preset = await user.loadPreset(this.presetName)
61
+
62
+ }
63
+ else{
64
+
65
+ }*/
66
+
67
+ const data = await this.load({ preset:currentPreset.presets[currentPreset.presetIdx] })
68
+
69
+ if(this.channel && this.socket){
70
+ if(this.socket.joinWithArgs){
71
+ this.socket.joinWithArgs(this.channel, { preset:currentPreset.presets[currentPreset.presetIdx] })
72
+ }
73
+ else{
74
+ this.socket.join(this.channel)
75
+ }
76
+ }
77
+
78
+ const mapApiKey = this.getMapApiKey ? this.getMapApiKey() : undefined
79
+
80
+ return {
81
+ configs: currentPreset,
82
+ mapApiKey,
83
+ ...data
84
+ }
85
+ },
86
+
87
+ async load(params){
88
+
89
+ const { items, hasNext, count } = await this._load(params)
90
+
91
+ return {
92
+ items,
93
+ hasNext,
94
+ count
95
+ }
96
+ },
97
+
98
+ async loadSummary(params){
99
+
100
+ if(!this.conn){
101
+ console.error('Unable to load summary, connection not found')
102
+ return
103
+ }
104
+
105
+ const { preset = {} } = params
106
+ const summary = preset.summaries.filter((_) => _.enabled).pop()
107
+
108
+ if(!summary) return
109
+
110
+ const { derivedSql, where, replacements } = await this._load(params)
111
+
112
+ switch(summary.mode){
113
+
114
+ case 'bar':
115
+ return await this.loadBarSummary(summary, derivedSql)
116
+
117
+ case 'line':
118
+ return await this.loadLineSummary(summary, derivedSql)
119
+
120
+ case 'table':
121
+ return await this.loadTableSummary(summary, derivedSql)
122
+
123
+ case 'map':
124
+ if(this.loadMapSummary){
125
+ return await this.loadMapSummary(preset, {
126
+ derivedSql,
127
+ where,
128
+ replacements
129
+ })
130
+ }
131
+ break
132
+
133
+ }
134
+
135
+ return
136
+
137
+
138
+
139
+ /*const attributes = []
140
+ const group = []
141
+ const summaryColumns = [
142
+ /!*{ key:"dfDate", label:"Date", width:"200px", visible:true },
143
+ { key:"type-1", label:"Type 1", type:"number", visible:true },
144
+ { key:"type-2", label:"Type 2", type:"number", visible:true },
145
+ { key:"type-3", label:"Type 3", type:"number", visible:true },
146
+ { key:"type-4", label:"Type 4", type:"number", visible:true },
147
+ { key:"type-8", label:"Type 8", type:"number", visible:true },*!/
148
+ ]
149
+
150
+ const row = rows[0]
151
+ const rowKey = row.key
152
+ const rowLabel = this.columns[row.key].label
153
+ switch(row.format){
154
+ case 'date':
155
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d') as dfDate`)
156
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d')`)
157
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"D MMM" })
158
+ break
159
+
160
+ case 'month':
161
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m') as dfDate`)
162
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m')`)
163
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
164
+ break
165
+
166
+ case 'quarter':
167
+ attributes.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey})) as dfDate`)
168
+ group.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey}))`)
169
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
170
+ break
171
+
172
+ case 'year':
173
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y') as dfDate`)
174
+ group.push(`DATE_FORMAT(${rowKey}, '%Y')`)
175
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"YYYY" })
176
+ break
177
+
178
+ default:
179
+ attributes.push(`${rowKey} as dfDate`)
180
+ group.push(`${rowKey}`)
181
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true })
182
+ break
183
+ }
184
+
185
+ const value = values[0]
186
+ if(columnValues.length > 0){
187
+ columnValues.forEach((obj) => {
188
+ const columnValue = obj.cols
189
+
190
+ let columnLabel = (columnValue ?? '').toString()
191
+ const baseColumn = this.columns[colKey]
192
+ switch(baseColumn.type){
193
+
194
+ case 'enum':
195
+ const enumValue = baseColumn.typeParams.filter((_) => _.value === columnValue).pop()
196
+ if(enumValue) columnLabel = enumValue.text
197
+ break
198
+ }
199
+
200
+ switch(value.aggregrate){
201
+ case 'count':
202
+ const fn = columnValue === null ? `${colKey} is null` : `${colKey} = '${columnValue}'`
203
+ attributes.push(`SUM(IF(${fn}, 1, 0)) as \`${colKey}-${columnValue}\``)
204
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
205
+ break
206
+
207
+ case 'min':
208
+ attributes.push(`MIN(${colKey}) as \`${colKey}-${columnValue}\``)
209
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
210
+ break
211
+
212
+ case 'max':
213
+ attributes.push(`MAX(${colKey}) as \`${colKey}-${columnValue}\``)
214
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
215
+ break
216
+
217
+ case 'avg':
218
+ attributes.push(`AVG(${colKey}) as \`${colKey}-${columnValue}\``)
219
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
220
+ break
221
+ }
222
+ })
223
+ }
224
+ else{
225
+ switch(value.aggregrate) {
226
+ case 'count':
227
+ default:
228
+ attributes.push(`COUNT(*) as \`Count\``)
229
+ summaryColumns.push({ key:'Count', label:'Count', type:"number", visible:true, aggregrate:"count" })
230
+ }
231
+ }
232
+
233
+ //console.log(attributes)
234
+
235
+ let [ summaryItems ] = await this.conn.query(`
236
+ SELECT
237
+ ${attributes.join(', ')}
238
+ FROM (
239
+ ${derivedSql}
240
+ ) as t1
241
+ GROUP BY ${group[0]}
242
+ ORDER BY dfDate ASC
243
+ `)
244
+
245
+ if(this.columns[rowKey] && this.columns[rowKey].type === 'enum'){
246
+ summaryItems = summaryItems.map((_) => {
247
+
248
+ const typeParam = this.columns[rowKey].typeParams.filter((__) => __.value === _.dfDate).pop()
249
+ if(typeParam){
250
+ _.dfDate = typeParam.text
251
+ }
252
+
253
+ return _
254
+ })
255
+ }
256
+
257
+ const summary = {
258
+ type: "table",
259
+ columns: summaryColumns,
260
+ items: summaryItems
261
+ /!*items: [
262
+ { date:"21 Jan 23", "type-1":12, "type-2":11, "type-3":16, "type-4":2, "type-8":8 },
263
+ { date:"22 Jan 23", "type-1":51, "type-2":87, "type-3":86, "type-4":3, "type-8":9 },
264
+ { date:"23 Jan 23", "type-1":14, "type-2":66, "type-3":77, "type-4":4, "type-8":18 },
265
+ { date:"24 Jan 23", "type-1":7, "type-2":3, "type-3":63, "type-4":5, "type-8":28 },
266
+ { date:"25 Jan 23", "type-1":88, "type-2":55, "type-3":68, "type-4":6, "type-8":38 },
267
+ { date:"26 Jan 23", "type-1":172, "type-2":13, "type-3":6, "type-4":7, "type-8":48 }
268
+ ]*!/
269
+ }
270
+
271
+ return summary*/
272
+ },
273
+
274
+ async subscribe(params, socket){
275
+ const { name } = params
276
+ if(name){
277
+ socket.join(this.name)
278
+ }
279
+ },
280
+
281
+ async unsubscribe(params, socket){
282
+ const { name } = params
283
+ if(name){
284
+ socket.leave(this.name)
285
+ }
286
+ },
287
+
288
+ async downloadRows(params, socket){
289
+
290
+ const { preset } = params
291
+
292
+ const columns = []
293
+ preset.columns.forEach((column) => {
294
+ if(column.visible){
295
+ columns.push({ header: column.label, key: column.key, width: 15 })
296
+ }
297
+ })
298
+
299
+ const workbook = new Exceljs.Workbook();
300
+ const sheet = workbook.addWorksheet('Export ' + this.name);
301
+ sheet.columns = columns
302
+
303
+ let where = {}
304
+ let replacements = []
305
+ let order = [
306
+ [ 'updatedAt', 'desc' ],
307
+ [ 'id', 'desc' ],
308
+ ]
309
+
310
+ let attributeIncludes
311
+ if(this.getAttributeIncludes){
312
+ attributeIncludes = this.getAttributeIncludes(preset)
313
+ }
314
+
315
+ let attributes = { id:1, updatedAt:1 }
316
+ if(preset.columns){
317
+ let modelAttributes = this.model.getAttributes();
318
+ preset.columns.forEach((column) => {
319
+ if(column.visible && modelAttributes[column.key]){
320
+ attributes[column.key] = 1
321
+ }
322
+ else if(column.virtual){
323
+ switch(column.virtual.type){
324
+
325
+ case 'sql':
326
+ if(!Array.isArray(attributeIncludes)){
327
+ attributeIncludes = []
328
+ }
329
+
330
+ attributeIncludes.push([
331
+ Sequelize.literal(`(${column.virtual.value})`), column.key
332
+ ])
333
+ break
334
+ }
335
+ }
336
+ })
337
+ }
338
+ attributes = Object.keys(attributes)
339
+
340
+ if(preset.filters){
341
+ const { where:presetWhere } = this.getPresetFilterParams(preset)
342
+ where = {
343
+ ...where,
344
+ ...presetWhere
345
+ }
346
+ }
347
+
348
+ if(preset.sorts){
349
+ const { order:presetOrder } = this.getPresetSortParams(preset)
350
+ if(presetOrder){
351
+ order = presetOrder
352
+ }
353
+ }
354
+
355
+ if(preset.search){
356
+ const tableName = this.model.name
357
+ where = {
358
+ ...where,
359
+ [Op.and]: Sequelize.literal(`MATCH(\`${tableName}\`.tag) AGAINST (? IN BOOLEAN MODE)`)
360
+ }
361
+ replacements.push(preset.search)
362
+ }
363
+
364
+ if(this.downloadFilters){
365
+ await this.downloadFilters(params, where)
366
+ }
367
+
368
+ const rows = await this.model.findAll({
369
+ where,
370
+ attributes: {
371
+ ...attributes,
372
+ include: attributeIncludes
373
+ },
374
+ order,
375
+ replacements,
376
+ include: this.getModelIncludes ? this.getModelIncludes(preset) : undefined
377
+ })
378
+
379
+ rows.forEach((row) => {
380
+
381
+ const obj = {}
382
+ preset.columns.forEach((column) => {
383
+ if(column.visible){
384
+ switch(column.type){
385
+
386
+ case 'enum':
387
+ const enumValue = row[column.key]
388
+ const enumObj = column.typeParams.filter((_) => _.value === enumValue).pop()
389
+ const enumText = (enumObj ?? {}).text ?? enumValue
390
+ obj[column.key] = enumText
391
+ break
392
+
393
+ default:
394
+ obj[column.key] = row[column.key]
395
+ break
396
+ }
397
+ }
398
+ })
399
+ sheet.addRow(obj)
400
+ })
401
+
402
+ const filename = 'data-konsumen-' + dayjs().format('YYYYMMDDHHmm') + '.xlsx'
403
+ await workbook.xlsx.writeFile(process.env.ROOT_PATH + '/storage/files/downloads/' + filename);
404
+ return {
405
+ url: '/downloads/' + filename
406
+ }
407
+ },
408
+
409
+
410
+
411
+ async _load(params){
412
+
413
+ /*const listAcl = socket.auth.user.getAclv('customer', 'list')
414
+ if(listAcl === false){
415
+ throw new Error('Insufficient privilege')
416
+ }
417
+ else if(Array.isArray(listAcl.filters) && listAcl.filters.includes('user-customers')){
418
+ where = {
419
+ ...where,
420
+ referralType: {
421
+ [Op.in]: [ "App\\Models\\User", "user" ]
422
+ },
423
+ referralId: socket.auth.userId
424
+ }
425
+ }*/
426
+
427
+ const { afterItem, itemsPerPage = this.itemsPerPage ?? 24 } = params
428
+ const { preset = {} } = params
429
+ let where = {}
430
+ let replacements = []
431
+ let order = [
432
+ [ 'updatedAt', 'desc' ],
433
+ [ 'id', 'desc' ],
434
+ ]
435
+
436
+ let attributeIncludes
437
+ if(this.getAttributeIncludes){
438
+ attributeIncludes = this.getAttributeIncludes(preset)
439
+ }
440
+
441
+ let attributes = { id:1, updatedAt:1 }
442
+ if(preset.columns){
443
+ let modelAttributes = this.model.getAttributes();
444
+ preset.columns.forEach((column) => {
445
+ if(column.visible && modelAttributes[column.key]){
446
+ attributes[column.key] = 1
447
+ }
448
+ else if(column.virtual){
449
+ switch(column.virtual.type){
450
+
451
+ case 'sql':
452
+ if(!Array.isArray(attributeIncludes)){
453
+ attributeIncludes = []
454
+ }
455
+
456
+ attributeIncludes.push([
457
+ Sequelize.literal(`(${column.virtual.value})`), column.key
458
+ ])
459
+ break
460
+ }
461
+ }
462
+ })
463
+ }
464
+ attributes = Object.keys(attributes)
465
+
466
+ if(preset.filters){
467
+ const { where:presetWhere } = this.getPresetFilterParams(preset)
468
+ where = {
469
+ ...where,
470
+ ...presetWhere
471
+ }
472
+ }
473
+
474
+ if(preset.sorts){
475
+ const { order:presetOrder } = this.getPresetSortParams(preset)
476
+ if(presetOrder){
477
+ order = presetOrder
478
+ }
479
+ }
480
+
481
+ if(preset.search){
482
+ const tableName = this.model.name
483
+ where = {
484
+ ...where,
485
+ [Op.and]: Sequelize.literal(`MATCH(\`${tableName}\`.tag) AGAINST (? IN BOOLEAN MODE)`)
486
+ }
487
+ replacements.push(preset.search)
488
+ }
489
+
490
+ if(afterItem){
491
+ const sortWhere = this.getPresetSortWhereParams(order, afterItem)
492
+ where = {
493
+ ...where,
494
+ ...sortWhere
495
+ }
496
+ }
497
+
498
+ let derivedSql
499
+ const { rows:items, count } = await this.model.findAndCountAll({
500
+ where,
501
+ attributes: {
502
+ ...attributes,
503
+ include: attributeIncludes
504
+ },
505
+ order,
506
+ limit: itemsPerPage + 1,
507
+ replacements,
508
+ include: this.getModelIncludes ? this.getModelIncludes(preset) : undefined,
509
+ logging: (sql, queryObject, p) => {
510
+ derivedSql = sql
511
+ }
512
+ })
513
+ derivedSql = derivedSql.replace('Executing (default): ', '').replace('LIMIT ' + (this.itemsPerPage + 1), '').slice(0, -1)
514
+
515
+ const hasNext = items.length > itemsPerPage
516
+ if(hasNext){
517
+ items.splice(items.length - 1, 1)
518
+ }
519
+
520
+ /*let summary
521
+ if(!afterItem && preset.summary && preset.summary.enabled){
522
+ if(preset.summary.mode === 'map' && this.loadMapSummary){
523
+ summary = await this.loadMapSummary(preset, {
524
+ where,
525
+ replacements
526
+ })
527
+ }
528
+ else{
529
+ derivedSql = derivedSql.replace('Executing (default): ', '').replace('LIMIT ' + (this.itemsPerPage + 1), '').slice(0, -1)
530
+ summary = await this.loadSummary(preset, {
531
+ where,
532
+ replacements
533
+ }, derivedSql)
534
+ }
535
+ }*/
536
+
537
+ if(this.socket){
538
+ this.socket.joinWithArgs(this.channel, { preset })
539
+ }
540
+
541
+ return {
542
+ items,
543
+ hasNext,
544
+ count,
545
+ derivedSql,
546
+ where,
547
+ replacements
548
+ }
549
+ },
550
+
551
+ async loadBarSummary(summary, derivedSql){
552
+
553
+ if(!summary.bar) return
554
+
555
+ const { columns, rows, values } = summary.bar
556
+
557
+ if(!Array.isArray(columns) || columns.length !== 1 || !columns[0].key) return
558
+ if(!Array.isArray(rows) || rows.length !== 1 || !rows[0].key) return
559
+ if(!Array.isArray(values) || values.length !== 1 || !values[0].aggregrate) return
560
+
561
+ const col = columns[0]
562
+ let columnValues = []
563
+ let colKey
564
+ if(col.key !== '(none)'){
565
+ colKey = col.key
566
+ const [ _columnValues ] = await this.conn.query(`
567
+ SELECT
568
+ DISTINCT(${colKey}) AS cols
569
+ FROM (${derivedSql}) AS derived
570
+ ORDER BY cols ASC
571
+ `)
572
+
573
+ columnValues = _columnValues
574
+ }
575
+ if(columnValues.length > 100){
576
+ throw new Error('Too many columns')
577
+ }
578
+
579
+ const attributes = []
580
+ const group = []
581
+ const summaryColumns = [
582
+ /*{ key:"dfDate", label:"Date", width:"200px", visible:true },
583
+ { key:"type-1", label:"Type 1", type:"number", visible:true },
584
+ { key:"type-2", label:"Type 2", type:"number", visible:true },
585
+ { key:"type-3", label:"Type 3", type:"number", visible:true },
586
+ { key:"type-4", label:"Type 4", type:"number", visible:true },
587
+ { key:"type-8", label:"Type 8", type:"number", visible:true },*/
588
+ ]
589
+
590
+ const row = rows[0]
591
+ const rowKey = row.key
592
+ const rowLabel = this.columns[row.key].label
593
+ switch(row.format){
594
+ case 'date':
595
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d') as dfDate`)
596
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d')`)
597
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"D MMM" })
598
+ break
599
+
600
+ case 'month':
601
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m') as dfDate`)
602
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m')`)
603
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
604
+ break
605
+
606
+ case 'quarter':
607
+ attributes.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey})) as dfDate`)
608
+ group.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey}))`)
609
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
610
+ break
611
+
612
+ case 'year':
613
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y') as dfDate`)
614
+ group.push(`DATE_FORMAT(${rowKey}, '%Y')`)
615
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"YYYY" })
616
+ break
617
+
618
+ default:
619
+ attributes.push(`${rowKey} as dfDate`)
620
+ group.push(`${rowKey}`)
621
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true })
622
+ break
623
+ }
624
+
625
+ const value = values[0]
626
+ if(columnValues.length > 0){
627
+ columnValues.forEach((obj) => {
628
+ const columnValue = obj.cols
629
+
630
+ let columnLabel = (columnValue ?? '').toString()
631
+ const baseColumn = this.columns[colKey]
632
+ switch(baseColumn.type){
633
+
634
+ case 'enum':
635
+ const enumValue = baseColumn.typeParams.filter((_) => _.value === columnValue).pop()
636
+ if(enumValue) columnLabel = enumValue.text
637
+ break
638
+ }
639
+
640
+ switch(value.aggregrate){
641
+ case 'count':
642
+ const fn = columnValue === null ? `${colKey} is null` : `${colKey} = '${columnValue}'`
643
+ attributes.push(`SUM(IF(${fn}, 1, 0)) as \`${colKey}-${columnValue}\``)
644
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
645
+ break
646
+
647
+ case 'min':
648
+ attributes.push(`MIN(${colKey}) as \`${colKey}-${columnValue}\``)
649
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
650
+ break
651
+
652
+ case 'max':
653
+ attributes.push(`MAX(${colKey}) as \`${colKey}-${columnValue}\``)
654
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
655
+ break
656
+
657
+ case 'avg':
658
+ attributes.push(`AVG(${colKey}) as \`${colKey}-${columnValue}\``)
659
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
660
+ break
661
+ }
662
+ })
663
+ }
664
+ else{
665
+ switch(value.aggregrate) {
666
+ case 'count':
667
+ default:
668
+ attributes.push(`COUNT(*) as \`Count\``)
669
+ summaryColumns.push({ key:'Count', label:'Count', type:"number", visible:true, aggregrate:"count" })
670
+ }
671
+ }
672
+
673
+ let [ summaryItems ] = await this.conn.query(`
674
+ SELECT
675
+ ${attributes.join(', ')}
676
+ FROM (
677
+ ${derivedSql}
678
+ ) as t1
679
+ GROUP BY ${group[0]}
680
+ ORDER BY dfDate ASC
681
+ `)
682
+
683
+ if(this.columns[rowKey] && this.columns[rowKey].type === 'enum'){
684
+ summaryItems = summaryItems.map((_) => {
685
+
686
+ const typeParam = this.columns[rowKey].typeParams.filter((__) => __.value === _.dfDate).pop()
687
+ if(typeParam){
688
+ _.dfDate = typeParam.text
689
+ }
690
+
691
+ return _
692
+ })
693
+ }
694
+
695
+ const result = {
696
+ mode: "bar",
697
+ columns: summaryColumns,
698
+ items: summaryItems
699
+ /*items: [
700
+ { date:"21 Jan 23", "type-1":12, "type-2":11, "type-3":16, "type-4":2, "type-8":8 },
701
+ { date:"22 Jan 23", "type-1":51, "type-2":87, "type-3":86, "type-4":3, "type-8":9 },
702
+ { date:"23 Jan 23", "type-1":14, "type-2":66, "type-3":77, "type-4":4, "type-8":18 },
703
+ { date:"24 Jan 23", "type-1":7, "type-2":3, "type-3":63, "type-4":5, "type-8":28 },
704
+ { date:"25 Jan 23", "type-1":88, "type-2":55, "type-3":68, "type-4":6, "type-8":38 },
705
+ { date:"26 Jan 23", "type-1":172, "type-2":13, "type-3":6, "type-4":7, "type-8":48 }
706
+ ]*/
707
+ }
708
+
709
+ return result
710
+ },
711
+
712
+ async loadLineSummary(summary, derivedSql){
713
+
714
+ if(!summary.line) return
715
+
716
+ const { columns, rows, values } = summary.line
717
+
718
+ if(!Array.isArray(columns) || columns.length !== 1 || !columns[0].key) return
719
+ if(!Array.isArray(rows) || rows.length !== 1 || !rows[0].key) return
720
+ if(!Array.isArray(values) || values.length !== 1 || !values[0].aggregrate) return
721
+
722
+ const col = columns[0]
723
+ let columnValues = []
724
+ let colKey
725
+ if(col.key !== '(none)'){
726
+ colKey = col.key
727
+ const [ _columnValues ] = await this.conn.query(`
728
+ SELECT
729
+ DISTINCT(${colKey}) AS cols
730
+ FROM (${derivedSql}) AS derived
731
+ ORDER BY cols ASC
732
+ `)
733
+
734
+ columnValues = _columnValues
735
+ }
736
+ if(columnValues.length > 100){
737
+ throw new Error('Too many columns')
738
+ }
739
+
740
+ const attributes = []
741
+ const group = []
742
+ const summaryColumns = [
743
+ /*{ key:"dfDate", label:"Date", width:"200px", visible:true },
744
+ { key:"type-1", label:"Type 1", type:"number", visible:true },
745
+ { key:"type-2", label:"Type 2", type:"number", visible:true },
746
+ { key:"type-3", label:"Type 3", type:"number", visible:true },
747
+ { key:"type-4", label:"Type 4", type:"number", visible:true },
748
+ { key:"type-8", label:"Type 8", type:"number", visible:true },*/
749
+ ]
750
+
751
+ const row = rows[0]
752
+ const rowKey = row.key
753
+ const rowLabel = this.columns[row.key].label
754
+ switch(row.format){
755
+ case 'date':
756
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d') as dfDate`)
757
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d')`)
758
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"D MMM" })
759
+ break
760
+
761
+ case 'month':
762
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m') as dfDate`)
763
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m')`)
764
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
765
+ break
766
+
767
+ case 'quarter':
768
+ attributes.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey})) as dfDate`)
769
+ group.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey}))`)
770
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
771
+ break
772
+
773
+ case 'year':
774
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y') as dfDate`)
775
+ group.push(`DATE_FORMAT(${rowKey}, '%Y')`)
776
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"YYYY" })
777
+ break
778
+
779
+ default:
780
+ attributes.push(`${rowKey} as dfDate`)
781
+ group.push(`${rowKey}`)
782
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true })
783
+ break
784
+ }
785
+
786
+ const value = values[0]
787
+ if(columnValues.length > 0){
788
+ columnValues.forEach((obj) => {
789
+ const columnValue = obj.cols
790
+
791
+ let columnLabel = (columnValue ?? '').toString()
792
+ const baseColumn = this.columns[colKey]
793
+ switch(baseColumn.type){
794
+
795
+ case 'enum':
796
+ const enumValue = baseColumn.typeParams.filter((_) => _.value === columnValue).pop()
797
+ if(enumValue) columnLabel = enumValue.text
798
+ break
799
+ }
800
+
801
+ switch(value.aggregrate){
802
+ case 'count':
803
+ const fn = columnValue === null ? `${colKey} is null` : `${colKey} = '${columnValue}'`
804
+ attributes.push(`SUM(IF(${fn}, 1, 0)) as \`${colKey}-${columnValue}\``)
805
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
806
+ break
807
+
808
+ case 'min':
809
+ attributes.push(`MIN(${colKey}) as \`${colKey}-${columnValue}\``)
810
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
811
+ break
812
+
813
+ case 'max':
814
+ attributes.push(`MAX(${colKey}) as \`${colKey}-${columnValue}\``)
815
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
816
+ break
817
+
818
+ case 'avg':
819
+ attributes.push(`AVG(${colKey}) as \`${colKey}-${columnValue}\``)
820
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
821
+ break
822
+ }
823
+ })
824
+ }
825
+ else{
826
+ switch(value.aggregrate) {
827
+ case 'count':
828
+ default:
829
+ attributes.push(`COUNT(*) as \`Count\``)
830
+ summaryColumns.push({ key:'Count', label:'Count', type:"number", visible:true, aggregrate:"count" })
831
+ }
832
+ }
833
+
834
+ let [ summaryItems ] = await this.conn.query(`
835
+ SELECT
836
+ ${attributes.join(', ')}
837
+ FROM (
838
+ ${derivedSql}
839
+ ) as t1
840
+ GROUP BY ${group[0]}
841
+ ORDER BY dfDate ASC
842
+ `)
843
+
844
+ if(this.columns[rowKey] && this.columns[rowKey].type === 'enum'){
845
+ summaryItems = summaryItems.map((_) => {
846
+
847
+ const typeParam = this.columns[rowKey].typeParams.filter((__) => __.value === _.dfDate).pop()
848
+ if(typeParam){
849
+ _.dfDate = typeParam.text
850
+ }
851
+
852
+ return _
853
+ })
854
+ }
855
+
856
+ const result = {
857
+ mode: "line",
858
+ columns: summaryColumns,
859
+ items: summaryItems
860
+ /*items: [
861
+ { date:"21 Jan 23", "type-1":12, "type-2":11, "type-3":16, "type-4":2, "type-8":8 },
862
+ { date:"22 Jan 23", "type-1":51, "type-2":87, "type-3":86, "type-4":3, "type-8":9 },
863
+ { date:"23 Jan 23", "type-1":14, "type-2":66, "type-3":77, "type-4":4, "type-8":18 },
864
+ { date:"24 Jan 23", "type-1":7, "type-2":3, "type-3":63, "type-4":5, "type-8":28 },
865
+ { date:"25 Jan 23", "type-1":88, "type-2":55, "type-3":68, "type-4":6, "type-8":38 },
866
+ { date:"26 Jan 23", "type-1":172, "type-2":13, "type-3":6, "type-4":7, "type-8":48 }
867
+ ]*/
868
+ }
869
+
870
+ return result
871
+ },
872
+
873
+ async loadTableSummary(summary, derivedSql){
874
+
875
+ if(!summary.table) return
876
+
877
+ const { columns, rows, values } = summary.table
878
+
879
+ if(!Array.isArray(columns) || columns.length !== 1 || !columns[0].key) return
880
+ if(!Array.isArray(rows) || rows.length !== 1 || !rows[0].key) return
881
+ if(!Array.isArray(values) || values.length !== 1 || !values[0].aggregrate) return
882
+
883
+ const col = columns[0]
884
+ let columnValues = []
885
+ let colKey
886
+ if(col.key !== '(none)'){
887
+ colKey = col.key
888
+ const [ _columnValues ] = await this.conn.query(`
889
+ SELECT
890
+ DISTINCT(${colKey}) AS cols
891
+ FROM (${derivedSql}) AS derived
892
+ ORDER BY cols ASC
893
+ `)
894
+
895
+ columnValues = _columnValues
896
+ }
897
+ if(columnValues.length > 100){
898
+ throw new Error('Too many columns')
899
+ }
900
+
901
+ const attributes = []
902
+ const group = []
903
+ const summaryColumns = [
904
+ /*{ key:"dfDate", label:"Date", width:"200px", visible:true },
905
+ { key:"type-1", label:"Type 1", type:"number", visible:true },
906
+ { key:"type-2", label:"Type 2", type:"number", visible:true },
907
+ { key:"type-3", label:"Type 3", type:"number", visible:true },
908
+ { key:"type-4", label:"Type 4", type:"number", visible:true },
909
+ { key:"type-8", label:"Type 8", type:"number", visible:true },*/
910
+ ]
911
+
912
+ const row = rows[0]
913
+ const rowKey = row.key
914
+ const rowLabel = this.columns[row.key].label
915
+ switch(row.format){
916
+ case 'date':
917
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d') as dfDate`)
918
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m-%d')`)
919
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"D MMM" })
920
+ break
921
+
922
+ case 'month':
923
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y-%m') as dfDate`)
924
+ group.push(`DATE_FORMAT(${rowKey}, '%Y-%m')`)
925
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
926
+ break
927
+
928
+ case 'quarter':
929
+ attributes.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey})) as dfDate`)
930
+ group.push(`CONCAT(YEAR(${rowKey}), ' Q', QUARTER(${rowKey}))`)
931
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
932
+ break
933
+
934
+ case 'year':
935
+ attributes.push(`DATE_FORMAT(${rowKey}, '%Y') as dfDate`)
936
+ group.push(`DATE_FORMAT(${rowKey}, '%Y')`)
937
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"YYYY" })
938
+ break
939
+
940
+ default:
941
+ attributes.push(`${rowKey} as dfDate`)
942
+ group.push(`${rowKey}`)
943
+ summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true })
944
+ break
945
+ }
946
+
947
+ const value = values[0]
948
+ if(columnValues.length > 0){
949
+ columnValues.forEach((obj) => {
950
+ const columnValue = obj.cols
951
+
952
+ let columnLabel = (columnValue ?? '').toString()
953
+ const baseColumn = this.columns[colKey]
954
+ switch(baseColumn.type){
955
+
956
+ case 'enum':
957
+ const enumValue = baseColumn.typeParams.filter((_) => _.value === columnValue).pop()
958
+ if(enumValue) columnLabel = enumValue.text
959
+ break
960
+ }
961
+
962
+ switch(value.aggregrate){
963
+ case 'count':
964
+ const fn = columnValue === null ? `${colKey} is null` : `${colKey} = '${columnValue}'`
965
+ attributes.push(`SUM(IF(${fn}, 1, 0)) as \`${colKey}-${columnValue}\``)
966
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
967
+ break
968
+
969
+ case 'min':
970
+ attributes.push(`MIN(${colKey}) as \`${colKey}-${columnValue}\``)
971
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
972
+ break
973
+
974
+ case 'max':
975
+ attributes.push(`MAX(${colKey}) as \`${colKey}-${columnValue}\``)
976
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
977
+ break
978
+
979
+ case 'avg':
980
+ attributes.push(`AVG(${colKey}) as \`${colKey}-${columnValue}\``)
981
+ summaryColumns.push({ key:colKey + "-" + columnValue, label:columnLabel, visible:true, aggregrate:"count" })
982
+ break
983
+ }
984
+ })
985
+ }
986
+ else{
987
+ switch(value.aggregrate) {
988
+ case 'count':
989
+ default:
990
+ attributes.push(`COUNT(*) as \`Count\``)
991
+ summaryColumns.push({ key:'Count', label:'Count', type:"number", visible:true, aggregrate:"count" })
992
+ }
993
+ }
994
+
995
+ let [ summaryItems ] = await this.conn.query(`
996
+ SELECT
997
+ ${attributes.join(', ')}
998
+ FROM (
999
+ ${derivedSql}
1000
+ ) as t1
1001
+ GROUP BY ${group[0]}
1002
+ ORDER BY dfDate ASC
1003
+ `)
1004
+
1005
+ if(this.columns[rowKey] && this.columns[rowKey].type === 'enum'){
1006
+ summaryItems = summaryItems.map((_) => {
1007
+
1008
+ const typeParam = this.columns[rowKey].typeParams.filter((__) => __.value === _.dfDate).pop()
1009
+ if(typeParam){
1010
+ _.dfDate = typeParam.text
1011
+ }
1012
+
1013
+ return _
1014
+ })
1015
+ }
1016
+
1017
+ const result = {
1018
+ mode: "table",
1019
+ columns: summaryColumns,
1020
+ items: summaryItems
1021
+ /*items: [
1022
+ { date:"21 Jan 23", "type-1":12, "type-2":11, "type-3":16, "type-4":2, "type-8":8 },
1023
+ { date:"22 Jan 23", "type-1":51, "type-2":87, "type-3":86, "type-4":3, "type-8":9 },
1024
+ { date:"23 Jan 23", "type-1":14, "type-2":66, "type-3":77, "type-4":4, "type-8":18 },
1025
+ { date:"24 Jan 23", "type-1":7, "type-2":3, "type-3":63, "type-4":5, "type-8":28 },
1026
+ { date:"25 Jan 23", "type-1":88, "type-2":55, "type-3":68, "type-4":6, "type-8":38 },
1027
+ { date:"26 Jan 23", "type-1":172, "type-2":13, "type-3":6, "type-4":7, "type-8":48 }
1028
+ ]*/
1029
+ }
1030
+
1031
+ return result
1032
+ },
1033
+
1034
+
1035
+
1036
+ getPresetFilterParams(preset){
1037
+
1038
+ let where = {}
1039
+ let replacements = []
1040
+
1041
+ if(preset.filters){
1042
+
1043
+ //console.log(util.inspect(preset.filters, false, null, true /* enable colors */))
1044
+
1045
+ preset.filters.forEach((filter) => {
1046
+
1047
+ if(!filter.enabled) return
1048
+
1049
+ const key = filter.key
1050
+ const type = filter.type
1051
+ const operand = filter.operand === 'or' ? 'or' : 'and'
1052
+ const items = filter.filters ?? []
1053
+
1054
+ let whereValue = []
1055
+ switch(type){
1056
+
1057
+ case 'date':
1058
+ items.forEach((item) => {
1059
+ if(!('operator' in item) || (item.operator === 'between' && !('value' in item))) return
1060
+
1061
+ const operator = item.operator
1062
+ const value = item.value
1063
+
1064
+ switch(operator){
1065
+
1066
+ case 'today':
1067
+ whereValue = {
1068
+ ...whereValue,
1069
+ [Op.eq]: dayjs().format('YYYY-MM-DD'),
1070
+ }
1071
+ break
1072
+
1073
+ case 'thisWeek':
1074
+ whereValue = {
1075
+ ...whereValue,
1076
+ [Op.gte]: dayjs().startOf('week').format('YYYY-MM-DD 00:00:00'),
1077
+ [Op.lt]: dayjs().endOf('week').format('YYYY-MM-DD 23:59:59'),
1078
+ }
1079
+ break
1080
+
1081
+ case 'weekAgo':
1082
+ whereValue = {
1083
+ ...whereValue,
1084
+ [Op.gte]: dayjs().add(-1, 'week').format('YYYY-MM-DD 00:00:00'),
1085
+ [Op.lt]: dayjs().format('YYYY-MM-DD 23:59:59'),
1086
+ }
1087
+ break
1088
+
1089
+ case 'thisMonth':
1090
+ whereValue = {
1091
+ ...whereValue,
1092
+ [Op.gte]: dayjs().format('YYYY-MM-01 00:00:00'),
1093
+ [Op.lt]: dayjs().endOf('month').format('YYYY-MM-DD 23:59:59'),
1094
+ }
1095
+ break
1096
+
1097
+ case 'monthAgo':
1098
+ whereValue = {
1099
+ ...whereValue,
1100
+ [Op.gte]: dayjs().add(-1, 'month').format('YYYY-MM-DD 00:00:00'),
1101
+ [Op.lt]: dayjs().format('YYYY-MM-DD 23:59:59'),
1102
+ }
1103
+ break
1104
+
1105
+ case 'lastMonth':
1106
+ whereValue = {
1107
+ [Op.gte]: dayjs().add(-1, 'month').format('YYYY-MM-01 00:00:00'),
1108
+ [Op.lte]: dayjs().add(-1, 'month').endOf('month').format('YYYY-MM-DD 23:59:59'),
1109
+ }
1110
+ break
1111
+
1112
+ case 'thisYear':
1113
+ whereValue = {
1114
+ ...whereValue,
1115
+ [Op.gte]: dayjs().startOf('year').format('YYYY-MM-DD 00:00:00'),
1116
+ [Op.lt]: dayjs().endOf('year').format('YYYY-MM-DD 23:59:59'),
1117
+ }
1118
+ break
1119
+
1120
+ case 'lastYear':
1121
+ whereValue = {
1122
+ ...whereValue,
1123
+ [Op.gte]: dayjs().add(-1, 'year').startOf('year').format('YYYY-MM-DD 00:00:00'),
1124
+ [Op.lt]: dayjs().add(-1, 'year').endOf('year').format('YYYY-MM-DD 23:59:59'),
1125
+ }
1126
+ break
1127
+
1128
+ case 'between':
1129
+ whereValue = {
1130
+ ...whereValue,
1131
+ [Op.gte]: dayjs(value[0]).format('YYYY-MM-DD 00:00:00'),
1132
+ [Op.lt]: dayjs(value[1]).format('YYYY-MM-DD 23:59:59'),
1133
+ }
1134
+ break
1135
+ }
1136
+ })
1137
+ break
1138
+
1139
+ case 'enum':
1140
+ items.forEach((item) => {
1141
+ if(!('value' in item)) return
1142
+
1143
+ const value = item.value ?? []
1144
+ whereValue = {
1145
+ ...whereValue,
1146
+ [Op.in]: value
1147
+ }
1148
+ })
1149
+ break
1150
+
1151
+ case 'number':
1152
+ case 'currency':
1153
+ items.forEach((item) => {
1154
+ if(!('operator' in item) || !('value' in item)) return
1155
+
1156
+ const operator = item.operator
1157
+ const value = item.value
1158
+
1159
+ switch(operator){
1160
+
1161
+ case '>':
1162
+ whereValue = {
1163
+ ...whereValue,
1164
+ [Op.gt]: parseFloat(value)
1165
+ }
1166
+ break
1167
+
1168
+ case '>=':
1169
+ whereValue = {
1170
+ ...whereValue,
1171
+ [Op.gte]: parseFloat(value)
1172
+ }
1173
+ break
1174
+
1175
+ case '=':
1176
+ whereValue = {
1177
+ ...whereValue,
1178
+ [Op.eq]: parseFloat(value)
1179
+ }
1180
+ break
1181
+
1182
+ case '<':
1183
+ whereValue = {
1184
+ ...whereValue,
1185
+ [Op.lt]: parseFloat(value)
1186
+ }
1187
+ break
1188
+
1189
+ case '<=':
1190
+ whereValue = {
1191
+ ...whereValue,
1192
+ [Op.lte]: parseFloat(value)
1193
+ }
1194
+ break
1195
+ }
1196
+ })
1197
+ break
1198
+
1199
+ default:
1200
+ items.forEach((item) => {
1201
+ if(!('operator' in item) ||
1202
+ ([ 'startsWith', 'endsWith', 'contains', '=' ].includes(item.operator) && !'value' in item))
1203
+ return
1204
+
1205
+ const operator = item.operator
1206
+ const value = item.value
1207
+
1208
+ switch(operator){
1209
+
1210
+ case 'startsWith':
1211
+ whereValue.push({
1212
+ [Op.like]: `${value}%`
1213
+ })
1214
+ break
1215
+
1216
+ case 'endsWith':
1217
+ whereValue.push({
1218
+ [Op.like]: `%${value}`
1219
+ })
1220
+ break
1221
+
1222
+ case 'contains':
1223
+ whereValue.push({
1224
+ [Op.like]: `%${value}%`
1225
+ })
1226
+ break
1227
+
1228
+ case '=':
1229
+ whereValue.push({
1230
+ [Op.eq]: value
1231
+ })
1232
+ break
1233
+
1234
+ case 'empty':
1235
+ whereValue.push({
1236
+ [Op.or]: [
1237
+ { [Op.eq]: null },
1238
+ { [Op.eq]: '' },
1239
+ ]
1240
+ })
1241
+ break
1242
+
1243
+ case 'notEmpty':
1244
+ whereValue.push({
1245
+ [Op.and]: [
1246
+ { [Op.ne]: null },
1247
+ { [Op.ne]: '' },
1248
+ ]
1249
+ })
1250
+ break
1251
+
1252
+ case 'length':
1253
+ break
1254
+
1255
+ case 'regex':
1256
+ whereValue.push({
1257
+ [Op.regexp]: value
1258
+ })
1259
+ break
1260
+ }
1261
+ })
1262
+ break
1263
+ }
1264
+
1265
+ switch(operand){
1266
+
1267
+ case 'or':
1268
+ where = {
1269
+ ...where,
1270
+ [key]: {
1271
+ [Op.or]: whereValue
1272
+ }
1273
+ }
1274
+ break
1275
+
1276
+ default:
1277
+ where = {
1278
+ ...where,
1279
+ [key]: {
1280
+ [Op.and]: whereValue
1281
+ }
1282
+ }
1283
+ break
1284
+ }
1285
+ })
1286
+ }
1287
+
1288
+ //console.log(util.inspect(where, false, null, true /* enable colors */))
1289
+
1290
+ /*console.log(util.inspect(preset.filters, false, null, true /!* enable colors *!/))
1291
+ console.log(where)
1292
+ console.log(replacements)*/
1293
+
1294
+ return {
1295
+ where,
1296
+ replacements
1297
+ }
1298
+ },
1299
+
1300
+ getPresetSortParams(preset){
1301
+
1302
+ if(preset.sorts && preset.sorts.length > 0){
1303
+ let order = []
1304
+ preset.sorts.forEach((sort) => {
1305
+ const key = sort.key
1306
+ const type = sort.type === 'desc' ? 'desc' : 'asc'
1307
+ order.push([ key, type ])
1308
+ })
1309
+ order.push([ 'id', 'desc' ])
1310
+
1311
+ return {
1312
+ order
1313
+ }
1314
+ }
1315
+ return {}
1316
+ },
1317
+
1318
+ getPresetSortWhereParams(order, afterItem){
1319
+
1320
+ if(order.filter((_) => _[0] === 'id').length <= 0){
1321
+ order.push([ 'id', 'desc' ])
1322
+ }
1323
+
1324
+ const opOr = []
1325
+ for(let i = 0 ; i < order.length ; i++){
1326
+
1327
+ const obj = order[i]
1328
+
1329
+ const exp = {}
1330
+ for(let j = 0 ; j < i ; j++){
1331
+ exp[order[j][0]] = afterItem[order[j][0]]
1332
+ }
1333
+ exp[obj[0]] = obj[1] === 'desc' ? { [Op.lt]:afterItem[obj[0]] } : { [Op.gt]:afterItem[obj[0]] }
1334
+
1335
+ if(Object.keys(exp).length === 1){
1336
+ opOr.push(exp)
1337
+ }
1338
+ else{
1339
+ opOr.push({
1340
+ [Op.and]: exp
1341
+ })
1342
+ }
1343
+ }
1344
+
1345
+ let sortWhere = {}
1346
+ if(opOr.length > 0){
1347
+ sortWhere = {
1348
+ [Op.or]: opOr
1349
+ }
1350
+ }
1351
+ return sortWhere
1352
+ },
1353
+
1354
+
1355
+
1356
+ async onHooks(model, event, items, socket){
1357
+
1358
+ switch(event){
1359
+ case 'destroy':
1360
+ case 'remove':
1361
+ default:
1362
+ socket.emit(model, event, items)
1363
+ break
1364
+ }
1365
+ }
1366
+
1367
+
1368
+
1369
+ }
1370
+
1371
+ module.exports = ListPage1