Add new/flexible "download results" feature
This commit is contained in:
parent
43472c7eb6
commit
922cbe4451
3 changed files with 553 additions and 3 deletions
|
@ -143,6 +143,155 @@
|
|||
|
||||
<%def name="grid_tools()">
|
||||
|
||||
## download search results
|
||||
% if master.results_downloadable and master.has_perm('download_results'):
|
||||
% if use_buefy:
|
||||
<b-button type="is-primary"
|
||||
icon-pack="fas"
|
||||
icon-left="fas fa-download"
|
||||
@click="showDownloadResultsDialog = true"
|
||||
:disabled="!total">
|
||||
Download Results
|
||||
</b-button>
|
||||
|
||||
${h.form(url('{}.download_results'.format(route_prefix)), ref='download_results_form')}
|
||||
${h.csrf_token(request)}
|
||||
<input type="hidden" name="fmt" :value="downloadResultsFormat" />
|
||||
<input type="hidden" name="fields" :value="downloadResultsFieldsIncluded" />
|
||||
${h.end_form()}
|
||||
|
||||
<b-modal :active.sync="showDownloadResultsDialog">
|
||||
<div class="card">
|
||||
|
||||
<div class="card-content">
|
||||
<p>
|
||||
There are
|
||||
<span class="is-size-4 has-text-weight-bold">
|
||||
{{ total.toLocaleString('en') }} ${model_title_plural}
|
||||
</span>
|
||||
matching your current filters.
|
||||
</p>
|
||||
<p>
|
||||
You may download this set as a single data file if you like.
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<b-notification type="is-warning" :closable="false"
|
||||
v-if="downloadResultsFormat == 'xlsx' && total >= 1000">
|
||||
Excel downloads for large data sets can take a long time to
|
||||
generate, and bog down the server in the meantime. You are
|
||||
encouraged to choose CSV for a large data set, even though
|
||||
the end result (file size) may be larger with CSV.
|
||||
</b-notification>
|
||||
|
||||
<div style="display: flex;">
|
||||
|
||||
<div style="flex-grow: 1;">
|
||||
<b-field horizontal label="Format">
|
||||
<b-select v-model="downloadResultsFormat">
|
||||
% for key, label in six.iteritems(master.download_results_supported_formats()):
|
||||
<option value="${key}">${label}</option>
|
||||
% endfor
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div v-show="downloadResultsFieldsMode != 'choose'"
|
||||
class="has-text-right">
|
||||
<p v-if="downloadResultsFieldsMode == 'default'">
|
||||
Will use DEFAULT fields.
|
||||
</p>
|
||||
<p v-if="downloadResultsFieldsMode == 'all'">
|
||||
Will use ALL fields.
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<div class="buttons">
|
||||
<b-button type="is-primary"
|
||||
v-show="downloadResultsFieldsMode != 'default'"
|
||||
@click="downloadResultsUseDefaultFields()">
|
||||
Use Default Fields
|
||||
</b-button>
|
||||
<b-button type="is-primary"
|
||||
v-show="downloadResultsFieldsMode != 'all'"
|
||||
@click="downloadResultsUseAllFields()">
|
||||
Use All Fields
|
||||
</b-button>
|
||||
<b-button type="is-primary"
|
||||
v-show="downloadResultsFieldsMode != 'choose'"
|
||||
@click="downloadResultsFieldsMode = 'choose'">
|
||||
Choose Fields
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div v-show="downloadResultsFieldsMode == 'choose'">
|
||||
<div style="display: flex;">
|
||||
<div>
|
||||
<b-field label="Excluded Fields">
|
||||
<b-select multiple native-size="8"
|
||||
expanded
|
||||
ref="downloadResultsExcludedFields">
|
||||
<option v-for="field in downloadResultsFieldsAvailable"
|
||||
v-if="!downloadResultsFieldsIncluded.includes(field)"
|
||||
:key="field"
|
||||
:value="field">
|
||||
{{ field }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
<div>
|
||||
<br /><br />
|
||||
<b-button style="margin: 0.5rem;"
|
||||
@click="downloadResultsExcludeFields()">
|
||||
<
|
||||
</b-button>
|
||||
<br />
|
||||
<b-button style="margin: 0.5rem;"
|
||||
@click="downloadResultsIncludeFields()">
|
||||
>
|
||||
</b-button>
|
||||
</div>
|
||||
<div>
|
||||
<b-field label="Included Fields">
|
||||
<b-select multiple native-size="8"
|
||||
expanded
|
||||
ref="downloadResultsIncludedFields">
|
||||
<option v-for="field in downloadResultsFieldsIncluded"
|
||||
:key="field"
|
||||
:value="field">
|
||||
{{ field }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- card-content -->
|
||||
|
||||
<footer class="modal-card-foot">
|
||||
<b-button @click="showDownloadResultsDialog = false">
|
||||
Cancel
|
||||
</b-button>
|
||||
<once-button type="is-primary"
|
||||
@click="downloadResultsSubmit()"
|
||||
icon-pack="fas"
|
||||
icon-left="fas fa-download"
|
||||
:disabled="!downloadResultsFieldsIncluded.length"
|
||||
text="Download Results">
|
||||
</once-button>
|
||||
</footer>
|
||||
</div>
|
||||
</b-modal>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
## merge 2 objects
|
||||
% if master.mergeable and request.has_perm('{}.merge'.format(permission_prefix)):
|
||||
|
||||
|
@ -256,6 +405,14 @@
|
|||
</%def>
|
||||
|
||||
<%def name="page_content()">
|
||||
|
||||
% if download_results_path:
|
||||
<b-notification type="is-info">
|
||||
Your download should start automatically, or you can
|
||||
${h.link_to("click here", '{}?filename={}'.format(url('{}.download_results'.format(route_prefix)), h.os.path.basename(download_results_path)))}
|
||||
</b-notification>
|
||||
% endif
|
||||
|
||||
<${grid.component} :csrftoken="csrftoken"
|
||||
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
|
||||
@deleteActionClicked="deleteObject"
|
||||
|
@ -295,6 +452,19 @@
|
|||
${parent.modify_this_page_vars()}
|
||||
<script type="text/javascript">
|
||||
|
||||
## maybe auto-redirect to download latest results file
|
||||
% if download_results_path and use_buefy:
|
||||
ThisPage.methods.downloadResultsRedirect = function() {
|
||||
location.href = '${url('{}.download_results'.format(route_prefix))}?filename=${h.os.path.basename(download_results_path)}';
|
||||
}
|
||||
ThisPage.mounted = function() {
|
||||
// we give this 1 second before attempting the redirect; otherwise
|
||||
// the FontAwesome icons do not seem to load properly. so this way
|
||||
// the page should fully render before redirecting
|
||||
window.setTimeout(this.downloadResultsRedirect, 1000)
|
||||
}
|
||||
% endif
|
||||
|
||||
## TODO: stop checking for buefy here once we only have the one session.pop()
|
||||
% if use_buefy and request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
|
||||
ThisPage.mounted = function() {
|
||||
|
@ -318,6 +488,83 @@
|
|||
}
|
||||
% endif
|
||||
|
||||
## download results
|
||||
% if master.results_downloadable and master.has_perm('download_results'):
|
||||
|
||||
${grid.component_studly}Data.downloadResultsFormat = '${master.download_results_default_format()}'
|
||||
${grid.component_studly}Data.showDownloadResultsDialog = false
|
||||
${grid.component_studly}Data.downloadResultsFieldsMode = 'default'
|
||||
${grid.component_studly}Data.downloadResultsFieldsAvailable = ${json.dumps(download_results_fields_available)|n}
|
||||
${grid.component_studly}Data.downloadResultsFieldsDefault = ${json.dumps(download_results_fields_default)|n}
|
||||
${grid.component_studly}Data.downloadResultsFieldsIncluded = ${json.dumps(download_results_fields_default)|n}
|
||||
|
||||
${grid.component_studly}.computed.downloadResultsFieldsExcluded = function() {
|
||||
let excluded = []
|
||||
this.downloadResultsFieldsAvailable.forEach(field => {
|
||||
if (!this.downloadResultsFieldsIncluded.includes(field)) {
|
||||
excluded.push(field)
|
||||
}
|
||||
}, this)
|
||||
return excluded
|
||||
}
|
||||
|
||||
${grid.component_studly}.methods.downloadResultsExcludeFields = function() {
|
||||
let selected = this.$refs.downloadResultsIncludedFields.selected
|
||||
if (!selected) {
|
||||
return
|
||||
}
|
||||
selected = Array.from(selected)
|
||||
selected.forEach(field => {
|
||||
|
||||
// de-select the entry within "included" field input
|
||||
let index = this.$refs.downloadResultsIncludedFields.selected.indexOf(field)
|
||||
if (index > -1) {
|
||||
this.$refs.downloadResultsIncludedFields.selected.splice(index, 1)
|
||||
}
|
||||
|
||||
// remove field from official "included" list
|
||||
index = this.downloadResultsFieldsIncluded.indexOf(field)
|
||||
if (index > -1) {
|
||||
this.downloadResultsFieldsIncluded.splice(index, 1)
|
||||
}
|
||||
}, this)
|
||||
}
|
||||
|
||||
${grid.component_studly}.methods.downloadResultsIncludeFields = function() {
|
||||
let selected = this.$refs.downloadResultsExcludedFields.selected
|
||||
if (!selected) {
|
||||
return
|
||||
}
|
||||
selected = Array.from(selected)
|
||||
selected.forEach(field => {
|
||||
|
||||
// de-select the entry within "excluded" field input
|
||||
let index = this.$refs.downloadResultsExcludedFields.selected.indexOf(field)
|
||||
if (index > -1) {
|
||||
this.$refs.downloadResultsExcludedFields.selected.splice(index, 1)
|
||||
}
|
||||
|
||||
// add field to official "included" list
|
||||
this.downloadResultsFieldsIncluded.push(field)
|
||||
|
||||
}, this)
|
||||
}
|
||||
|
||||
${grid.component_studly}.methods.downloadResultsUseDefaultFields = function() {
|
||||
this.downloadResultsFieldsIncluded = Array.from(this.downloadResultsFieldsDefault)
|
||||
this.downloadResultsFieldsMode = 'default'
|
||||
}
|
||||
|
||||
${grid.component_studly}.methods.downloadResultsUseAllFields = function() {
|
||||
this.downloadResultsFieldsIncluded = Array.from(this.downloadResultsFieldsAvailable)
|
||||
this.downloadResultsFieldsMode = 'all'
|
||||
}
|
||||
|
||||
${grid.component_studly}.methods.downloadResultsSubmit = function() {
|
||||
this.$refs.download_results_form.submit()
|
||||
}
|
||||
% endif
|
||||
|
||||
## enable / disable selected objects
|
||||
% if master.supports_set_enabled_toggle and master.has_perm('enable_disable_set'):
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue