mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Add ViewBase component to deal with skeletons and initial views queries, update ViewSearch accordingly
This commit is contained in:
parent
694bdb6ea1
commit
0486865f56
2 changed files with 124 additions and 30 deletions
83
app/src/components/globals/ViewBase.vue
Normal file
83
app/src/components/globals/ViewBase.vue
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<top-bar v-if="hasTopBar">
|
||||||
|
<slot name="top-bar-group-left" slot="group-left" />
|
||||||
|
<slot name="top-bar-group-right" slot="group-right" />
|
||||||
|
</top-bar>
|
||||||
|
<slot v-else name="top-bar" />
|
||||||
|
|
||||||
|
<slot name="top" v-bind="{ loading: isLoading }" />
|
||||||
|
|
||||||
|
<b-skeleton-wrapper :loading="isLoading">
|
||||||
|
<template #loading>
|
||||||
|
<slot name="skeleton">
|
||||||
|
<component :is="skeleton" />
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Empty div to be able to receive multiple components -->
|
||||||
|
<div>
|
||||||
|
<slot name="default" v-bind="{ loading: isLoading }" />
|
||||||
|
</div>
|
||||||
|
</b-skeleton-wrapper>
|
||||||
|
|
||||||
|
<slot name="bot" v-bind="{ loading: isLoading }" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from '@/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ViewBase',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
queries: { type: Array, default: null },
|
||||||
|
skeleton: { type: [String, Array], default: null },
|
||||||
|
// Optional prop to take control of the loading value
|
||||||
|
loading: { type: Boolean, default: null }
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
fallback_loading: this.loading === null && this.fetch !== null ? true : null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isLoading () {
|
||||||
|
if (this.loading !== null) return this.loading
|
||||||
|
return this.fallback_loading
|
||||||
|
},
|
||||||
|
|
||||||
|
hasTopBar () {
|
||||||
|
return ['top-bar-group-left', 'top-bar-group-right'].some(slotName => (slotName in this.$slots))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetchQueries (triggerLoading = false) {
|
||||||
|
if (triggerLoading) {
|
||||||
|
this.fallback_loading = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const [apiQueries, storeQueries] = this.queries.reduce((types, query) => {
|
||||||
|
types[typeof query === 'string' ? 0 : 1].push(query)
|
||||||
|
return types
|
||||||
|
}, [[], []])
|
||||||
|
|
||||||
|
Promise.all([
|
||||||
|
api.getAll(apiQueries),
|
||||||
|
this.$store.dispatch('FETCH_ALL', storeQueries)
|
||||||
|
]).then(([apiResponses, storeResponses]) => {
|
||||||
|
this.$emit('queries-response', ...apiResponses, ...storeResponses)
|
||||||
|
this.fallback_loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
if (this.queries) this.fetchQueries()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<view-base v-bind="$attrs" v-on="$listeners" :skeleton="skeleton">
|
||||||
<view-top-bar>
|
<slot v-if="hasCustomTopBar" name="top-bar" slot="top-bar" />
|
||||||
<template #group-left>
|
<template v-if="!hasCustomTopBar" #top-bar-group-left>
|
||||||
<b-input-group id="search-group" class="w-100">
|
<b-input-group class="w-100">
|
||||||
<b-input-group-prepend is-text>
|
<b-input-group-prepend is-text>
|
||||||
<icon iname="search" />
|
<icon iname="search" />
|
||||||
</b-input-group-prepend>
|
</b-input-group-prepend>
|
||||||
|
@ -15,11 +15,12 @@
|
||||||
/>
|
/>
|
||||||
</b-input-group>
|
</b-input-group>
|
||||||
</template>
|
</template>
|
||||||
|
<slot v-if="!hasCustomTopBar" name="top-bar-buttons" slot="top-bar-group-right" />
|
||||||
|
|
||||||
<slot name="top-bar-buttons" slot="group-right" />
|
<slot name="top" slot="top" />
|
||||||
</view-top-bar>
|
|
||||||
|
|
||||||
<b-alert v-if="items === null || filteredItems === null" variant="warning" show>
|
<template #default>
|
||||||
|
<b-alert v-if="items === null || filteredItems === null" variant="warning">
|
||||||
<slot name="alert-message">
|
<slot name="alert-message">
|
||||||
<icon iname="exclamation-triangle" />
|
<icon iname="exclamation-triangle" />
|
||||||
{{ $t(items === null ? 'items_verbose_count' : 'search.not_found', { items: $tc('items.' + itemsName, 0) }) }}
|
{{ $t(items === null ? 'items_verbose_count' : 'search.not_found', { items: $tc('items.' + itemsName, 0) }) }}
|
||||||
|
@ -27,20 +28,30 @@
|
||||||
</b-alert>
|
</b-alert>
|
||||||
|
|
||||||
<slot v-else name="default" />
|
<slot v-else name="default" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<slot name="extra"/>
|
<slot name="bot" slot="bot" />
|
||||||
</div>
|
|
||||||
|
<slot name="skeleton" slot="skeleton" />
|
||||||
|
</view-base>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'SearchView',
|
name: 'ViewSearch',
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
search: { type: String, required: true },
|
|
||||||
itemsName: { type: String, required: true },
|
|
||||||
items: { type: null, required: true },
|
items: { type: null, required: true },
|
||||||
filteredItems: { type: null, required: true }
|
itemsName: { type: String, required: true },
|
||||||
|
filteredItems: { type: null, required: true },
|
||||||
|
search: { type: String, default: null },
|
||||||
|
skeleton: { type: String, default: 'list-group-skeleton' }
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
hasCustomTopBar () {
|
||||||
|
return 'top-bar' in this.$slots
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue