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

View file

@ -289,26 +289,41 @@
</section>
</template>
% if grid.pageable:
<template slot="footer">
<b-field grouped position="is-right"
v-if="firstItem">
<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>
<template #footer>
<div style="display: flex; justify-content: space-between;">
% if grid.expose_direct_link:
<b-button type="is-primary"
size="is-small"
@click="copyDirectLink()"
title="Copy link to clipboard">
<span><i class="fa fa-share-alt"></i></span>
</b-button>
% else:
<div></div>
% endif
% if grid.pageable:
<b-field grouped
v-if="firstItem">
<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>
% endif
</b-table>
</div>
@ -368,10 +383,24 @@
visibleData() {
return this.data
},
directLink() {
let params = new URLSearchParams(this.getAllParams())
return `${request.current_route_url(_query=None)}?${'$'}{params}`
},
},
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) {
// TODO: this may add duplicated name to class string
@ -388,16 +417,45 @@
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) {
if (params === undefined || params === null) {
params = [
'partial=true',
`sortkey=${'$'}{this.sortField}`,
`sortdir=${'$'}{this.sortOrder}`,
`pagesize=${'$'}{this.perPage}`,
`page=${'$'}{this.currentPage}`
].join('&')
params = new URLSearchParams(this.getBasicParams())
params.append('partial', true)
params = params.toString()
}
this.loading = true
@ -482,23 +540,27 @@
applyFilters(params) {
if (params === undefined) {
params = []
params = {}
}
params.push('partial=true')
params.push('filter=true')
// merge in actual filter params
// cf. https://stackoverflow.com/a/171256
params = {...params, ...this.getFilterParams()}
// hide inactive filters
for (var key in this.filters) {
var filter = this.filters[key]
if (filter.active) {
params.push(key + '=' + encodeURIComponent(filter.value))
params.push(key + '.verb=' + encodeURIComponent(filter.verb))
} else {
if (!filter.active) {
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() {
@ -550,8 +612,7 @@
saveDefaults() {
// apply current filters as normal, but add special directive
const params = ['save-current-filters-as-defaults=true']
this.applyFilters(params)
this.applyFilters({'save-current-filters-as-defaults': true})
},
deleteObject(event) {

View file

@ -1,6 +1,6 @@
## -*- 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"
:key="key"

View file

@ -455,6 +455,10 @@ class MasterView(View):
'clicking_row_checks_box': self.clicking_row_checks_box,
'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:
main, more = self.get_grid_actions()
defaults['main_actions'] = main