waibu-db 2.16.1 → 2.16.3

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.
@@ -1,3 +1,5 @@
1
+ <% if (schema && schema.attachment) { %>
1
2
  <c:fieldset <%= schema.view.card === false ? '' : 'card' %> t:legend="attachment" grid-gutter="3">
2
3
  <!-- include waibuDb.partial:/crud/_list-attachment.html|<%= JSON.stringify({ readonly: true }) %> -->
3
4
  </c:fieldset>
5
+ <% } %>
@@ -1,50 +1,5 @@
1
1
  async function wdbBase () {
2
2
  return class WdbBase extends this.app.baseClass.MpaWidget {
3
- constructor (options) {
4
- super(options)
5
- const { getModel } = this.app.dobo
6
- const { get } = this.app.lib._
7
- this.schema = get(this, 'component.locals.schema', {})
8
- this.formData = get(this, 'component.locals.form', {})
9
- this.oldData = get(this, 'component.locals.oldData', {})
10
- this.model = getModel(this.schema.name, true)
11
- }
12
-
13
- getRef = ({ field, refName, returning } = {}) => {
14
- const { get } = this.app.lib._
15
- if (!this.model) return {}
16
- const prop = this.model.getProperty(field)
17
- if (!prop) return {}
18
- if (!refName && field.endsWith('Id')) refName = field.slice(0, -2)
19
- const key = this.params.attr.refName ?? refName
20
- const ref = get(prop, `ref.${key}`, {})
21
- if (returning === 'all') return { ref, key }
22
- else if (returning === 'key') return key
23
- return ref
24
- }
25
-
26
- getRefValue = ({ field, data, labelField, refName } = {}) => {
27
- const { get, isEmpty } = this.app.lib._
28
- const { ref, key } = this.getRef({ field, refName, returning: 'all' })
29
- if (isEmpty(ref)) return undefined
30
- labelField = labelField ?? ref.labelField ?? 'id'
31
- return (get(data ?? this.formData, `_ref.${key}.${labelField}`))
32
- }
33
-
34
- getRefName = (field) => {
35
- const { get } = this.app.lib._
36
- let refName = get(this.schema, `view.widget.${field}.attr.ref-name`, this.params.attr.refName)
37
- if (!refName && this.params.attr[field] && this.params.attr[field].endsWith('Id')) refName = this.params.attr[field].slice(0, -2)
38
- return refName
39
- }
40
-
41
- getSetting = (key, defValue) => {
42
- const { get, camelCase } = this.app.lib._
43
- const widgetName = camelCase(this.constructor.name)
44
- key = key.replaceAll('{self}', widgetName)
45
- const cfg = this.app.waibu.getSetting(`${this.plugin.ns}:${key}`, { defValue, req: this.component.req })
46
- return get(this.schema, `view.${key}`, cfg)
47
- }
48
3
  }
49
4
  }
50
5
 
@@ -1,59 +1,24 @@
1
1
  import wdbBase from '../wdb-base.js'
2
2
 
3
- async function handleRo (attr = {}, prop = {}, widget = {}) {
4
- const { get, camelCase, isEmpty, isString } = this.app.lib._
5
- const { callHandler } = this.app.bajo
6
- const { escape } = this.app.waibu
7
- const { req } = this.component
8
- const dataValue = get(this.formData, `_orig.${prop.name}`, prop.dataValue ?? '')
9
- let value = get(this.oldData, prop.name, get(this.formData, prop.name, prop.value ?? ''))
10
- const format = get(this.schema, `view.format.${prop.name}`)
11
- const formatValue = get(this.schema, `view.formatValue.${prop.name}`)
12
- const labelField = get(this.schema, `view.widget.${prop.name}.attr.labelField`)
13
- if (formatValue) value = await formatValue.call(this, value, this.formData, { req })
14
- else if (prop.ref) {
15
- value = this.getRefValue({ field: prop.name, labelField, refName: this.getRefName(prop.name) })
16
- if (format && !isEmpty(value)) attr.href = await format.call(this, value, this.formData, { linkOnly: true })
17
- } else if (prop.values) {
18
- const values = isString(prop.values) ? (await callHandler(prop.values)) : prop.values
19
- value = values.find(v => v.value === dataValue)
20
- if (value) {
21
- const key = camelCase(`${prop.name} ${value.text}`)
22
- value = req.te(key) ? req.t(key) : value.text
23
- }
24
- } else if (format && !isEmpty(value)) value = await format.call(this, value, this.formData)
25
- attr.dataValue = escape(dataValue)
26
- attr.value = escape(value)
27
- attr.dataType = prop.type
28
-
29
- if (['object', 'array', 'text'].includes(prop.type)) {
30
- attr.style = 'min-height: 100px'
31
- attr.readonly = true
32
- return await this.component.buildTag({ tag: 'formTextarea', attr, html: value })
33
- }
34
- return await this.component.buildTag({ tag: 'formPlaintext', attr, selfCosing: true, noEscape: true })
35
- }
36
-
37
- async function handleRw (attr = {}, prop = {}, widget = {}) {
38
- const { get, has, isPlainObject, isArray } = this.app.lib._
39
- const { escape } = this.app.waibu
40
- const { stringifyAttribs } = this.app.waibuMpa
41
- if (has(attr, 'name') && !has(attr, 'value')) {
42
- attr.dataType = attr.dataType ?? prop.type
43
- attr.dataValue = get(this, `formData.${attr.name}`)
44
- if (isPlainObject(attr.dataValue) || isArray(attr.dataValue)) attr.dataValue = JSON.stringify(attr.dataValue)
45
- attr.dataValue = escape(attr.dataValue)
46
- attr.value = widget.component === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
47
- }
48
-
49
- const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
50
- return `<c:${cmp} ${stringifyAttribs(attr)} data-type="${prop.type}" />`
51
- }
52
-
53
3
  async function form () {
54
4
  const WdbBase = await wdbBase.call(this)
55
5
 
56
6
  return class WdbForm extends WdbBase {
7
+ static async handleRo ({ attr = {}, prop = {} } = {}) {
8
+ return await this.component.buildTag({ tag: 'formPlaintext', attr, selfCosing: true, noEscape: true })
9
+ }
10
+
11
+ static async handleRw ({ attr = {}, prop = {}, widget = {} } = {}) {
12
+ const { get, has } = this.app.lib._
13
+ const { stringifyAttribs } = this.app.waibuMpa
14
+ attr.dataType = prop.type
15
+ const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
16
+ if (has(attr, 'name') && !has(attr, 'value')) {
17
+ attr.value = cmp === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
18
+ }
19
+ return `<c:${cmp} ${stringifyAttribs(attr)} />`
20
+ }
21
+
57
22
  build = async () => {
58
23
  const { get, find, filter, forOwn, isEmpty } = this.app.lib._
59
24
  const { base64JsonEncode } = this.app.waibu
@@ -86,9 +51,9 @@ async function form () {
86
51
  }
87
52
  if (widget.componentOpts) attr['c-opts'] = base64JsonEncode(widget.componentOpts)
88
53
  if (widget.component === 'form-plaintext' || this.params.attr.method !== 'POST') {
89
- body.push(await handleRo.call(this, attr, prop, widget))
54
+ body.push(await WdbForm.handleRo.call(this, { attr, prop, widget }))
90
55
  } else {
91
- body.push(await handleRw.call(this, attr, prop, widget))
56
+ body.push(await WdbForm.handleRw.call(this, { attr, prop, widget }))
92
57
  }
93
58
  }
94
59
  body.push('</c:fieldset>')
@@ -4,8 +4,6 @@ async function table () {
4
4
  const WdbBase = await wdbBase.call(this)
5
5
 
6
6
  return class WdbTable extends WdbBase {
7
- propValues = {}
8
-
9
7
  isRightAligned = (field, schema) => {
10
8
  const { get, find } = this.app.lib._
11
9
  const prop = find(schema.properties, { name: field })
@@ -22,11 +20,10 @@ async function table () {
22
20
  }
23
21
 
24
22
  build = async () => {
25
- const { callHandler } = this.app.bajo
26
23
  const { req } = this.component
27
24
  const { escape, attrToArray } = this.app.waibu
28
25
  const { groupAttrs } = this.app.waibuMpa
29
- const { get, omit, set, find, isEmpty, without, merge, camelCase } = this.app.lib._
26
+ const { get, omit, set, find, isEmpty, without, merge } = this.app.lib._
30
27
  const group = groupAttrs(this.params.attr, ['body', 'head', 'foot'])
31
28
  this.params.attr = group._
32
29
  const prettyUrl = this.params.attr.prettyUrl
@@ -35,11 +32,6 @@ async function table () {
35
32
  const data = get(this, 'component.locals.list.data', [])
36
33
  const filter = get(this, 'component.locals.list.filter', {})
37
34
  const count = get(this, 'component.locals.list.count', 0)
38
- // collect prop.values for later use
39
- for (const prop of schema.properties) {
40
- if (typeof prop.values === 'string') this.propValues[prop.name] = await callHandler(prop.values)
41
- else if (prop.values) this.propValues[prop.name] = prop.values
42
- }
43
35
  if (count === 0 || data.length === 0) {
44
36
  const alert = '<c:alert color="warning" t:content="noRecordFound" margin="top-4"/>'
45
37
  this.params.noTag = true
@@ -135,9 +127,9 @@ async function table () {
135
127
  if (!prop) prop = find(schema.view.calcFields, { name: f })
136
128
  if (!prop) continue
137
129
  let dataValue = d._orig[f]
138
- if (['datetime'].includes(prop.type)) dataValue = escape(dataValue.toISOString())
130
+ if (['datetime'].includes(prop.type) && dataValue) dataValue = escape(dataValue.toISOString())
139
131
  else if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
140
- else if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
132
+ else if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(dataValue))
141
133
  const refName = get(schema, `view.widget.${f}.attr.refName`)
142
134
  let value = this.getRefValue({ field: f, data: d, refName }) ?? d[f]
143
135
  const formatValue = get(schema, `view.formatValue.${f}`)
@@ -152,21 +144,9 @@ async function table () {
152
144
  if (formatCell) merge(attr, await formatCell.call(this, value, d, { params: this.params, req }))
153
145
  const noWrap = this.isNoWrap(f, schema, group.body.nowrap) ? 'nowrap' : ''
154
146
  if (this.isRightAligned(f, schema)) attr.text = `align:end ${noWrap}`
155
- else attr.text = noWrap
156
- const lookup = get(schema, `view.lookup.${f}`)
157
- if (lookup) {
158
- const item = find(lookup.values, set({}, lookup.id ?? 'id', dataValue))
159
- if (item) value = req.t(item[lookup.field ?? 'name'])
160
- }
147
+ else attr.text = `${noWrap}`
161
148
  const format = get(schema, `view.format.${f}`)
162
149
  if (format) value = await format.call(this, value, d, { params: this.params, req })
163
- if (this.propValues[f]) {
164
- const item = find(this.propValues[f], { value: dataValue })
165
- if (item) {
166
- const key = camelCase(`${f} ${item.text}`)
167
- value = req.te(key) ? req.t(key) : item.text
168
- }
169
- }
170
150
  const line = await this.component.buildTag({ tag: 'td', attr, html: value })
171
151
  lines.push(line)
172
152
  }
@@ -13,11 +13,17 @@ async function addHandler ({ req, reply, model, params = {}, template, addOnsHan
13
13
  opts.fields = schema.view.fields
14
14
  delete req.query.query
15
15
  let def = {}
16
- if (req.method === 'GET' && req.query.mode === 'clone' && req.query.id) {
17
- const resp = await getRecord({ model, req, id: req.query.id, options: { fields: map(schema.properties, 'name'), ...opts } })
18
- def = omit(resp.data._orig, ['id', 'createdAt', 'updatedAt'])
16
+ if (req.method === 'GET') {
17
+ const omitted = ['id', 'createdAt', 'updatedAt']
18
+ if (req.query.mode === 'clone' && req.query.id) {
19
+ const resp = await getRecord({ model, req, id: req.query.id, options: { fields: map(schema.properties, 'name'), ...opts } })
20
+ def = omit(resp.data._orig, omitted)
21
+ } else {
22
+ const picked = map(schema.properties, 'name')
23
+ def = omit(pick(req.query, picked), omitted)
24
+ }
19
25
  }
20
- let form = defaultsDeep(req.body, def)
26
+ let form = defaultsDeep({}, req.body, def)
21
27
  let error
22
28
  let resp
23
29
  if (req.method === 'POST') {
@@ -27,7 +27,7 @@ async function editHandler ({ req, reply, model, id, params = {}, template, addO
27
27
  for (const k in def) {
28
28
  if (isArray(def[k]) || isPlainObject(def[k])) def[k] = JSON.stringify(def[k])
29
29
  }
30
- form = defaultsDeep(req.body, def)
30
+ form = defaultsDeep({}, req.body, def)
31
31
  if (req.method !== 'GET') {
32
32
  form = omit(form, ['_action', '_value'])
33
33
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.16.1",
3
+ "version": "2.16.3",
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-18
4
+
5
+ - [2.16.3] Bug fix in ```WdbForm``` widget
6
+ - [2.16.3] Bug fix in ```WdbTable``` widget
7
+ - [2.16.3] Bug fix in ```add-handler.js``` module
8
+ - [2.16.3] Bug fix in ```edit-handler.js``` module
9
+
10
+ ## 2026-04-17
11
+
12
+ - [2.16.2] Bug fix in ```WdbTable``` widget
13
+ - [2.16.2] Bug fix in ```WdbForm``` widget
14
+ - [2.16.2] Remove reduncat codes in ```WdbBase``` widget
15
+
3
16
  ## 2026-04-16
4
17
 
5
18
  - [2.16.1] Bug fix in ```WdbBtnExport``` widget