waibu-db 2.13.0 → 2.14.0

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,5 +1,34 @@
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.model = getModel(this.schema.name)
10
+ }
11
+
12
+ getRef = ({ field, refName, returning } = {}) => {
13
+ const { get } = this.app.lib._
14
+ if (!this.schema) return {}
15
+ const prop = this.model.getProperty(field)
16
+ if (!prop) return {}
17
+ refName = refName ?? this.params.attr['x-ref'] ?? field.slice(0, -2)
18
+ const key = this.params.attr.refName ?? refName
19
+ const ref = get(prop, `ref.${key}`, {})
20
+ if (returning === 'all') return { ref, key }
21
+ else if (returning === 'key') return key
22
+ return ref
23
+ }
24
+
25
+ getRefValue = ({ field, data, labelField, refName } = {}) => {
26
+ const { isEmpty } = this.app.lib._
27
+ const { ref, key } = this.getRef({ field, refName, returning: 'all' })
28
+ if (isEmpty(ref)) return undefined
29
+ labelField = labelField ?? ref.labelField ?? 'id'
30
+ return (data ?? this.formData)._ref[key][labelField]
31
+ }
3
32
  }
4
33
  }
5
34
 
@@ -33,11 +33,16 @@ async function form () {
33
33
  attr.push(`@${o.bind}="${o.handler}"`)
34
34
  }
35
35
  if (w.componentOpts) attr.push(`c-opts="${base64JsonEncode(w.componentOpts)}"`)
36
- if (schema.view.valueFormatter[f] && (w.component === 'form-plaintext' || this.params.attr.method !== 'POST')) {
37
- const value = await schema.view.valueFormatter[f].call(this, data[f], data, { req })
38
- body.push(`<c:${w.component} ${w.attr.label ? ('t:label="' + w.attr.label + '"') : ''} value="${value}" label-floating name="${w.name}" ${attr.join(' ')} />`)
36
+ const attributes = `${w.attr.label ? ('t:label="' + w.attr.label + '"') : ''} label-floating name="${w.name}" ${attr.join(' ')}`
37
+ if (w.component === 'form-plaintext' || this.params.attr.method !== 'POST') {
38
+ let value
39
+ if (schema.view.valueFormatter[f]) value = await schema.view.valueFormatter[f].call(this, data[f], data, { req })
40
+ else if (prop.ref) value = this.getRefValue({ field: f, labelField: w.attr.labelField })
41
+ body.push(`<c:${w.component} ${attributes} data-type="${prop.type}" ${value ? `value="${value}"` : ''} />`)
42
+ } else if (prop.ref) {
43
+ body.push(`<c:wdb-lookup-select ${attributes} />`)
39
44
  } else {
40
- body.push(`<c:${w.component} ${w.attr.label ? ('t:label="' + w.attr.label + '"') : ''} data-type="${prop.type}" label-floating name="${w.name}" ${attr.join(' ')} />`)
45
+ body.push(`<c:${w.component} ${attributes} data-type="${prop.type}" />`)
41
46
  }
42
47
  }
43
48
  body.push('</c:fieldset>')
@@ -0,0 +1,42 @@
1
+ import wdbBase from '../wdb-base.js'
2
+
3
+ async function lookupSelect () {
4
+ const WdbBase = await wdbBase.call(this)
5
+
6
+ return class WdbLookupSelect extends WdbBase {
7
+ constructor (options) {
8
+ super(options)
9
+ this.params.noTag = true
10
+ }
11
+
12
+ returnEmpty = () => {
13
+ this.params.html = ''
14
+ }
15
+
16
+ build = async () => {
17
+ const { isEmpty, get, omit, set, camelCase, kebabCase } = this.app.lib._
18
+ const { parseQuery } = this.app.dobo
19
+ const { base64JsonEncode } = this.app.waibu
20
+ let refName = get(this.schema, `view.widget.${this.params.attr.name}.attr.refName`, this.params.attr.refName)
21
+ if (!refName && this.params.attr.name.endsWith('Id')) refName = this.params.attr.name.slice(0, -2)
22
+ const ref = this.getRef({ field: this.params.attr.name, refName })
23
+ if (isEmpty(ref)) return this.returnEmpty()
24
+
25
+ this.params.attr.url = this.params.attr.url ?? `waibuDb.restapi:/lookup/${kebabCase(ref.model)}`
26
+ const omitted = ['url', 'searchField', 'labelField', 'valueField']
27
+ const attr = omit(this.params.attr, omitted)
28
+ for (const k of omitted) {
29
+ attr[camelCase(`remote ${k}`)] = this.params.attr[k] ?? ref[k]
30
+ }
31
+ const q = set({}, this.params.attr.searchField ?? get(ref, 'searchField', 'id'), ['__REGEXP__', '{searchItem}', 'i'])
32
+ attr.remoteQuery = base64JsonEncode({ $and: [parseQuery(get(ref, 'query', {})), q] })
33
+ attr.remoteApiKey = true
34
+ attr.clearBtn = true
35
+ const sentence = `<c:form-select-ext ${Object.entries(attr).map(([k, v]) => `${kebabCase(k)}="${v}"`).join(' ')} />`
36
+ this.params.html = await this.component.buildSentence(sentence, this.component.locals)
37
+ this.params.attr = omit(this.params.attr, ['model', 'field', ...omitted])
38
+ }
39
+ }
40
+ }
41
+
42
+ export default lookupSelect
@@ -34,7 +34,7 @@ async function table () {
34
34
  const item = find(values, { value }) ?? {}
35
35
  const ttext = camelCase(`${prop.name} ${item.text}`)
36
36
  value = escape(req.format(!isEmpty(item) ? (req.te(ttext) ? req.t(ttext) : item.text) : value, prop.type))
37
- if (item && !params.attr.noDataValueRef) value += ` <sup><a href="#" title="${req.t('dataValue')}: ${data[key]}">*</a></sup>`
37
+ if (item && !params.attr.noDataValueRef && !isEmpty(data[key])) value += ` <sup><a href="#" title="${req.t('dataValue')}: ${data[key]}">*</a></sup>`
38
38
  } else if (['string', 'text'].includes(prop.type)) {
39
39
  if (!get(schema, 'view.noEscape', []).includes(key)) value = escape(value)
40
40
  }
@@ -161,7 +161,7 @@ async function table () {
161
161
  if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
162
162
  if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
163
163
  }
164
- let value = fd[f]
164
+ let value = this.getRefValue({ field: f, data: fd }) ?? fd[f]
165
165
  const attr = { dataValue, dataKey: prop.name, dataType: prop.type }
166
166
  if (!disableds.includes('get')) attr.style = { cursor: 'pointer' }
167
167
  const cellFormatter = get(schema, `view.cellFormatter.${f}`)
@@ -0,0 +1,4 @@
1
+ {
2
+ "model": ":model",
3
+ "disabled": ["create", "update", "remove"]
4
+ }
@@ -114,9 +114,11 @@ function applyLayout (action, schema, ext) {
114
114
  result.attr.options = 'false:no;true:yes'
115
115
  }
116
116
  if (prop.values) {
117
- result.component = result.component ?? 'form-select'
117
+ const orgCmp = result.component
118
+ result.component = orgCmp ?? 'form-select'
118
119
  if (typeof prop.values === 'string') result.attr.options = prop.values
119
120
  else result.attr.options = prop.values.map(item => `${item.value}:${item.text}`).join(';')
121
+ if (result.attr.options.split(';').length > 8 && !orgCmp) result.component = 'form-select-ext'
120
122
  }
121
123
  if (['string', 'text'].includes(prop.type) && prop.maxLength) set(result, 'attr.maxlength', prop.maxLength)
122
124
  if (readonly.includes(f)) result.component = 'form-plaintext'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-07
4
+
5
+ - [2.14.0] Add ```wdb-lookup-select``` widget
6
+ - [2.14.0] Add ```WdbBase.getRef()```
7
+ - [2.14.0] Add ```WdbBase.getRefValue()```
8
+ - [2.14.0] Rewrite necessary changes to use dobo's new lookup mechanism through model references
9
+
10
+
3
11
  ## 2026-04-02
4
12
 
5
13
  - [2.12.6] Bug fix in ```wdb-query``` widget