@mixd-id/web-scaffold 0.1.230406348 → 0.1.230406349

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.230406348",
4
+ "version": "0.1.230406349",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -1,7 +1,14 @@
1
1
  <template>
2
2
  <div :class="$style.comp">
3
- <div v-if="apiKey" ref="map" class="flex-1"></div>
3
+ <div v-if="apiKey" ref="map" class="flex-1">
4
+
5
+ </div>
4
6
  <div v-else class="flex-1 flex items-center justify-center text-text-400">{{ $t('Google maps api required') }}</div>
7
+
8
+ <div class="flex flex-row gap-2 p-1 px-3 pt-2">
9
+ <label class="text-sm text-text-400">Total points: {{ uniqueCount }}</label>
10
+
11
+ </div>
5
12
  </div>
6
13
  </template>
7
14
 
@@ -9,6 +16,8 @@
9
16
 
10
17
  import { Loader } from '@googlemaps/js-api-loader';
11
18
 
19
+ let loader = null
20
+
12
21
  export default{
13
22
 
14
23
  name: "GHeatMaps",
@@ -43,9 +52,10 @@ export default{
43
52
  if(!Array.isArray(this.datasets) || this.datasets.length < 1)
44
53
  return
45
54
 
46
- const loader = new Loader({
47
- apiKey: this.apiKey // "AIzaSyBmzMlmrR5St-njtN--64y_oLTa9FDLYfQ"
48
- })
55
+ if(!loader)
56
+ loader = new Loader({
57
+ apiKey: this.apiKey // "AIzaSyBmzMlmrR5St-njtN--64y_oLTa9FDLYfQ"
58
+ })
49
59
 
50
60
  loader.load()
51
61
  .then(async () => {
@@ -63,6 +73,7 @@ export default{
63
73
  mapTypeId: 'roadmap',
64
74
  streetViewControl: false,
65
75
  keyboardShortcuts: false,
76
+ disableDefaultUI: true,
66
77
  styles: [
67
78
  { elementType: "geometry", stylers: [{ color: "#242f3e" }] },
68
79
  { elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
@@ -207,8 +218,6 @@ export default{
207
218
  "rgba(255, 0, 0, 1)",
208
219
  ];
209
220
  heatmap.set("gradient", gradient);
210
-
211
- //console.log('Gmap, data count:', this.data.length)
212
221
  });
213
222
  }
214
223
 
@@ -216,6 +225,15 @@ export default{
216
225
 
217
226
  computed: {
218
227
 
228
+ uniqueCount(){
229
+ if(!Array.isArray(this.value?.items)) return 0
230
+
231
+ return Object.keys(this.value.items.reduce((acc, item) => {
232
+ acc[item[this.column]] = 1
233
+ return acc
234
+ }, {})).length
235
+ },
236
+
219
237
  datasets(){
220
238
  if(!Array.isArray(this.value?.items)) return []
221
239
 
@@ -250,7 +268,7 @@ export default{
250
268
  <style module>
251
269
 
252
270
  .comp{
253
- @apply flex flex-col h-[40vh] bg-base-500;
271
+ @apply flex flex-col h-[40vh] border-[1px] border-text-50 bg-base-500 rounded-xl overflow-hidden;
254
272
  }
255
273
 
256
274
  </style>
@@ -3,7 +3,8 @@ export const component = {
3
3
  type:"BarChart",
4
4
 
5
5
  props:{
6
- height:200
6
+ height:200,
7
+ excluded: [],
7
8
  }
8
9
 
9
10
  }
@@ -147,11 +147,11 @@ const generatePivotColumns = (preset, items) => {
147
147
  }
148
148
  }
149
149
 
150
- (preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
150
+ /*(preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
151
151
  .forEach(_ => {
152
152
  _.visible = false
153
153
  pivotColumns.push(_)
154
- })
154
+ })*/
155
155
 
156
156
  preset.pivot.columns = pivotColumns
157
157
 
@@ -16,18 +16,6 @@
16
16
  <div v-else class="flex flex-col gap-3">
17
17
  <div class="flex flex-row items-center gap-4">
18
18
  <label class="text-text-400 text-ellipsis overflow-hidden whitespace-nowrap flex-1">{{ label }}</label>
19
- <div v-if="yAxeMultiple && yLegends?.length > 0" class="flex flex-row items-center flex-wrap justify-center gap-1">
20
- <div v-for="yLegend in showedYLegends"
21
- v-tooltip="`${yLegend.key}`"
22
- class="p-0.5 px-1 rounded-full text-black cursor-default text-xs min-w-[50px] max-w-[60px] text-center text-ellipsis overflow-hidden whitespace-nowrap capitalize"
23
- :style="{ backgroundColor:yLegend.color }">
24
- {{ (yLegend.key ?? '').toString().split(' ')[0].toLowerCase() }}
25
- </div>
26
- <button v-if="yLegends.length > showedYLegends.length" @click="$refs.legendModal.open()"
27
- class="bg-text-200 hover:bg-primary-600 w-[21px] h-[21px] rounded-full flex items-center justify-center">
28
- <svg width="14" height="14" class="fill-white opacity-70" 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="M64 192C28.61 192 0 220.6 0 256s28.61 64 64 64s64-28.62 64-64S99.39 192 64 192zM256 192C220.6 192 192 220.6 192 256s28.61 64 64 64s64-28.62 64-64S291.4 192 256 192zM448 192c-35.39 0-64 28.62-64 64s28.61 64 64 64s64-28.62 64-64S483.4 192 448 192z"/></svg>
29
- </button>
30
- </div>
31
19
  </div>
32
20
 
33
21
  <div class="flex-1">
@@ -36,6 +24,20 @@
36
24
  :data="chartData"/>
37
25
  </div>
38
26
 
27
+ <div v-if="yAxeMultiple && yLegends?.length > 0" class="flex flex-row items-center flex-wrap justify-center gap-1">
28
+ <div v-for="yLegend in showedYLegends"
29
+ @click="toggleExcludes(yLegend)"
30
+ class="p-0.5 px-1 rounded-full text-black cursor-default text-xs min-w-[50px] max-w-[60px] text-center text-ellipsis overflow-hidden whitespace-nowrap capitalize"
31
+ :class="excluded.includes(yLegend.key) ? 'bg-text-200' : ''"
32
+ :style="{ backgroundColor:excluded.includes(yLegend.key) ? '' : yLegend.color }">
33
+ {{ yLegend.key }}
34
+ </div>
35
+ <button v-if="yLegends.length > showedYLegends.length" @click="$refs.legendModal.open()"
36
+ class="bg-text-200 hover:bg-primary-600 w-[21px] h-[21px] rounded-full flex items-center justify-center">
37
+ <svg width="14" height="14" class="fill-white opacity-70" 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="M64 192C28.61 192 0 220.6 0 256s28.61 64 64 64s64-28.62 64-64S99.39 192 64 192zM256 192C220.6 192 192 220.6 192 256s28.61 64 64 64s64-28.62 64-64S291.4 192 256 192zM448 192c-35.39 0-64 28.62-64 64s28.61 64 64 64s64-28.62 64-64S483.4 192 448 192z"/></svg>
38
+ </button>
39
+ </div>
40
+
39
41
  <Modal ref="legendModal" width="320" height="360" :dismissable="true" @dismiss="$refs.legendModal.close()">
40
42
  <template v-slot:head>
41
43
  <div class="relative p-5">
@@ -53,8 +55,9 @@
53
55
 
54
56
  <div class="flex flex-col divide-y divide-text-50">
55
57
  <div v-for="yLegend in yLegends" class="flex flex-row items-center gap-2 py-2">
56
- <div class="w-[24px] h-[24px] rounded-full" :style="{ backgroundColor:yLegend.color }"></div>
58
+ <div class="w-[19px] h-[19px] rounded-full" :style="{ backgroundColor:yLegend.color }"></div>
57
59
  <div class="flex-1 text-ellipsis whitespace-nowrap overflow-hidden">{{ yLegend.key }}</div>
60
+ <Checkbox :value="!excluded.includes(yLegend.key)" @click.prevent="toggleExcludes(yLegend)" />
58
61
  </div>
59
62
  </div>
60
63
 
@@ -95,16 +98,18 @@ export default{
95
98
 
96
99
  return {
97
100
  labels: this.value?.labels ?? [],
98
- datasets: this.value.datasets.map(_ => {
99
- return {
100
- ..._,
101
- borderWidth: 0,
102
- borderColor: function(context, options) {
103
- const hex = options.color;
104
- return color(hex).darken(0.5).rgbString()
105
- }
106
- }
107
- })
101
+ datasets: this.value.datasets
102
+ .filter(_ => !this.excluded.includes(_.label))
103
+ .map(_ => {
104
+ return {
105
+ ..._,
106
+ borderWidth: 0,
107
+ borderColor: function(context, options) {
108
+ const hex = options.color;
109
+ return color(hex).darken(0.5).rgbString()
110
+ }
111
+ }
112
+ })
108
113
  }
109
114
  },
110
115
 
@@ -125,7 +130,15 @@ export default{
125
130
  label: (tooltipItem) => {
126
131
  if(this.yAxeMultiple && this.usePercentage)
127
132
  return `${tooltipItem.dataset.label}: ${tooltipItem.dataset.data0[tooltipItem.dataIndex]} (${tooltipItem.raw}%)`
128
- return `${tooltipItem.dataset.label}: ${tooltipItem.raw}`;
133
+ else{
134
+ if(this.stacked){
135
+ const total = this.value.datasets.reduce((acc, cur) => acc + cur.data[tooltipItem.dataIndex], 0)
136
+ const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
137
+
138
+ return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
139
+ }
140
+ return `${tooltipItem.dataset.label}: ${tooltipItem.raw}`;
141
+ }
129
142
  }
130
143
  },
131
144
  }
@@ -154,10 +167,15 @@ export default{
154
167
  y: {
155
168
  beginAtZero: true,
156
169
  ticks: {
157
- display: !this.yAxeMultiple || this.usePercentage,
170
+ display: true,
158
171
  font: {
159
172
  size: 11,
160
173
  },
174
+ callback: (value, index, ticks) => {
175
+ if(this.usePercentage)
176
+ return Math.round(index / (ticks.length - 1) * 100) + '%'
177
+ return value
178
+ },
161
179
  },
162
180
  grid: {
163
181
  display: true,
@@ -251,6 +269,13 @@ export default{
251
269
  this.readyState = state
252
270
  },
253
271
 
272
+ toggleExcludes(yLegend){
273
+ if(this.excluded.includes(yLegend.key))
274
+ this.excluded.splice(this.excluded.indexOf(yLegend.key), 1)
275
+ else
276
+ this.excluded.push(yLegend.key)
277
+ }
278
+
254
279
  },
255
280
 
256
281
  props: {
@@ -272,6 +297,11 @@ export default{
272
297
  xAxeMultiple: Boolean,
273
298
  yAxeMultiple: Boolean,
274
299
 
300
+ excluded: {
301
+ type: Array,
302
+ default: []
303
+ },
304
+
275
305
  segments: Array,
276
306
  xAxesGroup: String,
277
307
 
@@ -133,7 +133,7 @@
133
133
  <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>
134
134
  </div>
135
135
  <div class="flex-1 flex flex-row gap-2">
136
- <Dropdown v-model="item.key" :readonly="readonly" class="flex-1">
136
+ <Dropdown v-model="item.key" :readonly="readonly" class="flex-1" @change="clearExcluded">
137
137
  <option v-for="column in selectedDatasourceColumns"
138
138
  :value="column.key">
139
139
  {{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
@@ -273,6 +273,10 @@ export default{
273
273
  this.$util.push(this.interactions, obj)
274
274
  },
275
275
 
276
+ clearExcluded(){
277
+ this.value.props.excluded = []
278
+ },
279
+
276
280
  swap(){
277
281
  const yAxes = this.value.props.yAxes
278
282
  const xAxes = this.value.props.xAxes
@@ -28,7 +28,7 @@
28
28
 
29
29
  export default{
30
30
 
31
- inject: [ 'alert', 'socket' ],
31
+ inject: [ 'alert', 'preview', 'socket' ],
32
32
 
33
33
  props: {
34
34
  src: String
@@ -67,13 +67,9 @@ export default{
67
67
  },
68
68
 
69
69
  load(){
70
- this.socket.send(this.src, {
71
- datasource: this.datasource
72
- })
73
- .then(res => {
74
- this.res = res
75
- })
76
- .catch(err => this.alert(err))
70
+ this.preview(this.datasource)
71
+ .then(res => this.res = res)
72
+ .catch(err => this.alert(err))
77
73
  },
78
74
 
79
75
  open(datasource){
@@ -55,6 +55,19 @@ export default{
55
55
  legend: {
56
56
  display: false
57
57
  },
58
+ tooltip: {
59
+ callbacks: {
60
+ title: function(tooltipItems) {
61
+ return `${tooltipItems[0].label}`;
62
+ },
63
+ label: (tooltipItem) => {
64
+ const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
65
+ const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
66
+
67
+ return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
68
+ }
69
+ },
70
+ },
58
71
  },
59
72
  onClick: this.onClick
60
73
  }
@@ -41,7 +41,8 @@
41
41
 
42
42
  <Dropdown v-model="value.props.rowsModifier"
43
43
  :readonly="readonly"
44
- :class="!value.props.rowsModifier ? 'w-[80px]' : 'w-[150px]'">
44
+ :class="!value.props.rowsModifier ? 'w-[80px]' : 'w-[150px]'"
45
+ @change="$emit('change')">
45
46
  <option value="">-</option>
46
47
  <option value="lowercase">Lower</option>
47
48
  <option value="capitalize">Capitalize</option>
@@ -71,7 +72,8 @@
71
72
 
72
73
  <Dropdown v-model="value.props.columnModifier"
73
74
  :readonly="readonly"
74
- :class="!value.props.columnModifier ? 'w-[80px]' : 'w-[150px]'">
75
+ :class="!value.props.columnModifier ? 'w-[80px]' : 'w-[150px]'"
76
+ @change="$emit('change')">
75
77
  <option value="">-</option>
76
78
  <option value="count">Count</option>
77
79
  <option value="countDistinct">Unique Count</option>
@@ -54,6 +54,19 @@ export default{
54
54
  legend: {
55
55
  display: false
56
56
  },
57
+ tooltip: {
58
+ callbacks: {
59
+ title: function(tooltipItems) {
60
+ return `${tooltipItems[0].label}`;
61
+ },
62
+ label: (tooltipItem) => {
63
+ const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
64
+ const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
65
+
66
+ return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
67
+ }
68
+ },
69
+ },
57
70
  },
58
71
  onClick: this.onClick
59
72
  }
@@ -50,11 +50,23 @@ export default{
50
50
  return {
51
51
  responsive: true,
52
52
  maintainAspectRatio: true,
53
- /*animation: false,*/
54
53
  plugins: {
55
54
  legend: {
56
55
  display: false
57
56
  },
57
+ tooltip: {
58
+ callbacks: {
59
+ title: function(tooltipItems) {
60
+ return `${tooltipItems[0].label}`;
61
+ },
62
+ label: (tooltipItem) => {
63
+ const total = tooltipItem.dataset.data.reduce((a, b) => a + b, 0)
64
+ const percentage = ((tooltipItem.raw / total) * 100).toFixed(1)
65
+
66
+ return `${tooltipItem.dataset.label}: ${tooltipItem.raw} (${percentage}%)`;
67
+ }
68
+ },
69
+ },
58
70
  },
59
71
  scales: {
60
72
  r: {
@@ -40,7 +40,8 @@
40
40
 
41
41
  <Dropdown v-model="value.props.rowsModifier"
42
42
  :readonly="readonly"
43
- class="w-[125px]">
43
+ class="w-[125px]"
44
+ @change="$emit('change')">
44
45
  <option value="">-</option>
45
46
  <option value="lowercase">Lower</option>
46
47
  <option value="capitalize">Capitalize</option>
@@ -70,7 +71,8 @@
70
71
 
71
72
  <Dropdown v-model="value.props.columnModifier"
72
73
  :readonly="readonly"
73
- class="w-[125px]">
74
+ class="w-[125px]"
75
+ @change="$emit('change')">
74
76
  <option value="">-</option>
75
77
  <option value="count">Count</option>
76
78
  <option value="countDistinct">Unique Count</option>
@@ -214,136 +214,10 @@
214
214
  </div>
215
215
 
216
216
  <div v-else-if="selectedDatasource.tabIndex === 4" class="p-5 flex-1 flex flex-col gap-5">
217
- <div>
218
- <Checkbox v-model="selectedDatasourcePivot.enabled"
219
- @change="" :disabled="selectedPreset.readonly">
220
- Pivot Enabled
221
- </Checkbox>
222
- </div>
223
-
224
- <div class="grid grid-cols-1 gap-6">
225
-
226
- <div>
227
- <div class="flex flex-row items-center gap-2">
228
- <label>Groups</label>
229
- <button v-if="!selectedPreset.readonly" type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), selectedDatasourcePivotColumns)">
230
- <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>
231
- </button>
232
- </div>
233
- <ListItem :items="selectedDatasourcePivot.rows"
234
- @reorder="(from, to) => { selectedDatasourcePivot.rows.splice(to, 0, selectedDatasourcePivot.rows.splice(from, 1)[0]); }"
235
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
236
- container-class="divide-y divide-text-50">
237
- <template v-slot="{ item, index }">
238
- <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
239
- <div data-reorder v-if="(selectedDatasourcePivot.rows ?? []).length > 1 && !selectedPreset.readonly">
240
- <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>
241
- </div>
242
- <div class="flex-1 flex flex-row gap-3">
243
- <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
244
- @click="!selectedPreset.readonly ? $refs.columnSelector.open(obj => { Object.assign(item, obj); }, selectedDatasourcePivotColumns) : null;">
245
- {{ item.label ? item.label : item.key }}
246
- </strong>
247
- <select v-if="item.type === 'date'"
248
- v-model="item.aggregrate"
249
- class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
250
- @change="">
251
- <option value="hour">Hour</option>
252
- <option value="date">Date</option>
253
- <option value="month">Month</option>
254
- <option value="year">Year</option>
255
- </select>
256
- </div>
257
- <button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.rows.splice(index, 1); loadPivotData()">
258
- <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>
259
- </button>
260
- </div>
261
- </template>
262
- </ListItem>
263
- </div>
264
-
265
- <div>
266
- <div class="flex flex-row items-center gap-2">
267
- <label>Aggregrates</label>
268
- <button v-if="!selectedPreset.readonly" type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), selectedDatasourcePivotColumns)">
269
- <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>
270
- </button>
271
- </div>
272
- <ListItem :items="selectedDatasourcePivot.values"
273
- @reorder="(from, to) => { selectedDatasourcePivot.values.splice(to, 0, selectedDatasourcePivot.values.splice(from, 1)[0]); }"
274
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
275
- container-class="divide-y divide-text-50">
276
- <template v-slot="{ item, index }">
277
- <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
278
- <div data-reorder v-if="(selectedDatasourcePivot.values ?? []).length > 1 && !selectedPreset.readonly">
279
- <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>
280
- </div>
281
- <div class="flex-1 flex flex-row gap-3">
282
- <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
283
- @click="!selectedPreset.readonly ? $refs.columnSelector.open(obj => { Object.assign(item, obj); }, selectedDatasourcePivotColumns) : null;">
284
- {{ item.label ? item.label : item.key }}
285
- </strong>
286
- <select v-model="item.aggregrate"
287
- :disabled="selectedPreset.readonly"
288
- class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
289
- @change="loadPivotData">
290
- <option value="">Default</option>
291
- <option value="count">Count</option>
292
- <option value="countDistinct">Distinct Count</option>
293
- <option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
294
- <option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
295
- <option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
296
- <option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
297
- </select>
298
- </div>
299
- <button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.values.splice(index, 1); loadPivotData()">
300
- <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>
301
- </button>
302
- </div>
303
- </template>
304
- </ListItem>
305
- </div>
306
217
 
307
- <div>
308
- <div class="flex flex-row items-center gap-2">
309
- <label class="flex-1">Columns</label>
310
- <button v-if="selectedDatasourcePivot.manualColumns && !selectedPreset.readonly"
311
- type="button"
312
- class="text-primary"
313
- @click="delete selectedDatasourcePivot.manualColumns; ">Reset</button>
314
- </div>
315
- <ListItem :items="selectedDatasourcePivot.columns"
316
- @reorder="(from, to) => { selectedDatasourcePivot.columns.splice(to, 0, selectedDatasourcePivot.columns.splice(from, 1)[0]); selectedDatasourcePivot.manualColumns = true; }"
317
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
318
- container-class="divide-y divide-text-50">
319
- <template v-slot="{ item, index }">
320
- <div class="flex flex-row gap-2 items-center px-2 bg-base-500">
321
- <div data-reorder v-if="!selectedPreset.readonly">
322
- <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>
323
- </div>
324
- <Textbox class="flex-1 border-none" :readonly="selectedPreset.readonly" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
325
- item-class="p-1"/>
326
- <button type="button" v-if="[ 'number' ].includes(item.type) && !selectedPreset.readonly" @click="">
327
- <svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
328
- @click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); })"
329
- 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>
330
- </button>
331
- <button v-if="!selectedPreset.readonly" type="button" @click="selectedDatasourcePivot.columns.splice(index, 1); selectedDatasourcePivot.manualColumns = true; ">
332
- <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>
333
- </button>
334
- </div>
335
- </template>
336
- </ListItem>
337
-
338
- <PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
339
- </div>
340
-
341
- <div class="flex flex-row items-center gap-3">
342
- <label>Total</label>
343
- <Switch v-model="selectedDatasourcePivot.useTotal" :readonly="selectedPreset.readonly" @change=""/>
344
- </div>
345
-
346
- </div>
218
+ <PresetBarPivot :pivot="selectedDatasourcePivot"
219
+ :columns="selectedDatasourcePivotColumns"
220
+ @apply="updatePivot" />
347
221
 
348
222
  <br />
349
223
  </div>
@@ -775,6 +649,7 @@ import {defineAsyncComponent} from "vue";
775
649
  import SharingModal from "./Dashboard/SharingModal.vue";
776
650
  import PresetSelectorFilterItem from "../components/PresetSelectorFilterItem.vue";
777
651
  import {generatePivotColumns} from "../utils/preset-selector.mjs";
652
+ import PresetBarPivot from "./PresetBarPivot.vue";
778
653
 
779
654
  const findComponents = (items, uid) => {
780
655
  if(!Array.isArray(items)) return
@@ -794,6 +669,7 @@ const findComponents = (items, uid) => {
794
669
  export default{
795
670
 
796
671
  components: {
672
+ PresetBarPivot,
797
673
  DatasourcePreview: defineAsyncComponent(() => import('./Dashboard/DatasourcePreview.vue')),
798
674
  PresetSelectorFilterItem,
799
675
  SharingModal,
@@ -1384,6 +1260,24 @@ export default{
1384
1260
  this.$router.replace({ query })
1385
1261
  },
1386
1262
 
1263
+ async preview(datasource){
1264
+ return new Promise((resolve, reject) => {
1265
+ this.socket.send(this.previewSrc, { datasource })
1266
+ .then(res => {
1267
+ this.previewData = res
1268
+ resolve(res)
1269
+ })
1270
+ .catch(err => reject(err))
1271
+ })
1272
+ },
1273
+
1274
+ updatePivot(){
1275
+ this.preview(this.selectedDatasource)
1276
+ .then(res => {
1277
+ generatePivotColumns(this.selectedDatasource, res.items)
1278
+ })
1279
+ }
1280
+
1387
1281
  },
1388
1282
 
1389
1283
  props:{
@@ -1413,7 +1307,8 @@ export default{
1413
1307
  previewDatasource: this.previewDatasource,
1414
1308
  emitRoot: this.emitRoot,
1415
1309
  getConfig: this.getConfig,
1416
- selectPreset: this.selectPreset
1310
+ selectPreset: this.selectPreset,
1311
+ preview: this.preview
1417
1312
  }
1418
1313
  },
1419
1314
 
@@ -454,137 +454,9 @@
454
454
 
455
455
  </div>
456
456
 
457
- <div v-else-if="config.presetBarTabIndex === 5" class="flex-1 flex flex-col gap-6 p-6">
457
+ <div v-else-if="config.presetBarTabIndex === 5" class="flex-1 p-6">
458
458
 
459
- <div>
460
- <Checkbox v-model="presetPivot.enabled"
461
- @change="apply()">
462
- Pivot Enabled
463
- </Checkbox>
464
- </div>
465
-
466
- <div class="grid grid-cols-1 gap-6">
467
-
468
- <div>
469
- <div class="flex flex-row items-center gap-2">
470
- <label>Groups</label>
471
- <button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), pivotColumns)">
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>
473
- </button>
474
- </div>
475
- <ListItem :items="presetPivot.rows"
476
- @reorder="(from, to) => { presetPivot.rows.splice(to, 0, presetPivot.rows.splice(from, 1)[0]); apply() }"
477
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
478
- container-class="divide-y divide-text-50">
479
- <template v-slot="{ item, index }">
480
- <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
481
- <div data-reorder v-if="(presetPivot.rows ?? []).length > 1">
482
- <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>
483
- </div>
484
- <div class="flex-1 flex flex-row gap-3">
485
- <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
486
- @click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
487
- {{ item.label ? item.label : item.key }}
488
- </strong>
489
- <select v-if="item.type === 'date'"
490
- v-model="item.aggregrate"
491
- class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
492
- @change="apply()">
493
- <option value="hour">Hour</option>
494
- <option value="date">Date</option>
495
- <option value="month">Month</option>
496
- <option value="year">Year</option>
497
- </select>
498
- </div>
499
- <button type="button" @click="presetPivot.rows.splice(index, 1); apply()">
500
- <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>
501
- </button>
502
- </div>
503
- </template>
504
- </ListItem>
505
- </div>
506
-
507
- <div>
508
- <div class="flex flex-row items-center gap-2">
509
- <label>Aggregrates</label>
510
- <button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), pivotColumns)">
511
- <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>
512
- </button>
513
- </div>
514
- <ListItem :items="presetPivot.values"
515
- @reorder="(from, to) => { presetPivot.values.splice(to, 0, presetPivot.values.splice(from, 1)[0]); }"
516
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
517
- container-class="divide-y divide-text-50">
518
- <template v-slot="{ item, index }">
519
- <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
520
- <div data-reorder v-if="(presetPivot.values ?? []).length > 1">
521
- <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>
522
- </div>
523
- <div class="flex-1 flex flex-row gap-3">
524
- <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
525
- @click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, pivotColumns);">
526
- {{ item.label ? item.label : item.key }}
527
- </strong>
528
- <select v-model="item.aggregrate"
529
- class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
530
- @change="apply()">
531
- <option value="">Default</option>
532
- <option value="count">Count</option>
533
- <option value="countDistinct">Distinct Count</option>
534
- <option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
535
- <option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
536
- <option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
537
- <option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
538
- </select>
539
- </div>
540
- <button type="button" @click="presetPivot.values.splice(index, 1); apply()">
541
- <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>
542
- </button>
543
- </div>
544
- </template>
545
- </ListItem>
546
- </div>
547
-
548
- <div>
549
- <div class="flex flex-row items-center gap-2">
550
- <label class="flex-1">Columns</label>
551
- <button v-if="presetPivot.manualColumns"
552
- type="button"
553
- class="text-primary"
554
- @click="delete presetPivot.manualColumns; apply()">Reset</button>
555
- </div>
556
- <ListItem :items="presetPivot.columns"
557
- @reorder="(from, to) => { presetPivot.columns.splice(to, 0, presetPivot.columns.splice(from, 1)[0]); presetPivot.manualColumns = true; apply() }"
558
- class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
559
- container-class="divide-y divide-text-50">
560
- <template v-slot="{ item, index }">
561
- <div class="flex flex-row gap-2 items-center px-2 bg-base-500">
562
- <div data-reorder>
563
- <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>
564
- </div>
565
- <Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
566
- item-class="p-1"/>
567
- <button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
568
- <svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
569
- @click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
570
- 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>
571
- </button>
572
- <button type="button" @click="presetPivot.columns.splice(index, 1); presetPivot.manualColumns = true; apply()">
573
- <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>
574
- </button>
575
- </div>
576
- </template>
577
- </ListItem>
578
-
579
- <PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
580
- </div>
581
-
582
- <div class="flex flex-row items-center gap-3">
583
- <label>Total</label>
584
- <Switch v-model="presetPivot.useTotal" @change="apply()"/>
585
- </div>
586
-
587
- </div>
459
+ <PresetBarPivot :pivot="presetPivot" :columns="pivotColumns" @apply="apply"/>
588
460
 
589
461
  </div>
590
462
 
@@ -622,10 +494,11 @@
622
494
  <script>
623
495
 
624
496
  import PresetSelectorFilterItem from "../components/PresetSelectorFilterItem.vue";
497
+ import PresetBarPivot from "./PresetBarPivot.vue";
625
498
 
626
499
  export default{
627
500
 
628
- components: {PresetSelectorFilterItem},
501
+ components: {PresetBarPivot, PresetSelectorFilterItem},
629
502
 
630
503
  emits: [ 'apply' ],
631
504
 
@@ -648,11 +521,6 @@ export default{
648
521
  this.apply()
649
522
  },
650
523
 
651
- addPivot(type, obj){
652
- this.presetPivot[type].push(Object.assign({}, obj))
653
- this.apply()
654
- },
655
-
656
524
  addSort(obj){
657
525
  if(!Array.isArray(this.preset.sorts))
658
526
  this.preset.sorts = []
@@ -0,0 +1,186 @@
1
+ <template>
2
+ <div class="flex flex-col gap-6">
3
+
4
+ <div>
5
+ <Checkbox v-model="pivot.enabled"
6
+ @change="apply()">
7
+ Pivot Enabled
8
+ </Checkbox>
9
+ </div>
10
+
11
+ <div class="grid grid-cols-1 gap-6">
12
+
13
+ <div>
14
+ <div class="flex flex-row items-center gap-2">
15
+ <label>Groups</label>
16
+ <button type="button" @click="$refs.columnSelector.open(obj => addPivot('rows', obj), columns)">
17
+ <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>
18
+ </button>
19
+ </div>
20
+ <ListItem :items="pivot.rows"
21
+ @reorder="(from, to) => { pivot.rows.splice(to, 0, pivot.rows.splice(from, 1)[0]); apply() }"
22
+ class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
23
+ container-class="divide-y divide-text-50">
24
+ <template v-slot="{ item, index }">
25
+ <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
26
+ <div data-reorder v-if="(pivot.rows ?? []).length > 1">
27
+ <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>
28
+ </div>
29
+ <div class="flex-1 flex flex-row gap-3">
30
+ <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
31
+ @click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, columns);">
32
+ {{ item.label ? item.label : item.key }}
33
+ </strong>
34
+ <select v-if="item.type === 'date'"
35
+ v-model="item.aggregrate"
36
+ class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
37
+ @change="apply()">
38
+ <option value="hour">Hour</option>
39
+ <option value="date">Date</option>
40
+ <option value="month">Month</option>
41
+ <option value="year">Year</option>
42
+ </select>
43
+ </div>
44
+ <button type="button" @click="pivot.rows.splice(index, 1); apply()">
45
+ <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>
46
+ </button>
47
+ </div>
48
+ </template>
49
+ </ListItem>
50
+ </div>
51
+
52
+ <div>
53
+ <div class="flex flex-row items-center gap-2">
54
+ <label>Aggregrates</label>
55
+ <button type="button" @click="$refs.columnSelector.open(obj => addPivot('values', obj), columns)">
56
+ <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>
57
+ </button>
58
+ </div>
59
+ <ListItem :items="pivot.values"
60
+ @reorder="(from, to) => { pivot.values.splice(to, 0, pivot.values.splice(from, 1)[0]); }"
61
+ class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
62
+ container-class="divide-y divide-text-50">
63
+ <template v-slot="{ item, index }">
64
+ <div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
65
+ <div data-reorder v-if="(pivot.values ?? []).length > 1">
66
+ <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>
67
+ </div>
68
+ <div class="flex-1 flex flex-row gap-3">
69
+ <strong class="flex-1 cursor-pointer text-ellipsis overflow-hidden whitespace-nowrap"
70
+ @click="$refs.columnSelector.open(obj => { Object.assign(item, obj); apply() }, columns);">
71
+ {{ item.label ? item.label : item.key }}
72
+ </strong>
73
+ <select v-model="item.aggregrate"
74
+ class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
75
+ @change="apply()">
76
+ <option value="">Default</option>
77
+ <option value="count">Count</option>
78
+ <option value="countDistinct">Distinct Count</option>
79
+ <option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
80
+ <option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
81
+ <option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
82
+ <option v-if="[ 'number' ].includes(item.type)" value="max">Max</option>
83
+ </select>
84
+ </div>
85
+ <button type="button" @click="pivot.values.splice(index, 1); apply()">
86
+ <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>
87
+ </button>
88
+ </div>
89
+ </template>
90
+ </ListItem>
91
+ </div>
92
+
93
+ <div>
94
+ <div class="flex flex-row items-center gap-2">
95
+ <label class="flex-1">Columns</label>
96
+ <button v-if="pivot.manualColumns"
97
+ type="button"
98
+ class="text-primary"
99
+ @click="delete pivot.manualColumns; apply()">Reset</button>
100
+ </div>
101
+ <ListItem :items="pivot.columns"
102
+ @reorder="(from, to) => { pivot.columns.splice(to, 0, pivot.columns.splice(from, 1)[0]); pivot.manualColumns = true; apply() }"
103
+ class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
104
+ container-class="divide-y divide-text-50">
105
+ <template v-slot="{ item, index }">
106
+ <div class="flex flex-row gap-2 items-center px-2 bg-base-500">
107
+ <div data-reorder>
108
+ <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>
109
+ </div>
110
+ <Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
111
+ item-class="p-1"/>
112
+ <button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
113
+ <svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
114
+ @click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
115
+ 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>
116
+ </button>
117
+ <button type="button" @click="pivot.columns.splice(index, 1); pivot.manualColumns = true; apply()">
118
+ <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>
119
+ </button>
120
+ </div>
121
+ </template>
122
+ </ListItem>
123
+
124
+ </div>
125
+
126
+ <div class="flex flex-row items-center gap-3">
127
+ <label>Total</label>
128
+ <Switch v-model="pivot.useTotal" @change="apply()"/>
129
+ </div>
130
+
131
+ </div>
132
+
133
+ <ColumnSelector ref="columnSelector" />
134
+
135
+ <PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
136
+
137
+ </div>
138
+ </template>
139
+
140
+ <script>
141
+
142
+ import PresetBarPivotColumnEdit from "./PresetBarPivotColumnEdit.vue";
143
+ import ColumnSelector from "./ColumnSelector.vue";
144
+
145
+ export default{
146
+ components: {ColumnSelector, PresetBarPivotColumnEdit},
147
+
148
+ emits: [ 'apply' ],
149
+
150
+ methods: {
151
+
152
+ apply(){
153
+ this.$emit('apply')
154
+ },
155
+
156
+ addPivot(type, obj){
157
+ console.log(this.pivot, type)
158
+ this.pivot[type].push(Object.assign({}, obj))
159
+ this.apply()
160
+ },
161
+
162
+ },
163
+
164
+ props:{
165
+
166
+ columns: Array,
167
+
168
+ pivot: Object
169
+
170
+ }
171
+
172
+ }
173
+
174
+ </script>
175
+
176
+ <style module>
177
+
178
+ .comp{
179
+
180
+ }
181
+
182
+ .columnTextbox input::placeholder{
183
+ @apply text-text;
184
+ }
185
+
186
+ </style>