waibu-db 1.0.1 → 1.0.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.
- package/package.json +1 -1
- package/waibuBootstrap/theme/component/factory/btn-add.js +24 -0
- package/waibuBootstrap/theme/component/factory/btn-back.js +22 -0
- package/waibuBootstrap/theme/component/factory/btn-clone.js +39 -0
- package/waibuBootstrap/theme/component/factory/btn-columns.js +55 -0
- package/waibuBootstrap/theme/component/factory/btn-delete.js +52 -0
- package/waibuBootstrap/theme/component/factory/btn-details.js +41 -0
- package/waibuBootstrap/theme/component/factory/btn-edit.js +67 -0
- package/waibuBootstrap/theme/component/factory/btn-export.js +138 -0
- package/waibuBootstrap/theme/component/factory/echarts.js +68 -0
- package/waibuBootstrap/theme/component/factory/pagination.js +69 -0
- package/waibuBootstrap/theme/component/factory/query.js +145 -0
- package/waibuBootstrap/theme/component/factory/recs-info.js +58 -0
- package/waibuBootstrap/theme/component/factory/table.js +168 -0
- package/waibuBootstrap/theme/component/wdb-base.js +6 -0
- package/waibuBootstrap/theme/component/btn-add.js +0 -15
- package/waibuBootstrap/theme/component/btn-back.js +0 -13
- package/waibuBootstrap/theme/component/btn-clone.js +0 -30
- package/waibuBootstrap/theme/component/btn-columns.js +0 -45
- package/waibuBootstrap/theme/component/btn-delete.js +0 -43
- package/waibuBootstrap/theme/component/btn-details.js +0 -32
- package/waibuBootstrap/theme/component/btn-edit.js +0 -56
- package/waibuBootstrap/theme/component/btn-export.js +0 -129
- package/waibuBootstrap/theme/component/echarts.js +0 -58
- package/waibuBootstrap/theme/component/pagination.js +0 -60
- package/waibuBootstrap/theme/component/query.js +0 -137
- package/waibuBootstrap/theme/component/recs-info.js +0 -50
- package/waibuBootstrap/theme/component/table.js +0 -161
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import wdbBase from '../wdb-base.js'
|
|
2
|
+
|
|
3
|
+
async function query () {
|
|
4
|
+
const WdbBase = await wdbBase.call(this)
|
|
5
|
+
|
|
6
|
+
return class WdbQuery extends WdbBase {
|
|
7
|
+
async build () {
|
|
8
|
+
const { generateId } = this.plugin.app.bajo
|
|
9
|
+
const { jsonStringify } = this.plugin.app.waibuMpa
|
|
10
|
+
const { find, get, without, isEmpty, filter, upperFirst } = this.plugin.app.bajo.lib._
|
|
11
|
+
const qsKey = this.plugin.app.waibu.config.qsKey
|
|
12
|
+
const schema = get(this, 'component.locals.schema', {})
|
|
13
|
+
if (schema.view.disabled.includes('find')) {
|
|
14
|
+
this.params.html = ''
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
let fields = without(get(this, `component.locals._meta.query.${qsKey.fields}`, '').split(','), '')
|
|
18
|
+
if (isEmpty(fields)) fields = schema.view.fields
|
|
19
|
+
fields = filter(fields, f => schema.sortables.includes(f))
|
|
20
|
+
const id = generateId('alpha')
|
|
21
|
+
const columns = []
|
|
22
|
+
const models = []
|
|
23
|
+
const selects = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'contains', 'starts', 'ends', '!in', '!contains', '!starts', '!ends']
|
|
24
|
+
for (const f of schema.view.fields) {
|
|
25
|
+
if (!fields.includes(f)) continue
|
|
26
|
+
const prop = find(schema.properties, { name: f })
|
|
27
|
+
const ops = []
|
|
28
|
+
if (['float', 'double', 'integer', 'smallint'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
|
|
29
|
+
else if (['datetime', 'date', 'time'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
|
|
30
|
+
else if (['boolean'].includes(prop.type)) ops.push('eq', 'neq')
|
|
31
|
+
else ops.push(...selects)
|
|
32
|
+
if (ops.length === 0) continue
|
|
33
|
+
const sels = ops.map(o => `<c:option>${o}</c:option>`)
|
|
34
|
+
models.push(`${f}Op: 'eq'`, `${f}Val: ''`)
|
|
35
|
+
columns.push(`
|
|
36
|
+
<c:grid-col col="4-md" flex="align-items:center">
|
|
37
|
+
<c:form-check x-model="selected" t:label="field.${f}" value="${f}" />
|
|
38
|
+
</c:grid-col>
|
|
39
|
+
<c:grid-col col="3-md">
|
|
40
|
+
<c:form-select x-model="${f}Op">
|
|
41
|
+
${sels.join('\n')}
|
|
42
|
+
</c:form-select>
|
|
43
|
+
</c:grid-col>
|
|
44
|
+
<c:grid-col col="5-md">
|
|
45
|
+
<c:form-input x-model="${f}Val" />
|
|
46
|
+
</c:grid-col>
|
|
47
|
+
`)
|
|
48
|
+
}
|
|
49
|
+
this.params.noTag = true
|
|
50
|
+
const container = this.params.attr.modal ? 'modal' : 'drawer'
|
|
51
|
+
this.params.html = await this.component.buildSentence(`
|
|
52
|
+
<c:form-input type="search" t:placeholder="Query" id="${id}" x-data="{ query: '' }" x-init="
|
|
53
|
+
const url = new URL(window.location.href)
|
|
54
|
+
query = url.searchParams.get('${qsKey.query}') ?? ''
|
|
55
|
+
" x-model="query" @on-query.window="query = $event.detail ?? ''" @keyup.enter="$dispatch('on-submit')">
|
|
56
|
+
<c:form-input-addon>
|
|
57
|
+
<c:${container} launch-icon="${this.params.attr.icon ?? 'dotsThree'}" launch-on-end t:title="Query Builder" x-ref="query" x-data="{
|
|
58
|
+
fields: ${jsonStringify(fields, true)},
|
|
59
|
+
builder: '',
|
|
60
|
+
selected: [],
|
|
61
|
+
${models.join(',\n')},
|
|
62
|
+
ops: { eq: ':', neq: ':-', gt: ':>', gte: ':>=', lt: ':<', lte: ':<=' },
|
|
63
|
+
opsIn (v, neg) { return ':' + (neg ? '-' : '') + '[' + this.expandArray(v) + ']' },
|
|
64
|
+
opsExt (v, neg, ext) {
|
|
65
|
+
let prefix = (neg ? '-' : '') + '~'
|
|
66
|
+
if (ext) prefix += ext
|
|
67
|
+
return ':' + prefix + '\\'' + v + '\\''
|
|
68
|
+
},
|
|
69
|
+
expandArray (val = '') {
|
|
70
|
+
return _.map(val.split(','), item => {
|
|
71
|
+
item = _.trim(item)
|
|
72
|
+
if (Number(item)) return item
|
|
73
|
+
return '\\'' + item + '\\''
|
|
74
|
+
})
|
|
75
|
+
},
|
|
76
|
+
rebuild () {
|
|
77
|
+
const items = []
|
|
78
|
+
for (const sel of this.selected) {
|
|
79
|
+
const key = this[sel + 'Op']
|
|
80
|
+
let val = this[sel + 'Val']
|
|
81
|
+
if (_.isEmpty(val)) continue
|
|
82
|
+
let item
|
|
83
|
+
if (key === 'in') item = this.opsIn(val)
|
|
84
|
+
else if (key === '!in') item = this.opsIn(val, true)
|
|
85
|
+
else if (key === 'contains') item = this.opsExt(val)
|
|
86
|
+
else if (key === '!contains') item = this.opsExt(val, true)
|
|
87
|
+
else if (key === 'starts') item = this.opsExt(val, false, '^')
|
|
88
|
+
else if (key === '!starts') item = this.opsExt(val, true, '^')
|
|
89
|
+
else if (key === 'ends') item = this.opsExt(val, false, '$$')
|
|
90
|
+
else if (key === '!ends') item = this.opsExt(val, true, '$$')
|
|
91
|
+
else if (val.includes(' ')) item = this.ops[key] + '\\'' + val + '\\''
|
|
92
|
+
else item = this.ops[key] + val
|
|
93
|
+
items.push(sel + item)
|
|
94
|
+
}
|
|
95
|
+
this.builder = items.join('+')
|
|
96
|
+
},
|
|
97
|
+
submit (run) {
|
|
98
|
+
if (run) {
|
|
99
|
+
const url = new URL(window.location.href)
|
|
100
|
+
const params = new URLSearchParams(url.search)
|
|
101
|
+
this.params.set('${qsKey.page}', 1)
|
|
102
|
+
this.params.set('${qsKey.query}', this.builder ?? '')
|
|
103
|
+
window.location.href = '?' + this.params.toString()
|
|
104
|
+
} else $dispatch('on-query', this.builder)
|
|
105
|
+
const instance = wbs.getInstance('${upperFirst(container)}', $refs.query)
|
|
106
|
+
instance.hide()
|
|
107
|
+
}
|
|
108
|
+
}" x-init="
|
|
109
|
+
const ops = _.map(fields, f => (f + 'Op'))
|
|
110
|
+
const vals = _.map(fields, f => (f + 'Val'))
|
|
111
|
+
const watcher = ['selected', ...ops, ...vals].join(',')
|
|
112
|
+
$watch(watcher, v => rebuild())
|
|
113
|
+
">
|
|
114
|
+
<c:grid-row gutter="2">
|
|
115
|
+
<c:grid-col col="12">
|
|
116
|
+
<c:form-textarea x-model="builder" readonly rows="4"/>
|
|
117
|
+
</c:grid-col>
|
|
118
|
+
${columns.join('\n')}
|
|
119
|
+
</c:grid-row>
|
|
120
|
+
<c:div flex="justify-content:end" margin="top-3">
|
|
121
|
+
<c:btn color="secondary" t:content="Close" dismiss="${container}" />
|
|
122
|
+
<c:btn color="primary" t:content="Apply" margin="start-2" @click="submit()" />
|
|
123
|
+
<c:btn color="primary" t:content="Submit Query" margin="start-2" @click="submit(true)" />
|
|
124
|
+
</c:div>
|
|
125
|
+
</c:${container}>
|
|
126
|
+
</c:form-input-addon>
|
|
127
|
+
<c:form-input-addon>
|
|
128
|
+
<c:btn t:content="Submit" x-data="{
|
|
129
|
+
submit () {
|
|
130
|
+
const val = document.getElementById('${id}').value ?? ''
|
|
131
|
+
const url = new URL(window.location.href)
|
|
132
|
+
const params = new URLSearchParams(url.search)
|
|
133
|
+
this.params.set('${qsKey.page}', 1)
|
|
134
|
+
this.params.set('${qsKey.query}', val)
|
|
135
|
+
window.location.href = '?' + this.params.toString()
|
|
136
|
+
}
|
|
137
|
+
}" @click="submit" @on-submit.window="submit()" />
|
|
138
|
+
</c:form-input-addon>
|
|
139
|
+
</c:form-input>
|
|
140
|
+
`)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default query
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getUrlOpts } from './pagination.js'
|
|
2
|
+
import wdbBase from '../wdb-base.js'
|
|
3
|
+
|
|
4
|
+
async function recsInfo () {
|
|
5
|
+
const WdbBase = await wdbBase.call(this)
|
|
6
|
+
|
|
7
|
+
return class WdbRecsInfo extends WdbBase {
|
|
8
|
+
async build () {
|
|
9
|
+
const { req } = this.component
|
|
10
|
+
const { attrToObject, groupAttrs, attrToArray } = this.plugin.app.waibuMpa
|
|
11
|
+
const { get, isEmpty, omit, merge } = this.plugin.app.bajo.lib._
|
|
12
|
+
const schema = get(this, 'component.locals.schema', {})
|
|
13
|
+
if (schema.view.disabled.includes('find')) {
|
|
14
|
+
this.params.html = ''
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
let { count, limit, page, pages } = attrToObject(this.params.attr.options)
|
|
18
|
+
count = count ?? get(this, 'component.locals.list.count', 0)
|
|
19
|
+
page = page ?? get(this, 'component.locals.list.page', 1)
|
|
20
|
+
limit = limit ?? get(this, 'component.locals.list.limit', 25)
|
|
21
|
+
pages = pages ?? get(this, 'component.locals.list.pages', 0)
|
|
22
|
+
|
|
23
|
+
this.params.tag = 'div'
|
|
24
|
+
this.params.attr.flex = 'justify-center:start align-items:center'
|
|
25
|
+
if (count === 0) {
|
|
26
|
+
this.params.html = req.t('No record found')
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
if (!this.params.attr.dropdown) this.params.attr.dropdown = true
|
|
30
|
+
const group = groupAttrs(this.params.attr, ['dropdown'])
|
|
31
|
+
const html = []
|
|
32
|
+
if (this.params.attr.count) html.push(req.t('%s record(s) found', req.format(count, 'integer')))
|
|
33
|
+
if (this.params.attr.pages) {
|
|
34
|
+
if (!isEmpty(html)) html[html.length - 1] += '.'
|
|
35
|
+
html.push(req.t('Page %s of %s pages', req.format(page, 'integer'), req.format(pages, 'integer')))
|
|
36
|
+
}
|
|
37
|
+
if (this.params.attr.recsPerPage) {
|
|
38
|
+
this.params.attr.recsPerPageValues = this.params.attr.recsPerPageValues ?? '10 25 50'
|
|
39
|
+
this.params.attr.recsPerPageValues = attrToArray(this.params.attr.recsPerPageValues)
|
|
40
|
+
if (!isEmpty(html)) html[html.length - 1] += ','
|
|
41
|
+
const items = []
|
|
42
|
+
for (const i of this.params.attr.recsPerPageValues) {
|
|
43
|
+
const attr = { href: this.component.buildUrl(merge(getUrlOpts.call(this), { params: { limit: i, page: 1 } })), disabled: i === limit }
|
|
44
|
+
items.push(await this.component.buildTag({ tag: 'dropdownItem', attr, html: i + '' }))
|
|
45
|
+
}
|
|
46
|
+
const attr = group.dropdown
|
|
47
|
+
attr.content = limit + ''
|
|
48
|
+
attr.color = attr.color ?? 'secondary-outline'
|
|
49
|
+
html.push(await this.component.buildTag({ tag: 'dropdown', attr, html: items.join('\n') }))
|
|
50
|
+
html.push(' ', req.t('recs per page'))
|
|
51
|
+
}
|
|
52
|
+
this.params.attr = omit(this.params.attr, ['count', 'pages', 'recsPerPage', 'dropdown', 'recsPerPageValues'])
|
|
53
|
+
this.params.html = html.map(h => `<div class="me-1">${h}</div>`).join('\n')
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default recsInfo
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import wdbBase from '../wdb-base.js'
|
|
2
|
+
|
|
3
|
+
async function table () {
|
|
4
|
+
const WdbBase = await wdbBase.call(this)
|
|
5
|
+
|
|
6
|
+
return class WdbTable extends WdbBase {
|
|
7
|
+
isRightAligned (type) {
|
|
8
|
+
return ['smallint', 'integer', 'float', 'double'].includes(type)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async build () {
|
|
12
|
+
const { req } = this.component
|
|
13
|
+
const { escape } = this.plugin.app.waibu
|
|
14
|
+
const { attrToArray, groupAttrs } = this.plugin.app.waibuMpa
|
|
15
|
+
const { get, omit, set, find, isEmpty, without } = this.plugin.app.bajo.lib._
|
|
16
|
+
const group = groupAttrs(this.params.attr, ['body', 'head', 'foot'])
|
|
17
|
+
this.params.attr = group._
|
|
18
|
+
|
|
19
|
+
const data = get(this, 'component.locals.list.data', [])
|
|
20
|
+
const schema = get(this, 'component.locals.schema', {})
|
|
21
|
+
if (schema.view.disabled.includes('find')) {
|
|
22
|
+
this.params.html = ''
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
const qsKey = this.plugin.app.waibu.config.qsKey
|
|
26
|
+
let fields = without(get(this, `component.locals._meta.query.${qsKey.fields}`, '').split(','), '')
|
|
27
|
+
if (isEmpty(fields)) fields = schema.view.fields
|
|
28
|
+
const sort = this.params.attr.sort ? attrToArray(this.params.attr.sort) : get(this, `component.locals._meta.query.${qsKey.sort}`, '')
|
|
29
|
+
|
|
30
|
+
let [sortCol, sortDir] = sort.split(':')
|
|
31
|
+
if (!['-1', '1'].includes(sortDir)) sortDir = '1'
|
|
32
|
+
|
|
33
|
+
let selection
|
|
34
|
+
const canDelete = !schema.view.disabled.includes('remove')
|
|
35
|
+
const canEdit = !schema.view.disabled.includes('update')
|
|
36
|
+
if (canEdit) selection = 'single'
|
|
37
|
+
if (canDelete) selection = 'multi'
|
|
38
|
+
if (selection) this.params.attr.hover = true
|
|
39
|
+
|
|
40
|
+
this.params.noTag = true
|
|
41
|
+
const html = []
|
|
42
|
+
let items = []
|
|
43
|
+
// head
|
|
44
|
+
for (const f of schema.view.fields) {
|
|
45
|
+
if (!fields.includes(f)) continue
|
|
46
|
+
const prop = find(schema.properties, { name: f })
|
|
47
|
+
let head = req.t(`field.${f}`)
|
|
48
|
+
if (!this.params.attr.noSort && (schema.sortables ?? []).includes(f)) {
|
|
49
|
+
let sortItem = `${f}:-1`
|
|
50
|
+
let icon = this.params.attr.sortUpIcon ?? 'caretUp'
|
|
51
|
+
if (f === sortCol) {
|
|
52
|
+
sortItem = `${f}:${sortDir === '1' ? '-1' : '1'}`
|
|
53
|
+
icon = sortDir === '1' ? (this.params.attr.sortUpIcon ?? 'caretUp') : (this.params.attr.sortDownIcon ?? 'caretDown')
|
|
54
|
+
}
|
|
55
|
+
const item = set({ page: 1 }, qsKey.sort, sortItem)
|
|
56
|
+
const href = this.component.buildUrl({ params: item })
|
|
57
|
+
const attr = this.isRightAligned(prop.type) ? { text: 'align:end' } : {}
|
|
58
|
+
const content = [
|
|
59
|
+
await this.component.buildTag({ tag: 'div', attr, html: req.t(`field.${f}`) }),
|
|
60
|
+
await this.component.buildTag({ tag: 'a', attr: { icon, href }, prepend: '<div class="ms-1">', append: '</div>' })
|
|
61
|
+
]
|
|
62
|
+
head = await this.component.buildTag({ tag: 'div', attr: { flex: 'justify-content:between align-items:end' }, html: content.join('\n') })
|
|
63
|
+
}
|
|
64
|
+
let text = this.params.attr.headerNowrap ? '' : 'nowrap'
|
|
65
|
+
if (this.isRightAligned(prop.type)) text += ' align:end'
|
|
66
|
+
const attr = { dataKey: f, dataType: prop.type, text }
|
|
67
|
+
items.push(await this.component.buildTag({ tag: 'th', attr, html: head }))
|
|
68
|
+
}
|
|
69
|
+
if (items.length > 0 && selection) {
|
|
70
|
+
let item = '<th></th>'
|
|
71
|
+
if (selection === 'multi') {
|
|
72
|
+
const attr = { 'x-model': 'toggleAll', name: '_rtm', noWrapper: true, noLabel: true }
|
|
73
|
+
item = await this.component.buildTag({ tag: 'formCheck', attr, prepend: '<th>', append: '</th>' })
|
|
74
|
+
} else {
|
|
75
|
+
const attr = { name: 'remove', '@click': 'selected = \'\'', style: { cursor: 'pointer' } }
|
|
76
|
+
item = await this.component.buildTag({ tag: 'icon', attr, prepend: '<th>', append: '</th>' })
|
|
77
|
+
}
|
|
78
|
+
items.unshift(item)
|
|
79
|
+
}
|
|
80
|
+
const header = await this.component.buildTag({ tag: 'tr', html: items.join('\n') })
|
|
81
|
+
html.push(await this.component.buildTag({ tag: 'thead', attr: group.head, html: header }))
|
|
82
|
+
// body
|
|
83
|
+
items = []
|
|
84
|
+
for (const d of data) {
|
|
85
|
+
const lines = []
|
|
86
|
+
if (selection) {
|
|
87
|
+
const tag = selection === 'single' ? 'formRadio' : 'formCheck'
|
|
88
|
+
const attr = { 'x-model': 'selected', name: '_rt', value: d.id, noLabel: true, noWrapper: true }
|
|
89
|
+
lines.push(await this.component.buildTag({ tag, attr, prepend: '<td>', append: '</td>' }))
|
|
90
|
+
}
|
|
91
|
+
for (const f of schema.view.fields) {
|
|
92
|
+
const prop = find(schema.properties, { name: f })
|
|
93
|
+
if (!fields.includes(f)) continue
|
|
94
|
+
const opts = {}
|
|
95
|
+
if (f === 'lng') opts.longitude = true
|
|
96
|
+
else if (f === 'lat') opts.latitude = true
|
|
97
|
+
let value = req.format(d[f], prop.type, opts)
|
|
98
|
+
if (prop.type === 'boolean') {
|
|
99
|
+
value = (await this.component.buildTag({ tag: 'icon', attr: { name: `circle${d[f] ? 'Check' : ''}` } })) +
|
|
100
|
+
' ' + (req.t(d[f] ? 'Yes' : 'No'))
|
|
101
|
+
} else value = escape(value)
|
|
102
|
+
let dataValue = d[f] ?? ''
|
|
103
|
+
if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
|
|
104
|
+
if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
|
|
105
|
+
const attr = { dataValue }
|
|
106
|
+
if (!['object', 'array'].includes(prop.type)) {
|
|
107
|
+
if (this.isRightAligned(prop.type)) attr.text = 'align:end nowrap'
|
|
108
|
+
else attr.text = 'nowrap'
|
|
109
|
+
}
|
|
110
|
+
const line = await this.component.buildTag({ tag: 'td', attr, html: value })
|
|
111
|
+
lines.push(line)
|
|
112
|
+
}
|
|
113
|
+
const attr = {}
|
|
114
|
+
if (!schema.view.disabled.includes('update') || !schema.view.disabled.includes('remove')) attr['@click'] = `toggle('${d.id}')`
|
|
115
|
+
if (!schema.view.disabled.includes('get')) attr['@dblclick'] = `goDetails('${d.id}')`
|
|
116
|
+
items.push(await this.component.buildTag({ tag: 'tr', attr, html: lines.join('\n') }))
|
|
117
|
+
}
|
|
118
|
+
html.push(await this.component.buildTag({ tag: 'tbody', attr: group.body, html: items.join('\n') }))
|
|
119
|
+
this.params.attr = omit(this.params.attr, ['sortUpIcon', 'sortDownIcon', 'noSort', 'selection', 'headerNowrap'])
|
|
120
|
+
const goDetails = `
|
|
121
|
+
goDetails (id) {
|
|
122
|
+
window.location.href = '${this.component.buildUrl({ base: 'details' })}&id=' + id
|
|
123
|
+
}
|
|
124
|
+
`
|
|
125
|
+
if (selection === 'multi') {
|
|
126
|
+
this.params.attr['x-data'] = `{
|
|
127
|
+
toggleAll: false,
|
|
128
|
+
selected: [],
|
|
129
|
+
toggle (id) {
|
|
130
|
+
if (this.selected.includes(id)) {
|
|
131
|
+
const idx = this.selected.indexOf(id)
|
|
132
|
+
this.selected.splice(idx, 1)
|
|
133
|
+
} else this.selected.push(id)
|
|
134
|
+
},
|
|
135
|
+
${goDetails}
|
|
136
|
+
}`
|
|
137
|
+
this.params.attr['x-init'] = `
|
|
138
|
+
$watch('toggleAll', val => {
|
|
139
|
+
if (val) {
|
|
140
|
+
const els = document.getElementsByName('_rt')
|
|
141
|
+
const items = Array.from(els)
|
|
142
|
+
selected = items.map(el => el.value)
|
|
143
|
+
} else selected = []
|
|
144
|
+
})
|
|
145
|
+
$watch('selected', val => $dispatch('on-selection', val))
|
|
146
|
+
`
|
|
147
|
+
} else if (selection === 'single') {
|
|
148
|
+
this.params.attr['x-data'] = `{
|
|
149
|
+
selected: '',
|
|
150
|
+
toggle (id) {
|
|
151
|
+
this.selected = id
|
|
152
|
+
},
|
|
153
|
+
${goDetails}
|
|
154
|
+
}`
|
|
155
|
+
this.params.attr['x-init'] = `
|
|
156
|
+
$watch('selected', val => $dispatch('on-selection', [val]))
|
|
157
|
+
`
|
|
158
|
+
} else {
|
|
159
|
+
this.params.attr['x-data'] = `{
|
|
160
|
+
${goDetails}
|
|
161
|
+
}`
|
|
162
|
+
}
|
|
163
|
+
this.params.html = await this.component.buildTag({ tag: 'table', attr: this.params.attr, html: html.join('\n') })
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default table
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
async function btnAdd (params = {}) {
|
|
2
|
-
const { isEmpty, get } = this.plugin.app.bajo.lib._
|
|
3
|
-
params.noTag = true
|
|
4
|
-
const schema = get(this, 'locals.schema', {})
|
|
5
|
-
if (schema.view.disabled.includes('create')) {
|
|
6
|
-
params.html = ''
|
|
7
|
-
return
|
|
8
|
-
}
|
|
9
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Add')
|
|
10
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
11
|
-
if (!params.attr.href) params.attr.href = this._buildUrl({ base: 'add' })
|
|
12
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default btnAdd
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
async function btnBack (params = {}) {
|
|
2
|
-
const { isEmpty } = this.plugin.app.bajo.lib._
|
|
3
|
-
const { attrToArray } = this.plugin.app.waibuMpa
|
|
4
|
-
params.noTag = true
|
|
5
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Back')
|
|
6
|
-
if (isEmpty(params.attr.icon)) params.attr.icon = 'arrowStart'
|
|
7
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
8
|
-
params.attr.excludeQs = ['mode', 'id', ...attrToArray(params.attr.excludeQs ?? '')]
|
|
9
|
-
if (!params.attr.href) params.attr.href = this._buildUrl({ base: 'list', exclude: params.attr.excludeQs })
|
|
10
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default btnBack
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
async function btnClone (params = {}) {
|
|
2
|
-
const { isEmpty, get } = this.plugin.app.bajo.lib._
|
|
3
|
-
params.noTag = true
|
|
4
|
-
const schema = get(this, 'locals.schema', {})
|
|
5
|
-
if (schema.view.disabled.includes('create')) {
|
|
6
|
-
params.html = ''
|
|
7
|
-
return
|
|
8
|
-
}
|
|
9
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Clone')
|
|
10
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
11
|
-
if (!params.attr.href) params.attr.href = this._buildUrl({ base: 'add', exclude: ['id'] }) + '&mode=clone'
|
|
12
|
-
if (params.attr.onList) {
|
|
13
|
-
params.attr['x-ref'] = 'clone'
|
|
14
|
-
params.attr.disabled = true
|
|
15
|
-
params.attr['x-data'] = `{
|
|
16
|
-
path: '${params.attr.href}'
|
|
17
|
-
}`
|
|
18
|
-
params.attr['@on-selection.window'] = `
|
|
19
|
-
const recId = $event.detail[0] ?? ''
|
|
20
|
-
if ($event.detail.length === 1) $refs.clone.classList.remove('disabled')
|
|
21
|
-
else $refs.clone.classList.add('disabled')
|
|
22
|
-
$refs.clone.href = path + '&id=' + recId
|
|
23
|
-
`
|
|
24
|
-
} else {
|
|
25
|
-
params.attr.href += '&id=' + this.req.query.id
|
|
26
|
-
}
|
|
27
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default btnClone
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
async function btnColumns (params = {}) {
|
|
2
|
-
const { get, isEmpty, without } = this.plugin.app.bajo.lib._
|
|
3
|
-
const { jsonStringify } = this.plugin.app.waibuMpa
|
|
4
|
-
const qsKey = this.plugin.app.waibu.config.qsKey
|
|
5
|
-
const schema = get(this, 'locals.schema', {})
|
|
6
|
-
if (schema.view.disabled.includes('find')) {
|
|
7
|
-
params.html = ''
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
let fields = without(get(this, `locals._meta.query.${qsKey.fields}`, '').split(','), '')
|
|
11
|
-
if (isEmpty(fields)) fields = schema.view.fields
|
|
12
|
-
const items = []
|
|
13
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
14
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Columns')
|
|
15
|
-
for (const f of schema.view.fields) {
|
|
16
|
-
if (f === 'id') {
|
|
17
|
-
items.push(await this.buildTag({ tag: 'formCheck', attr: { checked: true, label: this.req.t('ID'), value: f, disabled: true } }))
|
|
18
|
-
continue
|
|
19
|
-
}
|
|
20
|
-
const attr = { 'x-model': 'selected', label: this.req.t(`field.${f}`), value: f }
|
|
21
|
-
if (fields.includes(f)) attr.checked = true
|
|
22
|
-
items.push(await this.buildTag({ tag: 'formCheck', attr }))
|
|
23
|
-
}
|
|
24
|
-
const href = this._buildUrl({ exclude: [qsKey.fields] })
|
|
25
|
-
const html = ['<form class="mt-1 mb-2 mx-3" ']
|
|
26
|
-
html.push(`x-data="{
|
|
27
|
-
selected: ${jsonStringify(fields, true)},
|
|
28
|
-
all: ${jsonStringify(schema.view.fields, true)}
|
|
29
|
-
}"`)
|
|
30
|
-
html.push(`x-init="
|
|
31
|
-
$refs.apply.href = '${href}&${qsKey.fields}=' + selected.join(',')
|
|
32
|
-
$watch('selected', v => {
|
|
33
|
-
$refs.apply.href = '${href}&${qsKey.fields}=' + v.join(',')
|
|
34
|
-
})
|
|
35
|
-
">`)
|
|
36
|
-
html.push(...items)
|
|
37
|
-
const attr = { size: 'sm', 'x-ref': 'apply', margin: 'top-2', color: params.attr.applyColor ?? 'primary', icon: params.attr.applyIcon ?? 'arrowsStartEnd', href }
|
|
38
|
-
html.push(await this.buildTag({ tag: 'btn', attr, html: this.req.t('Apply') }))
|
|
39
|
-
html.push('</form>')
|
|
40
|
-
params.attr.autoClose = 'outside'
|
|
41
|
-
params.html = await this.buildTag({ tag: 'dropdown', attr: params.attr, html: html.join('\n') })
|
|
42
|
-
params.noTag = true
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default btnColumns
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
async function btnDelete (params = {}) {
|
|
2
|
-
const { generateId } = this.plugin.app.bajo
|
|
3
|
-
const { isEmpty, get } = this.plugin.app.bajo.lib._
|
|
4
|
-
params.noTag = true
|
|
5
|
-
const schema = get(this, 'locals.schema', {})
|
|
6
|
-
if (schema.view.disabled.includes('remove')) {
|
|
7
|
-
params.html = ''
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Delete')
|
|
11
|
-
params.attr.color = params.attr.color ?? 'danger-outline'
|
|
12
|
-
params.attr.id = generateId('alpha')
|
|
13
|
-
if (params.attr.onList) {
|
|
14
|
-
params.attr.disabled = true
|
|
15
|
-
params.attr['x-data'] = `{
|
|
16
|
-
selected: [],
|
|
17
|
-
remove (ids) {
|
|
18
|
-
wmpa.postForm({ ids }, '${this._buildUrl({ base: 'delete' })}')
|
|
19
|
-
}
|
|
20
|
-
}`
|
|
21
|
-
params.attr['@on-selection.window'] = `
|
|
22
|
-
const el = document.getElementById('${params.attr.id}')
|
|
23
|
-
selected = $event.detail
|
|
24
|
-
if (selected.length > 0) el.classList.remove('disabled')
|
|
25
|
-
else el.classList.add('disabled')
|
|
26
|
-
`
|
|
27
|
-
} else {
|
|
28
|
-
params.attr['x-data'] = `{
|
|
29
|
-
selected: ['${this.req.query.id}'],
|
|
30
|
-
remove (modalId, ids) {
|
|
31
|
-
wmpa.postForm({ ids }, '${this._buildUrl({ base: 'delete', exclude: ['id', 'page'] })}')
|
|
32
|
-
}
|
|
33
|
-
}`
|
|
34
|
-
}
|
|
35
|
-
const msg = 'You\'re about to remove one or more records. Are you really sure to do this?'
|
|
36
|
-
params.attr['@click'] = `
|
|
37
|
-
const opts = selected.join(',')
|
|
38
|
-
const id = await wbs.confirmation(\`${this.req.t(msg)}\`, { ok: '${params.attr.id}:remove', close: 'y', opts })
|
|
39
|
-
`
|
|
40
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default btnDelete
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
async function btnDetails (params = {}) {
|
|
2
|
-
const { generateId } = this.plugin.app.bajo
|
|
3
|
-
const { isEmpty, get } = this.plugin.app.bajo.lib._
|
|
4
|
-
params.noTag = true
|
|
5
|
-
const schema = get(this, 'locals.schema', {})
|
|
6
|
-
if (schema.view.disabled.includes('update')) {
|
|
7
|
-
params.html = ''
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Details')
|
|
11
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
12
|
-
params.attr.id = generateId('alpha')
|
|
13
|
-
if (!params.attr.href) params.attr.href = this._buildUrl({ base: 'details', exclude: ['id'] })
|
|
14
|
-
if (params.attr.onList) {
|
|
15
|
-
params.attr.disabled = true
|
|
16
|
-
params.attr['x-ref'] = 'details'
|
|
17
|
-
params.attr['x-data'] = `{
|
|
18
|
-
path: '${params.attr.href}'
|
|
19
|
-
}`
|
|
20
|
-
params.attr['@on-selection.window'] = `
|
|
21
|
-
const recId = $event.detail[0] ?? ''
|
|
22
|
-
if ($event.detail.length === 1) $refs.details.classList.remove('disabled')
|
|
23
|
-
else $refs.details.classList.add('disabled')
|
|
24
|
-
$refs.details.href = path + '&id=' + recId
|
|
25
|
-
`
|
|
26
|
-
} else {
|
|
27
|
-
params.attr.href += '&id=' + this.req.query.id
|
|
28
|
-
}
|
|
29
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export default btnDetails
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
async function btnEdit (params = {}) {
|
|
2
|
-
const { generateId } = this.plugin.app.bajo
|
|
3
|
-
const { isEmpty, get } = this.plugin.app.bajo.lib._
|
|
4
|
-
params.noTag = true
|
|
5
|
-
const schema = get(this, 'locals.schema', {})
|
|
6
|
-
if (schema.view.disabled.includes('update')) {
|
|
7
|
-
params.html = ''
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
if (isEmpty(params.attr.content)) params.attr.content = this.req.t('Edit')
|
|
11
|
-
params.attr.color = params.attr.color ?? 'secondary-outline'
|
|
12
|
-
params.attr.id = generateId('alpha')
|
|
13
|
-
if (!params.attr.href) params.attr.href = this._buildUrl({ base: 'edit', exclude: ['id'] })
|
|
14
|
-
if (params.attr.onList) {
|
|
15
|
-
params.attr.split = true
|
|
16
|
-
params.attr.disabled = true
|
|
17
|
-
params.attr['x-data'] = `{
|
|
18
|
-
path: '${params.attr.href}'
|
|
19
|
-
}`
|
|
20
|
-
if (params.attr.noClone) {
|
|
21
|
-
params.attr['@on-selection.window'] = `
|
|
22
|
-
const recId = $event.detail[0] ?? ''
|
|
23
|
-
const el = document.getElementById('${params.attr.id}')
|
|
24
|
-
if ($event.detail.length === 1) el.classList.remove('disabled')
|
|
25
|
-
else el.classList.add('disabled')
|
|
26
|
-
el.href = path + '&id=' + recId
|
|
27
|
-
`
|
|
28
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
29
|
-
} else {
|
|
30
|
-
params.attr['@on-selection.window'] = `
|
|
31
|
-
const recId = $event.detail[0] ?? ''
|
|
32
|
-
const elId = '${params.attr.id}'
|
|
33
|
-
for (const id of [elId, elId + '-split']) {
|
|
34
|
-
const el = document.getElementById(id)
|
|
35
|
-
if ($event.detail.length === 1) el.classList.remove('disabled')
|
|
36
|
-
else el.classList.add('disabled')
|
|
37
|
-
const href = path + '&id=' + recId
|
|
38
|
-
if (id.slice(-6) === '-split') {
|
|
39
|
-
const selector = '#' + id.replace('-split', '-menu') + ' a.dropdown-item'
|
|
40
|
-
const item = document.querySelector(selector)
|
|
41
|
-
item.href = href.replace('/edit', '/add') + '&mode=clone'
|
|
42
|
-
} else el.href = href
|
|
43
|
-
}
|
|
44
|
-
`
|
|
45
|
-
const html = [
|
|
46
|
-
await this.buildTag({ tag: 'dropdownItem', attr: { content: this.req.t('Add as New Clone') } })
|
|
47
|
-
]
|
|
48
|
-
params.html = await this.buildTag({ tag: 'dropdown', attr: params.attr, html: html.join('\n') })
|
|
49
|
-
}
|
|
50
|
-
} else {
|
|
51
|
-
params.attr.href += '&id=' + this.req.query.id
|
|
52
|
-
params.html = await this.buildTag({ tag: 'btn', attr: params.attr, html: params.html })
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export default btnEdit
|