@bildvitta/quasar-ui-asteroid 3.0.0-beta.2 → 3.0.0-beta.20

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 (173) hide show
  1. package/dist/api/QasActionsMenu.json +15 -15
  2. package/dist/api/QasAppBar.json +4 -8
  3. package/dist/api/QasAppMenu.json +11 -7
  4. package/dist/api/QasBtn.json +8 -4
  5. package/dist/api/QasCard.json +17 -13
  6. package/dist/api/QasCheckboxGroup.json +8 -8
  7. package/dist/api/QasCopy.json +4 -4
  8. package/dist/api/QasDateTimeInput.json +16 -16
  9. package/dist/api/QasDelete.json +17 -17
  10. package/dist/api/QasDialog.json +24 -20
  11. package/dist/api/QasFilters.json +14 -14
  12. package/dist/api/QasFormGenerator.json +57 -26
  13. package/dist/api/QasFormView.json +115 -87
  14. package/dist/api/QasGallery.json +4 -4
  15. package/dist/api/QasGridGenerator.json +40 -39
  16. package/dist/api/QasInput.json +13 -13
  17. package/dist/api/QasListItems.json +18 -17
  18. package/dist/api/QasListView.json +67 -53
  19. package/dist/api/QasNestedFields.json +45 -35
  20. package/dist/api/QasNumericInput.json +31 -12
  21. package/dist/api/QasPageHeader.json +7 -7
  22. package/dist/api/QasPasswordInput.json +13 -13
  23. package/dist/api/QasPasswordStrengthChecker.json +12 -12
  24. package/dist/api/QasProfile.json +5 -5
  25. package/dist/api/QasResizer.json +11 -11
  26. package/dist/api/QasSearchBox.json +90 -8
  27. package/dist/api/QasSelect.json +92 -25
  28. package/dist/api/QasSelectList.json +16 -14
  29. package/dist/api/QasSignaturePad.json +1 -1
  30. package/dist/api/QasSignatureUploader.json +9 -9
  31. package/dist/api/QasSingleView.json +52 -43
  32. package/dist/api/QasSortable.json +20 -20
  33. package/dist/api/QasTableGenerator.json +5 -5
  34. package/dist/api/QasTabsGenerator.json +5 -2
  35. package/dist/api/QasTransfer.json +9 -9
  36. package/dist/api/QasUploader.json +22 -17
  37. package/dist/asteroid.cjs.css +1 -1
  38. package/dist/asteroid.cjs.js +3904 -3102
  39. package/dist/asteroid.cjs.min.js +2 -2
  40. package/dist/asteroid.esm.css +1 -1
  41. package/dist/asteroid.esm.js +3908 -3106
  42. package/dist/asteroid.esm.min.js +2 -2
  43. package/dist/asteroid.umd.css +1 -1
  44. package/dist/asteroid.umd.js +3907 -3106
  45. package/dist/asteroid.umd.min.js +2 -2
  46. package/dist/vetur/asteroid-attributes.json +387 -303
  47. package/dist/vetur/asteroid-tags.json +129 -108
  48. package/package.json +1 -1
  49. package/src/assets/gear.svg +27 -0
  50. package/src/components/actions/QasActions.vue +1 -5
  51. package/src/components/actions-menu/QasActionsMenu.vue +4 -10
  52. package/src/components/actions-menu/QasActionsMenu.yml +15 -15
  53. package/src/components/app-bar/QasAppBar.vue +18 -14
  54. package/src/components/app-bar/QasAppBar.yml +4 -8
  55. package/src/components/app-menu/QasAppMenu.vue +8 -7
  56. package/src/components/app-menu/QasAppMenu.yml +11 -7
  57. package/src/components/avatar/QasAvatar.vue +0 -4
  58. package/src/components/box/QasBox.vue +1 -1
  59. package/src/components/btn/QasBtn.vue +11 -15
  60. package/src/components/btn/QasBtn.yml +7 -3
  61. package/src/components/card/QasCard.vue +18 -9
  62. package/src/components/card/QasCard.yml +17 -13
  63. package/src/components/checkbox-group/QasCheckboxGroup.yml +9 -8
  64. package/src/components/copy/QasCopy.vue +1 -1
  65. package/src/components/copy/QasCopy.yml +4 -3
  66. package/src/components/date-time-input/QasDateTimeInput.vue +39 -41
  67. package/src/components/date-time-input/QasDateTimeInput.yml +16 -16
  68. package/src/components/delete/QasDelete.vue +15 -1
  69. package/src/components/delete/QasDelete.yml +15 -15
  70. package/src/components/dialog/QasDialog.vue +28 -9
  71. package/src/components/dialog/QasDialog.yml +22 -18
  72. package/src/components/dialog-router/QasDialogRouter.vue +1 -1
  73. package/src/components/field/QasField.vue +15 -14
  74. package/src/components/filters/QasFilters.vue +30 -13
  75. package/src/components/filters/QasFilters.yml +14 -14
  76. package/src/components/form-generator/QasFormGenerator.vue +87 -12
  77. package/src/components/form-generator/QasFormGenerator.yml +32 -18
  78. package/src/components/form-view/QasFormView.vue +142 -60
  79. package/src/components/form-view/QasFormView.yml +91 -67
  80. package/src/components/gallery/QasGallery.vue +4 -8
  81. package/src/components/gallery/QasGallery.yml +4 -4
  82. package/src/components/grid-generator/QasGridGenerator.vue +23 -7
  83. package/src/components/grid-generator/QasGridGenerator.yml +29 -27
  84. package/src/components/input/QasInput.vue +37 -21
  85. package/src/components/input/QasInput.yml +13 -13
  86. package/src/components/layout/QasLayout.vue +4 -0
  87. package/src/components/list-items/QasListItems.vue +16 -24
  88. package/src/components/list-items/QasListItems.yml +14 -15
  89. package/src/components/list-view/QasListView.vue +48 -20
  90. package/src/components/list-view/QasListView.yml +58 -46
  91. package/src/components/map/QasMap.vue +5 -5
  92. package/src/components/nested-fields/QasNestedFields.vue +29 -21
  93. package/src/components/nested-fields/QasNestedFields.yml +35 -28
  94. package/src/components/numeric-input/QasNumericInput.vue +45 -27
  95. package/src/components/numeric-input/QasNumericInput.yml +26 -12
  96. package/src/components/page-header/QasPageHeader.vue +14 -11
  97. package/src/components/page-header/QasPageHeader.yml +4 -4
  98. package/src/components/password-input/QasPasswordInput.vue +17 -16
  99. package/src/components/password-input/QasPasswordInput.yml +11 -11
  100. package/src/components/password-strength-checker/QasPasswordStrengthChecker.yml +10 -10
  101. package/src/components/profile/QasProfile.vue +3 -6
  102. package/src/components/profile/QasProfile.yml +5 -5
  103. package/src/components/resizer/QasResizer.vue +1 -1
  104. package/src/components/resizer/QasResizer.yml +6 -5
  105. package/src/components/search-box/QasSearchBox.vue +138 -42
  106. package/src/components/search-box/QasSearchBox.yml +74 -7
  107. package/src/components/select/QasSelect.vue +63 -53
  108. package/src/components/select/QasSelect.yml +68 -17
  109. package/src/components/select-list/QasSelectList.vue +13 -32
  110. package/src/components/select-list/QasSelectList.yml +13 -14
  111. package/src/components/signature-pad/QasSignaturePad.vue +1 -1
  112. package/src/components/signature-pad/QasSignaturePad.yml +1 -1
  113. package/src/components/signature-uploader/QasSignatureUploader.vue +13 -14
  114. package/src/components/signature-uploader/QasSignatureUploader.yml +9 -9
  115. package/src/components/single-view/QasSingleView.vue +24 -8
  116. package/src/components/single-view/QasSingleView.yml +45 -38
  117. package/src/components/sortable/QasSortable.yml +17 -17
  118. package/src/components/table-generator/QasTableGenerator.vue +14 -6
  119. package/src/components/table-generator/QasTableGenerator.yml +5 -5
  120. package/src/components/tabs-generator/QasTabsGenerator.vue +2 -2
  121. package/src/components/tabs-generator/QasTabsGenerator.yml +2 -2
  122. package/src/components/text-truncate/QasTextTruncate.vue +2 -5
  123. package/src/components/transfer/QasTransfer.vue +5 -7
  124. package/src/components/transfer/QasTransfer.yml +9 -9
  125. package/src/components/uploader/QasUploader.vue +63 -16
  126. package/src/components/uploader/QasUploader.yml +17 -12
  127. package/src/composables/index.js +1 -1
  128. package/src/composables/{useHistory.js → use-history.js} +0 -0
  129. package/src/css/components/base.scss +3 -0
  130. package/src/css/components/field.scss +4 -0
  131. package/src/css/components/index.scss +4 -0
  132. package/src/css/components/radio.scss +3 -0
  133. package/src/css/components/tabs.scss +3 -0
  134. package/src/css/mixins/index.scss +1 -0
  135. package/src/css/{set-brand.scss → mixins/set-brand.scss} +0 -0
  136. package/src/css/{background.scss → utils/background.scss} +0 -0
  137. package/src/css/{border-radius.scss → utils/border-radius.scss} +0 -0
  138. package/src/css/{border.scss → utils/border.scss} +0 -0
  139. package/src/css/{container.scss → utils/container.scss} +0 -0
  140. package/src/css/{fonts.scss → utils/fonts.scss} +0 -0
  141. package/src/css/utils/index.scss +9 -0
  142. package/src/css/{line-height.scss → utils/line-height.scss} +0 -0
  143. package/src/css/{opacity.scss → utils/opacity.scss} +0 -0
  144. package/src/css/{text.scss → utils/text.scss} +0 -0
  145. package/src/css/{unset.scss → utils/unset.scss} +0 -0
  146. package/src/css/variables/button.scss +3 -0
  147. package/src/css/variables/index.scss +3 -0
  148. package/src/css/variables/shadow.scss +33 -0
  149. package/src/css/variables/typography.scss +139 -0
  150. package/src/helpers/camelize-fields-name.js +15 -0
  151. package/src/helpers/filters.js +2 -0
  152. package/src/helpers/get-normalized-options.js +20 -0
  153. package/src/helpers/handle-process.js +13 -0
  154. package/src/helpers/index.js +3 -0
  155. package/src/index.scss +11 -12
  156. package/src/mixins/generator.js +10 -2
  157. package/src/mixins/index.js +3 -3
  158. package/src/mixins/search-filter.js +227 -0
  159. package/src/mixins/view.js +35 -13
  160. package/src/pages/ErrorComponent.vue +56 -0
  161. package/src/pages/Forbidden.vue +21 -5
  162. package/src/pages/NotFound.vue +21 -5
  163. package/src/pages/ServerError.vue +25 -0
  164. package/src/pages/Unauthorized.vue +28 -0
  165. package/src/plugins/index.js +4 -2
  166. package/src/plugins/logger/Logger.js +44 -0
  167. package/src/plugins/logger/Logger.yml +9 -0
  168. package/src/plugins/screen/Screen.js +5 -0
  169. package/src/vue-plugin.js +6 -3
  170. package/src/assets/logo-modular.svg +0 -1
  171. package/src/css/design-system.scss +0 -18
  172. package/src/css/shadow.scss +0 -7
  173. package/src/mixins/screen.js +0 -34
@@ -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)
@@ -4,23 +4,25 @@ meta:
4
4
  desc: Componente para C.R.U.D. responsável por deletar (Delete).
5
5
 
6
6
  props:
7
- entity:
8
- desc: Entidade da store, por exemplo se tiver que trabalhar com modulo de usuários, teremos o model "users" na store, que vai ser nossa "entity".
9
- required: true
10
- type: String
11
-
12
7
  custom-id:
13
8
  desc: Por padrão, o componente vai pegar o "id" que vem como parâmetro na url, caso queira que o id seja diferente da url, use esta prop.
14
9
  type: String
15
10
  examples: ['my-custom-id']
16
11
 
12
+ deleting:
13
+ desc: Model para saber se está deletando.
14
+ type: Boolean
15
+ examples: [v-model:deleting="isDeleting"]
16
+ model: true
17
+
17
18
  dialog-props:
18
19
  desc: Props para ser repassada para o componente "QasDialog"
19
20
  default: {}
20
21
  type: Object
21
22
 
22
- url:
23
- desc: Envia como parâmetro para a action "fetchSingle" do modulo correspondente a "entity".
23
+ entity:
24
+ desc: Entidade da store, por exemplo se tiver que trabalhar com modulo de usuários, teremos o model "users" na store, que vai ser nossa "entity".
25
+ required: true
24
26
  type: String
25
27
 
26
28
  tag:
@@ -29,11 +31,9 @@ props:
29
31
  type: String
30
32
  examples: [q-item]
31
33
 
32
- deleting:
33
- desc: Model para saber se está deletando.
34
- type: Boolean
35
- examples: [v-model:deleting="isDeleting"]
36
- model: true
34
+ url:
35
+ desc: Envia como parâmetro para a action "fetchSingle" do modulo correspondente a "entity".
36
+ type: String
37
37
 
38
38
  use-auto-delete-route:
39
39
  desc: Controla se sempre que deletar com sucesso um item, remove todas as rotas do histórico de rotas que contenha id do item deletado.
@@ -45,12 +45,12 @@ slots:
45
45
  desc: 'Slot para acessar dentro do componente.'
46
46
 
47
47
  events:
48
- '@success -> function()':
49
- desc: Dispara quando o componente deleta com sucesso.
50
-
51
48
  '@error -> function(value)':
52
49
  desc: Dispara quando acontece algum erro na hora de deletar.
53
50
  params:
54
51
  value:
55
52
  desc: Erro retornado.
56
53
  type: Object
54
+
55
+ '@success -> function()':
56
+ desc: Dispara quando o componente deleta com sucesso.
@@ -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>
@@ -39,8 +39,6 @@
39
39
  import QasBtn from '../btn/QasBtn.vue'
40
40
  import QasActions from '../actions/QasActions.vue'
41
41
 
42
- import screenMixin from '../../mixins/screen'
43
-
44
42
  export default {
45
43
  name: 'QasDialog',
46
44
 
@@ -49,8 +47,6 @@ export default {
49
47
  QasActions
50
48
  },
51
49
 
52
- mixins: [screenMixin],
53
-
54
50
  props: {
55
51
  actionsProps: {
56
52
  default: () => ({}),
@@ -104,7 +100,11 @@ export default {
104
100
  type: Boolean
105
101
  },
106
102
 
107
- useCloseIcon: {
103
+ useCloseButton: {
104
+ type: Boolean
105
+ },
106
+
107
+ useValidationAllAtOnce: {
108
108
  type: Boolean
109
109
  }
110
110
  },
@@ -133,8 +133,8 @@ export default {
133
133
 
134
134
  style () {
135
135
  return {
136
- maxWidth: this.maxWidth || (this.mx_isSmall ? '' : '600px'),
137
- minWidth: this.minWidth || (this.mx_isSmall ? '' : '400px')
136
+ maxWidth: this.maxWidth || (this.$qas.screen.isSmall ? '' : '600px'),
137
+ minWidth: this.minWidth || (this.$qas.screen.isSmall ? '' : '400px')
138
138
  }
139
139
  },
140
140
 
@@ -152,7 +152,26 @@ export default {
152
152
 
153
153
  methods: {
154
154
  async submitHandler () {
155
- 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())
156
175
  },
157
176
 
158
177
  // método para funcionar como plugin
@@ -15,16 +15,16 @@ props:
15
15
  type: [Object, Boolean]
16
16
  examples: ["{ label: 'Meu botão de cancelar', onClick: () => alert('fui clicado!') }"]
17
17
 
18
- card:
19
- desc: Objeto contendo as informações para serem exibidas dentro do dialog como "title" e "description".
18
+ card-props:
19
+ desc: Props repassadas para o componente "<q-card />".
20
20
  default: {}
21
21
  type: Object
22
- examples: ["{ title: 'Meu título', description: 'Minha descrição' }"]
23
22
 
24
- card-props:
25
- desc: Props repassadas para o componente "<q-card />".
23
+ card:
24
+ desc: Objeto contendo as informações para serem exibidas dentro do dialog como "title" e "description".
26
25
  default: {}
27
26
  type: Object
27
+ examples: ["{ title: 'Meu título', description: 'Minha descrição' }"]
28
28
 
29
29
  max-width:
30
30
  desc: Tamanho máximo do dialog.
@@ -34,6 +34,12 @@ props:
34
34
  desc: Tamanho mínimo do dialog.
35
35
  type: String
36
36
 
37
+ model-value:
38
+ desc: Model do componente, abre ou fecha o dialog.
39
+ type: Boolean
40
+ examples: [v-model="value"]
41
+ model: true
42
+
37
43
  ok:
38
44
  desc: Props para o botão de confirmar (ok), pode ser objeto com as propriedades ou um boolean, caso for "false", remove o botão de confirmar.
39
45
  default: "{ label: 'Ok', outline: type: this.ok?.type || this.useForm ? 'submit' : 'button' }"
@@ -44,31 +50,29 @@ props:
44
50
  persistent:
45
51
  desc: Define se o dialog vai fechar ou não após clicar fora do dialog.
46
52
  default: true
47
- type: Object
53
+ type: Boolean
48
54
 
49
- use-form:
50
- desc: Define se a tag onde fica a descrição no dialog vai ser um "<q-form />" ou "<div />".
55
+ use-close-button:
56
+ desc: Define se vai ter ou não Ícone de fechar o dialog.
51
57
  type: Boolean
52
58
 
53
- model-value:
54
- desc: Model do componente, abre ou fecha o dialog.
59
+ use-form:
60
+ desc: Define se a tag onde fica a descrição no dialog vai ser um "<q-form />" ou "<div />".
55
61
  type: Boolean
56
- examples: [v-model="value"]
57
- model: true
58
62
 
59
- use-close-icon:
60
- desc: Define se vai ter ou não Ícone de fechar o dialog.
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).
61
65
  type: Boolean
62
66
 
63
67
  slots:
64
- header:
65
- desc: Slot para o título.
68
+ actions:
69
+ desc: Slot para ações (botões por exemplo).
66
70
 
67
71
  description:
68
72
  desc: Slot para descrição.
69
73
 
70
- actions:
71
- desc: Slot para ações (botões por exemplo).
74
+ header:
75
+ desc: Slot para o título.
72
76
 
73
77
  events:
74
78
  '@update:model-value -> function (value)':
@@ -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,19 +4,19 @@
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">
19
- <q-menu>
18
+ <qas-btn v-if="useFilterButton" :color="filterButtonColor" flat icon="o_filter_list" :label="filterButtonLabel">
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" />
22
22
  </div>
@@ -31,17 +31,17 @@
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
 
43
43
  <div v-if="useChip && hasActiveFilters" class="q-mt-md">
44
- <q-chip v-for="(filterItem, key) in activeFilters" :key="key" color="grey-4" dense removable size="md" text-color="grey-8" @remove="removeFilter(filterItem)">{{ filterItem.label }} = "{{ getChipValue(filterItem.value) }}"</q-chip>
44
+ <q-chip v-for="(filterItem, key) in activeFilters" :key="key" color="primary" dense removable size="md" text-color="white" @remove="removeFilter(filterItem)">{{ filterItem.label }} = "{{ getChipValue(filterItem.value) }}"</q-chip>
45
45
  </div>
46
46
 
47
47
  <slot :context="mx_context" :filter="filter" :filters="activeFilters" :remove-filter="removeFilter" />
@@ -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
  },
@@ -150,7 +152,7 @@ export default {
150
152
  },
151
153
 
152
154
  filterButtonColor () {
153
- return this.hasActiveFilters ? 'primary' : 'grey-8'
155
+ return this.hasActiveFilters ? 'primary' : 'grey-9'
154
156
  },
155
157
 
156
158
  filterButtonLabel () {
@@ -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,6 +9,15 @@ props:
9
9
  required: true
10
10
  type: String
11
11
 
12
+ search-placeholder:
13
+ desc: Placeholder do campo de busca.
14
+ default: Pesquisar...
15
+ type: String
16
+
17
+ url:
18
+ desc: Envia como parâmetro para a action "fetchFilters" do modulo correspondente a "entity".
19
+ type: String
20
+
12
21
  use-badges:
13
22
  desc: Habilita ou não os "chips" mostrando os filtros ativos.
14
23
  default: true
@@ -19,9 +28,8 @@ props:
19
28
  default: true
20
29
  type: Boolean
21
30
 
22
- use-search:
23
- desc: Habilita ou não o campo text de busca.
24
- default: true
31
+ use-force-refetch:
32
+ desc: Força refazer o "fetch" mesmo caso já exista dados na store de filters.
25
33
  type: Boolean
26
34
 
27
35
  use-search-on-type:
@@ -29,17 +37,9 @@ props:
29
37
  default: true
30
38
  type: Boolean
31
39
 
32
- search-placeholder:
33
- desc: Placeholder do campo de busca.
34
- default: Pesquisar...
35
- type: String
36
-
37
- url:
38
- desc: Envia como parâmetro para a action "fetchFilters" do modulo correspondente a "entity".
39
- type: String
40
-
41
- force-refetch:
42
- desc: Força refazer o "fetch" mesmo caso já exista dados na store de filters.
40
+ use-search:
41
+ desc: Habilita ou não o campo text de busca.
42
+ default: true
43
43
  type: Boolean
44
44
 
45
45
  slots:
@@ -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