@bildvitta/quasar-ui-asteroid 2.23.0-beta.7 → 2.24.0-beta.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
- "version": "2.23.0-beta.7",
3
+ "version": "2.24.0-beta.0",
4
4
  "description": "",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
@@ -26,52 +26,56 @@
26
26
  "author": "Inovação Bild & Vitta <inova@bild.com.br>",
27
27
  "license": "ISC",
28
28
  "devDependencies": {
29
- "@babel/core": "^7.12.10",
30
- "@babel/eslint-parser": "^7.12.1",
31
- "@babel/preset-env": "^7.12.11",
32
- "@storybook/addon-actions": "^6.2.9",
29
+ "@babel/core": "^7.20.12",
30
+ "@babel/eslint-parser": "^7.19.1",
31
+ "@babel/preset-env": "^7.20.2",
32
+ "@storybook/addon-actions": "^6.5.16",
33
33
  "@storybook/addon-console": "^1.2.3",
34
- "@storybook/addon-essentials": "^6.2.9",
35
- "@storybook/addon-links": "^6.2.9",
34
+ "@storybook/addon-essentials": "^6.5.16",
35
+ "@storybook/addon-links": "^6.5.16",
36
36
  "@storybook/addon-postcss": "^2.0.0",
37
- "@storybook/vue": "^6.2.9",
38
- "@testing-library/jest-dom": "^5.11.9",
39
- "@vue/test-utils": "^1.1.2",
40
- "autoprefixer": "^10.2.6",
37
+ "@storybook/vue": "^6.5.16",
38
+ "@testing-library/jest-dom": "^5.16.5",
39
+ "@vue/test-utils": "^1.3.4",
40
+ "autoprefixer": "^10.4.13",
41
41
  "babel-core": "^7.0.0-bridge.0",
42
42
  "babel-jest": "^27.0.1",
43
- "babel-loader": "^8.2.2",
44
- "core-js": "^3.8.3",
43
+ "babel-loader": "^8.3.0",
44
+ "core-js": "^3.27.2",
45
45
  "eslint": "^7.18.0",
46
46
  "eslint-plugin-jest": "^24.1.3",
47
47
  "eslint-plugin-vue": "^7.5.0",
48
- "eslint-webpack-plugin": "^2.4.3",
48
+ "eslint-webpack-plugin": "^2.7.0",
49
49
  "jest": "^27.0.3",
50
- "postcss": "^8.3.5",
50
+ "postcss": "^8.4.21",
51
51
  "react-is": "^17.0.1",
52
- "sass": "^1.32.5",
53
- "sass-loader": "^10.1.1",
52
+ "sass": "^1.58.0",
53
+ "sass-loader": "^10.4.1",
54
54
  "standard": "^16.0.3",
55
55
  "vue-jest": "^3.0.7",
56
- "vue-loader": "^15.9.6",
57
- "vue-template-compiler": "^2.6.14"
56
+ "vue-loader": "^15.10.1",
57
+ "vue-template-compiler": "^2.7.14"
58
58
  },
59
59
  "dependencies": {
60
- "@quasar/extras": "^1.9.14",
60
+ "@quasar/extras": "^1.15.10",
61
61
  "autonumeric": "^4.6.0",
62
62
  "axios": "^0.21.1",
63
- "date-fns": "^2.16.1",
63
+ "date-fns": "^2.29.3",
64
64
  "fuse.js": "^3.4.6",
65
65
  "humps": "^2.0.1",
66
66
  "lodash": "^4.17.21",
67
67
  "pica": "^7.1.0",
68
- "quasar": "^1.15.0",
68
+ "quasar": "^1.22.5",
69
69
  "signature_pad": "^3.0.0-beta.4",
70
70
  "sortablejs": "^1.12.0",
71
- "vue-router": "^3.4.9",
71
+ "vue-router": "^3.6.5",
72
72
  "vuex": "^3.6.0"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "vue": "^2.6.14"
76
+ },
77
+ "engines": {
78
+ "node": ">= 10.18.1 <= 16",
79
+ "npm": ">= 6.13.4"
76
80
  }
77
81
  }
@@ -31,6 +31,14 @@ export default {
31
31
  description: '[VuexStoreModule](https://github.com/bildvitta/vuex-store-module) entity.'
32
32
  },
33
33
 
34
+ fieldsEvents: {
35
+ description: 'Defines each field events.'
36
+ },
37
+
38
+ fieldsProps: {
39
+ description: 'Defines each field props.'
40
+ },
41
+
34
42
  noFilterButton: {
35
43
  description: 'Hides filter button.'
36
44
  },
@@ -27,7 +27,7 @@
27
27
 
28
28
  <q-form v-else class="q-gutter-y-md q-pa-md" @submit.prevent="filter()">
29
29
  <div v-for="(field, index) in fields" :key="index">
30
- <qas-field v-model="filters[field.name]" dense :field="field" />
30
+ <qas-field dense :field="field" :value="filters[field.name]" v-bind="fieldsProps[field.name]" v-on="fieldsEvents[field.name]" @input="emitter(field.name, $event)" />
31
31
  </div>
32
32
 
33
33
  <div class="text-right">
@@ -51,6 +51,7 @@
51
51
  <script>
52
52
  import QasField from '../field/QasField'
53
53
 
54
+ import { isNil, isEmpty } from 'lodash'
54
55
  import { camelize, camelizeKeys } from 'humps'
55
56
  import { humanize, parseValue } from '../../helpers/filters'
56
57
  import contextMixin from '../../mixins/context'
@@ -73,6 +74,16 @@ export default {
73
74
  type: String
74
75
  },
75
76
 
77
+ fieldsProps: {
78
+ default: () => ({}),
79
+ type: Object
80
+ },
81
+
82
+ fieldsEvents: {
83
+ default: () => ({}),
84
+ type: Object
85
+ },
86
+
76
87
  noFilterButton: {
77
88
  default: false,
78
89
  type: Boolean
@@ -100,6 +111,11 @@ export default {
100
111
 
101
112
  forceRefetch: {
102
113
  type: Boolean
114
+ },
115
+
116
+ value: {
117
+ default: () => ({}),
118
+ type: Object
103
119
  }
104
120
  },
105
121
 
@@ -127,7 +143,9 @@ export default {
127
143
  const hasField = fields.includes(key)
128
144
 
129
145
  if (hasField) {
130
- const value = humanize(this.fields[key], this.normalizeValues(filters[key], this.fields[key]?.multiple))
146
+ const field = { ...this.fields[key], ...this.fieldsProps?.[key] }
147
+
148
+ const value = humanize(field, this.normalizeValues(filters[key], this.fields[key]?.multiple))
131
149
  const { label, name } = this.fields[key]
132
150
 
133
151
  activeFilters[key] = { label, name, value }
@@ -184,10 +202,25 @@ export default {
184
202
  this.updateValues()
185
203
  },
186
204
 
205
+ '$route.query': {
206
+ immediate: true,
207
+ handler () {
208
+ this.$emit('input', this.context.filters)
209
+ }
210
+ },
211
+
187
212
  search () {
188
213
  if (this.debounce) {
189
214
  this.filter()
190
215
  }
216
+ },
217
+
218
+ value: {
219
+ immediate: true,
220
+ deep: true,
221
+ handler (value) {
222
+ this.filters = value
223
+ }
191
224
  }
192
225
  },
193
226
 
@@ -275,6 +308,11 @@ export default {
275
308
  this.search = search || ''
276
309
 
277
310
  for (const key in filters) {
311
+ if (isEmpty(filters[key]) || isNil(filters[key])) {
312
+ delete filters[key]
313
+ continue
314
+ }
315
+
278
316
  this.$set(this.filters, key, parseValue(this.normalizeValues(filters[key], this.fields[key]?.multiple)))
279
317
  }
280
318
  },
@@ -292,6 +330,11 @@ export default {
292
330
  watchOnce()
293
331
  }
294
332
  })
333
+ },
334
+
335
+ emitter (key, value) {
336
+ this.filters[key] = value
337
+ this.$emit('input', this.filters)
295
338
  }
296
339
  }
297
340
  }
@@ -33,6 +33,10 @@ export default {
33
33
 
34
34
  argTypes: {
35
35
  // Props
36
+ beforeFetch: {
37
+ description: 'Function to be called before fetching data.'
38
+ },
39
+
36
40
  cancelButton: {
37
41
  description: 'Cancel button label.'
38
42
  },
@@ -80,6 +84,10 @@ export default {
80
84
  description: 'Submit button label.'
81
85
  },
82
86
 
87
+ beforeSubmit: {
88
+ description: 'Function to be called before submit.'
89
+ },
90
+
83
91
  url: {
84
92
  control: null,
85
93
  description: 'Ignore entity and specify another endpoint.'
@@ -4,7 +4,7 @@
4
4
  <slot :errors="errors" :fields="fields" :metadata="metadata" name="header" />
5
5
  </header>
6
6
 
7
- <q-form ref="form" @submit="submit">
7
+ <q-form ref="form" @submit="submitHandler">
8
8
  <slot :errors="errors" :fields="fields" :metadata="metadata" />
9
9
 
10
10
  <slot v-if="!readOnly" :errors="errors" :fields="fields" :metadata="metadata" name="actions">
@@ -13,7 +13,7 @@
13
13
  <qas-btn v-close-popup="dialog" class="full-width" :data-cy="`btnCancel-${entity}`" :disable="isCancelButtonDisabled" :label="cancelButton" outline type="button" @click="cancel" />
14
14
  </div>
15
15
  <div class="col-12 col-sm-2" :class="saveButtonClass">
16
- <qas-btn class="full-width" :data-cy="`btnSave-${entity}`" :disable="disable" :label="submitButton" :loading="isSubmiting" type="submit" />
16
+ <qas-btn class="full-width" :data-cy="`btnSave-${entity}`" :disable="disable" :label="submitButton" :loading="isSubmitting" type="submit" />
17
17
  </div>
18
18
  </div>
19
19
  </slot>
@@ -95,6 +95,11 @@ export default {
95
95
  type: String
96
96
  },
97
97
 
98
+ beforeSubmit: {
99
+ default: null,
100
+ type: Function
101
+ },
102
+
98
103
  value: {
99
104
  default: () => ({}),
100
105
  type: Object
@@ -105,7 +110,7 @@ export default {
105
110
  return {
106
111
  cachedResult: {},
107
112
  hasResult: false,
108
- isSubmiting: false,
113
+ isSubmitting: false,
109
114
  showDialog: false,
110
115
 
111
116
  dialogConfig: {
@@ -181,7 +186,7 @@ export default {
181
186
  },
182
187
 
183
188
  created () {
184
- this.fetch()
189
+ this.fetchHandler({ form: true, id: this.id, url: this.fetchURL }, this.fetchSingle)
185
190
  },
186
191
 
187
192
  methods: {
@@ -203,14 +208,18 @@ export default {
203
208
  }
204
209
  },
205
210
 
206
- async fetch (params) {
211
+ async fetchSingle (externalPayload = {}) {
207
212
  this.isFetching = true
208
213
 
209
- try {
210
- const response = await this.$store.dispatch(
211
- `${this.entity}/fetchSingle`, { form: true, id: this.id, params, url: this.fetchURL }
212
- )
214
+ const payload = {
215
+ form: true,
216
+ id: this.id,
217
+ url: this.fetchURL,
218
+ ...externalPayload
219
+ }
213
220
 
221
+ try {
222
+ const response = await this.$store.dispatch(`${this.entity}/fetchSingle`, payload)
214
223
  const { errors, fields, metadata, result } = response.data
215
224
 
216
225
  this.setErrors(errors)
@@ -264,22 +273,33 @@ export default {
264
273
  this.showDialog = true
265
274
  },
266
275
 
267
- async submit (event) {
276
+ submitHandler (event) {
268
277
  if (event) {
269
278
  event.preventDefault()
270
279
  }
271
280
 
272
- if (this.disable || this.readyOnly) {
281
+ const hasBeforeSubmit = typeof this.beforeSubmit === 'function'
282
+
283
+ if (hasBeforeSubmit) {
284
+ return this.beforeSubmit({
285
+ params: { id: this.id, payload: this.value, url: this.url },
286
+ resolve: payload => this.submit(payload)
287
+ })
288
+ }
289
+
290
+ this.submit()
291
+ },
292
+
293
+ async submit (externalPayload = {}) {
294
+ if (this.disable) {
273
295
  return null
274
296
  }
275
297
 
276
- this.isSubmiting = true
298
+ this.isSubmitting = true
277
299
 
278
300
  try {
279
- const response = await this.$store.dispatch(
280
- `${this.entity}/${this.mode}`,
281
- { id: this.id, payload: this.value, url: this.url }
282
- )
301
+ const payload = { id: this.id, payload: this.value, url: this.url, ...externalPayload }
302
+ const response = await this.$store.dispatch(`${this.entity}/${this.mode}`, payload)
283
303
 
284
304
  if (this.showDialogOnUnsavedChanges) {
285
305
  this.cachedResult = cloneDeep(this.value)
@@ -301,7 +321,7 @@ export default {
301
321
 
302
322
  this.$emit('submit-error', error)
303
323
  } finally {
304
- this.isSubmiting = false
324
+ this.isSubmitting = false
305
325
  }
306
326
  }
307
327
  }
@@ -41,6 +41,10 @@ export default {
41
41
 
42
42
  argTypes: {
43
43
  // Props
44
+ beforeFetch: {
45
+ description: 'Function to be called before fetching data.'
46
+ },
47
+
44
48
  dialog: {
45
49
  description: 'Use when the component is inside a dialog.'
46
50
  },
@@ -67,6 +71,10 @@ export default {
67
71
  description: 'Ignore entity and specify another endpoint.'
68
72
  },
69
73
 
74
+ useResultsAreaOnly: {
75
+ description: 'Controls whether results will always be displayed regardless of there are no results to be displayed.'
76
+ },
77
+
70
78
  // Events
71
79
  'fetch-error': {
72
80
  description: 'Fires when occur an error fetching value.',
@@ -10,7 +10,7 @@
10
10
  </slot>
11
11
 
12
12
  <main class="relative-position">
13
- <div v-if="hasResults">
13
+ <div v-if="showResults">
14
14
  <slot :fields="fields" :metadata="metadata" :results="results" />
15
15
  </div>
16
16
 
@@ -67,6 +67,10 @@ export default {
67
67
  filtersProps: {
68
68
  default: () => ({}),
69
69
  type: Object
70
+ },
71
+
72
+ useResultsAreaOnly: {
73
+ type: Boolean
70
74
  }
71
75
  },
72
76
 
@@ -77,11 +81,6 @@ export default {
77
81
  },
78
82
 
79
83
  computed: {
80
- context () {
81
- const { limit, ordering, page, search, ...filters } = this.$route.query
82
- return { filters, limit, ordering, page: page ? parseInt(page) : 1, search }
83
- },
84
-
85
84
  hasHeaderSlot () {
86
85
  return !!(this.$slots.header || this.$scopedSlots.header)
87
86
  },
@@ -98,6 +97,10 @@ export default {
98
97
  return this.$store.getters[`${this.entity}/list`]
99
98
  },
100
99
 
100
+ showResults () {
101
+ return this.hasResults || (this.useResultsAreaOnly && !this.isFetching)
102
+ },
103
+
101
104
  totalPages () {
102
105
  return this.$store.getters[`${this.entity}/totalPages`]
103
106
  }
@@ -105,13 +108,13 @@ export default {
105
108
 
106
109
  watch: {
107
110
  $route () {
108
- this.fetchList()
111
+ this.onFetchHandler()
109
112
  this.setCurrentPage()
110
113
  }
111
114
  },
112
115
 
113
116
  created () {
114
- this.fetchList()
117
+ this.onFetchHandler()
115
118
  this.setCurrentPage()
116
119
  },
117
120
 
@@ -148,13 +151,17 @@ export default {
148
151
  },
149
152
 
150
153
  async refresh (done) {
151
- await this.fetchList()
154
+ await this.onFetchHandler()
152
155
 
153
156
  if (typeof done === 'function') {
154
157
  done()
155
158
  }
156
159
  },
157
160
 
161
+ async onFetchHandler () {
162
+ await this.fetchHandler({ ...this.context, url: this.url }, this.fetchList)
163
+ },
164
+
158
165
  setCurrentPage () {
159
166
  this.page = parseInt(this.$route.query.page || 1)
160
167
  }
@@ -12,14 +12,6 @@
12
12
  </slot>
13
13
  </template>
14
14
 
15
- <template #hint>
16
- <slot name="hint">
17
- <div v-if="isLoading" class="q-pb-sm">
18
- Buscando por opções...
19
- </div>
20
- </slot>
21
- </template>
22
-
23
15
  <template #no-option>
24
16
  <slot v-if="!isLoading" name="no-option">
25
17
  <q-item>
@@ -75,7 +67,7 @@ export default {
75
67
 
76
68
  value: {
77
69
  default: () => [],
78
- type: [Array, Object, String, Number]
70
+ type: [Array, Object, String, Number, Boolean]
79
71
  },
80
72
 
81
73
  valueKey: {
@@ -33,6 +33,10 @@ export default {
33
33
 
34
34
  argTypes: {
35
35
  // Props
36
+ beforeFetch: {
37
+ description: 'Function to be called before fetching data.'
38
+ },
39
+
36
40
  customId: {
37
41
  control: null,
38
42
  description: 'Sets a custom id to `entity`. When not set, will use the `:id` route param.'
@@ -57,7 +57,7 @@ export default {
57
57
 
58
58
  watch: {
59
59
  $route () {
60
- this.fetchSingle()
60
+ this.onFetchHandler()
61
61
  },
62
62
 
63
63
  result (value) {
@@ -66,7 +66,7 @@ export default {
66
66
  },
67
67
 
68
68
  created () {
69
- this.fetchSingle()
69
+ this.onFetchHandler()
70
70
  },
71
71
 
72
72
  methods: {
@@ -94,6 +94,10 @@ export default {
94
94
  } finally {
95
95
  this.isFetching = false
96
96
  }
97
+ },
98
+
99
+ async onFetchHandler () {
100
+ await this.fetchHandler({ id: this.id, url: this.url }, this.fetchSingle)
97
101
  }
98
102
  }
99
103
  }
@@ -5,6 +5,11 @@ import { NotifyError } from '../plugins'
5
5
 
6
6
  export default {
7
7
  props: {
8
+ beforeFetch: {
9
+ default: null,
10
+ type: Function
11
+ },
12
+
8
13
  dialog: {
9
14
  type: Boolean
10
15
  },
@@ -22,10 +27,10 @@ export default {
22
27
 
23
28
  data () {
24
29
  return {
30
+ cancelBeforeFetch: false,
25
31
  errors: {},
26
32
  fields: {},
27
33
  metadata: {},
28
-
29
34
  isFetching: false
30
35
  }
31
36
  },
@@ -59,6 +64,22 @@ export default {
59
64
  }
60
65
  },
61
66
 
67
+ fetchHandler (payload, resolve) {
68
+ const hasBeforeFetch = typeof this.beforeFetch === 'function'
69
+
70
+ if (hasBeforeFetch && !this.cancelBeforeFetch) {
71
+ return this.beforeFetch({
72
+ payload,
73
+ resolve: payload => resolve(payload),
74
+ done: () => {
75
+ this.cancelBeforeFetch = true
76
+ }
77
+ })
78
+ }
79
+
80
+ resolve()
81
+ },
82
+
62
83
  setErrors (errors = {}) {
63
84
  this.errors = errors
64
85
  },