waibu-db 2.12.2 → 2.12.5
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/extend/bajo/intl/en-US.json +15 -14
- package/extend/bajo/intl/id.json +15 -14
- package/extend/waibuBootstrap/theme/component/widget/btn-columns.js +1 -1
- package/extend/waibuBootstrap/theme/component/widget/pagination.js +2 -1
- package/extend/waibuBootstrap/theme/component/widget/query.js +44 -18
- package/extend/waibuBootstrap/theme/component/widget/recs-info.js +2 -1
- package/extend/waibuBootstrap/theme/component/widget/table.js +1 -1
- package/index.js +1 -2
- package/lib/crud/edit-handler.js +3 -0
- package/package.json +1 -1
- package/wiki/CHANGES.md +10 -0
|
@@ -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
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
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
|
}
|
package/extend/bajo/intl/id.json
CHANGED
|
@@ -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
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
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 ?? '
|
|
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
|
-
|
|
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,37 @@ 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
|
-
|
|
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="
|
|
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="
|
|
45
|
-
<c:
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
<c:grid-col col="6-md">
|
|
46
|
+
<c:div flex="justify-content:between">`]
|
|
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
|
+
if (prop.type === 'datetime') {
|
|
53
|
+
items.push(`<c:form-datetime wrapper-x-show="${f}Op === 'between'" x-model="${f}Val2" wrapper-margin="start-2"/>`)
|
|
54
|
+
} else {
|
|
55
|
+
items.push(`<c:form-input wrapper-x-show="${f}Op === 'between'" x-model="${f}Val2" wrapper-margin="start-2" />`)
|
|
56
|
+
}
|
|
57
|
+
items.push('</c:div></c:grid-col>')
|
|
58
|
+
columns.push(items.join('\n'))
|
|
48
59
|
}
|
|
49
60
|
this.params.noTag = true
|
|
50
61
|
const container = this.params.attr.modal ? 'modal' : 'drawer'
|
|
@@ -61,40 +72,50 @@ async function query () {
|
|
|
61
72
|
${models.join(',\n')},
|
|
62
73
|
ops: { eq: ':', neq: ':-', gt: ':>', gte: ':>=', lt: ':<', lte: ':<=' },
|
|
63
74
|
opsIn (v, neg) { return ':' + (neg ? '-' : '') + '[' + this.expandArray(v) + ']' },
|
|
75
|
+
opsBetween (v, v2, neg) { return ':' + (neg ? '-' : '') + '{' + this.expandArray(v) + ',' + this.expandArray(v2) + '}' },
|
|
64
76
|
opsExt (v, neg, ext) {
|
|
65
77
|
let prefix = (neg ? '-' : '') + '~'
|
|
66
78
|
if (ext) prefix += ext
|
|
67
79
|
return ':' + prefix + '\\'' + v + '\\''
|
|
68
80
|
},
|
|
69
|
-
|
|
81
|
+
parse () {
|
|
70
82
|
this.builder = document.getElementById('${id}').value
|
|
71
83
|
if (!this.builder.includes(':')) this.builder = ''
|
|
72
84
|
if (_.isEmpty(this.builder)) return
|
|
73
85
|
const tokens = _.merge({}, this.ops, {
|
|
74
86
|
in: ':[',
|
|
87
|
+
between: ':{',
|
|
75
88
|
contains: ':~',
|
|
76
89
|
starts: ':~^',
|
|
77
90
|
ends: ':~$$',
|
|
78
91
|
'!in': ':-[',
|
|
92
|
+
'!between': ':-{',
|
|
79
93
|
'!contains': ':-~',
|
|
80
94
|
'!starts': ':-~^',
|
|
81
95
|
'!ends': ':-~$$'
|
|
82
96
|
})
|
|
83
97
|
for (const part of this.builder.split('+')) {
|
|
84
|
-
let [f, opv] = part.split(':')
|
|
85
|
-
opv = ':' + opv
|
|
98
|
+
let [f, ...opv] = part.split(':')
|
|
99
|
+
opv = ':' + opv.join(':')
|
|
86
100
|
this.selected.push(f)
|
|
87
101
|
let op
|
|
88
102
|
let val
|
|
89
103
|
_.each(tokens, (v, k) => {
|
|
90
104
|
if (opv.slice(0, v.length) === v) {
|
|
91
105
|
op = k
|
|
92
|
-
val = opv.slice(v.length).replaceAll('[', '').replaceAll(']', '').replaceAll('\\'', '')
|
|
106
|
+
val = opv.slice(v.length).replaceAll('[', '').replaceAll('{', '').replaceAll(']', '').replaceAll('}', '').replaceAll('\\'', '')
|
|
93
107
|
}
|
|
94
108
|
})
|
|
109
|
+
console.log(op, val)
|
|
95
110
|
if (_.isEmpty(op)) continue
|
|
96
111
|
this[f + 'Op'] = op
|
|
97
|
-
|
|
112
|
+
if (op === 'between') {
|
|
113
|
+
const vals = val.split(',')
|
|
114
|
+
this[f + 'Val'] = vals[0]
|
|
115
|
+
this[f + 'Val2'] = vals[1]
|
|
116
|
+
} else {
|
|
117
|
+
this[f + 'Val'] = val
|
|
118
|
+
}
|
|
98
119
|
}
|
|
99
120
|
},
|
|
100
121
|
expandArray (val = '') {
|
|
@@ -109,10 +130,14 @@ async function query () {
|
|
|
109
130
|
for (const sel of this.selected) {
|
|
110
131
|
const key = this[sel + 'Op']
|
|
111
132
|
let val = this[sel + 'Val']
|
|
133
|
+
let val2 = this[sel + 'Val2']
|
|
112
134
|
if (_.isEmpty(val)) continue
|
|
135
|
+
if (key === 'between' && _.isEmpty(val2)) continue
|
|
113
136
|
let item
|
|
114
137
|
if (key === 'in') item = this.opsIn(val)
|
|
115
138
|
else if (key === '!in') item = this.opsIn(val, true)
|
|
139
|
+
else if (key === 'between') item = this.opsBetween(val, val2, false)
|
|
140
|
+
else if (key === '!between') item = this.opsBetween(val, val2, true)
|
|
116
141
|
else if (key === 'contains') item = this.opsExt(val)
|
|
117
142
|
else if (key === '!contains') item = this.opsExt(val, true)
|
|
118
143
|
else if (key === 'starts') item = this.opsExt(val, false, '^')
|
|
@@ -137,12 +162,13 @@ async function query () {
|
|
|
137
162
|
instance.hide()
|
|
138
163
|
}
|
|
139
164
|
}" x-init="
|
|
140
|
-
|
|
165
|
+
parse()
|
|
141
166
|
const ops = _.map(fields, f => (f + 'Op'))
|
|
142
167
|
const vals = _.map(fields, f => (f + 'Val'))
|
|
143
|
-
const
|
|
168
|
+
const vals2 = _.map(fields, f => (f + 'Val2'))
|
|
169
|
+
const watcher = ['selected', ...ops, ...vals, ...vals2].join(',')
|
|
144
170
|
$watch(watcher, v => rebuild())
|
|
145
|
-
">
|
|
171
|
+
" ${this.params.attr.modal ? '' : 'style="width:600px;"'}>
|
|
146
172
|
<c:grid-row gutter="2">
|
|
147
173
|
<c:grid-col col="12">
|
|
148
174
|
<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
|
-
|
|
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)
|
package/index.js
CHANGED
|
@@ -157,10 +157,9 @@ async function factory (pkgName) {
|
|
|
157
157
|
const q = query ?? set({}, field, { $in })
|
|
158
158
|
const options = {
|
|
159
159
|
dataOnly: true,
|
|
160
|
-
limit: -1,
|
|
161
160
|
query: q
|
|
162
161
|
}
|
|
163
|
-
return await this.
|
|
162
|
+
return await this.findAllRecord({ model, req, options })
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
formatRecord = async ({ data, req, schema, options = {} }) => {
|
package/lib/crud/edit-handler.js
CHANGED
|
@@ -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
package/wiki/CHANGES.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-04-01
|
|
4
|
+
|
|
5
|
+
- [2.12.4] Bug fix in ```wdb-btn-column``` widget
|
|
6
|
+
- [2.12.4] Bug fix in ```wdb-pagination``` widget
|
|
7
|
+
- [2.12.4] Bug fix in ```wdb-query``` widget
|
|
8
|
+
- [2.12.4] Bug fix in ```wdb-recs-info``` widget
|
|
9
|
+
- [2.12.4] Bug fix in ```wdb-table``` widget
|
|
10
|
+
- [2.12.4] Bug fix in remove attachment
|
|
11
|
+
|
|
3
12
|
## 2026-03-30
|
|
4
13
|
|
|
5
14
|
- [2.12.3] Bug fix in transaction supports
|
|
15
|
+
- [2.12.4] Bug fix in ```options.limit```, removed due to use ```findAllRecords()```
|
|
6
16
|
|
|
7
17
|
## 2026-03-27
|
|
8
18
|
|