waibu-db 1.1.18 → 1.1.19

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,4 +1,4 @@
1
- <% for (const ao of addOns) { %>
1
+ <% for (const ao of arguments[0].addOns ?? []) { %>
2
2
  <c:div append-to="#sb-addons" margin="bottom-3">
3
3
  <!-- include <%= ao.resource %>|<%= JSON.stringify(ao.data) %> -->
4
4
  </c:div>
@@ -1,17 +1,29 @@
1
1
  <c:grid-row gutter="2">
2
2
  <c:grid-col col="6-lg">
3
- <c:wdb-btn-back />
3
+ <% if (!schema.view.control.noBackBtn) { %>
4
+ <c:wdb-btn-back href="<%= schema.view.control.backHref ?? 'undefined' %>" />
5
+ <% } %>
4
6
  <% if (schema.disabled.includes('remove') && schema.disabled.includes('update')) { %>
5
- <c:wdb-btn-export selector="#main-form" handler="details" launch-margin="start-1"/>
7
+ <% if (!schema.view.control.noExportBtn) { %>
8
+ <c:wdb-btn-export selector="#main-form" handler="details" launch-margin="start-1" />
9
+ <% } %>
6
10
  <% } else { %>
7
11
  <c:btn-group margin="start-1">
8
- <c:wdb-btn-edit />
9
- <c:wdb-btn-clone />
12
+ <% if (!schema.view.control.noEditBtn) { %>
13
+ <c:wdb-btn-edit href="<%= schema.view.control.editHref ?? 'undefined' %>" />
14
+ <% } %>
15
+ <% if (!schema.view.control.noCloneBtn) { %>
16
+ <c:wdb-btn-clone href="<%= schema.view.control.cloneHref ?? 'undefined' %>" />
17
+ <% } %>
18
+ <% if (!schema.view.control.noExportBtn) { %>
10
19
  <c:wdb-btn-export selector="#main-form" handler="details" launch-on-end/>
20
+ <% } %>
11
21
  </c:btn-group>
12
22
  <% } %>
13
23
  </c:grid-col>
14
24
  <c:grid-col col="6-lg" flex="justify-content:end-lg align-items:center">
15
- <c:wdb-btn-delete/>
25
+ <% if (!schema.view.control.noDeleteBtn) { %>
26
+ <c:wdb-btn-delete href="<%= schema.view.control.deleteHref ?? 'undefined' %>" />
27
+ <% } %>
16
28
  </c:grid-col>
17
29
  </c:grid-row>
@@ -1,15 +1,27 @@
1
1
  <c:grid-row gutter="2">
2
2
  <c:grid-col col="6-lg">
3
- <c:wdb-btn-back />
3
+ <% if (!schema.view.control.noBackBtn) { %>
4
+ <c:wdb-btn-back href="<%= schema.view.control.backHref ?? 'undefined' %>"/>
5
+ <% } %>
4
6
  <c:btn-group margin="start-1">
5
- <c:wdb-btn-details />
6
- <c:wdb-btn-clone/>
7
+ <% if (!schema.view.control.noDetailsBtn) { %>
8
+ <c:wdb-btn-details href="<%= schema.view.control.detailsHref ?? 'undefined' %>" />
9
+ <% } %>
10
+ <% if (!schema.view.control.noCloneBtn) { %>
11
+ <c:wdb-btn-clone href="<%= schema.view.control.cloneHref ?? 'undefined' %>" />
12
+ <% } %>
7
13
  <c:wdb-btn-export selector="#main-form" handler="edit" launch-on-end/>
8
14
  </c:btn-group>
9
15
  </c:grid-col>
10
16
  <c:grid-col col="6-lg" flex="justify-content:end-lg align-items:center">
11
- <c:wdb-btn-delete/>
17
+ <% if (!schema.view.control.noDeleteBtn) { %>
18
+ <c:wdb-btn-delete href="<%= schema.view.control.deleteHref ?? 'undefined' %>"/>
19
+ <% } %>
20
+ <% if (!schema.view.control.noResetBtn) { %>
12
21
  <c:btn type="reset" color="secondary" t:content="reset" margin="start-2"/>
22
+ <% } %>
23
+ <% if (!schema.view.control.noSubmitBtn) { %>
13
24
  <c:btn type="submit" color="primary" t:content="submit" margin="start-2"/>
25
+ <% } %>
14
26
  </c:grid-col>
15
27
  </c:grid-row>
@@ -1,4 +1,4 @@
1
- async function detailsHandler ({ req, reply, model, params = {}, template, addOnsHandler, templateDisabled = 'waibuDb.template:/disabled.html' } = {}) {
1
+ async function detailsHandler ({ req, reply, model, params = {}, id, template, addOnsHandler, templateDisabled = 'waibuDb.template:/disabled.html' } = {}) {
2
2
  const { pascalCase } = this.app.bajo
3
3
  const { recordGet, getSchemaExt } = this.app.waibuDb
4
4
  const { merge } = this.lib._
@@ -8,7 +8,8 @@ async function detailsHandler ({ req, reply, model, params = {}, template, addOn
8
8
  if (schema.disabled.includes('get')) return reply.view(templateDisabled, { action: 'details' })
9
9
  // req.query.attachment = true
10
10
  options.fields = schema.view.fields
11
- const resp = await recordGet({ model, req, options })
11
+ id = id ?? req.params.id ?? req.query.id
12
+ const resp = await recordGet({ model, req, id, options })
12
13
  const form = resp.data
13
14
  const addOns = addOnsHandler ? await addOnsHandler.call(this.app[req.ns], { req, reply, params, data: resp, schema }) : undefined
14
15
  merge(params, { form, schema, addOns })
@@ -1,4 +1,4 @@
1
- async function editHandler ({ req, reply, model, params = {}, template, addOnsHandler, templateDisabled = 'waibuDb.template:/disabled.html' } = {}) {
1
+ async function editHandler ({ req, reply, model, id, params = {}, template, addOnsHandler, templateDisabled = 'waibuDb.template:/disabled.html' } = {}) {
2
2
  const { pascalCase } = this.app.bajo
3
3
  const { recordUpdate, recordGet, getSchemaExt } = this.app.waibuDb
4
4
  const { buildUrl } = this.app.waibuMpa
@@ -12,15 +12,16 @@ async function editHandler ({ req, reply, model, params = {}, template, addOnsHa
12
12
  let error
13
13
  let resp
14
14
  let form
15
+ id = id ?? req.params.id ?? req.query.id
15
16
  if (req.method === 'GET') {
16
- const old = await recordGet({ model, req, id: req.query.id, options })
17
+ const old = await recordGet({ model, req, id, options })
17
18
  form = defaultsDeep(req.body, old.data)
18
19
  } else {
19
20
  form = req.body
20
21
  try {
21
- resp = await recordUpdate({ model, req, id: req.query.id, reply, options })
22
+ resp = await recordUpdate({ model, req, id, reply, options })
22
23
  form = resp.data
23
- return reply.redirectTo(buildUrl({ url: req.url, base: 'list', params: { page: 1 }, exclude: ['id'] }))
24
+ return reply.redirectTo(buildUrl({ url: req.url, base: req.params.base ?? req.query.base ?? 'list', params: { page: 1 }, exclude: ['id'] }))
24
25
  } catch (err) {
25
26
  error = err
26
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "1.1.18",
3
+ "version": "1.1.19",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -5,32 +5,40 @@ const defReadonly = ['id', 'createdAt', 'updatedAt']
5
5
  const defFormatter = {}
6
6
 
7
7
  function getCommons (action, schema, ext, opts = {}) {
8
- const { merge, map, get, set, without, uniq } = this.lib._
8
+ const { defaultsDeep } = this.app.bajo
9
+ const { merge, map, get, set, without, uniq, pull } = this.lib._
9
10
  const calcFields = get(ext, `view.${action}.calcFields`, get(ext, 'common.calcFields', []))
11
+ const forceVisible = get(ext, `view.${action}.forceVisible`, get(ext, 'common.forceVisible', []))
12
+ const widget = defaultsDeep(get(ext, `view.${action}.widget`), get(ext, 'common.widget', {}))
10
13
  const noEscape = get(ext, `view.${action}.noEscape`, get(ext, 'common.noEscape', []))
11
- const valueFormatter = get(ext, `view.${action}.valueFormatter`, get(ext, 'common.valueFormatter', {}))
12
- const formatter = get(ext, `view.${action}.formatter`, get(ext, 'common.formatter', {}))
13
- const label = get(ext, `view.${action}.label`, get(ext, 'common.label', {}))
14
+ const control = defaultsDeep(get(ext, `view.${action}.control`), get(ext, 'common.control', {}))
15
+ const valueFormatter = defaultsDeep(get(ext, `view.${action}.valueFormatter`), get(ext, 'common.valueFormatter', {}))
16
+ const formatter = defaultsDeep(get(ext, `view.${action}.formatter`), get(ext, 'common.formatter', {}))
14
17
  const card = get(ext, `view.${action}.card`, get(ext, 'common.card', true))
15
- const hidden = get(ext, `view.${action}.hidden`, get(ext, 'common.hidden', []))
18
+ let hidden = get(ext, `view.${action}.hidden`, get(ext, 'common.hidden', []))
16
19
  const disabled = get(ext, `view.${action}.disabled`, get(ext, 'common.disabled', []))
17
- const x = get(ext, `view.${action}.x`, get(ext, 'common.x', {}))
20
+ const x = defaultsDeep(get(ext, `view.${action}.x`), get(ext, 'common.x', {}))
18
21
  const aggregate = get(ext, `view.${action}.stat.aggregate`, get(ext, 'common.stat.aggregate', []))
19
- hidden.push(...schema.hidden, ...(opts.hidden ?? []))
22
+ hidden.push('siteId', ...schema.hidden, ...(opts.hidden ?? []))
23
+ hidden = uniq(hidden)
24
+ pull(hidden, ...forceVisible)
20
25
  const allFields = without(map(schema.properties, 'name'), ...hidden)
21
26
  const forFields = get(ext, `view.${action}.fields`, get(ext, 'common.fields', allFields))
22
27
  set(schema, 'view.calcFields', calcFields)
23
28
  set(schema, 'view.noEscape', noEscape)
29
+ set(schema, 'view.widget', widget)
24
30
  set(schema, 'view.valueFormatter', valueFormatter)
25
31
  set(schema, 'view.formatter', merge({}, defFormatter, formatter))
26
32
  set(schema, 'view.stat.aggregate', aggregate)
27
33
  set(schema, 'view.disabled', disabled)
34
+ set(schema, 'view.control', control)
28
35
  set(schema, 'view.x', x)
29
36
  if (schema.disabled.length > 0) schema.view.disabled.push(...schema.disabled)
30
37
  let fields = []
31
38
  for (const f of forFields) {
32
- if (allFields.includes(f) || map(calcFields, 'name').includes(f)) fields.push(f)
39
+ if (allFields.includes(f)) fields.push(f)
33
40
  }
41
+ if (calcFields.length > 0) fields.push(...map(calcFields, 'name'))
34
42
  fields = uniq(without(fields, ...hidden))
35
43
 
36
44
  if (action !== 'add' && !fields.includes('id')) fields.unshift('id')
@@ -38,59 +46,58 @@ function getCommons (action, schema, ext, opts = {}) {
38
46
  if (noWrap === true) noWrap = fields
39
47
  else if (noWrap === false) noWrap = []
40
48
  set(schema, 'view.noWrap', noWrap)
41
- return { fields, allFields, label, card }
49
+ return { fields, allFields, card, calcFields }
42
50
  }
43
51
 
44
- function autoLayout ({ action, schema, ext, layout, allWidgets }) {
52
+ function autoLayout ({ action, schema, ext, layout }) {
53
+ const { forOwn, keys } = this.lib._
45
54
  const matches = ['id', 'createdAt', 'updatedAt']
46
55
  const meta = []
47
56
  const general = []
48
- for (const w of allWidgets) {
49
- if (matches.includes(w.name)) meta.push(w)
50
- else general.push(w)
51
- }
52
- if (meta.length <= 1) layout.push({ name: '_common', widgets: allWidgets })
57
+ forOwn(schema.view.widget, (w, f) => {
58
+ if (matches.includes(f)) meta.push(f)
59
+ else general.push(f)
60
+ })
61
+ if (meta.length <= 1) layout.push({ name: '_common', fields: keys(schema.view.widget) })
53
62
  else {
54
- layout.push({ name: 'Meta', widgets: meta })
55
- layout.push({ name: 'General', widgets: general })
63
+ layout.push({ name: 'Meta', fields: meta })
64
+ layout.push({ name: 'General', fields: general })
56
65
  }
57
66
  }
58
67
 
59
- function customLayout ({ action, schema, ext, layout, allWidgets, readonly }) {
60
- const { find, omit, merge, isString, isEmpty } = this.lib._
68
+ function customLayout ({ action, schema, ext, layout, readonly }) {
69
+ const { defaultsDeep } = this.app.bajo
70
+ const { isEmpty } = this.lib._
61
71
  const items = [...layout]
62
- layout.splice(0, layout.length)
63
72
  for (const item of items) {
64
- const widgets = []
65
- for (let f of item.fields) {
66
- if (isString(f)) {
67
- const [name, col, label, component] = f.split(':')
68
- f = { name }
69
- f.label = isEmpty(label) ? `field.${name}` : label
70
- if (!isEmpty(col)) f.col = col
71
- if (!isEmpty(component)) f.component = component
72
- }
73
- const widget = find(allWidgets, { name: f.name })
74
- if (!widget && !f.component) continue
75
- widget.attr = merge({}, widget.attr, omit(f, ['component', 'componentOpts']))
76
- if (f.component && !readonly.includes(f.name) && action !== 'details') {
77
- widget.component = f.component
78
- widget.componentOpts = f.componentOpts
79
- }
80
- widgets.push(widget)
73
+ for (const idx in item.fields) {
74
+ const f = item.fields[idx]
75
+ const [name, col, label, component] = f.split(':')
76
+ item.fields[idx] = name
77
+ const w = { name, attr: {} }
78
+ w.attr.label = isEmpty(label) ? `field.${name}` : label
79
+ if (!isEmpty(col)) w.attr.col = col
80
+ if (!isEmpty(component)) w.component = component
81
+ schema.view.widget[name] = defaultsDeep(w, schema.view.widget[w.name])
81
82
  }
82
- if (widgets.length > 0) layout.push({ name: item.name, widgets })
83
83
  }
84
84
  }
85
85
 
86
86
  function applyLayout (action, schema, ext) {
87
- const { set, get, isEmpty, map, find } = this.lib._
88
- const { fields, label, card } = getCommons.call(this, action, schema, ext)
87
+ const { defaultsDeep } = this.app.bajo
88
+ const { set, get, isEmpty, find } = this.lib._
89
+ const { fields, card, calcFields } = getCommons.call(this, action, schema, ext)
89
90
  const layout = get(ext, `view.${action}.layout`, get(ext, 'common.layout', []))
90
91
  const readonly = get(ext, `view.${action}.readonly`, get(ext, 'common.readonly', defReadonly))
91
- const allWidgets = map(fields, f => {
92
- const prop = find(schema.properties, { name: f })
93
- const result = { name: f, component: 'form-input', attr: { col: '4-md' } }
92
+ const widget = {}
93
+ for (const f of fields) {
94
+ let prop = find(schema.properties, { name: f })
95
+ if (!prop) prop = find(calcFields, { name: f })
96
+ if (!prop) continue
97
+ const result = schema.view.widget[f] ?? {}
98
+ result.name = result.name ?? f
99
+ result.component = result.component ?? 'form-input'
100
+ result.attr = defaultsDeep(result.attr, { col: '4-md', label: `field.${f}` })
94
101
  if (['array', 'object', 'text'].includes(prop.type)) {
95
102
  result.attr.col = '12'
96
103
  result.component = 'form-textarea'
@@ -110,20 +117,20 @@ function applyLayout (action, schema, ext) {
110
117
  if (['string', 'text'].includes(prop.type) && prop.maxLength) set(result, 'attr.maxlength', prop.maxLength)
111
118
  if (readonly.includes(f)) result.component = 'form-plaintext'
112
119
  }
113
- return result
114
- })
115
- if (isEmpty(layout)) autoLayout.call(this, { layout, allWidgets, schema, action, ext })
116
- else customLayout.call(this, { layout, allWidgets, schema, action, ext, readonly })
120
+ widget[f] = result
121
+ }
122
+ set(schema, 'view.widget', widget)
123
+ if (isEmpty(layout)) autoLayout.call(this, { layout, schema, action, ext })
124
+ else customLayout.call(this, { layout, schema, action, ext, readonly })
117
125
  set(schema, 'view.layout', layout)
118
126
  set(schema, 'view.fields', fields)
119
- set(schema, 'view.label', label)
120
127
  set(schema, 'view.card', card)
121
128
  }
122
129
 
123
130
  const handler = {
124
131
  list: async function (schema, ext, opts) {
125
132
  const { get, set } = this.lib._
126
- const { fields, label } = getCommons.call(this, 'list', schema, ext, opts)
133
+ const { fields } = getCommons.call(this, 'list', schema, ext, opts)
127
134
  const qsFields = []
128
135
  for (const f of get(schema, 'view.qs.fields', '').split(',')) {
129
136
  if (fields.includes(f)) qsFields.push(f)
@@ -135,7 +142,6 @@ const handler = {
135
142
  if (!['1', '-1'].includes(dir)) dir = '1'
136
143
  set(schema, 'view.qs.sort', `${col}:${dir}`)
137
144
  }
138
- set(schema, 'view.label', label)
139
145
  set(schema, 'view.fields', fields)
140
146
  set(schema, 'view.qs.fields', qsFields.join(','))
141
147
  },
@@ -159,7 +165,7 @@ async function getSchemaExt (model, view, opts) {
159
165
  const base = path.basename(schema.file, path.extname(schema.file))
160
166
  let ext = await readConfig(`${schema.ns}:/waibuDb/schema/${base}.*`, { ignoreError: true, opts })
161
167
  const over = await readConfig(`main:/waibuDb/extend/${schema.ns}/schema/${base}.*`, { ignoreError: true, opts })
162
- ext = defaultsDeep(over, ext)
168
+ ext = defaultsDeep(opts.schema ?? {}, over, ext)
163
169
  await handler[view].call(this, schema, ext, opts)
164
170
  schema = pick(schema, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'view'])
165
171
  return { schema, ext }
@@ -31,7 +31,8 @@ async function btnDetails () {
31
31
  $refs.details.href = path + '&id=' + recId
32
32
  `
33
33
  } else {
34
- this.params.attr.href += '&id=' + req.query.id
34
+ const prefix = this.params.attr.href.includes('?') ? '' : '?'
35
+ this.params.attr.href += prefix + '&id=' + req.query.id
35
36
  }
36
37
  this.params.html = await this.component.buildTag({ tag: 'btn', attr: this.params.attr, html: this.params.html })
37
38
  }
@@ -58,7 +58,8 @@ async function btnEdit () {
58
58
  this.params.html = await this.component.buildTag({ tag: 'dropdown', attr: this.params.attr, html: html.join('\n') })
59
59
  }
60
60
  } else {
61
- this.params.attr.href += '&id=' + req.query.id
61
+ const prefix = this.params.attr.href.includes('?') ? '' : '?'
62
+ this.params.attr.href += prefix + '&id=' + req.query.id
62
63
  this.params.html = await this.component.buildTag({ tag: 'btn', attr: this.params.attr, html: this.params.html })
63
64
  }
64
65
  }
@@ -13,8 +13,11 @@ async function form () {
13
13
  const xOns = get(schema, 'view.x.on', [])
14
14
  for (const l of schema.view.layout) {
15
15
  body.push(`<c:fieldset ${schema.view.card === false ? '' : 'card'} ${l.name[0] !== '_' ? ('t:legend="' + l.name + '"') : ''} grid-gutter="2">`)
16
- for (const w of l.widgets) {
17
- const prop = find(schema.properties, { name: w.name })
16
+ for (const f of l.fields) {
17
+ const w = schema.view.widget[f]
18
+ let prop = find(schema.properties, { name: f })
19
+ if (!prop) prop = find(schema.view.calcFields, { name: f })
20
+ if (!prop) continue
18
21
  const attr = [`x-ref="${w.name}"`]
19
22
  if (xModels.includes(w.name)) attr.push(`x-model="${w.name}"`)
20
23
  forOwn(w.attr, (v, k) => {