Add "most of" Buefy support for grid filters
still a couple of details to wrap up yet, but this is most of it!
This commit is contained in:
parent
23c38e33d4
commit
a0cd1f4cd0
8 changed files with 313 additions and 96 deletions
|
@ -1,6 +1,80 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
|
||||
<div id="buefy-table-app">
|
||||
<script type="text/x-template" id="grid-filter-template">
|
||||
|
||||
<div class="level filter" v-show="filter.visible">
|
||||
<div class="level-left">
|
||||
|
||||
<div class="level-item">
|
||||
|
||||
<b-field>
|
||||
<b-checkbox-button v-model="filter.active" native-value="IGNORED">
|
||||
<b-icon pack="fas" icon="check" v-show="filter.active"></b-icon>
|
||||
<span>{{ filter.label }}</span>
|
||||
</b-checkbox-button>
|
||||
</b-field>
|
||||
|
||||
</div>
|
||||
|
||||
<b-field grouped v-show="filter.active" custom-class="level-item">
|
||||
|
||||
<b-select v-model="filter.verb"
|
||||
@input="focusValue()">
|
||||
<option v-for="verb in filter.verbs"
|
||||
:key="verb"
|
||||
:value="verb">
|
||||
{{ filter.verb_labels[verb] }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
<b-input v-model="filter.value"
|
||||
v-show="! (filter.valueless_verbs && filter.valueless_verbs.includes(filter.verb))"
|
||||
ref="valueInput">
|
||||
</b-input>
|
||||
|
||||
</b-field>
|
||||
|
||||
</div><!-- level-left -->
|
||||
</div><!-- level -->
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<div id="buefy-grid-app">
|
||||
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5em;">
|
||||
|
||||
<div class="filters">
|
||||
% if grid.filterable:
|
||||
## TODO: stop using |n filter
|
||||
${grid.render_filters(allow_save_defaults=allow_save_defaults)|n}
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; justify-content: space-between;">
|
||||
|
||||
<div class="context-menu">
|
||||
% if context_menu:
|
||||
<ul id="context-menu">
|
||||
## TODO: stop using |n filter
|
||||
${context_menu|n}
|
||||
</ul>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<div class="grid-tools-wrapper">
|
||||
% if tools:
|
||||
<div class="grid-tools">
|
||||
## TODO: stop using |n filter
|
||||
${tools|n}
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<b-table
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
|
@ -76,7 +150,7 @@
|
|||
<script type="text/javascript">
|
||||
|
||||
new Vue({
|
||||
el: '#buefy-table-app',
|
||||
el: '#buefy-grid-app',
|
||||
data() {
|
||||
return {
|
||||
data: ${json.dumps(grid_data['data'])|n},
|
||||
|
@ -84,6 +158,7 @@
|
|||
sortField: '${grid.sortkey}',
|
||||
sortOrder: '${grid.sortdir}',
|
||||
rowStatusMap: ${json.dumps(grid_data['row_status_map'])|n},
|
||||
|
||||
% if grid.pageable:
|
||||
% if static_data:
|
||||
total: ${len(grid_data['data'])},
|
||||
|
@ -92,8 +167,14 @@
|
|||
% endif
|
||||
perPage: ${grid.pagesize},
|
||||
page: ${grid.page},
|
||||
firstItem: ${grid_data['first_item']},
|
||||
lastItem: ${grid_data['last_item']},
|
||||
firstItem: ${json.dumps(grid_data['first_item'])|n},
|
||||
lastItem: ${json.dumps(grid_data['last_item'])|n},
|
||||
% endif
|
||||
|
||||
% if grid.filterable:
|
||||
filters: ${json.dumps(filters_data)|n},
|
||||
filtersSequence: ${json.dumps(filters_sequence)|n},
|
||||
selectedFilter: null,
|
||||
% endif
|
||||
}
|
||||
},
|
||||
|
@ -103,15 +184,17 @@
|
|||
return this.rowStatusMap[index]
|
||||
},
|
||||
|
||||
loadAsyncData() {
|
||||
loadAsyncData(params) {
|
||||
|
||||
const params = [
|
||||
'partial=true',
|
||||
`sortkey=${'$'}{this.sortField}`,
|
||||
`sortdir=${'$'}{this.sortOrder}`,
|
||||
`pagesize=${'$'}{this.perPage}`,
|
||||
`page=${'$'}{this.page}`
|
||||
].join('&')
|
||||
if (params === undefined) {
|
||||
params = [
|
||||
'partial=true',
|
||||
`sortkey=${'$'}{this.sortField}`,
|
||||
`sortdir=${'$'}{this.sortOrder}`,
|
||||
`pagesize=${'$'}{this.perPage}`,
|
||||
`page=${'$'}{this.page}`
|
||||
].join('&')
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
this.$http.get(`${request.current_route_url(_query=None)}?${'$'}{params}`).then(({ data }) => {
|
||||
|
@ -142,6 +225,77 @@
|
|||
// TODO: i mean..right? would we ever not want that?
|
||||
this.page = 1
|
||||
this.loadAsyncData()
|
||||
},
|
||||
|
||||
resetView() {
|
||||
this.loading = true
|
||||
location.href = '?reset-to-default-filters=true'
|
||||
},
|
||||
|
||||
addFilter(filter_key) {
|
||||
|
||||
// reset dropdown so user again sees "Add Filter" placeholder
|
||||
this.$nextTick(function() {
|
||||
this.selectedFilter = null
|
||||
})
|
||||
|
||||
// show corresponding grid filter
|
||||
this.filters[filter_key].visible = true
|
||||
this.filters[filter_key].active = true
|
||||
|
||||
// track down the component
|
||||
var gridFilter = null
|
||||
for (var gf of this.$refs.gridFilters) {
|
||||
if (gf.filter.key == filter_key) {
|
||||
gridFilter = gf
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// tell component to focus the value field, ASAP
|
||||
this.$nextTick(function() {
|
||||
gridFilter.focusValue()
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
applyFilters(params) {
|
||||
if (params === undefined) {
|
||||
params = []
|
||||
}
|
||||
|
||||
params.push('partial=true')
|
||||
params.push('filter=true')
|
||||
|
||||
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 {
|
||||
filter.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
this.loadAsyncData(params.join('&'))
|
||||
},
|
||||
|
||||
clearFilters() {
|
||||
|
||||
// explicitly deactivate all filters
|
||||
for (var key in this.filters) {
|
||||
this.filters[key].active = false
|
||||
}
|
||||
|
||||
// then just "apply" as normal
|
||||
this.applyFilters()
|
||||
},
|
||||
|
||||
saveDefaults() {
|
||||
|
||||
// apply current filters as normal, but add special directive
|
||||
const params = ['save-current-filters-as-defaults=true']
|
||||
this.applyFilters(params)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
<%def name="extra_javascript()">
|
||||
${parent.extra_javascript()}
|
||||
% if use_buefy:
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.gridfilters.js') + '?ver={}'.format(tailbone.__version__))}
|
||||
% endif
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
|
@ -174,7 +177,8 @@
|
|||
|
||||
|
||||
% if use_buefy:
|
||||
${grid.render_buefy(grid_columns=grid_columns, grid_data=grid_data, static_data=static_data)|n}
|
||||
## TODO: stop using |n filter
|
||||
${grid.render_buefy(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
|
||||
|
||||
% else:
|
||||
## no buefy, so do the traditional thing
|
||||
|
|
|
@ -268,8 +268,8 @@
|
|||
## (needed for e.g. this.$http.get() calls, used by grid at least)
|
||||
${h.javascript_link('https://cdn.jsdelivr.net/npm/vue-resource@1.5.1')}
|
||||
|
||||
## Buefy 0.7.3
|
||||
${h.javascript_link('https://unpkg.com/buefy@0.7.3/dist/buefy.min.js')}
|
||||
## Buefy 0.7.4
|
||||
${h.javascript_link('https://unpkg.com/buefy@0.7.4/dist/buefy.min.js')}
|
||||
|
||||
## FontAwesome 5.3.1
|
||||
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
|
||||
|
@ -331,6 +331,7 @@
|
|||
${h.stylesheet_link(request.static_url('tailbone:static/css/grids.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/themes/falafel/css/grids.rowstatus.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
## ${h.stylesheet_link(request.static_url('tailbone:static/css/filters.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/themes/falafel/css/filters.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/themes/bobcat/css/forms.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/diffs.css') + '?ver={}'.format(tailbone.__version__))}
|
||||
</%def>
|
||||
|
|
|
@ -1,76 +1,57 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<div class="newfilters">
|
||||
|
||||
${h.form(form.action_url, method='get')}
|
||||
${h.hidden('reset-to-default-filters', value='false')}
|
||||
${h.hidden('save-current-filters-as-defaults', value='false')}
|
||||
<form action="${form.action_url}" method="GET" v-on:submit.prevent="applyFilters()">
|
||||
|
||||
<fieldset>
|
||||
<legend>Filters</legend>
|
||||
% for filtr in form.iter_filters():
|
||||
<div class="filter" id="filter-${filtr.key}" data-key="${filtr.key}"${' style="display: none;"' if not filtr.active else ''|n}>
|
||||
${h.checkbox('{}-active'.format(filtr.key), class_='active', id='filter-active-{}'.format(filtr.key), checked=filtr.active)}
|
||||
<label for="filter-active-${filtr.key}">${filtr.label}</label>
|
||||
<div class="inputs">
|
||||
${form.filter_verb(filtr)}
|
||||
${form.filter_value(filtr)}
|
||||
</div>
|
||||
</div>
|
||||
% endfor
|
||||
</fieldset>
|
||||
<grid-filter v-for="key in filtersSequence"
|
||||
:key="key"
|
||||
:filter="filters[key]"
|
||||
ref="gridFilters">
|
||||
</grid-filter>
|
||||
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
## <button type="submit" class="button is-primary" id="apply-filters">Apply Filters</button>
|
||||
<a class="button is-primary">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>Apply Filters</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<div class="select">
|
||||
<select id="add-filter">
|
||||
<option value="">Add Filter</option>
|
||||
% for filtr in form.iter_filters():
|
||||
<option value="${filtr.key}"${' disabled="disabled"' if filtr.active else ''|n}>${filtr.label}</option>
|
||||
% endfor
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
## <button type="button" class="button" id="default-filters">Default View</button>
|
||||
<a class="button">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-home"></i>
|
||||
</span>
|
||||
<span>Default View</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
## <button type="button" class="button" id="clear-filters">No Filters</button>
|
||||
<a class="button">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-trash"></i>
|
||||
</span>
|
||||
<span>No Filters</span>
|
||||
</a>
|
||||
</div>
|
||||
% if allow_save_defaults and request.user:
|
||||
<div class="level-item">
|
||||
## <button type="button" class="button" id="save-defaults">Save Defaults</button>
|
||||
<a class="button">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-save"></i>
|
||||
</span>
|
||||
<span>Save Defaults</span>
|
||||
</a>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
<b-field grouped>
|
||||
|
||||
${h.end_form()}
|
||||
</div><!-- newfilters -->
|
||||
<b-button type="is-primary"
|
||||
native-type="submit"
|
||||
icon-pack="fas"
|
||||
icon-left="check"
|
||||
class="control">
|
||||
Apply Filters
|
||||
</b-button>
|
||||
|
||||
<b-select @input="addFilter"
|
||||
placeholder="Add Filter"
|
||||
v-model="selectedFilter">
|
||||
<option v-for="key in filtersSequence"
|
||||
:key="key"
|
||||
:value="key"
|
||||
:disabled="filters[key].visible">
|
||||
{{ filters[key].label }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
<b-button @click="resetView()"
|
||||
icon-pack="fas"
|
||||
icon-left="home"
|
||||
class="control">
|
||||
Default View
|
||||
</b-button>
|
||||
|
||||
<b-button @click="clearFilters()"
|
||||
icon-pack="fas"
|
||||
icon-left="trash"
|
||||
class="control">
|
||||
No Filters
|
||||
</b-button>
|
||||
|
||||
% if allow_save_defaults and request.user:
|
||||
<b-button @click="saveDefaults()"
|
||||
icon-pack="fas"
|
||||
icon-left="save"
|
||||
class="control">
|
||||
Save Defaults
|
||||
</b-button>
|
||||
% endif
|
||||
|
||||
</b-field>
|
||||
|
||||
</form>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue