@mixd-id/web-scaffold 0.2.240702 → 0.2.240704

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 (95) hide show
  1. package/docs/schema/user-action.json +266 -0
  2. package/package.json +6 -2
  3. package/public/assets/dashboard/bar.png +0 -0
  4. package/public/assets/dashboard/doughnut.png +0 -0
  5. package/public/assets/dashboard/metric.png +0 -0
  6. package/public/assets/dashboard/pie.png +0 -0
  7. package/public/assets/dashboard/polar-area.png +0 -0
  8. package/public/assets/dashboard/virtual-table.png +0 -0
  9. package/public/static/dashboard/bar.png +0 -0
  10. package/public/static/dashboard/doughnut.png +0 -0
  11. package/public/static/dashboard/metric.png +0 -0
  12. package/public/static/dashboard/pie.png +0 -0
  13. package/public/static/dashboard/polar-area.png +0 -0
  14. package/public/static/dashboard/virtual-table.png +0 -0
  15. package/src/components/Button.vue +179 -160
  16. package/src/components/Checkbox.vue +0 -1
  17. package/src/components/Datepicker.vue +8 -6
  18. package/src/components/GHeatMaps.vue +317 -0
  19. package/src/components/GmapsDirection.vue +191 -0
  20. package/src/components/Grid.vue +2 -0
  21. package/src/components/HTMLEditor.vue +2 -2
  22. package/src/components/List.vue +384 -308
  23. package/src/components/Modal.vue +2 -3
  24. package/src/components/PresetSelectorFilterItem.vue +15 -2
  25. package/src/components/Switch.vue +3 -0
  26. package/src/components/Tabs.vue +1 -1
  27. package/src/components/TextWithTag.vue +67 -25
  28. package/src/components/Textbox.vue +5 -0
  29. package/src/components/VirtualGrid.vue +224 -228
  30. package/src/components/VirtualTable.vue +46 -28
  31. package/src/configs/dashboard/bar.js +10 -0
  32. package/src/configs/dashboard/collection-1.js +5 -0
  33. package/src/configs/dashboard/doughnut.js +7 -0
  34. package/src/configs/dashboard/gheatmaps.js +9 -0
  35. package/src/configs/dashboard/grid-2.js +34 -0
  36. package/src/configs/dashboard/grid-3.js +34 -0
  37. package/src/configs/dashboard/grid-4.js +34 -0
  38. package/src/configs/dashboard/grid.js +15 -0
  39. package/src/configs/dashboard/metric.js +10 -0
  40. package/src/configs/dashboard/pie.js +7 -0
  41. package/src/configs/dashboard/polar-area.js +7 -0
  42. package/src/configs/dashboard/virtual-table.js +9 -0
  43. package/src/defs/dashboard-preset.js +22 -0
  44. package/src/index.js +37 -23
  45. package/src/mixin/ready-state.js +37 -0
  46. package/src/stores/datasource.js +11 -0
  47. package/src/themes/default/index.js +1 -1
  48. package/src/utils/dashboard.js +1080 -0
  49. package/src/utils/event-bus.js +8 -0
  50. package/src/utils/helpers.js +56 -8
  51. package/src/utils/helpers.mjs +35 -1
  52. package/src/utils/preset-selector.js +5 -2
  53. package/src/utils/preset-selector.mjs +23 -13
  54. package/src/widgets/BotEditor/BotEditorActions.vue +162 -0
  55. package/src/widgets/BotEditor.vue +228 -0
  56. package/src/widgets/Dashboard/BarChart.vue +330 -0
  57. package/src/widgets/Dashboard/BarChartSetting.vue +317 -0
  58. package/src/widgets/Dashboard/DatasourceFilterSharing.vue +93 -0
  59. package/src/widgets/Dashboard/DatasourcePreview.vue +93 -0
  60. package/src/widgets/Dashboard/DatasourceSelector.vue +122 -0
  61. package/src/widgets/Dashboard/Doughnut.vue +157 -0
  62. package/src/widgets/Dashboard/DoughnutSetting.vue +196 -0
  63. package/src/widgets/Dashboard/GHeatMapsSetting.vue +108 -0
  64. package/src/widgets/Dashboard/InteractionEdit.vue +228 -0
  65. package/src/widgets/Dashboard/Metric.vue +76 -0
  66. package/src/widgets/Dashboard/MetricSetting.vue +174 -0
  67. package/src/widgets/Dashboard/Pie.vue +139 -0
  68. package/src/widgets/Dashboard/PieSetting.vue +247 -0
  69. package/src/widgets/Dashboard/PolarArea.vue +159 -0
  70. package/src/widgets/Dashboard/PolarAreaSetting.vue +195 -0
  71. package/src/widgets/Dashboard/SharingModal.vue +116 -0
  72. package/src/widgets/Dashboard/ViewSelector.vue +183 -0
  73. package/src/widgets/Dashboard/VirtualColumnEdit.vue +97 -0
  74. package/src/widgets/Dashboard/VirtualTableSetting.vue +234 -0
  75. package/src/widgets/Dashboard.vue +1773 -0
  76. package/src/widgets/PresetBar.vue +136 -175
  77. package/src/widgets/PresetBarPivot.vue +186 -0
  78. package/src/widgets/PresetSelector.vue +2 -2
  79. package/src/widgets/UserActionBuilder/UserActionCondition.vue +99 -0
  80. package/src/widgets/UserActionBuilder/UserActionConsole.vue +77 -0
  81. package/src/widgets/UserActionBuilder/UserActionItem.vue +166 -58
  82. package/src/widgets/UserActionBuilder/UserActionOutput.vue +35 -9
  83. package/src/widgets/UserActionBuilder/UserActionOutputDelay.vue +27 -0
  84. package/src/widgets/UserActionBuilder/UserActionOutputLog.vue +28 -0
  85. package/src/widgets/UserActionBuilder/UserActionOutputReply.vue +135 -0
  86. package/src/widgets/UserActionBuilder/UserActionProps.vue +213 -0
  87. package/src/widgets/UserActionBuilder.vue +68 -199
  88. package/src/widgets/WebPageBuilder4/GridSetting.vue +123 -73
  89. package/src/widgets/WebPageBuilder4/HeightSetting.vue +14 -11
  90. package/src/widgets/WebPageBuilder4/MarginSetting.vue +4 -1
  91. package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +12 -4
  92. package/src/widgets/WebPageBuilder4/PaddingSetting.vue +4 -0
  93. package/src/widgets/WebPageBuilder4/TreeView.vue +6 -3
  94. package/src/widgets/WebPageBuilder4/TreeViewItem.vue +32 -58
  95. package/tailwind.config.js +2 -2
@@ -0,0 +1,8 @@
1
+ // eventBus.js
2
+ import mitt from 'mitt'
3
+
4
+ const emitter = mitt()
5
+
6
+ export const useEmitter = () => {
7
+ return emitter
8
+ }
@@ -3,6 +3,7 @@ const fs = require("fs");
3
3
  const { Op } = require('sequelize')
4
4
  const axios = require('axios')
5
5
  const dayjs = require('dayjs')
6
+ const { camelCase } = require('lodash')
6
7
 
7
8
 
8
9
  const ceil = (num, precision = 0) => {
@@ -140,13 +141,14 @@ const strSlug = (title, separator) => {
140
141
  return title.replace(new RegExp('^[' + separator + '\\s]+|[' + separator + '\\s]+$', 'g'),'');
141
142
  }
142
143
 
143
- const strVars = (text, vars, opt = { emptyUndefined:true }) => {
144
-
145
- (text.match(/\{.*?(?=\})\}/gi) ?? []).forEach((match) => {
146
- const key = match.substring(1, match.length - 1)
147
- const value = vars[key] ?? (opt?.emptyUndefined ? '' : `{${key}}`)
148
- text = text.replace(match, value)
149
- })
144
+ const strVars = (text, vars = {}, opt = { emptyUndefined:true }) => {
145
+ if(text){
146
+ (text.match(/\{.*?(?=\})\}/gi) ?? []).forEach((match) => {
147
+ const key = match.substring(1, match.length - 1)
148
+ const value = vars[key] ?? (opt?.emptyUndefined ? '' : `{${key}}`)
149
+ text = text.replace(match, value)
150
+ })
151
+ }
150
152
 
151
153
  return text
152
154
  }
@@ -260,7 +262,7 @@ const unflatten = (flatObject) => {
260
262
  }
261
263
 
262
264
  const accessNestedObject = function(obj, path) {
263
- if(!obj || typeof path !== 'string') return undefined
265
+ if(!obj || typeof path !== 'string') return
264
266
 
265
267
  const keys = path.split('.');
266
268
  let nestedObj = obj;
@@ -277,6 +279,43 @@ const accessNestedObject = function(obj, path) {
277
279
  return nestedObj;
278
280
  }
279
281
 
282
+ const accessNestedSequelize = async(obj, path, opt = { defaultValue:'' }) => {
283
+ if(!obj || typeof path !== 'string') return
284
+
285
+ const keys = path.split('.');
286
+ let value = obj;
287
+
288
+ for (let i in keys) {
289
+ const key = keys[i]
290
+ const hasNext = i < keys.length - 1
291
+
292
+ if(hasNext){
293
+
294
+ if(!value[key]){
295
+ try{
296
+ value = await value[camelCase(`get-${key}`)]()
297
+ }
298
+ catch(e){}
299
+ }
300
+ else{
301
+ value = value[key]
302
+ }
303
+
304
+ if(!value){
305
+ return
306
+ }
307
+ }
308
+
309
+ else{
310
+ value = key in value.dataValues ?
311
+ value[key] :
312
+ opt.defaultValue
313
+ }
314
+ }
315
+
316
+ return value;
317
+ }
318
+
280
319
  const createObjectFromPath = (obj, path, value) => {
281
320
  const keys = path.split('.');
282
321
 
@@ -524,8 +563,16 @@ const dayTimeRange = (params, value) => {
524
563
  })
525
564
  }
526
565
 
566
+ function capitalize(str) {
567
+ return (str ?? '')
568
+ .toString()
569
+ .split(' ')
570
+ .map(_ => _.charAt(0).toUpperCase() + _.slice(1).toLowerCase())
571
+ .join(' ')
572
+ }
527
573
 
528
574
  module.exports = {
575
+ capitalize,
529
576
  ceil,
530
577
  floor,
531
578
  ftWildcard,
@@ -544,6 +591,7 @@ module.exports = {
544
591
  getPresetSortWhereParams,
545
592
  unflatten,
546
593
  accessNestedObject,
594
+ accessNestedSequelize,
547
595
  createObjectFromPath,
548
596
  generateStylesheet,
549
597
  hexToRgb,
@@ -360,7 +360,40 @@ function applyDatasourceReplacer(value, datasource){
360
360
  return value
361
361
  }
362
362
 
363
+ function capitalize(str) {
364
+ return str.replace(/\b\w/g, function(char) {
365
+ return char.toUpperCase();
366
+ });
367
+ }
368
+
369
+ const round = (num, precision = 0) => {
370
+ var p = Math.pow(10, precision)
371
+ var n = (num * p) * (1 + Number.EPSILON)
372
+ return Math.round(n) / p
373
+ }
374
+
375
+ let invokeAfterIdleStore = []
376
+ const invokeAfterIdle = (callback, delay = 1300) => {
377
+ let timeoutId
378
+
379
+ return function(){
380
+ if(invokeAfterIdleStore.includes(callback))
381
+ return
382
+
383
+ invokeAfterIdleStore.push(callback)
384
+
385
+ window.clearTimeout(timeoutId)
386
+ timeoutId = window.setTimeout(() => {
387
+ callback.apply(this, arguments)
388
+ invokeAfterIdleStore.splice(invokeAfterIdleStore.indexOf(callback), 1)
389
+ }, delay)
390
+ }
391
+ }
392
+
393
+
363
394
  export {
395
+ capitalize,
396
+ round,
364
397
  downsizeImage,
365
398
  hexToRgb,
366
399
  rgbToHex,
@@ -382,7 +415,8 @@ export {
382
415
  createFormData,
383
416
  unslugAndCapitalize,
384
417
  applyDatasourceReplacer,
385
- strVars
418
+ strVars,
419
+ invokeAfterIdle
386
420
  }
387
421
 
388
422
  function observeInit(){
@@ -925,9 +925,11 @@ const presetToSequelizeList = async(preset = {}, {
925
925
  order:initialOrder
926
926
  }) => {
927
927
 
928
+ const updatedAtField = model.rawAttributes['updatedAt'] ?? model.rawAttributes['updated_at']
929
+
928
930
  if(!initialOrder){
929
931
  initialOrder = [
930
- [ 'updatedAt', 'desc' ],
932
+ ...(updatedAtField ? [[ updatedAtField.fieldName, 'desc' ]] : []),
931
933
  [ 'id', 'desc' ],
932
934
  ]
933
935
  }
@@ -1036,7 +1038,8 @@ const presetToSequelizeList = async(preset = {}, {
1036
1038
  ...replacements,
1037
1039
  ...filterReplacements,
1038
1040
  ...searchReplacements
1039
- ]
1041
+ ],
1042
+ itemsPerPage
1040
1043
  }
1041
1044
  }
1042
1045
  }
@@ -1,3 +1,5 @@
1
+ import md5 from "md5";
2
+
1
3
  const sortsFn = function(a, b, sorts, index){
2
4
 
3
5
  const sort = sorts[index]
@@ -31,24 +33,31 @@ const pickColumns = function(columns, keys){
31
33
  return picked
32
34
  }
33
35
 
36
+ const getPresetUid = function(extra = ''){
37
+ return md5('preset-' + new Date().getTime() + extra)
38
+ }
39
+
34
40
  const setupConfig = (config) => {
35
41
 
36
42
  if(Array.isArray(config.presets)){
37
43
  for(let idx in config.presets){
38
- if(!Array.isArray(config.presets[idx].columns)){
39
- config.presets[idx].columns = []
44
+ if(!Array.isArray(config.presets[idx].params.columns)){
45
+ config.presets[idx].params.columns = []
40
46
  }
41
47
 
42
- if(config.presets[idx].columns[0] && typeof config.presets[idx].columns[0] === 'string'){
43
- config.presets[idx].columns = pickColumns(config.columns ?? [], config.presets[idx].columns)
48
+ if(config.presets[idx].params.columns[0] && typeof config.presets[idx].params.columns[0] === 'string'){
49
+ config.presets[idx].params.columns = pickColumns(config.params.columns ?? [], config.presets[idx].params.columns)
44
50
  }
45
51
 
46
- if(!config.presets[idx].view)
47
- config.presets[idx].view = 'table'
52
+ if(!config.presets[idx].params.view)
53
+ config.presets[idx].params.view = 'table'
54
+
55
+ if(!config.presets[idx].uid)
56
+ config.presets[idx].uid = getPresetUid(idx)
48
57
  }
49
58
 
50
- if(!config.presetIdx && config.presets.length > 0){
51
- config.presetIdx = 0
59
+ if(!config.params.presetIdx && config.presets.length > 0){
60
+ config.params.presetIdx = config.presets[0].uid
52
61
  }
53
62
  }
54
63
 
@@ -147,11 +156,11 @@ const generatePivotColumns = (preset, items) => {
147
156
  }
148
157
  }
149
158
 
150
- (preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
159
+ /*(preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
151
160
  .forEach(_ => {
152
161
  _.visible = false
153
162
  pivotColumns.push(_)
154
- })
163
+ })*/
155
164
 
156
165
  preset.pivot.columns = pivotColumns
157
166
 
@@ -177,9 +186,10 @@ const generateTotalColumns = (preset, items) => {
177
186
  }
178
187
 
179
188
  export {
180
- sortsFn,
189
+ getPresetUid,
190
+ generatePivotColumns,
191
+ generateTotalColumns,
181
192
  pickColumns,
182
193
  setupConfig,
183
- generatePivotColumns,
184
- generateTotalColumns
194
+ sortsFn,
185
195
  }
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <div v-if="!action" :class="$style.comp" class="flex items-center justify-center">
3
+ <p class="text-text-400">No action selected</p>
4
+ </div>
5
+
6
+ <div v-else class="flex-1 flex flex-col">
7
+
8
+ <div class="flex flex-row items-center p-2 pt-3 px-6 bg-base-300 border-b-[1px] border-text-50">
9
+ <div class="flex-1">
10
+ <strong>{{ action.name }}</strong>
11
+ </div>
12
+ <Button ref="saveBtn" :state="canSave ? 1 : -1" class="w-[80px] rounded-full" @click="save">Save</Button>
13
+ </div>
14
+
15
+ <div class="flex-1 flex flex-row">
16
+ <div class="flex-1 p-12 overflow-auto">
17
+ <UserActionItem :config="config"
18
+ :item="action"
19
+ :removable="false"
20
+ @select="(item) => config.selectedUid = item.uid" />
21
+ </div>
22
+
23
+ <div :style="sidebarStyle"
24
+ class="relative flex flex-col border-l-[1px] border-text-50 panel-400 overflow-hidden">
25
+ <div :class="$style.resize1"
26
+ @mousedown="(e) => $util.dragResize(e, resize1)"></div>
27
+
28
+ <UserActionProps ref="userActionProps" :instance="selectedItem" />
29
+
30
+ </div>
31
+ </div>
32
+
33
+
34
+ </div>
35
+ </template>
36
+
37
+ <script>
38
+
39
+ import UserActionItem from "../UserActionBuilder/UserActionItem.vue";
40
+ import UserActionProps from "../UserActionBuilder/UserActionProps.vue";
41
+
42
+ const findComponents = (items, uid) => {
43
+ for (let item of items) {
44
+ if (item.uid === uid)
45
+ return item
46
+
47
+ if (item.items) {
48
+ const component = findComponents(item.items, uid)
49
+ if (component)
50
+ return component
51
+ }
52
+ }
53
+ }
54
+
55
+ export default{
56
+ components: {UserActionProps, UserActionItem},
57
+
58
+ computed: {
59
+
60
+ canSave(){
61
+ return JSON.stringify(this.action) !== this.initialAction
62
+ },
63
+
64
+ selectedItem(){
65
+ if (!this.config.selectedUid) return
66
+ if (!this.action) return
67
+
68
+ if(this.action.uid === this.config.selectedUid)
69
+ return this.action
70
+ return findComponents(this.action.items ?? [], this.config.selectedUid)
71
+ },
72
+
73
+ sidebar(){
74
+ if (!this.config.actionSidebar)
75
+ this.config.actionSidebar = {
76
+ open: true,
77
+ width: 300
78
+ }
79
+
80
+ return this.config.actionSidebar
81
+ },
82
+
83
+ sidebarStyle() {
84
+ return {
85
+ width: this.sidebar.width + 'px'
86
+ }
87
+ },
88
+
89
+ },
90
+
91
+ data(){
92
+ return {
93
+ action: null,
94
+ initialAction: null,
95
+ }
96
+ },
97
+
98
+ inject: [ 'socket' ],
99
+
100
+ props: {
101
+
102
+ config: Object,
103
+ controller: String,
104
+
105
+ },
106
+
107
+ methods: {
108
+
109
+ load(uid){
110
+ if(!uid) return
111
+
112
+ this.socket.send(`${this.controller}.open-action`, { uid })
113
+ .then(_ => {
114
+ this.action = _.item
115
+ this.initialAction = JSON.stringify(this.action)
116
+ })
117
+ },
118
+
119
+ resize1(w) {
120
+ if (this.sidebar.width - w >= 200 && this.sidebar.width - w <= 600) {
121
+ this.sidebar.width -= w
122
+ }
123
+ },
124
+
125
+ save(){
126
+ this.$refs.saveBtn.setState(2)
127
+ this.socket.send(`${this.controller}.save-action`, {
128
+ item: this.action
129
+ })
130
+ .then(_ => this.initialAction = JSON.stringify(this.action))
131
+ .catch(err => this.alert(err))
132
+ .finally(_ => this.$refs.saveBtn?.resetState())
133
+ }
134
+
135
+ },
136
+
137
+ watch: {
138
+
139
+ '$route.query.actionUid': {
140
+ immediate: true,
141
+ handler(to){
142
+ this.load(to)
143
+ }
144
+ }
145
+
146
+ }
147
+
148
+ }
149
+
150
+ </script>
151
+
152
+ <style module>
153
+
154
+ .comp{
155
+ @apply flex-1;
156
+ }
157
+
158
+ .resize1 {
159
+ @apply w-[3px] cursor-ew-resize absolute top-0 left-0 bottom-0;
160
+ }
161
+
162
+ </style>
@@ -0,0 +1,228 @@
1
+ <template>
2
+ <div v-if="cConfig" :class="$style.comp">
3
+
4
+ <div :style="sidebarStyle"
5
+ class="relative flex flex-col border-r-[1px] border-text-50 panel-400 overflow-hidden">
6
+
7
+ <div v-if="page !== 'Actions'" class="flex-1 flex flex-col">
8
+ <div class="p-5">
9
+ <h5>Bot Settings</h5>
10
+ <br />
11
+ </div>
12
+
13
+ <div class="flex-1">
14
+
15
+ <div class="flex flex-col divide-y divide-text-50 border-y-[1px] border-text-50">
16
+ <router-link :to="{ query:{ t:'actions' } }" type="button" class="p-3 px-5 text-left">Actions</router-link>
17
+ <router-link :to="{ query:{ t:'knowledge' } }" type="button" class="p-3 px-5 text-left">Knowledge</router-link>
18
+ <router-link :to="{ query:{ t:'classifications' } }" type="button" class="p-3 px-5 text-left">Classifications</router-link>
19
+ <router-link :to="{ query:{ t:'settings' } }" type="button" class="p-3 px-5 text-left">Settings</router-link>
20
+ </div>
21
+
22
+ </div>
23
+ </div>
24
+
25
+ <div v-else-if="page === 'Actions'" class="flex-1 flex flex-col">
26
+ <div class="p-5 flex flex-row gap-2">
27
+ <button type="button" @click="$router.replace({ query:{} })">
28
+ <svg width="16" height="16" class="fill-text" 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="M447.1 256C447.1 273.7 433.7 288 416 288H109.3l105.4 105.4c12.5 12.5 12.5 32.75 0 45.25C208.4 444.9 200.2 448 192 448s-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25l160-160c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L109.3 224H416C433.7 224 447.1 238.3 447.1 256z"/></svg>
29
+ </button>
30
+ <h5>Actions</h5>
31
+ </div>
32
+
33
+ <br />
34
+
35
+ <ListItem :items="actions"
36
+ container-class="divide-y divide-text-50"
37
+ @reorder="(from, to) => { actions.splice(to, 0, actions.splice(from, 1)[0]); }">
38
+ <template v-slot="{ item }">
39
+ <div class="p-3 hover:bg-base-500 flex flex-row gap-3 items-center">
40
+ <div data-reorder>
41
+ <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>
42
+ </div>
43
+ <label class="flex-1 text-ellipsis overflow-hidden whitespace-nowrap"
44
+ @click="$router.push({ query:{ t:'actions', actionUid:item.uid } })">
45
+ {{ item.name }}
46
+ </label>
47
+ <button type="button" @click="">
48
+ <svg width="14" height="14" class="fill-text-300 hover:fill-red-600" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/></svg>
49
+ </button>
50
+ </div>
51
+ </template>
52
+ </ListItem>
53
+
54
+ </div>
55
+
56
+ <div class="flex flex-col border-t-[1px] border-text-50 relative" :style="bottombarStyle">
57
+ <div :class="$style.resize2"
58
+ @mousedown="(e) => $util.dragResize(e, resize2)"></div>
59
+
60
+ <UserActionConsole class="flex-1"
61
+ ref="console"
62
+ @test-message="testMessage"
63
+ @test-reset="testReset" />
64
+
65
+ </div>
66
+
67
+ <div :class="$style.resize1"
68
+ @mousedown="(e) => $util.dragResize(e, resize1)"></div>
69
+ </div>
70
+
71
+ <div v-if="page" class="flex-1 overflow-y-auto flex flex-col">
72
+
73
+ <component :is="`BotEditor${page}`"
74
+ :config="config"
75
+ :controller="controller" />
76
+
77
+ </div>
78
+
79
+ </div>
80
+ </template>
81
+
82
+ <script>
83
+
84
+ import {capitalize} from "../utils/helpers.mjs";
85
+ import BotEditorActions from "./BotEditor/BotEditorActions.vue";
86
+ import VirtualGrid from "../components/VirtualGrid.vue";
87
+ import UserActionConsole from "./UserActionBuilder/UserActionConsole.vue";
88
+
89
+
90
+ export default{
91
+
92
+ components: {
93
+ UserActionConsole,
94
+ VirtualGrid,
95
+ BotEditorActions,
96
+ },
97
+
98
+ inject: [ 'alert', 'confirm', 'socket', 'toast' ],
99
+
100
+ computed: {
101
+
102
+ bottombar(){
103
+ if (!this.cConfig.bottombar)
104
+ this.cConfig.bottombar = {
105
+ open: true,
106
+ height: 240
107
+ }
108
+
109
+ return this.cConfig.bottombar
110
+ },
111
+
112
+ bottombarStyle(){
113
+ return {
114
+ height: !this.bottombar.open ? 0 : this.bottombar.height + 'px'
115
+ }
116
+ },
117
+
118
+ cConfig(){
119
+ return this.config
120
+ },
121
+
122
+ sidebar() {
123
+ if (!this.cConfig.sidebar || !('open' in this.cConfig.sidebar))
124
+ this.cConfig.sidebar = {
125
+ open: true,
126
+ width: 360
127
+ }
128
+
129
+ return this.cConfig.sidebar
130
+ },
131
+
132
+ sidebarStyle() {
133
+ return {
134
+ width: !this.sidebar.open ? 0 : this.sidebar.width + 'px'
135
+ }
136
+ },
137
+
138
+ },
139
+
140
+ data(){
141
+ return {
142
+ actions: null,
143
+ page: '',
144
+ }
145
+ },
146
+
147
+ methods: {
148
+
149
+ load(){
150
+
151
+ },
152
+
153
+ loadActions(){
154
+ this.socket.send(`${this.controller}.load-actions`, {})
155
+ .then(_ => {
156
+ this.actions = _.items
157
+ })
158
+ },
159
+
160
+ resize1(w) {
161
+ if (this.sidebar.width + w >= 200 && this.sidebar.width + w <= 600) {
162
+ this.sidebar.width += w
163
+ }
164
+ },
165
+
166
+ resize2(_, h) {
167
+ if (this.bottombar.height - h >= 200 && this.bottombar.height - h <= 400) {
168
+ this.bottombar.height -= h
169
+ }
170
+ },
171
+
172
+ testMessage(){
173
+
174
+ },
175
+
176
+ testReset(){
177
+
178
+ },
179
+
180
+ },
181
+
182
+ props: {
183
+
184
+ config: Object,
185
+ configSrc: String,
186
+
187
+ controller: String,
188
+
189
+ },
190
+
191
+ watch: {
192
+
193
+ '$route.query.t': {
194
+ immediate: true,
195
+ handler(to){
196
+ this.page = to ? capitalize(to) : ''
197
+ }
198
+ },
199
+
200
+ page: {
201
+ immediate: true,
202
+ handler(to){
203
+ if(this[`load${to}`])
204
+ this[`load${to}`]()
205
+ }
206
+ }
207
+
208
+ }
209
+
210
+ }
211
+
212
+ </script>
213
+
214
+ <style module>
215
+
216
+ .comp{
217
+ @apply flex flex-row;
218
+ }
219
+
220
+ .resize1 {
221
+ @apply w-[3px] cursor-ew-resize absolute top-0 right-0 bottom-0;
222
+ }
223
+
224
+ .resize2 {
225
+ @apply h-[3px] cursor-n-resize absolute top-0 right-0 left-0 bg-red-500;
226
+ }
227
+
228
+ </style>