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.
- package/bajoTemplate/partial/crud/_addons.html +1 -1
- package/bajoTemplate/partial/crud/_details-btns.html +17 -5
- package/bajoTemplate/partial/crud/_edit-btns.html +16 -4
- package/lib/crud/details-handler.js +3 -2
- package/lib/crud/edit-handler.js +5 -4
- package/package.json +1 -1
- package/plugin/method/get-schema-ext.js +57 -51
- package/waibuBootstrap/theme/component/factory/btn-details.js +2 -1
- package/waibuBootstrap/theme/component/factory/btn-edit.js +2 -1
- package/waibuBootstrap/theme/component/factory/form.js +5 -2
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
<c:grid-row gutter="2">
|
|
2
2
|
<c:grid-col col="6-lg">
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
<c:wdb-btn-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6
|
-
<c:wdb-btn-
|
|
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
|
-
|
|
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
|
-
|
|
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 })
|
package/lib/crud/edit-handler.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
@@ -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 {
|
|
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
|
|
12
|
-
const
|
|
13
|
-
const
|
|
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
|
-
|
|
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
|
|
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)
|
|
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,
|
|
49
|
+
return { fields, allFields, card, calcFields }
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
function autoLayout ({ action, schema, ext, layout
|
|
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
|
-
|
|
49
|
-
if (matches.includes(
|
|
50
|
-
else general.push(
|
|
51
|
-
}
|
|
52
|
-
if (meta.length <= 1) layout.push({ name: '_common',
|
|
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',
|
|
55
|
-
layout.push({ name: '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,
|
|
60
|
-
const {
|
|
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
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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 {
|
|
88
|
-
const {
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
17
|
-
const
|
|
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) => {
|