waibu-db 2.18.0 → 2.18.2

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.
@@ -23,7 +23,7 @@ async function table () {
23
23
  const { req } = this.component
24
24
  const { escape, attrToArray } = this.app.waibu
25
25
  const { groupAttrs } = this.app.waibuMpa
26
- const { get, omit, set, find, isEmpty, without, merge } = this.app.lib._
26
+ const { get, omit, set, find, isEmpty, without, merge, isString } = this.app.lib._
27
27
  const group = groupAttrs(this.params.attr, ['body', 'head', 'foot'])
28
28
  this.params.attr = group._
29
29
  const prettyUrl = this.params.attr.prettyUrl
@@ -123,17 +123,20 @@ async function table () {
123
123
  }
124
124
  for (const f of schema.view.fields) {
125
125
  if (!fields.includes(f)) continue
126
- let prop = find(schema.properties, { name: f })
127
- if (!prop) prop = find(schema.view.calcFields, { name: f })
126
+ const prop = find(schema.properties, { name: f })
128
127
  if (!prop) continue
129
128
  let dataValue = d[f]
130
129
  if (['datetime'].includes(prop.type) && dataValue instanceof Date && !isNaN(dataValue)) dataValue = escape(dataValue.toISOString())
131
130
  else if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
132
131
  else if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(dataValue))
133
132
  const refName = get(schema, `view.widget.${f}.attr.refName`)
134
- let value = this.getRefValue({ field: f, data: d, refName }) ?? get(d, `_fmt.${f}`)
133
+ let value = this.getRefValue({ field: f, data: d, refName }) ?? get(d, `_fmt.${f}`, d[f])
135
134
  if (!get(schema, 'view.noEscape', []).includes(f)) value = escape(value)
136
135
  const attr = { dataValue, dataKey: prop.name, dataType: prop.type }
136
+ if (isString(d[f]) && d[f].startsWith('<a ')) {
137
+ delete attr.dataValue
138
+ value = d[f]
139
+ }
137
140
  if (!disableds.includes('get')) attr.style = { cursor: 'pointer' }
138
141
  const formatCell = get(schema, `view.formatCell.${f}`)
139
142
  if (formatCell) merge(attr, await formatCell.call(this, value, d, { params: this.params, req }))
@@ -12,11 +12,11 @@ async function form () {
12
12
  const { get, has } = this.app.lib._
13
13
  const { stringifyAttribs } = this.app.waibuMpa
14
14
  attr.dataType = prop.type
15
- const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
16
15
  if (has(attr, 'name') && !has(attr, 'value')) {
17
- attr.value = cmp === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
16
+ attr.value = widget.component === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
18
17
  }
19
- return `<c:${cmp} ${stringifyAttribs(attr)} />`
18
+ if (prop.virtual) widget.component = 'form-plaintext'
19
+ return `<c:${widget.component} ${stringifyAttribs(attr)} />`
20
20
  }
21
21
 
22
22
  build = async () => {
@@ -31,9 +31,9 @@ async function form () {
31
31
  body.push(`<c:fieldset ${this.schema.view.card === false ? '' : 'card'} ${l.name[0] !== '_' ? ('t:legend="' + l.name + '"') : ''} grid-gutter="2">`)
32
32
  for (const f of fields) {
33
33
  const widget = this.schema.view.widget[f]
34
- let prop = find(this.schema.properties, { name: f })
35
- if (!prop) prop = find(this.schema.view.calcFields, { name: f })
34
+ const prop = find(this.schema.properties, { name: f })
36
35
  if (!prop) continue
36
+ if (['dobo:image'].includes(prop.feature)) continue
37
37
  const attr = {
38
38
  'x-ref': widget.name,
39
39
  labelFloating: true,
package/index.js CHANGED
@@ -167,49 +167,6 @@ async function factory (pkgName) {
167
167
  return await this.findAllRecord({ model, req, options })
168
168
  }
169
169
 
170
- formatRecord = async ({ data, req, schema, options = {} }) => {
171
- const { isArray } = this.app.lib._
172
- if (!isArray(data)) return await this.formatRow({ data, req, schema, options })
173
- const items = []
174
- for (const d of data) {
175
- const item = await this.formatRow({ data: d, req, schema, options })
176
- items.push(item)
177
- }
178
- return items
179
- }
180
-
181
- formatRow = async ({ data, req, schema, options = {} }) => {
182
- const { get, find, isFunction, cloneDeep } = this.app.lib._
183
- const { format, callHandler } = this.app.bajo
184
- const { escape } = this.app.waibu
185
- const fields = get(schema, 'view.fields', Object.keys(schema.properties))
186
- const rec = cloneDeep(data)
187
- const lang = get(req, 'lang')
188
- const unitSys = get(req, 'site.setting.sumba.unitSys')
189
- const timeZone = get(req, 'site.setting.sumba.timeZone', this.app.bajo.config.intl.format.datetime.timeZone)
190
- for (const f of fields) {
191
- if (f === '_ref') continue
192
- let prop = find(schema.properties, { name: f })
193
- if (!prop) prop = find(schema.view.calcFields, { name: f })
194
- if (!prop) continue
195
- const opts = {
196
- lang: options.lang ?? lang,
197
- longitude: ['lng', 'longitude'].includes(f),
198
- latitude: ['lat', 'latitude'].includes(f),
199
- speed: ['speed'].includes(f),
200
- degree: ['course', 'heading'].includes(f),
201
- distance: ['distance'].includes(f),
202
- unitSys: options.unitSys ?? unitSys,
203
- datetime: options.datetime ?? { timeZone },
204
- date: options.date ?? { timeZone },
205
- time: options.time ?? { timeZone }
206
- }
207
- rec[f] = format(data[f], prop.type, opts)
208
- if (['string', 'text'].includes(prop.type)) rec[f] = escape(rec[f])
209
- }
210
- return rec
211
- }
212
-
213
170
  countRecord = countRecord
214
171
  createAggregate = createAggregate
215
172
  createHistogram = createHistogram
@@ -2,10 +2,8 @@ import { attachmentHandler, notFoundTpl } from './helper.js'
2
2
 
3
3
  async function editHandler ({ req, reply, model, id, params = {}, template, addOnsHandler, templateDisabled = 'waibuDb.template:/disabled.html', options = {} } = {}) {
4
4
  const { pascalCase } = this.app.lib.aneka
5
- const { getPluginDataDir } = this.app.bajo
6
5
  const { updateRecord, getRecord, getSchemaExt } = this.app.waibuDb
7
6
  const { buildUrl } = this.app.waibuMpa
8
- const { fs } = this.app.lib
9
7
  const { defaultsDeep } = this.app.lib.aneka
10
8
  const { merge, isEmpty, omit, cloneDeep, isArray, isPlainObject } = this.app.lib._
11
9
  const opts = merge({}, options.modelOpts)
@@ -34,12 +32,12 @@ async function editHandler ({ req, reply, model, id, params = {}, template, addO
34
32
  req.body._value = JSON.parse(req.body._value)
35
33
  } catch (err) {}
36
34
  if (req.body._action === 'removeatt' && !isEmpty(req.body._value)) {
37
- const root = `${getPluginDataDir('dobo')}/attachment`
38
35
  for (const item of req.body._value) {
39
36
  try {
40
- const file = `${root}/${item}`
41
- await fs.unlink(file)
42
- } catch (err) {}
37
+ const [,,, field, fname] = item.split('/')
38
+ await mdl.removeAttachment(id, field, fname)
39
+ } catch (err) {
40
+ }
43
41
  }
44
42
  if (req && req.flash) req.flash('notify', req.t('attachmentRemoved'))
45
43
  } else {
@@ -7,7 +7,6 @@ const defFormatter = {}
7
7
  function getCommons (action, schema, ext, options = {}) {
8
8
  const { defaultsDeep } = this.app.lib.aneka
9
9
  const { merge, map, get, set, without, uniq, pull } = this.app.lib._
10
- const calcFields = get(ext, `view.${action}.calcFields`, get(ext, 'common.calcFields', []))
11
10
  const forceVisible = get(ext, `view.${action}.forceVisible`, get(ext, 'common.forceVisible', []))
12
11
  const widget = defaultsDeep(get(ext, `view.${action}.widget`), get(ext, 'common.widget', {}))
13
12
  const noEscape = get(ext, `view.${action}.noEscape`, get(ext, 'common.noEscape', []))
@@ -19,7 +18,7 @@ function getCommons (action, schema, ext, options = {}) {
19
18
  const disabled = get(ext, `view.${action}.disabled`, get(ext, 'common.disabled', []))
20
19
  const x = defaultsDeep(get(ext, `view.${action}.x`), get(ext, 'common.x', {}))
21
20
  const aggregate = get(ext, `view.${action}.stat.aggregate`, get(ext, 'common.stat.aggregate', []))
22
- let attachment = get(ext, `view.${action}.attachment`, get(ext, 'common.attachment', false))
21
+ let attachment = get(ext, `view.${action}.attachment`, get(ext, 'common.attachment', schema.attachment))
23
22
  if (!schema.attachment || action === 'list') attachment = false
24
23
  hidden.push('siteId', ...schema.hidden, ...(options.hidden ?? []))
25
24
  hidden = uniq(hidden)
@@ -27,7 +26,6 @@ function getCommons (action, schema, ext, options = {}) {
27
26
  const allFields = without(map(schema.properties, 'name'), ...hidden)
28
27
  const forFields = get(ext, `view.${action}.fields`, get(ext, 'common.fields', allFields))
29
28
  set(schema, 'view.attachment', attachment)
30
- set(schema, 'view.calcFields', calcFields)
31
29
  set(schema, 'view.noEscape', noEscape)
32
30
  set(schema, 'view.widget', widget)
33
31
  set(schema, 'view.formatCell', formatCell)
@@ -38,9 +36,8 @@ function getCommons (action, schema, ext, options = {}) {
38
36
  set(schema, 'view.x', x)
39
37
  if (schema.disabled.length > 0) schema.view.disabled.push(...schema.disabled)
40
38
  let fields = []
41
- const calcFieldNames = map(calcFields, 'name')
42
39
  for (const f of forFields) {
43
- if (calcFieldNames.includes(f) || allFields.includes(f)) fields.push(f)
40
+ if (allFields.includes(f)) fields.push(f)
44
41
  }
45
42
  fields = uniq(without(fields, ...hidden))
46
43
 
@@ -50,7 +47,7 @@ function getCommons (action, schema, ext, options = {}) {
50
47
  if (noWrap === true) noWrap = fields
51
48
  else if (noWrap === false) noWrap = []
52
49
  set(schema, 'view.noWrap', noWrap)
53
- return { fields, allFields, card, calcFields }
50
+ return { fields, allFields, card }
54
51
  }
55
52
 
56
53
  function autoLayout ({ action, schema, ext, layout }) {
@@ -89,14 +86,13 @@ function customLayout ({ action, schema, ext, layout, readonly }) {
89
86
 
90
87
  function applyLayout (action, schema, ext) {
91
88
  const { defaultsDeep } = this.app.lib.aneka
92
- const { set, get, isEmpty, find, kebabCase } = this.app.lib._
93
- const { fields, card, calcFields } = getCommons.call(this, action, schema, ext)
89
+ const { set, get, isEmpty, find } = this.app.lib._
90
+ const { fields, card } = getCommons.call(this, action, schema, ext)
94
91
  const layout = get(ext, `view.${action}.layout`, get(ext, 'common.layout', []))
95
92
  const readonly = get(ext, `view.${action}.readonly`, get(ext, 'common.readonly', defReadonly))
96
93
  const widget = {}
97
94
  for (const f of fields) {
98
- let prop = find(schema.properties, { name: f })
99
- if (!prop) prop = find(calcFields, { name: f })
95
+ const prop = find(schema.properties, { name: f })
100
96
  if (!prop) continue
101
97
  const result = schema.view.widget[f] ?? {}
102
98
  result.name = result.name ?? f
@@ -109,8 +105,11 @@ function applyLayout (action, schema, ext) {
109
105
  if (action === 'details') {
110
106
  result.component = 'form-plaintext'
111
107
  } else {
108
+ if (prop.ref) {
109
+ result.component = result.component ?? 'wdb-lookup-select'
110
+ }
112
111
  if (prop.type === 'boolean') {
113
- result.component = 'form-select'
112
+ result.component = result.component ?? 'form-select'
114
113
  result.attr.options = 'false:no;true:yes'
115
114
  }
116
115
  if (prop.values) {
@@ -124,6 +123,7 @@ function applyLayout (action, schema, ext) {
124
123
  if (readonly.includes(f)) result.component = 'form-plaintext'
125
124
  if (!result.component) result.component = 'form-input'
126
125
  }
126
+ /*
127
127
  for (const k in result.attr ?? {}) {
128
128
  const newKey = kebabCase(k)
129
129
  if (k !== newKey) {
@@ -131,6 +131,7 @@ function applyLayout (action, schema, ext) {
131
131
  delete result.attr[k]
132
132
  }
133
133
  }
134
+ */
134
135
  widget[f] = result
135
136
  }
136
137
  set(schema, 'view.widget', widget)
@@ -180,7 +181,7 @@ async function getSchemaExt (modelName, view, options = {}) {
180
181
 
181
182
  const model = isString(modelName) ? this.app.dobo.getModel(modelName) : modelName
182
183
  const ns = model.plugin.ns
183
- const schema = pick(model, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'scanables', 'view', 'hidden'])
184
+ const schema = pick(model, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'scanables', 'view', 'hidden', 'attachment'])
184
185
  const base = options.base ?? path.basename(model.file, path.extname(model.file))
185
186
  const parserOpts = { args: options.args }
186
187
  let ext = await readConfig(`${ns}:/extend/waibuDb/schema/${base}.*`, { ns, baseNs: 'waibuDb', parserOpts })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.18.0",
3
+ "version": "2.18.2",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-05-02
4
+
5
+ - [2.18.2] Bug fix in ```wdb-data-table``` widget
6
+ - [2.18.2] Bug fix in ```wdb-form``` widget
7
+
3
8
  ## 2026-04-25
4
9
 
5
10
  - [2.18.0] Change options to format value using the new key set by dobo