waibu-db 2.12.4 → 2.12.6

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.
@@ -39,19 +39,20 @@
39
39
  "dataValue": "Data value",
40
40
  "suppressedError": "Error occured and suppressed. Please check error log for details",
41
41
  "op": {
42
- "equals": "Equals",
43
- "notEquals": "Not Equals",
44
- "greaterThan": "Greater Than",
45
- "greaterThanOrEquals": "Greater Than or Equals",
46
- "lessThan": "Less Than",
47
- "lessThanOrEquals": "Less Than or Equals",
48
- "in": "Includes",
49
- "notIn": "Not Includes",
50
- "contains": "Contains",
51
- "notContains": "Not Contains",
52
- "startsWith": "Starts With",
53
- "notStartsWith": "Not Starts With",
54
- "endsWith": "Ends With",
55
- "notEndsWith": "Not Ends With"
42
+ "eq": "=",
43
+ "neq": "",
44
+ "gt": ">",
45
+ "gte": "",
46
+ "lt": "<",
47
+ "lte": "",
48
+ "between": "between",
49
+ "in": "includes",
50
+ "!in": "not includes",
51
+ "contains": "contains",
52
+ "!contains": "not contains",
53
+ "starts": "starts with",
54
+ "!starts": "not starts with",
55
+ "ends": "ends with",
56
+ "!ends": "not ends with"
56
57
  }
57
58
  }
@@ -39,19 +39,20 @@
39
39
  "dataValue": "Nilai data",
40
40
  "suppressedError": "Kesalahan terjadi dan tidak ditampilkan. Silahkan cek log kesalahan untuk detilnya",
41
41
  "op": {
42
- "equals": "Sama Dengan",
43
- "notEquals": "Tidak Sama Dengan",
44
- "greaterThan": "Lebih Besar Dari",
45
- "greaterThanOrEquals": "Lebih Besar Dari atau Sama Dengan",
46
- "lessThan": "Lebih Kecil Dari",
47
- "lessThanOrEquals": "Lebih Kecil Dari atau Sama Dengan",
48
- "in": "Termasuk",
49
- "notIn": "Tidak Termasuk",
50
- "contains": "Mengandung",
51
- "notContains": "Tidak Mengandung",
52
- "startsWith": "Dimulai Dengan",
53
- "notStartsWith": "Tidak Dimulai Dengan",
54
- "endsWith": "Diakhiri Dengan",
55
- "notEndsWith": "Tidak Diakhiri Dengan"
42
+ "eq": "=",
43
+ "neq": "",
44
+ "gt": ">",
45
+ "gte": "",
46
+ "lt": "<",
47
+ "lte": "",
48
+ "between": "between",
49
+ "in": "termasuk",
50
+ "!in": "tidak termasuk",
51
+ "contains": "mengandung",
52
+ "!contains": "tidak mengandung",
53
+ "starts": "dimulai dengan",
54
+ "!starts": "tidak dimulai dengan",
55
+ "ends": "diakhiri dengan",
56
+ "!ends": "tidak diakhiri dengan"
56
57
  }
57
58
  }
@@ -49,7 +49,7 @@ async function btnColumns () {
49
49
  this.params.attr.autoClose = 'outside'
50
50
  this.params.attr.triggerColor = this.params.attr.color
51
51
  this.params.attr.menuDir = this.params.attr.menuDir ?? 'end'
52
- this.params.attr.menuMax = this.params.attr.menuMax ?? '10'
52
+ this.params.attr.menuMax = this.params.attr.menuMax ?? '20'
53
53
  const html = [...items]
54
54
  this.params.html = await this.component.buildTag({ tag: 'dropdown', attr: this.params.attr, html: html.join('\n') })
55
55
  this.params.noTag = true
@@ -27,7 +27,8 @@ async function pagination () {
27
27
  }
28
28
  let { count, limit, page } = attrToObject(this.params.attr.options)
29
29
  count = count ?? get(this, 'component.locals.list.count', 0)
30
- if (count === 0) {
30
+ const data = get(this, 'component.locals.list.data', [])
31
+ if (count === 0 || data.length === 0) {
31
32
  this.params.noTag = true
32
33
  this.params.html = ''
33
34
  return
@@ -5,6 +5,7 @@ async function query () {
5
5
 
6
6
  return class WdbQuery extends WdbBase {
7
7
  build = async () => {
8
+ const { req } = this.component
8
9
  const { generateId } = this.app.lib.aneka
9
10
  const { jsonStringify } = this.app.waibuMpa
10
11
  const { find, get, without, isEmpty, filter, upperFirst } = this.app.lib._
@@ -24,27 +25,38 @@ async function query () {
24
25
  if (!fields.includes(f)) continue
25
26
  const prop = find(schema.properties, { name: f })
26
27
  const ops = []
27
- if (['float', 'double', 'integer', 'smallint'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
28
- else if (['datetime', 'date', 'time'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
28
+ if (['float', 'double', 'integer', 'smallint'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between')
29
+ else if (['datetime', 'date', 'time'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'in')
29
30
  else if (['boolean'].includes(prop.type)) ops.push('eq', 'neq')
30
31
  else ops.push('eq', 'neq', 'in', 'contains', 'starts', 'ends', '!in', '!contains', '!starts', '!ends')
31
32
  if (ops.length === 0) continue
32
- const sels = ops.map(o => `<c:option>${o}</c:option>`)
33
- models.push(`${f}Op: 'eq'`, `${f}Val: ''`)
33
+ const sels = ops.map(o => `<c:option value="${o}">${req.t('op.' + o)}</c:option>`)
34
+ models.push(`${f}Op: 'eq'`, `${f}Val: ''`, `${f}Val2: ''`)
34
35
  const label = this.component.req.t(get(schema, `view.label.${f}`, `field.${f}`))
35
- columns.push(`
36
+ const items = [`
36
37
  <c:grid-col col="4-md" flex="align-items:center">
37
38
  <c:form-check x-model="selected" t:label="${label}" value="${f}" />
38
39
  </c:grid-col>
39
- <c:grid-col col="3-md">
40
+ <c:grid-col col="2-md">
40
41
  <c:form-select x-model="${f}Op">
41
42
  ${sels.join('\n')}
42
43
  </c:form-select>
43
44
  </c:grid-col>
44
- <c:grid-col col="5-md">
45
- <c:form-input x-model="${f}Val" />
46
- </c:grid-col>
47
- `)
45
+ <c:grid-col col="6-md">
46
+ <c:grid-row gutter="1"><c:grid-col>`]
47
+ if (prop.type === 'datetime') {
48
+ items.push(`<c:form-datetime x-model="${f}Val" />`)
49
+ } else {
50
+ items.push(`<c:form-input x-model="${f}Val" />`)
51
+ }
52
+ items.push(`</c:grid-col><c:grid-col x-show="${f}Op === 'between'">`)
53
+ if (prop.type === 'datetime') {
54
+ items.push(`<c:form-datetime x-model="${f}Val2" wrapper-margin="start-2"/>`)
55
+ } else {
56
+ items.push(`<c:form-input x-model="${f}Val2" wrapper-margin="start-2" />`)
57
+ }
58
+ items.push('</c:grid-col></c:grid-row></c:grid-col>')
59
+ columns.push(items.join('\n'))
48
60
  }
49
61
  this.params.noTag = true
50
62
  const container = this.params.attr.modal ? 'modal' : 'drawer'
@@ -61,40 +73,50 @@ async function query () {
61
73
  ${models.join(',\n')},
62
74
  ops: { eq: ':', neq: ':-', gt: ':>', gte: ':>=', lt: ':<', lte: ':<=' },
63
75
  opsIn (v, neg) { return ':' + (neg ? '-' : '') + '[' + this.expandArray(v) + ']' },
76
+ opsBetween (v, v2, neg) { return ':' + (neg ? '-' : '') + '{' + this.expandArray(v) + ',' + this.expandArray(v2) + '}' },
64
77
  opsExt (v, neg, ext) {
65
78
  let prefix = (neg ? '-' : '') + '~'
66
79
  if (ext) prefix += ext
67
80
  return ':' + prefix + '\\'' + v + '\\''
68
81
  },
69
- initBuilder () {
82
+ parse () {
70
83
  this.builder = document.getElementById('${id}').value
71
84
  if (!this.builder.includes(':')) this.builder = ''
72
85
  if (_.isEmpty(this.builder)) return
73
86
  const tokens = _.merge({}, this.ops, {
74
87
  in: ':[',
88
+ between: ':{',
75
89
  contains: ':~',
76
90
  starts: ':~^',
77
91
  ends: ':~$$',
78
92
  '!in': ':-[',
93
+ '!between': ':-{',
79
94
  '!contains': ':-~',
80
95
  '!starts': ':-~^',
81
96
  '!ends': ':-~$$'
82
97
  })
83
98
  for (const part of this.builder.split('+')) {
84
- let [f, opv] = part.split(':')
85
- opv = ':' + opv
99
+ let [f, ...opv] = part.split(':')
100
+ opv = ':' + opv.join(':')
86
101
  this.selected.push(f)
87
102
  let op
88
103
  let val
89
104
  _.each(tokens, (v, k) => {
90
105
  if (opv.slice(0, v.length) === v) {
91
106
  op = k
92
- val = opv.slice(v.length).replaceAll('[', '').replaceAll(']', '').replaceAll('\\'', '')
107
+ val = opv.slice(v.length).replaceAll('[', '').replaceAll('{', '').replaceAll(']', '').replaceAll('}', '').replaceAll('\\'', '')
93
108
  }
94
109
  })
110
+ console.log(op, val)
95
111
  if (_.isEmpty(op)) continue
96
112
  this[f + 'Op'] = op
97
- this[f + 'Val'] = val
113
+ if (op === 'between') {
114
+ const vals = val.split(',')
115
+ this[f + 'Val'] = vals[0]
116
+ this[f + 'Val2'] = vals[1]
117
+ } else {
118
+ this[f + 'Val'] = val
119
+ }
98
120
  }
99
121
  },
100
122
  expandArray (val = '') {
@@ -109,10 +131,14 @@ async function query () {
109
131
  for (const sel of this.selected) {
110
132
  const key = this[sel + 'Op']
111
133
  let val = this[sel + 'Val']
134
+ let val2 = this[sel + 'Val2']
112
135
  if (_.isEmpty(val)) continue
136
+ if (key === 'between' && _.isEmpty(val2)) continue
113
137
  let item
114
138
  if (key === 'in') item = this.opsIn(val)
115
139
  else if (key === '!in') item = this.opsIn(val, true)
140
+ else if (key === 'between') item = this.opsBetween(val, val2, false)
141
+ else if (key === '!between') item = this.opsBetween(val, val2, true)
116
142
  else if (key === 'contains') item = this.opsExt(val)
117
143
  else if (key === '!contains') item = this.opsExt(val, true)
118
144
  else if (key === 'starts') item = this.opsExt(val, false, '^')
@@ -137,12 +163,13 @@ async function query () {
137
163
  instance.hide()
138
164
  }
139
165
  }" x-init="
140
- initBuilder()
166
+ parse()
141
167
  const ops = _.map(fields, f => (f + 'Op'))
142
168
  const vals = _.map(fields, f => (f + 'Val'))
143
- const watcher = ['selected', ...ops, ...vals].join(',')
169
+ const vals2 = _.map(fields, f => (f + 'Val2'))
170
+ const watcher = ['selected', ...ops, ...vals, ...vals2].join(',')
144
171
  $watch(watcher, v => rebuild())
145
- ">
172
+ " ${this.params.attr.modal ? '' : 'style="width:600px;"'}>
146
173
  <c:grid-row gutter="2">
147
174
  <c:grid-col col="12">
148
175
  <c:form-textarea x-model="builder" readonly rows="4"/>
@@ -17,7 +17,8 @@ async function recsInfo () {
17
17
  }
18
18
  let { count, limit, page, pages } = attrToObject(this.params.attr.options)
19
19
  count = count ?? get(this, 'component.locals.list.count', 0)
20
- if (count === 0) {
20
+ const data = get(this, 'component.locals.list.data', [])
21
+ if (count === 0 || data.length === 0) {
21
22
  this.params.noTag = true
22
23
  this.params.html = ''
23
24
  return
@@ -61,7 +61,7 @@ async function table () {
61
61
  for (const prop of schema.properties) {
62
62
  if (typeof prop.values === 'string') this.propValues[prop.name] = await callHandler(prop.values)
63
63
  }
64
- if (count === 0) {
64
+ if (count === 0 || data.length === 0) {
65
65
  const alert = '<c:alert color="warning" t:content="noRecordFound" margin="top-4"/>'
66
66
  this.params.noTag = true
67
67
  this.params.html = await this.component.buildSentence(alert)
@@ -24,6 +24,9 @@ async function editHandler ({ req, reply, model, id, params = {}, template, addO
24
24
  form = defaultsDeep(req.body, old.data)
25
25
  if (req.method !== 'GET') {
26
26
  form = omit(form, ['_action', '_value'])
27
+ try {
28
+ req.body._value = JSON.parse(req.body._value)
29
+ } catch (err) {}
27
30
  if (req.body._action === 'removeatt' && !isEmpty(req.body._value)) {
28
31
  const root = `${getPluginDataDir('dobo')}/attachment`
29
32
  for (const item of req.body._value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.12.4",
3
+ "version": "2.12.6",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-02
4
+
5
+ - [2.12.6] Bug fix in ```wdb-query``` widget
6
+
7
+ ## 2026-04-01
8
+
9
+ - [2.12.5] Bug fix in ```wdb-btn-column``` widget
10
+ - [2.12.5] Bug fix in ```wdb-pagination``` widget
11
+ - [2.12.5] Bug fix in ```wdb-query``` widget
12
+ - [2.12.5] Bug fix in ```wdb-recs-info``` widget
13
+ - [2.12.5] Bug fix in ```wdb-table``` widget
14
+ - [2.12.5] Bug fix in remove attachment
15
+
3
16
  ## 2026-03-30
4
17
 
5
18
  - [2.12.3] Bug fix in transaction supports