waibu-db 1.0.7 → 1.0.9
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/bajo/method/get-schema-ext.js +6 -3
- package/bajo/method/record/find-one.js +4 -8
- package/package.json +1 -1
- package/waibuBootstrap/theme/component/factory/btn-columns.js +2 -1
- package/waibuBootstrap/theme/component/factory/btn-delete.js +1 -0
- package/waibuBootstrap/theme/component/factory/query.js +2 -1
- package/waibuBootstrap/theme/component/factory/table.js +27 -15
- package/waibuMpa/partial/crud/_list-footer.html +8 -0
- package/waibuMpa/partial/crud/list-handler.html +1 -8
|
@@ -4,6 +4,7 @@ const defReadonly = ['id', 'createdAt', 'updatedAt']
|
|
|
4
4
|
|
|
5
5
|
function getCommons (action, schema, ext, opts = {}) {
|
|
6
6
|
const { map, get, set, without, uniq } = this.app.bajo.lib._
|
|
7
|
+
const label = get(ext, `view.${action}.label`, get(ext, 'common.label', {}))
|
|
7
8
|
const hidden = get(ext, `view.${action}.hidden`, get(ext, 'common.hidden', []))
|
|
8
9
|
hidden.push(...schema.hidden, ...(opts.hidden ?? []))
|
|
9
10
|
const allFields = without(map(schema.properties, 'name'), ...hidden)
|
|
@@ -17,7 +18,7 @@ function getCommons (action, schema, ext, opts = {}) {
|
|
|
17
18
|
}
|
|
18
19
|
fields = uniq(without(fields, ...hidden))
|
|
19
20
|
if (action !== 'add' && !fields.includes('id')) fields.unshift('id')
|
|
20
|
-
return { fields, allFields }
|
|
21
|
+
return { fields, allFields, label }
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
function autoLayout ({ action, schema, ext, layout, allWidgets }) {
|
|
@@ -58,7 +59,7 @@ function customLayout ({ action, schema, ext, layout, allWidgets, readonly }) {
|
|
|
58
59
|
|
|
59
60
|
function applyLayout (action, schema, ext) {
|
|
60
61
|
const { set, get, isEmpty, map, find } = this.app.bajo.lib._
|
|
61
|
-
const { fields } = getCommons.call(this, action, schema, ext)
|
|
62
|
+
const { fields, label } = getCommons.call(this, action, schema, ext)
|
|
62
63
|
const layout = get(ext, `view.${action}.layout`, get(ext, 'common.layout', []))
|
|
63
64
|
const readonly = get(ext, `view.${action}.readonly`, get(ext, 'common.readonly', defReadonly))
|
|
64
65
|
const allWidgets = map(fields, f => {
|
|
@@ -89,12 +90,13 @@ function applyLayout (action, schema, ext) {
|
|
|
89
90
|
else customLayout.call(this, { layout, allWidgets, schema, action, ext, readonly })
|
|
90
91
|
set(schema, 'view.layout', layout)
|
|
91
92
|
set(schema, 'view.fields', fields)
|
|
93
|
+
set(schema, 'view.label', label)
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
const handler = {
|
|
95
97
|
list: async function (schema, ext, opts) {
|
|
96
98
|
const { get, set } = this.app.bajo.lib._
|
|
97
|
-
const { fields } = getCommons.call(this, 'list', schema, ext, opts)
|
|
99
|
+
const { fields, label } = getCommons.call(this, 'list', schema, ext, opts)
|
|
98
100
|
const qsFields = []
|
|
99
101
|
for (const f of get(schema, 'view.qs.fields', '').split(',')) {
|
|
100
102
|
if (fields.includes(f)) qsFields.push(f)
|
|
@@ -102,6 +104,7 @@ const handler = {
|
|
|
102
104
|
let [col, dir] = get(schema, 'view.qs.sort', '').split(':')
|
|
103
105
|
if (!fields.includes(col) || !col) col = 'id'
|
|
104
106
|
if (!['1', '-1'].includes(dir)) dir = '1'
|
|
107
|
+
set(schema, 'view.label', label)
|
|
105
108
|
set(schema, 'view.fields', fields)
|
|
106
109
|
set(schema, 'view.qs.fields', qsFields.join(','))
|
|
107
110
|
set(schema, 'view.qs.sort', `${col}:${dir}`)
|
|
@@ -2,17 +2,13 @@ import prepCrud from '../../../lib/prep-crud.js'
|
|
|
2
2
|
|
|
3
3
|
async function find ({ model, req, reply, options = {} }) {
|
|
4
4
|
const { recordFindOne, attachmentFind } = this.app.dobo
|
|
5
|
-
const {
|
|
6
|
-
const { name, opts } = prepCrud.call(this, { model, req, options, args: ['model'] })
|
|
7
|
-
const cfgWeb = this.app.waibu.config
|
|
8
|
-
opts.bboxLatField = req.query[cfgWeb.qsKey.bboxLatField]
|
|
9
|
-
opts.bboxLngField = req.query[cfgWeb.qsKey.bboxLngField]
|
|
10
|
-
const filter = parseFilter(req)
|
|
5
|
+
const { name, opts, filter } = prepCrud.call(this, { model, req, options, args: ['model'] })
|
|
11
6
|
const ret = await recordFindOne(name, filter, opts)
|
|
12
|
-
ret.filter = filter
|
|
13
7
|
const { attachment, stats, mimeType } = req.query
|
|
14
8
|
if (attachment) {
|
|
15
|
-
|
|
9
|
+
for (const d of ret.data) {
|
|
10
|
+
d._attachment = await attachmentFind(name, d.id, { stats, mimeType })
|
|
11
|
+
}
|
|
16
12
|
}
|
|
17
13
|
return ret
|
|
18
14
|
}
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ async function btnColumns () {
|
|
|
24
24
|
items.push(await this.component.buildTag({ tag: 'formCheck', attr: { checked: true, label: req.t('ID'), value: f, disabled: true } }))
|
|
25
25
|
continue
|
|
26
26
|
}
|
|
27
|
-
const attr = { 'x-model': 'selected', label: req.t(`field.${f}`), value: f }
|
|
27
|
+
const attr = { 'x-model': 'selected', label: req.t(get(schema, `view.label.${f}`, `field.${f}`)), value: f }
|
|
28
28
|
if (fields.includes(f)) attr.checked = true
|
|
29
29
|
items.push(await this.component.buildTag({ tag: 'formCheck', attr }))
|
|
30
30
|
}
|
|
@@ -46,6 +46,7 @@ async function btnColumns () {
|
|
|
46
46
|
html.push('</form>')
|
|
47
47
|
this.params.attr.autoClose = 'outside'
|
|
48
48
|
this.params.attr.triggerColor = this.params.attr.color
|
|
49
|
+
this.params.attr.menudir = this.params.attr.menudir ?? 'end'
|
|
49
50
|
this.params.html = await this.component.buildTag({ tag: 'dropdown', attr: this.params.attr, html: html.join('\n') })
|
|
50
51
|
this.params.noTag = true
|
|
51
52
|
}
|
|
@@ -32,9 +32,10 @@ async function query () {
|
|
|
32
32
|
if (ops.length === 0) continue
|
|
33
33
|
const sels = ops.map(o => `<c:option>${o}</c:option>`)
|
|
34
34
|
models.push(`${f}Op: 'eq'`, `${f}Val: ''`)
|
|
35
|
+
const label = this.component.req.t(get(schema, `view.label.${f}`, `field.${f}`))
|
|
35
36
|
columns.push(`
|
|
36
37
|
<c:grid-col col="4-md" flex="align-items:center">
|
|
37
|
-
<c:form-check x-model="selected" t:label="
|
|
38
|
+
<c:form-check x-model="selected" t:label="${label}" value="${f}" />
|
|
38
39
|
</c:grid-col>
|
|
39
40
|
<c:grid-col col="3-md">
|
|
40
41
|
<c:form-select x-model="${f}Op">
|
|
@@ -6,9 +6,10 @@ async function table () {
|
|
|
6
6
|
return class WdbTable extends WdbBase {
|
|
7
7
|
isRightAligned (field, schema) {
|
|
8
8
|
const { get, find } = this.plugin.app.bajo.lib._
|
|
9
|
-
const
|
|
9
|
+
const prop = find(schema.properties, { name: field })
|
|
10
|
+
if (!prop) return false
|
|
10
11
|
let value = get(schema, 'view.alignEnd', []).includes(field)
|
|
11
|
-
if (!value) value = ['smallint', 'integer', 'float', 'double'].includes(type)
|
|
12
|
+
if (!value) value = ['smallint', 'integer', 'float', 'double'].includes(prop.type)
|
|
12
13
|
return value
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -19,15 +20,18 @@ async function table () {
|
|
|
19
20
|
|
|
20
21
|
async build () {
|
|
21
22
|
const { req } = this.component
|
|
23
|
+
const { callHandler } = this.plugin.app.bajo
|
|
22
24
|
const { escape } = this.plugin.app.waibu
|
|
23
25
|
const { attrToArray, groupAttrs } = this.plugin.app.waibuMpa
|
|
24
|
-
const { get, omit, set, find, isEmpty, without } = this.plugin.app.bajo.lib._
|
|
26
|
+
const { get, omit, set, find, isEmpty, without, isFunction } = this.plugin.app.bajo.lib._
|
|
25
27
|
const group = groupAttrs(this.params.attr, ['body', 'head', 'foot'])
|
|
26
28
|
this.params.attr = group._
|
|
29
|
+
const prettyUrl = this.params.attr.prettyUrl
|
|
27
30
|
|
|
28
31
|
const data = get(this, 'component.locals.list.data', [])
|
|
29
32
|
const schema = get(this, 'component.locals.schema', {})
|
|
30
|
-
|
|
33
|
+
const disableds = get(schema, 'view.disabled', [])
|
|
34
|
+
if (disableds.includes('find')) {
|
|
31
35
|
this.params.html = ''
|
|
32
36
|
return
|
|
33
37
|
}
|
|
@@ -40,8 +44,8 @@ async function table () {
|
|
|
40
44
|
if (!['-1', '1'].includes(sortDir)) sortDir = '1'
|
|
41
45
|
|
|
42
46
|
let selection
|
|
43
|
-
const canDelete = !
|
|
44
|
-
const canEdit = !
|
|
47
|
+
const canDelete = !disableds.includes('remove')
|
|
48
|
+
const canEdit = !disableds.includes('update')
|
|
45
49
|
if (canEdit) selection = 'single'
|
|
46
50
|
if (canDelete) selection = 'multi'
|
|
47
51
|
if (selection) this.params.attr.hover = true
|
|
@@ -53,7 +57,8 @@ async function table () {
|
|
|
53
57
|
for (const f of schema.view.fields) {
|
|
54
58
|
if (!fields.includes(f)) continue
|
|
55
59
|
const prop = find(schema.properties, { name: f })
|
|
56
|
-
|
|
60
|
+
if (!prop) continue
|
|
61
|
+
let head = req.t(get(schema, `view.label.${f}`, `field.${f}`))
|
|
57
62
|
if (!this.params.attr.noSort && (schema.sortables ?? []).includes(f)) {
|
|
58
63
|
let sortItem = `${f}:-1`
|
|
59
64
|
let icon = this.params.attr.sortUpIcon ?? 'caretUp'
|
|
@@ -65,7 +70,7 @@ async function table () {
|
|
|
65
70
|
const href = this.component.buildUrl({ params: item })
|
|
66
71
|
const attr = this.isRightAligned(f, schema) ? { text: 'align:end' } : {}
|
|
67
72
|
const content = [
|
|
68
|
-
await this.component.buildTag({ tag: 'div', attr, html:
|
|
73
|
+
await this.component.buildTag({ tag: 'div', attr, html: head }),
|
|
69
74
|
await this.component.buildTag({ tag: 'a', attr: { icon, href }, prepend: '<div class="ms-1">', append: '</div>' })
|
|
70
75
|
]
|
|
71
76
|
head = await this.component.buildTag({ tag: 'div', attr: { flex: 'justify-content:between align-items:end' }, html: content.join('\n') })
|
|
@@ -95,11 +100,14 @@ async function table () {
|
|
|
95
100
|
if (selection) {
|
|
96
101
|
const tag = selection === 'single' ? 'formRadio' : 'formCheck'
|
|
97
102
|
const attr = { 'x-model': 'selected', name: '_rt', value: d.id, noLabel: true, noWrapper: true }
|
|
98
|
-
|
|
103
|
+
const type = find(schema.properties, { name: 'id' }).type
|
|
104
|
+
const prepend = `<td data-value="${d.id}" data-key="id" data-type="${type}">`
|
|
105
|
+
lines.push(await this.component.buildTag({ tag, attr, prepend, append: '</td>' }))
|
|
99
106
|
}
|
|
100
107
|
for (const f of schema.view.fields) {
|
|
101
|
-
const prop = find(schema.properties, { name: f })
|
|
102
108
|
if (!fields.includes(f)) continue
|
|
109
|
+
const prop = find(schema.properties, { name: f })
|
|
110
|
+
if (!prop) continue
|
|
103
111
|
const opts = {}
|
|
104
112
|
if (f === 'lng') opts.longitude = true
|
|
105
113
|
else if (f === 'lat') opts.latitude = true
|
|
@@ -111,27 +119,31 @@ async function table () {
|
|
|
111
119
|
let dataValue = d[f] ?? ''
|
|
112
120
|
if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
|
|
113
121
|
if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
|
|
114
|
-
const attr = { dataValue }
|
|
122
|
+
const attr = { dataValue, dataKey: prop.name, dataType: prop.type }
|
|
115
123
|
if (!['object', 'array'].includes(prop.type)) {
|
|
116
124
|
const noWrap = this.isNoWrap(f, schema) ? 'nowrap' : ''
|
|
117
125
|
if (this.isRightAligned(f, schema)) attr.text = `align:end ${noWrap}`
|
|
118
126
|
else attr.text = noWrap
|
|
119
127
|
}
|
|
120
128
|
const formatter = get(schema, `formatter.${f}`)
|
|
121
|
-
if (formatter)
|
|
129
|
+
if (formatter) {
|
|
130
|
+
if (isFunction(formatter)) value = await formatter(dataValue, d)
|
|
131
|
+
else value = await callHandler(formatter, req, dataValue, d)
|
|
132
|
+
value = await this.component.buildSentence(value)
|
|
133
|
+
}
|
|
122
134
|
const line = await this.component.buildTag({ tag: 'td', attr, html: value })
|
|
123
135
|
lines.push(line)
|
|
124
136
|
}
|
|
125
137
|
const attr = {}
|
|
126
|
-
if (!
|
|
127
|
-
if (!
|
|
138
|
+
if (!disableds.includes('update') || !disableds.includes('remove')) attr['@click'] = `toggle('${d.id}')`
|
|
139
|
+
if (!disableds.includes('get')) attr['@dblclick'] = `goDetails('${d.id}')`
|
|
128
140
|
items.push(await this.component.buildTag({ tag: 'tr', attr, html: lines.join('\n') }))
|
|
129
141
|
}
|
|
130
142
|
html.push(await this.component.buildTag({ tag: 'tbody', attr: group.body, html: items.join('\n') }))
|
|
131
143
|
this.params.attr = omit(this.params.attr, ['sortUpIcon', 'sortDownIcon', 'noSort', 'selection', 'headerNowrap'])
|
|
132
144
|
const goDetails = `
|
|
133
145
|
goDetails (id) {
|
|
134
|
-
window.location.href = '${this.component.buildUrl({ base: 'details' })}&id=' + id
|
|
146
|
+
window.location.href = '${this.component.buildUrl({ base: 'details', prettyUrl })}&id=' + id
|
|
135
147
|
}
|
|
136
148
|
`
|
|
137
149
|
if (selection === 'multi') {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<c:grid-row gutter="3" margin="top-2">
|
|
2
|
+
<c:grid-col col="6-lg">
|
|
3
|
+
<c:wdb-recs-info pages recs-per-page recs-per-page-values="10 15 25 50" />
|
|
4
|
+
</c:grid-col>
|
|
5
|
+
<c:grid-col col="6-lg" flex="justify-content:end-lg">
|
|
6
|
+
<c:wdb-pagination />
|
|
7
|
+
</c:grid-col>
|
|
8
|
+
</c:grid-row>
|
|
@@ -15,12 +15,5 @@
|
|
|
15
15
|
</c:grid-col>
|
|
16
16
|
</c:grid-row>
|
|
17
17
|
<c:wdb-table id="main-table" border body-divider strip responsive />
|
|
18
|
-
<c:
|
|
19
|
-
<c:grid-col col="6-lg">
|
|
20
|
-
<c:wdb-recs-info pages recs-per-page recs-per-page-values="10 15 25 50" />
|
|
21
|
-
</c:grid-col>
|
|
22
|
-
<c:grid-col col="6-lg" flex="justify-content:end-lg">
|
|
23
|
-
<c:wdb-pagination />
|
|
24
|
-
</c:grid-col>
|
|
25
|
-
</c:grid-row>
|
|
18
|
+
<c:include resource="waibuDb.partial:/crud/_list-footer.html" />
|
|
26
19
|
<c:include resource="waibuDb.partial:/crud/_addons.html" />
|