waibu-db 1.2.3 → 1.2.4

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.
@@ -32,6 +32,9 @@
32
32
  "checkAll": "Check All",
33
33
  "uncheckAll": "Uncheck All",
34
34
  "attachment": "Attachment",
35
+ "exportInQueue": "Data export in queue. Please check your download list for progress",
36
+ "tsv": "TSV",
37
+ "ndjson": "NDJSON",
35
38
  "op": {
36
39
  "equals": "Equals",
37
40
  "notEquals": "Not Equals",
package/bajo/intl/id.json CHANGED
@@ -32,6 +32,9 @@
32
32
  "checkAll": "Cek Semua",
33
33
  "uncheckAll": "Uncheck Semua",
34
34
  "attachment": "Attachment",
35
+ "exportInQueue": "Ekspor data sedang dalam antrian. Silahkan cek daftar unduh Anda untuk perkembangan terakhir",
36
+ "tsv": "TSV",
37
+ "ndjson": "NDJSON",
35
38
  "op": {
36
39
  "equals": "Sama Dengan",
37
40
  "notEquals": "Tidak Sama Dengan",
@@ -16,7 +16,7 @@
16
16
  <c:wdb-btn-clone href="<%= schema.view.control.cloneHref ?? 'undefined' %>" />
17
17
  <% } %>
18
18
  <% if (!schema.view.control.noExportBtn) { %>
19
- <c:wdb-btn-export selector="#main-form" handler="details" launch-on-end/>
19
+ <c:wdb-btn-export selector="#main-form" handler="details" launch-on-end no-save/>
20
20
  <% } %>
21
21
  </c:btn-group>
22
22
  <% } %>
@@ -10,7 +10,7 @@
10
10
  <% if (!schema.view.control.noCloneBtn) { %>
11
11
  <c:wdb-btn-clone href="<%= schema.view.control.cloneHref ?? 'undefined' %>" />
12
12
  <% } %>
13
- <c:wdb-btn-export selector="#main-form" handler="edit" launch-on-end/>
13
+ <c:wdb-btn-export selector="#main-form" handler="edit" launch-on-end no-save />
14
14
  </c:btn-group>
15
15
  </c:grid-col>
16
16
  <c:grid-col col="6-lg" flex="justify-content:end-lg align-items:center">
package/index.js CHANGED
@@ -5,7 +5,7 @@ async function factory (pkgName) {
5
5
  constructor () {
6
6
  super(pkgName, me.app)
7
7
  this.alias = 'wdb'
8
- this.dependencies = ['dobo', 'waibu']
8
+ this.dependencies = ['dobo', 'waibu', 'bajo-queue', 'dobo-extra']
9
9
  this.config = {
10
10
  waibu: {
11
11
  prefix: 'db',
@@ -25,6 +25,33 @@ async function factory (pkgName) {
25
25
  modelRestApi: false
26
26
  }
27
27
  }
28
+
29
+ exportData = async (params) => {
30
+ const { getPlugin } = this.app.bajo
31
+ const { get } = this.lib._
32
+ const { fs } = this.lib
33
+ const { recordUpdate } = this.app.dobo
34
+ const { exportTo } = this.app.doboExtra
35
+ const { downloadDir } = getPlugin('sumba')
36
+ const model = get(params, 'payload.data.name')
37
+ const fields = get(params, 'payload.data.opts.fields')
38
+ const { id, file } = get(params, 'payload.data.download', {})
39
+ const dest = `${downloadDir}/${file}`
40
+ const options = {
41
+ filter: get(params, 'payload.data.filter', {}),
42
+ ensureDir: true,
43
+ fields
44
+ }
45
+ const dmodel = 'SumbaDownload'
46
+ try {
47
+ await recordUpdate(dmodel, id, { status: 'PROCESSING' })
48
+ await exportTo(model, dest, options)
49
+ const { size } = fs.statSync(dest)
50
+ await recordUpdate(dmodel, id, { size, status: 'COMPLETE' })
51
+ } catch (err) {
52
+ await recordUpdate(dmodel, id, { status: 'FAIL' })
53
+ }
54
+ }
28
55
  }
29
56
  }
30
57
 
@@ -34,6 +34,8 @@ async function addHandler ({ req, reply, model, params = {}, template, addOnsHan
34
34
  }
35
35
  const addOns = addOnsHandler ? await addOnsHandler.call(this.app[req.ns], { req, reply, params, data: resp, schema, error }) : undefined
36
36
  merge(params, { form, schema, error, addOns })
37
+ if (schema.template) template = schema.template
38
+ if (schema.layout) params.page.layout = schema.layout
37
39
  return await reply.view(template, params)
38
40
  }
39
41
 
@@ -16,6 +16,8 @@ async function detailsHandler ({ req, reply, model, params = {}, id, template, a
16
16
  const addOns = addOnsHandler ? await addOnsHandler.call(this.app[req.ns], { req, reply, params, data: resp, schema }) : undefined
17
17
  const attachments = await attachmentHandler.call(this, { schema, id })
18
18
  merge(params, { form, schema, addOns, attachments })
19
+ if (schema.template) template = schema.template
20
+ if (schema.layout) params.page.layout = schema.layout
19
21
  return await reply.view(template, params)
20
22
  }
21
23
 
@@ -45,6 +45,8 @@ async function editHandler ({ req, reply, model, id, params = {}, template, addO
45
45
  const addOns = addOnsHandler ? await addOnsHandler.call(this.app[req.ns], { req, reply, params, data: resp, schema, error }) : undefined
46
46
  const attachments = await attachmentHandler.call(this, { schema, id })
47
47
  merge(params, { form, schema, error, addOns, attachments })
48
+ if (schema.template) template = schema.template
49
+ if (schema.layout) params.page.layout = schema.layout
48
50
  return await reply.view(template, params)
49
51
  }
50
52
 
@@ -1,14 +1,27 @@
1
+ import prepCrud from '../prep-crud.js'
2
+
1
3
  async function exportHandler ({ req, reply, model, params = {}, templateDisabled = 'waibuDb.template:/disabled.html' } = {}) {
4
+ const { getPlugin } = this.app.bajo
5
+ const { dayjs } = this.lib
6
+ const { omit, kebabCase, get } = this.lib._
2
7
  const { pascalCase } = this.lib.aneka
3
8
  const { getSchemaExt } = this.app.waibuDb
4
9
  const { buildUrl } = this.app.waibuMpa
5
- const options = {}
10
+ const { pushDownload } = getPlugin('sumba')
6
11
  model = model ?? pascalCase(req.params.model)
7
- const { schema } = await getSchemaExt(model, 'add', options, { params })
12
+ const { schema } = await getSchemaExt(model, 'add', { params })
8
13
  if (schema.disabled.includes('find')) return await reply.view(templateDisabled, { action: 'list' })
9
- options.fields = schema.view.fields
14
+ const data = prepCrud.call(this, { model, req, reply, args: ['model'] })
15
+ data.opts = omit(data.opts, ['req', 'reply'])
16
+ const source = `${this.name}:/export-handler`
17
+ const worker = 'waibuDb:exportData'
18
+ const type = get(data, 'input.ftype', 'json')
19
+ const settings = get(data, 'input.options', '').split(',')
20
+ const ext = settings.includes('zip') ? `${type}.gz` : type
21
+ const file = `${kebabCase(model)}_${dayjs().format('YYYYMMDDhhmmss')}.${ext}`
22
+ await pushDownload({ file, type, worker, source, data, req })
23
+ req.flash('notify', req.t('exportInQueue'))
10
24
  const url = buildUrl({ url: req.url, base: req.body.handler })
11
- req.flash('notify', req.t('Data export in queue. You\'ll be notified once completed'))
12
25
  return reply.redirectTo(url)
13
26
  }
14
27
 
@@ -21,6 +21,8 @@ async function listHandler ({ req, reply, model, template, params = {}, addOnsHa
21
21
  if (!isArray(addOns)) addOns = [addOns]
22
22
  }
23
23
  merge(params, { list, schema, addOns })
24
+ if (schema.template) template = schema.template
25
+ if (schema.layout) params.page.layout = schema.layout
24
26
  return await reply.view(template, params)
25
27
  }
26
28
 
package/lib/prep-crud.js CHANGED
@@ -1,5 +1,6 @@
1
1
  function prepCrud ({ model, body, id, req, reply, options = {}, args }) {
2
2
  const { parseFilter } = this.app.waibu
3
+ const { buildQuery, getInfo } = this.app.dobo
3
4
  const { pascalCase } = this.lib.aneka
4
5
  const { cloneDeep, has } = this.lib._
5
6
  const cfgWeb = this.app.waibu.getConfig()
@@ -20,6 +21,7 @@ function prepCrud ({ model, body, id, req, reply, options = {}, args }) {
20
21
 
21
22
  const recId = id ?? params.id ?? req.query.id
22
23
  const name = pascalCase(model ?? params.model)
24
+ const { schema } = getInfo(name)
23
25
  const input = body ?? params.body
24
26
  opts.bboxLatField = req.query[cfgWeb.qsKey.bboxLatField]
25
27
  opts.bboxLngField = req.query[cfgWeb.qsKey.bboxLngField]
@@ -28,6 +30,7 @@ function prepCrud ({ model, body, id, req, reply, options = {}, args }) {
28
30
  if (options.limit) filter.limit = options.limit
29
31
  if (options.sort) filter.sort = options.sort
30
32
  if (options.page) filter.page = options.page
33
+ filter.query = buildQuery({ filter, schema })
31
34
  return { name, recId, input, opts, filter, attachment, stats, mimeType }
32
35
  }
33
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,15 +29,22 @@ async function btnExport () {
29
29
  ftype: 'json',
30
30
  toggle (val) {
31
31
  if (val === 'clipboard') {
32
+ $refs.fkey.removeAttribute('disabled')
33
+ $refs.fvalue.removeAttribute('disabled')
32
34
  $refs.zip.setAttribute('disabled', '')
33
35
  $refs.xlsx.setAttribute('disabled', '')
34
- $refs.xml.setAttribute('disabled', '')
36
+ $refs.tsv.setAttribute('disabled', '')
37
+ $refs.ndjson.setAttribute('disabled', '')
35
38
  _.pull(this.options, 'zip')
36
39
  if (!['json', 'csv'].includes(this.ftype)) this.ftype = 'json'
37
40
  } else {
41
+ $refs.fkey.setAttribute('disabled', '')
42
+ $refs.fvalue.setAttribute('disabled', '')
38
43
  $refs.zip.removeAttribute('disabled')
39
44
  $refs.xlsx.removeAttribute('disabled')
40
- $refs.xml.removeAttribute('disabled')
45
+ $refs.tsv.removeAttribute('disabled')
46
+ $refs.ndjson.removeAttribute('disabled')
47
+ _.pull(this.options, 'fkey', 'fvalue')
41
48
  }
42
49
  },
43
50
  extractForm (selector) {
@@ -117,8 +124,8 @@ async function btnExport () {
117
124
  <c:grid-row gutter="2">
118
125
  <c:grid-col col="6-md">
119
126
  <c:fieldset t:legend="delivery" legend-type="6">
120
- <c:form-radio x-model="delivery" value="file" t:label="saveAsFile" />
121
127
  <c:form-radio x-model="delivery" value="clipboard" t:label="copyClipboard" />
128
+ <c:form-radio x-model="delivery" value="file" t:label="saveAsFile" ${this.params.attr.noSave ? 'disabled' : ''} />
122
129
  </c:fieldset>
123
130
  <c:fieldset t:legend="options" legend-type="6" margin="top-2">
124
131
  <c:form-check x-ref="fkey" x-model="options" value="fkey" t:label="formattedField" />
@@ -130,8 +137,9 @@ async function btnExport () {
130
137
  <c:fieldset t:legend="fileType" legend-type="6">
131
138
  <c:form-radio x-ref="xlsx" x-model="ftype" value="xlsx" t:label="excelXlsx" />
132
139
  <c:form-radio x-ref="csv" x-model="ftype" value="csv" t:label="csv" />
133
- <c:form-radio x-ref="xml" x-model="ftype" value="xml" t:label="xml" />
140
+ <c:form-radio x-ref="tsv" x-model="ftype" value="tsv" t:label="tsv" />
134
141
  <c:form-radio x-ref="json" x-model="ftype" value="json" t:label="json" />
142
+ <c:form-radio x-ref="ndjson" x-model="ftype" value="ndjson" t:label="ndjson" />
135
143
  </c:fieldset />
136
144
  </c:grid-col>
137
145
  </c:grid-row>
@@ -10,7 +10,6 @@ async function query () {
10
10
  const { find, get, without, isEmpty, filter, upperFirst } = this.plugin.app.bajo.lib._
11
11
  const qsKey = this.plugin.app.waibu.config.qsKey
12
12
  const schema = get(this, 'component.locals.schema', {})
13
- const count = get(this, 'component.locals.list.count', 0)
14
13
  if (schema.view.disabled.includes('find')) {
15
14
  this.params.html = ''
16
15
  return
@@ -21,7 +20,6 @@ async function query () {
21
20
  const id = generateId('alpha')
22
21
  const columns = []
23
22
  const models = []
24
- const selects = ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'contains', 'starts', 'ends', '!in', '!contains', '!starts', '!ends']
25
23
  for (const f of schema.view.fields) {
26
24
  if (!fields.includes(f)) continue
27
25
  const prop = find(schema.properties, { name: f })
@@ -29,7 +27,7 @@ async function query () {
29
27
  if (['float', 'double', 'integer', 'smallint'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
30
28
  else if (['datetime', 'date', 'time'].includes(prop.type)) ops.push('eq', 'neq', 'gt', 'gte', 'lt', 'lte')
31
29
  else if (['boolean'].includes(prop.type)) ops.push('eq', 'neq')
32
- else ops.push(...selects)
30
+ else ops.push('eq', 'neq', 'in', 'contains', 'starts', 'ends', '!in', '!contains', '!starts', '!ends')
33
31
  if (ops.length === 0) continue
34
32
  const sels = ops.map(o => `<c:option>${o}</c:option>`)
35
33
  models.push(`${f}Op: 'eq'`, `${f}Val: ''`)
@@ -51,12 +49,12 @@ async function query () {
51
49
  this.params.noTag = true
52
50
  const container = this.params.attr.modal ? 'modal' : 'drawer'
53
51
  this.params.html = await this.component.buildSentence(`
54
- <c:form-input ${count === 0 ? 'disabled' : ''} type="search" t:placeholder="query" id="${id}" x-data="{ query: '' }" x-init="
52
+ <c:form-input type="search" t:placeholder="query" id="${id}" x-data="{ query: '' }" x-init="
55
53
  const url = new URL(window.location.href)
56
54
  query = url.searchParams.get('${qsKey.query}') ?? ''
57
55
  " x-model="query" @on-query.window="query = $event.detail ?? ''" @keyup.enter="$dispatch('on-submit')">
58
56
  <c:form-input-addon>
59
- <c:${container} ${count === 0 ? 'trigger-disabled' : ''} trigger-icon="${this.params.attr.icon ?? 'dotsThree'}" trigger-on-end t:title="queryBuilder" x-ref="query" x-data="{
57
+ <c:${container} trigger-icon="${this.params.attr.icon ?? 'dotsThree'}" trigger-on-end t:title="queryBuilder" x-ref="query" x-data="{
60
58
  fields: ${jsonStringify(fields, true)},
61
59
  builder: '',
62
60
  selected: [],
@@ -70,6 +68,7 @@ async function query () {
70
68
  },
71
69
  initBuilder () {
72
70
  this.builder = document.getElementById('${id}').value
71
+ if (!this.builder.includes(':')) this.builder = ''
73
72
  if (_.isEmpty(this.builder)) return
74
73
  const tokens = _.merge({}, this.ops, {
75
74
  in: ':[',
@@ -158,7 +157,7 @@ async function query () {
158
157
  </c:${container}>
159
158
  </c:form-input-addon>
160
159
  <c:form-input-addon>
161
- <c:btn ${count === 0 ? 'disabled' : ''} t:content="submit" x-data="{
160
+ <c:btn t:content="submit" x-data="{
162
161
  submit () {
163
162
  const val = document.getElementById('${id}').value ?? ''
164
163
  const url = new URL(window.location.href)
@@ -1,14 +0,0 @@
1
- const action = {
2
- method: ['GET', 'POST'],
3
- title: 'Database Export',
4
- handler: async function (req, reply) {
5
- const { importModule } = this.app.bajo
6
- const handler = await importModule('waibuDb:/lib/crud/all-handler.js')
7
- const model = 'SumbaUser'
8
- const { action } = req.params
9
- const template = `sumba.template:/crud/${action}.html`
10
- return handler.call(this, { model, req, reply, action, template })
11
- }
12
- }
13
-
14
- export default action