Add "direct link" support for master grids

This commit is contained in:
Lance Edgar 2022-12-25 14:41:58 -06:00
parent cd466a64e5
commit 8264a69cec
4 changed files with 105 additions and 38 deletions

View file

@ -189,6 +189,7 @@ class Grid(object):
clicking_row_checks_box=False, click_handlers=None, clicking_row_checks_box=False, click_handlers=None,
main_actions=[], more_actions=[], delete_speedbump=False, main_actions=[], more_actions=[], delete_speedbump=False,
ajax_data_url=None, component='tailbone-grid', ajax_data_url=None, component='tailbone-grid',
expose_direct_link=False,
**kwargs): **kwargs):
self.key = key self.key = key
@ -256,11 +257,12 @@ class Grid(object):
if ajax_data_url: if ajax_data_url:
self.ajax_data_url = ajax_data_url self.ajax_data_url = ajax_data_url
elif self.request: elif self.request:
self.ajax_data_url = self.request.current_route_url() self.ajax_data_url = self.request.current_route_url(_query=None)
else: else:
self.ajax_data_url = '' self.ajax_data_url = ''
self.component = component self.component = component
self.expose_direct_link = expose_direct_link
self._whgrid_kwargs = kwargs self._whgrid_kwargs = kwargs
@property @property

View file

@ -289,26 +289,41 @@
</section> </section>
</template> </template>
% if grid.pageable: <template #footer>
<template slot="footer"> <div style="display: flex; justify-content: space-between;">
<b-field grouped position="is-right"
v-if="firstItem"> % if grid.expose_direct_link:
<span class="control"> <b-button type="is-primary"
showing {{ firstItem.toLocaleString('en') }} - {{ lastItem.toLocaleString('en') }} of {{ total.toLocaleString('en') }} results; size="is-small"
</span> @click="copyDirectLink()"
<b-select v-model="perPage" title="Copy link to clipboard">
size="is-small" <span><i class="fa fa-share-alt"></i></span>
@input="loadAsyncData()"> </b-button>
% for value in grid.get_pagesize_options(): % else:
<option value="${value}">${value}</option> <div></div>
% endfor % endif
</b-select>
<span class="control"> % if grid.pageable:
per page <b-field grouped
</span> v-if="firstItem">
</b-field> <span class="control">
showing {{ firstItem.toLocaleString('en') }} - {{ lastItem.toLocaleString('en') }} of {{ total.toLocaleString('en') }} results;
</span>
<b-select v-model="perPage"
size="is-small"
@input="loadAsyncData()">
% for value in grid.get_pagesize_options():
<option value="${value}">${value}</option>
% endfor
</b-select>
<span class="control">
per page
</span>
</b-field>
% endif
</div>
</template> </template>
% endif
</b-table> </b-table>
</div> </div>
@ -368,10 +383,24 @@
visibleData() { visibleData() {
return this.data return this.data
}, },
directLink() {
let params = new URLSearchParams(this.getAllParams())
return `${request.current_route_url(_query=None)}?${'$'}{params}`
},
}, },
methods: { methods: {
copyDirectLink() {
navigator.clipboard.writeText(this.directLink)
this.$buefy.toast.open({
message: "Link was copied to clipboard",
type: 'is-info',
duration: 2000, // 2 seconds
})
},
addRowClass(index, className) { addRowClass(index, className) {
// TODO: this may add duplicated name to class string // TODO: this may add duplicated name to class string
@ -388,16 +417,45 @@
return this.rowStatusMap[index] return this.rowStatusMap[index]
}, },
getBasicParams() {
let params = {}
% if grid.sortable:
params.sortkey = this.sortField
params.sortdir = this.sortOrder
% endif
% if grid.pageable:
params.pagesize = this.perPage
params.page = this.currentPage
% endif
return params
},
getFilterParams() {
let params = {}
for (var key in this.filters) {
var filter = this.filters[key]
if (filter.active) {
params[key] = filter.value
params[key+'.verb'] = filter.verb
}
}
if (Object.keys(params).length) {
params.filter = true
}
return params
},
getAllParams() {
return {...this.getBasicParams(),
...this.getFilterParams()}
},
loadAsyncData(params, callback) { loadAsyncData(params, callback) {
if (params === undefined || params === null) { if (params === undefined || params === null) {
params = [ params = new URLSearchParams(this.getBasicParams())
'partial=true', params.append('partial', true)
`sortkey=${'$'}{this.sortField}`, params = params.toString()
`sortdir=${'$'}{this.sortOrder}`,
`pagesize=${'$'}{this.perPage}`,
`page=${'$'}{this.currentPage}`
].join('&')
} }
this.loading = true this.loading = true
@ -482,23 +540,27 @@
applyFilters(params) { applyFilters(params) {
if (params === undefined) { if (params === undefined) {
params = [] params = {}
} }
params.push('partial=true') // merge in actual filter params
params.push('filter=true') // cf. https://stackoverflow.com/a/171256
params = {...params, ...this.getFilterParams()}
// hide inactive filters
for (var key in this.filters) { for (var key in this.filters) {
var filter = this.filters[key] var filter = this.filters[key]
if (filter.active) { if (!filter.active) {
params.push(key + '=' + encodeURIComponent(filter.value))
params.push(key + '.verb=' + encodeURIComponent(filter.verb))
} else {
filter.visible = false filter.visible = false
} }
} }
this.loadAsyncData(params.join('&')) // set some explicit params
params.partial = true
params.filter = true
params = new URLSearchParams(params)
this.loadAsyncData(params)
}, },
clearFilters() { clearFilters() {
@ -550,8 +612,7 @@
saveDefaults() { saveDefaults() {
// apply current filters as normal, but add special directive // apply current filters as normal, but add special directive
const params = ['save-current-filters-as-defaults=true'] this.applyFilters({'save-current-filters-as-defaults': true})
this.applyFilters(params)
}, },
deleteObject(event) { deleteObject(event) {

View file

@ -1,6 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<form action="${form.action_url}" method="GET" v-on:submit.prevent="applyFilters()"> <form action="${form.action_url}" method="GET" @submit.prevent="applyFilters()">
<grid-filter v-for="key in filtersSequence" <grid-filter v-for="key in filtersSequence"
:key="key" :key="key"

View file

@ -455,6 +455,10 @@ class MasterView(View):
'clicking_row_checks_box': self.clicking_row_checks_box, 'clicking_row_checks_box': self.clicking_row_checks_box,
'assume_local_times': self.has_local_times, 'assume_local_times': self.has_local_times,
} }
if self.sortable or self.pageable or self.filterable:
defaults['expose_direct_link'] = True
if 'main_actions' not in kwargs and 'more_actions' not in kwargs: if 'main_actions' not in kwargs and 'more_actions' not in kwargs:
main, more = self.get_grid_actions() main, more = self.get_grid_actions()
defaults['main_actions'] = main defaults['main_actions'] = main