See #228: generic action table component
This commit is contained in:
parent
c6b5c71d26
commit
fc88f72a71
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<table class="ui compact very basic single line unstackable table">
|
||||||
|
<thead>
|
||||||
|
<tr v-if="actions.length > 0 && objectsData.count > 0">
|
||||||
|
<th colspan="1000">
|
||||||
|
<div class="ui small form">
|
||||||
|
<div class="ui inline fields">
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ $t('Actions') }}</label>
|
||||||
|
<select class="ui dropdown" v-model="currentAction">
|
||||||
|
<option v-for="action in actions" :value="action[0]">
|
||||||
|
{{ action[1] }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div
|
||||||
|
@click="launchAction"
|
||||||
|
:disabled="checked.length === 0"
|
||||||
|
:class="['ui', {disabled: checked.length === 0}, {'loading': actionLoading}, 'button']">
|
||||||
|
{{ $t('Go') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="count field">
|
||||||
|
<span v-if="selectAll">{{ $t('{% count %} on {% total %} selected', {count: objectsData.count, total: objectsData.count}) }}</span>
|
||||||
|
<span v-else>{{ $t('{% count %} on {% total %} selected', {count: checked.length, total: objectsData.count}) }}</span>
|
||||||
|
<template v-if="checked.length === objectsData.results.length">
|
||||||
|
<a @click="selectAll = true" v-if="!selectAll">
|
||||||
|
{{ $t('Select all {% total %} elements', {total: objectsData.count}) }}
|
||||||
|
</a>
|
||||||
|
<a @click="selectAll = false" v-else>
|
||||||
|
{{ $t('Select only current page') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="actionErrors.length > 0" class="ui negative message">
|
||||||
|
<div class="header">{{ $t('Error while applying action') }}</div>
|
||||||
|
<ul class="list">
|
||||||
|
<li v-for="error in actionErrors">{{ error }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-if="actionResult" class="ui positive message">
|
||||||
|
<p>{{ $t('Action {% action %} was launched successfully on {% count %} objects.', {action: actionResult.action, count: actionResult.updated}) }}</p>
|
||||||
|
<slot name="action-success-footer" :result="actionResult">
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
@change="toggleCheckAll"
|
||||||
|
:checked="objectsData.results.length === checked.length"><label> </label>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<slot name="header-cells"></slot>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="obj in objectsData.results">
|
||||||
|
<td class="collapsing">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
@change="toggleCheck(obj.id)"
|
||||||
|
:checked="checked.indexOf(obj.id) > -1"><label> </label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<slot name="row-cells" :obj="obj"></slot>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
actionUrl: {type: String, required: true},
|
||||||
|
objectsData: {type: Object, required: true},
|
||||||
|
actions: {type: Array, required: true, default: () => { return [] }},
|
||||||
|
filters: {type: Object, required: false, default: () => { return {} }}
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
data () {
|
||||||
|
let d = {
|
||||||
|
checked: [],
|
||||||
|
actionLoading: false,
|
||||||
|
actionResult: null,
|
||||||
|
actionErrors: [],
|
||||||
|
currentAction: null,
|
||||||
|
selectAll: false
|
||||||
|
}
|
||||||
|
if (this.actions.length > 0) {
|
||||||
|
d.currentAction = this.actions[0][0]
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleCheckAll () {
|
||||||
|
if (this.checked.length === this.objectsData.results.length) {
|
||||||
|
// we uncheck
|
||||||
|
this.checked = []
|
||||||
|
} else {
|
||||||
|
this.checked = this.objectsData.results.map(t => { return t.id })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleCheck (id) {
|
||||||
|
if (this.checked.indexOf(id) > -1) {
|
||||||
|
// we uncheck
|
||||||
|
this.selectAll = false
|
||||||
|
this.checked.splice(this.checked.indexOf(id), 1)
|
||||||
|
} else {
|
||||||
|
this.checked.push(id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
launchAction () {
|
||||||
|
let self = this
|
||||||
|
self.actionLoading = true
|
||||||
|
self.result = null
|
||||||
|
let payload = {
|
||||||
|
action: this.currentAction,
|
||||||
|
filters: this.filters
|
||||||
|
}
|
||||||
|
if (this.selectAll) {
|
||||||
|
payload.objects = 'all'
|
||||||
|
} else {
|
||||||
|
payload.objects = this.checked
|
||||||
|
}
|
||||||
|
axios.post(this.actionUrl, payload).then((response) => {
|
||||||
|
self.actionResult = response.data
|
||||||
|
self.actionLoading = false
|
||||||
|
}, error => {
|
||||||
|
self.actionLoading = false
|
||||||
|
self.actionErrors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.count.field {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.ui.form .inline.fields {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue