@mixd-id/web-scaffold 0.1.230406341 → 0.1.230406342

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 (44) hide show
  1. package/package.json +2 -1
  2. package/public/assets/dashboard/bar.png +0 -0
  3. package/public/assets/dashboard/doughnut.png +0 -0
  4. package/public/assets/dashboard/metric.png +0 -0
  5. package/public/assets/dashboard/pie.png +0 -0
  6. package/public/assets/dashboard/polar-area.png +0 -0
  7. package/public/assets/dashboard/virtual-table.png +0 -0
  8. package/public/static/dashboard/bar.png +0 -0
  9. package/public/static/dashboard/doughnut.png +0 -0
  10. package/public/static/dashboard/metric.png +0 -0
  11. package/public/static/dashboard/pie.png +0 -0
  12. package/public/static/dashboard/polar-area.png +0 -0
  13. package/public/static/dashboard/virtual-table.png +0 -0
  14. package/src/components/Grid.vue +2 -0
  15. package/src/components/VirtualTable.vue +5 -1
  16. package/src/configs/dashboard/bar.js +9 -0
  17. package/src/configs/dashboard/collection-1.js +5 -0
  18. package/src/configs/dashboard/doughnut.js +7 -0
  19. package/src/configs/dashboard/grid-2.js +32 -0
  20. package/src/configs/dashboard/grid-3.js +32 -0
  21. package/src/configs/dashboard/grid-4.js +32 -0
  22. package/src/configs/dashboard/grid.js +13 -0
  23. package/src/configs/dashboard/metric.js +10 -0
  24. package/src/configs/dashboard/pie.js +7 -0
  25. package/src/configs/dashboard/polar-area.js +7 -0
  26. package/src/configs/dashboard/virtual-table.js +9 -0
  27. package/src/utils/dashboard.js +100 -0
  28. package/src/widgets/Dashboard/BarChart.vue +7 -6
  29. package/src/widgets/Dashboard/BarChartSetting.vue +30 -25
  30. package/src/widgets/Dashboard/DatasourcePreview.vue +83 -0
  31. package/src/widgets/Dashboard/DatasourceSelector.vue +19 -5
  32. package/src/widgets/Dashboard/Doughnut.vue +1 -0
  33. package/src/widgets/Dashboard/DoughnutSetting.vue +30 -9
  34. package/src/widgets/Dashboard/InteractionEdit.vue +194 -0
  35. package/src/widgets/Dashboard/Metric.vue +11 -1
  36. package/src/widgets/Dashboard/MetricSetting.vue +54 -7
  37. package/src/widgets/Dashboard/Pie.vue +32 -1
  38. package/src/widgets/Dashboard/PieSetting.vue +127 -19
  39. package/src/widgets/Dashboard/PolarArea.vue +1 -0
  40. package/src/widgets/Dashboard/PolarAreaSetting.vue +30 -9
  41. package/src/widgets/Dashboard/SharingModal.vue +12 -9
  42. package/src/widgets/Dashboard/ViewSelector.vue +104 -36
  43. package/src/widgets/Dashboard/VirtualTableSetting.vue +71 -39
  44. package/src/widgets/Dashboard.vue +251 -132
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.230406341",
4
+ "version": "0.1.230406342",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "./importer": "./src/utils/importer.js",
28
28
  "./listpage1": "./src/utils/listpage1.js",
29
+ "./dashboard": "./src/utils/dashboard.js",
29
30
  "./listview": "./src/utils/listview.js",
30
31
  "./preset-selector": {
31
32
  "require": "./src/utils/preset-selector.js",
Binary file
Binary file
Binary file
Binary file
@@ -17,6 +17,8 @@ export default{
17
17
 
18
18
  mixins: [ componentMixin ],
19
19
 
20
+ name: "Grid",
21
+
20
22
  props:{
21
23
  items: Array
22
24
  }
@@ -103,7 +103,7 @@ export default{
103
103
  }
104
104
  },
105
105
 
106
- inject: [ 'listStyle' ],
106
+ inject: [ 'emitRoot', 'listStyle' ],
107
107
 
108
108
  emits: [ 'scroll-end', 'item-click' ],
109
109
 
@@ -114,6 +114,8 @@ export default{
114
114
 
115
115
  itemClass: String,
116
116
 
117
+ uid: String,
118
+
117
119
  items: Array,
118
120
 
119
121
  pinned: Function,
@@ -314,6 +316,8 @@ export default{
314
316
  if(this.scrollTop > this.$refs.scroller.offsetHeight - this.$refs.cont.clientHeight - this.itemHeight){
315
317
  if(!this.isOnEndScroll){
316
318
  this.$emit('scroll-end')
319
+ if(typeof this.emitRoot === 'function')
320
+ this.emitRoot.apply(this, [ 'scroll-end', this.$props ])
317
321
  this.isOnEndScroll = true
318
322
  }
319
323
  }
@@ -0,0 +1,9 @@
1
+ export const component = {
2
+
3
+ type:"BarChart",
4
+
5
+ props:{
6
+ height:200
7
+ }
8
+
9
+ }
@@ -0,0 +1,5 @@
1
+ export const component = {
2
+
3
+ props: {}
4
+
5
+ }
@@ -0,0 +1,7 @@
1
+ export const component = {
2
+
3
+ type:"Doughnut",
4
+
5
+ props:{}
6
+
7
+ }
@@ -0,0 +1,32 @@
1
+ export const component = {
2
+
3
+ type:'Grid',
4
+
5
+ isContainer:true,
6
+
7
+ props:{
8
+
9
+ columns:[
10
+ 'grid-cols-1',
11
+ 'md:grid-cols-2',
12
+ '',
13
+ ''
14
+ ],
15
+
16
+ gap:[
17
+ 'gap-5',
18
+ 'md:gap-5',
19
+ '',
20
+ ''
21
+ ],
22
+
23
+ alignItems:[
24
+ 'items-start',
25
+ 'md:items-start',
26
+ '',
27
+ ''
28
+ ],
29
+
30
+ }
31
+
32
+ }
@@ -0,0 +1,32 @@
1
+ export const component = {
2
+
3
+ type:'Grid',
4
+
5
+ isContainer:true,
6
+
7
+ props:{
8
+
9
+ columns:[
10
+ 'grid-cols-1',
11
+ 'md:grid-cols-3',
12
+ '',
13
+ ''
14
+ ],
15
+
16
+ gap:[
17
+ 'gap-5',
18
+ 'md:gap-5',
19
+ '',
20
+ ''
21
+ ],
22
+
23
+ alignItems:[
24
+ 'items-start',
25
+ 'md:items-start',
26
+ '',
27
+ ''
28
+ ],
29
+
30
+ }
31
+
32
+ }
@@ -0,0 +1,32 @@
1
+ export const component = {
2
+
3
+ type:'Grid',
4
+
5
+ isContainer:true,
6
+
7
+ props:{
8
+
9
+ columns:[
10
+ 'grid-cols-2',
11
+ 'md:grid-cols-4',
12
+ '',
13
+ ''
14
+ ],
15
+
16
+ gap:[
17
+ 'gap-5',
18
+ 'md:gap-5',
19
+ '',
20
+ ''
21
+ ],
22
+
23
+ alignItems:[
24
+ 'items-start',
25
+ 'md:items-start',
26
+ '',
27
+ ''
28
+ ],
29
+
30
+ }
31
+
32
+ }
@@ -0,0 +1,13 @@
1
+ export const component = {
2
+
3
+ type:'Grid',
4
+
5
+ isContainer:true,
6
+
7
+ props:{
8
+ columns:['grid-cols-2', 'md:grid-cols-5', '', ''],
9
+ gap:['gap-5', 'md:gap-5', '', ''],
10
+ alignItems:['items-start', 'md:items-start', '', ''],
11
+ }
12
+
13
+ }
@@ -0,0 +1,10 @@
1
+ export const component = {
2
+
3
+ type:"Metric",
4
+
5
+ props:{
6
+ columnModifier:"sum",
7
+ column2Modifier:"sum"
8
+ }
9
+
10
+ }
@@ -0,0 +1,7 @@
1
+ export const component = {
2
+
3
+ type:"Pie",
4
+
5
+ props:{}
6
+
7
+ }
@@ -0,0 +1,7 @@
1
+ export const component = {
2
+
3
+ type:"PolarArea",
4
+
5
+ props:{}
6
+
7
+ }
@@ -0,0 +1,9 @@
1
+ export const component = {
2
+
3
+ type:"VirtualTable",
4
+
5
+ props:{
6
+ height:[ "h-[50vh]", "md:h-[50vh]", "", "" ]
7
+ }
8
+
9
+ }
@@ -0,0 +1,100 @@
1
+ const {presetToSequelizeList} = require("./preset-selector");
2
+
3
+ const backgroundColors = [
4
+ '#5D9CEC',
5
+ '#A0D468',
6
+ '#FFCE54',
7
+ '#FC6E51',
8
+ '#48CFAD',
9
+ '#AC92EC',
10
+ '#4FC1E9',
11
+ '#FFCE54',
12
+ '#ED5565',
13
+ '#EC87C0'
14
+ ]
15
+
16
+ const getModelFromDatasource = async (datasource, opt) => {
17
+ if(!opt.conn.models[datasource.datasourceUid]){
18
+ const tableColumns = await getSequelizeColumns(datasource.columns, opt)
19
+
20
+ opt.conn.define(datasource.datasourceUid, tableColumns, {
21
+ tableName: `datasource_${datasource.datasourceUid}`
22
+ })
23
+ }
24
+
25
+ return opt.conn.models[datasource.datasourceUid]
26
+ }
27
+
28
+ const getDatasourceItems = async (datasource, opt) => {
29
+
30
+ const Model = await getModelFromDatasource(datasource, opt)
31
+ const config = {
32
+ columns: datasource.columns
33
+ }
34
+ const findOpt = await presetToSequelizeList(datasource, {
35
+ config,
36
+ model: Model,
37
+ conn: opt.conn,
38
+ limit: 100
39
+ })
40
+
41
+ return await Model.findAll({
42
+ ...findOpt,
43
+ raw: true
44
+ })
45
+ }
46
+
47
+ const getSequelizeColumns = async (columns, opt) => {
48
+
49
+ const { DataTypes } = opt.Sequelize
50
+
51
+ const tableColumns = {
52
+ id: {
53
+ type: DataTypes.INTEGER,
54
+ autoIncrement: true,
55
+ primaryKey: true,
56
+ allowNull: false,
57
+ },
58
+ createdAt: { type: DataTypes.DATE },
59
+ updatedAt: { type: DataTypes.DATE },
60
+ }
61
+
62
+ for(let column of columns){
63
+
64
+ let type
65
+ switch(column.type){
66
+ case 'date':
67
+ type = DataTypes.DATE
68
+ break
69
+ case 'number':
70
+ type = DataTypes.BIGINT
71
+ break
72
+
73
+ default:
74
+ type = DataTypes.STRING(column.maxLength ?? 40)
75
+ break
76
+ }
77
+
78
+ tableColumns[column.key] = {
79
+ type
80
+ }
81
+ }
82
+
83
+ return tableColumns
84
+ }
85
+
86
+
87
+ module.exports = {
88
+ getModelFromDatasource,
89
+ getDatasourceItems,
90
+ getSequelizeColumns,
91
+
92
+ backgroundColors,
93
+
94
+ /*loadBarChart,
95
+ loadMetric,
96
+ loadDoughnut,
97
+ loadPie,
98
+ loadPolarArea,
99
+ loadVirtualTable*/
100
+ }
@@ -49,6 +49,7 @@ export default{
49
49
  return {
50
50
  responsive: true,
51
51
  maintainAspectRatio: false,
52
+ borderRadius: 4,
52
53
  plugins: {
53
54
  legend: {
54
55
  display: false // This hides the legend
@@ -69,7 +70,8 @@ export default{
69
70
  },
70
71
  minRotation: 0,
71
72
  maxRotation: 0
72
- }
73
+ },
74
+ stacked: !!this.stacked,
73
75
  },
74
76
  y: {
75
77
  beginAtZero: true,
@@ -82,6 +84,7 @@ export default{
82
84
  return `rgba(255,255,255, .1)`
83
85
  }
84
86
  },
87
+ stacked: !!this.stacked,
85
88
  }
86
89
  },
87
90
  onClick: function(evt, evt2) {
@@ -98,7 +101,7 @@ export default{
98
101
  },
99
102
 
100
103
  yLegends(){
101
- return this.value.yLegends ?? []
104
+ return this.value?.yLegends ?? []
102
105
  }
103
106
 
104
107
  },
@@ -126,10 +129,8 @@ export default{
126
129
 
127
130
  datasourceUid: String,
128
131
 
129
- usePercentage: {
130
- type: Number,
131
- default: false
132
- },
132
+ usePercentage: [ Boolean, Number ],
133
+ stacked: [ Boolean, Number ],
133
134
 
134
135
  barHeight: {
135
136
  type: Number,
@@ -1,19 +1,21 @@
1
1
  <template>
2
2
  <div class="flex flex-col gap-5 p-6">
3
3
 
4
- <div class="flex flex-row items-center">
5
- <label class="flex-1">Datasource</label>
6
- <div>
7
- <Dropdown class="w-[120px]"
8
- :readonly="readonly"
9
- v-model="value.props.datasourceUid"
10
- @change="delete value.props.columns">
11
- <option v-for="obj in datasource"
12
- :value="obj.uid">
13
- {{ obj.name }}
14
- </option>
15
- </Dropdown>
4
+ <div class="flex flex-col gap-1">
5
+ <div class="flex flex-row gap-2">
6
+ <label class="flex-1">Datasource</label>
7
+ <button type="button" class="text-primary"
8
+ @click="previewDatasource(selectedDatasource)">Preview</button>
16
9
  </div>
10
+ <Dropdown class="min-w-[150px]"
11
+ :readonly="readonly"
12
+ v-model="value.props.datasourceUid"
13
+ @change="delete value.props.columns">
14
+ <option v-for="obj in datasource"
15
+ :value="obj.uid">
16
+ {{ obj.name }}
17
+ </option>
18
+ </Dropdown>
17
19
  </div>
18
20
 
19
21
  <div class="flex flex-col gap-1">
@@ -60,9 +62,9 @@
60
62
  </div>
61
63
  <div class="flex-1">
62
64
  <Dropdown v-model="item.key" :readonly="readonly">
63
- <option v-for="column in selectedDatasource?.columns"
65
+ <option v-for="column in selectedDatasourceColumns"
64
66
  :value="column.key">
65
- {{ column.label }}
67
+ {{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
66
68
  </option>
67
69
  </Dropdown>
68
70
  </div>
@@ -111,9 +113,9 @@
111
113
  </div>
112
114
  <div class="flex-1">
113
115
  <Dropdown v-model="item.key">
114
- <option v-for="column in selectedDatasource?.columns"
116
+ <option v-for="column in selectedDatasourceColumns"
115
117
  :value="column.key">
116
- {{ column.label }}
118
+ {{ selectedDatasource.pivot?.enabled ? column.key : column.label }}
117
119
  </option>
118
120
  </Dropdown>
119
121
  </div>
@@ -138,14 +140,9 @@
138
140
  <Switch v-model="value.props.usePercentage" />
139
141
  </div>
140
142
 
141
- <div class="flex flex-row items-center gap-2">
142
- <label class="flex-1">Height</label>
143
- <Dropdown class="w-[100px]"
144
- v-model.number="value.props.barHeight">
145
- <option :value="200">200px</option>
146
- <option :value="300">300px</option>
147
- <option :value="400">400px</option>
148
- </Dropdown>
143
+ <div v-if="value.props.yAxeMultiple" class="flex flex-row items-center gap-2">
144
+ <label class="flex-1">Stacked</label>
145
+ <Switch v-model="value.props.stacked" />
149
146
  </div>
150
147
 
151
148
  </div>
@@ -164,6 +161,14 @@ export default{
164
161
  return this.datasource.find(d => d.uid === this.value.props.datasourceUid)
165
162
  },
166
163
 
164
+ selectedDatasourceColumns(){
165
+ if(!this.selectedDatasource) return []
166
+
167
+ return this.selectedDatasource.pivot?.enabled ?
168
+ this.selectedDatasource.pivot.columns :
169
+ this.selectedDatasource.columns
170
+ },
171
+
167
172
  xAxes(){
168
173
  if(!Array.isArray(this.value.props.xAxes))
169
174
  this.value.props.xAxes = [{ key:"" }]
@@ -188,7 +193,7 @@ export default{
188
193
 
189
194
  },
190
195
 
191
- inject: [ 'appStyle' ],
196
+ inject: [ 'appStyle', 'previewDatasource' ],
192
197
 
193
198
  methods: {
194
199
 
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <Modal ref="modal"
3
+ dismissable="true"
4
+ width="600"
5
+ height="600"
6
+ @dismiss="close">
7
+ <template v-slot:head>
8
+ <div class="relative p-6">
9
+ <h3>Data Preview</h3>
10
+ <div class="absolute top-0 right-0 p-2">
11
+ <button type="button" class="p-2" @click="close">
12
+ <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">
13
+ <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"/>
14
+ </svg>
15
+ </button>
16
+ </div>
17
+ </div>
18
+ </template>
19
+ <div class="flex-1 p-6 flex flex-col">
20
+
21
+ <VirtualTable class="flex-1" :columns="columns" :items="res?.items" />
22
+
23
+ </div>
24
+ </Modal>
25
+ </template>
26
+
27
+ <script>
28
+
29
+ export default{
30
+
31
+ inject: [ 'alert', 'socket' ],
32
+
33
+ props: {
34
+ src: String
35
+ },
36
+
37
+ data(){
38
+ return {
39
+ columns: [],
40
+ datasource: null,
41
+ res: null
42
+ }
43
+ },
44
+
45
+ methods: {
46
+
47
+ close(){
48
+ this.$refs.modal.close()
49
+ },
50
+
51
+ load(){
52
+ this.socket.send(this.src, {
53
+ datasource: this.datasource
54
+ })
55
+ .then(res => {
56
+ this.res = res
57
+
58
+ this.columns = this.datasource.pivot?.enabled ?
59
+ this.datasource.pivot.columns :
60
+ this.datasource.columns
61
+ })
62
+ .catch(err => this.alert(err))
63
+ },
64
+
65
+ open(datasource){
66
+ this.datasource = datasource
67
+ this.$refs.modal.open()
68
+ this.load()
69
+ },
70
+
71
+ }
72
+
73
+ }
74
+
75
+ </script>
76
+
77
+ <style module>
78
+
79
+ .comp{
80
+
81
+ }
82
+
83
+ </style>
@@ -36,7 +36,7 @@
36
36
  :class="dashboardStyle.button"
37
37
  class="flex flex-row items-start gap-2">
38
38
  <button type="button" class="flex-1 text-left" @click="add(datasource)">{{ datasource.name }}</button>
39
- <button type="button" class="py-1" :ref="`btn${idx}`" @click="$refs.contextMenu.open($refs[`btn${idx}`][0], { datasource })">
39
+ <button v-if="contextMenuItems.length > 0" type="button" class="py-1" :ref="`btn${idx}`" @click="$refs.contextMenu.open($refs[`btn${idx}`][0], { datasource })">
40
40
  <svg width="14" height="14" class="fill-text-300 hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M128 64c0-35.39-28.62-64-64-64S0 28.61 0 64s28.62 64 64 64S128 99.39 128 64zM128 256c0-35.39-28.62-64-64-64S0 220.6 0 256s28.62 64 64 64S128 291.4 128 256zM128 448c0-35.39-28.62-64-64-64s-64 28.61-64 64s28.62 64 64 64S128 483.4 128 448z"/></svg>
41
41
  </button>
42
42
  </div>
@@ -44,10 +44,13 @@
44
44
  <ContextMenu ref="contextMenu" position="bottom-right">
45
45
  <template #default="{ context }">
46
46
  <div class="flex flex-col min-w-[200px]">
47
- <button class="w-full p-3 text-left flex flex-row" :class="appStyle.menuItem"
48
- @click="remove(context.datasource)">
49
- {{ $t('Remove') }}
50
- </button>
47
+ <div v-for="item in contextMenuItems">
48
+ <button v-if="item.type === 'remove'" class="w-full p-3 text-left flex flex-row" :class="appStyle.menuItem"
49
+ @click="remove(context.datasource)">
50
+ {{ $t('Remove') }}
51
+ </button>
52
+ </div>
53
+
51
54
  </div>
52
55
  </template>
53
56
  </ContextMenu>
@@ -87,6 +90,17 @@ export default{
87
90
 
88
91
  src: String,
89
92
 
93
+ },
94
+
95
+ computed: {
96
+
97
+ contextMenuItems(){
98
+ return [
99
+ this.removeSrc ? { type:'remove' } : null
100
+ ]
101
+ .filter(_=>_)
102
+ }
103
+
90
104
  },
91
105
 
92
106
  data(){
@@ -35,6 +35,7 @@ export default{
35
35
  return {
36
36
  responsive: true,
37
37
  maintainAspectRatio: true,
38
+ /*animation: false,*/
38
39
  plugins: {
39
40
  legend: {
40
41
  display: false