@mixd-id/web-scaffold 0.1.230406290 → 0.1.230406292
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/Button.vue +5 -5
- package/src/components/Image.vue +1 -1
- package/src/components/List.vue +13 -5
- package/src/components/VirtualTable.vue +115 -5
- package/src/index.js +2 -1
- package/src/mixin/component.js +4 -1
- package/src/utils/preset-selector.js +9 -8
- package/src/utils/preset-selector.mjs +3 -0
- package/src/widgets/ColumnSelector.vue +3 -7
- package/src/widgets/PresetBar.vue +36 -11
- package/src/widgets/PresetBarPivotColumnEdit.vue +176 -0
package/package.json
CHANGED
|
@@ -146,7 +146,7 @@ export default{
|
|
|
146
146
|
@apply flex items-center justify-center
|
|
147
147
|
}
|
|
148
148
|
.button:disabled{
|
|
149
|
-
|
|
149
|
+
@apply text-opacity-50;
|
|
150
150
|
}
|
|
151
151
|
.button:active{
|
|
152
152
|
@apply top-[1px] left-[1px] relative;
|
|
@@ -164,7 +164,7 @@ export default{
|
|
|
164
164
|
@apply bg-primary-600;
|
|
165
165
|
}
|
|
166
166
|
.button-primary:disabled{
|
|
167
|
-
@apply bg-primary-500
|
|
167
|
+
@apply bg-primary-500 top-0 left-0 cursor-not-allowed;
|
|
168
168
|
@apply top-0 left-0;
|
|
169
169
|
}
|
|
170
170
|
.button-primary *{
|
|
@@ -188,7 +188,7 @@ export default{
|
|
|
188
188
|
.button-outline:hover{
|
|
189
189
|
}
|
|
190
190
|
.button-outline:disabled{
|
|
191
|
-
@apply
|
|
191
|
+
@apply top-0 left-0 cursor-not-allowed;
|
|
192
192
|
@apply text-text border-primary-500;
|
|
193
193
|
}
|
|
194
194
|
.button-outline *{
|
|
@@ -214,7 +214,7 @@ export default{
|
|
|
214
214
|
@apply bg-primary-200 border-primary-200;
|
|
215
215
|
}
|
|
216
216
|
.button-secondary:disabled{
|
|
217
|
-
@apply bg-primary-100
|
|
217
|
+
@apply bg-primary-100 top-0 left-0 cursor-not-allowed;
|
|
218
218
|
}
|
|
219
219
|
.button-secondary *{
|
|
220
220
|
@apply text-text-500 fill-white;
|
|
@@ -238,7 +238,7 @@ export default{
|
|
|
238
238
|
@apply bg-red-600 border-red-600;
|
|
239
239
|
}
|
|
240
240
|
.button-red:disabled{
|
|
241
|
-
@apply bg-red-500 border-red-500
|
|
241
|
+
@apply bg-red-500 border-red-500 top-0 left-0 cursor-not-allowed;
|
|
242
242
|
}
|
|
243
243
|
.button-red *{
|
|
244
244
|
@apply text-white fill-white;
|
package/src/components/Image.vue
CHANGED
package/src/components/List.vue
CHANGED
|
@@ -120,7 +120,11 @@
|
|
|
120
120
|
</div>
|
|
121
121
|
</slot>
|
|
122
122
|
|
|
123
|
-
<
|
|
123
|
+
<div v-if="readyState === 3" class="flex-1 flex items-center justify-center">
|
|
124
|
+
<svg class="animate-spin" width="36" height="36" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<VirtualTable v-else-if="presetView === 'table' || pivotEnabled"
|
|
124
128
|
ref="table"
|
|
125
129
|
:columns="columns"
|
|
126
130
|
class="flex-1 rounded-lg panel-400"
|
|
@@ -310,6 +314,7 @@ export default{
|
|
|
310
314
|
this.preset.columns = JSON.parse(JSON.stringify(this.config.columns))
|
|
311
315
|
}
|
|
312
316
|
|
|
317
|
+
this.readyState = 3
|
|
313
318
|
return this.socket.send(this.src, {
|
|
314
319
|
...this.preset,
|
|
315
320
|
itemsPerPage: this.data.itemsPerPage,
|
|
@@ -325,6 +330,7 @@ export default{
|
|
|
325
330
|
.catch(err => {
|
|
326
331
|
this.toast(err)
|
|
327
332
|
})
|
|
333
|
+
.finally(_ => this.readyState = 1)
|
|
328
334
|
}
|
|
329
335
|
return new Promise(resolve => resolve())
|
|
330
336
|
},
|
|
@@ -399,7 +405,7 @@ export default{
|
|
|
399
405
|
|
|
400
406
|
const reqItems = Object.values(this.enumCache[column.key]).filter(_ => !_.text).map(_ => _.value)
|
|
401
407
|
|
|
402
|
-
if(reqItems.length > 0){
|
|
408
|
+
if(reqItems.length > 0 && reqItems !== this.lastEnumItems){
|
|
403
409
|
|
|
404
410
|
const [ src, key, attr ] = column.enumSrc.split(':')
|
|
405
411
|
this.socket.send(src, {
|
|
@@ -425,6 +431,8 @@ export default{
|
|
|
425
431
|
if(!this.enumCache[column.key][key].text)
|
|
426
432
|
this.enumCache[column.key][key].text = key
|
|
427
433
|
}
|
|
434
|
+
|
|
435
|
+
this.lastEnumItems = reqItems
|
|
428
436
|
})
|
|
429
437
|
.catch(err => this.log('Load enums error', err))
|
|
430
438
|
}
|
|
@@ -581,7 +589,7 @@ export default{
|
|
|
581
589
|
let [ kk, ...vv ] = column.key.split('-')
|
|
582
590
|
vv = vv.join('-')
|
|
583
591
|
|
|
584
|
-
if(![ 'count' ].includes(vv)){
|
|
592
|
+
if(![ 'count', 'countDistinct' ].includes(vv)){
|
|
585
593
|
|
|
586
594
|
const key = kk.substring(1)
|
|
587
595
|
const presetColumn = this.preset.columns.find(_ => _.key === key)
|
|
@@ -627,7 +635,7 @@ export default{
|
|
|
627
635
|
switch(e.code){
|
|
628
636
|
|
|
629
637
|
case 'Backquote':
|
|
630
|
-
this
|
|
638
|
+
this.togglePreset()
|
|
631
639
|
break
|
|
632
640
|
|
|
633
641
|
default:
|
|
@@ -824,6 +832,7 @@ export default{
|
|
|
824
832
|
compPrefix: '',
|
|
825
833
|
enumCache: {},
|
|
826
834
|
extItems: null,
|
|
835
|
+
lastEnumItems: null,
|
|
827
836
|
}
|
|
828
837
|
},
|
|
829
838
|
|
|
@@ -850,7 +859,6 @@ export default{
|
|
|
850
859
|
|
|
851
860
|
.resize2{
|
|
852
861
|
@apply h-[5px] hover:bg-primary bg-text-50 cursor-n-resize absolute top-0 left-0 right-0 flex items-center justify-center;
|
|
853
|
-
@apply z-20;
|
|
854
862
|
}
|
|
855
863
|
|
|
856
864
|
.extClose{
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
<table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
|
|
5
5
|
<thead>
|
|
6
6
|
<tr>
|
|
7
|
-
<th v-for="column in visibleColumns" :style="thStyle(column)"
|
|
7
|
+
<th v-for="column in visibleColumns" :style="thStyle(column)"
|
|
8
|
+
v-tooltip="`${column.label ? column.label : column.key}`">
|
|
8
9
|
<slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
|
|
9
10
|
<div v-else :class="headerColumnClass(column)">
|
|
10
|
-
<span>{{ column.label2 ? column.label2 : (column.label
|
|
11
|
+
<span>{{ column.label2 ? column.label2 : (column.label ?? column.key) }}</span>
|
|
11
12
|
</div>
|
|
12
13
|
<div :class="$style.separator" @mousedown="startResize($event, column)"></div>
|
|
13
14
|
</th>
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
@click="$emit('item-click', item, column)">
|
|
40
41
|
<slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
41
42
|
<slot v-else-if="$slots.default" name="default" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
42
|
-
<div v-else :class="columnClass(column)" v-html="formatColumn(item, column)"></div>
|
|
43
|
+
<div v-else :class="columnClass(column, item)" v-html="formatColumn(item, column)"></div>
|
|
43
44
|
</td>
|
|
44
45
|
<td :class="$style.spacer"></td>
|
|
45
46
|
</tr>
|
|
@@ -322,7 +323,7 @@ export default{
|
|
|
322
323
|
window.addEventListener('mouseup', onMouseUp)
|
|
323
324
|
},
|
|
324
325
|
|
|
325
|
-
columnClass(column){
|
|
326
|
+
columnClass(column, item){
|
|
326
327
|
|
|
327
328
|
let align
|
|
328
329
|
if(!column.align){
|
|
@@ -333,9 +334,118 @@ export default{
|
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
336
|
|
|
337
|
+
let appearanceClass = ''
|
|
338
|
+
if(item && Array.isArray(column.appearances)){
|
|
339
|
+
|
|
340
|
+
let value
|
|
341
|
+
switch(column.type){
|
|
342
|
+
|
|
343
|
+
case 'number':
|
|
344
|
+
value = parseInt(item[column.key])
|
|
345
|
+
break
|
|
346
|
+
|
|
347
|
+
default:
|
|
348
|
+
value = (item[column.key] ?? '').toString()
|
|
349
|
+
break
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for(let appearance of column.appearances){
|
|
353
|
+
|
|
354
|
+
let conditionMatched = false
|
|
355
|
+
for(let condition of appearance.conditions ?? []){
|
|
356
|
+
switch(condition.operator){
|
|
357
|
+
|
|
358
|
+
case '>':
|
|
359
|
+
if(value > condition.value){
|
|
360
|
+
conditionMatched = true
|
|
361
|
+
}
|
|
362
|
+
break
|
|
363
|
+
|
|
364
|
+
case '>=':
|
|
365
|
+
if(value >= condition.value){
|
|
366
|
+
conditionMatched = true
|
|
367
|
+
}
|
|
368
|
+
break
|
|
369
|
+
|
|
370
|
+
case '=':
|
|
371
|
+
if(value === condition.value){
|
|
372
|
+
conditionMatched = true
|
|
373
|
+
}
|
|
374
|
+
break
|
|
375
|
+
|
|
376
|
+
case '<':
|
|
377
|
+
if(value < condition.value){
|
|
378
|
+
conditionMatched = true
|
|
379
|
+
}
|
|
380
|
+
break
|
|
381
|
+
|
|
382
|
+
case '<=':
|
|
383
|
+
if(value <= condition.value){
|
|
384
|
+
conditionMatched = true
|
|
385
|
+
}
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
case 'startsWith':
|
|
389
|
+
if(value.startsWith(condition.value)){
|
|
390
|
+
conditionMatched = true
|
|
391
|
+
}
|
|
392
|
+
break
|
|
393
|
+
|
|
394
|
+
case 'notStartsWith':
|
|
395
|
+
if(!value.startsWith(condition.value)){
|
|
396
|
+
conditionMatched = true
|
|
397
|
+
}
|
|
398
|
+
break
|
|
399
|
+
|
|
400
|
+
case 'contains':
|
|
401
|
+
if(value.indexOf(condition.value) >= 0){
|
|
402
|
+
conditionMatched = true
|
|
403
|
+
}
|
|
404
|
+
break
|
|
405
|
+
|
|
406
|
+
case 'notContains':
|
|
407
|
+
if(value.indexOf(condition.value) < 0){
|
|
408
|
+
conditionMatched = true
|
|
409
|
+
}
|
|
410
|
+
break
|
|
411
|
+
|
|
412
|
+
case 'endsWith':
|
|
413
|
+
if(value.endsWith(condition.value)){
|
|
414
|
+
conditionMatched = true
|
|
415
|
+
}
|
|
416
|
+
break
|
|
417
|
+
|
|
418
|
+
case 'notEndsWith':
|
|
419
|
+
if(!value.endsWith(condition.value)){
|
|
420
|
+
conditionMatched = true
|
|
421
|
+
}
|
|
422
|
+
break
|
|
423
|
+
|
|
424
|
+
case 'none':
|
|
425
|
+
conditionMatched = true
|
|
426
|
+
break
|
|
427
|
+
|
|
428
|
+
case 'regex':
|
|
429
|
+
break
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if(conditionMatched) break
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
console.log('value', value, conditionMatched)
|
|
437
|
+
|
|
438
|
+
if(conditionMatched){
|
|
439
|
+
appearanceClass = appearance.class
|
|
440
|
+
break
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
336
445
|
return [
|
|
337
446
|
this.$style.tdDiv,
|
|
338
|
-
this.$style['align-' + align]
|
|
447
|
+
this.$style['align-' + align],
|
|
448
|
+
appearanceClass
|
|
339
449
|
]
|
|
340
450
|
.join(' ')
|
|
341
451
|
},
|
package/src/index.js
CHANGED
|
@@ -332,7 +332,7 @@ export default{
|
|
|
332
332
|
tooltip.classList.add('active')
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
-
},
|
|
335
|
+
}, 1000)
|
|
336
336
|
el.setAttribute('data-tooltip-open', true)
|
|
337
337
|
})
|
|
338
338
|
|
|
@@ -565,6 +565,7 @@ export default{
|
|
|
565
565
|
app.component('SvgSetting', defineAsyncComponent(() => import("./widgets/SvgSetting.vue")))
|
|
566
566
|
app.component('PresetBar', defineAsyncComponent(() => import("./widgets/PresetBar.vue")))
|
|
567
567
|
app.component('PresetSelector', defineAsyncComponent(() => import("./widgets/PresetSelector.vue")))
|
|
568
|
+
app.component('PresetBarPivotColumnEdit', defineAsyncComponent(() => import("./widgets/PresetBarPivotColumnEdit.vue")))
|
|
568
569
|
app.component('LogViewer', defineAsyncComponent(() => import("./widgets/LogViewer.vue")))
|
|
569
570
|
app.component('ColumnSelector', defineAsyncComponent(() => import("./widgets/ColumnSelector.vue")))
|
|
570
571
|
},
|
package/src/mixin/component.js
CHANGED
|
@@ -737,33 +737,34 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
737
737
|
|
|
738
738
|
const sortKeyToOrders = {} // Helper to determine group ordering
|
|
739
739
|
for(let value of pivot.values){
|
|
740
|
+
const valueKey = model.rawAttributes[value.key].field
|
|
740
741
|
|
|
741
742
|
switch(value.aggregrate){
|
|
742
743
|
|
|
743
744
|
case 'sum':
|
|
744
|
-
attributes.push([ fn('SUM', literal(`${model.name}.${
|
|
745
|
+
attributes.push([ fn('SUM', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
745
746
|
break
|
|
746
747
|
|
|
747
748
|
case 'avg':
|
|
748
|
-
attributes.push([ fn('AVG', literal(`${model.name}.${
|
|
749
|
+
attributes.push([ fn('AVG', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
749
750
|
break
|
|
750
751
|
|
|
751
752
|
case 'min':
|
|
752
|
-
attributes.push([ fn('MIN', literal(`${model.name}.${
|
|
753
|
+
attributes.push([ fn('MIN', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
753
754
|
break
|
|
754
755
|
|
|
755
756
|
case 'max':
|
|
756
|
-
attributes.push([ fn('MAX', literal(`${model.name}.${
|
|
757
|
+
attributes.push([ fn('MAX', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
757
758
|
break
|
|
758
759
|
|
|
759
760
|
case 'countDistinct':
|
|
760
|
-
attributes.push([ literal(`COUNT(DISTINCT ${model.name}.${
|
|
761
|
-
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = literal(`COUNT(DISTINCT ${model.name}.${
|
|
761
|
+
attributes.push([ literal(`COUNT(DISTINCT ${model.name}.${valueKey})`), `_${value.key}-${value.aggregrate}` ])
|
|
762
|
+
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = literal(`COUNT(DISTINCT ${model.name}.${valueKey})`)
|
|
762
763
|
break
|
|
763
764
|
|
|
764
765
|
case 'count':
|
|
765
|
-
attributes.push([ fn('COUNT', literal(`${model.name}.${
|
|
766
|
-
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = fn('COUNT', literal(`${model.name}.${
|
|
766
|
+
attributes.push([ fn('COUNT', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
767
|
+
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = fn('COUNT', literal(`${model.name}.${valueKey}`))
|
|
767
768
|
break
|
|
768
769
|
|
|
769
770
|
default:
|
|
@@ -139,6 +139,9 @@ const generatePivotColumns = (preset, items) => {
|
|
|
139
139
|
label,
|
|
140
140
|
label2: (((tableColumns[k1] ?? {}).label ?? '') + ': ' + label).trim(),
|
|
141
141
|
type: 'number',
|
|
142
|
+
appearances: [
|
|
143
|
+
{ class:"text-primary cursor-pointer", conditions:[ { operator:'none' } ] }
|
|
144
|
+
]
|
|
142
145
|
})
|
|
143
146
|
}
|
|
144
147
|
}
|
|
@@ -35,23 +35,19 @@ export default{
|
|
|
35
35
|
|
|
36
36
|
emits: [ 'select' ],
|
|
37
37
|
|
|
38
|
-
props: {
|
|
39
|
-
|
|
40
|
-
columns: Array,
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
|
|
44
38
|
data(){
|
|
45
39
|
return {
|
|
46
40
|
isOpen: false,
|
|
47
41
|
context: null,
|
|
42
|
+
columns: []
|
|
48
43
|
}
|
|
49
44
|
},
|
|
50
45
|
|
|
51
46
|
methods: {
|
|
52
47
|
|
|
53
|
-
open(context){
|
|
48
|
+
open(context, columns){
|
|
54
49
|
this.context = context
|
|
50
|
+
this.columns = columns
|
|
55
51
|
this.isOpen = true
|
|
56
52
|
},
|
|
57
53
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<div class="p-3">
|
|
17
|
-
<div class="
|
|
17
|
+
<div class="px-2">
|
|
18
18
|
<label class="text-text-300">Presets</label>
|
|
19
19
|
</div>
|
|
20
20
|
<div class="flex flex-col divide-y divide-text-50 bg-base-500 border-[1px] border-text-50 overflow-hidden rounded-lg">
|
|
@@ -95,7 +95,8 @@
|
|
|
95
95
|
body-class="divide-y divide-text-50 rounded-lg border-[1px] border-text-50 bg-base-300"
|
|
96
96
|
@reorder="(from, to) => { presetColumns.splice(to, 0, presetColumns.splice(from, 1)[0]); }">
|
|
97
97
|
<template v-slot="{ item }">
|
|
98
|
-
<div v-if="!item.key.startsWith('_') || (item.key.startsWith('_') && (preset.pivot && preset.pivot.enabled))"
|
|
98
|
+
<div v-if="!item.key.startsWith('_') || (item.key.startsWith('_') && (preset.pivot && preset.pivot.enabled))"
|
|
99
|
+
class="flex flex-row items-center gap-3 px-3 p-1 hover:bg-primary-100">
|
|
99
100
|
<div data-reorder>
|
|
100
101
|
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
101
102
|
</div>
|
|
@@ -103,7 +104,9 @@
|
|
|
103
104
|
<div>
|
|
104
105
|
<Checkbox v-model="item.visible" default="true" />
|
|
105
106
|
</div>
|
|
106
|
-
|
|
107
|
+
<Textbox v-model="item.label2" :placeholder="item.label"
|
|
108
|
+
class="border-none bg-transparent" :class="$style.columnTextbox"
|
|
109
|
+
item-class="p-1 px-0" />
|
|
107
110
|
</div>
|
|
108
111
|
</div>
|
|
109
112
|
</template>
|
|
@@ -174,7 +177,7 @@
|
|
|
174
177
|
|
|
175
178
|
<button type="button"
|
|
176
179
|
class="text-primary flex flex-row items-center justify-center p-3"
|
|
177
|
-
@click="$refs.columnSelector.open(addFilter)">
|
|
180
|
+
@click="$refs.columnSelector.open(addFilter, filterColumns)">
|
|
178
181
|
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
179
182
|
Add Filter
|
|
180
183
|
</button>
|
|
@@ -465,7 +468,7 @@
|
|
|
465
468
|
<div>
|
|
466
469
|
<div class="flex flex-row items-center gap-2">
|
|
467
470
|
<label>Groups</label>
|
|
468
|
-
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj))">
|
|
471
|
+
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), pivotColumns)">
|
|
469
472
|
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
470
473
|
</button>
|
|
471
474
|
</div>
|
|
@@ -480,7 +483,7 @@
|
|
|
480
483
|
</div>
|
|
481
484
|
<div class="flex-1 flex flex-row gap-3">
|
|
482
485
|
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
483
|
-
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() });">
|
|
486
|
+
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
|
|
484
487
|
{{ item.label ? item.label : item.key }}
|
|
485
488
|
</strong>
|
|
486
489
|
<select v-if="item.type === 'date'"
|
|
@@ -503,7 +506,7 @@
|
|
|
503
506
|
<div>
|
|
504
507
|
<div class="flex flex-row items-center gap-2">
|
|
505
508
|
<label>Aggregrates</label>
|
|
506
|
-
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj))">
|
|
509
|
+
<button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), pivotColumns)">
|
|
507
510
|
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
508
511
|
</button>
|
|
509
512
|
</div>
|
|
@@ -518,7 +521,7 @@
|
|
|
518
521
|
</div>
|
|
519
522
|
<div class="flex-1 flex flex-row gap-3">
|
|
520
523
|
<strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
|
|
521
|
-
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() });">
|
|
524
|
+
@click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
|
|
522
525
|
{{ item.label ? item.label : item.key }}
|
|
523
526
|
</strong>
|
|
524
527
|
<select v-model="item.aggregrate"
|
|
@@ -558,14 +561,21 @@
|
|
|
558
561
|
<div data-reorder>
|
|
559
562
|
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
560
563
|
</div>
|
|
561
|
-
<Textbox class="flex-1 border-none" v-model="item.label2" :placeholder="item.label"
|
|
564
|
+
<Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
562
565
|
item-class="p-1"/>
|
|
566
|
+
<button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
|
|
567
|
+
<svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
|
|
568
|
+
@click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
|
|
569
|
+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M176 0h-128C21.49 0 0 21.49 0 48v128C0 202.5 21.49 224 48 224h128C202.5 224 224 202.5 224 176v-128C224 21.49 202.5 0 176 0zM176 288h-128C21.49 288 0 309.5 0 336v128C0 490.5 21.49 512 48 512h128C202.5 512 224 490.5 224 464v-128C224 309.5 202.5 288 176 288zM464 0h-128C309.5 0 288 21.49 288 48v128C288 202.5 309.5 224 336 224h128C490.5 224 512 202.5 512 176v-128C512 21.49 490.5 0 464 0zM488 376h-64v-64C424 298.8 413.3 288 400 288s-24 10.75-24 24v64h-64c-13.25 0-24 10.75-24 24s10.75 24 24 24h64v64c0 13.25 10.75 24 24 24s24-10.75 24-24v-64h64c13.25 0 24-10.75 24-24S501.3 376 488 376z"/></svg>
|
|
570
|
+
</button>
|
|
563
571
|
<button type="button" @click="presetPivot.columns.splice(index, 1); presetPivot.manualColumns = true; apply()">
|
|
564
572
|
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
565
573
|
</button>
|
|
566
574
|
</div>
|
|
567
575
|
</template>
|
|
568
576
|
</ListItem>
|
|
577
|
+
|
|
578
|
+
<PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
|
|
569
579
|
</div>
|
|
570
580
|
|
|
571
581
|
</div>
|
|
@@ -594,8 +604,7 @@
|
|
|
594
604
|
|
|
595
605
|
</div>
|
|
596
606
|
|
|
597
|
-
<ColumnSelector ref="columnSelector"
|
|
598
|
-
:columns="config.columns" />
|
|
607
|
+
<ColumnSelector ref="columnSelector" />
|
|
599
608
|
|
|
600
609
|
</div>
|
|
601
610
|
|
|
@@ -756,6 +765,18 @@ export default{
|
|
|
756
765
|
return this.presetChart[this.chartType]
|
|
757
766
|
},
|
|
758
767
|
|
|
768
|
+
filterColumns(){
|
|
769
|
+
return this.config.columns.filter(_ => {
|
|
770
|
+
return _.filterable !== false
|
|
771
|
+
})
|
|
772
|
+
},
|
|
773
|
+
|
|
774
|
+
pivotColumns(){
|
|
775
|
+
return this.config.columns.filter(_ => {
|
|
776
|
+
return _.pivot !== false
|
|
777
|
+
})
|
|
778
|
+
},
|
|
779
|
+
|
|
759
780
|
preset(){
|
|
760
781
|
return this.config.presets[this.config.presetIdx]
|
|
761
782
|
},
|
|
@@ -846,4 +867,8 @@ export default{
|
|
|
846
867
|
@apply flex flex-col relative;
|
|
847
868
|
}
|
|
848
869
|
|
|
870
|
+
.columnTextbox input::placeholder{
|
|
871
|
+
@apply text-text;
|
|
872
|
+
}
|
|
873
|
+
|
|
849
874
|
</style>
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal ref="modal" :hash="hash" :state="state" width="480" height="480">
|
|
3
|
+
<template v-slot:head>
|
|
4
|
+
<div class="relative p-6">
|
|
5
|
+
<h3>{{ obj.label }}</h3>
|
|
6
|
+
<div class="absolute top-0 right-0 p-2">
|
|
7
|
+
<button type="button" class="p-2" @click="close">
|
|
8
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
9
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</button>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<template v-slot:foot>
|
|
16
|
+
<div class="p-6">
|
|
17
|
+
<Button class="w-[100px]" @click="apply">Apply</Button>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<div class="flex-1 p-6 flex flex-col gap-4">
|
|
21
|
+
|
|
22
|
+
<div class="flex flex-col gap-1">
|
|
23
|
+
<div class="flex flex-row gap-2">
|
|
24
|
+
<label class="text-text-400">Appearances</label>
|
|
25
|
+
<button type="button" class="text-primary" @click="appearances.push({ conditions:[{}], class:'' })">
|
|
26
|
+
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z"/></svg>
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<ListItem :items="appearances"
|
|
31
|
+
class="bg-transparent"
|
|
32
|
+
@reorder="(from, to) => { appearances.splice(to, 0, appearances.splice(from, 1)[0]); }"
|
|
33
|
+
container-class="flex flex-col gap-1">
|
|
34
|
+
<template v-slot="{ item, index }">
|
|
35
|
+
<div class="flex flex-row items-center gap-3">
|
|
36
|
+
<div data-reorder>
|
|
37
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="flex-1 flex flex-col gap-1">
|
|
40
|
+
<div v-for="condition in item.conditions" class="flex flex-row gap-1">
|
|
41
|
+
<Dropdown v-model="condition.operator" :class="condition.operator === 'none' ? 'w-[200px]' : 'w-[100px]'">
|
|
42
|
+
<option v-for="op in operators" :value="op.value">{{ op.text }}</option>
|
|
43
|
+
<option value="none">No Condition</option>
|
|
44
|
+
</Dropdown>
|
|
45
|
+
<Textbox v-if="condition.operator !== 'none'" v-model.numberconditions="condition.value" class="w-[100px]"/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div :class="item.class" class="px-2">
|
|
49
|
+
Sample
|
|
50
|
+
</div>
|
|
51
|
+
<div>
|
|
52
|
+
<Dropdown class="w-[120px]" v-model="item.class">
|
|
53
|
+
<option value="text-primary cursor-pointer">Default</option>
|
|
54
|
+
<option value="bg-red-100 text-red-600">Red 1</option>
|
|
55
|
+
<option value="bg-red-200 text-red-600">Red 2</option>
|
|
56
|
+
<option value="bg-red-300 text-red-600">Red 3</option>
|
|
57
|
+
<option value="bg-red-400 text-white">Red 4</option>
|
|
58
|
+
<option value="bg-red-500 text-white">Red 5</option>
|
|
59
|
+
<option value="bg-green-100 text-green-700">Green 1</option>
|
|
60
|
+
<option value="bg-green-200 text-green-700">Green 2</option>
|
|
61
|
+
<option value="bg-green-300 text-green-700">Green 3</option>
|
|
62
|
+
<option value="bg-green-400 text-white">Green 4</option>
|
|
63
|
+
<option value="bg-green-500 border-[1px] border-green-600 text-white">Green 5</option>
|
|
64
|
+
<option value="text-primary underline cursor-pointer">Underline</option>
|
|
65
|
+
</Dropdown>
|
|
66
|
+
</div>
|
|
67
|
+
<div>
|
|
68
|
+
<button type="button" @click="appearances.splice(index, 1)">
|
|
69
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
70
|
+
</button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
</ListItem>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</Modal>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script>
|
|
81
|
+
|
|
82
|
+
export default{
|
|
83
|
+
|
|
84
|
+
emits: [ 'apply' ],
|
|
85
|
+
|
|
86
|
+
inject: [ 'socketEmit2' ],
|
|
87
|
+
|
|
88
|
+
props: {
|
|
89
|
+
|
|
90
|
+
hash: String,
|
|
91
|
+
state: Boolean
|
|
92
|
+
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
computed: {
|
|
96
|
+
|
|
97
|
+
appearances(){
|
|
98
|
+
if(!Array.isArray(this.obj.appearances)){
|
|
99
|
+
this.obj.appearances = []
|
|
100
|
+
}
|
|
101
|
+
return this.obj.appearances
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
operators(){
|
|
105
|
+
|
|
106
|
+
let operators = []
|
|
107
|
+
|
|
108
|
+
switch(this.obj?.type){
|
|
109
|
+
|
|
110
|
+
case 'number':
|
|
111
|
+
operators = [
|
|
112
|
+
{ value:">", text:">" },
|
|
113
|
+
{ value:">=", text:">=" },
|
|
114
|
+
{ value:"=", text:"=" },
|
|
115
|
+
{ value:"<=", text:"<=" },
|
|
116
|
+
{ value:"<", text:"<" }
|
|
117
|
+
]
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
default:
|
|
121
|
+
operators = [
|
|
122
|
+
{ value:"contains", text:"Contains" },
|
|
123
|
+
{ value:"startsWith", text:"Starts With" },
|
|
124
|
+
{ value:"endsWith", text:"Ends With" },
|
|
125
|
+
{ value:"notContains", text:"Not Contains" },
|
|
126
|
+
{ value:"notStartsWith", text:"Not Starts With" },
|
|
127
|
+
{ value:"notEndsWith", text:"Not StartEnds With" },
|
|
128
|
+
{ value:"regex", text:"Match Pattern" }
|
|
129
|
+
]
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return operators
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
data(){
|
|
139
|
+
return {
|
|
140
|
+
obj: null,
|
|
141
|
+
callback: null
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
methods: {
|
|
146
|
+
|
|
147
|
+
apply(){
|
|
148
|
+
if(typeof this.callback === 'function')
|
|
149
|
+
this.callback(this.obj)
|
|
150
|
+
this.$emit('apply', this.obj)
|
|
151
|
+
this.close()
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
open(obj, callback){
|
|
155
|
+
this.obj = JSON.parse(JSON.stringify(obj))
|
|
156
|
+
this.callback = callback
|
|
157
|
+
this.$refs.modal.open()
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
close(){
|
|
161
|
+
this.$refs.modal.close()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
</script>
|
|
169
|
+
|
|
170
|
+
<style module>
|
|
171
|
+
|
|
172
|
+
.comp{
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
</style>
|