@bildvitta/quasar-ui-asteroid 3.16.0-beta.3 → 3.16.0-beta.5
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 +2 -1
- package/src/components/expansion-item/QasExpansionItem.vue +53 -7
- package/src/components/expansion-item/QasExpansionItem.yml +3 -0
- package/src/components/single-view/QasSingleView.vue +123 -80
- package/src/components/single-view/QasSingleView.yml +5 -0
- package/src/components/toggle-visibility/QasToggleVisibility.vue +79 -0
- package/src/components/toggle-visibility/QasToggleVisibility.yml +30 -0
- package/src/composables/private/index.js +3 -0
- package/src/composables/private/use-toggle-visibility.js +48 -0
- package/src/composables/private/use-view.js +180 -0
- package/src/vue-plugin.js +6 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bildvitta/quasar-ui-asteroid",
|
|
3
3
|
"description": "Asteroid",
|
|
4
|
-
"version": "3.16.0-beta.
|
|
4
|
+
"version": "3.16.0-beta.5",
|
|
5
5
|
"author": "Bild & Vitta <systemteam@bild.com.br>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/asteroid.cjs.min.js",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"sass": "^1.62.1"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
+
"@bildvitta/composables": "^1.0.0-beta.7",
|
|
46
47
|
"@bildvitta/store-adapter": "^1.0.0",
|
|
47
48
|
"autonumeric": "^4.9.0",
|
|
48
49
|
"axios": "^1.4.0",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="qas-expansion-item" :class="errorClasses">
|
|
3
|
-
<
|
|
2
|
+
<div ref="expansionItem" class="qas-expansion-item" :class="errorClasses">
|
|
3
|
+
<component :is="component.is" class="qas-expansion-item__box">
|
|
4
4
|
<q-expansion-item header-class="text-bold q-mt-sm q-pa-none" :label="props.label">
|
|
5
5
|
<template #header>
|
|
6
6
|
<slot name="header">
|
|
7
7
|
<div class="full-width">
|
|
8
8
|
<div class="items-center q-col-gutter-sm row">
|
|
9
9
|
<slot name="label">
|
|
10
|
-
<h5 class="col-auto text-h5
|
|
10
|
+
<h5 class="col-auto text-h5">
|
|
11
11
|
{{ props.label }}
|
|
12
12
|
</h5>
|
|
13
13
|
</slot>
|
|
@@ -18,17 +18,23 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
|
+
|
|
22
|
+
<div v-if="hasHeaderBottom" class="q-mt-sm">
|
|
23
|
+
<slot name="header-bottom" />
|
|
24
|
+
</div>
|
|
21
25
|
</div>
|
|
22
26
|
</slot>
|
|
23
27
|
</template>
|
|
24
28
|
|
|
25
|
-
<q-separator class="q-my-md" />
|
|
29
|
+
<q-separator v-if="!isNestedExpansionItem" class="q-my-md" />
|
|
26
30
|
|
|
27
31
|
<slot name="content">
|
|
28
32
|
<qas-grid-generator v-if="hasGridGenerator" v-bind="gridGeneratorProps" use-inline />
|
|
29
33
|
</slot>
|
|
34
|
+
|
|
35
|
+
<q-separator v-if="hasBottomSeparator" class="q-mt-md" />
|
|
30
36
|
</q-expansion-item>
|
|
31
|
-
</
|
|
37
|
+
</component>
|
|
32
38
|
|
|
33
39
|
<div v-if="hasError" class="q-pt-sm qas-expansion-item__error-message text-caption text-negative">
|
|
34
40
|
{{ props.errorMessage }}
|
|
@@ -37,7 +43,9 @@
|
|
|
37
43
|
</template>
|
|
38
44
|
|
|
39
45
|
<script setup>
|
|
40
|
-
import
|
|
46
|
+
import QasBox from '../box/QasBox.vue'
|
|
47
|
+
|
|
48
|
+
import { computed, provide, inject, onMounted, ref } from 'vue'
|
|
41
49
|
|
|
42
50
|
defineOptions({ name: 'QasExpansionItem' })
|
|
43
51
|
|
|
@@ -67,17 +75,55 @@ const props = defineProps({
|
|
|
67
75
|
}
|
|
68
76
|
})
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
provide('isExpansionItem', true)
|
|
79
|
+
|
|
80
|
+
// slots
|
|
81
|
+
const slots = defineSlots()
|
|
82
|
+
|
|
83
|
+
// refs
|
|
84
|
+
const expansionItem = ref(null)
|
|
85
|
+
const hasNextSibling = ref(false)
|
|
86
|
+
|
|
87
|
+
onMounted(setHasNextSibling)
|
|
88
|
+
|
|
89
|
+
// constants
|
|
90
|
+
const isNestedExpansionItem = inject('isExpansionItem', false)
|
|
91
|
+
const component = {
|
|
92
|
+
is: isNestedExpansionItem ? 'div' : QasBox
|
|
93
|
+
}
|
|
71
94
|
|
|
95
|
+
// computed
|
|
96
|
+
const hasError = computed(() => props.error || !!props.errorMessage)
|
|
72
97
|
const errorClasses = computed(() => ({ 'qas-expansion-item--error': hasError.value }))
|
|
73
98
|
|
|
74
99
|
const hasGridGenerator = computed(() => !!Object.keys(props.gridGeneratorProps).length)
|
|
100
|
+
const hasBottomSeparator = computed(() => isNestedExpansionItem && hasNextSibling.value)
|
|
101
|
+
const hasHeaderBottom = computed(() => !!slots['header-bottom'])
|
|
102
|
+
|
|
103
|
+
// functions
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Caso o componente esteja dentro de um QasExpansionItem, verifica se existe um próximo irmão
|
|
107
|
+
* para adicionar um separador.
|
|
108
|
+
*/
|
|
109
|
+
function setHasNextSibling (value) {
|
|
110
|
+
if (!isNestedExpansionItem) return
|
|
111
|
+
|
|
112
|
+
const hasTextContentSibling = !!expansionItem.value.nextSibling.textContent?.trim?.()
|
|
113
|
+
const hasElementSibling = !!expansionItem.value.nextElementSibling
|
|
114
|
+
|
|
115
|
+
hasNextSibling.value = hasElementSibling || hasTextContentSibling
|
|
116
|
+
}
|
|
75
117
|
</script>
|
|
76
118
|
|
|
77
119
|
<style lang="scss">
|
|
78
120
|
.qas-expansion-item {
|
|
79
121
|
$root: &;
|
|
80
122
|
|
|
123
|
+
& + & {
|
|
124
|
+
margin-top: var(--qas-spacing-lg);
|
|
125
|
+
}
|
|
126
|
+
|
|
81
127
|
&--error {
|
|
82
128
|
#{$root}__box {
|
|
83
129
|
border: 2px solid $negative;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="
|
|
3
|
-
<header v-if="
|
|
2
|
+
<div :class="componentClass">
|
|
3
|
+
<header v-if="hasHeaderSlot">
|
|
4
4
|
<slot name="header" />
|
|
5
5
|
</header>
|
|
6
6
|
|
|
@@ -8,117 +8,160 @@
|
|
|
8
8
|
<slot />
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
|
-
<qas-empty-result-text v-else-if="!
|
|
11
|
+
<qas-empty-result-text v-else-if="!viewState.fetching" class="q-my-xl" />
|
|
12
12
|
|
|
13
|
-
<footer v-if="
|
|
13
|
+
<footer v-if="hasFooterSlot">
|
|
14
14
|
<slot name="footer" />
|
|
15
15
|
</footer>
|
|
16
16
|
|
|
17
|
-
<q-inner-loading :showing="
|
|
17
|
+
<q-inner-loading :showing="viewState.fetching">
|
|
18
18
|
<q-spinner color="grey" size="3em" />
|
|
19
19
|
</q-inner-loading>
|
|
20
20
|
</div>
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
|
-
<script>
|
|
24
|
-
import
|
|
23
|
+
<script setup>
|
|
24
|
+
import useView, { baseProps, baseEmits } from '../../composables/private/use-view'
|
|
25
25
|
|
|
26
|
-
import { markRaw } from 'vue'
|
|
27
|
-
import { getGetter, getAction } from '@bildvitta/store-adapter'
|
|
28
26
|
import debug from 'debug'
|
|
27
|
+
import { decamelize } from 'humps'
|
|
28
|
+
import { markRaw, computed, watch, inject } from 'vue'
|
|
29
|
+
import { useRoute } from 'vue-router'
|
|
29
30
|
|
|
30
31
|
const log = debug('asteroid-ui:qas-single-view')
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
name: 'QasSingleView',
|
|
33
|
+
defineOptions({ name: 'QasSingleView' })
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const props = defineProps({
|
|
36
|
+
...baseProps,
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
type: [Number, String]
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
result: {
|
|
44
|
-
default: () => ({}),
|
|
45
|
-
type: Object
|
|
46
|
-
}
|
|
38
|
+
customId: {
|
|
39
|
+
default: '',
|
|
40
|
+
type: [Number, String]
|
|
47
41
|
},
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
result: {
|
|
44
|
+
default: () => ({}),
|
|
45
|
+
type: Object
|
|
46
|
+
}
|
|
47
|
+
})
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return !!this.resultModel
|
|
58
|
-
},
|
|
49
|
+
const emit = defineEmits([
|
|
50
|
+
...baseEmits,
|
|
59
51
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
52
|
+
'update:result',
|
|
53
|
+
'fetch-success',
|
|
54
|
+
'fetch-error'
|
|
55
|
+
])
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
return getGetter.call(this, { entity: this.entity, key: 'byId' })(this.id) || {}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
57
|
+
const slots = defineSlots()
|
|
68
58
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.mx_fetchHandler({ id: this.id, url: this.url }, this.fetchSingle)
|
|
73
|
-
}
|
|
74
|
-
},
|
|
59
|
+
// globals
|
|
60
|
+
const axios = inject('axios')
|
|
61
|
+
const qas = inject('qas')
|
|
75
62
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
},
|
|
63
|
+
// composables
|
|
64
|
+
const route = useRoute()
|
|
80
65
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
const {
|
|
67
|
+
// state
|
|
68
|
+
viewState,
|
|
69
|
+
|
|
70
|
+
// computed
|
|
71
|
+
componentClass,
|
|
72
|
+
hasHeaderSlot,
|
|
73
|
+
hasFooterSlot,
|
|
74
|
+
|
|
75
|
+
// functions
|
|
76
|
+
errorHandler,
|
|
77
|
+
fetchHandler,
|
|
78
|
+
setErrors,
|
|
79
|
+
setFields,
|
|
80
|
+
setMetadata,
|
|
81
|
+
setResult,
|
|
82
|
+
updateModels
|
|
83
|
+
} = useView({ emit, props, slots, mode: 'single' })
|
|
84
|
+
|
|
85
|
+
// computed
|
|
86
|
+
const id = computed(() => props.customId || route.params.id)
|
|
87
|
+
|
|
88
|
+
const resultModel = computed(() => {
|
|
89
|
+
if (props.useStore) return qas.getGetter({ entity: props.entity, key: 'byId' })(id.value) || {}
|
|
90
|
+
|
|
91
|
+
return viewState.value.result || {}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const hasResult = computed(() => !!resultModel.value)
|
|
95
|
+
|
|
96
|
+
// watch
|
|
97
|
+
watch(() => route, (to, from) => {
|
|
98
|
+
if (to.name === from.name) {
|
|
99
|
+
fetchHandler({ id: id.value, url: props.url }, fetchSingle)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
watch(() => resultModel.value, value => emit('update:result', markRaw({ ...value })))
|
|
104
|
+
|
|
105
|
+
// created
|
|
106
|
+
fetchHandler({ id: id.value, url: props.url }, fetchSingle)
|
|
107
|
+
|
|
108
|
+
// functions
|
|
109
|
+
async function fetchSingle (externalPayload = {}) {
|
|
110
|
+
viewState.value.fetching = true
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const payload = { id: id.value, url: props.url, ...externalPayload }
|
|
114
|
+
|
|
115
|
+
const response = await getAction(payload)
|
|
84
116
|
|
|
85
|
-
|
|
86
|
-
async fetchSingle (externalPayload = {}) {
|
|
87
|
-
this.mx_isFetching = true
|
|
117
|
+
const { errors, fields, metadata, result } = response.data
|
|
88
118
|
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
setErrors(errors)
|
|
120
|
+
setFields(fields)
|
|
121
|
+
setMetadata(metadata)
|
|
91
122
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
123
|
+
/**
|
|
124
|
+
* result só precisa ser adicionado ao estado se não estiver usando store,
|
|
125
|
+
* pois com a store é usado o getter.
|
|
126
|
+
*/
|
|
127
|
+
!props.useStore && setResult(result)
|
|
97
128
|
|
|
98
|
-
|
|
129
|
+
updateModels({
|
|
130
|
+
errors: viewState.value.errors,
|
|
131
|
+
fields: viewState.value.fields,
|
|
132
|
+
metadata: viewState.value.metadata,
|
|
99
133
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.mx_setMetadata(metadata)
|
|
134
|
+
...(!props.useStore && { result: viewState.value.result })
|
|
135
|
+
})
|
|
103
136
|
|
|
104
|
-
|
|
105
|
-
errors: this.mx_errors,
|
|
106
|
-
fields: this.mx_fields,
|
|
107
|
-
metadata: this.mx_metadata
|
|
108
|
-
})
|
|
137
|
+
emit('fetch-success', response)
|
|
109
138
|
|
|
110
|
-
|
|
139
|
+
log(`[${props.entity}]:fetchSingle:success`, response)
|
|
140
|
+
} catch (error) {
|
|
141
|
+
errorHandler(error)
|
|
142
|
+
emit('fetch-error', error)
|
|
111
143
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
144
|
+
log(`[${props.entity}]:fetchSingle:error`, error)
|
|
145
|
+
} finally {
|
|
146
|
+
viewState.value.fetching = false
|
|
147
|
+
}
|
|
148
|
+
}
|
|
116
149
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
150
|
+
function getAction (payload) {
|
|
151
|
+
if (props.useStore) {
|
|
152
|
+
return qas.getAction({
|
|
153
|
+
entity: props.entity,
|
|
154
|
+
key: 'fetchSingle',
|
|
155
|
+
payload
|
|
156
|
+
})
|
|
122
157
|
}
|
|
158
|
+
|
|
159
|
+
const { id: unusedID, url: unusedURL, ...externalPayload } = payload
|
|
160
|
+
|
|
161
|
+
const decamelizedEntity = decamelize(props.entity, { separator: '-' })
|
|
162
|
+
|
|
163
|
+
const url = props.url || `${decamelizedEntity}/${id.value}`
|
|
164
|
+
|
|
165
|
+
return axios.get(url, { ...externalPayload })
|
|
123
166
|
}
|
|
124
167
|
</script>
|
|
@@ -62,6 +62,11 @@ props:
|
|
|
62
62
|
default: true
|
|
63
63
|
type: Boolean
|
|
64
64
|
|
|
65
|
+
use-route:
|
|
66
|
+
desc: Controla se o componente usará internamente uma store do vuex/pinia ou se vai ser utilizado o axios diretamente.
|
|
67
|
+
default: true
|
|
68
|
+
type: Boolean
|
|
69
|
+
|
|
65
70
|
slots:
|
|
66
71
|
default:
|
|
67
72
|
desc: 'Slot para ter o conteúdo principal (dentro do main).'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="qas-toggle-visibility">
|
|
3
|
+
<div class="items-center no-wrap row" :style>
|
|
4
|
+
<div class="ellipsis qas-toggle-visibility__content">
|
|
5
|
+
<div
|
|
6
|
+
v-if="isVisible"
|
|
7
|
+
class="ellipsis full-width"
|
|
8
|
+
:title="props.text"
|
|
9
|
+
>
|
|
10
|
+
<slot>
|
|
11
|
+
{{ props.text }}
|
|
12
|
+
</slot>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<q-separator
|
|
16
|
+
v-else
|
|
17
|
+
size="4px"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<qas-btn
|
|
22
|
+
class="q-ml-sm qas-toggle-visibility__button"
|
|
23
|
+
:icon
|
|
24
|
+
@click="toggleVisibility"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup>
|
|
31
|
+
import { useToggleVisibility } from '../../composables/private'
|
|
32
|
+
|
|
33
|
+
import { uid } from 'quasar'
|
|
34
|
+
import { computed } from 'vue'
|
|
35
|
+
|
|
36
|
+
defineOptions({ name: 'QasToggleVisibility' })
|
|
37
|
+
|
|
38
|
+
const props = defineProps({
|
|
39
|
+
group: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: ''
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
text: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: ''
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
uuid: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: ''
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
width: {
|
|
55
|
+
type: String,
|
|
56
|
+
default: '140px'
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const {
|
|
61
|
+
isVisible,
|
|
62
|
+
toggleVisibility
|
|
63
|
+
} = useToggleVisibility({ group: props.group, uuid: props.uuid || uid() })
|
|
64
|
+
|
|
65
|
+
const icon = computed(() => isVisible.value ? 'sym_r_visibility' : 'sym_r_visibility_off')
|
|
66
|
+
const style = computed(() => ({ width: props.width }))
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<style lang="scss">
|
|
70
|
+
.qas-toggle-visibility {
|
|
71
|
+
&__content {
|
|
72
|
+
flex-grow: 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&__button {
|
|
76
|
+
flex-grow: 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type: component
|
|
2
|
+
|
|
3
|
+
meta:
|
|
4
|
+
desc: Componente para ocultar e exibir conteúdo, utilizado para dados sensíveis.
|
|
5
|
+
|
|
6
|
+
props:
|
|
7
|
+
group:
|
|
8
|
+
desc: Propriedade para criar grupos de separação.
|
|
9
|
+
default: ''
|
|
10
|
+
type: String
|
|
11
|
+
examples: ["name", "document", "users"]
|
|
12
|
+
|
|
13
|
+
text:
|
|
14
|
+
desc: Texto a ser oculto/exibido.
|
|
15
|
+
default: ''
|
|
16
|
+
type: String
|
|
17
|
+
|
|
18
|
+
uuid:
|
|
19
|
+
desc: É criado um uuid random para cada componente, para que possa ser feito o controle interno, porém é possível sobrescrever por esta propriedade.
|
|
20
|
+
default: ''
|
|
21
|
+
type: String
|
|
22
|
+
|
|
23
|
+
width:
|
|
24
|
+
desc: Tamanho do conteúdo a ser oculto/exibido.
|
|
25
|
+
default: '140px'
|
|
26
|
+
type: String
|
|
27
|
+
|
|
28
|
+
slots:
|
|
29
|
+
default:
|
|
30
|
+
desc: Slot para inserir conteúdo a ser oculto/exibido.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ref, computed } from 'vue'
|
|
2
|
+
|
|
3
|
+
const visibleState = ref({})
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {{
|
|
7
|
+
* group?: string,
|
|
8
|
+
* uuid: string
|
|
9
|
+
* }}
|
|
10
|
+
*/
|
|
11
|
+
export default function useToggleVisibility ({ group, uuid }) {
|
|
12
|
+
group = group || 'default'
|
|
13
|
+
|
|
14
|
+
visibleState.value[group] = {
|
|
15
|
+
...visibleState.value[group],
|
|
16
|
+
[uuid]: false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isVisible = computed(() => visibleState.value[group]?.[uuid] || false)
|
|
20
|
+
|
|
21
|
+
function toggleVisibility () {
|
|
22
|
+
const item = visibleState.value[group]
|
|
23
|
+
const lastVisibleItemKey = Object.keys(item).find(key => !!item[key])
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* cenário onde esta visível e clicou no mesmo item
|
|
27
|
+
*/
|
|
28
|
+
if (visibleState.value[group][uuid]) {
|
|
29
|
+
visibleState.value[group][uuid] = false
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* cenário onde tem um item visível e clicou em outro item
|
|
35
|
+
*/
|
|
36
|
+
if (lastVisibleItemKey) {
|
|
37
|
+
visibleState.value[group][lastVisibleItemKey] = false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
visibleState.value[group][uuid] = true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
isVisible,
|
|
45
|
+
|
|
46
|
+
toggleVisibility
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { NotifyError } from '../../plugins'
|
|
2
|
+
import { camelizeFieldsName } from '../../helpers'
|
|
3
|
+
|
|
4
|
+
import { useView as useViewComposable } from '@bildvitta/composables'
|
|
5
|
+
import { ref, computed, watch, markRaw } from 'vue'
|
|
6
|
+
import { useRouter } from 'vue-router'
|
|
7
|
+
|
|
8
|
+
export const baseProps = {
|
|
9
|
+
beforeFetch: {
|
|
10
|
+
default: null,
|
|
11
|
+
type: Function
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
errors: {
|
|
15
|
+
default: () => ({}),
|
|
16
|
+
type: Object
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
entity: {
|
|
20
|
+
type: String,
|
|
21
|
+
required: ''
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
fetching: {
|
|
25
|
+
type: Boolean
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
fields: {
|
|
29
|
+
default: () => ({}),
|
|
30
|
+
type: Object
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
metadata: {
|
|
34
|
+
default: () => ({}),
|
|
35
|
+
type: Object
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
url: {
|
|
39
|
+
default: '',
|
|
40
|
+
type: String
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
useBoundary: {
|
|
44
|
+
default: true,
|
|
45
|
+
type: Boolean
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
useStore: {
|
|
49
|
+
default: true,
|
|
50
|
+
type: Boolean
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const baseEmits = [
|
|
55
|
+
'update:fields',
|
|
56
|
+
'update:errors',
|
|
57
|
+
'update:metadata',
|
|
58
|
+
'update:fetching'
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {{
|
|
63
|
+
* mode: import('@bildvitta/composables').ViewModeTypes,
|
|
64
|
+
* props: baseProps,
|
|
65
|
+
* emit: (baseEmits: string) => void,
|
|
66
|
+
* slots: import('vue').Slots
|
|
67
|
+
* }} config
|
|
68
|
+
*/
|
|
69
|
+
export default function useView (config) {
|
|
70
|
+
const {
|
|
71
|
+
emit,
|
|
72
|
+
mode,
|
|
73
|
+
slots,
|
|
74
|
+
props
|
|
75
|
+
} = config
|
|
76
|
+
|
|
77
|
+
// composables
|
|
78
|
+
const router = useRouter()
|
|
79
|
+
const { viewState } = useViewComposable({ mode })
|
|
80
|
+
|
|
81
|
+
// refs
|
|
82
|
+
const cancelBeforeFetch = ref(false)
|
|
83
|
+
|
|
84
|
+
// constants
|
|
85
|
+
const fetchErrorMessage = 'Ops… Não conseguimos acessar as informações. Por favor, tente novamente em alguns minutos.'
|
|
86
|
+
|
|
87
|
+
// computed
|
|
88
|
+
const componentClass = computed(() => props.useBoundary && 'container spaced')
|
|
89
|
+
const hasFooterSlot = computed(() => !!slots.footer)
|
|
90
|
+
const hasHeaderSlot = computed(() => !!slots.header)
|
|
91
|
+
|
|
92
|
+
// watch
|
|
93
|
+
watch(() => viewState.value.fetching, value => emit('update:fetching', value))
|
|
94
|
+
|
|
95
|
+
// functions
|
|
96
|
+
function errorHandler (error) {
|
|
97
|
+
const { response } = error
|
|
98
|
+
|
|
99
|
+
const status = response?.status
|
|
100
|
+
|
|
101
|
+
const redirect = status >= 500
|
|
102
|
+
? 'ServerError'
|
|
103
|
+
: ({ 403: 'Forbidden', 404: 'NotFound' })[status]
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* caso exista um desses status será redirecionado sem aparecer o "notify"
|
|
107
|
+
*/
|
|
108
|
+
if (redirect) {
|
|
109
|
+
router.replace({ name: redirect })
|
|
110
|
+
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
NotifyError(fetchErrorMessage)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setErrors (errors = {}) {
|
|
118
|
+
viewState.value.errors = markRaw(errors)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setFields (fields = {}) {
|
|
122
|
+
const camelizedFields = camelizeFieldsName(fields)
|
|
123
|
+
|
|
124
|
+
viewState.value.fields = markRaw(camelizedFields)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function setMetadata (metadata = {}) {
|
|
128
|
+
viewState.value.metadata = markRaw(metadata)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function setResult (result = {}) {
|
|
132
|
+
viewState.value.result = result
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function updateModels (models) {
|
|
136
|
+
for (const key in models) {
|
|
137
|
+
if (!models[key]) continue
|
|
138
|
+
|
|
139
|
+
emit(`update:${key}`, models[key])
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function fetchHandler (payload, resolve) {
|
|
144
|
+
const hasBeforeFetch = typeof props.beforeFetch === 'function'
|
|
145
|
+
|
|
146
|
+
if (hasBeforeFetch && !cancelBeforeFetch.value) {
|
|
147
|
+
return props.beforeFetch({
|
|
148
|
+
payload,
|
|
149
|
+
resolve: payload => resolve(payload),
|
|
150
|
+
done: () => {
|
|
151
|
+
cancelBeforeFetch.value = true
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
resolve()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
// state
|
|
161
|
+
viewState,
|
|
162
|
+
|
|
163
|
+
// constants
|
|
164
|
+
fetchErrorMessage,
|
|
165
|
+
|
|
166
|
+
// computed
|
|
167
|
+
componentClass,
|
|
168
|
+
hasFooterSlot,
|
|
169
|
+
hasHeaderSlot,
|
|
170
|
+
|
|
171
|
+
// functions
|
|
172
|
+
errorHandler,
|
|
173
|
+
fetchHandler,
|
|
174
|
+
setErrors,
|
|
175
|
+
setFields,
|
|
176
|
+
setResult,
|
|
177
|
+
setMetadata,
|
|
178
|
+
updateModels
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/vue-plugin.js
CHANGED
|
@@ -64,6 +64,7 @@ import QasTableGenerator from './components/table-generator/QasTableGenerator.vu
|
|
|
64
64
|
import QasTabsGenerator from './components/tabs-generator/QasTabsGenerator.vue'
|
|
65
65
|
import QasTextTruncate from './components/text-truncate/QasTextTruncate.vue'
|
|
66
66
|
import QasTimeline from './components/timeline/QasTimeline.vue'
|
|
67
|
+
import QasToggleVisibility from './components/toggle-visibility/QasToggleVisibility.vue'
|
|
67
68
|
import QasTransfer from './components/transfer/QasTransfer.vue'
|
|
68
69
|
import QasTreeGenerator from './components/tree-generator/QasTreeGenerator.vue'
|
|
69
70
|
import QasUploader from './components/uploader/QasUploader.vue'
|
|
@@ -72,7 +73,7 @@ import QasWhatsappLink from './components/whatsapp-link/QasWhatsappLink.vue'
|
|
|
72
73
|
|
|
73
74
|
import { Notify, Loading, Quasar, Dialog as QuasarDialog } from 'quasar'
|
|
74
75
|
|
|
75
|
-
import { getAction } from '@bildvitta/store-adapter'
|
|
76
|
+
import { getAction, getGetter } from '@bildvitta/store-adapter'
|
|
76
77
|
|
|
77
78
|
// Plugins
|
|
78
79
|
import {
|
|
@@ -157,6 +158,7 @@ async function install (app) {
|
|
|
157
158
|
app.component('QasTabsGenerator', QasTabsGenerator)
|
|
158
159
|
app.component('QasTextTruncate', QasTextTruncate)
|
|
159
160
|
app.component('QasTimeline', QasTimeline)
|
|
161
|
+
app.component('QasToggleVisibility', QasToggleVisibility)
|
|
160
162
|
app.component('QasTransfer', QasTransfer)
|
|
161
163
|
app.component('QasTreeGenerator', QasTreeGenerator)
|
|
162
164
|
app.component('QasUploader', QasUploader)
|
|
@@ -176,7 +178,8 @@ async function install (app) {
|
|
|
176
178
|
app.provide('qas', {
|
|
177
179
|
delete: params => Delete.call(app.config.globalProperties, params),
|
|
178
180
|
|
|
179
|
-
getAction: params => getAction.call(app.config.globalProperties, params)
|
|
181
|
+
getAction: params => getAction.call(app.config.globalProperties, params),
|
|
182
|
+
getGetter: params => getGetter.call(app.config.globalProperties, params)
|
|
180
183
|
})
|
|
181
184
|
|
|
182
185
|
app.directive(Test.name, Test)
|
|
@@ -251,6 +254,7 @@ export {
|
|
|
251
254
|
QasTabsGenerator,
|
|
252
255
|
QasTextTruncate,
|
|
253
256
|
QasTimeline,
|
|
257
|
+
QasToggleVisibility,
|
|
254
258
|
QasTransfer,
|
|
255
259
|
QasTreeGenerator,
|
|
256
260
|
QasUploader,
|