@bildvitta/quasar-ui-asteroid 3.20.0-beta.0 → 3.20.0-beta.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/src/components/actions-menu/QasActionsMenu.vue +11 -1
- package/src/components/actions-menu/QasActionsMenu.yml +5 -0
- package/src/components/btn-dropdown/QasBtnDropdown.vue +8 -2
- package/src/components/btn-dropdown/QasBtnDropdown.yml +4 -0
- package/src/components/filters/QasFilters.vue +69 -33
- package/src/components/filters/QasFilters.yml +5 -0
- package/src/components/filters/private/PvFiltersActions.vue +133 -0
- package/src/components/table-generator/QasTableGenerator.vue +44 -32
- package/src/components/table-generator/QasTableGenerator.yml +5 -0
- package/src/components/toggle-visibility/QasToggleVisibility.vue +14 -0
- package/src/components/toggle-visibility/QasToggleVisibility.yml +10 -0
- package/src/components/tooltip/QasTooltip.vue +5 -2
- package/src/css/components/button.scss +1 -1
- package/src/helpers/filters.js +2 -0
- package/src/components/filters/private/PvFiltersButton.vue +0 -101
package/package.json
CHANGED
|
@@ -86,6 +86,10 @@ const props = defineProps({
|
|
|
86
86
|
type: String
|
|
87
87
|
},
|
|
88
88
|
|
|
89
|
+
useDropdownAlways: {
|
|
90
|
+
type: Boolean
|
|
91
|
+
},
|
|
92
|
+
|
|
89
93
|
useLabel: {
|
|
90
94
|
default: true,
|
|
91
95
|
type: Boolean
|
|
@@ -209,7 +213,13 @@ const formattedList = computed(() => {
|
|
|
209
213
|
*/
|
|
210
214
|
const payload = { dropdownList: {}, buttonsList: {} }
|
|
211
215
|
|
|
212
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Se a prop "useDropdownAlways" for true, significa que sempre usaremos o dropdown,
|
|
218
|
+
* mesmo que tenha apenas 1 item na lista ou que não tenha splitName.
|
|
219
|
+
* Também se não tiver splitName e a tela for pequena (mobile/tablet) e não for
|
|
220
|
+
* single, usaremos o dropdown.
|
|
221
|
+
*/
|
|
222
|
+
if (props.useDropdownAlways || ((!hasSplitName.value || screen.isSmall) && !isSingle.value)) {
|
|
213
223
|
const { buttonsList } = useOptionsActions({ color: DEFAULT_COLOR, props })
|
|
214
224
|
|
|
215
225
|
payload.buttonsList = buttonsList.value
|
|
@@ -49,6 +49,11 @@ props:
|
|
|
49
49
|
type: String
|
|
50
50
|
examples: [visibility]
|
|
51
51
|
|
|
52
|
+
use-dropdown-always:
|
|
53
|
+
desc: Força o uso do dropdown mesmo caso tenha apenas 1 item na lista de ações.
|
|
54
|
+
default: false
|
|
55
|
+
type: Boolean
|
|
56
|
+
|
|
52
57
|
use-tooltip:
|
|
53
58
|
desc: Controla se vai ter o tooltip caso passe nas regras de exibição de tooltip
|
|
54
59
|
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
<div v-if="hasButtons" :class="classes.list">
|
|
4
4
|
<div v-for="(buttonProps, key, index) in props.buttonsPropsList" :key="key">
|
|
5
5
|
<div class="flex no-wrap">
|
|
6
|
-
<qas-btn :disable="props.disable"
|
|
7
|
-
<
|
|
6
|
+
<qas-btn v-bind="buttonProps" :data-btn-dropdown="key" :disable="props.disable" no-wrap variant="tertiary" @click="onClick">
|
|
7
|
+
<slot v-if="hasBtnContentSlot(key)" :name="`btn-content-${key}`" />
|
|
8
|
+
|
|
9
|
+
<q-menu v-else-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" :auto-close="props.useAutoClose" class="qas-menu" self="top right" @update:model-value="onUpdateMenuValue">
|
|
8
10
|
<div :class="classes.menuContent">
|
|
9
11
|
<slot />
|
|
10
12
|
</div>
|
|
@@ -142,6 +144,10 @@ function isLast (index) {
|
|
|
142
144
|
function hasSeparator (index) {
|
|
143
145
|
return props.useSplit || !isLast(index)
|
|
144
146
|
}
|
|
147
|
+
|
|
148
|
+
function hasBtnContentSlot (name) {
|
|
149
|
+
return !!slots[`btn-content-${name}`]
|
|
150
|
+
}
|
|
145
151
|
</script>
|
|
146
152
|
|
|
147
153
|
<style lang="scss">
|
|
@@ -44,9 +44,13 @@ props:
|
|
|
44
44
|
slots:
|
|
45
45
|
default:
|
|
46
46
|
desc: Slot para passar o conteúdo do dropdown (menu).
|
|
47
|
+
|
|
47
48
|
bottom-[buttons-props-list-key]:
|
|
48
49
|
desc: Slot unitário para acessar abaixo de cada botão (normalmente utilizado para tooltip).
|
|
49
50
|
|
|
51
|
+
btn-content-[buttons-props-list-key]:
|
|
52
|
+
desc: Slot para acessar o conteúdo dentro do botão, exemplo de uso QMenu.
|
|
53
|
+
|
|
50
54
|
events:
|
|
51
55
|
'@click -> function (event)':
|
|
52
56
|
desc: Caso não tenha "useSplit", o evento é disparado ao clicar no componente como um todo, caso tenha "useSplit", o evento é disparado ao clicar no botão a esquerda.
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<slot :filter="filter" name="search">
|
|
6
6
|
<q-form v-if="useSearch" @submit.prevent="filter()">
|
|
7
7
|
<qas-search-input v-model="internalSearch" :placeholder="searchPlaceholder" :use-search-on-type="useSearchOnType" @clear="clearSearch" @filter="filter()" @update:model-value="onSearch">
|
|
8
|
-
<template v-if="
|
|
8
|
+
<template v-if="showFilterActions" #after-clear>
|
|
9
9
|
<slot :context="mx_context" :filter="filter" :filters="activeFilters" name="filter-button" :remove-filter="removeFilter">
|
|
10
|
-
<pv-filters-
|
|
10
|
+
<pv-filters-actions ref="filtersActions" v-model:filtersButton="internalFilters" v-bind="filtersActionsProps" />
|
|
11
11
|
</slot>
|
|
12
12
|
</template>
|
|
13
13
|
</qas-search-input>
|
|
@@ -15,14 +15,20 @@
|
|
|
15
15
|
</slot>
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
<div v-else-if="
|
|
18
|
+
<div v-else-if="showFilterActions" class="col-12">
|
|
19
19
|
<slot :context="mx_context" :filter="filter" :filters="activeFilters" name="filter-button" :remove-filter="removeFilter">
|
|
20
|
-
<pv-filters-
|
|
20
|
+
<pv-filters-actions ref="filtersActions" v-model:filtersButton="internalFilters" v-bind="filtersActionsProps" />
|
|
21
21
|
</slot>
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
25
|
<div v-if="hasChip" class="q-mt-md">
|
|
26
|
+
<qas-badge v-if="hasOrderByChip" color="grey-4" removable text-color="black" @remove="changeOrderBy(undefined)">
|
|
27
|
+
<div class="ellipsis qas-filters__badge-content" :title="orderByLabel">
|
|
28
|
+
Ordenar por: "{{ orderByLabel }}"
|
|
29
|
+
</div>
|
|
30
|
+
</qas-badge>
|
|
31
|
+
|
|
26
32
|
<qas-badge v-for="(filterItem, key) in activeFilters" :key="key" :data-cy="`filters-${filterItem.value}-chip`" removable @remove="removeFilter(filterItem)">
|
|
27
33
|
<div class="ellipsis qas-filters__badge-content" :title="getChipValue(filterItem.value)">
|
|
28
34
|
{{ filterItem.label }}: "{{ getChipValue(filterItem.value) }}"
|
|
@@ -37,7 +43,7 @@
|
|
|
37
43
|
<script>
|
|
38
44
|
import QasBadge from '../badge/QasBadge.vue'
|
|
39
45
|
import QasSearchInput from '../search-input/QasSearchInput.vue'
|
|
40
|
-
import
|
|
46
|
+
import PvFiltersActions from './private/PvFiltersActions.vue'
|
|
41
47
|
|
|
42
48
|
import { useOverlayNavigation } from '../../composables'
|
|
43
49
|
|
|
@@ -54,9 +60,9 @@ export default {
|
|
|
54
60
|
name: 'QasFilters',
|
|
55
61
|
|
|
56
62
|
components: {
|
|
57
|
-
PvFiltersButton,
|
|
58
63
|
QasBadge,
|
|
59
|
-
QasSearchInput
|
|
64
|
+
QasSearchInput,
|
|
65
|
+
PvFiltersActions
|
|
60
66
|
},
|
|
61
67
|
|
|
62
68
|
mixins: [contextMixin],
|
|
@@ -72,11 +78,21 @@ export default {
|
|
|
72
78
|
type: Object
|
|
73
79
|
},
|
|
74
80
|
|
|
81
|
+
fieldsProps: {
|
|
82
|
+
default: () => ({}),
|
|
83
|
+
type: Object
|
|
84
|
+
},
|
|
85
|
+
|
|
75
86
|
listenerQueryKeys: {
|
|
76
87
|
type: Array,
|
|
77
88
|
default: () => []
|
|
78
89
|
},
|
|
79
90
|
|
|
91
|
+
orderByOptions: {
|
|
92
|
+
default: () => ([]),
|
|
93
|
+
type: Array
|
|
94
|
+
},
|
|
95
|
+
|
|
80
96
|
searchPlaceholder: {
|
|
81
97
|
default: 'Pesquisar...',
|
|
82
98
|
type: String
|
|
@@ -123,11 +139,6 @@ export default {
|
|
|
123
139
|
useUpdateRoute: {
|
|
124
140
|
default: true,
|
|
125
141
|
type: Boolean
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
fieldsProps: {
|
|
129
|
-
default: () => ({}),
|
|
130
|
-
type: Object
|
|
131
142
|
}
|
|
132
143
|
},
|
|
133
144
|
|
|
@@ -233,25 +244,30 @@ export default {
|
|
|
233
244
|
return this.hasActiveFilters ? 'primary' : 'grey-10'
|
|
234
245
|
},
|
|
235
246
|
|
|
236
|
-
|
|
247
|
+
filtersActionsProps () {
|
|
237
248
|
return {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
* Para solucionar esse problema, sempre ao fechar os filtros as opções não filtradas são removidas,
|
|
249
|
-
* voltando o filtro para o seu estado anterior.
|
|
250
|
-
*/
|
|
251
|
-
onHide: this.setInternalFilters
|
|
249
|
+
orderByOptions: this.orderByOptions,
|
|
250
|
+
useOrderBy: this.hasOrderByOptions,
|
|
251
|
+
useFilterButton: this.useFilterButton,
|
|
252
|
+
|
|
253
|
+
filtersButtonProps: {
|
|
254
|
+
color: this.filterButtonColor,
|
|
255
|
+
error: this.hasFetchError,
|
|
256
|
+
fields: this.fields,
|
|
257
|
+
fieldsProps: this.formattedFieldsProps,
|
|
258
|
+
loading: this.isFetching
|
|
252
259
|
},
|
|
253
260
|
|
|
254
|
-
|
|
261
|
+
/**
|
|
262
|
+
* O tratamento no onHide do menu é que como o menu é recriado toda vez que o filtro é aberto, ocorre que as
|
|
263
|
+
* opções selecionadas anteriormente (e que não foram filtradas) não ficam salvas na memória, ocasionando em
|
|
264
|
+
* campos lazy loading um problema de exibir o uuid da opção por não achar essa opção no array de options do field.
|
|
265
|
+
* Para solucionar esse problema, sempre ao fechar os filtros as opções não filtradas são removidas,
|
|
266
|
+
* voltando o filtro para o seu estado anterior.
|
|
267
|
+
*/
|
|
268
|
+
onHideFiltersMenu: this.setInternalFilters,
|
|
269
|
+
onClearFilters: this.clearFilters,
|
|
270
|
+
onChangeOrder: this.changeOrderBy,
|
|
255
271
|
onFilter: () => this.filter()
|
|
256
272
|
}
|
|
257
273
|
},
|
|
@@ -264,12 +280,12 @@ export default {
|
|
|
264
280
|
return !!Object.keys(this.fields || {}).length
|
|
265
281
|
},
|
|
266
282
|
|
|
267
|
-
|
|
268
|
-
return !!this.$slots.filterButton || this.useFilterButton
|
|
283
|
+
showFilterActions () {
|
|
284
|
+
return !!this.$slots.filterButton || this.useFilterButton || this.hasOrderByOptions
|
|
269
285
|
},
|
|
270
286
|
|
|
271
287
|
showFilters () {
|
|
272
|
-
return this.useFilterButton || this.showSearch
|
|
288
|
+
return this.useFilterButton || this.showSearch || this.hasOrderByOptions
|
|
273
289
|
},
|
|
274
290
|
|
|
275
291
|
showSearch () {
|
|
@@ -277,7 +293,23 @@ export default {
|
|
|
277
293
|
},
|
|
278
294
|
|
|
279
295
|
hasChip () {
|
|
280
|
-
return this.useChip && this.hasActiveFilters
|
|
296
|
+
return this.useChip && (this.hasActiveFilters || this.orderBy)
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
hasOrderByOptions () {
|
|
300
|
+
return !!this.orderByOptions.length
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
hasOrderByChip () {
|
|
304
|
+
return !!this.orderBy && this.hasOrderByOptions
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
orderBy () {
|
|
308
|
+
return this.$route.query.order_by
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
orderByLabel () {
|
|
312
|
+
return this.orderByOptions.find(option => option.value === this.orderBy)?.label
|
|
281
313
|
}
|
|
282
314
|
},
|
|
283
315
|
|
|
@@ -419,7 +451,7 @@ export default {
|
|
|
419
451
|
},
|
|
420
452
|
|
|
421
453
|
hideFiltersMenu () {
|
|
422
|
-
this.$refs.
|
|
454
|
+
this.$refs.filtersActions?.hideFiltersMenu()
|
|
423
455
|
},
|
|
424
456
|
|
|
425
457
|
setInternalFilters () {
|
|
@@ -492,6 +524,10 @@ export default {
|
|
|
492
524
|
for (const key in filters) {
|
|
493
525
|
this.internalFilters[key] = parseValue(this.normalizeValues(filters[key], this.fields[key]?.multiple))
|
|
494
526
|
}
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
changeOrderBy (value) {
|
|
530
|
+
this.filter({ order_by: value })
|
|
495
531
|
}
|
|
496
532
|
}
|
|
497
533
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<qas-btn-dropdown v-bind="btnDropdownProps">
|
|
3
|
+
<!-- Seção do botão de filtrar -->
|
|
4
|
+
<template v-if="props.useFilterButton" #btn-content-filtersButton>
|
|
5
|
+
<q-menu ref="filtersButtonMenu" anchor="center right" class="full-width" max-width="270px" no-refocus self="top right" @hide="emit('hide-filters-menu')">
|
|
6
|
+
<div v-if="props.filtersButtonProps.loading" class="q-pa-xl text-center">
|
|
7
|
+
<q-spinner color="grey" size="2em" />
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div v-else-if="props.filtersButtonProps.error" class="q-pa-xl text-center">
|
|
11
|
+
<q-icon color="negative" name="sym_r_warning" size="2em" />
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<q-form v-else class="q-gutter-y-md q-pa-md" @submit.prevent="emit('filter')">
|
|
15
|
+
<div v-for="(field, index) in props.filtersButtonProps.fields" :key="index">
|
|
16
|
+
<qas-field v-model="filtersButtonModel[field.name]" :data-cy="`filters-${field.name}-field`" :field="field" v-bind="props.filtersButtonProps.fieldsProps[field.name]" />
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<qas-actions gutter="sm" use-equal-width>
|
|
20
|
+
<template #primary>
|
|
21
|
+
<qas-btn class="full-width" data-cy="filters-submit-btn" label="Filtrar" size="sm" type="submit" variant="primary" />
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<template #secondary>
|
|
25
|
+
<qas-btn class="full-width" data-cy="filters-clear-btn" label="Limpar" size="sm" variant="secondary" @click="emit('clear-filters')" />
|
|
26
|
+
</template>
|
|
27
|
+
</qas-actions>
|
|
28
|
+
</q-form>
|
|
29
|
+
</q-menu>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<!-- Seção do botão de ordenar -->
|
|
33
|
+
<template v-if="props.useOrderBy" #btn-content-orderBy>
|
|
34
|
+
<q-menu anchor="bottom right" class="qas-menu" self="top right">
|
|
35
|
+
<q-list>
|
|
36
|
+
<q-item v-for="option in props.orderByOptions" :key="option.value" :active="isActive(option.value)" active-class="text-primary" clickable @click="emit('change-order', option.value)">
|
|
37
|
+
<q-item-section>
|
|
38
|
+
<q-item-label>
|
|
39
|
+
{{ option.label }}
|
|
40
|
+
</q-item-label>
|
|
41
|
+
</q-item-section>
|
|
42
|
+
</q-item>
|
|
43
|
+
</q-list>
|
|
44
|
+
</q-menu>
|
|
45
|
+
</template>
|
|
46
|
+
</qas-btn-dropdown>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup>
|
|
50
|
+
import QasActions from '../../actions/QasActions.vue'
|
|
51
|
+
import QasBtn from '../../btn/QasBtn.vue'
|
|
52
|
+
import QasBtnDropdown from '../../btn-dropdown/QasBtnDropdown.vue'
|
|
53
|
+
import QasField from '../../field/QasField.vue'
|
|
54
|
+
|
|
55
|
+
import { useRoute } from 'vue-router'
|
|
56
|
+
import { computed, ref } from 'vue'
|
|
57
|
+
|
|
58
|
+
defineOptions({ name: 'PvFiltersActions' })
|
|
59
|
+
|
|
60
|
+
const props = defineProps({
|
|
61
|
+
filtersButtonProps: {
|
|
62
|
+
default: () => ({}),
|
|
63
|
+
type: Object
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
orderByOptions: {
|
|
67
|
+
default: () => ([]),
|
|
68
|
+
type: Array
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
useFilterButton: {
|
|
72
|
+
type: Boolean
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
useOrderBy: {
|
|
76
|
+
type: Boolean
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// models
|
|
81
|
+
const filtersButtonModel = defineModel('filtersButton', { type: Object, default: () => ({}) })
|
|
82
|
+
|
|
83
|
+
// emits
|
|
84
|
+
const emit = defineEmits(['change-order', 'clear-filters', 'filter', 'hide-filters-menu'])
|
|
85
|
+
|
|
86
|
+
// expose
|
|
87
|
+
defineExpose({ hideFiltersMenu })
|
|
88
|
+
|
|
89
|
+
// template refs
|
|
90
|
+
const filtersButtonMenu = ref(null)
|
|
91
|
+
|
|
92
|
+
// composables
|
|
93
|
+
const route = useRoute()
|
|
94
|
+
|
|
95
|
+
// computeds
|
|
96
|
+
const btnDropdownProps = computed(() => {
|
|
97
|
+
return {
|
|
98
|
+
buttonsPropsList: {
|
|
99
|
+
...(props.useFilterButton && {
|
|
100
|
+
filtersButton: {
|
|
101
|
+
label: 'Filtrar',
|
|
102
|
+
useLabelOnSmallScreen: false,
|
|
103
|
+
icon: 'sym_r_filter_alt',
|
|
104
|
+
'data-cy': 'filters-btn' // manter compatibilidade
|
|
105
|
+
}
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
...(props.useOrderBy && {
|
|
109
|
+
orderBy: {
|
|
110
|
+
color: 'grey-10',
|
|
111
|
+
label: 'Ordenar',
|
|
112
|
+
useLabelOnSmallScreen: false,
|
|
113
|
+
icon: 'sym_r_swap_vert'
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// functions
|
|
121
|
+
/**
|
|
122
|
+
* Retorna se a opção de ordenação está ativa.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} value
|
|
125
|
+
*/
|
|
126
|
+
function isActive (value) {
|
|
127
|
+
return route.query.order_by === value
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function hideFiltersMenu () {
|
|
131
|
+
filtersButtonMenu.value?.hide()
|
|
132
|
+
}
|
|
133
|
+
</script>
|
|
@@ -36,6 +36,14 @@
|
|
|
36
36
|
</component>
|
|
37
37
|
</q-td>
|
|
38
38
|
</template>
|
|
39
|
+
|
|
40
|
+
<template v-for="(column, index) in columnsWithTooltip" :key="index" #[`header-cell-${column.name}`]="context">
|
|
41
|
+
<q-th :props="context">
|
|
42
|
+
{{ context.col.label }}
|
|
43
|
+
|
|
44
|
+
<qas-tip class="q-pl-xs" :text="column.tooltip" />
|
|
45
|
+
</q-th>
|
|
46
|
+
</template>
|
|
39
47
|
</q-table>
|
|
40
48
|
|
|
41
49
|
<qas-empty-result-text v-if="!hasResults" />
|
|
@@ -45,9 +53,10 @@
|
|
|
45
53
|
<script>
|
|
46
54
|
import PvTableGeneratorTd from './private/PvTableGeneratorTd.vue'
|
|
47
55
|
import QasBox from '../box/QasBox.vue'
|
|
56
|
+
import QasCheckbox from '../checkbox/QasCheckbox.vue'
|
|
48
57
|
import QasEmptyResultText from '../empty-result-text/QasEmptyResultText.vue'
|
|
49
58
|
import QasHeader from '../header/QasHeader.vue'
|
|
50
|
-
import
|
|
59
|
+
import QasTip from '../tip/QasTip.vue'
|
|
51
60
|
|
|
52
61
|
import { isEmpty, humanize, setScrollOnGrab, setScrollGradient } from '../../helpers'
|
|
53
62
|
|
|
@@ -61,7 +70,8 @@ export default {
|
|
|
61
70
|
QasBox,
|
|
62
71
|
QasEmptyResultText,
|
|
63
72
|
QasHeader,
|
|
64
|
-
QasCheckbox
|
|
73
|
+
QasCheckbox,
|
|
74
|
+
QasTip
|
|
65
75
|
},
|
|
66
76
|
|
|
67
77
|
provide () {
|
|
@@ -70,7 +80,7 @@ export default {
|
|
|
70
80
|
* @see QasBtn.vue - Injetando os valores padrões para o QasBtn.
|
|
71
81
|
*/
|
|
72
82
|
btnPropsDefaults: {
|
|
73
|
-
size: '
|
|
83
|
+
size: 'sm'
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
},
|
|
@@ -146,6 +156,10 @@ export default {
|
|
|
146
156
|
default: true
|
|
147
157
|
},
|
|
148
158
|
|
|
159
|
+
useMultiline: {
|
|
160
|
+
type: Boolean
|
|
161
|
+
},
|
|
162
|
+
|
|
149
163
|
useObjectSelectedModel: {
|
|
150
164
|
type: Boolean
|
|
151
165
|
},
|
|
@@ -287,7 +301,11 @@ export default {
|
|
|
287
301
|
* caso tenha a prop "actionsMenuProps" é adicionado automaticamente a coluna "actions" como ultimo item
|
|
288
302
|
*/
|
|
289
303
|
normalizedColumns () {
|
|
290
|
-
return this.hasActionsMenu ? [...this.columns, { name: 'actions' }] : this.columns
|
|
304
|
+
return this.hasActionsMenu ? [...this.columns, { name: 'actions', label: 'Ações' }] : this.columns
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
columnsWithTooltip () {
|
|
308
|
+
return this.normalizedColumns.filter(column => column.tooltip)
|
|
291
309
|
},
|
|
292
310
|
|
|
293
311
|
hasFields () {
|
|
@@ -301,6 +319,10 @@ export default {
|
|
|
301
319
|
|
|
302
320
|
const mappedResults = results.map((result, index) => {
|
|
303
321
|
for (const key in result) {
|
|
322
|
+
if (this.fields[key]?.type === 'object') {
|
|
323
|
+
continue
|
|
324
|
+
}
|
|
325
|
+
|
|
304
326
|
const humanizedResult = humanize(this.fields[key], result[key])
|
|
305
327
|
const formattedResult = isEmpty({ value: humanizedResult }) ? this.emptyResultText : humanizedResult
|
|
306
328
|
|
|
@@ -322,7 +344,8 @@ export default {
|
|
|
322
344
|
return {
|
|
323
345
|
'qas-table-generator--mobile': this.$qas.screen.isSmall,
|
|
324
346
|
'qas-table-generator--sticky-header': this.useStickyHeader,
|
|
325
|
-
'qas-table-generator--has-actions': this.hasActionsMenu
|
|
347
|
+
'qas-table-generator--has-actions': this.hasActionsMenu,
|
|
348
|
+
'qas-table-generator--multiline': this.useMultiline
|
|
326
349
|
}
|
|
327
350
|
},
|
|
328
351
|
|
|
@@ -539,7 +562,7 @@ export default {
|
|
|
539
562
|
}
|
|
540
563
|
|
|
541
564
|
th {
|
|
542
|
-
@include set-typography($
|
|
565
|
+
@include set-typography($subtitle2);
|
|
543
566
|
|
|
544
567
|
color: $grey-10;
|
|
545
568
|
|
|
@@ -554,18 +577,10 @@ export default {
|
|
|
554
577
|
}
|
|
555
578
|
}
|
|
556
579
|
|
|
557
|
-
|
|
558
|
-
padding-bottom: 0;
|
|
580
|
+
padding-bottom: var(--qas-spacing-sm);;
|
|
559
581
|
padding-left: 0;
|
|
560
582
|
padding-top: 0;
|
|
561
|
-
|
|
562
|
-
&:not(:last-child) {
|
|
563
|
-
padding-right: var(--qas-spacing-md);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
&:last-child {
|
|
567
|
-
padding-right: 0;
|
|
568
|
-
}
|
|
583
|
+
padding-right: var(--qas-spacing-md);
|
|
569
584
|
}
|
|
570
585
|
|
|
571
586
|
td,
|
|
@@ -576,7 +591,7 @@ export default {
|
|
|
576
591
|
}
|
|
577
592
|
|
|
578
593
|
td {
|
|
579
|
-
@include set-typography($
|
|
594
|
+
@include set-typography($body2);
|
|
580
595
|
|
|
581
596
|
height: 40px;
|
|
582
597
|
padding-bottom: var(--qas-spacing-sm);
|
|
@@ -584,14 +599,7 @@ export default {
|
|
|
584
599
|
padding-top: var(--qas-spacing-sm);
|
|
585
600
|
position: relative;
|
|
586
601
|
z-index: 0;
|
|
587
|
-
|
|
588
|
-
&:not(:last-child) {
|
|
589
|
-
padding-right: var(--qas-spacing-md);
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
&:last-child {
|
|
593
|
-
padding-right: 0;
|
|
594
|
-
}
|
|
602
|
+
padding-right: var(--qas-spacing-md);
|
|
595
603
|
|
|
596
604
|
&::before {
|
|
597
605
|
position: absolute;
|
|
@@ -648,18 +656,22 @@ export default {
|
|
|
648
656
|
}
|
|
649
657
|
}
|
|
650
658
|
|
|
659
|
+
&--multiline {
|
|
660
|
+
@media (min-width: $breakpoint-sm) {
|
|
661
|
+
.q-table td {
|
|
662
|
+
*:not(.qas-btn, .qas-btn *, .q-badge, .q-badge *){
|
|
663
|
+
white-space: normal;
|
|
664
|
+
overflow-wrap: anywhere;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
651
670
|
.q-table__container {
|
|
652
671
|
margin-left: calc(var(--qas-spacing-md) * -1);
|
|
653
672
|
margin-right: calc(var(--qas-spacing-md) * -1);
|
|
654
673
|
}
|
|
655
674
|
|
|
656
|
-
&--has-actions {
|
|
657
|
-
td:last-child #{$root}__td-item {
|
|
658
|
-
display: flex;
|
|
659
|
-
justify-content: flex-end;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
675
|
&--mobile {
|
|
664
676
|
margin: 0 -10px;
|
|
665
677
|
|
|
@@ -99,6 +99,11 @@ props:
|
|
|
99
99
|
default: true
|
|
100
100
|
type: Boolean
|
|
101
101
|
|
|
102
|
+
use-multiline:
|
|
103
|
+
desc: Usado para permitir que o conteúdo da célula quebre linha (não permite scroll na tabela a partir de tablet).
|
|
104
|
+
default: false
|
|
105
|
+
type: Boolean
|
|
106
|
+
|
|
102
107
|
use-object-selected-model:
|
|
103
108
|
desc: Usado para definir o modelo de seleção como um array de objeto ao invés de um array de string.
|
|
104
109
|
default: false
|
|
@@ -21,12 +21,15 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<qas-btn class="q-ml-sm qas-toggle-visibility__button" :icon />
|
|
24
|
+
|
|
25
|
+
<qas-tooltip :text="tooltipText" />
|
|
24
26
|
</div>
|
|
25
27
|
</div>
|
|
26
28
|
</template>
|
|
27
29
|
|
|
28
30
|
<script setup>
|
|
29
31
|
import QasBtn from '../btn/QasBtn.vue'
|
|
32
|
+
import QasTooltip from '../tooltip/QasTooltip.vue'
|
|
30
33
|
|
|
31
34
|
import { useToggleVisibility } from '../../composables/private'
|
|
32
35
|
|
|
@@ -54,6 +57,16 @@ const props = defineProps({
|
|
|
54
57
|
width: {
|
|
55
58
|
type: String,
|
|
56
59
|
default: '140px'
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
visibleTooltip: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: 'Ocultar conteúdo'
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
hiddenTooltip: {
|
|
68
|
+
type: String,
|
|
69
|
+
default: 'Visualizar conteúdo'
|
|
57
70
|
}
|
|
58
71
|
})
|
|
59
72
|
|
|
@@ -64,6 +77,7 @@ const {
|
|
|
64
77
|
|
|
65
78
|
const icon = computed(() => isVisible.value ? 'sym_r_visibility' : 'sym_r_visibility_off')
|
|
66
79
|
const style = computed(() => ({ width: props.width }))
|
|
80
|
+
const tooltipText = computed(() => isVisible.value ? props.visibleTooltip : props.hiddenTooltip)
|
|
67
81
|
</script>
|
|
68
82
|
|
|
69
83
|
<style lang="scss">
|
|
@@ -25,6 +25,16 @@ props:
|
|
|
25
25
|
default: '140px'
|
|
26
26
|
type: String
|
|
27
27
|
|
|
28
|
+
visible-tooltip:
|
|
29
|
+
desc: Texto do tooltip exibido quando o conteúdo está visível.
|
|
30
|
+
default: 'Ocultar conteúdo'
|
|
31
|
+
type: String
|
|
32
|
+
|
|
33
|
+
hidden-tooltip:
|
|
34
|
+
desc: Texto do tooltip exibido quando o conteúdo está oculto.
|
|
35
|
+
default: 'Exibir conteúdo'
|
|
36
|
+
type: String
|
|
37
|
+
|
|
28
38
|
slots:
|
|
29
39
|
default:
|
|
30
40
|
desc: Slot para inserir conteúdo a ser oculto/exibido.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<q-tooltip v-bind="tooltipProps" class="bg-grey-10 text-caption">
|
|
3
|
-
|
|
3
|
+
<qas-breakline :text="props.text" />
|
|
4
4
|
</q-tooltip>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup>
|
|
8
|
+
import QasBreakline from '../breakline/QasBreakline.vue'
|
|
9
|
+
|
|
8
10
|
defineOptions({ name: 'QasTooltip' })
|
|
9
11
|
|
|
10
12
|
const props = defineProps({
|
|
@@ -18,6 +20,7 @@ const props = defineProps({
|
|
|
18
20
|
const tooltipProps = {
|
|
19
21
|
anchor: 'center right',
|
|
20
22
|
self: 'center left',
|
|
21
|
-
offset: [5, 5]
|
|
23
|
+
offset: [5, 5],
|
|
24
|
+
maxWidth: '300px'
|
|
22
25
|
}
|
|
23
26
|
</script>
|
package/src/helpers/filters.js
CHANGED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<qas-btn data-cy="filters-btn" icon="sym_r_filter_alt" label="Filtrar" :use-label-on-small-screen="false" variant="tertiary">
|
|
3
|
-
<q-menu ref="menu" anchor="center right" class="full-width" max-width="270px" v-bind="menuProps" no-refocus self="top right">
|
|
4
|
-
<div v-if="loading" class="q-pa-xl text-center">
|
|
5
|
-
<q-spinner color="grey" size="2em" />
|
|
6
|
-
</div>
|
|
7
|
-
|
|
8
|
-
<div v-else-if="error" class="q-pa-xl text-center">
|
|
9
|
-
<q-icon color="negative" name="sym_r_warning" size="2em" />
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<q-form v-else class="q-gutter-y-md q-pa-md" @submit.prevent="$emit('filter')">
|
|
13
|
-
<div v-for="(field, index) in fields" :key="index">
|
|
14
|
-
<qas-field v-model="filters[field.name]" :data-cy="`filters-${field.name}-field`" :field="field" v-bind="fieldsProps[field.name]" />
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<qas-actions gutter="sm" use-equal-width>
|
|
18
|
-
<template #primary>
|
|
19
|
-
<qas-btn class="full-width" data-cy="filters-submit-btn" label="Filtrar" size="sm" type="submit" variant="primary" />
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<template #secondary>
|
|
23
|
-
<qas-btn class="full-width" data-cy="filters-clear-btn" label="Limpar" size="sm" variant="secondary" @click="$emit('clear')" />
|
|
24
|
-
</template>
|
|
25
|
-
</qas-actions>
|
|
26
|
-
</q-form>
|
|
27
|
-
</q-menu>
|
|
28
|
-
</qas-btn>
|
|
29
|
-
</template>
|
|
30
|
-
|
|
31
|
-
<script>
|
|
32
|
-
import QasActions from '../../actions/QasActions.vue'
|
|
33
|
-
import QasBtn from '../../btn/QasBtn.vue'
|
|
34
|
-
import QasField from '../../field/QasField.vue'
|
|
35
|
-
|
|
36
|
-
export default {
|
|
37
|
-
name: 'PvFiltersButton',
|
|
38
|
-
|
|
39
|
-
components: {
|
|
40
|
-
QasActions,
|
|
41
|
-
QasBtn,
|
|
42
|
-
QasField
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
props: {
|
|
46
|
-
color: {
|
|
47
|
-
type: String,
|
|
48
|
-
default: 'grey-10',
|
|
49
|
-
validator: value => ['grey-10', 'primary', 'white'].includes(value)
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
error: {
|
|
53
|
-
type: Boolean
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
fields: {
|
|
57
|
-
default: () => ({}),
|
|
58
|
-
type: Object
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
fieldsProps: {
|
|
62
|
-
default: () => ({}),
|
|
63
|
-
type: Object
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
loading: {
|
|
67
|
-
type: Boolean
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
menuProps: {
|
|
71
|
-
default: () => ({}),
|
|
72
|
-
type: Object
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
modelValue: {
|
|
76
|
-
default: () => ({}),
|
|
77
|
-
type: Object
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
emits: ['clear', 'filter', 'update:modelValue'],
|
|
82
|
-
|
|
83
|
-
computed: {
|
|
84
|
-
filters: {
|
|
85
|
-
get () {
|
|
86
|
-
return this.modelValue
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
set (value) {
|
|
90
|
-
return this.$emit('update:modelValue', value)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
methods: {
|
|
96
|
-
hideMenu () {
|
|
97
|
-
this.$refs.menu.hide()
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
</script>
|