@bildvitta/quasar-ui-asteroid 3.0.0-beta.7 → 3.0.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.
Files changed (106) hide show
  1. package/dist/api/QasAppBar.json +0 -4
  2. package/dist/api/QasBtn.json +2 -1
  3. package/dist/api/QasCard.json +13 -9
  4. package/dist/api/QasDateTimeInput.json +12 -12
  5. package/dist/api/QasDialog.json +6 -2
  6. package/dist/api/QasFilters.json +4 -4
  7. package/dist/api/QasFormGenerator.json +33 -2
  8. package/dist/api/QasFormView.json +43 -15
  9. package/dist/api/QasGridGenerator.json +5 -4
  10. package/dist/api/QasInput.json +1 -1
  11. package/dist/api/QasListItems.json +18 -17
  12. package/dist/api/QasListView.json +21 -7
  13. package/dist/api/QasNestedFields.json +13 -3
  14. package/dist/api/QasNumericInput.json +10 -10
  15. package/dist/api/QasPasswordInput.json +1 -1
  16. package/dist/api/QasSearchBox.json +85 -3
  17. package/dist/api/QasSelect.json +81 -14
  18. package/dist/api/QasSelectList.json +16 -14
  19. package/dist/api/QasSignaturePad.json +1 -1
  20. package/dist/api/QasSingleView.json +13 -4
  21. package/dist/api/QasTabsGenerator.json +5 -2
  22. package/dist/api/QasUploader.json +5 -0
  23. package/dist/asteroid.cjs.css +1 -1
  24. package/dist/asteroid.cjs.js +1522 -706
  25. package/dist/asteroid.cjs.min.js +2 -2
  26. package/dist/asteroid.esm.css +1 -1
  27. package/dist/asteroid.esm.js +1525 -709
  28. package/dist/asteroid.esm.min.js +2 -2
  29. package/dist/asteroid.umd.css +1 -1
  30. package/dist/asteroid.umd.js +1525 -710
  31. package/dist/asteroid.umd.min.js +2 -2
  32. package/dist/vetur/asteroid-attributes.json +176 -100
  33. package/dist/vetur/asteroid-tags.json +60 -41
  34. package/package.json +1 -1
  35. package/src/components/actions-menu/QasActionsMenu.vue +2 -8
  36. package/src/components/app-bar/QasAppBar.vue +16 -12
  37. package/src/components/app-bar/QasAppBar.yml +0 -4
  38. package/src/components/avatar/QasAvatar.vue +0 -4
  39. package/src/components/btn/QasBtn.vue +5 -8
  40. package/src/components/btn/QasBtn.yml +2 -1
  41. package/src/components/card/QasCard.vue +18 -9
  42. package/src/components/card/QasCard.yml +13 -9
  43. package/src/components/date-time-input/QasDateTimeInput.vue +39 -41
  44. package/src/components/date-time-input/QasDateTimeInput.yml +11 -12
  45. package/src/components/delete/QasDelete.vue +15 -1
  46. package/src/components/dialog/QasDialog.vue +26 -3
  47. package/src/components/dialog/QasDialog.yml +6 -3
  48. package/src/components/dialog-router/QasDialogRouter.vue +1 -1
  49. package/src/components/field/QasField.vue +15 -14
  50. package/src/components/filters/QasFilters.vue +27 -10
  51. package/src/components/filters/QasFilters.yml +4 -4
  52. package/src/components/form-generator/QasFormGenerator.vue +87 -12
  53. package/src/components/form-generator/QasFormGenerator.yml +16 -2
  54. package/src/components/form-view/QasFormView.vue +138 -56
  55. package/src/components/form-view/QasFormView.yml +39 -15
  56. package/src/components/grid-generator/QasGridGenerator.vue +23 -7
  57. package/src/components/grid-generator/QasGridGenerator.yml +5 -4
  58. package/src/components/input/QasInput.vue +37 -21
  59. package/src/components/input/QasInput.yml +1 -1
  60. package/src/components/layout/QasLayout.vue +4 -0
  61. package/src/components/list-items/QasListItems.vue +15 -23
  62. package/src/components/list-items/QasListItems.yml +14 -15
  63. package/src/components/list-view/QasListView.vue +45 -24
  64. package/src/components/list-view/QasListView.yml +19 -7
  65. package/src/components/map/QasMap.vue +5 -5
  66. package/src/components/nested-fields/QasNestedFields.vue +29 -21
  67. package/src/components/nested-fields/QasNestedFields.yml +9 -3
  68. package/src/components/numeric-input/QasNumericInput.vue +14 -14
  69. package/src/components/numeric-input/QasNumericInput.yml +10 -10
  70. package/src/components/page-header/QasPageHeader.vue +14 -11
  71. package/src/components/password-input/QasPasswordInput.vue +17 -16
  72. package/src/components/password-input/QasPasswordInput.yml +1 -1
  73. package/src/components/profile/QasProfile.vue +1 -1
  74. package/src/components/search-box/QasSearchBox.vue +138 -42
  75. package/src/components/search-box/QasSearchBox.yml +69 -2
  76. package/src/components/select/QasSelect.vue +63 -53
  77. package/src/components/select/QasSelect.yml +64 -13
  78. package/src/components/select-list/QasSelectList.vue +11 -27
  79. package/src/components/select-list/QasSelectList.yml +13 -14
  80. package/src/components/signature-pad/QasSignaturePad.yml +1 -1
  81. package/src/components/signature-uploader/QasSignatureUploader.vue +7 -5
  82. package/src/components/single-view/QasSingleView.vue +22 -6
  83. package/src/components/single-view/QasSingleView.yml +11 -4
  84. package/src/components/table-generator/QasTableGenerator.vue +13 -2
  85. package/src/components/tabs-generator/QasTabsGenerator.vue +2 -2
  86. package/src/components/tabs-generator/QasTabsGenerator.yml +2 -2
  87. package/src/components/text-truncate/QasTextTruncate.vue +1 -1
  88. package/src/components/uploader/QasUploader.vue +62 -15
  89. package/src/components/uploader/QasUploader.yml +5 -0
  90. package/src/helpers/camelize-fields-name.js +15 -0
  91. package/src/helpers/filters.js +2 -0
  92. package/src/helpers/get-normalized-options.js +20 -0
  93. package/src/helpers/handle-process.js +13 -0
  94. package/src/helpers/index.js +3 -0
  95. package/src/mixins/generator.js +10 -2
  96. package/src/mixins/index.js +2 -0
  97. package/src/mixins/search-filter.js +227 -0
  98. package/src/mixins/view.js +35 -13
  99. package/src/pages/Forbidden.vue +3 -1
  100. package/src/pages/NotFound.vue +3 -1
  101. package/src/pages/ServerError.vue +3 -1
  102. package/src/pages/Unauthorized.vue +28 -0
  103. package/src/plugins/index.js +4 -2
  104. package/src/plugins/logger/Logger.js +44 -0
  105. package/src/plugins/logger/Logger.yml +9 -0
  106. package/src/vue-plugin.js +6 -3
@@ -1,21 +1,19 @@
1
1
  <template>
2
- <div>
3
- <qas-input ref="input" v-bind="attributes" v-model="currentValue" :unmasked-value="false" @update:model-value="updateModelValue">
4
- <template #append>
5
- <q-icon v-if="!timeOnly" class="cursor-pointer" name="o_event">
6
- <q-popup-proxy ref="dateProxy" transition-hide="scale" transition-show="scale">
7
- <q-date v-model="currentValue" v-bind="dateProps" :mask="maskDate" @update:model-value="updateModelValue" />
8
- </q-popup-proxy>
9
- </q-icon>
10
-
11
- <q-icon v-if="!dateOnly" class="cursor-pointer q-ml-md" name="o_access_time">
12
- <q-popup-proxy ref="timeProxy" transition-hide="scale" transition-show="scale">
13
- <q-time v-model="currentValue" v-bind="timeProps" format24h :mask="maskDate" @update:model-value="updateModelValue" />
14
- </q-popup-proxy>
15
- </q-icon>
16
- </template>
17
- </qas-input>
18
- </div>
2
+ <qas-input ref="input" v-bind="attributes" v-model="currentValue" :unmasked-value="false" @update:model-value="updateModelValue">
3
+ <template #append>
4
+ <q-icon v-if="!useTimeOnly" class="cursor-pointer" name="o_event">
5
+ <q-popup-proxy ref="dateProxy" transition-hide="scale" transition-show="scale">
6
+ <q-date v-model="currentValue" v-bind="dateProps" :mask="maskDate" @update:model-value="updateModelValue" />
7
+ </q-popup-proxy>
8
+ </q-icon>
9
+
10
+ <q-icon v-if="!useDateOnly" class="cursor-pointer q-ml-md" name="o_access_time">
11
+ <q-popup-proxy ref="timeProxy" transition-hide="scale" transition-show="scale">
12
+ <q-time v-model="currentValue" v-bind="timeProps" format24h :mask="maskDate" @update:model-value="updateModelValue" />
13
+ </q-popup-proxy>
14
+ </q-icon>
15
+ </template>
16
+ </qas-input>
19
17
  </template>
20
18
 
21
19
  <script>
@@ -33,33 +31,33 @@ export default {
33
31
  type: String
34
32
  },
35
33
 
36
- dateOnly: {
37
- type: Boolean
38
- },
39
-
40
34
  dateProps: {
41
35
  default: () => ({}),
42
36
  type: Object
43
37
  },
44
38
 
45
- gmt: {
46
- type: Boolean
47
- },
48
-
49
39
  timeMask: {
50
40
  default: 'HH:mm',
51
41
  type: String
52
42
  },
53
43
 
54
- timeOnly: {
55
- type: Boolean
56
- },
57
-
58
44
  timeProps: {
59
45
  default: () => ({}),
60
46
  type: Object
61
47
  },
62
48
 
49
+ useIso: {
50
+ type: Boolean
51
+ },
52
+
53
+ useTimeOnly: {
54
+ type: Boolean
55
+ },
56
+
57
+ useDateOnly: {
58
+ type: Boolean
59
+ },
60
+
63
61
  modelValue: {
64
62
  default: '',
65
63
  type: String
@@ -96,16 +94,16 @@ export default {
96
94
  maskDate () {
97
95
  const mask = []
98
96
 
99
- if (!this.timeOnly) { mask.push(this.dateMask) }
100
- if (!this.dateOnly) { mask.push(this.timeMask) }
97
+ if (!this.useTimeOnly) { mask.push(this.dateMask) }
98
+ if (!this.useDateOnly) { mask.push(this.timeMask) }
101
99
 
102
100
  return mask.join(' ')
103
101
  }
104
102
  },
105
103
 
106
104
  watch: {
107
- value (current, original) {
108
- if (!current || this.timeOnly) {
105
+ modelValue (current, original) {
106
+ if (!current || this.useTimeOnly) {
109
107
  this.currentValue = current
110
108
  return
111
109
  }
@@ -131,18 +129,18 @@ export default {
131
129
 
132
130
  updateModelValue (value) {
133
131
  this.currentValue = value
134
- const valueLength = value.replace(/_/g, '').length
132
+ const valueLength = value?.replace?.(/_/g, '')?.length
135
133
 
136
134
  if (value === '' || valueLength === this.mask.length) {
137
- this.lastValue = this.timeOnly ? value : this.toISOString(value)
135
+ this.lastValue = this.useTimeOnly ? value : this.toISOString(value)
138
136
  this.$emit('update:modelValue', this.lastValue)
139
137
  }
140
138
 
141
- if (this.dateOnly) {
139
+ if (this.useDateOnly) {
142
140
  this.$refs.dateProxy.hide()
143
141
  }
144
142
 
145
- if (this.timeOnly) {
143
+ if (this.useTimeOnly) {
146
144
  this.$refs.timeProxy.hide()
147
145
  }
148
146
  },
@@ -152,11 +150,11 @@ export default {
152
150
  return ''
153
151
  }
154
152
 
155
- if (this.dateOnly && !this.gmt) {
153
+ if (this.useDateOnly && !this.useIso) {
156
154
  return dateFn(date.extractDate(value, this.maskDate), 'yyyy-MM-dd')
157
155
  }
158
156
 
159
- if (this.timeOnly && !this.gmt) {
157
+ if (this.useTimeOnly && !this.useIso) {
160
158
  return date.extractDate(value, 'HH:MM')
161
159
  }
162
160
 
@@ -164,14 +162,14 @@ export default {
164
162
  },
165
163
 
166
164
  toMask (value) {
167
- if (!value || this.timeOnly) {
165
+ if (!value || this.useTimeOnly) {
168
166
  return value || ''
169
167
  }
170
168
 
171
169
  const newDate = new Date(value).toISOString()
172
170
 
173
171
  return date.formatDate(
174
- this.dateOnly ? newDate.slice(0, 23) : newDate,
172
+ this.useDateOnly ? newDate.slice(0, 23) : newDate,
175
173
  this.maskDate
176
174
  )
177
175
  }
@@ -12,19 +12,11 @@ props:
12
12
  default: DD/MM/YYYY
13
13
  type: String
14
14
 
15
- date-only:
16
- desc: Habilita o componente para usar somente data.
17
- type: Boolean
18
-
19
15
  date-props:
20
16
  desc: Propriedades do QDate (https://quasar.dev/vue-components/date#introduction).
21
17
  default: {}
22
18
  type: Object
23
19
 
24
- gmt:
25
- desc: Utilizado para se usar junto da prop "date-only" ou "time-only", caso "gmt" for "true", o model sempre vai ser retornado no padrão ISO 8601, independente ser apenas um campo somente de data ou hora.
26
- type: Boolean
27
-
28
20
  model-value:
29
21
  desc: Model do componente, usado para v-model.
30
22
  default: ''
@@ -36,15 +28,22 @@ props:
36
28
  default: HH:mm
37
29
  type: String
38
30
 
39
- time-only:
40
- desc: Habilita o componente para usar somente hora.
41
- type: Boolean
42
-
43
31
  time-props:
44
32
  desc: Propriedades do QTime (https://quasar.dev/vue-components/time#introduction).
45
33
  default: {}
46
34
  type: Object
47
35
 
36
+ use-time-only:
37
+ desc: Habilita o componente para usar somente hora.
38
+ type: Boolean
39
+
40
+ use-date-only:
41
+ desc: Habilita o componente para usar somente data.
42
+ type: Boolean
43
+
44
+ use-iso:
45
+ desc: Utilizado para se usar junto da prop "date-only" ou "time-only", caso "useIso" for "true", o model sempre vai ser retornado no padrão ISO 8601, independente ser apenas um campo somente de data ou hora.
46
+ type: Boolean
48
47
 
49
48
  events:
50
49
  '@update:model-value -> function (value)':
@@ -106,7 +106,13 @@ export default {
106
106
  try {
107
107
  const { destroyRoutes, history } = useHistory()
108
108
 
109
- await this.$store.dispatch(`${this.entity}/destroy`, { id: this.id, url: this.url })
109
+ const payload = { id: this.id, url: this.url }
110
+
111
+ this.$qas.logger.group(
112
+ `QasDelete - destroy -> Payload do parâmetro do ${this.entity}/destroy`, [payload]
113
+ )
114
+
115
+ await this.$store.dispatch(`${this.entity}/destroy`, payload)
110
116
 
111
117
  NotifySuccess('Item deletado com sucesso!')
112
118
 
@@ -120,9 +126,17 @@ export default {
120
126
  this.createDeleteSuccessEvent()
121
127
 
122
128
  this.$emit('success')
129
+
130
+ this.$qas.logger.info('QasDelete - destroy -> item deletado com sucesso!')
123
131
  } catch (error) {
124
132
  NotifyError('Ops! Não foi possível deletar o item.')
125
133
  this.$emit('error', error)
134
+
135
+ this.$qas.logger.group(
136
+ `QasDelete - destroy -> exceção da action ${this.entity}/destroy`,
137
+ [error],
138
+ { error: true }
139
+ )
126
140
  } finally {
127
141
  Loading.hide()
128
142
  this.$emit('update:deleting', false)
@@ -5,7 +5,7 @@
5
5
  <slot name="header">
6
6
  <div class="justify-between row">
7
7
  <div class="text-bold text-h6">{{ card.title }}</div>
8
- <qas-btn v-if="useCloseIcon" v-close-popup dense flat icon="o_close" rounded />
8
+ <qas-btn v-if="useCloseButton" v-close-popup dense flat icon="o_close" rounded />
9
9
  </div>
10
10
  </slot>
11
11
  </q-card-section>
@@ -100,7 +100,11 @@ export default {
100
100
  type: Boolean
101
101
  },
102
102
 
103
- useCloseIcon: {
103
+ useCloseButton: {
104
+ type: Boolean
105
+ },
106
+
107
+ useValidationAllAtOnce: {
104
108
  type: Boolean
105
109
  }
106
110
  },
@@ -148,7 +152,26 @@ export default {
148
152
 
149
153
  methods: {
150
154
  async submitHandler () {
151
- this.useForm && this.$emit('validate', await this.$refs.form.validate())
155
+ if (!this.useForm) return
156
+
157
+ if (this.useValidationAllAtOnce) {
158
+ let isAllComponentValid = true
159
+ const components = this.$refs.form.getValidationComponents() || []
160
+
161
+ for (const component of components) {
162
+ const isValid = component?.validate?.()
163
+
164
+ if (!isValid) {
165
+ isAllComponentValid = false
166
+ }
167
+ }
168
+
169
+ this.$emit('validate', isAllComponentValid)
170
+
171
+ return
172
+ }
173
+
174
+ this.$emit('validate', await this.$refs.form.validate())
152
175
  },
153
176
 
154
177
  // método para funcionar como plugin
@@ -50,9 +50,9 @@ props:
50
50
  persistent:
51
51
  desc: Define se o dialog vai fechar ou não após clicar fora do dialog.
52
52
  default: true
53
- type: Object
53
+ type: Boolean
54
54
 
55
- use-close-icon:
55
+ use-close-button:
56
56
  desc: Define se vai ter ou não Ícone de fechar o dialog.
57
57
  type: Boolean
58
58
 
@@ -60,8 +60,11 @@ props:
60
60
  desc: Define se a tag onde fica a descrição no dialog vai ser um "<q-form />" ou "<div />".
61
61
  type: Boolean
62
62
 
63
- slots:
63
+ use-validation-at-once:
64
+ desc: Valida todos os campos de uma única vez, ao invés de ser um por vez (que é o padrão).
65
+ type: Boolean
64
66
 
67
+ slots:
65
68
  actions:
66
69
  desc: Slot para ações (botões por exemplo).
67
70
 
@@ -2,7 +2,7 @@
2
2
  <q-dialog ref="dialog" persistent @hide="onDialogHide">
3
3
  <q-card class="full-width" style="max-width: 80vw;">
4
4
  <q-card-section>
5
- <component :is="component" v-if="component" dialog :route="route" @hide="hide" />
5
+ <component :is="component" v-if="component" :route="route" :use-boundary="false" @hide="hide" />
6
6
  </q-card-section>
7
7
  </q-card>
8
8
  </q-dialog>
@@ -1,11 +1,9 @@
1
1
  <template>
2
- <div>
3
- <component :is="component.is" v-bind="component" :data-cy="field.name" :model-value="formattedValue" @update:model-value="updateModel">
4
- <template v-for="(_, name) in $slots" #[name]="context">
5
- <slot :name="name" v-bind="context || {}" />
6
- </template>
7
- </component>
8
- </div>
2
+ <component :is="component.is" v-bind="component" :data-cy="field.name" :model-value="formattedValue" @update:model-value="updateModel">
3
+ <template v-for="(_, name) in $slots" #[name]="context">
4
+ <slot :name="name" v-bind="context || {}" />
5
+ </template>
6
+ </component>
9
7
  </template>
10
8
 
11
9
  <script>
@@ -36,6 +34,8 @@ export default {
36
34
  QasSignatureUploader
37
35
  },
38
36
 
37
+ inheritAttrs: false,
38
+
39
39
  props: {
40
40
  error: {
41
41
  default: '',
@@ -75,8 +75,9 @@ export default {
75
75
  type,
76
76
  mask,
77
77
  maxFiles,
78
- searchable,
79
- gmt
78
+ useIso,
79
+ useSearch,
80
+ useLazyLoading
80
81
  } = this.formattedField
81
82
 
82
83
  // Default error attributes for Quasar.
@@ -98,11 +99,11 @@ export default {
98
99
  minlength,
99
100
  suffix,
100
101
  prefix,
101
- gmt
102
+ useIso
102
103
  }
103
104
 
104
105
  const numericInput = { is: 'qas-numeric-input', ...input }
105
- const datetimeInput = { is: 'qas-date-time-input', gmt, ...input }
106
+ const datetimeInput = { is: 'qas-date-time-input', useIso, ...input }
106
107
 
107
108
  // It'll generate a list of acceptable files extensions.
108
109
  const accept = extensions && extensions.length ? extensions.map(extension => `.${extension}`).join(',') : ''
@@ -130,9 +131,9 @@ export default {
130
131
  money: { ...numericInput, mode: 'money' },
131
132
  percent: { ...numericInput, mode: 'percent' },
132
133
 
133
- date: { ...datetimeInput, dateOnly: true },
134
+ date: { ...datetimeInput, useDateOnly: true },
134
135
  datetime: { ...datetimeInput },
135
- time: { ...datetimeInput, timeOnly: true },
136
+ time: { ...datetimeInput, useTimeOnly: true },
136
137
 
137
138
  boolean: { is: 'q-toggle', label, ...error },
138
139
  checkbox: { is: 'qas-checkbox-group', label, options, ...error },
@@ -143,7 +144,7 @@ export default {
143
144
 
144
145
  'signature-uploader': { is: 'qas-signature-uploader', entity, uploadLabel: label, ...error },
145
146
 
146
- select: { is: 'qas-select', multiple, options, searchable, ...input }
147
+ select: { is: 'qas-select', entity, name, multiple, options, useSearch, useLazyLoading, ...input }
147
148
  }
148
149
 
149
150
  return { ...(profiles[type] || profiles.default), ...this.$attrs }
@@ -4,18 +4,18 @@
4
4
  <div v-if="showSearch" class="col">
5
5
  <slot :filter="filter" name="search">
6
6
  <q-form v-if="useSearch" @submit.prevent="filter()">
7
- <q-input v-model="search" :debounce="debounce" dense :placeholder="searchPlaceholder" type="search">
7
+ <qas-input v-model="search" :debounce="debounce" dense hide-bottom-space :outlined="false" :placeholder="searchPlaceholder" type="search">
8
8
  <template #append>
9
- <q-btn v-if="hasSearch" icon="o_clear" unelevated @click="clearSearch" />
10
- <q-btn v-if="!debounce" icon="o_search" type="submit" unelevated @click="filter()" />
9
+ <qas-btn v-if="hasSearch" color="grey-9" flat icon="o_clear" unelevated @click="clearSearch" />
10
+ <qas-btn v-if="!debounce" color="grey-9" flat icon="o_search" type="submit" unelevated @click="filter()" />
11
11
  </template>
12
- </q-input>
12
+ </qas-input>
13
13
  </q-form>
14
14
  </slot>
15
15
  </div>
16
16
 
17
17
  <slot v-if="showFilterButton" :filter="filter" name="filter-button">
18
- <q-btn v-if="useFilterButton" :color="filterButtonColor" flat icon="o_filter_list" :label="filterButtonLabel">
18
+ <qas-btn v-if="useFilterButton" :color="filterButtonColor" flat icon="o_filter_list" :label="filterButtonLabel">
19
19
  <q-menu class="full-width" max-width="240px">
20
20
  <div v-if="isFetching" class="q-pa-xl text-center">
21
21
  <q-spinner color="grey" size="2em" />
@@ -31,12 +31,12 @@
31
31
  </div>
32
32
 
33
33
  <div class="text-right">
34
- <q-btn class="q-mr-sm" label="Limpar" size="12px" unelevated @click="clearFilters" />
35
- <q-btn color="primary" label="Filtrar" size="12px" type="submit" unelevated />
34
+ <qas-btn class="q-mr-sm" flat label="Limpar" :no-caps="false" size="12px" unelevated @click="clearFilters" />
35
+ <qas-btn color="primary" label="Filtrar" :no-caps="false" size="12px" type="submit" unelevated />
36
36
  </div>
37
37
  </q-form>
38
38
  </q-menu>
39
- </q-btn>
39
+ </qas-btn>
40
40
  </slot>
41
41
  </div>
42
42
 
@@ -50,6 +50,7 @@
50
50
 
51
51
  <script>
52
52
  import QasField from '../field/QasField.vue'
53
+ import QasBtn from '../btn/QasBtn.vue'
53
54
 
54
55
  import { camelize, camelizeKeys } from 'humps'
55
56
  import { humanize, parseValue } from '../../helpers/filters.js'
@@ -59,6 +60,7 @@ export default {
59
60
  name: 'QasFilters',
60
61
 
61
62
  components: {
63
+ QasBtn,
62
64
  QasField
63
65
  },
64
66
 
@@ -100,7 +102,7 @@ export default {
100
102
  type: String
101
103
  },
102
104
 
103
- forceRefetch: {
105
+ useForceRefetch: {
104
106
  type: Boolean
105
107
  }
106
108
  },
@@ -231,7 +233,7 @@ export default {
231
233
  },
232
234
 
233
235
  async fetchFilters () {
234
- if (!this.forceRefetch && (this.hasFields || !this.useFilterButton)) {
236
+ if (!this.useForceRefetch && (this.hasFields || !this.useFilterButton)) {
235
237
  return null
236
238
  }
237
239
 
@@ -239,11 +241,26 @@ export default {
239
241
  this.isFetching = true
240
242
 
241
243
  try {
244
+ this.$qas.logger.group(
245
+ `QasFilters - fetchFilters -> Payload do parâmetro do ${this.entity}/fetchFilters`,
246
+ [{ url: this.url }]
247
+ )
248
+
242
249
  const response = await this.$store.dispatch(`${this.entity}/fetchFilters`, { url: this.url })
243
250
  this.$emit('fetch-success', response)
251
+
252
+ this.$qas.logger.group(
253
+ `QasFilters - fetchFilters -> resposta da action ${this.entity}/fetchFilters`, [response]
254
+ )
244
255
  } catch (error) {
245
256
  this.hasFetchError = true
246
257
  this.$emit('fetch-error', error)
258
+
259
+ this.$qas.logger.group(
260
+ `QasFilters - fetchFilters -> exceção da action ${this.entity}/fetchFilters`,
261
+ [error],
262
+ { error: true }
263
+ )
247
264
  } finally {
248
265
  this.isFetching = false
249
266
  }
@@ -9,10 +9,6 @@ props:
9
9
  required: true
10
10
  type: String
11
11
 
12
- force-refetch:
13
- desc: Força refazer o "fetch" mesmo caso já exista dados na store de filters.
14
- type: Boolean
15
-
16
12
  search-placeholder:
17
13
  desc: Placeholder do campo de busca.
18
14
  default: Pesquisar...
@@ -32,6 +28,10 @@ props:
32
28
  default: true
33
29
  type: Boolean
34
30
 
31
+ use-force-refetch:
32
+ desc: Força refazer o "fetch" mesmo caso já exista dados na store de filters.
33
+ type: Boolean
34
+
35
35
  use-search-on-type:
36
36
  desc: Habilita ou não o filtro de busca sempre que o usuário digita.
37
37
  default: true
@@ -1,17 +1,25 @@
1
1
  <template>
2
- <div>
3
- <div :class="mx_classes">
4
- <div v-for="(field, key) in groupedFields.visible" :key="key" :class="mx_getFieldClass(key)">
5
- <slot :field="field" :name="`field-${field.name}`">
6
- <qas-field v-bind="fieldsProps[field.name]" :error="errors[key]" :field="field" :model-value="modelValue[field.name]" @update:model-value="updateModelValue(field.name, $event)" />
7
- </slot>
8
- </div>
9
- </div>
10
-
11
- <div v-for="(field, key) in groupedFields.hidden" :key="key">
12
- <slot :field="field" :name="`field-${field.name}`">
13
- <qas-field v-bind="fieldsProps[field.name]" :field="field" :model-value="modelValue[field.name]" @update:model-value="updateModelValue(field.name, $event)" />
2
+ <div :class="fieldsetClasses">
3
+ <div v-for="(fieldsetItem, fieldsetItemKey) in normalizedFields" :key="fieldsetItemKey" class="full-width">
4
+ <slot v-if="fieldsetItem.label" :name="`legend-${fieldsetItemKey}`">
5
+ <qas-label :label="fieldsetItem.label" />
14
6
  </slot>
7
+
8
+ <div>
9
+ <div :class="mx_classes">
10
+ <div v-for="(field, key) in fieldsetItem.fields.visible" :key="key" :class="mx_getFieldClass(key)">
11
+ <slot :field="field" :name="`field-${field.name}`">
12
+ <qas-field v-bind="fieldsProps[field.name]" :error="errors[key]" :field="field" :model-value="modelValue[field.name]" @update:model-value="updateModelValue(field.name, $event)" />
13
+ </slot>
14
+ </div>
15
+ </div>
16
+
17
+ <div v-for="(field, key) in fieldsetItem.fields.hidden" :key="key">
18
+ <slot :field="field" :name="`field-${field.name}`">
19
+ <qas-field v-bind="fieldsProps[field.name]" :field="field" :model-value="modelValue[field.name]" @update:model-value="updateModelValue(field.name, $event)" />
20
+ </slot>
21
+ </div>
22
+ </div>
15
23
  </div>
16
24
  </div>
17
25
  </template>
@@ -49,6 +57,19 @@ export default {
49
57
  default: () => ({}),
50
58
  required: true,
51
59
  type: Object
60
+ },
61
+
62
+ fieldset: {
63
+ default: () => ({}),
64
+ type: Object
65
+ },
66
+
67
+ fieldsetGutter: {
68
+ default: 'lg',
69
+ type: [String, Boolean],
70
+ validator: value => {
71
+ return typeof value === 'boolean' || ['xs', 'sm', 'md', 'lg', 'xl'].includes(value)
72
+ }
52
73
  }
53
74
  },
54
75
 
@@ -58,6 +79,8 @@ export default {
58
79
  groupedFields () {
59
80
  const fields = { hidden: {}, visible: {} }
60
81
 
82
+ if (this.hasFieldset) return fields
83
+
61
84
  for (const key in this.fields) {
62
85
  const field = this.fields[key]
63
86
  fields[field.type === 'hidden' ? 'hidden' : 'visible'][key] = field
@@ -74,6 +97,58 @@ export default {
74
97
  }
75
98
 
76
99
  return fields
100
+ },
101
+
102
+ normalizedFields () {
103
+ if (!this.hasFieldset) {
104
+ return {
105
+ default: {
106
+ fields: this.groupedFields
107
+ }
108
+ }
109
+ }
110
+
111
+ const fields = {}
112
+
113
+ for (const fieldsetKey in this.fieldset) {
114
+ const fieldsetItem = this.fieldset[fieldsetKey]
115
+
116
+ fields[fieldsetKey] = {
117
+ label: fieldsetItem.label,
118
+ fields: { hidden: {}, visible: {} }
119
+ }
120
+
121
+ for (const fieldName of fieldsetItem.fields) {
122
+ const field = this.fields[fieldName]
123
+
124
+ if (!field) continue
125
+
126
+ Object.assign(
127
+ fields[fieldsetKey].fields[
128
+ field.type === 'hidden' ? 'hidden' : 'visible'
129
+ ],
130
+ {
131
+ [fieldName]: field
132
+ }
133
+ )
134
+ }
135
+ }
136
+
137
+ return fields
138
+ },
139
+
140
+ hasFieldset () {
141
+ return !!Object.keys(this.fieldset).length
142
+ },
143
+
144
+ fieldsetClasses () {
145
+ const classes = ['row']
146
+
147
+ if (this.fieldsetGutter) {
148
+ classes.push(`q-col-gutter-y-${this.fieldsetGutter}`)
149
+ }
150
+
151
+ return classes
77
152
  }
78
153
  },
79
154
 
@@ -27,11 +27,23 @@ props:
27
27
  type: Object
28
28
  examples: ["{ email: { name: 'email', type: 'email', label: 'E-mail' } }"]
29
29
 
30
+ fieldset:
31
+ desc: Lista para agrupar elementos por rótulo (label).
32
+ default: {}
33
+ type: Object
34
+ examples: ["{ personalInformation: { label: 'Informações pessoais', fields: [name, email] } }"]
35
+
36
+ fieldset-gutter:
37
+ desc: Espaçamento entre rótulos (label).
38
+ default: lg
39
+ type: [String, Boolean]
40
+ examples: [xs, sm, md, lg, xl, false]
41
+
30
42
  gutter:
31
43
  desc: Espaçamento entre colunas.
32
44
  default: md
33
- type: String
34
- examples: [xs, sm, md, lg, xl]
45
+ type: [String, Boolean]
46
+ examples: [xs, sm, md, lg, xl, false]
35
47
 
36
48
  model-value:
37
49
  desc: Model do componente, usado para o v-model.
@@ -54,6 +66,8 @@ slots:
54
66
  desc: Payload do campo atual.
55
67
  default: {}
56
68
  type: Object
69
+ 'legend-[nome-da-chave]':
70
+ desc: Acessa o slot de um rótulo (label).
57
71
 
58
72
  events:
59
73
  '@update:model-value -> function(value)':